@philippwassibauer/agentlens 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/BUILD_ID +1 -0
- package/.next/app-build-manifest.json +44 -0
- package/.next/app-path-routes-manifest.json +1 -0
- package/.next/build-manifest.json +32 -0
- package/.next/export-marker.json +1 -0
- package/.next/images-manifest.json +1 -0
- package/.next/next-minimal-server.js.nft.json +1 -0
- package/.next/next-server.js.nft.json +1 -0
- package/.next/package.json +1 -0
- package/.next/prerender-manifest.json +1 -0
- package/.next/react-loadable-manifest.json +1 -0
- package/.next/required-server-files.json +1 -0
- package/.next/routes-manifest.json +1 -0
- package/.next/server/app/_not-found/page.js +1 -0
- package/.next/server/app/_not-found/page.js.nft.json +1 -0
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
- package/.next/server/app/_not-found.html +1 -0
- package/.next/server/app/_not-found.meta +6 -0
- package/.next/server/app/_not-found.rsc +9 -0
- package/.next/server/app/api/check-prs/route.js +86 -0
- package/.next/server/app/api/check-prs/route.js.nft.json +1 -0
- package/.next/server/app/api/events/route.js +86 -0
- package/.next/server/app/api/events/route.js.nft.json +1 -0
- package/.next/server/app/api/sessions/[id]/route.js +86 -0
- package/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -0
- package/.next/server/app/api/sessions/route.js +86 -0
- package/.next/server/app/api/sessions/route.js.nft.json +1 -0
- package/.next/server/app/api/stats/route.js +86 -0
- package/.next/server/app/api/stats/route.js.nft.json +1 -0
- package/.next/server/app/page.js +1 -0
- package/.next/server/app/page.js.nft.json +1 -0
- package/.next/server/app/page_client-reference-manifest.js +1 -0
- package/.next/server/app/sessions/[id]/page.js +1 -0
- package/.next/server/app/sessions/[id]/page.js.nft.json +1 -0
- package/.next/server/app/sessions/[id]/page_client-reference-manifest.js +1 -0
- package/.next/server/app/sessions/page.js +1 -0
- package/.next/server/app/sessions/page.js.nft.json +1 -0
- package/.next/server/app/sessions/page_client-reference-manifest.js +1 -0
- package/.next/server/app-paths-manifest.json +11 -0
- package/.next/server/chunks/111.js +1 -0
- package/.next/server/chunks/19.js +1 -0
- package/.next/server/chunks/218.js +1 -0
- package/.next/server/chunks/267.js +13 -0
- package/.next/server/chunks/449.js +12 -0
- package/.next/server/chunks/522.js +2 -0
- package/.next/server/chunks/590.js +6 -0
- package/.next/server/chunks/619.js +2 -0
- package/.next/server/chunks/780.js +1 -0
- package/.next/server/chunks/787.js +1 -0
- package/.next/server/chunks/938.js +1 -0
- package/.next/server/chunks/95.js +1 -0
- package/.next/server/chunks/98.js +86 -0
- package/.next/server/chunks/font-manifest.json +1 -0
- package/.next/server/font-manifest.json +1 -0
- package/.next/server/functions-config-manifest.json +1 -0
- package/.next/server/interception-route-rewrite-manifest.js +1 -0
- package/.next/server/middleware-build-manifest.js +1 -0
- package/.next/server/middleware-manifest.json +6 -0
- package/.next/server/middleware-react-loadable-manifest.js +1 -0
- package/.next/server/next-font-manifest.js +1 -0
- package/.next/server/next-font-manifest.json +1 -0
- package/.next/server/pages/404.html +1 -0
- package/.next/server/pages/500.html +1 -0
- package/.next/server/pages/_app.js +1 -0
- package/.next/server/pages/_app.js.nft.json +1 -0
- package/.next/server/pages/_document.js +1 -0
- package/.next/server/pages/_document.js.nft.json +1 -0
- package/.next/server/pages/_error.js +1 -0
- package/.next/server/pages/_error.js.nft.json +1 -0
- package/.next/server/pages-manifest.json +1 -0
- package/.next/server/server-reference-manifest.js +1 -0
- package/.next/server/server-reference-manifest.json +1 -0
- package/.next/server/webpack-runtime.js +1 -0
- package/.next/static/VcvMciURiwijLrVt2jf_P/_buildManifest.js +1 -0
- package/.next/static/VcvMciURiwijLrVt2jf_P/_ssgManifest.js +1 -0
- package/.next/static/chunks/2200cc46-96120a9be9a790d7.js +1 -0
- package/.next/static/chunks/838-ee1ac53cffa08ff2.js +1 -0
- package/.next/static/chunks/919-13111e16ca5aad12.js +1 -0
- package/.next/static/chunks/945-08d88d38313883d1.js +2 -0
- package/.next/static/chunks/app/_not-found/page-52828565ce3bf1a5.js +1 -0
- package/.next/static/chunks/app/layout-d3c17bc5a9ba9afe.js +1 -0
- package/.next/static/chunks/app/page-f02e37b80f020816.js +1 -0
- package/.next/static/chunks/app/sessions/[id]/page-9cd58c2b3cbdb58c.js +1 -0
- package/.next/static/chunks/app/sessions/page-381d2eb994edfbe5.js +1 -0
- package/.next/static/chunks/framework-6e06c675866dc992.js +1 -0
- package/.next/static/chunks/main-921b2ae56ade90f2.js +1 -0
- package/.next/static/chunks/main-app-f7575201e7f66c72.js +1 -0
- package/.next/static/chunks/pages/_app-0c3037849002a4aa.js +1 -0
- package/.next/static/chunks/pages/_error-a647cd2c75dc4dc7.js +1 -0
- package/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- package/.next/static/chunks/webpack-5a21843c4f0469c6.js +1 -0
- package/.next/static/css/e0ed3c3bd07a0247.css +3 -0
- package/.next/static/media/011e180705008d6f-s.woff2 +0 -0
- package/.next/static/media/0aa834ed78bf6d07-s.woff2 +0 -0
- package/.next/static/media/20535187d867b7b9-s.woff2 +0 -0
- package/.next/static/media/37786be940ec402b-s.p.woff2 +0 -0
- package/.next/static/media/46e154b2fcbd6033-s.woff2 +0 -0
- package/.next/static/media/5356a6a4f2c8c8d8-s.woff2 +0 -0
- package/.next/static/media/58f386aa6b1a2a92-s.woff2 +0 -0
- package/.next/static/media/656feb427634a431-s.woff2 +0 -0
- package/.next/static/media/67957d42bae0796d-s.woff2 +0 -0
- package/.next/static/media/704b853f32d191d5-s.woff2 +0 -0
- package/.next/static/media/73cb51aac9c97f90-s.woff2 +0 -0
- package/.next/static/media/7ba5fb2a8c88521c-s.woff2 +0 -0
- package/.next/static/media/886030b0b59bc5a7-s.woff2 +0 -0
- package/.next/static/media/92eeb95d069020cc-s.woff2 +0 -0
- package/.next/static/media/939c4f875ee75fbb-s.woff2 +0 -0
- package/.next/static/media/98e207f02528a563-s.p.woff2 +0 -0
- package/.next/static/media/991629005c80bdf1-s.woff2 +0 -0
- package/.next/static/media/99dcf268bda04fe5-s.woff2 +0 -0
- package/.next/static/media/bb3ef058b751a6ad-s.p.woff2 +0 -0
- package/.next/static/media/d26bbd13d6b70f89-s.woff2 +0 -0
- package/.next/static/media/d29838c109ef09b4-s.woff2 +0 -0
- package/.next/static/media/d3ebbfd689654d3a-s.p.woff2 +0 -0
- package/.next/static/media/db96af6b531dc71f-s.p.woff2 +0 -0
- package/.next/static/media/e40af3453d7c920a-s.woff2 +0 -0
- package/.next/static/media/ef4d5661765d0e49-s.woff2 +0 -0
- package/.next/static/media/f911b923c6adde36-s.woff2 +0 -0
- package/README.md +152 -0
- package/dist/bin/agentlens.mjs +1104 -0
- package/next.config.mjs +10 -0
- package/package.json +88 -0
|
@@ -0,0 +1,1104 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// bin/cli.ts
|
|
4
|
+
import { join as join2, dirname, resolve } from "path";
|
|
5
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2 } from "fs";
|
|
6
|
+
import { homedir as homedir2 } from "os";
|
|
7
|
+
import { fileURLToPath } from "url";
|
|
8
|
+
import { spawn, exec } from "child_process";
|
|
9
|
+
import { createRequire } from "module";
|
|
10
|
+
|
|
11
|
+
// collector/indexer.ts
|
|
12
|
+
import { readdirSync, readFileSync, existsSync } from "fs";
|
|
13
|
+
import { join } from "path";
|
|
14
|
+
import { execSync } from "child_process";
|
|
15
|
+
import { userInfo } from "os";
|
|
16
|
+
import { eq as eq2 } from "drizzle-orm";
|
|
17
|
+
|
|
18
|
+
// lib/db/schema.ts
|
|
19
|
+
import { sql, eq, and, gte, lte, desc, asc, count } from "drizzle-orm";
|
|
20
|
+
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
|
|
21
|
+
var sessions = sqliteTable("sessions", {
|
|
22
|
+
id: text("id").primaryKey(),
|
|
23
|
+
teamId: text("team_id").notNull(),
|
|
24
|
+
userId: text("user_id").notNull(),
|
|
25
|
+
project: text("project").notNull(),
|
|
26
|
+
gitRepo: text("git_repo"),
|
|
27
|
+
gitBranch: text("git_branch"),
|
|
28
|
+
piVersion: text("pi_version").notNull().default(""),
|
|
29
|
+
skillsUsed: text("skills_used").notNull().default("[]"),
|
|
30
|
+
model: text("model"),
|
|
31
|
+
harness: text("harness").notNull().default("pi"),
|
|
32
|
+
startedAt: text("started_at").notNull(),
|
|
33
|
+
endedAt: text("ended_at"),
|
|
34
|
+
status: text("status").notNull().default("active"),
|
|
35
|
+
createdAt: text("created_at").notNull().default(sql`(datetime('now'))`)
|
|
36
|
+
});
|
|
37
|
+
var events = sqliteTable("events", {
|
|
38
|
+
id: integer("id").primaryKey({ autoIncrement: true }),
|
|
39
|
+
sessionId: text("session_id").notNull(),
|
|
40
|
+
eventType: text("event_type").notNull(),
|
|
41
|
+
timestamp: text("timestamp").notNull(),
|
|
42
|
+
payload: text("payload").notNull().default("{}"),
|
|
43
|
+
createdAt: text("created_at").notNull().default(sql`(datetime('now'))`)
|
|
44
|
+
});
|
|
45
|
+
var pullRequests = sqliteTable("pull_requests", {
|
|
46
|
+
id: integer("id").primaryKey({ autoIncrement: true }),
|
|
47
|
+
sessionId: text("session_id").notNull(),
|
|
48
|
+
repo: text("repo").notNull(),
|
|
49
|
+
branch: text("branch").notNull(),
|
|
50
|
+
prNumber: integer("pr_number").notNull(),
|
|
51
|
+
prUrl: text("pr_url").notNull(),
|
|
52
|
+
prTitle: text("pr_title").notNull().default(""),
|
|
53
|
+
status: text("status").notNull().default("open"),
|
|
54
|
+
mergedAt: text("merged_at"),
|
|
55
|
+
reviewsApproved: integer("reviews_approved").notNull().default(0),
|
|
56
|
+
reviewsChangesRequested: integer("reviews_changes_requested").notNull().default(0),
|
|
57
|
+
reviewComments: integer("review_comments").notNull().default(0),
|
|
58
|
+
commitsAfterReview: integer("commits_after_review").notNull().default(0),
|
|
59
|
+
firstReviewAt: text("first_review_at"),
|
|
60
|
+
timeToMergeHours: text("time_to_merge_hours"),
|
|
61
|
+
// stored as text for SQLite real compat
|
|
62
|
+
checkedAt: text("checked_at"),
|
|
63
|
+
createdAt: text("created_at").notNull().default(sql`(datetime('now'))`)
|
|
64
|
+
});
|
|
65
|
+
function insertSession(db, input) {
|
|
66
|
+
db.insert(sessions).values({
|
|
67
|
+
id: input.id,
|
|
68
|
+
teamId: input.teamId,
|
|
69
|
+
userId: input.userId,
|
|
70
|
+
project: input.project,
|
|
71
|
+
gitRepo: input.gitRepo,
|
|
72
|
+
gitBranch: input.gitBranch,
|
|
73
|
+
piVersion: input.piVersion,
|
|
74
|
+
skillsUsed: JSON.stringify(input.skillsUsed),
|
|
75
|
+
model: input.model,
|
|
76
|
+
harness: input.harness || "pi",
|
|
77
|
+
startedAt: input.startedAt
|
|
78
|
+
}).run();
|
|
79
|
+
}
|
|
80
|
+
function insertEvent(db, input) {
|
|
81
|
+
db.insert(events).values({
|
|
82
|
+
sessionId: input.sessionId,
|
|
83
|
+
eventType: input.eventType,
|
|
84
|
+
timestamp: input.timestamp,
|
|
85
|
+
payload: JSON.stringify(input.payload)
|
|
86
|
+
}).run();
|
|
87
|
+
}
|
|
88
|
+
function upsertPullRequest(db, input) {
|
|
89
|
+
const existing = db.select().from(pullRequests).where(
|
|
90
|
+
and(eq(pullRequests.sessionId, input.sessionId), eq(pullRequests.prNumber, input.prNumber))
|
|
91
|
+
).get();
|
|
92
|
+
if (existing) {
|
|
93
|
+
db.update(pullRequests).set({
|
|
94
|
+
status: input.status,
|
|
95
|
+
prTitle: input.prTitle,
|
|
96
|
+
checkedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
97
|
+
}).where(eq(pullRequests.id, existing.id)).run();
|
|
98
|
+
} else {
|
|
99
|
+
db.insert(pullRequests).values({
|
|
100
|
+
sessionId: input.sessionId,
|
|
101
|
+
repo: input.repo,
|
|
102
|
+
branch: input.branch,
|
|
103
|
+
prNumber: input.prNumber,
|
|
104
|
+
prUrl: input.prUrl,
|
|
105
|
+
prTitle: input.prTitle,
|
|
106
|
+
status: input.status
|
|
107
|
+
}).run();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// collector/model-context.ts
|
|
112
|
+
var CONTEXT_WINDOWS = {
|
|
113
|
+
// Claude 4
|
|
114
|
+
"claude-opus-4-6": 2e5,
|
|
115
|
+
"claude-sonnet-4-6": 2e5,
|
|
116
|
+
// Claude 3.5+
|
|
117
|
+
"claude-opus-4-5": 2e5,
|
|
118
|
+
"claude-sonnet-4-5": 2e5,
|
|
119
|
+
"claude-haiku-4-5-20251001": 2e5,
|
|
120
|
+
// Claude 3
|
|
121
|
+
"claude-3-opus-20240229": 2e5,
|
|
122
|
+
"claude-3-sonnet-20240229": 2e5,
|
|
123
|
+
"claude-3-haiku-20240307": 2e5,
|
|
124
|
+
// OpenAI
|
|
125
|
+
"gpt-4o": 128e3,
|
|
126
|
+
"gpt-4-turbo": 128e3,
|
|
127
|
+
"gpt-4": 8192,
|
|
128
|
+
"gpt-5.3-codex": 2e5,
|
|
129
|
+
"o1-preview": 128e3,
|
|
130
|
+
"o1-mini": 128e3
|
|
131
|
+
};
|
|
132
|
+
function getContextWindow(model) {
|
|
133
|
+
if (!model) return null;
|
|
134
|
+
if (CONTEXT_WINDOWS[model]) return CONTEXT_WINDOWS[model];
|
|
135
|
+
for (const [key, value] of Object.entries(CONTEXT_WINDOWS)) {
|
|
136
|
+
if (model.startsWith(key)) return value;
|
|
137
|
+
}
|
|
138
|
+
if (model.includes("claude")) return 2e5;
|
|
139
|
+
if (model.includes("gpt-4")) return 128e3;
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// collector/claude-code/parser.ts
|
|
144
|
+
var SUBAGENT_TOOLS = /* @__PURE__ */ new Set(["Task", "Agent"]);
|
|
145
|
+
function projectFromCwd(cwd) {
|
|
146
|
+
const parts = cwd.replace(/\/+$/, "").split("/");
|
|
147
|
+
return parts[parts.length - 1] || cwd;
|
|
148
|
+
}
|
|
149
|
+
function getFilePath(input) {
|
|
150
|
+
return input.file_path || input.path || null;
|
|
151
|
+
}
|
|
152
|
+
function summarizeToolInput(name, input) {
|
|
153
|
+
if (name === "Bash" && input.command) {
|
|
154
|
+
return String(input.command).slice(0, 200);
|
|
155
|
+
}
|
|
156
|
+
const filePath = getFilePath(input);
|
|
157
|
+
if ((name === "Write" || name === "Edit" || name === "MultiEdit") && filePath) {
|
|
158
|
+
return filePath;
|
|
159
|
+
}
|
|
160
|
+
if (name === "Read" && filePath) {
|
|
161
|
+
return filePath;
|
|
162
|
+
}
|
|
163
|
+
if ((name === "Task" || name === "Agent") && input.description) {
|
|
164
|
+
return String(input.description).slice(0, 200);
|
|
165
|
+
}
|
|
166
|
+
if ((name === "Task" || name === "Agent") && input.prompt) {
|
|
167
|
+
return String(input.prompt).slice(0, 200);
|
|
168
|
+
}
|
|
169
|
+
for (const val of Object.values(input)) {
|
|
170
|
+
if (typeof val === "string" && val.length > 0) {
|
|
171
|
+
return val.slice(0, 200);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return "";
|
|
175
|
+
}
|
|
176
|
+
function parseClaudeCodeSession(jsonl) {
|
|
177
|
+
const lines = jsonl.split("\n").filter((l) => l.trim()).map((l) => JSON.parse(l));
|
|
178
|
+
const events2 = [];
|
|
179
|
+
let sessionId = "";
|
|
180
|
+
let project = "";
|
|
181
|
+
let gitBranch = null;
|
|
182
|
+
let model = null;
|
|
183
|
+
let version = "";
|
|
184
|
+
let userId = "";
|
|
185
|
+
let startedAt = "";
|
|
186
|
+
let endedAt = "";
|
|
187
|
+
let usedSubagents = false;
|
|
188
|
+
let totalInputTokens = 0;
|
|
189
|
+
let totalOutputTokens = 0;
|
|
190
|
+
let totalCacheReadTokens = 0;
|
|
191
|
+
let totalCacheWriteTokens = 0;
|
|
192
|
+
const toolResults = /* @__PURE__ */ new Map();
|
|
193
|
+
for (const line of lines) {
|
|
194
|
+
if (line.type === "user") {
|
|
195
|
+
const content = line.message?.content;
|
|
196
|
+
if (Array.isArray(content)) {
|
|
197
|
+
for (const item of content) {
|
|
198
|
+
if (item.type === "tool_result" && item.tool_use_id) {
|
|
199
|
+
toolResults.set(item.tool_use_id, item);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
for (const line of lines) {
|
|
206
|
+
const ts = line.timestamp;
|
|
207
|
+
if (!ts) continue;
|
|
208
|
+
if (!startedAt || ts < startedAt) startedAt = ts;
|
|
209
|
+
if (!endedAt || ts > endedAt) endedAt = ts;
|
|
210
|
+
if (line.type === "user" && line.sessionId && !sessionId) {
|
|
211
|
+
sessionId = line.sessionId;
|
|
212
|
+
project = projectFromCwd(line.cwd || "");
|
|
213
|
+
gitBranch = line.gitBranch || null;
|
|
214
|
+
version = line.version || "";
|
|
215
|
+
userId = line.message?.content?.user_id || "";
|
|
216
|
+
}
|
|
217
|
+
if (line.type === "user" && line.userType === "external") {
|
|
218
|
+
const content = line.message?.content;
|
|
219
|
+
if (typeof content === "string" && content.trim()) {
|
|
220
|
+
events2.push({
|
|
221
|
+
eventType: "user_prompt",
|
|
222
|
+
timestamp: ts,
|
|
223
|
+
payload: {
|
|
224
|
+
prompt_text: content,
|
|
225
|
+
prompt_length: content.length
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
if (line.type === "assistant") {
|
|
231
|
+
const msg = line.message || {};
|
|
232
|
+
const usage = msg.usage || {};
|
|
233
|
+
if (msg.model && !model) {
|
|
234
|
+
model = msg.model;
|
|
235
|
+
}
|
|
236
|
+
const inputTokens = usage.input_tokens || 0;
|
|
237
|
+
const outputTokens = usage.output_tokens || 0;
|
|
238
|
+
const cacheRead = usage.cache_read_input_tokens || 0;
|
|
239
|
+
const cacheWrite = usage.cache_creation_input_tokens || 0;
|
|
240
|
+
totalInputTokens += inputTokens;
|
|
241
|
+
totalOutputTokens += outputTokens;
|
|
242
|
+
totalCacheReadTokens += cacheRead;
|
|
243
|
+
totalCacheWriteTokens += cacheWrite;
|
|
244
|
+
const responseModel = msg.model || model;
|
|
245
|
+
const contextWindow = getContextWindow(responseModel);
|
|
246
|
+
events2.push({
|
|
247
|
+
eventType: "llm_response",
|
|
248
|
+
timestamp: ts,
|
|
249
|
+
payload: {
|
|
250
|
+
model: responseModel,
|
|
251
|
+
input_tokens: inputTokens,
|
|
252
|
+
output_tokens: outputTokens,
|
|
253
|
+
cache_read_tokens: cacheRead,
|
|
254
|
+
cache_write_tokens: cacheWrite,
|
|
255
|
+
total_tokens: inputTokens + outputTokens,
|
|
256
|
+
stop_reason: msg.stop_reason || null,
|
|
257
|
+
...contextWindow ? { context_window: contextWindow } : {}
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
const content = msg.content || [];
|
|
261
|
+
if (Array.isArray(content)) {
|
|
262
|
+
for (const item of content) {
|
|
263
|
+
if (item.type === "tool_use") {
|
|
264
|
+
const toolUse = item;
|
|
265
|
+
const toolResult = toolResults.get(toolUse.id);
|
|
266
|
+
const isError = toolResult?.is_error === true;
|
|
267
|
+
const isSubagent = SUBAGENT_TOOLS.has(toolUse.name);
|
|
268
|
+
if (isSubagent) usedSubagents = true;
|
|
269
|
+
const argsSummary = summarizeToolInput(toolUse.name, toolUse.input || {});
|
|
270
|
+
events2.push({
|
|
271
|
+
eventType: "tool_call",
|
|
272
|
+
timestamp: ts,
|
|
273
|
+
payload: {
|
|
274
|
+
tool: toolUse.name,
|
|
275
|
+
args_summary: argsSummary,
|
|
276
|
+
result_summary: toolResult?.content ? String(toolResult.content).slice(0, 200) : "",
|
|
277
|
+
success: !isError,
|
|
278
|
+
is_error: isError,
|
|
279
|
+
...isSubagent ? { is_subagent: true } : {}
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
const changeFilePath = getFilePath(toolUse.input || {});
|
|
283
|
+
if (toolUse.name === "Write" && changeFilePath) {
|
|
284
|
+
events2.push({
|
|
285
|
+
eventType: "file_change",
|
|
286
|
+
timestamp: ts,
|
|
287
|
+
payload: { path: changeFilePath, action: "create" }
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
if ((toolUse.name === "Edit" || toolUse.name === "MultiEdit") && changeFilePath) {
|
|
291
|
+
events2.push({
|
|
292
|
+
eventType: "file_change",
|
|
293
|
+
timestamp: ts,
|
|
294
|
+
payload: { path: changeFilePath, action: "edit" }
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
if (toolUse.name === "Bash" && toolUse.input?.command) {
|
|
298
|
+
const cmd = String(toolUse.input.command);
|
|
299
|
+
const resultText = toolResult?.content ? String(toolResult.content) : "";
|
|
300
|
+
if (cmd.includes("git commit")) {
|
|
301
|
+
events2.push({
|
|
302
|
+
eventType: "git_commit",
|
|
303
|
+
timestamp: ts,
|
|
304
|
+
payload: {
|
|
305
|
+
command: cmd,
|
|
306
|
+
result_summary: resultText.slice(0, 200)
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
if (cmd.includes("git push")) {
|
|
311
|
+
events2.push({
|
|
312
|
+
eventType: "git_push",
|
|
313
|
+
timestamp: ts,
|
|
314
|
+
payload: {
|
|
315
|
+
command: cmd,
|
|
316
|
+
result_summary: resultText.slice(0, 200)
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
if (cmd.includes("gh pr create") || cmd.includes("gh pr merge")) {
|
|
321
|
+
const prMatch = resultText.match(
|
|
322
|
+
/https:\/\/github\.com\/([^/]+\/[^/]+)\/pull\/(\d+)/
|
|
323
|
+
);
|
|
324
|
+
if (prMatch) {
|
|
325
|
+
events2.push({
|
|
326
|
+
eventType: "pr_opened",
|
|
327
|
+
timestamp: ts,
|
|
328
|
+
payload: {
|
|
329
|
+
command: cmd.slice(0, 200),
|
|
330
|
+
pr_url: prMatch[0],
|
|
331
|
+
repo: prMatch[1],
|
|
332
|
+
pr_number: parseInt(prMatch[2], 10)
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
if (isError && toolResult?.content) {
|
|
339
|
+
events2.push({
|
|
340
|
+
eventType: "error",
|
|
341
|
+
timestamp: ts,
|
|
342
|
+
payload: {
|
|
343
|
+
tool: toolUse.name,
|
|
344
|
+
message: String(toolResult.content).slice(0, 500)
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
events2.sort((a, b) => a.timestamp.localeCompare(b.timestamp));
|
|
354
|
+
events2.unshift({
|
|
355
|
+
eventType: "session_start",
|
|
356
|
+
timestamp: startedAt,
|
|
357
|
+
payload: {
|
|
358
|
+
model,
|
|
359
|
+
git_branch: gitBranch,
|
|
360
|
+
project,
|
|
361
|
+
harness: "claude-code",
|
|
362
|
+
version,
|
|
363
|
+
user_id: userId
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
events2.push({
|
|
367
|
+
eventType: "session_end",
|
|
368
|
+
timestamp: endedAt,
|
|
369
|
+
payload: {
|
|
370
|
+
reason: "session_end_inferred"
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
return {
|
|
374
|
+
sessionId,
|
|
375
|
+
project,
|
|
376
|
+
gitBranch,
|
|
377
|
+
harness: "claude-code",
|
|
378
|
+
model,
|
|
379
|
+
version,
|
|
380
|
+
userId,
|
|
381
|
+
startedAt,
|
|
382
|
+
endedAt,
|
|
383
|
+
events: events2,
|
|
384
|
+
totalInputTokens,
|
|
385
|
+
totalOutputTokens,
|
|
386
|
+
totalCacheReadTokens,
|
|
387
|
+
totalCacheWriteTokens,
|
|
388
|
+
usedSubagents
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// collector/pi/parser.ts
|
|
393
|
+
var SUBAGENT_TOOLS2 = /* @__PURE__ */ new Set(["subagent", "delegate", "Task", "Agent"]);
|
|
394
|
+
function projectFromCwd2(cwd) {
|
|
395
|
+
const parts = cwd.replace(/\/+$/, "").split("/");
|
|
396
|
+
return parts[parts.length - 1] || cwd;
|
|
397
|
+
}
|
|
398
|
+
function getFilePath2(args2) {
|
|
399
|
+
return args2.path || args2.file_path || null;
|
|
400
|
+
}
|
|
401
|
+
function summarizeToolInput2(name, args2) {
|
|
402
|
+
const lname = name.toLowerCase();
|
|
403
|
+
if (lname === "bash" && args2.command) {
|
|
404
|
+
return String(args2.command).slice(0, 200);
|
|
405
|
+
}
|
|
406
|
+
const filePath = getFilePath2(args2);
|
|
407
|
+
if ((lname === "write" || lname === "edit" || lname === "read") && filePath) {
|
|
408
|
+
return filePath;
|
|
409
|
+
}
|
|
410
|
+
if (lname === "edit" && Array.isArray(args2.multi) && args2.multi.length > 0) {
|
|
411
|
+
const firstPath = args2.multi[0].path || args2.multi[0].file_path || "";
|
|
412
|
+
const count2 = args2.multi.length;
|
|
413
|
+
return count2 > 1 ? `${firstPath} (+${count2 - 1} more)` : firstPath;
|
|
414
|
+
}
|
|
415
|
+
if (SUBAGENT_TOOLS2.has(name)) {
|
|
416
|
+
return String(args2.task || args2.description || args2.prompt || "").slice(0, 200);
|
|
417
|
+
}
|
|
418
|
+
for (const [key, val] of Object.entries(args2)) {
|
|
419
|
+
if (key === "content") continue;
|
|
420
|
+
if (typeof val === "string" && val.length > 0) {
|
|
421
|
+
return val.slice(0, 200);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
return "";
|
|
425
|
+
}
|
|
426
|
+
function parsePiSession(jsonl, sessionDir) {
|
|
427
|
+
const lines = jsonl.split("\n").filter((l) => l.trim()).map((l) => JSON.parse(l));
|
|
428
|
+
const events2 = [];
|
|
429
|
+
let sessionId = "";
|
|
430
|
+
let project = "";
|
|
431
|
+
let model = null;
|
|
432
|
+
let version = "";
|
|
433
|
+
let startedAt = "";
|
|
434
|
+
let endedAt = "";
|
|
435
|
+
let usedSubagents = false;
|
|
436
|
+
let totalInputTokens = 0;
|
|
437
|
+
let totalOutputTokens = 0;
|
|
438
|
+
let totalCacheReadTokens = 0;
|
|
439
|
+
let totalCacheWriteTokens = 0;
|
|
440
|
+
const toolResultById = /* @__PURE__ */ new Map();
|
|
441
|
+
const toolResultsByIndex = [];
|
|
442
|
+
for (const line of lines) {
|
|
443
|
+
if (line.type !== "message") continue;
|
|
444
|
+
const msg = line.message || {};
|
|
445
|
+
if (msg.role !== "toolResult") continue;
|
|
446
|
+
const text2 = (msg.content || []).filter((c) => c.type === "text").map((c) => c.text).join("\n");
|
|
447
|
+
const info = {
|
|
448
|
+
content: text2,
|
|
449
|
+
isError: msg.isError === true,
|
|
450
|
+
ts: line.timestamp
|
|
451
|
+
};
|
|
452
|
+
if (msg.toolCallId) {
|
|
453
|
+
toolResultById.set(msg.toolCallId, info);
|
|
454
|
+
}
|
|
455
|
+
toolResultsByIndex.push(info);
|
|
456
|
+
}
|
|
457
|
+
let toolCallSeqIndex = 0;
|
|
458
|
+
for (const line of lines) {
|
|
459
|
+
const ts = line.timestamp;
|
|
460
|
+
if (!ts) continue;
|
|
461
|
+
if (!startedAt || ts < startedAt) startedAt = ts;
|
|
462
|
+
if (!endedAt || ts > endedAt) endedAt = ts;
|
|
463
|
+
if (line.type === "session") {
|
|
464
|
+
sessionId = line.id;
|
|
465
|
+
version = String(line.version || "");
|
|
466
|
+
if (line.cwd) project = projectFromCwd2(line.cwd);
|
|
467
|
+
}
|
|
468
|
+
if (line.type === "model_change" && line.modelId) {
|
|
469
|
+
model = line.modelId;
|
|
470
|
+
}
|
|
471
|
+
if (line.type !== "message") continue;
|
|
472
|
+
const msg = line.message || {};
|
|
473
|
+
if (msg.role === "user") {
|
|
474
|
+
const text2 = (msg.content || []).filter((c) => c.type === "text").map((c) => c.text).join("\n");
|
|
475
|
+
if (text2.trim()) {
|
|
476
|
+
events2.push({
|
|
477
|
+
eventType: "user_prompt",
|
|
478
|
+
timestamp: ts,
|
|
479
|
+
payload: { prompt_text: text2, prompt_length: text2.length }
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
if (msg.role === "assistant") {
|
|
484
|
+
const usage = msg.usage || {};
|
|
485
|
+
const inputTokens = usage.input || 0;
|
|
486
|
+
const outputTokens = usage.output || 0;
|
|
487
|
+
const cacheRead = usage.cacheRead || 0;
|
|
488
|
+
const cacheWrite = usage.cacheWrite || 0;
|
|
489
|
+
const costTotal = usage.cost?.total || 0;
|
|
490
|
+
totalInputTokens += inputTokens;
|
|
491
|
+
totalOutputTokens += outputTokens;
|
|
492
|
+
totalCacheReadTokens += cacheRead;
|
|
493
|
+
totalCacheWriteTokens += cacheWrite;
|
|
494
|
+
const responseModel = msg.model || model;
|
|
495
|
+
const contextWindow = getContextWindow(responseModel);
|
|
496
|
+
events2.push({
|
|
497
|
+
eventType: "llm_response",
|
|
498
|
+
timestamp: ts,
|
|
499
|
+
payload: {
|
|
500
|
+
model: responseModel,
|
|
501
|
+
input_tokens: inputTokens,
|
|
502
|
+
output_tokens: outputTokens,
|
|
503
|
+
cache_read_tokens: cacheRead,
|
|
504
|
+
cache_write_tokens: cacheWrite,
|
|
505
|
+
total_tokens: usage.totalTokens || inputTokens + outputTokens,
|
|
506
|
+
total_cost_usd: costTotal,
|
|
507
|
+
stop_reason: msg.stop_reason || null,
|
|
508
|
+
...contextWindow ? { context_window: contextWindow } : {}
|
|
509
|
+
}
|
|
510
|
+
});
|
|
511
|
+
for (const c of msg.content || []) {
|
|
512
|
+
if (c.type !== "toolCall") continue;
|
|
513
|
+
const toolId = c.id;
|
|
514
|
+
const args2 = c.arguments || c.input || {};
|
|
515
|
+
const toolResult = toolResultById.get(toolId) || toolResultsByIndex[toolCallSeqIndex] || null;
|
|
516
|
+
const isError = toolResult?.isError === true;
|
|
517
|
+
const isSubagent = SUBAGENT_TOOLS2.has(c.name);
|
|
518
|
+
if (isSubagent) usedSubagents = true;
|
|
519
|
+
const argsSummary = summarizeToolInput2(c.name, args2);
|
|
520
|
+
events2.push({
|
|
521
|
+
eventType: "tool_call",
|
|
522
|
+
timestamp: ts,
|
|
523
|
+
payload: {
|
|
524
|
+
tool: c.name,
|
|
525
|
+
args_summary: argsSummary,
|
|
526
|
+
result_summary: toolResult?.content ? toolResult.content.slice(0, 200) : "",
|
|
527
|
+
success: !isError,
|
|
528
|
+
is_error: isError,
|
|
529
|
+
...isSubagent ? { is_subagent: true } : {}
|
|
530
|
+
}
|
|
531
|
+
});
|
|
532
|
+
const lname = c.name.toLowerCase();
|
|
533
|
+
const filePath = getFilePath2(args2);
|
|
534
|
+
if (lname === "write" && filePath) {
|
|
535
|
+
events2.push({
|
|
536
|
+
eventType: "file_change",
|
|
537
|
+
timestamp: ts,
|
|
538
|
+
payload: { path: filePath, action: "create" }
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
if (lname === "edit" || lname === "multiedit") {
|
|
542
|
+
if (filePath) {
|
|
543
|
+
events2.push({
|
|
544
|
+
eventType: "file_change",
|
|
545
|
+
timestamp: ts,
|
|
546
|
+
payload: { path: filePath, action: "edit" }
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
if (Array.isArray(args2.multi)) {
|
|
550
|
+
const seen = /* @__PURE__ */ new Set();
|
|
551
|
+
for (const item of args2.multi) {
|
|
552
|
+
const p = item.path || item.file_path;
|
|
553
|
+
if (p && !seen.has(p)) {
|
|
554
|
+
seen.add(p);
|
|
555
|
+
events2.push({
|
|
556
|
+
eventType: "file_change",
|
|
557
|
+
timestamp: ts,
|
|
558
|
+
payload: { path: p, action: "edit" }
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
if (lname === "bash" && args2.command) {
|
|
565
|
+
const cmd = String(args2.command);
|
|
566
|
+
if (cmd.includes("git commit")) {
|
|
567
|
+
events2.push({
|
|
568
|
+
eventType: "git_commit",
|
|
569
|
+
timestamp: ts,
|
|
570
|
+
payload: {
|
|
571
|
+
command: cmd,
|
|
572
|
+
result_summary: toolResult?.content?.slice(0, 200) || ""
|
|
573
|
+
}
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
if (cmd.includes("git push")) {
|
|
577
|
+
events2.push({
|
|
578
|
+
eventType: "git_push",
|
|
579
|
+
timestamp: ts,
|
|
580
|
+
payload: {
|
|
581
|
+
command: cmd,
|
|
582
|
+
result_summary: toolResult?.content?.slice(0, 200) || ""
|
|
583
|
+
}
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
if (cmd.includes("gh pr create") || cmd.includes("gh pr merge")) {
|
|
587
|
+
const resultText = toolResult?.content || "";
|
|
588
|
+
const prMatch = resultText.match(/https:\/\/github\.com\/([^/]+\/[^/]+)\/pull\/(\d+)/);
|
|
589
|
+
if (prMatch) {
|
|
590
|
+
events2.push({
|
|
591
|
+
eventType: "pr_opened",
|
|
592
|
+
timestamp: ts,
|
|
593
|
+
payload: {
|
|
594
|
+
command: cmd.slice(0, 200),
|
|
595
|
+
pr_url: prMatch[0],
|
|
596
|
+
repo: prMatch[1],
|
|
597
|
+
pr_number: parseInt(prMatch[2], 10)
|
|
598
|
+
}
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
if (isError && toolResult?.content) {
|
|
604
|
+
events2.push({
|
|
605
|
+
eventType: "error",
|
|
606
|
+
timestamp: ts,
|
|
607
|
+
payload: { tool: c.name, message: toolResult.content.slice(0, 500) }
|
|
608
|
+
});
|
|
609
|
+
}
|
|
610
|
+
toolCallSeqIndex++;
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
events2.sort((a, b) => a.timestamp.localeCompare(b.timestamp));
|
|
615
|
+
events2.unshift({
|
|
616
|
+
eventType: "session_start",
|
|
617
|
+
timestamp: startedAt,
|
|
618
|
+
payload: { model, project, harness: "pi", version }
|
|
619
|
+
});
|
|
620
|
+
events2.push({
|
|
621
|
+
eventType: "session_end",
|
|
622
|
+
timestamp: endedAt,
|
|
623
|
+
payload: { reason: "session_end_inferred" }
|
|
624
|
+
});
|
|
625
|
+
return {
|
|
626
|
+
sessionId,
|
|
627
|
+
project,
|
|
628
|
+
gitBranch: null,
|
|
629
|
+
harness: "pi",
|
|
630
|
+
model,
|
|
631
|
+
version,
|
|
632
|
+
userId: "",
|
|
633
|
+
startedAt,
|
|
634
|
+
endedAt,
|
|
635
|
+
events: events2,
|
|
636
|
+
totalInputTokens,
|
|
637
|
+
totalOutputTokens,
|
|
638
|
+
totalCacheReadTokens,
|
|
639
|
+
totalCacheWriteTokens,
|
|
640
|
+
usedSubagents
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
// collector/indexer.ts
|
|
645
|
+
var _cachedUserId = null;
|
|
646
|
+
function detectUserId() {
|
|
647
|
+
if (_cachedUserId) return _cachedUserId;
|
|
648
|
+
try {
|
|
649
|
+
_cachedUserId = execSync("git config user.email", { encoding: "utf-8" }).trim();
|
|
650
|
+
if (_cachedUserId) return _cachedUserId;
|
|
651
|
+
} catch {
|
|
652
|
+
}
|
|
653
|
+
_cachedUserId = userInfo().username || "unknown";
|
|
654
|
+
return _cachedUserId;
|
|
655
|
+
}
|
|
656
|
+
function discoverClaudeCodeSessions(projectsDir) {
|
|
657
|
+
if (!existsSync(projectsDir)) return [];
|
|
658
|
+
const files = [];
|
|
659
|
+
try {
|
|
660
|
+
const projectDirs = readdirSync(projectsDir, { withFileTypes: true });
|
|
661
|
+
for (const dir of projectDirs) {
|
|
662
|
+
if (!dir.isDirectory()) continue;
|
|
663
|
+
const dirPath = join(projectsDir, dir.name);
|
|
664
|
+
const dirEntries = readdirSync(dirPath, { withFileTypes: true });
|
|
665
|
+
for (const entry of dirEntries) {
|
|
666
|
+
if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
667
|
+
files.push(join(dirPath, entry.name));
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
} catch {
|
|
672
|
+
}
|
|
673
|
+
return files;
|
|
674
|
+
}
|
|
675
|
+
function discoverPiSessions(sessionsDir) {
|
|
676
|
+
if (!existsSync(sessionsDir)) return [];
|
|
677
|
+
const files = [];
|
|
678
|
+
try {
|
|
679
|
+
const projectDirs = readdirSync(sessionsDir, { withFileTypes: true });
|
|
680
|
+
for (const dir of projectDirs) {
|
|
681
|
+
if (!dir.isDirectory()) continue;
|
|
682
|
+
const dirPath = join(sessionsDir, dir.name);
|
|
683
|
+
const dirEntries = readdirSync(dirPath, { withFileTypes: true });
|
|
684
|
+
for (const entry of dirEntries) {
|
|
685
|
+
if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
686
|
+
files.push(join(dirPath, entry.name));
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
} catch {
|
|
691
|
+
}
|
|
692
|
+
return files;
|
|
693
|
+
}
|
|
694
|
+
function importParsedSession(db, parsed, result) {
|
|
695
|
+
if (!parsed.sessionId) {
|
|
696
|
+
return false;
|
|
697
|
+
}
|
|
698
|
+
const existing = db.select().from(sessions).where(eq2(sessions.id, parsed.sessionId)).get();
|
|
699
|
+
if (existing) {
|
|
700
|
+
result.skipped++;
|
|
701
|
+
return false;
|
|
702
|
+
}
|
|
703
|
+
const userId = parsed.userId || detectUserId();
|
|
704
|
+
insertSession(db, {
|
|
705
|
+
id: parsed.sessionId,
|
|
706
|
+
teamId: "default",
|
|
707
|
+
userId,
|
|
708
|
+
project: parsed.project,
|
|
709
|
+
gitRepo: null,
|
|
710
|
+
gitBranch: parsed.gitBranch,
|
|
711
|
+
piVersion: parsed.version,
|
|
712
|
+
skillsUsed: [],
|
|
713
|
+
model: parsed.model,
|
|
714
|
+
harness: parsed.harness,
|
|
715
|
+
startedAt: parsed.startedAt
|
|
716
|
+
});
|
|
717
|
+
if (parsed.endedAt) {
|
|
718
|
+
db.update(sessions).set({ endedAt: parsed.endedAt, status: "completed" }).where(eq2(sessions.id, parsed.sessionId)).run();
|
|
719
|
+
}
|
|
720
|
+
for (const event of parsed.events) {
|
|
721
|
+
insertEvent(db, {
|
|
722
|
+
sessionId: parsed.sessionId,
|
|
723
|
+
eventType: event.eventType,
|
|
724
|
+
timestamp: event.timestamp,
|
|
725
|
+
payload: event.payload
|
|
726
|
+
});
|
|
727
|
+
if (event.eventType === "pr_opened" && event.payload.pr_url) {
|
|
728
|
+
upsertPullRequest(db, {
|
|
729
|
+
sessionId: parsed.sessionId,
|
|
730
|
+
repo: event.payload.repo || "",
|
|
731
|
+
branch: parsed.gitBranch || "",
|
|
732
|
+
prNumber: event.payload.pr_number || 0,
|
|
733
|
+
prUrl: event.payload.pr_url,
|
|
734
|
+
prTitle: "",
|
|
735
|
+
// not available from bash output
|
|
736
|
+
status: "open"
|
|
737
|
+
});
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
result.imported++;
|
|
741
|
+
return true;
|
|
742
|
+
}
|
|
743
|
+
function indexSessions(db, options = {}) {
|
|
744
|
+
const result = { imported: 0, skipped: 0, errors: [] };
|
|
745
|
+
const harness = options.harness;
|
|
746
|
+
if (!harness || harness === "claude-code") {
|
|
747
|
+
const projectsDir = options.claudeProjectsDir || join(process.env.HOME || "~", ".claude", "projects");
|
|
748
|
+
const files = discoverClaudeCodeSessions(projectsDir);
|
|
749
|
+
for (const filePath of files) {
|
|
750
|
+
try {
|
|
751
|
+
const jsonl = readFileSync(filePath, "utf-8");
|
|
752
|
+
const parsed = parseClaudeCodeSession(jsonl);
|
|
753
|
+
if (!parsed.sessionId) {
|
|
754
|
+
result.errors.push(`No session ID found in ${filePath}`);
|
|
755
|
+
continue;
|
|
756
|
+
}
|
|
757
|
+
importParsedSession(db, parsed, result);
|
|
758
|
+
} catch (err) {
|
|
759
|
+
result.errors.push(`Error processing ${filePath}: ${err}`);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
if (!harness || harness === "pi") {
|
|
764
|
+
const sessionsDir = options.piSessionsDir || join(process.env.HOME || "~", ".pi", "agent", "sessions");
|
|
765
|
+
const files = discoverPiSessions(sessionsDir);
|
|
766
|
+
for (const filePath of files) {
|
|
767
|
+
try {
|
|
768
|
+
const jsonl = readFileSync(filePath, "utf-8");
|
|
769
|
+
const dirName = join(filePath, "..").split("/").pop() || "";
|
|
770
|
+
const parsed = parsePiSession(jsonl, dirName);
|
|
771
|
+
if (!parsed.sessionId) {
|
|
772
|
+
result.errors.push(`No session ID found in ${filePath}`);
|
|
773
|
+
continue;
|
|
774
|
+
}
|
|
775
|
+
importParsedSession(db, parsed, result);
|
|
776
|
+
} catch (err) {
|
|
777
|
+
result.errors.push(`Error processing ${filePath}: ${err}`);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
return result;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
// collector/watcher.ts
|
|
785
|
+
function createWatcher(db, options = {}) {
|
|
786
|
+
const interval = options.pollIntervalMs ?? 5e3;
|
|
787
|
+
let stopped = false;
|
|
788
|
+
let timer = null;
|
|
789
|
+
function poll() {
|
|
790
|
+
if (stopped) return;
|
|
791
|
+
try {
|
|
792
|
+
indexSessions(db, options);
|
|
793
|
+
} catch {
|
|
794
|
+
}
|
|
795
|
+
if (!stopped) {
|
|
796
|
+
timer = setTimeout(poll, interval);
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
poll();
|
|
800
|
+
return {
|
|
801
|
+
stop() {
|
|
802
|
+
stopped = true;
|
|
803
|
+
if (timer) {
|
|
804
|
+
clearTimeout(timer);
|
|
805
|
+
timer = null;
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
};
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
// lib/db/index.ts
|
|
812
|
+
import Database from "better-sqlite3";
|
|
813
|
+
import { drizzle } from "drizzle-orm/better-sqlite3";
|
|
814
|
+
import { sql as sql2 } from "drizzle-orm";
|
|
815
|
+
import path from "path";
|
|
816
|
+
import fs from "fs";
|
|
817
|
+
import { homedir } from "os";
|
|
818
|
+
var _db = null;
|
|
819
|
+
function getDb() {
|
|
820
|
+
if (_db) return _db;
|
|
821
|
+
const dbPath2 = process.env.AGENTLENS_DB_PATH || path.join(homedir(), ".agentlens", "agentlens.db");
|
|
822
|
+
const dataDir2 = path.dirname(dbPath2);
|
|
823
|
+
if (!fs.existsSync(dataDir2)) {
|
|
824
|
+
fs.mkdirSync(dataDir2, { recursive: true });
|
|
825
|
+
}
|
|
826
|
+
const sqlite = new Database(dbPath2);
|
|
827
|
+
sqlite.pragma("journal_mode = WAL");
|
|
828
|
+
const db = drizzle(sqlite);
|
|
829
|
+
db.run(sql2`
|
|
830
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
831
|
+
id TEXT PRIMARY KEY,
|
|
832
|
+
team_id TEXT NOT NULL,
|
|
833
|
+
user_id TEXT NOT NULL,
|
|
834
|
+
project TEXT NOT NULL,
|
|
835
|
+
git_repo TEXT,
|
|
836
|
+
git_branch TEXT,
|
|
837
|
+
pi_version TEXT NOT NULL DEFAULT '',
|
|
838
|
+
skills_used TEXT NOT NULL DEFAULT '[]',
|
|
839
|
+
model TEXT,
|
|
840
|
+
harness TEXT NOT NULL DEFAULT 'pi',
|
|
841
|
+
started_at TEXT NOT NULL,
|
|
842
|
+
ended_at TEXT,
|
|
843
|
+
status TEXT NOT NULL DEFAULT 'active',
|
|
844
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
845
|
+
)
|
|
846
|
+
`);
|
|
847
|
+
db.run(sql2`
|
|
848
|
+
CREATE TABLE IF NOT EXISTS events (
|
|
849
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
850
|
+
session_id TEXT NOT NULL,
|
|
851
|
+
event_type TEXT NOT NULL,
|
|
852
|
+
timestamp TEXT NOT NULL,
|
|
853
|
+
payload TEXT NOT NULL DEFAULT '{}',
|
|
854
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
855
|
+
)
|
|
856
|
+
`);
|
|
857
|
+
try {
|
|
858
|
+
db.run(sql2`ALTER TABLE sessions ADD COLUMN model TEXT`);
|
|
859
|
+
} catch {
|
|
860
|
+
}
|
|
861
|
+
db.run(sql2`CREATE INDEX IF NOT EXISTS idx_sessions_team_id ON sessions(team_id)`);
|
|
862
|
+
db.run(sql2`CREATE INDEX IF NOT EXISTS idx_sessions_user_id ON sessions(user_id)`);
|
|
863
|
+
db.run(sql2`CREATE INDEX IF NOT EXISTS idx_sessions_project ON sessions(project)`);
|
|
864
|
+
db.run(sql2`CREATE INDEX IF NOT EXISTS idx_sessions_started_at ON sessions(started_at)`);
|
|
865
|
+
db.run(sql2`CREATE INDEX IF NOT EXISTS idx_sessions_status ON sessions(status)`);
|
|
866
|
+
db.run(sql2`CREATE INDEX IF NOT EXISTS idx_events_session_id ON events(session_id)`);
|
|
867
|
+
db.run(
|
|
868
|
+
sql2`CREATE INDEX IF NOT EXISTS idx_events_session_timestamp ON events(session_id, timestamp)`
|
|
869
|
+
);
|
|
870
|
+
db.run(sql2`CREATE INDEX IF NOT EXISTS idx_events_event_type ON events(event_type)`);
|
|
871
|
+
db.run(sql2`
|
|
872
|
+
CREATE TABLE IF NOT EXISTS pull_requests (
|
|
873
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
874
|
+
session_id TEXT NOT NULL,
|
|
875
|
+
repo TEXT NOT NULL,
|
|
876
|
+
branch TEXT NOT NULL,
|
|
877
|
+
pr_number INTEGER NOT NULL,
|
|
878
|
+
pr_url TEXT NOT NULL,
|
|
879
|
+
pr_title TEXT NOT NULL DEFAULT '',
|
|
880
|
+
status TEXT NOT NULL DEFAULT 'open',
|
|
881
|
+
merged_at TEXT,
|
|
882
|
+
reviews_approved INTEGER NOT NULL DEFAULT 0,
|
|
883
|
+
reviews_changes_requested INTEGER NOT NULL DEFAULT 0,
|
|
884
|
+
review_comments INTEGER NOT NULL DEFAULT 0,
|
|
885
|
+
commits_after_review INTEGER NOT NULL DEFAULT 0,
|
|
886
|
+
first_review_at TEXT,
|
|
887
|
+
time_to_merge_hours REAL,
|
|
888
|
+
checked_at TEXT,
|
|
889
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
890
|
+
UNIQUE(session_id, pr_number)
|
|
891
|
+
)
|
|
892
|
+
`);
|
|
893
|
+
db.run(sql2`CREATE INDEX IF NOT EXISTS idx_prs_session_id ON pull_requests(session_id)`);
|
|
894
|
+
db.run(sql2`CREATE INDEX IF NOT EXISTS idx_prs_status ON pull_requests(status)`);
|
|
895
|
+
db.run(sql2`CREATE INDEX IF NOT EXISTS idx_prs_repo_branch ON pull_requests(repo, branch)`);
|
|
896
|
+
try {
|
|
897
|
+
db.run(sql2`ALTER TABLE sessions ADD COLUMN model TEXT`);
|
|
898
|
+
} catch {
|
|
899
|
+
}
|
|
900
|
+
try {
|
|
901
|
+
db.run(sql2`ALTER TABLE sessions ADD COLUMN harness TEXT NOT NULL DEFAULT 'pi'`);
|
|
902
|
+
} catch {
|
|
903
|
+
}
|
|
904
|
+
db.run(sql2`
|
|
905
|
+
CREATE TABLE IF NOT EXISTS eval_checks (
|
|
906
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
907
|
+
session_id TEXT NOT NULL,
|
|
908
|
+
check_id TEXT NOT NULL,
|
|
909
|
+
check_version TEXT NOT NULL,
|
|
910
|
+
score REAL NOT NULL,
|
|
911
|
+
raw_score INTEGER NOT NULL,
|
|
912
|
+
reasoning TEXT NOT NULL DEFAULT '',
|
|
913
|
+
evidence TEXT,
|
|
914
|
+
model TEXT NOT NULL,
|
|
915
|
+
cost_usd REAL NOT NULL DEFAULT 0,
|
|
916
|
+
evaluated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
917
|
+
UNIQUE(session_id, check_id, check_version)
|
|
918
|
+
)
|
|
919
|
+
`);
|
|
920
|
+
db.run(sql2`
|
|
921
|
+
CREATE TABLE IF NOT EXISTS eval_summaries (
|
|
922
|
+
session_id TEXT PRIMARY KEY,
|
|
923
|
+
qual_score REAL NOT NULL,
|
|
924
|
+
checks_passed INTEGER NOT NULL DEFAULT 0,
|
|
925
|
+
checks_total INTEGER NOT NULL DEFAULT 0,
|
|
926
|
+
total_eval_cost_usd REAL NOT NULL DEFAULT 0,
|
|
927
|
+
evaluated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
928
|
+
)
|
|
929
|
+
`);
|
|
930
|
+
db.run(sql2`CREATE INDEX IF NOT EXISTS idx_eval_checks_session ON eval_checks(session_id)`);
|
|
931
|
+
db.run(
|
|
932
|
+
sql2`CREATE INDEX IF NOT EXISTS idx_eval_checks_lookup ON eval_checks(session_id, check_id, check_version)`
|
|
933
|
+
);
|
|
934
|
+
db.run(sql2`
|
|
935
|
+
CREATE TABLE IF NOT EXISTS session_insights (
|
|
936
|
+
session_id TEXT PRIMARY KEY,
|
|
937
|
+
task_category TEXT NOT NULL,
|
|
938
|
+
task_size TEXT NOT NULL,
|
|
939
|
+
workflow_tags TEXT NOT NULL DEFAULT '[]',
|
|
940
|
+
prompting_tags TEXT NOT NULL DEFAULT '[]',
|
|
941
|
+
failure_modes TEXT NOT NULL DEFAULT '[]',
|
|
942
|
+
complexity_factors TEXT NOT NULL DEFAULT '[]',
|
|
943
|
+
key_learning TEXT,
|
|
944
|
+
extracted_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
945
|
+
model TEXT NOT NULL,
|
|
946
|
+
synced_at TEXT
|
|
947
|
+
)
|
|
948
|
+
`);
|
|
949
|
+
for (const col of [
|
|
950
|
+
"failure_modes TEXT NOT NULL DEFAULT '[]'",
|
|
951
|
+
"complexity_factors TEXT NOT NULL DEFAULT '[]'",
|
|
952
|
+
"key_learning TEXT"
|
|
953
|
+
]) {
|
|
954
|
+
try {
|
|
955
|
+
db.run(sql2.raw(`ALTER TABLE session_insights ADD COLUMN ${col}`));
|
|
956
|
+
} catch {
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
_db = db;
|
|
960
|
+
return db;
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
// bin/cli.ts
|
|
964
|
+
var args = process.argv.slice(2);
|
|
965
|
+
function getFlag(name) {
|
|
966
|
+
return args.includes(`--${name}`);
|
|
967
|
+
}
|
|
968
|
+
function getFlagValue(name) {
|
|
969
|
+
const idx = args.indexOf(`--${name}`);
|
|
970
|
+
if (idx >= 0 && idx + 1 < args.length) return args[idx + 1];
|
|
971
|
+
return void 0;
|
|
972
|
+
}
|
|
973
|
+
if (getFlag("help") || getFlag("h")) {
|
|
974
|
+
console.log(`
|
|
975
|
+
agentlens \u2014 observability for AI coding agents
|
|
976
|
+
|
|
977
|
+
Usage:
|
|
978
|
+
npx agentlens [options]
|
|
979
|
+
|
|
980
|
+
Options:
|
|
981
|
+
--port <number> Port for the dashboard (default: 3333)
|
|
982
|
+
--data <path> Data directory for the SQLite DB (default: ~/.agentlens)
|
|
983
|
+
--no-open Don't auto-open the browser
|
|
984
|
+
--help, -h Show this help message
|
|
985
|
+
`);
|
|
986
|
+
process.exit(0);
|
|
987
|
+
}
|
|
988
|
+
var port = parseInt(getFlagValue("port") || "3333", 10);
|
|
989
|
+
var dataDir = getFlagValue("data") || join2(homedir2(), ".agentlens");
|
|
990
|
+
var noOpen = getFlag("no-open");
|
|
991
|
+
var dbPath = join2(dataDir, "agentlens.db");
|
|
992
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
993
|
+
var __dirname = dirname(__filename);
|
|
994
|
+
var pkgRoot = existsSync2(join2(__dirname, "..", ".next")) ? resolve(__dirname, "..") : resolve(__dirname, "..", "..");
|
|
995
|
+
var claudeProjectsDir = join2(homedir2(), ".claude", "projects");
|
|
996
|
+
var piSessionsDir = join2(homedir2(), ".pi", "agent", "sessions");
|
|
997
|
+
async function main() {
|
|
998
|
+
if (!existsSync2(dataDir)) {
|
|
999
|
+
mkdirSync(dataDir, { recursive: true });
|
|
1000
|
+
}
|
|
1001
|
+
process.env.AGENTLENS_DB_PATH = dbPath;
|
|
1002
|
+
console.log(`
|
|
1003
|
+
\x1B[1magentlens\x1B[0m v${getVersion()}
|
|
1004
|
+
|
|
1005
|
+
\u25B8 Dashboard: \x1B[36mhttp://localhost:${port}\x1B[0m
|
|
1006
|
+
\u25B8 Data: ${dbPath}
|
|
1007
|
+
\u25B8 Watching: ${claudeProjectsDir}
|
|
1008
|
+
${piSessionsDir}
|
|
1009
|
+
`);
|
|
1010
|
+
const db = getDb();
|
|
1011
|
+
const startTime = Date.now();
|
|
1012
|
+
process.stdout.write(" Indexing sessions...");
|
|
1013
|
+
const result = indexSessions(db, { claudeProjectsDir, piSessionsDir });
|
|
1014
|
+
const elapsed = ((Date.now() - startTime) / 1e3).toFixed(1);
|
|
1015
|
+
const total = result.imported + result.skipped;
|
|
1016
|
+
console.log(
|
|
1017
|
+
` found ${total} session${total !== 1 ? "s" : ""}, ${result.imported} new (${elapsed}s)`
|
|
1018
|
+
);
|
|
1019
|
+
if (result.errors.length > 0) {
|
|
1020
|
+
console.log(` \u26A0 ${result.errors.length} error${result.errors.length !== 1 ? "s" : ""}`);
|
|
1021
|
+
}
|
|
1022
|
+
const watcher = createWatcher(db, {
|
|
1023
|
+
claudeProjectsDir,
|
|
1024
|
+
piSessionsDir,
|
|
1025
|
+
pollIntervalMs: 5e3
|
|
1026
|
+
});
|
|
1027
|
+
console.log(" Watching for new sessions...\n");
|
|
1028
|
+
const require2 = createRequire(import.meta.url);
|
|
1029
|
+
const nextBin = require2.resolve("next/dist/bin/next");
|
|
1030
|
+
const server = spawn(process.execPath, [nextBin, "start", "--port", String(port)], {
|
|
1031
|
+
cwd: pkgRoot,
|
|
1032
|
+
env: {
|
|
1033
|
+
...process.env,
|
|
1034
|
+
AGENTLENS_DB_PATH: dbPath,
|
|
1035
|
+
PORT: String(port),
|
|
1036
|
+
HOSTNAME: "localhost"
|
|
1037
|
+
},
|
|
1038
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
1039
|
+
});
|
|
1040
|
+
let serverReady = false;
|
|
1041
|
+
server.stdout?.on("data", (data) => {
|
|
1042
|
+
const text2 = data.toString().trim();
|
|
1043
|
+
if (text2 && !serverReady) {
|
|
1044
|
+
serverReady = true;
|
|
1045
|
+
if (!noOpen) {
|
|
1046
|
+
openBrowser(`http://localhost:${port}`);
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
});
|
|
1050
|
+
server.stderr?.on("data", (data) => {
|
|
1051
|
+
const text2 = data.toString().trim();
|
|
1052
|
+
if (text2) {
|
|
1053
|
+
if (!text2.includes("ExperimentalWarning")) {
|
|
1054
|
+
console.error(` [server] ${text2}`);
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
});
|
|
1058
|
+
server.on("error", (err) => {
|
|
1059
|
+
console.error(` Failed to start server: ${err.message}`);
|
|
1060
|
+
cleanup(watcher, server);
|
|
1061
|
+
process.exit(1);
|
|
1062
|
+
});
|
|
1063
|
+
server.on("exit", (code) => {
|
|
1064
|
+
if (code !== 0 && code !== null) {
|
|
1065
|
+
console.error(` Server exited with code ${code}`);
|
|
1066
|
+
}
|
|
1067
|
+
cleanup(watcher, null);
|
|
1068
|
+
process.exit(code ?? 0);
|
|
1069
|
+
});
|
|
1070
|
+
function shutdown() {
|
|
1071
|
+
console.log("\n Shutting down...");
|
|
1072
|
+
cleanup(watcher, server);
|
|
1073
|
+
process.exit(0);
|
|
1074
|
+
}
|
|
1075
|
+
process.on("SIGINT", shutdown);
|
|
1076
|
+
process.on("SIGTERM", shutdown);
|
|
1077
|
+
}
|
|
1078
|
+
function cleanup(watcher, server) {
|
|
1079
|
+
if (watcher) watcher.stop();
|
|
1080
|
+
if (server && !server.killed) {
|
|
1081
|
+
server.kill("SIGTERM");
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
function getVersion() {
|
|
1085
|
+
try {
|
|
1086
|
+
const pkgPath = join2(pkgRoot, "package.json");
|
|
1087
|
+
if (existsSync2(pkgPath)) {
|
|
1088
|
+
const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
|
|
1089
|
+
return pkg.version || "0.0.0";
|
|
1090
|
+
}
|
|
1091
|
+
} catch {
|
|
1092
|
+
}
|
|
1093
|
+
return "0.0.0";
|
|
1094
|
+
}
|
|
1095
|
+
function openBrowser(url) {
|
|
1096
|
+
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
1097
|
+
exec(`${cmd} ${url}`, () => {
|
|
1098
|
+
});
|
|
1099
|
+
}
|
|
1100
|
+
main().catch((err) => {
|
|
1101
|
+
console.error("Fatal error:", err);
|
|
1102
|
+
process.exit(1);
|
|
1103
|
+
});
|
|
1104
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vYmluL2NsaS50cyIsICIuLi8uLi9jb2xsZWN0b3IvaW5kZXhlci50cyIsICIuLi8uLi9saWIvZGIvc2NoZW1hLnRzIiwgIi4uLy4uL2NvbGxlY3Rvci9tb2RlbC1jb250ZXh0LnRzIiwgIi4uLy4uL2NvbGxlY3Rvci9jbGF1ZGUtY29kZS9wYXJzZXIudHMiLCAiLi4vLi4vY29sbGVjdG9yL3BpL3BhcnNlci50cyIsICIuLi8uLi9jb2xsZWN0b3Ivd2F0Y2hlci50cyIsICIuLi8uLi9saWIvZGIvaW5kZXgudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbIi8qKlxuICogYWdlbnRsZW5zIENMSSBcdTIwMTQgc2luZ2xlIGNvbW1hbmQgdG8gaW5kZXggc2Vzc2lvbnMsIHdhdGNoIGZvciBuZXcgb25lcywgYW5kIHNlcnZlIHRoZSBkYXNoYm9hcmQuXG4gKlxuICogVXNhZ2U6XG4gKiAgIG5weCBhZ2VudGxlbnMgICAgICAgICAgICAgICAgICAgICAjIHN0YXJ0IGV2ZXJ5dGhpbmcgb24gOjMzMzNcbiAqICAgbnB4IGFnZW50bGVucyAtLXBvcnQgNDAwMCAgICAgICAgICMgY3VzdG9tIHBvcnRcbiAqICAgbnB4IGFnZW50bGVucyAtLWRhdGEgfi9teS1kYXRhICAgICMgY3VzdG9tIGRhdGEgZGlyZWN0b3J5XG4gKiAgIG5weCBhZ2VudGxlbnMgLS1uby1vcGVuICAgICAgICAgICAjIGRvbid0IGF1dG8tb3BlbiBicm93c2VyXG4gKi9cblxuaW1wb3J0IHsgam9pbiwgZGlybmFtZSwgcmVzb2x2ZSB9IGZyb20gXCJwYXRoXCI7XG5pbXBvcnQgeyBleGlzdHNTeW5jLCBta2RpclN5bmMsIHJlYWRGaWxlU3luYyB9IGZyb20gXCJmc1wiO1xuaW1wb3J0IHsgaG9tZWRpciB9IGZyb20gXCJvc1wiO1xuaW1wb3J0IHsgZmlsZVVSTFRvUGF0aCB9IGZyb20gXCJ1cmxcIjtcbmltcG9ydCB7IHNwYXduLCBleGVjIH0gZnJvbSBcImNoaWxkX3Byb2Nlc3NcIjtcbmltcG9ydCB7IGNyZWF0ZVJlcXVpcmUgfSBmcm9tIFwibW9kdWxlXCI7XG5pbXBvcnQgeyBpbmRleFNlc3Npb25zIH0gZnJvbSBcIi4uL2NvbGxlY3Rvci9pbmRleGVyXCI7XG5pbXBvcnQgeyBjcmVhdGVXYXRjaGVyLCB0eXBlIFdhdGNoZXIgfSBmcm9tIFwiLi4vY29sbGVjdG9yL3dhdGNoZXJcIjtcbmltcG9ydCB7IGdldERiIH0gZnJvbSBcIi4uL2xpYi9kYi9pbmRleFwiO1xuXG4vLyAtLS0gUGFyc2UgQ0xJIGFyZ3MgLS0tXG5cbmNvbnN0IGFyZ3MgPSBwcm9jZXNzLmFyZ3Yuc2xpY2UoMik7XG5cbmZ1bmN0aW9uIGdldEZsYWcobmFtZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gIHJldHVybiBhcmdzLmluY2x1ZGVzKGAtLSR7bmFtZX1gKTtcbn1cblxuZnVuY3Rpb24gZ2V0RmxhZ1ZhbHVlKG5hbWU6IHN0cmluZyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IGlkeCA9IGFyZ3MuaW5kZXhPZihgLS0ke25hbWV9YCk7XG4gIGlmIChpZHggPj0gMCAmJiBpZHggKyAxIDwgYXJncy5sZW5ndGgpIHJldHVybiBhcmdzW2lkeCArIDFdO1xuICByZXR1cm4gdW5kZWZpbmVkO1xufVxuXG5pZiAoZ2V0RmxhZyhcImhlbHBcIikgfHwgZ2V0RmxhZyhcImhcIikpIHtcbiAgY29uc29sZS5sb2coYFxuICBhZ2VudGxlbnMgXHUyMDE0IG9ic2VydmFiaWxpdHkgZm9yIEFJIGNvZGluZyBhZ2VudHNcblxuICBVc2FnZTpcbiAgICBucHggYWdlbnRsZW5zIFtvcHRpb25zXVxuXG4gIE9wdGlvbnM6XG4gICAgLS1wb3J0IDxudW1iZXI+ICAgIFBvcnQgZm9yIHRoZSBkYXNoYm9hcmQgKGRlZmF1bHQ6IDMzMzMpXG4gICAgLS1kYXRhIDxwYXRoPiAgICAgIERhdGEgZGlyZWN0b3J5IGZvciB0aGUgU1FMaXRlIERCIChkZWZhdWx0OiB+Ly5hZ2VudGxlbnMpXG4gICAgLS1uby1vcGVuICAgICAgICAgIERvbid0IGF1dG8tb3BlbiB0aGUgYnJvd3NlclxuICAgIC0taGVscCwgLWggICAgICAgICBTaG93IHRoaXMgaGVscCBtZXNzYWdlXG5gKTtcbiAgcHJvY2Vzcy5leGl0KDApO1xufVxuXG5jb25zdCBwb3J0ID0gcGFyc2VJbnQoZ2V0RmxhZ1ZhbHVlKFwicG9ydFwiKSB8fCBcIjMzMzNcIiwgMTApO1xuY29uc3QgZGF0YURpciA9IGdldEZsYWdWYWx1ZShcImRhdGFcIikgfHwgam9pbihob21lZGlyKCksIFwiLmFnZW50bGVuc1wiKTtcbmNvbnN0IG5vT3BlbiA9IGdldEZsYWcoXCJuby1vcGVuXCIpO1xuY29uc3QgZGJQYXRoID0gam9pbihkYXRhRGlyLCBcImFnZW50bGVucy5kYlwiKTtcblxuLy8gLS0tIFJlc29sdmUgcGFja2FnZSByb290ICh3aGVyZSAubmV4dC8gbGl2ZXMpIC0tLVxuXG5jb25zdCBfX2ZpbGVuYW1lID0gZmlsZVVSTFRvUGF0aChpbXBvcnQubWV0YS51cmwpO1xuY29uc3QgX19kaXJuYW1lID0gZGlybmFtZShfX2ZpbGVuYW1lKTtcbi8vIEluIHByb2R1Y3Rpb24gKGRpc3QvYmluL2FnZW50bGVucy5tanMpLCBwYWNrYWdlIHJvb3QgaXMgLi4vLi4vXG4vLyBJbiBkZXYgKGJpbi9jbGkudHMpLCBwYWNrYWdlIHJvb3QgaXMgLi4vXG5jb25zdCBwa2dSb290ID0gZXhpc3RzU3luYyhqb2luKF9fZGlybmFtZSwgXCIuLlwiLCBcIi5uZXh0XCIpKVxuICA/IHJlc29sdmUoX19kaXJuYW1lLCBcIi4uXCIpXG4gIDogcmVzb2x2ZShfX2Rpcm5hbWUsIFwiLi5cIiwgXCIuLlwiKTtcblxuLy8gLS0tIFNlc3Npb24gc291cmNlIGRpcmVjdG9yaWVzIC0tLVxuXG5jb25zdCBjbGF1ZGVQcm9qZWN0c0RpciA9IGpvaW4oaG9tZWRpcigpLCBcIi5jbGF1ZGVcIiwgXCJwcm9qZWN0c1wiKTtcbmNvbnN0IHBpU2Vzc2lvbnNEaXIgPSBqb2luKGhvbWVkaXIoKSwgXCIucGlcIiwgXCJhZ2VudFwiLCBcInNlc3Npb25zXCIpO1xuXG4vLyAtLS0gTWFpbiAtLS1cblxuYXN5bmMgZnVuY3Rpb24gbWFpbigpIHtcbiAgLy8gRW5zdXJlIGRhdGEgZGlyZWN0b3J5IGV4aXN0c1xuICBpZiAoIWV4aXN0c1N5bmMoZGF0YURpcikpIHtcbiAgICBta2RpclN5bmMoZGF0YURpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gIH1cblxuICAvLyBTZXQgZW52IGZvciB0aGUgTmV4dC5qcyBzZXJ2ZXIgcHJvY2Vzc1xuICBwcm9jZXNzLmVudi5BR0VOVExFTlNfREJfUEFUSCA9IGRiUGF0aDtcblxuICBjb25zb2xlLmxvZyhgXG4gIFxceDFiWzFtYWdlbnRsZW5zXFx4MWJbMG0gdiR7Z2V0VmVyc2lvbigpfVxuXG4gIFx1MjVCOCBEYXNoYm9hcmQ6ICAgXFx4MWJbMzZtaHR0cDovL2xvY2FsaG9zdDoke3BvcnR9XFx4MWJbMG1cbiAgXHUyNUI4IERhdGE6ICAgICAgICAke2RiUGF0aH1cbiAgXHUyNUI4IFdhdGNoaW5nOiAgICAke2NsYXVkZVByb2plY3RzRGlyfVxuICAgICAgICAgICAgICAgICAke3BpU2Vzc2lvbnNEaXJ9XG5gKTtcblxuICAvLyAtLS0gSW5pdGlhbCBpbmRleCAtLS1cblxuICBjb25zdCBkYiA9IGdldERiKCk7XG4gIGNvbnN0IHN0YXJ0VGltZSA9IERhdGUubm93KCk7XG5cbiAgcHJvY2Vzcy5zdGRvdXQud3JpdGUoXCIgIEluZGV4aW5nIHNlc3Npb25zLi4uXCIpO1xuICBjb25zdCByZXN1bHQgPSBpbmRleFNlc3Npb25zKGRiLCB7IGNsYXVkZVByb2plY3RzRGlyLCBwaVNlc3Npb25zRGlyIH0pO1xuICBjb25zdCBlbGFwc2VkID0gKChEYXRlLm5vdygpIC0gc3RhcnRUaW1lKSAvIDEwMDApLnRvRml4ZWQoMSk7XG5cbiAgY29uc3QgdG90YWwgPSByZXN1bHQuaW1wb3J0ZWQgKyByZXN1bHQuc2tpcHBlZDtcbiAgY29uc29sZS5sb2coXG4gICAgYCBmb3VuZCAke3RvdGFsfSBzZXNzaW9uJHt0b3RhbCAhPT0gMSA/IFwic1wiIDogXCJcIn0sICR7cmVzdWx0LmltcG9ydGVkfSBuZXcgKCR7ZWxhcHNlZH1zKWAsXG4gICk7XG5cbiAgaWYgKHJlc3VsdC5lcnJvcnMubGVuZ3RoID4gMCkge1xuICAgIGNvbnNvbGUubG9nKGAgIFx1MjZBMCAke3Jlc3VsdC5lcnJvcnMubGVuZ3RofSBlcnJvciR7cmVzdWx0LmVycm9ycy5sZW5ndGggIT09IDEgPyBcInNcIiA6IFwiXCJ9YCk7XG4gIH1cblxuICAvLyAtLS0gU3RhcnQgd2F0Y2hlciAtLS1cblxuICBjb25zdCB3YXRjaGVyID0gY3JlYXRlV2F0Y2hlcihkYiwge1xuICAgIGNsYXVkZVByb2plY3RzRGlyLFxuICAgIHBpU2Vzc2lvbnNEaXIsXG4gICAgcG9sbEludGVydmFsTXM6IDUwMDAsXG4gIH0pO1xuXG4gIGNvbnNvbGUubG9nKFwiICBXYXRjaGluZyBmb3IgbmV3IHNlc3Npb25zLi4uXFxuXCIpO1xuXG4gIC8vIC0tLSBTdGFydCBOZXh0LmpzIHNlcnZlciAtLS1cblxuICBjb25zdCByZXF1aXJlID0gY3JlYXRlUmVxdWlyZShpbXBvcnQubWV0YS51cmwpO1xuICBjb25zdCBuZXh0QmluID0gcmVxdWlyZS5yZXNvbHZlKFwibmV4dC9kaXN0L2Jpbi9uZXh0XCIpO1xuXG4gIGNvbnN0IHNlcnZlciA9IHNwYXduKHByb2Nlc3MuZXhlY1BhdGgsIFtuZXh0QmluLCBcInN0YXJ0XCIsIFwiLS1wb3J0XCIsIFN0cmluZyhwb3J0KV0sIHtcbiAgICBjd2Q6IHBrZ1Jvb3QsXG4gICAgZW52OiB7XG4gICAgICAuLi5wcm9jZXNzLmVudixcbiAgICAgIEFHRU5UTEVOU19EQl9QQVRIOiBkYlBhdGgsXG4gICAgICBQT1JUOiBTdHJpbmcocG9ydCksXG4gICAgICBIT1NUTkFNRTogXCJsb2NhbGhvc3RcIixcbiAgICB9LFxuICAgIHN0ZGlvOiBbXCJpZ25vcmVcIiwgXCJwaXBlXCIsIFwicGlwZVwiXSxcbiAgfSk7XG5cbiAgbGV0IHNlcnZlclJlYWR5ID0gZmFsc2U7XG5cbiAgc2VydmVyLnN0ZG91dD8ub24oXCJkYXRhXCIsIChkYXRhOiBCdWZmZXIpID0+IHtcbiAgICBjb25zdCB0ZXh0ID0gZGF0YS50b1N0cmluZygpLnRyaW0oKTtcbiAgICBpZiAodGV4dCAmJiAhc2VydmVyUmVhZHkpIHtcbiAgICAgIHNlcnZlclJlYWR5ID0gdHJ1ZTtcbiAgICAgIGlmICghbm9PcGVuKSB7XG4gICAgICAgIG9wZW5Ccm93c2VyKGBodHRwOi8vbG9jYWxob3N0OiR7cG9ydH1gKTtcbiAgICAgIH1cbiAgICB9XG4gIH0pO1xuXG4gIHNlcnZlci5zdGRlcnI/Lm9uKFwiZGF0YVwiLCAoZGF0YTogQnVmZmVyKSA9PiB7XG4gICAgY29uc3QgdGV4dCA9IGRhdGEudG9TdHJpbmcoKS50cmltKCk7XG4gICAgaWYgKHRleHQpIHtcbiAgICAgIC8vIEZpbHRlciBvdXQgbm9pc3kgTmV4dC5qcyB3YXJuaW5nc1xuICAgICAgaWYgKCF0ZXh0LmluY2x1ZGVzKFwiRXhwZXJpbWVudGFsV2FybmluZ1wiKSkge1xuICAgICAgICBjb25zb2xlLmVycm9yKGAgIFtzZXJ2ZXJdICR7dGV4dH1gKTtcbiAgICAgIH1cbiAgICB9XG4gIH0pO1xuXG4gIHNlcnZlci5vbihcImVycm9yXCIsIChlcnIpID0+IHtcbiAgICBjb25zb2xlLmVycm9yKGAgIEZhaWxlZCB0byBzdGFydCBzZXJ2ZXI6ICR7ZXJyLm1lc3NhZ2V9YCk7XG4gICAgY2xlYW51cCh3YXRjaGVyLCBzZXJ2ZXIpO1xuICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgfSk7XG5cbiAgc2VydmVyLm9uKFwiZXhpdFwiLCAoY29kZSkgPT4ge1xuICAgIGlmIChjb2RlICE9PSAwICYmIGNvZGUgIT09IG51bGwpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoYCAgU2VydmVyIGV4aXRlZCB3aXRoIGNvZGUgJHtjb2RlfWApO1xuICAgIH1cbiAgICBjbGVhbnVwKHdhdGNoZXIsIG51bGwpO1xuICAgIHByb2Nlc3MuZXhpdChjb2RlID8/IDApO1xuICB9KTtcblxuICAvLyAtLS0gR3JhY2VmdWwgc2h1dGRvd24gLS0tXG5cbiAgZnVuY3Rpb24gc2h1dGRvd24oKSB7XG4gICAgY29uc29sZS5sb2coXCJcXG4gIFNodXR0aW5nIGRvd24uLi5cIik7XG4gICAgY2xlYW51cCh3YXRjaGVyLCBzZXJ2ZXIpO1xuICAgIHByb2Nlc3MuZXhpdCgwKTtcbiAgfVxuXG4gIHByb2Nlc3Mub24oXCJTSUdJTlRcIiwgc2h1dGRvd24pO1xuICBwcm9jZXNzLm9uKFwiU0lHVEVSTVwiLCBzaHV0ZG93bik7XG59XG5cbmZ1bmN0aW9uIGNsZWFudXAod2F0Y2hlcjogV2F0Y2hlciB8IG51bGwsIHNlcnZlcjogUmV0dXJuVHlwZTx0eXBlb2Ygc3Bhd24+IHwgbnVsbCkge1xuICBpZiAod2F0Y2hlcikgd2F0Y2hlci5zdG9wKCk7XG4gIGlmIChzZXJ2ZXIgJiYgIXNlcnZlci5raWxsZWQpIHtcbiAgICBzZXJ2ZXIua2lsbChcIlNJR1RFUk1cIik7XG4gIH1cbn1cblxuZnVuY3Rpb24gZ2V0VmVyc2lvbigpOiBzdHJpbmcge1xuICB0cnkge1xuICAgIGNvbnN0IHBrZ1BhdGggPSBqb2luKHBrZ1Jvb3QsIFwicGFja2FnZS5qc29uXCIpO1xuICAgIGlmIChleGlzdHNTeW5jKHBrZ1BhdGgpKSB7XG4gICAgICBjb25zdCBwa2cgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhwa2dQYXRoLCBcInV0Zi04XCIpKTtcbiAgICAgIHJldHVybiBwa2cudmVyc2lvbiB8fCBcIjAuMC4wXCI7XG4gICAgfVxuICB9IGNhdGNoIHt9XG4gIHJldHVybiBcIjAuMC4wXCI7XG59XG5cbmZ1bmN0aW9uIG9wZW5Ccm93c2VyKHVybDogc3RyaW5nKSB7XG4gIGNvbnN0IGNtZCA9XG4gICAgcHJvY2Vzcy5wbGF0Zm9ybSA9PT0gXCJkYXJ3aW5cIiA/IFwib3BlblwiIDogcHJvY2Vzcy5wbGF0Zm9ybSA9PT0gXCJ3aW4zMlwiID8gXCJzdGFydFwiIDogXCJ4ZGctb3BlblwiO1xuXG4gIGV4ZWMoYCR7Y21kfSAke3VybH1gLCAoKSA9PiB7XG4gICAgLy8gU2lsZW50bHkgaWdub3JlIGVycm9ycyAoZS5nLiwgbm8gZGlzcGxheSBzZXJ2ZXIpXG4gIH0pO1xufVxuXG5tYWluKCkuY2F0Y2goKGVycikgPT4ge1xuICBjb25zb2xlLmVycm9yKFwiRmF0YWwgZXJyb3I6XCIsIGVycik7XG4gIHByb2Nlc3MuZXhpdCgxKTtcbn0pO1xuIiwgIi8qKlxuICogVW5pZmllZCBzZXNzaW9uIGluZGV4ZXI6IGRpc2NvdmVycyBhbmQgaW1wb3J0cyBhZ2VudCBzZXNzaW9ucyBpbnRvIGFnZW50bGVucyBEQi5cbiAqL1xuXG5pbXBvcnQgeyByZWFkZGlyU3luYywgcmVhZEZpbGVTeW5jLCBleGlzdHNTeW5jIH0gZnJvbSBcImZzXCI7XG5pbXBvcnQgeyBqb2luIH0gZnJvbSBcInBhdGhcIjtcbmltcG9ydCB7IGV4ZWNTeW5jIH0gZnJvbSBcImNoaWxkX3Byb2Nlc3NcIjtcbmltcG9ydCB7IHVzZXJJbmZvIH0gZnJvbSBcIm9zXCI7XG5pbXBvcnQgdHlwZSB7IEJldHRlclNRTGl0ZTNEYXRhYmFzZSB9IGZyb20gXCJkcml6emxlLW9ybS9iZXR0ZXItc3FsaXRlM1wiO1xuaW1wb3J0IHsgZXEgfSBmcm9tIFwiZHJpenpsZS1vcm1cIjtcbmltcG9ydCB7IHNlc3Npb25zLCBpbnNlcnRTZXNzaW9uLCBpbnNlcnRFdmVudCwgdXBzZXJ0UHVsbFJlcXVlc3QgfSBmcm9tIFwiQC9saWIvZGIvc2NoZW1hXCI7XG5pbXBvcnQgeyBwYXJzZUNsYXVkZUNvZGVTZXNzaW9uIH0gZnJvbSBcIi4vY2xhdWRlLWNvZGUvcGFyc2VyXCI7XG5pbXBvcnQgeyBwYXJzZVBpU2Vzc2lvbiB9IGZyb20gXCIuL3BpL3BhcnNlclwiO1xuaW1wb3J0IHR5cGUgeyBQYXJzZWRTZXNzaW9uIH0gZnJvbSBcIi4vY2xhdWRlLWNvZGUvcGFyc2VyXCI7XG5cbi8qKiBEZXRlY3QgdXNlciBpZGVudGl0eSBmcm9tIGdpdCBjb25maWcgb3IgT1MsIGNhY2hlZC4gKi9cbmxldCBfY2FjaGVkVXNlcklkOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbmV4cG9ydCBmdW5jdGlvbiBkZXRlY3RVc2VySWQoKTogc3RyaW5nIHtcbiAgaWYgKF9jYWNoZWRVc2VySWQpIHJldHVybiBfY2FjaGVkVXNlcklkO1xuICB0cnkge1xuICAgIF9jYWNoZWRVc2VySWQgPSBleGVjU3luYyhcImdpdCBjb25maWcgdXNlci5lbWFpbFwiLCB7IGVuY29kaW5nOiBcInV0Zi04XCIgfSkudHJpbSgpO1xuICAgIGlmIChfY2FjaGVkVXNlcklkKSByZXR1cm4gX2NhY2hlZFVzZXJJZDtcbiAgfSBjYXRjaCB7XG4gICAgLyogZ2l0IG5vdCBhdmFpbGFibGUgKi9cbiAgfVxuICBfY2FjaGVkVXNlcklkID0gdXNlckluZm8oKS51c2VybmFtZSB8fCBcInVua25vd25cIjtcbiAgcmV0dXJuIF9jYWNoZWRVc2VySWQ7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSW5kZXhPcHRpb25zIHtcbiAgLyoqIFBhdGggdG8gQ2xhdWRlIENvZGUgcHJvamVjdHMgZGlyZWN0b3J5IChkZWZhdWx0OiB+Ly5jbGF1ZGUvcHJvamVjdHMpICovXG4gIGNsYXVkZVByb2plY3RzRGlyPzogc3RyaW5nO1xuICAvKiogUGF0aCB0byBQaSBzZXNzaW9ucyBkaXJlY3RvcnkgKGRlZmF1bHQ6IH4vLnBpL2FnZW50L3Nlc3Npb25zKSAqL1xuICBwaVNlc3Npb25zRGlyPzogc3RyaW5nO1xuICAvKiogRmlsdGVyIHRvIGEgc3BlY2lmaWMgaGFybmVzcyAqL1xuICBoYXJuZXNzPzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEluZGV4UmVzdWx0IHtcbiAgaW1wb3J0ZWQ6IG51bWJlcjtcbiAgc2tpcHBlZDogbnVtYmVyO1xuICBlcnJvcnM6IHN0cmluZ1tdO1xufVxuXG4vKipcbiAqIERpc2NvdmVyIENsYXVkZSBDb2RlIHNlc3Npb24gSlNPTkwgZmlsZXMgaW4gdGhlIHByb2plY3RzIGRpcmVjdG9yeS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRpc2NvdmVyQ2xhdWRlQ29kZVNlc3Npb25zKHByb2plY3RzRGlyOiBzdHJpbmcpOiBzdHJpbmdbXSB7XG4gIGlmICghZXhpc3RzU3luYyhwcm9qZWN0c0RpcikpIHJldHVybiBbXTtcblxuICBjb25zdCBmaWxlczogc3RyaW5nW10gPSBbXTtcbiAgdHJ5IHtcbiAgICBjb25zdCBwcm9qZWN0RGlycyA9IHJlYWRkaXJTeW5jKHByb2plY3RzRGlyLCB7IHdpdGhGaWxlVHlwZXM6IHRydWUgfSk7XG4gICAgZm9yIChjb25zdCBkaXIgb2YgcHJvamVjdERpcnMpIHtcbiAgICAgIGlmICghZGlyLmlzRGlyZWN0b3J5KCkpIGNvbnRpbnVlO1xuICAgICAgY29uc3QgZGlyUGF0aCA9IGpvaW4ocHJvamVjdHNEaXIsIGRpci5uYW1lKTtcbiAgICAgIGNvbnN0IGRpckVudHJpZXMgPSByZWFkZGlyU3luYyhkaXJQYXRoLCB7IHdpdGhGaWxlVHlwZXM6IHRydWUgfSk7XG4gICAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIGRpckVudHJpZXMpIHtcbiAgICAgICAgaWYgKGVudHJ5LmlzRmlsZSgpICYmIGVudHJ5Lm5hbWUuZW5kc1dpdGgoXCIuanNvbmxcIikpIHtcbiAgICAgICAgICBmaWxlcy5wdXNoKGpvaW4oZGlyUGF0aCwgZW50cnkubmFtZSkpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9IGNhdGNoIHtcbiAgICAvLyBEaXJlY3Rvcnkgbm90IHJlYWRhYmxlXG4gIH1cbiAgcmV0dXJuIGZpbGVzO1xufVxuXG4vKipcbiAqIERpc2NvdmVyIFBpIHNlc3Npb24gSlNPTkwgZmlsZXMgaW4gdGhlIHNlc3Npb25zIGRpcmVjdG9yeS5cbiAqIFBpIHN0b3JlcyBzZXNzaW9ucyBhdCB+Ly5waS9hZ2VudC9zZXNzaW9ucy88cHJvamVjdC1kaXI+Lzx0aW1lc3RhbXA+Xzx1dWlkPi5qc29ubFxuICovXG5leHBvcnQgZnVuY3Rpb24gZGlzY292ZXJQaVNlc3Npb25zKHNlc3Npb25zRGlyOiBzdHJpbmcpOiBzdHJpbmdbXSB7XG4gIGlmICghZXhpc3RzU3luYyhzZXNzaW9uc0RpcikpIHJldHVybiBbXTtcblxuICBjb25zdCBmaWxlczogc3RyaW5nW10gPSBbXTtcbiAgdHJ5IHtcbiAgICBjb25zdCBwcm9qZWN0RGlycyA9IHJlYWRkaXJTeW5jKHNlc3Npb25zRGlyLCB7IHdpdGhGaWxlVHlwZXM6IHRydWUgfSk7XG4gICAgZm9yIChjb25zdCBkaXIgb2YgcHJvamVjdERpcnMpIHtcbiAgICAgIGlmICghZGlyLmlzRGlyZWN0b3J5KCkpIGNvbnRpbnVlO1xuICAgICAgY29uc3QgZGlyUGF0aCA9IGpvaW4oc2Vzc2lvbnNEaXIsIGRpci5uYW1lKTtcbiAgICAgIGNvbnN0IGRpckVudHJpZXMgPSByZWFkZGlyU3luYyhkaXJQYXRoLCB7IHdpdGhGaWxlVHlwZXM6IHRydWUgfSk7XG4gICAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIGRpckVudHJpZXMpIHtcbiAgICAgICAgaWYgKGVudHJ5LmlzRmlsZSgpICYmIGVudHJ5Lm5hbWUuZW5kc1dpdGgoXCIuanNvbmxcIikpIHtcbiAgICAgICAgICBmaWxlcy5wdXNoKGpvaW4oZGlyUGF0aCwgZW50cnkubmFtZSkpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9IGNhdGNoIHtcbiAgICAvLyBEaXJlY3Rvcnkgbm90IHJlYWRhYmxlXG4gIH1cbiAgcmV0dXJuIGZpbGVzO1xufVxuXG4vKipcbiAqIEltcG9ydCBhIHBhcnNlZCBzZXNzaW9uIGludG8gdGhlIERCLiBSZXR1cm5zIHRydWUgaWYgaW1wb3J0ZWQsIGZhbHNlIGlmIHNraXBwZWQuXG4gKi9cbmZ1bmN0aW9uIGltcG9ydFBhcnNlZFNlc3Npb24oXG4gIGRiOiBCZXR0ZXJTUUxpdGUzRGF0YWJhc2UsXG4gIHBhcnNlZDogUGFyc2VkU2Vzc2lvbixcbiAgcmVzdWx0OiBJbmRleFJlc3VsdCxcbik6IGJvb2xlYW4ge1xuICBpZiAoIXBhcnNlZC5zZXNzaW9uSWQpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvLyBDaGVjayBpZiBhbHJlYWR5IGltcG9ydGVkXG4gIGNvbnN0IGV4aXN0aW5nID0gZGIuc2VsZWN0KCkuZnJvbShzZXNzaW9ucykud2hlcmUoZXEoc2Vzc2lvbnMuaWQsIHBhcnNlZC5zZXNzaW9uSWQpKS5nZXQoKTtcbiAgaWYgKGV4aXN0aW5nKSB7XG4gICAgcmVzdWx0LnNraXBwZWQrKztcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvLyBJbnNlcnQgc2Vzc2lvblxuICBjb25zdCB1c2VySWQgPSBwYXJzZWQudXNlcklkIHx8IGRldGVjdFVzZXJJZCgpO1xuICBpbnNlcnRTZXNzaW9uKGRiLCB7XG4gICAgaWQ6IHBhcnNlZC5zZXNzaW9uSWQsXG4gICAgdGVhbUlkOiBcImRlZmF1bHRcIixcbiAgICB1c2VySWQsXG4gICAgcHJvamVjdDogcGFyc2VkLnByb2plY3QsXG4gICAgZ2l0UmVwbzogbnVsbCxcbiAgICBnaXRCcmFuY2g6IHBhcnNlZC5naXRCcmFuY2gsXG4gICAgcGlWZXJzaW9uOiBwYXJzZWQudmVyc2lvbixcbiAgICBza2lsbHNVc2VkOiBbXSxcbiAgICBtb2RlbDogcGFyc2VkLm1vZGVsLFxuICAgIGhhcm5lc3M6IHBhcnNlZC5oYXJuZXNzLFxuICAgIHN0YXJ0ZWRBdDogcGFyc2VkLnN0YXJ0ZWRBdCxcbiAgfSk7XG5cbiAgLy8gVXBkYXRlIHNlc3Npb24gZW5kIGlmIHdlIGhhdmUgaXRcbiAgaWYgKHBhcnNlZC5lbmRlZEF0KSB7XG4gICAgZGIudXBkYXRlKHNlc3Npb25zKVxuICAgICAgLnNldCh7IGVuZGVkQXQ6IHBhcnNlZC5lbmRlZEF0LCBzdGF0dXM6IFwiY29tcGxldGVkXCIgfSlcbiAgICAgIC53aGVyZShlcShzZXNzaW9ucy5pZCwgcGFyc2VkLnNlc3Npb25JZCkpXG4gICAgICAucnVuKCk7XG4gIH1cblxuICAvLyBJbnNlcnQgYWxsIGV2ZW50c1xuICBmb3IgKGNvbnN0IGV2ZW50IG9mIHBhcnNlZC5ldmVudHMpIHtcbiAgICBpbnNlcnRFdmVudChkYiwge1xuICAgICAgc2Vzc2lvbklkOiBwYXJzZWQuc2Vzc2lvbklkLFxuICAgICAgZXZlbnRUeXBlOiBldmVudC5ldmVudFR5cGUsXG4gICAgICB0aW1lc3RhbXA6IGV2ZW50LnRpbWVzdGFtcCxcbiAgICAgIHBheWxvYWQ6IGV2ZW50LnBheWxvYWQsXG4gICAgfSk7XG5cbiAgICAvLyBQb3B1bGF0ZSBwdWxsX3JlcXVlc3RzIHRhYmxlIGZyb20gcHJfb3BlbmVkIGV2ZW50c1xuICAgIGlmIChldmVudC5ldmVudFR5cGUgPT09IFwicHJfb3BlbmVkXCIgJiYgZXZlbnQucGF5bG9hZC5wcl91cmwpIHtcbiAgICAgIHVwc2VydFB1bGxSZXF1ZXN0KGRiLCB7XG4gICAgICAgIHNlc3Npb25JZDogcGFyc2VkLnNlc3Npb25JZCxcbiAgICAgICAgcmVwbzogZXZlbnQucGF5bG9hZC5yZXBvIHx8IFwiXCIsXG4gICAgICAgIGJyYW5jaDogcGFyc2VkLmdpdEJyYW5jaCB8fCBcIlwiLFxuICAgICAgICBwck51bWJlcjogZXZlbnQucGF5bG9hZC5wcl9udW1iZXIgfHwgMCxcbiAgICAgICAgcHJVcmw6IGV2ZW50LnBheWxvYWQucHJfdXJsLFxuICAgICAgICBwclRpdGxlOiBcIlwiLCAvLyBub3QgYXZhaWxhYmxlIGZyb20gYmFzaCBvdXRwdXRcbiAgICAgICAgc3RhdHVzOiBcIm9wZW5cIixcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIHJlc3VsdC5pbXBvcnRlZCsrO1xuICByZXR1cm4gdHJ1ZTtcbn1cblxuLyoqXG4gKiBJbXBvcnQgc2Vzc2lvbnMgZnJvbSBkaXNjb3ZlcmVkIGZpbGVzIGludG8gdGhlIGFnZW50bGVucyBEQi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGluZGV4U2Vzc2lvbnMoZGI6IEJldHRlclNRTGl0ZTNEYXRhYmFzZSwgb3B0aW9uczogSW5kZXhPcHRpb25zID0ge30pOiBJbmRleFJlc3VsdCB7XG4gIGNvbnN0IHJlc3VsdDogSW5kZXhSZXN1bHQgPSB7IGltcG9ydGVkOiAwLCBza2lwcGVkOiAwLCBlcnJvcnM6IFtdIH07XG4gIGNvbnN0IGhhcm5lc3MgPSBvcHRpb25zLmhhcm5lc3M7XG5cbiAgLy8gQ2xhdWRlIENvZGUgc2Vzc2lvbnNcbiAgaWYgKCFoYXJuZXNzIHx8IGhhcm5lc3MgPT09IFwiY2xhdWRlLWNvZGVcIikge1xuICAgIGNvbnN0IHByb2plY3RzRGlyID1cbiAgICAgIG9wdGlvbnMuY2xhdWRlUHJvamVjdHNEaXIgfHwgam9pbihwcm9jZXNzLmVudi5IT01FIHx8IFwiflwiLCBcIi5jbGF1ZGVcIiwgXCJwcm9qZWN0c1wiKTtcbiAgICBjb25zdCBmaWxlcyA9IGRpc2NvdmVyQ2xhdWRlQ29kZVNlc3Npb25zKHByb2plY3RzRGlyKTtcblxuICAgIGZvciAoY29uc3QgZmlsZVBhdGggb2YgZmlsZXMpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IGpzb25sID0gcmVhZEZpbGVTeW5jKGZpbGVQYXRoLCBcInV0Zi04XCIpO1xuICAgICAgICBjb25zdCBwYXJzZWQgPSBwYXJzZUNsYXVkZUNvZGVTZXNzaW9uKGpzb25sKTtcbiAgICAgICAgaWYgKCFwYXJzZWQuc2Vzc2lvbklkKSB7XG4gICAgICAgICAgcmVzdWx0LmVycm9ycy5wdXNoKGBObyBzZXNzaW9uIElEIGZvdW5kIGluICR7ZmlsZVBhdGh9YCk7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgaW1wb3J0UGFyc2VkU2Vzc2lvbihkYiwgcGFyc2VkLCByZXN1bHQpO1xuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIHJlc3VsdC5lcnJvcnMucHVzaChgRXJyb3IgcHJvY2Vzc2luZyAke2ZpbGVQYXRofTogJHtlcnJ9YCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gUGkgc2Vzc2lvbnNcbiAgaWYgKCFoYXJuZXNzIHx8IGhhcm5lc3MgPT09IFwicGlcIikge1xuICAgIGNvbnN0IHNlc3Npb25zRGlyID1cbiAgICAgIG9wdGlvbnMucGlTZXNzaW9uc0RpciB8fCBqb2luKHByb2Nlc3MuZW52LkhPTUUgfHwgXCJ+XCIsIFwiLnBpXCIsIFwiYWdlbnRcIiwgXCJzZXNzaW9uc1wiKTtcbiAgICBjb25zdCBmaWxlcyA9IGRpc2NvdmVyUGlTZXNzaW9ucyhzZXNzaW9uc0Rpcik7XG5cbiAgICBmb3IgKGNvbnN0IGZpbGVQYXRoIG9mIGZpbGVzKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBqc29ubCA9IHJlYWRGaWxlU3luYyhmaWxlUGF0aCwgXCJ1dGYtOFwiKTtcbiAgICAgICAgY29uc3QgZGlyTmFtZSA9IGpvaW4oZmlsZVBhdGgsIFwiLi5cIikuc3BsaXQoXCIvXCIpLnBvcCgpIHx8IFwiXCI7XG4gICAgICAgIGNvbnN0IHBhcnNlZCA9IHBhcnNlUGlTZXNzaW9uKGpzb25sLCBkaXJOYW1lKTtcbiAgICAgICAgaWYgKCFwYXJzZWQuc2Vzc2lvbklkKSB7XG4gICAgICAgICAgcmVzdWx0LmVycm9ycy5wdXNoKGBObyBzZXNzaW9uIElEIGZvdW5kIGluICR7ZmlsZVBhdGh9YCk7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgaW1wb3J0UGFyc2VkU2Vzc2lvbihkYiwgcGFyc2VkLCByZXN1bHQpO1xuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIHJlc3VsdC5lcnJvcnMucHVzaChgRXJyb3IgcHJvY2Vzc2luZyAke2ZpbGVQYXRofTogJHtlcnJ9YCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHJlc3VsdDtcbn1cbiIsICJpbXBvcnQgeyBzcWwsIGVxLCBhbmQsIGd0ZSwgbHRlLCBkZXNjLCBhc2MsIGNvdW50IH0gZnJvbSBcImRyaXp6bGUtb3JtXCI7XG5pbXBvcnQgeyBzcWxpdGVUYWJsZSwgdGV4dCwgaW50ZWdlciB9IGZyb20gXCJkcml6emxlLW9ybS9zcWxpdGUtY29yZVwiO1xuaW1wb3J0IHR5cGUgeyBCZXR0ZXJTUUxpdGUzRGF0YWJhc2UgfSBmcm9tIFwiZHJpenpsZS1vcm0vYmV0dGVyLXNxbGl0ZTNcIjtcblxuLy8gLS0tIFRhYmxlIERlZmluaXRpb25zIC0tLVxuXG5leHBvcnQgY29uc3Qgc2Vzc2lvbnMgPSBzcWxpdGVUYWJsZShcInNlc3Npb25zXCIsIHtcbiAgaWQ6IHRleHQoXCJpZFwiKS5wcmltYXJ5S2V5KCksXG4gIHRlYW1JZDogdGV4dChcInRlYW1faWRcIikubm90TnVsbCgpLFxuICB1c2VySWQ6IHRleHQoXCJ1c2VyX2lkXCIpLm5vdE51bGwoKSxcbiAgcHJvamVjdDogdGV4dChcInByb2plY3RcIikubm90TnVsbCgpLFxuICBnaXRSZXBvOiB0ZXh0KFwiZ2l0X3JlcG9cIiksXG4gIGdpdEJyYW5jaDogdGV4dChcImdpdF9icmFuY2hcIiksXG4gIHBpVmVyc2lvbjogdGV4dChcInBpX3ZlcnNpb25cIikubm90TnVsbCgpLmRlZmF1bHQoXCJcIiksXG4gIHNraWxsc1VzZWQ6IHRleHQoXCJza2lsbHNfdXNlZFwiKS5ub3ROdWxsKCkuZGVmYXVsdChcIltdXCIpLFxuICBtb2RlbDogdGV4dChcIm1vZGVsXCIpLFxuICBoYXJuZXNzOiB0ZXh0KFwiaGFybmVzc1wiKS5ub3ROdWxsKCkuZGVmYXVsdChcInBpXCIpLFxuICBzdGFydGVkQXQ6IHRleHQoXCJzdGFydGVkX2F0XCIpLm5vdE51bGwoKSxcbiAgZW5kZWRBdDogdGV4dChcImVuZGVkX2F0XCIpLFxuICBzdGF0dXM6IHRleHQoXCJzdGF0dXNcIikubm90TnVsbCgpLmRlZmF1bHQoXCJhY3RpdmVcIiksXG4gIGNyZWF0ZWRBdDogdGV4dChcImNyZWF0ZWRfYXRcIilcbiAgICAubm90TnVsbCgpXG4gICAgLmRlZmF1bHQoc3FsYChkYXRldGltZSgnbm93JykpYCksXG59KTtcblxuZXhwb3J0IGNvbnN0IGV2ZW50cyA9IHNxbGl0ZVRhYmxlKFwiZXZlbnRzXCIsIHtcbiAgaWQ6IGludGVnZXIoXCJpZFwiKS5wcmltYXJ5S2V5KHsgYXV0b0luY3JlbWVudDogdHJ1ZSB9KSxcbiAgc2Vzc2lvbklkOiB0ZXh0KFwic2Vzc2lvbl9pZFwiKS5ub3ROdWxsKCksXG4gIGV2ZW50VHlwZTogdGV4dChcImV2ZW50X3R5cGVcIikubm90TnVsbCgpLFxuICB0aW1lc3RhbXA6IHRleHQoXCJ0aW1lc3RhbXBcIikubm90TnVsbCgpLFxuICBwYXlsb2FkOiB0ZXh0KFwicGF5bG9hZFwiKS5ub3ROdWxsKCkuZGVmYXVsdChcInt9XCIpLFxuICBjcmVhdGVkQXQ6IHRleHQoXCJjcmVhdGVkX2F0XCIpXG4gICAgLm5vdE51bGwoKVxuICAgIC5kZWZhdWx0KHNxbGAoZGF0ZXRpbWUoJ25vdycpKWApLFxufSk7XG5cbmV4cG9ydCBjb25zdCBwdWxsUmVxdWVzdHMgPSBzcWxpdGVUYWJsZShcInB1bGxfcmVxdWVzdHNcIiwge1xuICBpZDogaW50ZWdlcihcImlkXCIpLnByaW1hcnlLZXkoeyBhdXRvSW5jcmVtZW50OiB0cnVlIH0pLFxuICBzZXNzaW9uSWQ6IHRleHQoXCJzZXNzaW9uX2lkXCIpLm5vdE51bGwoKSxcbiAgcmVwbzogdGV4dChcInJlcG9cIikubm90TnVsbCgpLFxuICBicmFuY2g6IHRleHQoXCJicmFuY2hcIikubm90TnVsbCgpLFxuICBwck51bWJlcjogaW50ZWdlcihcInByX251bWJlclwiKS5ub3ROdWxsKCksXG4gIHByVXJsOiB0ZXh0KFwicHJfdXJsXCIpLm5vdE51bGwoKSxcbiAgcHJUaXRsZTogdGV4dChcInByX3RpdGxlXCIpLm5vdE51bGwoKS5kZWZhdWx0KFwiXCIpLFxuICBzdGF0dXM6IHRleHQoXCJzdGF0dXNcIikubm90TnVsbCgpLmRlZmF1bHQoXCJvcGVuXCIpLFxuICBtZXJnZWRBdDogdGV4dChcIm1lcmdlZF9hdFwiKSxcbiAgcmV2aWV3c0FwcHJvdmVkOiBpbnRlZ2VyKFwicmV2aWV3c19hcHByb3ZlZFwiKS5ub3ROdWxsKCkuZGVmYXVsdCgwKSxcbiAgcmV2aWV3c0NoYW5nZXNSZXF1ZXN0ZWQ6IGludGVnZXIoXCJyZXZpZXdzX2NoYW5nZXNfcmVxdWVzdGVkXCIpLm5vdE51bGwoKS5kZWZhdWx0KDApLFxuICByZXZpZXdDb21tZW50czogaW50ZWdlcihcInJldmlld19jb21tZW50c1wiKS5ub3ROdWxsKCkuZGVmYXVsdCgwKSxcbiAgY29tbWl0c0FmdGVyUmV2aWV3OiBpbnRlZ2VyKFwiY29tbWl0c19hZnRlcl9yZXZpZXdcIikubm90TnVsbCgpLmRlZmF1bHQoMCksXG4gIGZpcnN0UmV2aWV3QXQ6IHRleHQoXCJmaXJzdF9yZXZpZXdfYXRcIiksXG4gIHRpbWVUb01lcmdlSG91cnM6IHRleHQoXCJ0aW1lX3RvX21lcmdlX2hvdXJzXCIpLCAvLyBzdG9yZWQgYXMgdGV4dCBmb3IgU1FMaXRlIHJlYWwgY29tcGF0XG4gIGNoZWNrZWRBdDogdGV4dChcImNoZWNrZWRfYXRcIiksXG4gIGNyZWF0ZWRBdDogdGV4dChcImNyZWF0ZWRfYXRcIilcbiAgICAubm90TnVsbCgpXG4gICAgLmRlZmF1bHQoc3FsYChkYXRldGltZSgnbm93JykpYCksXG59KTtcblxuLy8gLS0tIFR5cGVzIC0tLVxuXG5leHBvcnQgaW50ZXJmYWNlIFNlc3Npb25JbnB1dCB7XG4gIGlkOiBzdHJpbmc7XG4gIHRlYW1JZDogc3RyaW5nO1xuICB1c2VySWQ6IHN0cmluZztcbiAgcHJvamVjdDogc3RyaW5nO1xuICBnaXRSZXBvOiBzdHJpbmcgfCBudWxsO1xuICBnaXRCcmFuY2g6IHN0cmluZyB8IG51bGw7XG4gIHBpVmVyc2lvbjogc3RyaW5nO1xuICBza2lsbHNVc2VkOiBzdHJpbmdbXTtcbiAgbW9kZWw/OiBzdHJpbmcgfCBudWxsO1xuICBoYXJuZXNzPzogc3RyaW5nO1xuICBzdGFydGVkQXQ6IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBFdmVudElucHV0IHtcbiAgc2Vzc2lvbklkOiBzdHJpbmc7XG4gIGV2ZW50VHlwZTogc3RyaW5nO1xuICB0aW1lc3RhbXA6IHN0cmluZztcbiAgcGF5bG9hZDogb2JqZWN0O1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFNlc3Npb25Sb3cge1xuICBpZDogc3RyaW5nO1xuICB0ZWFtSWQ6IHN0cmluZztcbiAgdXNlcklkOiBzdHJpbmc7XG4gIHByb2plY3Q6IHN0cmluZztcbiAgZ2l0UmVwbzogc3RyaW5nIHwgbnVsbDtcbiAgZ2l0QnJhbmNoOiBzdHJpbmcgfCBudWxsO1xuICBwaVZlcnNpb246IHN0cmluZztcbiAgc2tpbGxzVXNlZDogc3RyaW5nW107XG4gIG1vZGVsOiBzdHJpbmcgfCBudWxsO1xuICBoYXJuZXNzOiBzdHJpbmc7XG4gIHN0YXJ0ZWRBdDogc3RyaW5nO1xuICBlbmRlZEF0OiBzdHJpbmcgfCBudWxsO1xuICBzdGF0dXM6IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBFdmVudFJvdyB7XG4gIGlkOiBudW1iZXI7XG4gIHNlc3Npb25JZDogc3RyaW5nO1xuICBldmVudFR5cGU6IHN0cmluZztcbiAgdGltZXN0YW1wOiBzdHJpbmc7XG4gIHBheWxvYWQ6IGFueTtcbn1cblxuLy8gLS0tIFF1ZXJ5IEhlbHBlcnMgLS0tXG5cbnR5cGUgREIgPSBCZXR0ZXJTUUxpdGUzRGF0YWJhc2U7XG5cbmV4cG9ydCBmdW5jdGlvbiBpbnNlcnRTZXNzaW9uKGRiOiBEQiwgaW5wdXQ6IFNlc3Npb25JbnB1dCk6IHZvaWQge1xuICBkYi5pbnNlcnQoc2Vzc2lvbnMpXG4gICAgLnZhbHVlcyh7XG4gICAgICBpZDogaW5wdXQuaWQsXG4gICAgICB0ZWFtSWQ6IGlucHV0LnRlYW1JZCxcbiAgICAgIHVzZXJJZDogaW5wdXQudXNlcklkLFxuICAgICAgcHJvamVjdDogaW5wdXQucHJvamVjdCxcbiAgICAgIGdpdFJlcG86IGlucHV0LmdpdFJlcG8sXG4gICAgICBnaXRCcmFuY2g6IGlucHV0LmdpdEJyYW5jaCxcbiAgICAgIHBpVmVyc2lvbjogaW5wdXQucGlWZXJzaW9uLFxuICAgICAgc2tpbGxzVXNlZDogSlNPTi5zdHJpbmdpZnkoaW5wdXQuc2tpbGxzVXNlZCksXG4gICAgICBtb2RlbDogaW5wdXQubW9kZWwsXG4gICAgICBoYXJuZXNzOiBpbnB1dC5oYXJuZXNzIHx8IFwicGlcIixcbiAgICAgIHN0YXJ0ZWRBdDogaW5wdXQuc3RhcnRlZEF0LFxuICAgIH0pXG4gICAgLnJ1bigpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gdXBkYXRlU2Vzc2lvbkVuZChkYjogREIsIHNlc3Npb25JZDogc3RyaW5nLCBlbmRlZEF0OiBzdHJpbmcsIHN0YXR1czogc3RyaW5nKTogdm9pZCB7XG4gIGRiLnVwZGF0ZShzZXNzaW9ucykuc2V0KHsgZW5kZWRBdCwgc3RhdHVzIH0pLndoZXJlKGVxKHNlc3Npb25zLmlkLCBzZXNzaW9uSWQpKS5ydW4oKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHVwZGF0ZVNlc3Npb25Nb2RlbChkYjogREIsIHNlc3Npb25JZDogc3RyaW5nLCBtb2RlbDogc3RyaW5nKTogdm9pZCB7XG4gIGRiLnVwZGF0ZShzZXNzaW9ucykuc2V0KHsgbW9kZWwgfSkud2hlcmUoZXEoc2Vzc2lvbnMuaWQsIHNlc3Npb25JZCkpLnJ1bigpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gdXBzZXJ0U2Vzc2lvbihkYjogREIsIGlucHV0OiBTZXNzaW9uSW5wdXQpOiB2b2lkIHtcbiAgLy8gVHJ5IGluc2VydCwgb24gY29uZmxpY3QgdXBkYXRlXG4gIGNvbnN0IGV4aXN0aW5nID0gZGIuc2VsZWN0KCkuZnJvbShzZXNzaW9ucykud2hlcmUoZXEoc2Vzc2lvbnMuaWQsIGlucHV0LmlkKSkuZ2V0KCk7XG5cbiAgaWYgKGV4aXN0aW5nKSB7XG4gICAgZGIudXBkYXRlKHNlc3Npb25zKVxuICAgICAgLnNldCh7XG4gICAgICAgIHVzZXJJZDogaW5wdXQudXNlcklkLFxuICAgICAgICBwcm9qZWN0OiBpbnB1dC5wcm9qZWN0LFxuICAgICAgICBnaXRSZXBvOiBpbnB1dC5naXRSZXBvLFxuICAgICAgICBnaXRCcmFuY2g6IGlucHV0LmdpdEJyYW5jaCxcbiAgICAgICAgcGlWZXJzaW9uOiBpbnB1dC5waVZlcnNpb24sXG4gICAgICAgIHNraWxsc1VzZWQ6IEpTT04uc3RyaW5naWZ5KGlucHV0LnNraWxsc1VzZWQpLFxuICAgICAgICBtb2RlbDogaW5wdXQubW9kZWwsXG4gICAgICB9KVxuICAgICAgLndoZXJlKGVxKHNlc3Npb25zLmlkLCBpbnB1dC5pZCkpXG4gICAgICAucnVuKCk7XG4gIH0gZWxzZSB7XG4gICAgaW5zZXJ0U2Vzc2lvbihkYiwgaW5wdXQpO1xuICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpbnNlcnRFdmVudChkYjogREIsIGlucHV0OiBFdmVudElucHV0KTogdm9pZCB7XG4gIGRiLmluc2VydChldmVudHMpXG4gICAgLnZhbHVlcyh7XG4gICAgICBzZXNzaW9uSWQ6IGlucHV0LnNlc3Npb25JZCxcbiAgICAgIGV2ZW50VHlwZTogaW5wdXQuZXZlbnRUeXBlLFxuICAgICAgdGltZXN0YW1wOiBpbnB1dC50aW1lc3RhbXAsXG4gICAgICBwYXlsb2FkOiBKU09OLnN0cmluZ2lmeShpbnB1dC5wYXlsb2FkKSxcbiAgICB9KVxuICAgIC5ydW4oKTtcbn1cblxuZnVuY3Rpb24gcGFyc2VTZXNzaW9uUm93KHJvdzogYW55KTogU2Vzc2lvblJvdyB7XG4gIHJldHVybiB7XG4gICAgaWQ6IHJvdy5pZCxcbiAgICB0ZWFtSWQ6IHJvdy50ZWFtSWQsXG4gICAgdXNlcklkOiByb3cudXNlcklkLFxuICAgIHByb2plY3Q6IHJvdy5wcm9qZWN0LFxuICAgIGdpdFJlcG86IHJvdy5naXRSZXBvLFxuICAgIGdpdEJyYW5jaDogcm93LmdpdEJyYW5jaCxcbiAgICBwaVZlcnNpb246IHJvdy5waVZlcnNpb24sXG4gICAgc2tpbGxzVXNlZDogSlNPTi5wYXJzZShyb3cuc2tpbGxzVXNlZCB8fCBcIltdXCIpLFxuICAgIG1vZGVsOiByb3cubW9kZWwgfHwgbnVsbCxcbiAgICBoYXJuZXNzOiByb3cuaGFybmVzcyB8fCBcInBpXCIsXG4gICAgc3RhcnRlZEF0OiByb3cuc3RhcnRlZEF0LFxuICAgIGVuZGVkQXQ6IHJvdy5lbmRlZEF0LFxuICAgIHN0YXR1czogcm93LnN0YXR1cyxcbiAgfTtcbn1cblxuZnVuY3Rpb24gcGFyc2VFdmVudFJvdyhyb3c6IGFueSk6IEV2ZW50Um93IHtcbiAgcmV0dXJuIHtcbiAgICBpZDogcm93LmlkLFxuICAgIHNlc3Npb25JZDogcm93LnNlc3Npb25JZCxcbiAgICBldmVudFR5cGU6IHJvdy5ldmVudFR5cGUsXG4gICAgdGltZXN0YW1wOiByb3cudGltZXN0YW1wLFxuICAgIHBheWxvYWQ6IEpTT04ucGFyc2Uocm93LnBheWxvYWQgfHwgXCJ7fVwiKSxcbiAgfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldFNlc3Npb25XaXRoRXZlbnRzKFxuICBkYjogREIsXG4gIHNlc3Npb25JZDogc3RyaW5nLFxuKTogeyBzZXNzaW9uOiBTZXNzaW9uUm93OyBldmVudHM6IEV2ZW50Um93W10gfSB8IG51bGwge1xuICBjb25zdCBzZXNzaW9uUm93ID0gZGIuc2VsZWN0KCkuZnJvbShzZXNzaW9ucykud2hlcmUoZXEoc2Vzc2lvbnMuaWQsIHNlc3Npb25JZCkpLmdldCgpO1xuXG4gIGlmICghc2Vzc2lvblJvdykgcmV0dXJuIG51bGw7XG5cbiAgY29uc3QgZXZlbnRSb3dzID0gZGJcbiAgICAuc2VsZWN0KClcbiAgICAuZnJvbShldmVudHMpXG4gICAgLndoZXJlKGVxKGV2ZW50cy5zZXNzaW9uSWQsIHNlc3Npb25JZCkpXG4gICAgLm9yZGVyQnkoYXNjKGV2ZW50cy50aW1lc3RhbXApLCBhc2MoZXZlbnRzLmlkKSlcbiAgICAuYWxsKCk7XG5cbiAgcmV0dXJuIHtcbiAgICBzZXNzaW9uOiBwYXJzZVNlc3Npb25Sb3coc2Vzc2lvblJvdyksXG4gICAgZXZlbnRzOiBldmVudFJvd3MubWFwKHBhcnNlRXZlbnRSb3cpLFxuICB9O1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIExpc3RTZXNzaW9uc0ZpbHRlciB7XG4gIHRlYW1JZDogc3RyaW5nO1xuICB1c2VySWQ/OiBzdHJpbmc7XG4gIHByb2plY3Q/OiBzdHJpbmc7XG4gIGhhcm5lc3M/OiBzdHJpbmc7XG4gIHN0YXR1cz86IHN0cmluZztcbiAgZnJvbT86IHN0cmluZztcbiAgdG8/OiBzdHJpbmc7XG4gIGxpbWl0PzogbnVtYmVyO1xuICBvZmZzZXQ/OiBudW1iZXI7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBsaXN0U2Vzc2lvbnMoXG4gIGRiOiBEQixcbiAgZmlsdGVyOiBMaXN0U2Vzc2lvbnNGaWx0ZXIsXG4pOiB7IHNlc3Npb25zOiBTZXNzaW9uUm93W107IHRvdGFsOiBudW1iZXIgfSB7XG4gIGNvbnN0IGNvbmRpdGlvbnMgPSBbZXEoc2Vzc2lvbnMudGVhbUlkLCBmaWx0ZXIudGVhbUlkKV07XG5cbiAgaWYgKGZpbHRlci51c2VySWQpIGNvbmRpdGlvbnMucHVzaChlcShzZXNzaW9ucy51c2VySWQsIGZpbHRlci51c2VySWQpKTtcbiAgaWYgKGZpbHRlci5wcm9qZWN0KSBjb25kaXRpb25zLnB1c2goZXEoc2Vzc2lvbnMucHJvamVjdCwgZmlsdGVyLnByb2plY3QpKTtcbiAgaWYgKGZpbHRlci5oYXJuZXNzKSBjb25kaXRpb25zLnB1c2goZXEoc2Vzc2lvbnMuaGFybmVzcywgZmlsdGVyLmhhcm5lc3MpKTtcbiAgaWYgKGZpbHRlci5zdGF0dXMpIGNvbmRpdGlvbnMucHVzaChlcShzZXNzaW9ucy5zdGF0dXMsIGZpbHRlci5zdGF0dXMpKTtcbiAgaWYgKGZpbHRlci5mcm9tKSBjb25kaXRpb25zLnB1c2goZ3RlKHNlc3Npb25zLnN0YXJ0ZWRBdCwgZmlsdGVyLmZyb20pKTtcbiAgaWYgKGZpbHRlci50bykgY29uZGl0aW9ucy5wdXNoKGx0ZShzZXNzaW9ucy5zdGFydGVkQXQsIGZpbHRlci50bykpO1xuXG4gIGNvbnN0IHdoZXJlID0gY29uZGl0aW9ucy5sZW5ndGggPT09IDEgPyBjb25kaXRpb25zWzBdIDogYW5kKC4uLmNvbmRpdGlvbnMpO1xuXG4gIC8vIENvdW50IHRvdGFsXG4gIGNvbnN0IGNvdW50UmVzdWx0ID0gZGIuc2VsZWN0KHsgY291bnQ6IGNvdW50KCkgfSkuZnJvbShzZXNzaW9ucykud2hlcmUod2hlcmUhKS5nZXQoKTtcbiAgY29uc3QgdG90YWwgPSBjb3VudFJlc3VsdD8uY291bnQgPz8gMDtcblxuICAvLyBGZXRjaCBwYWdlXG4gIGNvbnN0IGxpbWl0ID0gTWF0aC5taW4oZmlsdGVyLmxpbWl0ID8/IDUwLCAyMDApO1xuICBjb25zdCBvZmZzZXQgPSBmaWx0ZXIub2Zmc2V0ID8/IDA7XG5cbiAgY29uc3Qgcm93cyA9IGRiXG4gICAgLnNlbGVjdCgpXG4gICAgLmZyb20oc2Vzc2lvbnMpXG4gICAgLndoZXJlKHdoZXJlISlcbiAgICAub3JkZXJCeShkZXNjKHNlc3Npb25zLnN0YXJ0ZWRBdCkpXG4gICAgLmxpbWl0KGxpbWl0KVxuICAgIC5vZmZzZXQob2Zmc2V0KVxuICAgIC5hbGwoKTtcblxuICByZXR1cm4ge1xuICAgIHNlc3Npb25zOiByb3dzLm1hcChwYXJzZVNlc3Npb25Sb3cpLFxuICAgIHRvdGFsLFxuICB9O1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFRva2VuU3RhdHMge1xuICB0b3RhbElucHV0VG9rZW5zOiBudW1iZXI7XG4gIHRvdGFsT3V0cHV0VG9rZW5zOiBudW1iZXI7XG4gIHRvdGFsQ2FjaGVSZWFkVG9rZW5zOiBudW1iZXI7XG4gIHRvdGFsQ2FjaGVXcml0ZVRva2VuczogbnVtYmVyO1xuICB0b3RhbFRva2VuczogbnVtYmVyO1xuICB0b3RhbENvc3RVc2Q6IG51bWJlcjtcbiAgbGxtQ2FsbENvdW50OiBudW1iZXI7XG4gIGF2Z0lucHV0VG9rZW5zUGVyQ2FsbDogbnVtYmVyO1xuICBwZWFrSW5wdXRUb2tlbnM6IG51bWJlcjtcbiAgY29udGV4dFdpbmRvdzogbnVtYmVyIHwgbnVsbDtcbiAgY29udGV4dFV0aWxpemF0aW9uUGN0OiBudW1iZXIgfCBudWxsO1xuICBtb2RlbDogc3RyaW5nIHwgbnVsbDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldFRva2VuU3RhdHMoZGI6IERCLCBzZXNzaW9uSWQ6IHN0cmluZyk6IFRva2VuU3RhdHMge1xuICBjb25zdCBldmVudFJvd3MgPSBkYlxuICAgIC5zZWxlY3QoKVxuICAgIC5mcm9tKGV2ZW50cylcbiAgICAud2hlcmUoYW5kKGVxKGV2ZW50cy5zZXNzaW9uSWQsIHNlc3Npb25JZCksIGVxKGV2ZW50cy5ldmVudFR5cGUsIFwibGxtX3Jlc3BvbnNlXCIpKSlcbiAgICAub3JkZXJCeShhc2MoZXZlbnRzLnRpbWVzdGFtcCkpXG4gICAgLmFsbCgpO1xuXG4gIGxldCB0b3RhbElucHV0ID0gMDtcbiAgbGV0IHRvdGFsT3V0cHV0ID0gMDtcbiAgbGV0IHRvdGFsQ2FjaGVSZWFkID0gMDtcbiAgbGV0IHRvdGFsQ2FjaGVXcml0ZSA9IDA7XG4gIGxldCB0b3RhbFRva2Vuc1N1bSA9IDA7XG4gIGxldCB0b3RhbENvc3QgPSAwO1xuICBsZXQgcGVha0lucHV0ID0gMDtcbiAgbGV0IGNvbnRleHRXaW5kb3c6IG51bWJlciB8IG51bGwgPSBudWxsO1xuICBjb25zdCBtb2RlbENvdW50cyA9IG5ldyBNYXA8c3RyaW5nLCBudW1iZXI+KCk7XG5cbiAgZm9yIChjb25zdCByb3cgb2YgZXZlbnRSb3dzKSB7XG4gICAgY29uc3QgcGF5bG9hZCA9IEpTT04ucGFyc2Uocm93LnBheWxvYWQgfHwgXCJ7fVwiKTtcbiAgICB0b3RhbElucHV0ICs9IHBheWxvYWQuaW5wdXRfdG9rZW5zIHx8IDA7XG4gICAgdG90YWxPdXRwdXQgKz0gcGF5bG9hZC5vdXRwdXRfdG9rZW5zIHx8IDA7XG4gICAgdG90YWxDYWNoZVJlYWQgKz0gcGF5bG9hZC5jYWNoZV9yZWFkX3Rva2VucyB8fCAwO1xuICAgIHRvdGFsQ2FjaGVXcml0ZSArPSBwYXlsb2FkLmNhY2hlX3dyaXRlX3Rva2VucyB8fCAwO1xuICAgIHRvdGFsVG9rZW5zU3VtICs9IHBheWxvYWQudG90YWxfdG9rZW5zIHx8IDA7XG4gICAgdG90YWxDb3N0ICs9IHBheWxvYWQudG90YWxfY29zdF91c2QgfHwgMDtcblxuICAgIGlmICgocGF5bG9hZC5pbnB1dF90b2tlbnMgfHwgMCkgPiBwZWFrSW5wdXQpIHtcbiAgICAgIHBlYWtJbnB1dCA9IHBheWxvYWQuaW5wdXRfdG9rZW5zIHx8IDA7XG4gICAgfVxuXG4gICAgaWYgKHBheWxvYWQuY29udGV4dF93aW5kb3cpIHtcbiAgICAgIGNvbnRleHRXaW5kb3cgPSBwYXlsb2FkLmNvbnRleHRfd2luZG93O1xuICAgIH1cblxuICAgIGlmIChwYXlsb2FkLm1vZGVsKSB7XG4gICAgICBtb2RlbENvdW50cy5zZXQocGF5bG9hZC5tb2RlbCwgKG1vZGVsQ291bnRzLmdldChwYXlsb2FkLm1vZGVsKSB8fCAwKSArIDEpO1xuICAgIH1cbiAgfVxuXG4gIGNvbnN0IGxsbUNhbGxDb3VudCA9IGV2ZW50Um93cy5sZW5ndGg7XG5cbiAgLy8gRmluZCBtb3N0LXVzZWQgbW9kZWxcbiAgbGV0IG1vZGVsOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgbGV0IG1heE1vZGVsQ291bnQgPSAwO1xuICBtb2RlbENvdW50cy5mb3JFYWNoKChjLCBtKSA9PiB7XG4gICAgaWYgKGMgPiBtYXhNb2RlbENvdW50KSB7XG4gICAgICBtb2RlbCA9IG07XG4gICAgICBtYXhNb2RlbENvdW50ID0gYztcbiAgICB9XG4gIH0pO1xuXG4gIHJldHVybiB7XG4gICAgdG90YWxJbnB1dFRva2VuczogdG90YWxJbnB1dCxcbiAgICB0b3RhbE91dHB1dFRva2VuczogdG90YWxPdXRwdXQsXG4gICAgdG90YWxDYWNoZVJlYWRUb2tlbnM6IHRvdGFsQ2FjaGVSZWFkLFxuICAgIHRvdGFsQ2FjaGVXcml0ZVRva2VuczogdG90YWxDYWNoZVdyaXRlLFxuICAgIHRvdGFsVG9rZW5zOiB0b3RhbFRva2Vuc1N1bSxcbiAgICB0b3RhbENvc3RVc2Q6IHRvdGFsQ29zdCxcbiAgICBsbG1DYWxsQ291bnQsXG4gICAgYXZnSW5wdXRUb2tlbnNQZXJDYWxsOiBsbG1DYWxsQ291bnQgPiAwID8gTWF0aC5yb3VuZCh0b3RhbElucHV0IC8gbGxtQ2FsbENvdW50KSA6IDAsXG4gICAgcGVha0lucHV0VG9rZW5zOiBwZWFrSW5wdXQsXG4gICAgY29udGV4dFdpbmRvdyxcbiAgICBjb250ZXh0VXRpbGl6YXRpb25QY3Q6XG4gICAgICBjb250ZXh0V2luZG93ICYmIHBlYWtJbnB1dCA+IDAgPyBNYXRoLnJvdW5kKChwZWFrSW5wdXQgLyBjb250ZXh0V2luZG93KSAqIDEwMDAwKSAvIDEwMCA6IG51bGwsXG4gICAgbW9kZWwsXG4gIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRFdmVudENvdW50c0J5VHlwZShkYjogREIsIHNlc3Npb25JZDogc3RyaW5nKTogUmVjb3JkPHN0cmluZywgbnVtYmVyPiB7XG4gIGNvbnN0IHJvd3MgPSBkYlxuICAgIC5zZWxlY3Qoe1xuICAgICAgZXZlbnRUeXBlOiBldmVudHMuZXZlbnRUeXBlLFxuICAgICAgY291bnQ6IGNvdW50KCksXG4gICAgfSlcbiAgICAuZnJvbShldmVudHMpXG4gICAgLndoZXJlKGVxKGV2ZW50cy5zZXNzaW9uSWQsIHNlc3Npb25JZCkpXG4gICAgLmdyb3VwQnkoZXZlbnRzLmV2ZW50VHlwZSlcbiAgICAuYWxsKCk7XG5cbiAgY29uc3QgY291bnRzOiBSZWNvcmQ8c3RyaW5nLCBudW1iZXI+ID0ge1xuICAgIHVzZXJfcHJvbXB0OiAwLFxuICAgIHRvb2xfY2FsbDogMCxcbiAgICBlcnJvcjogMCxcbiAgICBmaWxlX2NoYW5nZTogMCxcbiAgICBoZWFydGJlYXQ6IDAsXG4gICAgc2Vzc2lvbl9zdGFydDogMCxcbiAgICBzZXNzaW9uX2VuZDogMCxcbiAgfTtcblxuICBmb3IgKGNvbnN0IHJvdyBvZiByb3dzKSB7XG4gICAgY291bnRzW3Jvdy5ldmVudFR5cGVdID0gcm93LmNvdW50O1xuICB9XG5cbiAgcmV0dXJuIGNvdW50cztcbn1cblxuLy8gLS0tIFBSIEhlbHBlcnMgLS0tXG5cbmV4cG9ydCBpbnRlcmZhY2UgUHVsbFJlcXVlc3RJbnB1dCB7XG4gIHNlc3Npb25JZDogc3RyaW5nO1xuICByZXBvOiBzdHJpbmc7XG4gIGJyYW5jaDogc3RyaW5nO1xuICBwck51bWJlcjogbnVtYmVyO1xuICBwclVybDogc3RyaW5nO1xuICBwclRpdGxlOiBzdHJpbmc7XG4gIHN0YXR1czogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFB1bGxSZXF1ZXN0Um93IHtcbiAgaWQ6IG51bWJlcjtcbiAgc2Vzc2lvbklkOiBzdHJpbmc7XG4gIHJlcG86IHN0cmluZztcbiAgYnJhbmNoOiBzdHJpbmc7XG4gIHByTnVtYmVyOiBudW1iZXI7XG4gIHByVXJsOiBzdHJpbmc7XG4gIHByVGl0bGU6IHN0cmluZztcbiAgc3RhdHVzOiBzdHJpbmc7XG4gIG1lcmdlZEF0OiBzdHJpbmcgfCBudWxsO1xuICByZXZpZXdzQXBwcm92ZWQ6IG51bWJlcjtcbiAgcmV2aWV3c0NoYW5nZXNSZXF1ZXN0ZWQ6IG51bWJlcjtcbiAgcmV2aWV3Q29tbWVudHM6IG51bWJlcjtcbiAgY29tbWl0c0FmdGVyUmV2aWV3OiBudW1iZXI7XG4gIGZpcnN0UmV2aWV3QXQ6IHN0cmluZyB8IG51bGw7XG4gIHRpbWVUb01lcmdlSG91cnM6IG51bWJlciB8IG51bGw7XG4gIGNoZWNrZWRBdDogc3RyaW5nIHwgbnVsbDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHVwc2VydFB1bGxSZXF1ZXN0KGRiOiBEQiwgaW5wdXQ6IFB1bGxSZXF1ZXN0SW5wdXQpOiB2b2lkIHtcbiAgY29uc3QgZXhpc3RpbmcgPSBkYlxuICAgIC5zZWxlY3QoKVxuICAgIC5mcm9tKHB1bGxSZXF1ZXN0cylcbiAgICAud2hlcmUoXG4gICAgICBhbmQoZXEocHVsbFJlcXVlc3RzLnNlc3Npb25JZCwgaW5wdXQuc2Vzc2lvbklkKSwgZXEocHVsbFJlcXVlc3RzLnByTnVtYmVyLCBpbnB1dC5wck51bWJlcikpLFxuICAgIClcbiAgICAuZ2V0KCk7XG5cbiAgaWYgKGV4aXN0aW5nKSB7XG4gICAgZGIudXBkYXRlKHB1bGxSZXF1ZXN0cylcbiAgICAgIC5zZXQoe1xuICAgICAgICBzdGF0dXM6IGlucHV0LnN0YXR1cyxcbiAgICAgICAgcHJUaXRsZTogaW5wdXQucHJUaXRsZSxcbiAgICAgICAgY2hlY2tlZEF0OiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgICB9KVxuICAgICAgLndoZXJlKGVxKHB1bGxSZXF1ZXN0cy5pZCwgZXhpc3RpbmcuaWQpKVxuICAgICAgLnJ1bigpO1xuICB9IGVsc2Uge1xuICAgIGRiLmluc2VydChwdWxsUmVxdWVzdHMpXG4gICAgICAudmFsdWVzKHtcbiAgICAgICAgc2Vzc2lvbklkOiBpbnB1dC5zZXNzaW9uSWQsXG4gICAgICAgIHJlcG86IGlucHV0LnJlcG8sXG4gICAgICAgIGJyYW5jaDogaW5wdXQuYnJhbmNoLFxuICAgICAgICBwck51bWJlcjogaW5wdXQucHJOdW1iZXIsXG4gICAgICAgIHByVXJsOiBpbnB1dC5wclVybCxcbiAgICAgICAgcHJUaXRsZTogaW5wdXQucHJUaXRsZSxcbiAgICAgICAgc3RhdHVzOiBpbnB1dC5zdGF0dXMsXG4gICAgICB9KVxuICAgICAgLnJ1bigpO1xuICB9XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUHJVcGRhdGVEYXRhIHtcbiAgc3RhdHVzPzogc3RyaW5nO1xuICBtZXJnZWRBdD86IHN0cmluZztcbiAgcmV2aWV3c0FwcHJvdmVkPzogbnVtYmVyO1xuICByZXZpZXdzQ2hhbmdlc1JlcXVlc3RlZD86IG51bWJlcjtcbiAgcmV2aWV3Q29tbWVudHM/OiBudW1iZXI7XG4gIGNvbW1pdHNBZnRlclJldmlldz86IG51bWJlcjtcbiAgZmlyc3RSZXZpZXdBdD86IHN0cmluZztcbiAgdGltZVRvTWVyZ2VIb3Vycz86IHN0cmluZztcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHVwZGF0ZVB1bGxSZXF1ZXN0KGRiOiBEQiwgaWQ6IG51bWJlciwgZGF0YTogUHJVcGRhdGVEYXRhKTogdm9pZCB7XG4gIGRiLnVwZGF0ZShwdWxsUmVxdWVzdHMpXG4gICAgLnNldCh7XG4gICAgICAuLi5kYXRhLFxuICAgICAgY2hlY2tlZEF0OiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgfSlcbiAgICAud2hlcmUoZXEocHVsbFJlcXVlc3RzLmlkLCBpZCkpXG4gICAgLnJ1bigpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0T3BlblB1bGxSZXF1ZXN0cyhkYjogREIpOiBQdWxsUmVxdWVzdFJvd1tdIHtcbiAgcmV0dXJuIGRiXG4gICAgLnNlbGVjdCgpXG4gICAgLmZyb20ocHVsbFJlcXVlc3RzKVxuICAgIC53aGVyZShlcShwdWxsUmVxdWVzdHMuc3RhdHVzLCBcIm9wZW5cIikpXG4gICAgLmFsbCgpIGFzIFB1bGxSZXF1ZXN0Um93W107XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRQdWxsUmVxdWVzdHNGb3JTZXNzaW9uKGRiOiBEQiwgc2Vzc2lvbklkOiBzdHJpbmcpOiBQdWxsUmVxdWVzdFJvd1tdIHtcbiAgcmV0dXJuIGRiXG4gICAgLnNlbGVjdCgpXG4gICAgLmZyb20ocHVsbFJlcXVlc3RzKVxuICAgIC53aGVyZShlcShwdWxsUmVxdWVzdHMuc2Vzc2lvbklkLCBzZXNzaW9uSWQpKVxuICAgIC5hbGwoKSBhcyBQdWxsUmVxdWVzdFJvd1tdO1xufVxuIiwgIi8qKlxuICogS25vd24gY29udGV4dCB3aW5kb3cgc2l6ZXMgZm9yIGNvbW1vbiBtb2RlbHMuXG4gKiBVc2VkIHRvIGNvbXB1dGUgY29udGV4dCB1dGlsaXphdGlvbiBwZXJjZW50YWdlLlxuICovXG5cbmNvbnN0IENPTlRFWFRfV0lORE9XUzogUmVjb3JkPHN0cmluZywgbnVtYmVyPiA9IHtcbiAgLy8gQ2xhdWRlIDRcbiAgXCJjbGF1ZGUtb3B1cy00LTZcIjogMjAwMDAwLFxuICBcImNsYXVkZS1zb25uZXQtNC02XCI6IDIwMDAwMCxcblxuICAvLyBDbGF1ZGUgMy41K1xuICBcImNsYXVkZS1vcHVzLTQtNVwiOiAyMDAwMDAsXG4gIFwiY2xhdWRlLXNvbm5ldC00LTVcIjogMjAwMDAwLFxuICBcImNsYXVkZS1oYWlrdS00LTUtMjAyNTEwMDFcIjogMjAwMDAwLFxuXG4gIC8vIENsYXVkZSAzXG4gIFwiY2xhdWRlLTMtb3B1cy0yMDI0MDIyOVwiOiAyMDAwMDAsXG4gIFwiY2xhdWRlLTMtc29ubmV0LTIwMjQwMjI5XCI6IDIwMDAwMCxcbiAgXCJjbGF1ZGUtMy1oYWlrdS0yMDI0MDMwN1wiOiAyMDAwMDAsXG5cbiAgLy8gT3BlbkFJXG4gIFwiZ3B0LTRvXCI6IDEyODAwMCxcbiAgXCJncHQtNC10dXJib1wiOiAxMjgwMDAsXG4gIFwiZ3B0LTRcIjogODE5MixcbiAgXCJncHQtNS4zLWNvZGV4XCI6IDIwMDAwMCxcbiAgXCJvMS1wcmV2aWV3XCI6IDEyODAwMCxcbiAgXCJvMS1taW5pXCI6IDEyODAwMCxcbn07XG5cbi8qKlxuICogTG9vayB1cCBrbm93biBjb250ZXh0IHdpbmRvdyBmb3IgYSBtb2RlbC5cbiAqIERvZXMgcHJlZml4IG1hdGNoaW5nOiBcImNsYXVkZS1zb25uZXQtNC02XCIgbWF0Y2hlcyBcImNsYXVkZS1zb25uZXQtNC02XCIuXG4gKiBSZXR1cm5zIG51bGwgaWYgbW9kZWwgaXMgdW5rbm93bi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldENvbnRleHRXaW5kb3cobW9kZWw6IHN0cmluZyB8IG51bGwpOiBudW1iZXIgfCBudWxsIHtcbiAgaWYgKCFtb2RlbCkgcmV0dXJuIG51bGw7XG5cbiAgLy8gRXhhY3QgbWF0Y2hcbiAgaWYgKENPTlRFWFRfV0lORE9XU1ttb2RlbF0pIHJldHVybiBDT05URVhUX1dJTkRPV1NbbW9kZWxdO1xuXG4gIC8vIFByZWZpeCBtYXRjaCAoaGFuZGxlcyB2ZXJzaW9uZWQgbW9kZWwgbmFtZXMgbGlrZSBcImNsYXVkZS1zb25uZXQtNC02LTIwMjYwMzAxXCIpXG4gIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKENPTlRFWFRfV0lORE9XUykpIHtcbiAgICBpZiAobW9kZWwuc3RhcnRzV2l0aChrZXkpKSByZXR1cm4gdmFsdWU7XG4gIH1cblxuICAvLyBGYW1pbHkgbWF0Y2hcbiAgaWYgKG1vZGVsLmluY2x1ZGVzKFwiY2xhdWRlXCIpKSByZXR1cm4gMjAwMDAwO1xuICBpZiAobW9kZWwuaW5jbHVkZXMoXCJncHQtNFwiKSkgcmV0dXJuIDEyODAwMDtcblxuICByZXR1cm4gbnVsbDtcbn1cbiIsICIvKipcbiAqIFBhcnNlIGEgQ2xhdWRlIENvZGUgc2Vzc2lvbiBKU09OTCBzdHJpbmcgaW50byBhZ2VudGxlbnMgZXZlbnRzLlxuICovXG5cbmV4cG9ydCBpbnRlcmZhY2UgUGFyc2VkRXZlbnQge1xuICBldmVudFR5cGU6IHN0cmluZztcbiAgdGltZXN0YW1wOiBzdHJpbmc7XG4gIHBheWxvYWQ6IFJlY29yZDxzdHJpbmcsIGFueT47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUGFyc2VkU2Vzc2lvbiB7XG4gIHNlc3Npb25JZDogc3RyaW5nO1xuICBwcm9qZWN0OiBzdHJpbmc7XG4gIGdpdEJyYW5jaDogc3RyaW5nIHwgbnVsbDtcbiAgaGFybmVzczogc3RyaW5nO1xuICBtb2RlbDogc3RyaW5nIHwgbnVsbDtcbiAgdmVyc2lvbjogc3RyaW5nO1xuICB1c2VySWQ6IHN0cmluZztcbiAgc3RhcnRlZEF0OiBzdHJpbmc7XG4gIGVuZGVkQXQ6IHN0cmluZztcbiAgZXZlbnRzOiBQYXJzZWRFdmVudFtdO1xuICB0b3RhbElucHV0VG9rZW5zOiBudW1iZXI7XG4gIHRvdGFsT3V0cHV0VG9rZW5zOiBudW1iZXI7XG4gIHRvdGFsQ2FjaGVSZWFkVG9rZW5zOiBudW1iZXI7XG4gIHRvdGFsQ2FjaGVXcml0ZVRva2VuczogbnVtYmVyO1xuICB1c2VkU3ViYWdlbnRzOiBib29sZWFuO1xufVxuXG5pbnRlcmZhY2UgVG9vbFVzZUl0ZW0ge1xuICB0eXBlOiBcInRvb2xfdXNlXCI7XG4gIGlkOiBzdHJpbmc7XG4gIG5hbWU6IHN0cmluZztcbiAgaW5wdXQ6IFJlY29yZDxzdHJpbmcsIGFueT47XG59XG5cbmludGVyZmFjZSBUb29sUmVzdWx0SXRlbSB7XG4gIHR5cGU6IFwidG9vbF9yZXN1bHRcIjtcbiAgdG9vbF91c2VfaWQ6IHN0cmluZztcbiAgY29udGVudDogc3RyaW5nO1xuICBpc19lcnJvcj86IGJvb2xlYW47XG59XG5cbmltcG9ydCB7IGdldENvbnRleHRXaW5kb3cgfSBmcm9tIFwiLi4vbW9kZWwtY29udGV4dFwiO1xuXG5jb25zdCBTVUJBR0VOVF9UT09MUyA9IG5ldyBTZXQoW1wiVGFza1wiLCBcIkFnZW50XCJdKTtcblxuLyoqXG4gKiBEZXJpdmUgYSBwcm9qZWN0IG5hbWUgZnJvbSB0aGUgY3dkIHBhdGguXG4gKiBlLmcuIFwiL1VzZXJzL2Rldi9teS1wcm9qZWN0XCIgXHUyMTkyIFwibXktcHJvamVjdFwiXG4gKi9cbmZ1bmN0aW9uIHByb2plY3RGcm9tQ3dkKGN3ZDogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3QgcGFydHMgPSBjd2QucmVwbGFjZSgvXFwvKyQvLCBcIlwiKS5zcGxpdChcIi9cIik7XG4gIHJldHVybiBwYXJ0c1twYXJ0cy5sZW5ndGggLSAxXSB8fCBjd2Q7XG59XG5cbi8qKlxuICogU3VtbWFyaXplIHRvb2wgaW5wdXQgZm9yIGRpc3BsYXkuXG4gKi9cbi8qKiBHZXQgZmlsZSBwYXRoIGZyb20gdG9vbCBhcmdzIFx1MjAxNCBDQyB1c2VzIGZpbGVfcGF0aCwgUGkgdXNlcyBwYXRoLiAqL1xuZnVuY3Rpb24gZ2V0RmlsZVBhdGgoaW5wdXQ6IFJlY29yZDxzdHJpbmcsIGFueT4pOiBzdHJpbmcgfCBudWxsIHtcbiAgcmV0dXJuIGlucHV0LmZpbGVfcGF0aCB8fCBpbnB1dC5wYXRoIHx8IG51bGw7XG59XG5cbmZ1bmN0aW9uIHN1bW1hcml6ZVRvb2xJbnB1dChuYW1lOiBzdHJpbmcsIGlucHV0OiBSZWNvcmQ8c3RyaW5nLCBhbnk+KTogc3RyaW5nIHtcbiAgaWYgKG5hbWUgPT09IFwiQmFzaFwiICYmIGlucHV0LmNvbW1hbmQpIHtcbiAgICByZXR1cm4gU3RyaW5nKGlucHV0LmNvbW1hbmQpLnNsaWNlKDAsIDIwMCk7XG4gIH1cbiAgY29uc3QgZmlsZVBhdGggPSBnZXRGaWxlUGF0aChpbnB1dCk7XG4gIGlmICgobmFtZSA9PT0gXCJXcml0ZVwiIHx8IG5hbWUgPT09IFwiRWRpdFwiIHx8IG5hbWUgPT09IFwiTXVsdGlFZGl0XCIpICYmIGZpbGVQYXRoKSB7XG4gICAgcmV0dXJuIGZpbGVQYXRoO1xuICB9XG4gIGlmIChuYW1lID09PSBcIlJlYWRcIiAmJiBmaWxlUGF0aCkge1xuICAgIHJldHVybiBmaWxlUGF0aDtcbiAgfVxuICBpZiAoKG5hbWUgPT09IFwiVGFza1wiIHx8IG5hbWUgPT09IFwiQWdlbnRcIikgJiYgaW5wdXQuZGVzY3JpcHRpb24pIHtcbiAgICByZXR1cm4gU3RyaW5nKGlucHV0LmRlc2NyaXB0aW9uKS5zbGljZSgwLCAyMDApO1xuICB9XG4gIGlmICgobmFtZSA9PT0gXCJUYXNrXCIgfHwgbmFtZSA9PT0gXCJBZ2VudFwiKSAmJiBpbnB1dC5wcm9tcHQpIHtcbiAgICByZXR1cm4gU3RyaW5nKGlucHV0LnByb21wdCkuc2xpY2UoMCwgMjAwKTtcbiAgfVxuICAvLyBHZW5lcmljOiBmaXJzdCBzdHJpbmcgdmFsdWVcbiAgZm9yIChjb25zdCB2YWwgb2YgT2JqZWN0LnZhbHVlcyhpbnB1dCkpIHtcbiAgICBpZiAodHlwZW9mIHZhbCA9PT0gXCJzdHJpbmdcIiAmJiB2YWwubGVuZ3RoID4gMCkge1xuICAgICAgcmV0dXJuIHZhbC5zbGljZSgwLCAyMDApO1xuICAgIH1cbiAgfVxuICByZXR1cm4gXCJcIjtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlQ2xhdWRlQ29kZVNlc3Npb24oanNvbmw6IHN0cmluZyk6IFBhcnNlZFNlc3Npb24ge1xuICBjb25zdCBsaW5lcyA9IGpzb25sXG4gICAgLnNwbGl0KFwiXFxuXCIpXG4gICAgLmZpbHRlcigobCkgPT4gbC50cmltKCkpXG4gICAgLm1hcCgobCkgPT4gSlNPTi5wYXJzZShsKSk7XG5cbiAgY29uc3QgZXZlbnRzOiBQYXJzZWRFdmVudFtdID0gW107XG4gIGxldCBzZXNzaW9uSWQgPSBcIlwiO1xuICBsZXQgcHJvamVjdCA9IFwiXCI7XG4gIGxldCBnaXRCcmFuY2g6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICBsZXQgbW9kZWw6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICBsZXQgdmVyc2lvbiA9IFwiXCI7XG4gIGxldCB1c2VySWQgPSBcIlwiO1xuICBsZXQgc3RhcnRlZEF0ID0gXCJcIjtcbiAgbGV0IGVuZGVkQXQgPSBcIlwiO1xuICBsZXQgdXNlZFN1YmFnZW50cyA9IGZhbHNlO1xuXG4gIGxldCB0b3RhbElucHV0VG9rZW5zID0gMDtcbiAgbGV0IHRvdGFsT3V0cHV0VG9rZW5zID0gMDtcbiAgbGV0IHRvdGFsQ2FjaGVSZWFkVG9rZW5zID0gMDtcbiAgbGV0IHRvdGFsQ2FjaGVXcml0ZVRva2VucyA9IDA7XG5cbiAgLy8gQnVpbGQgYSBtYXAgb2YgdG9vbF91c2VfaWQgXHUyMTkyIHRvb2xfcmVzdWx0IGZvciBtYXRjaGluZ1xuICBjb25zdCB0b29sUmVzdWx0cyA9IG5ldyBNYXA8c3RyaW5nLCBUb29sUmVzdWx0SXRlbT4oKTtcbiAgZm9yIChjb25zdCBsaW5lIG9mIGxpbmVzKSB7XG4gICAgaWYgKGxpbmUudHlwZSA9PT0gXCJ1c2VyXCIpIHtcbiAgICAgIGNvbnN0IGNvbnRlbnQgPSBsaW5lLm1lc3NhZ2U/LmNvbnRlbnQ7XG4gICAgICBpZiAoQXJyYXkuaXNBcnJheShjb250ZW50KSkge1xuICAgICAgICBmb3IgKGNvbnN0IGl0ZW0gb2YgY29udGVudCkge1xuICAgICAgICAgIGlmIChpdGVtLnR5cGUgPT09IFwidG9vbF9yZXN1bHRcIiAmJiBpdGVtLnRvb2xfdXNlX2lkKSB7XG4gICAgICAgICAgICB0b29sUmVzdWx0cy5zZXQoaXRlbS50b29sX3VzZV9pZCwgaXRlbSBhcyBUb29sUmVzdWx0SXRlbSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgZm9yIChjb25zdCBsaW5lIG9mIGxpbmVzKSB7XG4gICAgY29uc3QgdHMgPSBsaW5lLnRpbWVzdGFtcDtcbiAgICBpZiAoIXRzKSBjb250aW51ZTtcblxuICAgIC8vIFRyYWNrIHRpbWVzdGFtcHNcbiAgICBpZiAoIXN0YXJ0ZWRBdCB8fCB0cyA8IHN0YXJ0ZWRBdCkgc3RhcnRlZEF0ID0gdHM7XG4gICAgaWYgKCFlbmRlZEF0IHx8IHRzID4gZW5kZWRBdCkgZW5kZWRBdCA9IHRzO1xuXG4gICAgLy8gRXh0cmFjdCBzZXNzaW9uIG1ldGFkYXRhIGZyb20gZmlyc3QgdXNlciBtZXNzYWdlXG4gICAgaWYgKGxpbmUudHlwZSA9PT0gXCJ1c2VyXCIgJiYgbGluZS5zZXNzaW9uSWQgJiYgIXNlc3Npb25JZCkge1xuICAgICAgc2Vzc2lvbklkID0gbGluZS5zZXNzaW9uSWQ7XG4gICAgICBwcm9qZWN0ID0gcHJvamVjdEZyb21Dd2QobGluZS5jd2QgfHwgXCJcIik7XG4gICAgICBnaXRCcmFuY2ggPSBsaW5lLmdpdEJyYW5jaCB8fCBudWxsO1xuICAgICAgdmVyc2lvbiA9IGxpbmUudmVyc2lvbiB8fCBcIlwiO1xuICAgICAgdXNlcklkID0gbGluZS5tZXNzYWdlPy5jb250ZW50Py51c2VyX2lkIHx8IFwiXCI7XG4gICAgfVxuXG4gICAgLy8gVXNlciBwcm9tcHRzOiBvbmx5IGV4dGVybmFsLCB3aXRoIHN0cmluZyBjb250ZW50IChub3QgdG9vbF9yZXN1bHQgYXJyYXlzKVxuICAgIGlmIChsaW5lLnR5cGUgPT09IFwidXNlclwiICYmIGxpbmUudXNlclR5cGUgPT09IFwiZXh0ZXJuYWxcIikge1xuICAgICAgY29uc3QgY29udGVudCA9IGxpbmUubWVzc2FnZT8uY29udGVudDtcbiAgICAgIGlmICh0eXBlb2YgY29udGVudCA9PT0gXCJzdHJpbmdcIiAmJiBjb250ZW50LnRyaW0oKSkge1xuICAgICAgICBldmVudHMucHVzaCh7XG4gICAgICAgICAgZXZlbnRUeXBlOiBcInVzZXJfcHJvbXB0XCIsXG4gICAgICAgICAgdGltZXN0YW1wOiB0cyxcbiAgICAgICAgICBwYXlsb2FkOiB7XG4gICAgICAgICAgICBwcm9tcHRfdGV4dDogY29udGVudCxcbiAgICAgICAgICAgIHByb21wdF9sZW5ndGg6IGNvbnRlbnQubGVuZ3RoLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEFzc2lzdGFudCBtZXNzYWdlczogZXh0cmFjdCBsbG1fcmVzcG9uc2UgKyB0b29sX2NhbGwgZXZlbnRzXG4gICAgaWYgKGxpbmUudHlwZSA9PT0gXCJhc3Npc3RhbnRcIikge1xuICAgICAgY29uc3QgbXNnID0gbGluZS5tZXNzYWdlIHx8IHt9O1xuICAgICAgY29uc3QgdXNhZ2UgPSBtc2cudXNhZ2UgfHwge307XG5cbiAgICAgIC8vIEV4dHJhY3QgbW9kZWxcbiAgICAgIGlmIChtc2cubW9kZWwgJiYgIW1vZGVsKSB7XG4gICAgICAgIG1vZGVsID0gbXNnLm1vZGVsO1xuICAgICAgfVxuXG4gICAgICAvLyBMTE0gcmVzcG9uc2UgZXZlbnRcbiAgICAgIGNvbnN0IGlucHV0VG9rZW5zID0gdXNhZ2UuaW5wdXRfdG9rZW5zIHx8IDA7XG4gICAgICBjb25zdCBvdXRwdXRUb2tlbnMgPSB1c2FnZS5vdXRwdXRfdG9rZW5zIHx8IDA7XG4gICAgICBjb25zdCBjYWNoZVJlYWQgPSB1c2FnZS5jYWNoZV9yZWFkX2lucHV0X3Rva2VucyB8fCAwO1xuICAgICAgY29uc3QgY2FjaGVXcml0ZSA9IHVzYWdlLmNhY2hlX2NyZWF0aW9uX2lucHV0X3Rva2VucyB8fCAwO1xuXG4gICAgICB0b3RhbElucHV0VG9rZW5zICs9IGlucHV0VG9rZW5zO1xuICAgICAgdG90YWxPdXRwdXRUb2tlbnMgKz0gb3V0cHV0VG9rZW5zO1xuICAgICAgdG90YWxDYWNoZVJlYWRUb2tlbnMgKz0gY2FjaGVSZWFkO1xuICAgICAgdG90YWxDYWNoZVdyaXRlVG9rZW5zICs9IGNhY2hlV3JpdGU7XG5cbiAgICAgIGNvbnN0IHJlc3BvbnNlTW9kZWwgPSBtc2cubW9kZWwgfHwgbW9kZWw7XG4gICAgICBjb25zdCBjb250ZXh0V2luZG93ID0gZ2V0Q29udGV4dFdpbmRvdyhyZXNwb25zZU1vZGVsKTtcblxuICAgICAgZXZlbnRzLnB1c2goe1xuICAgICAgICBldmVudFR5cGU6IFwibGxtX3Jlc3BvbnNlXCIsXG4gICAgICAgIHRpbWVzdGFtcDogdHMsXG4gICAgICAgIHBheWxvYWQ6IHtcbiAgICAgICAgICBtb2RlbDogcmVzcG9uc2VNb2RlbCxcbiAgICAgICAgICBpbnB1dF90b2tlbnM6IGlucHV0VG9rZW5zLFxuICAgICAgICAgIG91dHB1dF90b2tlbnM6IG91dHB1dFRva2VucyxcbiAgICAgICAgICBjYWNoZV9yZWFkX3Rva2VuczogY2FjaGVSZWFkLFxuICAgICAgICAgIGNhY2hlX3dyaXRlX3Rva2VuczogY2FjaGVXcml0ZSxcbiAgICAgICAgICB0b3RhbF90b2tlbnM6IGlucHV0VG9rZW5zICsgb3V0cHV0VG9rZW5zLFxuICAgICAgICAgIHN0b3BfcmVhc29uOiBtc2cuc3RvcF9yZWFzb24gfHwgbnVsbCxcbiAgICAgICAgICAuLi4oY29udGV4dFdpbmRvdyA/IHsgY29udGV4dF93aW5kb3c6IGNvbnRleHRXaW5kb3cgfSA6IHt9KSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuXG4gICAgICAvLyBFeHRyYWN0IHRvb2xfdXNlIGl0ZW1zIGZyb20gY29udGVudFxuICAgICAgY29uc3QgY29udGVudCA9IG1zZy5jb250ZW50IHx8IFtdO1xuICAgICAgaWYgKEFycmF5LmlzQXJyYXkoY29udGVudCkpIHtcbiAgICAgICAgZm9yIChjb25zdCBpdGVtIG9mIGNvbnRlbnQpIHtcbiAgICAgICAgICBpZiAoaXRlbS50eXBlID09PSBcInRvb2xfdXNlXCIpIHtcbiAgICAgICAgICAgIGNvbnN0IHRvb2xVc2UgPSBpdGVtIGFzIFRvb2xVc2VJdGVtO1xuICAgICAgICAgICAgY29uc3QgdG9vbFJlc3VsdCA9IHRvb2xSZXN1bHRzLmdldCh0b29sVXNlLmlkKTtcbiAgICAgICAgICAgIGNvbnN0IGlzRXJyb3IgPSB0b29sUmVzdWx0Py5pc19lcnJvciA9PT0gdHJ1ZTtcbiAgICAgICAgICAgIGNvbnN0IGlzU3ViYWdlbnQgPSBTVUJBR0VOVF9UT09MUy5oYXModG9vbFVzZS5uYW1lKTtcblxuICAgICAgICAgICAgaWYgKGlzU3ViYWdlbnQpIHVzZWRTdWJhZ2VudHMgPSB0cnVlO1xuXG4gICAgICAgICAgICBjb25zdCBhcmdzU3VtbWFyeSA9IHN1bW1hcml6ZVRvb2xJbnB1dCh0b29sVXNlLm5hbWUsIHRvb2xVc2UuaW5wdXQgfHwge30pO1xuXG4gICAgICAgICAgICBldmVudHMucHVzaCh7XG4gICAgICAgICAgICAgIGV2ZW50VHlwZTogXCJ0b29sX2NhbGxcIixcbiAgICAgICAgICAgICAgdGltZXN0YW1wOiB0cyxcbiAgICAgICAgICAgICAgcGF5bG9hZDoge1xuICAgICAgICAgICAgICAgIHRvb2w6IHRvb2xVc2UubmFtZSxcbiAgICAgICAgICAgICAgICBhcmdzX3N1bW1hcnk6IGFyZ3NTdW1tYXJ5LFxuICAgICAgICAgICAgICAgIHJlc3VsdF9zdW1tYXJ5OiB0b29sUmVzdWx0Py5jb250ZW50ID8gU3RyaW5nKHRvb2xSZXN1bHQuY29udGVudCkuc2xpY2UoMCwgMjAwKSA6IFwiXCIsXG4gICAgICAgICAgICAgICAgc3VjY2VzczogIWlzRXJyb3IsXG4gICAgICAgICAgICAgICAgaXNfZXJyb3I6IGlzRXJyb3IsXG4gICAgICAgICAgICAgICAgLi4uKGlzU3ViYWdlbnQgPyB7IGlzX3N1YmFnZW50OiB0cnVlIH0gOiB7fSksXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgLy8gRmlsZSBjaGFuZ2UgZXZlbnRzIGZvciBXcml0ZS9FZGl0XG4gICAgICAgICAgICBjb25zdCBjaGFuZ2VGaWxlUGF0aCA9IGdldEZpbGVQYXRoKHRvb2xVc2UuaW5wdXQgfHwge30pO1xuICAgICAgICAgICAgaWYgKHRvb2xVc2UubmFtZSA9PT0gXCJXcml0ZVwiICYmIGNoYW5nZUZpbGVQYXRoKSB7XG4gICAgICAgICAgICAgIGV2ZW50cy5wdXNoKHtcbiAgICAgICAgICAgICAgICBldmVudFR5cGU6IFwiZmlsZV9jaGFuZ2VcIixcbiAgICAgICAgICAgICAgICB0aW1lc3RhbXA6IHRzLFxuICAgICAgICAgICAgICAgIHBheWxvYWQ6IHsgcGF0aDogY2hhbmdlRmlsZVBhdGgsIGFjdGlvbjogXCJjcmVhdGVcIiB9LFxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICgodG9vbFVzZS5uYW1lID09PSBcIkVkaXRcIiB8fCB0b29sVXNlLm5hbWUgPT09IFwiTXVsdGlFZGl0XCIpICYmIGNoYW5nZUZpbGVQYXRoKSB7XG4gICAgICAgICAgICAgIGV2ZW50cy5wdXNoKHtcbiAgICAgICAgICAgICAgICBldmVudFR5cGU6IFwiZmlsZV9jaGFuZ2VcIixcbiAgICAgICAgICAgICAgICB0aW1lc3RhbXA6IHRzLFxuICAgICAgICAgICAgICAgIHBheWxvYWQ6IHsgcGF0aDogY2hhbmdlRmlsZVBhdGgsIGFjdGlvbjogXCJlZGl0XCIgfSxcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIEdpdCBjb21taXQgZGV0ZWN0aW9uIGZyb20gQmFzaCBjb21tYW5kc1xuICAgICAgICAgICAgaWYgKHRvb2xVc2UubmFtZSA9PT0gXCJCYXNoXCIgJiYgdG9vbFVzZS5pbnB1dD8uY29tbWFuZCkge1xuICAgICAgICAgICAgICBjb25zdCBjbWQgPSBTdHJpbmcodG9vbFVzZS5pbnB1dC5jb21tYW5kKTtcbiAgICAgICAgICAgICAgY29uc3QgcmVzdWx0VGV4dCA9IHRvb2xSZXN1bHQ/LmNvbnRlbnQgPyBTdHJpbmcodG9vbFJlc3VsdC5jb250ZW50KSA6IFwiXCI7XG4gICAgICAgICAgICAgIGlmIChjbWQuaW5jbHVkZXMoXCJnaXQgY29tbWl0XCIpKSB7XG4gICAgICAgICAgICAgICAgZXZlbnRzLnB1c2goe1xuICAgICAgICAgICAgICAgICAgZXZlbnRUeXBlOiBcImdpdF9jb21taXRcIixcbiAgICAgICAgICAgICAgICAgIHRpbWVzdGFtcDogdHMsXG4gICAgICAgICAgICAgICAgICBwYXlsb2FkOiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbW1hbmQ6IGNtZCxcbiAgICAgICAgICAgICAgICAgICAgcmVzdWx0X3N1bW1hcnk6IHJlc3VsdFRleHQuc2xpY2UoMCwgMjAwKSxcbiAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgaWYgKGNtZC5pbmNsdWRlcyhcImdpdCBwdXNoXCIpKSB7XG4gICAgICAgICAgICAgICAgZXZlbnRzLnB1c2goe1xuICAgICAgICAgICAgICAgICAgZXZlbnRUeXBlOiBcImdpdF9wdXNoXCIsXG4gICAgICAgICAgICAgICAgICB0aW1lc3RhbXA6IHRzLFxuICAgICAgICAgICAgICAgICAgcGF5bG9hZDoge1xuICAgICAgICAgICAgICAgICAgICBjb21tYW5kOiBjbWQsXG4gICAgICAgICAgICAgICAgICAgIHJlc3VsdF9zdW1tYXJ5OiByZXN1bHRUZXh0LnNsaWNlKDAsIDIwMCksXG4gICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIC8vIFBSIGRldGVjdGlvbiBmcm9tIGdoIHByIGNyZWF0ZSAvIHJlc3VsdCBVUkxzXG4gICAgICAgICAgICAgIGlmIChjbWQuaW5jbHVkZXMoXCJnaCBwciBjcmVhdGVcIikgfHwgY21kLmluY2x1ZGVzKFwiZ2ggcHIgbWVyZ2VcIikpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBwck1hdGNoID0gcmVzdWx0VGV4dC5tYXRjaChcbiAgICAgICAgICAgICAgICAgIC9odHRwczpcXC9cXC9naXRodWJcXC5jb21cXC8oW14vXStcXC9bXi9dKylcXC9wdWxsXFwvKFxcZCspLyxcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIGlmIChwck1hdGNoKSB7XG4gICAgICAgICAgICAgICAgICBldmVudHMucHVzaCh7XG4gICAgICAgICAgICAgICAgICAgIGV2ZW50VHlwZTogXCJwcl9vcGVuZWRcIixcbiAgICAgICAgICAgICAgICAgICAgdGltZXN0YW1wOiB0cyxcbiAgICAgICAgICAgICAgICAgICAgcGF5bG9hZDoge1xuICAgICAgICAgICAgICAgICAgICAgIGNvbW1hbmQ6IGNtZC5zbGljZSgwLCAyMDApLFxuICAgICAgICAgICAgICAgICAgICAgIHByX3VybDogcHJNYXRjaFswXSxcbiAgICAgICAgICAgICAgICAgICAgICByZXBvOiBwck1hdGNoWzFdLFxuICAgICAgICAgICAgICAgICAgICAgIHByX251bWJlcjogcGFyc2VJbnQocHJNYXRjaFsyXSwgMTApLFxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIEVycm9yIGV2ZW50cyBmb3IgZmFpbGVkIHRvb2wgY2FsbHNcbiAgICAgICAgICAgIGlmIChpc0Vycm9yICYmIHRvb2xSZXN1bHQ/LmNvbnRlbnQpIHtcbiAgICAgICAgICAgICAgZXZlbnRzLnB1c2goe1xuICAgICAgICAgICAgICAgIGV2ZW50VHlwZTogXCJlcnJvclwiLFxuICAgICAgICAgICAgICAgIHRpbWVzdGFtcDogdHMsXG4gICAgICAgICAgICAgICAgcGF5bG9hZDoge1xuICAgICAgICAgICAgICAgICAgdG9vbDogdG9vbFVzZS5uYW1lLFxuICAgICAgICAgICAgICAgICAgbWVzc2FnZTogU3RyaW5nKHRvb2xSZXN1bHQuY29udGVudCkuc2xpY2UoMCwgNTAwKSxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvLyBTb3J0IGV2ZW50cyBieSB0aW1lc3RhbXBcbiAgZXZlbnRzLnNvcnQoKGEsIGIpID0+IGEudGltZXN0YW1wLmxvY2FsZUNvbXBhcmUoYi50aW1lc3RhbXApKTtcblxuICAvLyBBZGQgc2Vzc2lvbl9zdGFydCBhcyBmaXJzdCBldmVudFxuICBldmVudHMudW5zaGlmdCh7XG4gICAgZXZlbnRUeXBlOiBcInNlc3Npb25fc3RhcnRcIixcbiAgICB0aW1lc3RhbXA6IHN0YXJ0ZWRBdCxcbiAgICBwYXlsb2FkOiB7XG4gICAgICBtb2RlbCxcbiAgICAgIGdpdF9icmFuY2g6IGdpdEJyYW5jaCxcbiAgICAgIHByb2plY3QsXG4gICAgICBoYXJuZXNzOiBcImNsYXVkZS1jb2RlXCIsXG4gICAgICB2ZXJzaW9uLFxuICAgICAgdXNlcl9pZDogdXNlcklkLFxuICAgIH0sXG4gIH0pO1xuXG4gIC8vIEFkZCBzZXNzaW9uX2VuZCBhcyBsYXN0IGV2ZW50XG4gIGV2ZW50cy5wdXNoKHtcbiAgICBldmVudFR5cGU6IFwic2Vzc2lvbl9lbmRcIixcbiAgICB0aW1lc3RhbXA6IGVuZGVkQXQsXG4gICAgcGF5bG9hZDoge1xuICAgICAgcmVhc29uOiBcInNlc3Npb25fZW5kX2luZmVycmVkXCIsXG4gICAgfSxcbiAgfSk7XG5cbiAgcmV0dXJuIHtcbiAgICBzZXNzaW9uSWQsXG4gICAgcHJvamVjdCxcbiAgICBnaXRCcmFuY2gsXG4gICAgaGFybmVzczogXCJjbGF1ZGUtY29kZVwiLFxuICAgIG1vZGVsLFxuICAgIHZlcnNpb24sXG4gICAgdXNlcklkLFxuICAgIHN0YXJ0ZWRBdCxcbiAgICBlbmRlZEF0LFxuICAgIGV2ZW50cyxcbiAgICB0b3RhbElucHV0VG9rZW5zLFxuICAgIHRvdGFsT3V0cHV0VG9rZW5zLFxuICAgIHRvdGFsQ2FjaGVSZWFkVG9rZW5zLFxuICAgIHRvdGFsQ2FjaGVXcml0ZVRva2VucyxcbiAgICB1c2VkU3ViYWdlbnRzLFxuICB9O1xufVxuIiwgIi8qKlxuICogUGFyc2UgYSBQaSBzZXNzaW9uIEpTT05MIHN0cmluZyBpbnRvIGFnZW50bGVucyBldmVudHMuXG4gKlxuICogUGkgc2Vzc2lvbiBmb3JtYXQgKHJlYWwgZGF0YSBmcm9tIH4vLnBpL2FnZW50L3Nlc3Npb25zLyk6XG4gKiAtIHR5cGU6IFwic2Vzc2lvblwiIFx1MjAxNCBtZXRhZGF0YTogeyBpZCwgdmVyc2lvbiwgY3dkLCB0aW1lc3RhbXAgfVxuICogLSB0eXBlOiBcIm1vZGVsX2NoYW5nZVwiIFx1MjAxNCB7IHByb3ZpZGVyLCBtb2RlbElkIH1cbiAqIC0gdHlwZTogXCJ0aGlua2luZ19sZXZlbF9jaGFuZ2VcIiBcdTIwMTQgeyB0aGlua2luZ0xldmVsIH1cbiAqIC0gdHlwZTogXCJtZXNzYWdlXCIgXHUyMDE0IGNvbnZlcnNhdGlvbiB0dXJuczpcbiAqICAgLSByb2xlOiBcInVzZXJcIiAgICAgICBcdTIwMTQgY29udGVudDogW3t0eXBlOlwidGV4dFwiLCB0ZXh0OlwiLi4uXCJ9XVxuICogICAtIHJvbGU6IFwiYXNzaXN0YW50XCIgIFx1MjAxNCBjb250ZW50OiBbe3R5cGU6XCJ0b29sQ2FsbFwifFwidGV4dFwifFwidGhpbmtpbmdcIiwgLi4ufV0sXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgIHVzYWdlOiB7aW5wdXQsIG91dHB1dCwgY2FjaGVSZWFkLCBjYWNoZVdyaXRlLCB0b3RhbFRva2VucywgY29zdDp7dG90YWwsLi4ufX1cbiAqICAgLSByb2xlOiBcInRvb2xSZXN1bHRcIiBcdTIwMTQgY29udGVudDogW3t0eXBlOlwidGV4dFwiLCB0ZXh0OlwiLi4uXCJ9XSxcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9vbENhbGxJZDogXCIuLi5cIiwgdG9vbE5hbWU6IFwiLi4uXCIsIGlzRXJyb3I6IGJvb2xcbiAqXG4gKiBUb29sIGFyZ3VtZW50IGtleXMgKGZyb20gcmVhbCBQaSBkYXRhKTpcbiAqICAgd3JpdGUvZWRpdC9yZWFkIFx1MjE5MiBhcmdzLnBhdGggKE5PVCBmaWxlX3BhdGggXHUyMDE0IHRoYXQncyBDbGF1ZGUgQ29kZSlcbiAqICAgYmFzaCAgICAgICAgICAgIFx1MjE5MiBhcmdzLmNvbW1hbmRcbiAqL1xuXG5pbXBvcnQgdHlwZSB7IFBhcnNlZEV2ZW50LCBQYXJzZWRTZXNzaW9uIH0gZnJvbSBcIi4uL2NsYXVkZS1jb2RlL3BhcnNlclwiO1xuaW1wb3J0IHsgZ2V0Q29udGV4dFdpbmRvdyB9IGZyb20gXCIuLi9tb2RlbC1jb250ZXh0XCI7XG5cbmNvbnN0IFNVQkFHRU5UX1RPT0xTID0gbmV3IFNldChbXCJzdWJhZ2VudFwiLCBcImRlbGVnYXRlXCIsIFwiVGFza1wiLCBcIkFnZW50XCJdKTtcblxuLyoqIEV4dHJhY3QgdGhlIGxhc3QgcGF0aCBzZWdtZW50IGFzIHRoZSBwcm9qZWN0IG5hbWUuICovXG5mdW5jdGlvbiBwcm9qZWN0RnJvbUN3ZChjd2Q6IHN0cmluZyk6IHN0cmluZyB7XG4gIGNvbnN0IHBhcnRzID0gY3dkLnJlcGxhY2UoL1xcLyskLywgXCJcIikuc3BsaXQoXCIvXCIpO1xuICByZXR1cm4gcGFydHNbcGFydHMubGVuZ3RoIC0gMV0gfHwgY3dkO1xufVxuXG4vKiogR2V0IHRoZSBmaWxlIHBhdGggZnJvbSB0b29sIGFyZ3MgXHUyMDE0IFBpIHVzZXMgYHBhdGhgLCBDbGF1ZGUgQ29kZSB1c2VzIGBmaWxlX3BhdGhgLiAqL1xuZnVuY3Rpb24gZ2V0RmlsZVBhdGgoYXJnczogUmVjb3JkPHN0cmluZywgYW55Pik6IHN0cmluZyB8IG51bGwge1xuICByZXR1cm4gYXJncy5wYXRoIHx8IGFyZ3MuZmlsZV9wYXRoIHx8IG51bGw7XG59XG5cbi8qKiBCdWlsZCBhIG9uZS1saW5lIHN1bW1hcnkgb2YgdG9vbCBhcmd1bWVudHMgZm9yIGRpc3BsYXkuICovXG5mdW5jdGlvbiBzdW1tYXJpemVUb29sSW5wdXQobmFtZTogc3RyaW5nLCBhcmdzOiBSZWNvcmQ8c3RyaW5nLCBhbnk+KTogc3RyaW5nIHtcbiAgY29uc3QgbG5hbWUgPSBuYW1lLnRvTG93ZXJDYXNlKCk7XG4gIGlmIChsbmFtZSA9PT0gXCJiYXNoXCIgJiYgYXJncy5jb21tYW5kKSB7XG4gICAgcmV0dXJuIFN0cmluZyhhcmdzLmNvbW1hbmQpLnNsaWNlKDAsIDIwMCk7XG4gIH1cbiAgY29uc3QgZmlsZVBhdGggPSBnZXRGaWxlUGF0aChhcmdzKTtcbiAgaWYgKChsbmFtZSA9PT0gXCJ3cml0ZVwiIHx8IGxuYW1lID09PSBcImVkaXRcIiB8fCBsbmFtZSA9PT0gXCJyZWFkXCIpICYmIGZpbGVQYXRoKSB7XG4gICAgcmV0dXJuIGZpbGVQYXRoO1xuICB9XG4gIC8vIG11bHRpLWVkaXQ6IHN1bW1hcml6ZSBmaXJzdCBwYXRoXG4gIGlmIChsbmFtZSA9PT0gXCJlZGl0XCIgJiYgQXJyYXkuaXNBcnJheShhcmdzLm11bHRpKSAmJiBhcmdzLm11bHRpLmxlbmd0aCA+IDApIHtcbiAgICBjb25zdCBmaXJzdFBhdGggPSBhcmdzLm11bHRpWzBdLnBhdGggfHwgYXJncy5tdWx0aVswXS5maWxlX3BhdGggfHwgXCJcIjtcbiAgICBjb25zdCBjb3VudCA9IGFyZ3MubXVsdGkubGVuZ3RoO1xuICAgIHJldHVybiBjb3VudCA+IDEgPyBgJHtmaXJzdFBhdGh9ICgrJHtjb3VudCAtIDF9IG1vcmUpYCA6IGZpcnN0UGF0aDtcbiAgfVxuICBpZiAoU1VCQUdFTlRfVE9PTFMuaGFzKG5hbWUpKSB7XG4gICAgcmV0dXJuIFN0cmluZyhhcmdzLnRhc2sgfHwgYXJncy5kZXNjcmlwdGlvbiB8fCBhcmdzLnByb21wdCB8fCBcIlwiKS5zbGljZSgwLCAyMDApO1xuICB9XG4gIC8vIEdlbmVyaWM6IGZpcnN0IG5vbi1jb250ZW50IHN0cmluZyB2YWx1ZVxuICBmb3IgKGNvbnN0IFtrZXksIHZhbF0gb2YgT2JqZWN0LmVudHJpZXMoYXJncykpIHtcbiAgICBpZiAoa2V5ID09PSBcImNvbnRlbnRcIikgY29udGludWU7IC8vIHNraXAgZmlsZSBjb250ZW50XG4gICAgaWYgKHR5cGVvZiB2YWwgPT09IFwic3RyaW5nXCIgJiYgdmFsLmxlbmd0aCA+IDApIHtcbiAgICAgIHJldHVybiB2YWwuc2xpY2UoMCwgMjAwKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIFwiXCI7XG59XG5cbi8vIFx1MjUwMFx1MjUwMCBUeXBlcyBmb3IgZmlyc3QtcGFzcyBjb2xsZWN0aW9uIFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFxuXG5pbnRlcmZhY2UgVG9vbFJlc3VsdEluZm8ge1xuICBjb250ZW50OiBzdHJpbmc7XG4gIGlzRXJyb3I6IGJvb2xlYW47XG4gIHRzOiBzdHJpbmc7XG59XG5cbi8vIFx1MjUwMFx1MjUwMCBNYWluIHBhcnNlciBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcblxuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlUGlTZXNzaW9uKGpzb25sOiBzdHJpbmcsIHNlc3Npb25EaXI/OiBzdHJpbmcpOiBQYXJzZWRTZXNzaW9uIHtcbiAgY29uc3QgbGluZXMgPSBqc29ubFxuICAgIC5zcGxpdChcIlxcblwiKVxuICAgIC5maWx0ZXIoKGwpID0+IGwudHJpbSgpKVxuICAgIC5tYXAoKGwpID0+IEpTT04ucGFyc2UobCkpO1xuXG4gIGNvbnN0IGV2ZW50czogUGFyc2VkRXZlbnRbXSA9IFtdO1xuICBsZXQgc2Vzc2lvbklkID0gXCJcIjtcbiAgbGV0IHByb2plY3QgPSBcIlwiO1xuICBsZXQgbW9kZWw6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICBsZXQgdmVyc2lvbiA9IFwiXCI7XG4gIGxldCBzdGFydGVkQXQgPSBcIlwiO1xuICBsZXQgZW5kZWRBdCA9IFwiXCI7XG4gIGxldCB1c2VkU3ViYWdlbnRzID0gZmFsc2U7XG5cbiAgbGV0IHRvdGFsSW5wdXRUb2tlbnMgPSAwO1xuICBsZXQgdG90YWxPdXRwdXRUb2tlbnMgPSAwO1xuICBsZXQgdG90YWxDYWNoZVJlYWRUb2tlbnMgPSAwO1xuICBsZXQgdG90YWxDYWNoZVdyaXRlVG9rZW5zID0gMDtcblxuICAvLyBcdTI1MDBcdTI1MDAgRmlyc3QgcGFzczogaW5kZXggdG9vbFJlc3VsdCBtZXNzYWdlcyBieSB0b29sQ2FsbElkIFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFxuICAvLyBSZWFsIFBpIGRhdGEgaGFzIHRvb2xDYWxsSWQgb24gdG9vbFJlc3VsdCBtZXNzYWdlcyBmb3IgZXhhY3QgbWF0Y2hpbmcuXG4gIC8vIEZhbGwgYmFjayB0byBzZXF1ZW50aWFsIGluZGV4IG1hdGNoaW5nIHdoZW4gdG9vbENhbGxJZCBpcyBhYnNlbnQuXG5cbiAgY29uc3QgdG9vbFJlc3VsdEJ5SWQgPSBuZXcgTWFwPHN0cmluZywgVG9vbFJlc3VsdEluZm8+KCk7XG4gIGNvbnN0IHRvb2xSZXN1bHRzQnlJbmRleDogVG9vbFJlc3VsdEluZm9bXSA9IFtdO1xuXG4gIGZvciAoY29uc3QgbGluZSBvZiBsaW5lcykge1xuICAgIGlmIChsaW5lLnR5cGUgIT09IFwibWVzc2FnZVwiKSBjb250aW51ZTtcbiAgICBjb25zdCBtc2cgPSBsaW5lLm1lc3NhZ2UgfHwge307XG4gICAgaWYgKG1zZy5yb2xlICE9PSBcInRvb2xSZXN1bHRcIikgY29udGludWU7XG5cbiAgICBjb25zdCB0ZXh0ID0gKG1zZy5jb250ZW50IHx8IFtdKVxuICAgICAgLmZpbHRlcigoYzogYW55KSA9PiBjLnR5cGUgPT09IFwidGV4dFwiKVxuICAgICAgLm1hcCgoYzogYW55KSA9PiBjLnRleHQpXG4gICAgICAuam9pbihcIlxcblwiKTtcbiAgICBjb25zdCBpbmZvOiBUb29sUmVzdWx0SW5mbyA9IHtcbiAgICAgIGNvbnRlbnQ6IHRleHQsXG4gICAgICBpc0Vycm9yOiBtc2cuaXNFcnJvciA9PT0gdHJ1ZSxcbiAgICAgIHRzOiBsaW5lLnRpbWVzdGFtcCxcbiAgICB9O1xuXG4gICAgaWYgKG1zZy50b29sQ2FsbElkKSB7XG4gICAgICB0b29sUmVzdWx0QnlJZC5zZXQobXNnLnRvb2xDYWxsSWQsIGluZm8pO1xuICAgIH1cbiAgICB0b29sUmVzdWx0c0J5SW5kZXgucHVzaChpbmZvKTtcbiAgfVxuXG4gIC8vIFx1MjUwMFx1MjUwMCBTZWNvbmQgcGFzczogZ2VuZXJhdGUgZXZlbnRzIFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFx1MjUwMFxuXG4gIGxldCB0b29sQ2FsbFNlcUluZGV4ID0gMDsgLy8gZmFsbGJhY2sgc2VxdWVudGlhbCBjb3VudGVyXG5cbiAgZm9yIChjb25zdCBsaW5lIG9mIGxpbmVzKSB7XG4gICAgY29uc3QgdHMgPSBsaW5lLnRpbWVzdGFtcDtcbiAgICBpZiAoIXRzKSBjb250aW51ZTtcblxuICAgIGlmICghc3RhcnRlZEF0IHx8IHRzIDwgc3RhcnRlZEF0KSBzdGFydGVkQXQgPSB0cztcbiAgICBpZiAoIWVuZGVkQXQgfHwgdHMgPiBlbmRlZEF0KSBlbmRlZEF0ID0gdHM7XG5cbiAgICAvLyBTZXNzaW9uIG1ldGFkYXRhXG4gICAgaWYgKGxpbmUudHlwZSA9PT0gXCJzZXNzaW9uXCIpIHtcbiAgICAgIHNlc3Npb25JZCA9IGxpbmUuaWQ7XG4gICAgICB2ZXJzaW9uID0gU3RyaW5nKGxpbmUudmVyc2lvbiB8fCBcIlwiKTtcbiAgICAgIGlmIChsaW5lLmN3ZCkgcHJvamVjdCA9IHByb2plY3RGcm9tQ3dkKGxpbmUuY3dkKTtcbiAgICB9XG5cbiAgICAvLyBNb2RlbCBjaGFuZ2VzXG4gICAgaWYgKGxpbmUudHlwZSA9PT0gXCJtb2RlbF9jaGFuZ2VcIiAmJiBsaW5lLm1vZGVsSWQpIHtcbiAgICAgIG1vZGVsID0gbGluZS5tb2RlbElkO1xuICAgIH1cblxuICAgIC8vIFNraXAgbm9uLW1lc3NhZ2UgbGluZXMgZnJvbSBoZXJlIG9uXG4gICAgaWYgKGxpbmUudHlwZSAhPT0gXCJtZXNzYWdlXCIpIGNvbnRpbnVlO1xuICAgIGNvbnN0IG1zZyA9IGxpbmUubWVzc2FnZSB8fCB7fTtcblxuICAgIC8vIFx1MjUwMFx1MjUwMCBVc2VyIHByb21wdHMgXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXG4gICAgaWYgKG1zZy5yb2xlID09PSBcInVzZXJcIikge1xuICAgICAgY29uc3QgdGV4dCA9IChtc2cuY29udGVudCB8fCBbXSlcbiAgICAgICAgLmZpbHRlcigoYzogYW55KSA9PiBjLnR5cGUgPT09IFwidGV4dFwiKVxuICAgICAgICAubWFwKChjOiBhbnkpID0+IGMudGV4dClcbiAgICAgICAgLmpvaW4oXCJcXG5cIik7XG4gICAgICBpZiAodGV4dC50cmltKCkpIHtcbiAgICAgICAgZXZlbnRzLnB1c2goe1xuICAgICAgICAgIGV2ZW50VHlwZTogXCJ1c2VyX3Byb21wdFwiLFxuICAgICAgICAgIHRpbWVzdGFtcDogdHMsXG4gICAgICAgICAgcGF5bG9hZDogeyBwcm9tcHRfdGV4dDogdGV4dCwgcHJvbXB0X2xlbmd0aDogdGV4dC5sZW5ndGggfSxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gXHUyNTAwXHUyNTAwIEFzc2lzdGFudCBtZXNzYWdlcyBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcbiAgICBpZiAobXNnLnJvbGUgPT09IFwiYXNzaXN0YW50XCIpIHtcbiAgICAgIGNvbnN0IHVzYWdlID0gbXNnLnVzYWdlIHx8IHt9O1xuICAgICAgY29uc3QgaW5wdXRUb2tlbnMgPSB1c2FnZS5pbnB1dCB8fCAwO1xuICAgICAgY29uc3Qgb3V0cHV0VG9rZW5zID0gdXNhZ2Uub3V0cHV0IHx8IDA7XG4gICAgICBjb25zdCBjYWNoZVJlYWQgPSB1c2FnZS5jYWNoZVJlYWQgfHwgMDtcbiAgICAgIGNvbnN0IGNhY2hlV3JpdGUgPSB1c2FnZS5jYWNoZVdyaXRlIHx8IDA7XG4gICAgICBjb25zdCBjb3N0VG90YWwgPSB1c2FnZS5jb3N0Py50b3RhbCB8fCAwO1xuXG4gICAgICB0b3RhbElucHV0VG9rZW5zICs9IGlucHV0VG9rZW5zO1xuICAgICAgdG90YWxPdXRwdXRUb2tlbnMgKz0gb3V0cHV0VG9rZW5zO1xuICAgICAgdG90YWxDYWNoZVJlYWRUb2tlbnMgKz0gY2FjaGVSZWFkO1xuICAgICAgdG90YWxDYWNoZVdyaXRlVG9rZW5zICs9IGNhY2hlV3JpdGU7XG5cbiAgICAgIGNvbnN0IHJlc3BvbnNlTW9kZWwgPSBtc2cubW9kZWwgfHwgbW9kZWw7XG4gICAgICBjb25zdCBjb250ZXh0V2luZG93ID0gZ2V0Q29udGV4dFdpbmRvdyhyZXNwb25zZU1vZGVsKTtcblxuICAgICAgZXZlbnRzLnB1c2goe1xuICAgICAgICBldmVudFR5cGU6IFwibGxtX3Jlc3BvbnNlXCIsXG4gICAgICAgIHRpbWVzdGFtcDogdHMsXG4gICAgICAgIHBheWxvYWQ6IHtcbiAgICAgICAgICBtb2RlbDogcmVzcG9uc2VNb2RlbCxcbiAgICAgICAgICBpbnB1dF90b2tlbnM6IGlucHV0VG9rZW5zLFxuICAgICAgICAgIG91dHB1dF90b2tlbnM6IG91dHB1dFRva2VucyxcbiAgICAgICAgICBjYWNoZV9yZWFkX3Rva2VuczogY2FjaGVSZWFkLFxuICAgICAgICAgIGNhY2hlX3dyaXRlX3Rva2VuczogY2FjaGVXcml0ZSxcbiAgICAgICAgICB0b3RhbF90b2tlbnM6IHVzYWdlLnRvdGFsVG9rZW5zIHx8IGlucHV0VG9rZW5zICsgb3V0cHV0VG9rZW5zLFxuICAgICAgICAgIHRvdGFsX2Nvc3RfdXNkOiBjb3N0VG90YWwsXG4gICAgICAgICAgc3RvcF9yZWFzb246IG1zZy5zdG9wX3JlYXNvbiB8fCBudWxsLFxuICAgICAgICAgIC4uLihjb250ZXh0V2luZG93ID8geyBjb250ZXh0X3dpbmRvdzogY29udGV4dFdpbmRvdyB9IDoge30pLFxuICAgICAgICB9LFxuICAgICAgfSk7XG5cbiAgICAgIC8vIFx1MjUwMFx1MjUwMCBUb29sIGNhbGxzIHdpdGhpbiBhc3Npc3RhbnQgY29udGVudCBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcbiAgICAgIGZvciAoY29uc3QgYyBvZiBtc2cuY29udGVudCB8fCBbXSkge1xuICAgICAgICBpZiAoYy50eXBlICE9PSBcInRvb2xDYWxsXCIpIGNvbnRpbnVlO1xuXG4gICAgICAgIGNvbnN0IHRvb2xJZCA9IGMuaWQ7XG4gICAgICAgIGNvbnN0IGFyZ3MgPSBjLmFyZ3VtZW50cyB8fCBjLmlucHV0IHx8IHt9O1xuXG4gICAgICAgIC8vIE1hdGNoIHRvIHJlc3VsdDogcHJlZmVyIGV4YWN0IGlkIG1hdGNoLCBmYWxsIGJhY2sgdG8gaW5kZXhcbiAgICAgICAgY29uc3QgdG9vbFJlc3VsdCA9XG4gICAgICAgICAgdG9vbFJlc3VsdEJ5SWQuZ2V0KHRvb2xJZCkgfHwgdG9vbFJlc3VsdHNCeUluZGV4W3Rvb2xDYWxsU2VxSW5kZXhdIHx8IG51bGw7XG4gICAgICAgIGNvbnN0IGlzRXJyb3IgPSB0b29sUmVzdWx0Py5pc0Vycm9yID09PSB0cnVlO1xuICAgICAgICBjb25zdCBpc1N1YmFnZW50ID0gU1VCQUdFTlRfVE9PTFMuaGFzKGMubmFtZSk7XG4gICAgICAgIGlmIChpc1N1YmFnZW50KSB1c2VkU3ViYWdlbnRzID0gdHJ1ZTtcblxuICAgICAgICBjb25zdCBhcmdzU3VtbWFyeSA9IHN1bW1hcml6ZVRvb2xJbnB1dChjLm5hbWUsIGFyZ3MpO1xuXG4gICAgICAgIGV2ZW50cy5wdXNoKHtcbiAgICAgICAgICBldmVudFR5cGU6IFwidG9vbF9jYWxsXCIsXG4gICAgICAgICAgdGltZXN0YW1wOiB0cyxcbiAgICAgICAgICBwYXlsb2FkOiB7XG4gICAgICAgICAgICB0b29sOiBjLm5hbWUsXG4gICAgICAgICAgICBhcmdzX3N1bW1hcnk6IGFyZ3NTdW1tYXJ5LFxuICAgICAgICAgICAgcmVzdWx0X3N1bW1hcnk6IHRvb2xSZXN1bHQ/LmNvbnRlbnQgPyB0b29sUmVzdWx0LmNvbnRlbnQuc2xpY2UoMCwgMjAwKSA6IFwiXCIsXG4gICAgICAgICAgICBzdWNjZXNzOiAhaXNFcnJvcixcbiAgICAgICAgICAgIGlzX2Vycm9yOiBpc0Vycm9yLFxuICAgICAgICAgICAgLi4uKGlzU3ViYWdlbnQgPyB7IGlzX3N1YmFnZW50OiB0cnVlIH0gOiB7fSksXG4gICAgICAgICAgfSxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gXHUyNTAwXHUyNTAwIEZpbGUgY2hhbmdlcyBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcbiAgICAgICAgY29uc3QgbG5hbWUgPSBjLm5hbWUudG9Mb3dlckNhc2UoKTtcbiAgICAgICAgY29uc3QgZmlsZVBhdGggPSBnZXRGaWxlUGF0aChhcmdzKTtcblxuICAgICAgICBpZiAobG5hbWUgPT09IFwid3JpdGVcIiAmJiBmaWxlUGF0aCkge1xuICAgICAgICAgIGV2ZW50cy5wdXNoKHtcbiAgICAgICAgICAgIGV2ZW50VHlwZTogXCJmaWxlX2NoYW5nZVwiLFxuICAgICAgICAgICAgdGltZXN0YW1wOiB0cyxcbiAgICAgICAgICAgIHBheWxvYWQ6IHsgcGF0aDogZmlsZVBhdGgsIGFjdGlvbjogXCJjcmVhdGVcIiB9LFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIGlmIChsbmFtZSA9PT0gXCJlZGl0XCIgfHwgbG5hbWUgPT09IFwibXVsdGllZGl0XCIpIHtcbiAgICAgICAgICBpZiAoZmlsZVBhdGgpIHtcbiAgICAgICAgICAgIGV2ZW50cy5wdXNoKHtcbiAgICAgICAgICAgICAgZXZlbnRUeXBlOiBcImZpbGVfY2hhbmdlXCIsXG4gICAgICAgICAgICAgIHRpbWVzdGFtcDogdHMsXG4gICAgICAgICAgICAgIHBheWxvYWQ6IHsgcGF0aDogZmlsZVBhdGgsIGFjdGlvbjogXCJlZGl0XCIgfSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgICAvLyBIYW5kbGUgbXVsdGktZWRpdDogYXJyYXkgb2Yge3BhdGgsIG9sZFRleHQsIG5ld1RleHR9XG4gICAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkoYXJncy5tdWx0aSkpIHtcbiAgICAgICAgICAgIGNvbnN0IHNlZW4gPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgICAgICAgICAgIGZvciAoY29uc3QgaXRlbSBvZiBhcmdzLm11bHRpKSB7XG4gICAgICAgICAgICAgIGNvbnN0IHAgPSBpdGVtLnBhdGggfHwgaXRlbS5maWxlX3BhdGg7XG4gICAgICAgICAgICAgIGlmIChwICYmICFzZWVuLmhhcyhwKSkge1xuICAgICAgICAgICAgICAgIHNlZW4uYWRkKHApO1xuICAgICAgICAgICAgICAgIGV2ZW50cy5wdXNoKHtcbiAgICAgICAgICAgICAgICAgIGV2ZW50VHlwZTogXCJmaWxlX2NoYW5nZVwiLFxuICAgICAgICAgICAgICAgICAgdGltZXN0YW1wOiB0cyxcbiAgICAgICAgICAgICAgICAgIHBheWxvYWQ6IHsgcGF0aDogcCwgYWN0aW9uOiBcImVkaXRcIiB9LFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gXHUyNTAwXHUyNTAwIEdpdCBkZXRlY3Rpb24gXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXHUyNTAwXG4gICAgICAgIGlmIChsbmFtZSA9PT0gXCJiYXNoXCIgJiYgYXJncy5jb21tYW5kKSB7XG4gICAgICAgICAgY29uc3QgY21kID0gU3RyaW5nKGFyZ3MuY29tbWFuZCk7XG4gICAgICAgICAgaWYgKGNtZC5pbmNsdWRlcyhcImdpdCBjb21taXRcIikpIHtcbiAgICAgICAgICAgIGV2ZW50cy5wdXNoKHtcbiAgICAgICAgICAgICAgZXZlbnRUeXBlOiBcImdpdF9jb21taXRcIixcbiAgICAgICAgICAgICAgdGltZXN0YW1wOiB0cyxcbiAgICAgICAgICAgICAgcGF5bG9hZDoge1xuICAgICAgICAgICAgICAgIGNvbW1hbmQ6IGNtZCxcbiAgICAgICAgICAgICAgICByZXN1bHRfc3VtbWFyeTogdG9vbFJlc3VsdD8uY29udGVudD8uc2xpY2UoMCwgMjAwKSB8fCBcIlwiLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChjbWQuaW5jbHVkZXMoXCJnaXQgcHVzaFwiKSkge1xuICAgICAgICAgICAgZXZlbnRzLnB1c2goe1xuICAgICAgICAgICAgICBldmVudFR5cGU6IFwiZ2l0X3B1c2hcIixcbiAgICAgICAgICAgICAgdGltZXN0YW1wOiB0cyxcbiAgICAgICAgICAgICAgcGF5bG9hZDoge1xuICAgICAgICAgICAgICAgIGNvbW1hbmQ6IGNtZCxcbiAgICAgICAgICAgICAgICByZXN1bHRfc3VtbWFyeTogdG9vbFJlc3VsdD8uY29udGVudD8uc2xpY2UoMCwgMjAwKSB8fCBcIlwiLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIC8vIFBSIGRldGVjdGlvbiBmcm9tIGdoIHByIGNyZWF0ZSAvIHJlc3VsdCBVUkxzXG4gICAgICAgICAgaWYgKGNtZC5pbmNsdWRlcyhcImdoIHByIGNyZWF0ZVwiKSB8fCBjbWQuaW5jbHVkZXMoXCJnaCBwciBtZXJnZVwiKSkge1xuICAgICAgICAgICAgY29uc3QgcmVzdWx0VGV4dCA9IHRvb2xSZXN1bHQ/LmNvbnRlbnQgfHwgXCJcIjtcbiAgICAgICAgICAgIGNvbnN0IHByTWF0Y2ggPSByZXN1bHRUZXh0Lm1hdGNoKC9odHRwczpcXC9cXC9naXRodWJcXC5jb21cXC8oW14vXStcXC9bXi9dKylcXC9wdWxsXFwvKFxcZCspLyk7XG4gICAgICAgICAgICBpZiAocHJNYXRjaCkge1xuICAgICAgICAgICAgICBldmVudHMucHVzaCh7XG4gICAgICAgICAgICAgICAgZXZlbnRUeXBlOiBcInByX29wZW5lZFwiLFxuICAgICAgICAgICAgICAgIHRpbWVzdGFtcDogdHMsXG4gICAgICAgICAgICAgICAgcGF5bG9hZDoge1xuICAgICAgICAgICAgICAgICAgY29tbWFuZDogY21kLnNsaWNlKDAsIDIwMCksXG4gICAgICAgICAgICAgICAgICBwcl91cmw6IHByTWF0Y2hbMF0sXG4gICAgICAgICAgICAgICAgICByZXBvOiBwck1hdGNoWzFdLFxuICAgICAgICAgICAgICAgICAgcHJfbnVtYmVyOiBwYXJzZUludChwck1hdGNoWzJdLCAxMCksXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gXHUyNTAwXHUyNTAwIEVycm9yIGV2ZW50cyBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcdTI1MDBcbiAgICAgICAgaWYgKGlzRXJyb3IgJiYgdG9vbFJlc3VsdD8uY29udGVudCkge1xuICAgICAgICAgIGV2ZW50cy5wdXNoKHtcbiAgICAgICAgICAgIGV2ZW50VHlwZTogXCJlcnJvclwiLFxuICAgICAgICAgICAgdGltZXN0YW1wOiB0cyxcbiAgICAgICAgICAgIHBheWxvYWQ6IHsgdG9vbDogYy5uYW1lLCBtZXNzYWdlOiB0b29sUmVzdWx0LmNvbnRlbnQuc2xpY2UoMCwgNTAwKSB9LFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgdG9vbENhbGxTZXFJbmRleCsrO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8vIFNvcnQgZXZlbnRzIGJ5IHRpbWVzdGFtcFxuICBldmVudHMuc29ydCgoYSwgYikgPT4gYS50aW1lc3RhbXAubG9jYWxlQ29tcGFyZShiLnRpbWVzdGFtcCkpO1xuXG4gIC8vIEJvb2tlbmQgZXZlbnRzXG4gIGV2ZW50cy51bnNoaWZ0KHtcbiAgICBldmVudFR5cGU6IFwic2Vzc2lvbl9zdGFydFwiLFxuICAgIHRpbWVzdGFtcDogc3RhcnRlZEF0LFxuICAgIHBheWxvYWQ6IHsgbW9kZWwsIHByb2plY3QsIGhhcm5lc3M6IFwicGlcIiwgdmVyc2lvbiB9LFxuICB9KTtcbiAgZXZlbnRzLnB1c2goe1xuICAgIGV2ZW50VHlwZTogXCJzZXNzaW9uX2VuZFwiLFxuICAgIHRpbWVzdGFtcDogZW5kZWRBdCxcbiAgICBwYXlsb2FkOiB7IHJlYXNvbjogXCJzZXNzaW9uX2VuZF9pbmZlcnJlZFwiIH0sXG4gIH0pO1xuXG4gIHJldHVybiB7XG4gICAgc2Vzc2lvbklkLFxuICAgIHByb2plY3QsXG4gICAgZ2l0QnJhbmNoOiBudWxsLFxuICAgIGhhcm5lc3M6IFwicGlcIixcbiAgICBtb2RlbCxcbiAgICB2ZXJzaW9uLFxuICAgIHVzZXJJZDogXCJcIixcbiAgICBzdGFydGVkQXQsXG4gICAgZW5kZWRBdCxcbiAgICBldmVudHMsXG4gICAgdG90YWxJbnB1dFRva2VucyxcbiAgICB0b3RhbE91dHB1dFRva2VucyxcbiAgICB0b3RhbENhY2hlUmVhZFRva2VucyxcbiAgICB0b3RhbENhY2hlV3JpdGVUb2tlbnMsXG4gICAgdXNlZFN1YmFnZW50cyxcbiAgfTtcbn1cbiIsICIvKipcbiAqIEZpbGUgd2F0Y2hlcjogcG9sbHMgZm9yIG5ldy91cGRhdGVkIHNlc3Npb24gSlNPTkwgZmlsZXMgYW5kIGltcG9ydHMgdGhlbS5cbiAqIFVzZXMgcG9sbGluZyAobm90IGZzLndhdGNoKSBmb3IgcmVsaWFiaWxpdHkgYWNyb3NzIHBsYXRmb3JtcyBhbmQgbmV0d29yayBkcml2ZXMuXG4gKi9cblxuaW1wb3J0IHR5cGUgeyBCZXR0ZXJTUUxpdGUzRGF0YWJhc2UgfSBmcm9tIFwiZHJpenpsZS1vcm0vYmV0dGVyLXNxbGl0ZTNcIjtcbmltcG9ydCB7IGluZGV4U2Vzc2lvbnMsIHR5cGUgSW5kZXhPcHRpb25zIH0gZnJvbSBcIi4vaW5kZXhlclwiO1xuXG5leHBvcnQgaW50ZXJmYWNlIFdhdGNoZXJPcHRpb25zIGV4dGVuZHMgSW5kZXhPcHRpb25zIHtcbiAgLyoqIFBvbGwgaW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIChkZWZhdWx0OiA1MDAwKSAqL1xuICBwb2xsSW50ZXJ2YWxNcz86IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBXYXRjaGVyIHtcbiAgc3RvcDogKCkgPT4gdm9pZDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVdhdGNoZXIoZGI6IEJldHRlclNRTGl0ZTNEYXRhYmFzZSwgb3B0aW9uczogV2F0Y2hlck9wdGlvbnMgPSB7fSk6IFdhdGNoZXIge1xuICBjb25zdCBpbnRlcnZhbCA9IG9wdGlvbnMucG9sbEludGVydmFsTXMgPz8gNTAwMDtcbiAgbGV0IHN0b3BwZWQgPSBmYWxzZTtcbiAgbGV0IHRpbWVyOiBSZXR1cm5UeXBlPHR5cGVvZiBzZXRUaW1lb3V0PiB8IG51bGwgPSBudWxsO1xuXG4gIGZ1bmN0aW9uIHBvbGwoKSB7XG4gICAgaWYgKHN0b3BwZWQpIHJldHVybjtcblxuICAgIHRyeSB7XG4gICAgICBpbmRleFNlc3Npb25zKGRiLCBvcHRpb25zKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8vIFN3YWxsb3cgZXJyb3JzIFx1MjAxNCBrZWVwIHBvbGxpbmdcbiAgICB9XG5cbiAgICBpZiAoIXN0b3BwZWQpIHtcbiAgICAgIHRpbWVyID0gc2V0VGltZW91dChwb2xsLCBpbnRlcnZhbCk7XG4gICAgfVxuICB9XG5cbiAgLy8gU3RhcnQgZmlyc3QgcG9sbCBpbW1lZGlhdGVseVxuICBwb2xsKCk7XG5cbiAgcmV0dXJuIHtcbiAgICBzdG9wKCkge1xuICAgICAgc3RvcHBlZCA9IHRydWU7XG4gICAgICBpZiAodGltZXIpIHtcbiAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVyKTtcbiAgICAgICAgdGltZXIgPSBudWxsO1xuICAgICAgfVxuICAgIH0sXG4gIH07XG59XG4iLCAiaW1wb3J0IERhdGFiYXNlIGZyb20gXCJiZXR0ZXItc3FsaXRlM1wiO1xuaW1wb3J0IHsgZHJpenpsZSB9IGZyb20gXCJkcml6emxlLW9ybS9iZXR0ZXItc3FsaXRlM1wiO1xuaW1wb3J0IHsgc3FsIH0gZnJvbSBcImRyaXp6bGUtb3JtXCI7XG5pbXBvcnQgdHlwZSB7IEJldHRlclNRTGl0ZTNEYXRhYmFzZSB9IGZyb20gXCJkcml6emxlLW9ybS9iZXR0ZXItc3FsaXRlM1wiO1xuaW1wb3J0IHBhdGggZnJvbSBcInBhdGhcIjtcbmltcG9ydCBmcyBmcm9tIFwiZnNcIjtcbmltcG9ydCB7IGhvbWVkaXIgfSBmcm9tIFwib3NcIjtcblxubGV0IF9kYjogQmV0dGVyU1FMaXRlM0RhdGFiYXNlIHwgbnVsbCA9IG51bGw7XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXREYigpOiBCZXR0ZXJTUUxpdGUzRGF0YWJhc2Uge1xuICBpZiAoX2RiKSByZXR1cm4gX2RiO1xuXG4gIGNvbnN0IGRiUGF0aCA9XG4gICAgcHJvY2Vzcy5lbnYuQUdFTlRMRU5TX0RCX1BBVEggfHwgcGF0aC5qb2luKGhvbWVkaXIoKSwgXCIuYWdlbnRsZW5zXCIsIFwiYWdlbnRsZW5zLmRiXCIpO1xuICBjb25zdCBkYXRhRGlyID0gcGF0aC5kaXJuYW1lKGRiUGF0aCk7XG4gIGlmICghZnMuZXhpc3RzU3luYyhkYXRhRGlyKSkge1xuICAgIGZzLm1rZGlyU3luYyhkYXRhRGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgfVxuICBjb25zdCBzcWxpdGUgPSBuZXcgRGF0YWJhc2UoZGJQYXRoKTtcblxuICAvLyBFbmFibGUgV0FMIG1vZGUgZm9yIGJldHRlciBjb25jdXJyZW50IHJlYWQvd3JpdGVcbiAgc3FsaXRlLnByYWdtYShcImpvdXJuYWxfbW9kZSA9IFdBTFwiKTtcblxuICBjb25zdCBkYiA9IGRyaXp6bGUoc3FsaXRlKTtcblxuICAvLyBBdXRvLWNyZWF0ZSB0YWJsZXMgaWYgdGhleSBkb24ndCBleGlzdFxuICBkYi5ydW4oc3FsYFxuICAgIENSRUFURSBUQUJMRSBJRiBOT1QgRVhJU1RTIHNlc3Npb25zIChcbiAgICAgIGlkIFRFWFQgUFJJTUFSWSBLRVksXG4gICAgICB0ZWFtX2lkIFRFWFQgTk9UIE5VTEwsXG4gICAgICB1c2VyX2lkIFRFWFQgTk9UIE5VTEwsXG4gICAgICBwcm9qZWN0IFRFWFQgTk9UIE5VTEwsXG4gICAgICBnaXRfcmVwbyBURVhULFxuICAgICAgZ2l0X2JyYW5jaCBURVhULFxuICAgICAgcGlfdmVyc2lvbiBURVhUIE5PVCBOVUxMIERFRkFVTFQgJycsXG4gICAgICBza2lsbHNfdXNlZCBURVhUIE5PVCBOVUxMIERFRkFVTFQgJ1tdJyxcbiAgICAgIG1vZGVsIFRFWFQsXG4gICAgICBoYXJuZXNzIFRFWFQgTk9UIE5VTEwgREVGQVVMVCAncGknLFxuICAgICAgc3RhcnRlZF9hdCBURVhUIE5PVCBOVUxMLFxuICAgICAgZW5kZWRfYXQgVEVYVCxcbiAgICAgIHN0YXR1cyBURVhUIE5PVCBOVUxMIERFRkFVTFQgJ2FjdGl2ZScsXG4gICAgICBjcmVhdGVkX2F0IFRFWFQgTk9UIE5VTEwgREVGQVVMVCAoZGF0ZXRpbWUoJ25vdycpKVxuICAgIClcbiAgYCk7XG4gIGRiLnJ1bihzcWxgXG4gICAgQ1JFQVRFIFRBQkxFIElGIE5PVCBFWElTVFMgZXZlbnRzIChcbiAgICAgIGlkIElOVEVHRVIgUFJJTUFSWSBLRVkgQVVUT0lOQ1JFTUVOVCxcbiAgICAgIHNlc3Npb25faWQgVEVYVCBOT1QgTlVMTCxcbiAgICAgIGV2ZW50X3R5cGUgVEVYVCBOT1QgTlVMTCxcbiAgICAgIHRpbWVzdGFtcCBURVhUIE5PVCBOVUxMLFxuICAgICAgcGF5bG9hZCBURVhUIE5PVCBOVUxMIERFRkFVTFQgJ3t9JyxcbiAgICAgIGNyZWF0ZWRfYXQgVEVYVCBOT1QgTlVMTCBERUZBVUxUIChkYXRldGltZSgnbm93JykpXG4gICAgKVxuICBgKTtcblxuICAvLyBNaWdyYXRpb25zIGZvciBleGlzdGluZyBkYXRhYmFzZXNcbiAgdHJ5IHtcbiAgICBkYi5ydW4oc3FsYEFMVEVSIFRBQkxFIHNlc3Npb25zIEFERCBDT0xVTU4gbW9kZWwgVEVYVGApO1xuICB9IGNhdGNoIHtcbiAgICAvLyBDb2x1bW4gYWxyZWFkeSBleGlzdHNcbiAgfVxuXG4gIC8vIENyZWF0ZSBpbmRleGVzXG4gIGRiLnJ1bihzcWxgQ1JFQVRFIElOREVYIElGIE5PVCBFWElTVFMgaWR4X3Nlc3Npb25zX3RlYW1faWQgT04gc2Vzc2lvbnModGVhbV9pZClgKTtcbiAgZGIucnVuKHNxbGBDUkVBVEUgSU5ERVggSUYgTk9UIEVYSVNUUyBpZHhfc2Vzc2lvbnNfdXNlcl9pZCBPTiBzZXNzaW9ucyh1c2VyX2lkKWApO1xuICBkYi5ydW4oc3FsYENSRUFURSBJTkRFWCBJRiBOT1QgRVhJU1RTIGlkeF9zZXNzaW9uc19wcm9qZWN0IE9OIHNlc3Npb25zKHByb2plY3QpYCk7XG4gIGRiLnJ1bihzcWxgQ1JFQVRFIElOREVYIElGIE5PVCBFWElTVFMgaWR4X3Nlc3Npb25zX3N0YXJ0ZWRfYXQgT04gc2Vzc2lvbnMoc3RhcnRlZF9hdClgKTtcbiAgZGIucnVuKHNxbGBDUkVBVEUgSU5ERVggSUYgTk9UIEVYSVNUUyBpZHhfc2Vzc2lvbnNfc3RhdHVzIE9OIHNlc3Npb25zKHN0YXR1cylgKTtcbiAgZGIucnVuKHNxbGBDUkVBVEUgSU5ERVggSUYgTk9UIEVYSVNUUyBpZHhfZXZlbnRzX3Nlc3Npb25faWQgT04gZXZlbnRzKHNlc3Npb25faWQpYCk7XG4gIGRiLnJ1bihcbiAgICBzcWxgQ1JFQVRFIElOREVYIElGIE5PVCBFWElTVFMgaWR4X2V2ZW50c19zZXNzaW9uX3RpbWVzdGFtcCBPTiBldmVudHMoc2Vzc2lvbl9pZCwgdGltZXN0YW1wKWAsXG4gICk7XG4gIGRiLnJ1bihzcWxgQ1JFQVRFIElOREVYIElGIE5PVCBFWElTVFMgaWR4X2V2ZW50c19ldmVudF90eXBlIE9OIGV2ZW50cyhldmVudF90eXBlKWApO1xuXG4gIC8vIFBSIHRyYWNraW5nIHRhYmxlXG4gIGRiLnJ1bihzcWxgXG4gICAgQ1JFQVRFIFRBQkxFIElGIE5PVCBFWElTVFMgcHVsbF9yZXF1ZXN0cyAoXG4gICAgICBpZCBJTlRFR0VSIFBSSU1BUlkgS0VZIEFVVE9JTkNSRU1FTlQsXG4gICAgICBzZXNzaW9uX2lkIFRFWFQgTk9UIE5VTEwsXG4gICAgICByZXBvIFRFWFQgTk9UIE5VTEwsXG4gICAgICBicmFuY2ggVEVYVCBOT1QgTlVMTCxcbiAgICAgIHByX251bWJlciBJTlRFR0VSIE5PVCBOVUxMLFxuICAgICAgcHJfdXJsIFRFWFQgTk9UIE5VTEwsXG4gICAgICBwcl90aXRsZSBURVhUIE5PVCBOVUxMIERFRkFVTFQgJycsXG4gICAgICBzdGF0dXMgVEVYVCBOT1QgTlVMTCBERUZBVUxUICdvcGVuJyxcbiAgICAgIG1lcmdlZF9hdCBURVhULFxuICAgICAgcmV2aWV3c19hcHByb3ZlZCBJTlRFR0VSIE5PVCBOVUxMIERFRkFVTFQgMCxcbiAgICAgIHJldmlld3NfY2hhbmdlc19yZXF1ZXN0ZWQgSU5URUdFUiBOT1QgTlVMTCBERUZBVUxUIDAsXG4gICAgICByZXZpZXdfY29tbWVudHMgSU5URUdFUiBOT1QgTlVMTCBERUZBVUxUIDAsXG4gICAgICBjb21taXRzX2FmdGVyX3JldmlldyBJTlRFR0VSIE5PVCBOVUxMIERFRkFVTFQgMCxcbiAgICAgIGZpcnN0X3Jldmlld19hdCBURVhULFxuICAgICAgdGltZV90b19tZXJnZV9ob3VycyBSRUFMLFxuICAgICAgY2hlY2tlZF9hdCBURVhULFxuICAgICAgY3JlYXRlZF9hdCBURVhUIE5PVCBOVUxMIERFRkFVTFQgKGRhdGV0aW1lKCdub3cnKSksXG4gICAgICBVTklRVUUoc2Vzc2lvbl9pZCwgcHJfbnVtYmVyKVxuICAgIClcbiAgYCk7XG4gIGRiLnJ1bihzcWxgQ1JFQVRFIElOREVYIElGIE5PVCBFWElTVFMgaWR4X3Byc19zZXNzaW9uX2lkIE9OIHB1bGxfcmVxdWVzdHMoc2Vzc2lvbl9pZClgKTtcbiAgZGIucnVuKHNxbGBDUkVBVEUgSU5ERVggSUYgTk9UIEVYSVNUUyBpZHhfcHJzX3N0YXR1cyBPTiBwdWxsX3JlcXVlc3RzKHN0YXR1cylgKTtcbiAgZGIucnVuKHNxbGBDUkVBVEUgSU5ERVggSUYgTk9UIEVYSVNUUyBpZHhfcHJzX3JlcG9fYnJhbmNoIE9OIHB1bGxfcmVxdWVzdHMocmVwbywgYnJhbmNoKWApO1xuXG4gIC8vIE1pZ3JhdGlvbnM6IGFkZCBjb2x1bW5zIHRoYXQgbWF5IGJlIG1pc3NpbmcgaW4gZXhpc3RpbmcgREJzXG4gIHRyeSB7XG4gICAgZGIucnVuKHNxbGBBTFRFUiBUQUJMRSBzZXNzaW9ucyBBREQgQ09MVU1OIG1vZGVsIFRFWFRgKTtcbiAgfSBjYXRjaCB7XG4gICAgLy8gQ29sdW1uIGFscmVhZHkgZXhpc3RzXG4gIH1cbiAgdHJ5IHtcbiAgICBkYi5ydW4oc3FsYEFMVEVSIFRBQkxFIHNlc3Npb25zIEFERCBDT0xVTU4gaGFybmVzcyBURVhUIE5PVCBOVUxMIERFRkFVTFQgJ3BpJ2ApO1xuICB9IGNhdGNoIHtcbiAgICAvLyBDb2x1bW4gYWxyZWFkeSBleGlzdHNcbiAgfVxuXG4gIC8vIEV2YWx1YXRpb24gdGFibGVzXG4gIGRiLnJ1bihzcWxgXG4gICAgQ1JFQVRFIFRBQkxFIElGIE5PVCBFWElTVFMgZXZhbF9jaGVja3MgKFxuICAgICAgaWQgSU5URUdFUiBQUklNQVJZIEtFWSBBVVRPSU5DUkVNRU5ULFxuICAgICAgc2Vzc2lvbl9pZCBURVhUIE5PVCBOVUxMLFxuICAgICAgY2hlY2tfaWQgVEVYVCBOT1QgTlVMTCxcbiAgICAgIGNoZWNrX3ZlcnNpb24gVEVYVCBOT1QgTlVMTCxcbiAgICAgIHNjb3JlIFJFQUwgTk9UIE5VTEwsXG4gICAgICByYXdfc2NvcmUgSU5URUdFUiBOT1QgTlVMTCxcbiAgICAgIHJlYXNvbmluZyBURVhUIE5PVCBOVUxMIERFRkFVTFQgJycsXG4gICAgICBldmlkZW5jZSBURVhULFxuICAgICAgbW9kZWwgVEVYVCBOT1QgTlVMTCxcbiAgICAgIGNvc3RfdXNkIFJFQUwgTk9UIE5VTEwgREVGQVVMVCAwLFxuICAgICAgZXZhbHVhdGVkX2F0IFRFWFQgTk9UIE5VTEwgREVGQVVMVCAoZGF0ZXRpbWUoJ25vdycpKSxcbiAgICAgIFVOSVFVRShzZXNzaW9uX2lkLCBjaGVja19pZCwgY2hlY2tfdmVyc2lvbilcbiAgICApXG4gIGApO1xuICBkYi5ydW4oc3FsYFxuICAgIENSRUFURSBUQUJMRSBJRiBOT1QgRVhJU1RTIGV2YWxfc3VtbWFyaWVzIChcbiAgICAgIHNlc3Npb25faWQgVEVYVCBQUklNQVJZIEtFWSxcbiAgICAgIHF1YWxfc2NvcmUgUkVBTCBOT1QgTlVMTCxcbiAgICAgIGNoZWNrc19wYXNzZWQgSU5URUdFUiBOT1QgTlVMTCBERUZBVUxUIDAsXG4gICAgICBjaGVja3NfdG90YWwgSU5URUdFUiBOT1QgTlVMTCBERUZBVUxUIDAsXG4gICAgICB0b3RhbF9ldmFsX2Nvc3RfdXNkIFJFQUwgTk9UIE5VTEwgREVGQVVMVCAwLFxuICAgICAgZXZhbHVhdGVkX2F0IFRFWFQgTk9UIE5VTEwgREVGQVVMVCAoZGF0ZXRpbWUoJ25vdycpKVxuICAgIClcbiAgYCk7XG4gIGRiLnJ1bihzcWxgQ1JFQVRFIElOREVYIElGIE5PVCBFWElTVFMgaWR4X2V2YWxfY2hlY2tzX3Nlc3Npb24gT04gZXZhbF9jaGVja3Moc2Vzc2lvbl9pZClgKTtcbiAgZGIucnVuKFxuICAgIHNxbGBDUkVBVEUgSU5ERVggSUYgTk9UIEVYSVNUUyBpZHhfZXZhbF9jaGVja3NfbG9va3VwIE9OIGV2YWxfY2hlY2tzKHNlc3Npb25faWQsIGNoZWNrX2lkLCBjaGVja192ZXJzaW9uKWAsXG4gICk7XG5cbiAgLy8gU2Vzc2lvbiBpbnNpZ2h0cyB0YWJsZSAodGVhbSBpbnNpZ2h0cyBmZWF0dXJlKVxuICBkYi5ydW4oc3FsYFxuICAgIENSRUFURSBUQUJMRSBJRiBOT1QgRVhJU1RTIHNlc3Npb25faW5zaWdodHMgKFxuICAgICAgc2Vzc2lvbl9pZCBURVhUIFBSSU1BUlkgS0VZLFxuICAgICAgdGFza19jYXRlZ29yeSBURVhUIE5PVCBOVUxMLFxuICAgICAgdGFza19zaXplIFRFWFQgTk9UIE5VTEwsXG4gICAgICB3b3JrZmxvd190YWdzIFRFWFQgTk9UIE5VTEwgREVGQVVMVCAnW10nLFxuICAgICAgcHJvbXB0aW5nX3RhZ3MgVEVYVCBOT1QgTlVMTCBERUZBVUxUICdbXScsXG4gICAgICBmYWlsdXJlX21vZGVzIFRFWFQgTk9UIE5VTEwgREVGQVVMVCAnW10nLFxuICAgICAgY29tcGxleGl0eV9mYWN0b3JzIFRFWFQgTk9UIE5VTEwgREVGQVVMVCAnW10nLFxuICAgICAga2V5X2xlYXJuaW5nIFRFWFQsXG4gICAgICBleHRyYWN0ZWRfYXQgVEVYVCBOT1QgTlVMTCBERUZBVUxUIChkYXRldGltZSgnbm93JykpLFxuICAgICAgbW9kZWwgVEVYVCBOT1QgTlVMTCxcbiAgICAgIHN5bmNlZF9hdCBURVhUXG4gICAgKVxuICBgKTtcblxuICAvLyBNaWdyYXRpb25zIGZvciBzZXNzaW9uX2luc2lnaHRzIG5ldyBjb2x1bW5zXG4gIGZvciAoY29uc3QgY29sIG9mIFtcbiAgICBcImZhaWx1cmVfbW9kZXMgVEVYVCBOT1QgTlVMTCBERUZBVUxUICdbXSdcIixcbiAgICBcImNvbXBsZXhpdHlfZmFjdG9ycyBURVhUIE5PVCBOVUxMIERFRkFVTFQgJ1tdJ1wiLFxuICAgIFwia2V5X2xlYXJuaW5nIFRFWFRcIixcbiAgXSkge1xuICAgIHRyeSB7XG4gICAgICBkYi5ydW4oc3FsLnJhdyhgQUxURVIgVEFCTEUgc2Vzc2lvbl9pbnNpZ2h0cyBBREQgQ09MVU1OICR7Y29sfWApKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8vIENvbHVtbiBhbHJlYWR5IGV4aXN0c1xuICAgIH1cbiAgfVxuXG4gIF9kYiA9IGRiO1xuICByZXR1cm4gZGI7XG59XG4iXSwKICAibWFwcGluZ3MiOiAiOzs7QUFVQSxTQUFTLFFBQUFBLE9BQU0sU0FBUyxlQUFlO0FBQ3ZDLFNBQVMsY0FBQUMsYUFBWSxXQUFXLGdCQUFBQyxxQkFBb0I7QUFDcEQsU0FBUyxXQUFBQyxnQkFBZTtBQUN4QixTQUFTLHFCQUFxQjtBQUM5QixTQUFTLE9BQU8sWUFBWTtBQUM1QixTQUFTLHFCQUFxQjs7O0FDWDlCLFNBQVMsYUFBYSxjQUFjLGtCQUFrQjtBQUN0RCxTQUFTLFlBQVk7QUFDckIsU0FBUyxnQkFBZ0I7QUFDekIsU0FBUyxnQkFBZ0I7QUFFekIsU0FBUyxNQUFBQyxXQUFVOzs7QUNUbkIsU0FBUyxLQUFLLElBQUksS0FBSyxLQUFLLEtBQUssTUFBTSxLQUFLLGFBQWE7QUFDekQsU0FBUyxhQUFhLE1BQU0sZUFBZTtBQUtwQyxJQUFNLFdBQVcsWUFBWSxZQUFZO0FBQUEsRUFDOUMsSUFBSSxLQUFLLElBQUksRUFBRSxXQUFXO0FBQUEsRUFDMUIsUUFBUSxLQUFLLFNBQVMsRUFBRSxRQUFRO0FBQUEsRUFDaEMsUUFBUSxLQUFLLFNBQVMsRUFBRSxRQUFRO0FBQUEsRUFDaEMsU0FBUyxLQUFLLFNBQVMsRUFBRSxRQUFRO0FBQUEsRUFDakMsU0FBUyxLQUFLLFVBQVU7QUFBQSxFQUN4QixXQUFXLEtBQUssWUFBWTtBQUFBLEVBQzVCLFdBQVcsS0FBSyxZQUFZ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RCxhQUFPLElBQUksV0FBVztBQUFBLElBQ3hCO0FBQUEsRUFDRixRQUFRO0FBQUEsRUFBQztBQUNULFNBQU87QUFDVDtBQUVBLFNBQVMsWUFBWSxLQUFhO0FBQ2hDLFFBQU0sTUFDSixRQUFRLGFBQWEsV0FBVyxTQUFTLFFBQVEsYUFBYSxVQUFVLFVBQVU7QUFFcEYsT0FBSyxHQUFHLEdBQUcsSUFBSSxHQUFHLElBQUksTUFBTTtBQUFBLEVBRTVCLENBQUM7QUFDSDtBQUVBLEtBQUssRUFBRSxNQUFNLENBQUMsUUFBUTtBQUNwQixVQUFRLE1BQU0sZ0JBQWdCLEdBQUc7QUFDakMsVUFBUSxLQUFLLENBQUM7QUFDaEIsQ0FBQzsiLAogICJuYW1lcyI6IFsiam9pbiIsICJleGlzdHNTeW5jIiwgInJlYWRGaWxlU3luYyIsICJob21lZGlyIiwgImVxIiwgImV2ZW50cyIsICJTVUJBR0VOVF9UT09MUyIsICJwcm9qZWN0RnJvbUN3ZCIsICJnZXRGaWxlUGF0aCIsICJhcmdzIiwgInN1bW1hcml6ZVRvb2xJbnB1dCIsICJjb3VudCIsICJldmVudHMiLCAidGV4dCIsICJlcSIsICJzcWwiLCAiZGJQYXRoIiwgImRhdGFEaXIiLCAiam9pbiIsICJob21lZGlyIiwgImV4aXN0c1N5bmMiLCAicmVxdWlyZSIsICJ0ZXh0IiwgInJlYWRGaWxlU3luYyJdCn0K
|