@hanzo/browser-extension 1.7.2

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.
Files changed (134) hide show
  1. package/.github/workflows/docs.yml +44 -0
  2. package/.github/workflows/release.yml +55 -0
  3. package/LICENSE +21 -0
  4. package/README.md +126 -0
  5. package/dist/browser-extension/README.md +43 -0
  6. package/dist/browser-extension/ai-worker.js +30 -0
  7. package/dist/browser-extension/background-firefox.js +617 -0
  8. package/dist/browser-extension/background.js +2737 -0
  9. package/dist/browser-extension/browser-control.js +683 -0
  10. package/dist/browser-extension/cdp-bridge-server.js +444 -0
  11. package/dist/browser-extension/chrome/ai-worker.js +571 -0
  12. package/dist/browser-extension/chrome/background.js +2737 -0
  13. package/dist/browser-extension/chrome/callback.html +17 -0
  14. package/dist/browser-extension/chrome/content-script.js +1270 -0
  15. package/dist/browser-extension/chrome/icon128.png +0 -0
  16. package/dist/browser-extension/chrome/icon16.png +0 -0
  17. package/dist/browser-extension/chrome/icon32.png +0 -0
  18. package/dist/browser-extension/chrome/icon48.png +0 -0
  19. package/dist/browser-extension/chrome/manifest.json +57 -0
  20. package/dist/browser-extension/chrome/popup.css +519 -0
  21. package/dist/browser-extension/chrome/popup.html +242 -0
  22. package/dist/browser-extension/chrome/popup.js +267 -0
  23. package/dist/browser-extension/chrome/sidebar.css +1176 -0
  24. package/dist/browser-extension/chrome/sidebar.html +280 -0
  25. package/dist/browser-extension/chrome/sidebar.js +778 -0
  26. package/dist/browser-extension/cli.js +233 -0
  27. package/dist/browser-extension/content-script.js +1270 -0
  28. package/dist/browser-extension/firefox/ai-worker.js +571 -0
  29. package/dist/browser-extension/firefox/background.js +617 -0
  30. package/dist/browser-extension/firefox/callback.html +17 -0
  31. package/dist/browser-extension/firefox/content-script.js +1270 -0
  32. package/dist/browser-extension/firefox/icon128.png +0 -0
  33. package/dist/browser-extension/firefox/icon16.png +0 -0
  34. package/dist/browser-extension/firefox/icon32.png +0 -0
  35. package/dist/browser-extension/firefox/icon48.png +0 -0
  36. package/dist/browser-extension/firefox/manifest.json +66 -0
  37. package/dist/browser-extension/firefox/popup.css +519 -0
  38. package/dist/browser-extension/firefox/popup.html +242 -0
  39. package/dist/browser-extension/firefox/popup.js +267 -0
  40. package/dist/browser-extension/firefox/sidebar.css +1176 -0
  41. package/dist/browser-extension/firefox/sidebar.html +280 -0
  42. package/dist/browser-extension/firefox/sidebar.js +778 -0
  43. package/dist/browser-extension/hanzo-browser-extension-firefox-1.1.0.zip +0 -0
  44. package/dist/browser-extension/icon128.png +0 -0
  45. package/dist/browser-extension/icon16.png +0 -0
  46. package/dist/browser-extension/icon32.png +0 -0
  47. package/dist/browser-extension/icon48.png +0 -0
  48. package/dist/browser-extension/manifest.json +57 -0
  49. package/dist/browser-extension/package.json +41 -0
  50. package/dist/browser-extension/popup.css +468 -0
  51. package/dist/browser-extension/popup.html +191 -0
  52. package/dist/browser-extension/popup.js +267 -0
  53. package/dist/browser-extension/safari/Info.plist +21 -0
  54. package/dist/browser-extension/safari/ai-worker.js +571 -0
  55. package/dist/browser-extension/safari/background.js +2737 -0
  56. package/dist/browser-extension/safari/callback.html +17 -0
  57. package/dist/browser-extension/safari/content-script.js +1270 -0
  58. package/dist/browser-extension/safari/icon128.png +0 -0
  59. package/dist/browser-extension/safari/icon16.png +0 -0
  60. package/dist/browser-extension/safari/icon32.png +0 -0
  61. package/dist/browser-extension/safari/icon48.png +0 -0
  62. package/dist/browser-extension/safari/popup.css +519 -0
  63. package/dist/browser-extension/safari/popup.html +242 -0
  64. package/dist/browser-extension/safari/popup.js +267 -0
  65. package/dist/browser-extension/safari/sidebar.css +1176 -0
  66. package/dist/browser-extension/safari/sidebar.html +280 -0
  67. package/dist/browser-extension/safari/sidebar.js +778 -0
  68. package/dist/browser-extension/sidebar.css +718 -0
  69. package/dist/browser-extension/sidebar.html +184 -0
  70. package/dist/browser-extension/sidebar.js +778 -0
  71. package/dist/browser-extension/webgpu-ai.js +495 -0
  72. package/dist/cdp-bridge-server.js +411 -0
  73. package/dist/safari/Hanzo AI/Hanzo AI.xcodeproj/project.pbxproj +1047 -0
  74. package/dist/safari/Hanzo AI/Hanzo AI.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  75. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
  76. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/Contents.json +98 -0
  77. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-128@1x.png +0 -0
  78. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-128@2x.png +0 -0
  79. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-16@1x.png +0 -0
  80. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-16@2x.png +0 -0
  81. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-256@1x.png +0 -0
  82. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-256@2x.png +0 -0
  83. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-32@1x.png +0 -0
  84. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-32@2x.png +0 -0
  85. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-512@1x.png +0 -0
  86. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-512@2x.png +0 -0
  87. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/universal-icon-1024@1x.png +0 -0
  88. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/Contents.json +6 -0
  89. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/LargeIcon.imageset/Contents.json +21 -0
  90. package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/LargeIcon.imageset/icon128.png +0 -0
  91. package/dist/safari/Hanzo AI/Shared (App)/Resources/Base.lproj/Main.html +20 -0
  92. package/dist/safari/Hanzo AI/Shared (App)/Resources/Icon.png +0 -0
  93. package/dist/safari/Hanzo AI/Shared (App)/Resources/Script.js +24 -0
  94. package/dist/safari/Hanzo AI/Shared (App)/Resources/Style.css +61 -0
  95. package/dist/safari/Hanzo AI/Shared (App)/ViewController.swift +81 -0
  96. package/dist/safari/Hanzo AI/Shared (Extension)/SafariWebExtensionHandler.swift +42 -0
  97. package/dist/safari/Hanzo AI/iOS (App)/AppDelegate.swift +24 -0
  98. package/dist/safari/Hanzo AI/iOS (App)/Base.lproj/LaunchScreen.storyboard +36 -0
  99. package/dist/safari/Hanzo AI/iOS (App)/Base.lproj/Main.storyboard +38 -0
  100. package/dist/safari/Hanzo AI/iOS (App)/Info.plist +27 -0
  101. package/dist/safari/Hanzo AI/iOS (App)/SceneDelegate.swift +18 -0
  102. package/dist/safari/Hanzo AI/iOS (Extension)/Info.plist +13 -0
  103. package/dist/safari/Hanzo AI/macOS (App)/AppDelegate.swift +21 -0
  104. package/dist/safari/Hanzo AI/macOS (App)/Base.lproj/Main.storyboard +124 -0
  105. package/dist/safari/Hanzo AI/macOS (App)/Info.plist +8 -0
  106. package/dist/safari/Hanzo AI/macOS (Extension)/Info.plist +13 -0
  107. package/docs/_config.yml +13 -0
  108. package/docs/_layouts/default.html +435 -0
  109. package/docs/index.md +54 -0
  110. package/install-extension.sh +75 -0
  111. package/manifest.json +29 -0
  112. package/package.json +32 -0
  113. package/src/ai-worker.js +571 -0
  114. package/src/callback.html +17 -0
  115. package/src/chat-widget.tsx +93 -0
  116. package/src/icon128.png +0 -0
  117. package/src/icon16.png +0 -0
  118. package/src/icon32.png +0 -0
  119. package/src/icon48.png +0 -0
  120. package/src/manifest-firefox.json +66 -0
  121. package/src/manifest.json +57 -0
  122. package/src/package.json +41 -0
  123. package/src/popup.css +519 -0
  124. package/src/popup.html +242 -0
  125. package/src/popup.js +192 -0
  126. package/src/sidebar.css +1176 -0
  127. package/src/sidebar.html +280 -0
  128. package/src/sidebar.js +884 -0
  129. package/src/webgpu.d.ts +131 -0
  130. package/test/claude-integration.test.ts +251 -0
  131. package/test/server-frameworks-edge-cases.test.ts +145 -0
  132. package/test/server-frameworks.test.ts +395 -0
  133. package/test-cdp-connection.js +140 -0
  134. package/tsconfig.json +19 -0
@@ -0,0 +1,778 @@
1
+ "use strict";
2
+ (() => {
3
+ // src/sidebar.ts
4
+ var HanzoSidebar = class {
5
+ constructor() {
6
+ this.agents = /* @__PURE__ */ new Map();
7
+ this.currentTab = "chat";
8
+ this.messages = [];
9
+ this.streaming = false;
10
+ this.streamController = null;
11
+ this.authenticated = false;
12
+ this.ragContext = null;
13
+ this.initializeUI();
14
+ this.setupEventListeners();
15
+ this.checkAuth();
16
+ }
17
+ initializeUI() {
18
+ this.el = {
19
+ // Auth
20
+ authSection: document.getElementById("auth-section"),
21
+ authBtn: document.getElementById("auth-btn"),
22
+ tabBar: document.getElementById("tab-bar"),
23
+ userBadge: document.getElementById("user-badge"),
24
+ headerAvatar: document.getElementById("header-avatar"),
25
+ // Chat
26
+ tabChat: document.getElementById("tab-chat"),
27
+ chatMessages: document.getElementById("chat-messages"),
28
+ chatInput: document.getElementById("chat-input"),
29
+ sendBtn: document.getElementById("send-btn"),
30
+ modelSelect: document.getElementById("model-select"),
31
+ ragEnabled: document.getElementById("rag-enabled"),
32
+ tabContextEnabled: document.getElementById("tab-context-enabled"),
33
+ ragStatus: document.getElementById("rag-status"),
34
+ // Tools
35
+ tabTools: document.getElementById("tab-tools"),
36
+ mcpStatus: document.getElementById("mcp-status"),
37
+ mcpTools: document.getElementById("mcp-tools"),
38
+ mcpToolList: document.getElementById("mcp-tool-list"),
39
+ agentCount: document.getElementById("agent-count"),
40
+ agentList: document.getElementById("agent-list"),
41
+ tabFs: document.getElementById("tab-fs"),
42
+ refreshTabs: document.getElementById("refresh-tabs"),
43
+ gpuStatus: document.getElementById("gpu-status"),
44
+ gpuModel: document.getElementById("gpu-model"),
45
+ launchAgent: document.getElementById("launch-agent"),
46
+ // Settings
47
+ tabSettings: document.getElementById("tab-settings"),
48
+ userAvatar: document.getElementById("user-avatar"),
49
+ userName: document.getElementById("user-name"),
50
+ userEmail: document.getElementById("user-email"),
51
+ logoutBtn: document.getElementById("logout-btn"),
52
+ saveSettings: document.getElementById("save-settings"),
53
+ defaultModel: document.getElementById("default-model"),
54
+ ragUseZap: document.getElementById("rag-use-zap"),
55
+ ragIncludeTabContext: document.getElementById("rag-include-tab-context"),
56
+ ragTopK: document.getElementById("rag-top-k"),
57
+ ragKb: document.getElementById("rag-kb"),
58
+ ragEndpoint: document.getElementById("rag-endpoint"),
59
+ ragApiKey: document.getElementById("rag-api-key")
60
+ };
61
+ }
62
+ setupEventListeners() {
63
+ var _a, _b;
64
+ this.el.authBtn.addEventListener("click", () => this.login());
65
+ document.querySelectorAll(".tab").forEach((tab) => {
66
+ tab.addEventListener("click", () => this.switchTab(tab.dataset.tab));
67
+ });
68
+ this.el.sendBtn.addEventListener("click", () => this.sendMessage());
69
+ this.el.chatInput.addEventListener("keydown", (e) => {
70
+ if (e.key === "Enter" && !e.shiftKey) {
71
+ e.preventDefault();
72
+ this.sendMessage();
73
+ }
74
+ });
75
+ this.el.chatInput.addEventListener("input", () => this.autoResize());
76
+ (_a = this.el.ragEnabled) == null ? void 0 : _a.addEventListener("change", () => {
77
+ this.setRagStatus(this.el.ragEnabled.checked ? "RAG enabled" : "RAG disabled");
78
+ });
79
+ (_b = this.el.tabContextEnabled) == null ? void 0 : _b.addEventListener("change", () => {
80
+ var _a2;
81
+ if (!((_a2 = this.el.ragEnabled) == null ? void 0 : _a2.checked)) return;
82
+ this.setRagStatus(this.el.tabContextEnabled.checked ? "Tab context on" : "Tab context off");
83
+ });
84
+ this.el.refreshTabs.addEventListener("click", () => this.refreshTabFilesystem());
85
+ this.el.launchAgent.addEventListener("click", () => this.showAgentLauncher());
86
+ this.el.logoutBtn.addEventListener("click", () => this.logout());
87
+ this.el.saveSettings.addEventListener("click", () => this.saveSettings());
88
+ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
89
+ this.handleMessage(request);
90
+ return true;
91
+ });
92
+ }
93
+ // ===========================================================================
94
+ // Auth
95
+ // ===========================================================================
96
+ async checkAuth() {
97
+ this.el.tabBar.classList.remove("hidden");
98
+ this.el.authSection.classList.add("hidden");
99
+ this.switchTab("tools");
100
+ this.connectToMCP();
101
+ this.refreshTabFilesystem();
102
+ this.checkWebGPU();
103
+ this.loadSettings();
104
+ this.startMonitoring();
105
+ try {
106
+ const response = await chrome.runtime.sendMessage({ action: "auth.status" });
107
+ if ((response == null ? void 0 : response.success) && response.authenticated) {
108
+ this.setUser(response.user);
109
+ this.switchTab("chat");
110
+ } else {
111
+ this.showChatLoginPrompt();
112
+ }
113
+ } catch (error) {
114
+ console.error("Auth check failed:", error);
115
+ this.showChatLoginPrompt();
116
+ }
117
+ }
118
+ async login() {
119
+ this.el.authBtn.disabled = true;
120
+ this.el.authBtn.textContent = "Signing in...";
121
+ try {
122
+ const response = await chrome.runtime.sendMessage({ action: "auth.login" });
123
+ if (response == null ? void 0 : response.success) {
124
+ this.setUser(response.user);
125
+ this.hideChatLoginPrompt();
126
+ } else {
127
+ this.showError((response == null ? void 0 : response.error) || "Sign in failed");
128
+ }
129
+ } catch (error) {
130
+ this.showError("Sign in failed");
131
+ } finally {
132
+ this.el.authBtn.disabled = false;
133
+ this.el.authBtn.textContent = "Sign in with Hanzo";
134
+ }
135
+ }
136
+ async logout() {
137
+ await chrome.runtime.sendMessage({ action: "auth.logout" });
138
+ this.el.userBadge.classList.add("hidden");
139
+ this.el.userName.textContent = "";
140
+ this.el.userEmail.textContent = "";
141
+ this.showChatLoginPrompt();
142
+ this.switchTab("tools");
143
+ }
144
+ setUser(user) {
145
+ this.authenticated = true;
146
+ if (user) {
147
+ const avatar = user.picture || user.avatar || "";
148
+ if (avatar) {
149
+ this.el.headerAvatar.src = avatar;
150
+ this.el.userBadge.classList.remove("hidden");
151
+ this.el.userAvatar.src = avatar;
152
+ }
153
+ this.el.userName.textContent = user.name || user.displayName || "User";
154
+ this.el.userEmail.textContent = user.email || "";
155
+ }
156
+ this.loadModels();
157
+ this.loadConversation();
158
+ }
159
+ showChatLoginPrompt() {
160
+ this.authenticated = false;
161
+ const chatLogin = document.getElementById("chat-login-prompt");
162
+ if (chatLogin) chatLogin.classList.remove("hidden");
163
+ const chatComposer = document.getElementById("chat-composer");
164
+ if (chatComposer) chatComposer.classList.add("hidden");
165
+ }
166
+ hideChatLoginPrompt() {
167
+ this.authenticated = true;
168
+ const chatLogin = document.getElementById("chat-login-prompt");
169
+ if (chatLogin) chatLogin.classList.add("hidden");
170
+ const chatComposer = document.getElementById("chat-composer");
171
+ if (chatComposer) chatComposer.classList.remove("hidden");
172
+ }
173
+ // ===========================================================================
174
+ // Tab Navigation
175
+ // ===========================================================================
176
+ switchTab(name) {
177
+ this.currentTab = name;
178
+ document.querySelectorAll(".tab").forEach((t) => {
179
+ t.classList.toggle("active", t.dataset.tab === name);
180
+ });
181
+ document.querySelectorAll(".tab-content").forEach((t) => t.classList.add("hidden"));
182
+ const target = document.getElementById(`tab-${name}`);
183
+ if (target) target.classList.remove("hidden");
184
+ }
185
+ // ===========================================================================
186
+ // Chat
187
+ // ===========================================================================
188
+ async loadModels() {
189
+ var _a;
190
+ try {
191
+ const response = await chrome.runtime.sendMessage({ action: "chat.listModels" });
192
+ if ((response == null ? void 0 : response.success) && ((_a = response.models) == null ? void 0 : _a.length)) {
193
+ const select = this.el.modelSelect;
194
+ select.innerHTML = "";
195
+ for (const model of response.models) {
196
+ const opt = document.createElement("option");
197
+ opt.value = model.id;
198
+ opt.textContent = model.name || model.id;
199
+ select.appendChild(opt);
200
+ }
201
+ this.el.defaultModel.innerHTML = select.innerHTML;
202
+ }
203
+ } catch {
204
+ }
205
+ }
206
+ async sendMessage() {
207
+ var _a, _b, _c, _d, _e, _f;
208
+ const text = this.el.chatInput.value.trim();
209
+ if (!text || this.streaming) return;
210
+ if (!this.authenticated) {
211
+ this.showError("Please sign in to use chat");
212
+ return;
213
+ }
214
+ const tokenResp = await chrome.runtime.sendMessage({ action: "auth.getToken" });
215
+ if (!(tokenResp == null ? void 0 : tokenResp.success) || !tokenResp.token) {
216
+ this.showError("Please sign in again");
217
+ return;
218
+ }
219
+ const userMessage = { role: "user", content: text };
220
+ const model = this.el.modelSelect.value;
221
+ let requestMessages = [...this.messages, userMessage];
222
+ this.ragContext = null;
223
+ if ((_a = this.el.ragEnabled) == null ? void 0 : _a.checked) {
224
+ this.setRagStatus("Retrieving context...");
225
+ const ragResp = await this.requestRagContext(text);
226
+ if ((ragResp == null ? void 0 : ragResp.success) && Array.isArray(ragResp.snippets) && ragResp.snippets.length) {
227
+ this.ragContext = ragResp;
228
+ requestMessages = [
229
+ { role: "system", content: this.buildRagSystemPrompt(ragResp) },
230
+ ...requestMessages
231
+ ];
232
+ this.setRagStatus(`RAG: ${ragResp.snippets.length} snippet(s) from ${ragResp.source || "context"}`);
233
+ } else if (ragResp == null ? void 0 : ragResp.error) {
234
+ this.setRagStatus(`RAG unavailable (${ragResp.error})`);
235
+ } else {
236
+ this.setRagStatus("No context found");
237
+ }
238
+ } else {
239
+ this.setRagStatus("RAG disabled");
240
+ }
241
+ this.messages.push(userMessage);
242
+ this.appendMessage("user", text);
243
+ this.el.chatInput.value = "";
244
+ this.autoResize();
245
+ this.streaming = true;
246
+ this.el.sendBtn.disabled = true;
247
+ const typingEl = this.showTyping();
248
+ const assistantEl = this.appendMessage("assistant", "");
249
+ let fullContent = "";
250
+ try {
251
+ const response = await fetch("https://api.hanzo.ai/v1/chat/completions", {
252
+ method: "POST",
253
+ headers: {
254
+ "Content-Type": "application/json",
255
+ "Authorization": `Bearer ${tokenResp.token}`
256
+ },
257
+ body: JSON.stringify({
258
+ model,
259
+ messages: requestMessages,
260
+ stream: true
261
+ }),
262
+ signal: (this.streamController = new AbortController()).signal
263
+ });
264
+ if (!response.ok) {
265
+ const errText = await response.text();
266
+ throw new Error(`API error ${response.status}: ${errText}`);
267
+ }
268
+ typingEl.remove();
269
+ const reader = response.body.getReader();
270
+ const decoder = new TextDecoder();
271
+ let buffer = "";
272
+ while (true) {
273
+ const { done, value } = await reader.read();
274
+ if (done) break;
275
+ buffer += decoder.decode(value, { stream: true });
276
+ const lines = buffer.split("\n");
277
+ buffer = lines.pop() || "";
278
+ for (const line of lines) {
279
+ const trimmed = line.trim();
280
+ if (!trimmed || trimmed.startsWith(":")) continue;
281
+ if (trimmed.startsWith("data: ")) {
282
+ const data = trimmed.slice(6);
283
+ if (data === "[DONE]") break;
284
+ try {
285
+ const parsed = JSON.parse(data);
286
+ const delta = (_d = (_c = (_b = parsed.choices) == null ? void 0 : _b[0]) == null ? void 0 : _c.delta) == null ? void 0 : _d.content;
287
+ if (delta) {
288
+ fullContent += delta;
289
+ assistantEl.innerHTML = this.renderMarkdown(fullContent);
290
+ this.scrollToBottom();
291
+ }
292
+ } catch {
293
+ }
294
+ }
295
+ }
296
+ }
297
+ if ((_f = (_e = this.ragContext) == null ? void 0 : _e.snippets) == null ? void 0 : _f.length) {
298
+ fullContent += this.buildRagCitationBlock(this.ragContext);
299
+ assistantEl.innerHTML = this.renderMarkdown(fullContent);
300
+ }
301
+ this.messages.push({ role: "assistant", content: fullContent });
302
+ this.saveConversation();
303
+ } catch (error) {
304
+ typingEl.remove();
305
+ if ((error == null ? void 0 : error.name) !== "AbortError") {
306
+ assistantEl.remove();
307
+ this.appendError((error == null ? void 0 : error.message) || "Chat failed");
308
+ }
309
+ } finally {
310
+ this.streaming = false;
311
+ this.streamController = null;
312
+ this.el.sendBtn.disabled = false;
313
+ }
314
+ }
315
+ async getActiveTabContext() {
316
+ try {
317
+ const [activeTab] = await chrome.tabs.query({ active: true, currentWindow: true });
318
+ if (!activeTab) return null;
319
+ return {
320
+ url: activeTab.url || "",
321
+ title: activeTab.title || ""
322
+ };
323
+ } catch {
324
+ return null;
325
+ }
326
+ }
327
+ async requestRagContext(query) {
328
+ var _a, _b, _c, _d, _e, _f, _g;
329
+ try {
330
+ const pageContext = ((_a = this.el.tabContextEnabled) == null ? void 0 : _a.checked) ? await this.getActiveTabContext() : null;
331
+ const topK = Math.max(1, Math.min(parseInt(((_b = this.el.ragTopK) == null ? void 0 : _b.value) || "5", 10) || 5, 20));
332
+ return await chrome.runtime.sendMessage({
333
+ action: "rag.query",
334
+ query,
335
+ topK,
336
+ includeTabContext: !!((_c = this.el.tabContextEnabled) == null ? void 0 : _c.checked),
337
+ useZapMemory: !!((_d = this.el.ragUseZap) == null ? void 0 : _d.checked),
338
+ knowledgeBase: ((_e = this.el.ragKb) == null ? void 0 : _e.value) || "",
339
+ endpoint: ((_f = this.el.ragEndpoint) == null ? void 0 : _f.value) || "",
340
+ apiKey: ((_g = this.el.ragApiKey) == null ? void 0 : _g.value) || "",
341
+ pageContext: pageContext || void 0
342
+ });
343
+ } catch (error) {
344
+ return { success: false, error: (error == null ? void 0 : error.message) || "Failed to query RAG" };
345
+ }
346
+ }
347
+ buildRagSystemPrompt(ragResponse) {
348
+ const snippets = ((ragResponse == null ? void 0 : ragResponse.snippets) || []).slice(0, 8);
349
+ const lines = snippets.map((snippet, index) => {
350
+ const title = snippet.title || snippet.source || `Snippet ${index + 1}`;
351
+ const score = typeof snippet.score === "number" ? ` (score ${snippet.score.toFixed(3)})` : "";
352
+ const sourceLine = snippet.url ? `${title}${score} \u2014 ${snippet.url}` : `${title}${score}`;
353
+ return `[${index + 1}] ${sourceLine}
354
+ ${snippet.content}`;
355
+ });
356
+ return [
357
+ "You are assisting inside Hanzo Browser Extension.",
358
+ "Use the retrieved context below when relevant, and state uncertainty if context is insufficient.",
359
+ "Retrieved Context:",
360
+ ...lines
361
+ ].join("\n\n");
362
+ }
363
+ buildRagCitationBlock(ragResponse) {
364
+ const snippets = ((ragResponse == null ? void 0 : ragResponse.snippets) || []).slice(0, 5);
365
+ if (!snippets.length) return "";
366
+ const rows = snippets.map((snippet, index) => {
367
+ const title = snippet.title || snippet.source || `Snippet ${index + 1}`;
368
+ if (snippet.url) {
369
+ return `- ${title}: ${snippet.url}`;
370
+ }
371
+ return `- ${title}`;
372
+ });
373
+ return `
374
+
375
+ ---
376
+ Context Sources:
377
+ ${rows.join("\n")}`;
378
+ }
379
+ setRagStatus(text) {
380
+ if (!this.el.ragStatus) return;
381
+ this.el.ragStatus.textContent = text || "Ready";
382
+ }
383
+ appendMessage(role, content) {
384
+ const welcome = this.el.chatMessages.querySelector(".chat-welcome");
385
+ if (welcome) welcome.remove();
386
+ const div = document.createElement("div");
387
+ div.className = `msg msg-${role}`;
388
+ div.innerHTML = role === "assistant" ? this.renderMarkdown(content) : this.escapeHtml(content);
389
+ this.el.chatMessages.appendChild(div);
390
+ this.scrollToBottom();
391
+ return div;
392
+ }
393
+ appendError(message) {
394
+ const div = document.createElement("div");
395
+ div.className = "msg-error";
396
+ div.textContent = message;
397
+ this.el.chatMessages.appendChild(div);
398
+ this.scrollToBottom();
399
+ }
400
+ showTyping() {
401
+ const div = document.createElement("div");
402
+ div.className = "typing-indicator";
403
+ div.innerHTML = "<span></span><span></span><span></span>";
404
+ this.el.chatMessages.appendChild(div);
405
+ this.scrollToBottom();
406
+ return div;
407
+ }
408
+ scrollToBottom() {
409
+ this.el.chatMessages.scrollTop = this.el.chatMessages.scrollHeight;
410
+ }
411
+ autoResize() {
412
+ const el = this.el.chatInput;
413
+ el.style.height = "auto";
414
+ el.style.height = Math.min(el.scrollHeight, 120) + "px";
415
+ }
416
+ // Minimal markdown: code blocks, inline code, bold, italic, line breaks
417
+ renderMarkdown(text) {
418
+ if (!text) return "";
419
+ let html = this.escapeHtml(text);
420
+ html = html.replace(/```(\w*)\n([\s\S]*?)```/g, (_, lang, code) => {
421
+ return `<pre><code>${code.trim()}</code></pre>`;
422
+ });
423
+ html = html.replace(/`([^`]+)`/g, "<code>$1</code>");
424
+ html = html.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>");
425
+ html = html.replace(/\*([^*]+)\*/g, "<em>$1</em>");
426
+ html = html.replace(/\n/g, "<br>");
427
+ return html;
428
+ }
429
+ escapeHtml(text) {
430
+ const div = document.createElement("div");
431
+ div.textContent = text;
432
+ return div.innerHTML;
433
+ }
434
+ async loadConversation() {
435
+ return new Promise((resolve) => {
436
+ chrome.storage.local.get(["hanzo_chat_messages"], (result) => {
437
+ var _a;
438
+ if ((_a = result.hanzo_chat_messages) == null ? void 0 : _a.length) {
439
+ this.messages = result.hanzo_chat_messages;
440
+ const welcome = this.el.chatMessages.querySelector(".chat-welcome");
441
+ if (welcome) welcome.remove();
442
+ for (const msg of this.messages) {
443
+ this.appendMessage(msg.role, msg.content);
444
+ }
445
+ }
446
+ resolve();
447
+ });
448
+ });
449
+ }
450
+ saveConversation() {
451
+ const toStore = this.messages.slice(-50);
452
+ chrome.storage.local.set({ hanzo_chat_messages: toStore });
453
+ }
454
+ // ===========================================================================
455
+ // Tools Tab
456
+ // ===========================================================================
457
+ async connectToMCP() {
458
+ var _a, _b;
459
+ try {
460
+ const zapResponse = await chrome.runtime.sendMessage({ action: "zap.status" });
461
+ if (zapResponse == null ? void 0 : zapResponse.success) {
462
+ const zap = zapResponse.zap;
463
+ const toolCount = ((_a = zap.mcps) == null ? void 0 : _a.reduce((sum, m) => {
464
+ var _a2;
465
+ return sum + (((_a2 = m.tools) == null ? void 0 : _a2.length) || 0);
466
+ }, 0)) || 0;
467
+ this.updateMCPStatus(zap.connected, toolCount, ((_b = zap.mcps) == null ? void 0 : _b.length) || 0);
468
+ if (zap.connected) {
469
+ const toolsResp = await chrome.runtime.sendMessage({ action: "zap.listTools" });
470
+ this.updateMCPToolList((toolsResp == null ? void 0 : toolsResp.success) ? toolsResp.tools : []);
471
+ } else {
472
+ this.updateMCPToolList([]);
473
+ }
474
+ } else {
475
+ this.updateMCPStatus(false);
476
+ this.updateMCPToolList([]);
477
+ }
478
+ } catch {
479
+ this.updateMCPStatus(false);
480
+ this.updateMCPToolList([]);
481
+ }
482
+ }
483
+ updateMCPStatus(connected, toolCount = 0, mcpCount = 0) {
484
+ this.el.mcpStatus.innerHTML = connected ? `
485
+ <span class="status-indicator connected"></span>
486
+ ${mcpCount > 0 ? `ZAP: ${mcpCount} MCP(s)` : "Connected"}
487
+ ` : `
488
+ <span class="status-indicator disconnected"></span>
489
+ Disconnected
490
+ `;
491
+ this.el.mcpTools.textContent = toolCount;
492
+ }
493
+ updateMCPToolList(tools) {
494
+ if (!this.el.mcpToolList) return;
495
+ if (!tools || !tools.length) {
496
+ this.el.mcpToolList.textContent = "No tools discovered yet.";
497
+ return;
498
+ }
499
+ const names = Array.from(new Set(tools.map((tool) => tool.name))).sort();
500
+ const preview = names.slice(0, 20);
501
+ const suffix = names.length > preview.length ? `
502
+ ... +${names.length - preview.length} more` : "";
503
+ this.el.mcpToolList.textContent = `${preview.join("\n")}${suffix}`;
504
+ }
505
+ async refreshTabFilesystem() {
506
+ try {
507
+ const tabs = await chrome.tabs.query({});
508
+ this.el.tabFs.innerHTML = tabs.map((tab, i) => `
509
+ <div class="tab-item ${tab.active ? "active" : ""}" data-tab-id="${tab.id}">
510
+ <svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor">
511
+ <path d="M2 2v12h12V2H2zm1 1h10v10H3V3z"/>
512
+ </svg>
513
+ <span title="${this.escapeHtml(tab.url || "")}">/tabs/${i}/${this.sanitizePath(tab.title || "untitled")}</span>
514
+ </div>
515
+ `).join("");
516
+ this.el.tabFs.querySelectorAll(".tab-item").forEach((item) => {
517
+ item.addEventListener("click", () => {
518
+ chrome.tabs.update(parseInt(item.dataset.tabId), { active: true });
519
+ });
520
+ });
521
+ } catch {
522
+ }
523
+ }
524
+ sanitizePath(title) {
525
+ return title.replace(/[^a-zA-Z0-9-_]/g, "_").toLowerCase().substring(0, 30);
526
+ }
527
+ async checkWebGPU() {
528
+ try {
529
+ const response = await chrome.runtime.sendMessage({ action: "checkWebGPU" });
530
+ if (response == null ? void 0 : response.available) {
531
+ this.el.gpuStatus.innerHTML = `
532
+ <span class="status-indicator connected"></span>
533
+ Available
534
+ `;
535
+ this.el.gpuModel.textContent = response.adapter || "Unknown";
536
+ } else {
537
+ this.el.gpuStatus.innerHTML = `
538
+ <span class="status-indicator disconnected"></span>
539
+ Not Available
540
+ `;
541
+ }
542
+ } catch {
543
+ }
544
+ }
545
+ updateAgentList() {
546
+ const arr = Array.from(this.agents.values());
547
+ this.el.agentCount.textContent = arr.length;
548
+ if (arr.length === 0) {
549
+ this.el.agentList.innerHTML = '<div class="empty-state">No active agents</div>';
550
+ return;
551
+ }
552
+ this.el.agentList.innerHTML = arr.map((a) => `
553
+ <div class="agent-item">
554
+ <div class="agent-icon">
555
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
556
+ <circle cx="12" cy="12" r="10" stroke-width="2"/>
557
+ <path d="M12 6v6l4 2" stroke-width="2"/>
558
+ </svg>
559
+ </div>
560
+ <div class="agent-info">
561
+ <div class="agent-name">${this.escapeHtml(a.name)}</div>
562
+ <div class="agent-status">${a.status} \u2022 Tab ${a.tabId}</div>
563
+ </div>
564
+ <div class="agent-actions">
565
+ <button class="icon-btn small" data-stop="${a.id}" title="Stop">
566
+ <svg viewBox="0 0 16 16" fill="currentColor">
567
+ <rect x="4" y="4" width="8" height="8" stroke-width="2"/>
568
+ </svg>
569
+ </button>
570
+ </div>
571
+ </div>
572
+ `).join("");
573
+ this.el.agentList.querySelectorAll("[data-stop]").forEach((btn) => {
574
+ btn.addEventListener("click", () => {
575
+ const id = btn.dataset.stop;
576
+ chrome.runtime.sendMessage({ action: "stopAgent", agentId: id });
577
+ this.agents.delete(id);
578
+ this.updateAgentList();
579
+ });
580
+ });
581
+ }
582
+ showAgentLauncher() {
583
+ const overlay = document.createElement("div");
584
+ overlay.className = "modal-overlay";
585
+ overlay.innerHTML = `
586
+ <div class="modal-content">
587
+ <div class="modal-header">
588
+ <h3>Launch Agent</h3>
589
+ <button class="icon-btn close-modal">&times;</button>
590
+ </div>
591
+ <div class="modal-body">
592
+ <label class="setting-item">
593
+ <span>Target Tab</span>
594
+ <select id="agent-tab-select">
595
+ <option value="active">Active Tab</option>
596
+ </select>
597
+ </label>
598
+ <label class="setting-item">
599
+ <span>Agent Type</span>
600
+ <select id="agent-type-select">
601
+ <option value="browser-control">Browser Automation</option>
602
+ <option value="page-analyzer">Page Analyzer</option>
603
+ <option value="form-filler">Form Filler</option>
604
+ <option value="data-extractor">Data Extractor</option>
605
+ </select>
606
+ </label>
607
+ <label class="setting-item">
608
+ <span>Instructions</span>
609
+ <textarea id="agent-instructions" rows="3" placeholder="Describe what the agent should do..."></textarea>
610
+ </label>
611
+ </div>
612
+ <div class="modal-footer">
613
+ <button class="secondary-btn cancel-modal">Cancel</button>
614
+ <button class="primary-btn launch-modal">Launch</button>
615
+ </div>
616
+ </div>
617
+ `;
618
+ document.body.appendChild(overlay);
619
+ chrome.tabs.query({}, (tabs) => {
620
+ const select = overlay.querySelector("#agent-tab-select");
621
+ tabs.forEach((tab) => {
622
+ var _a;
623
+ if (tab.id) {
624
+ const opt = document.createElement("option");
625
+ opt.value = tab.id;
626
+ opt.textContent = `${((_a = tab.title) == null ? void 0 : _a.substring(0, 40)) || "Untitled"} ${tab.active ? "(active)" : ""}`;
627
+ select.appendChild(opt);
628
+ }
629
+ });
630
+ });
631
+ overlay.querySelector(".close-modal").addEventListener("click", () => overlay.remove());
632
+ overlay.querySelector(".cancel-modal").addEventListener("click", () => overlay.remove());
633
+ overlay.addEventListener("click", (e) => {
634
+ if (e.target === overlay) overlay.remove();
635
+ });
636
+ overlay.querySelector(".launch-modal").addEventListener("click", async () => {
637
+ var _a;
638
+ const tabSelect = overlay.querySelector("#agent-tab-select");
639
+ const typeSelect = overlay.querySelector("#agent-type-select");
640
+ const instructions = overlay.querySelector("#agent-instructions");
641
+ let tabId;
642
+ if (tabSelect.value === "active") {
643
+ const [activeTab] = await chrome.tabs.query({ active: true, currentWindow: true });
644
+ tabId = activeTab == null ? void 0 : activeTab.id;
645
+ } else {
646
+ tabId = parseInt(tabSelect.value);
647
+ }
648
+ if (!tabId) {
649
+ this.showError("No tab selected");
650
+ return;
651
+ }
652
+ const agentType = typeSelect.value;
653
+ const agentInstructions = ((_a = instructions.value) == null ? void 0 : _a.trim()) || "";
654
+ overlay.remove();
655
+ try {
656
+ const response = await chrome.runtime.sendMessage({
657
+ action: "launchAIWorker",
658
+ tabId,
659
+ model: agentType,
660
+ instructions: agentInstructions
661
+ });
662
+ if (response == null ? void 0 : response.success) {
663
+ const agentId = response.agentId || `agent-${Date.now().toString(36)}`;
664
+ this.agents.set(agentId, {
665
+ id: agentId,
666
+ name: agentType,
667
+ tabId,
668
+ status: "running"
669
+ });
670
+ this.updateAgentList();
671
+ this.showNotification(`Agent launched on tab ${tabId}`);
672
+ } else {
673
+ this.showError((response == null ? void 0 : response.error) || "Failed to launch agent");
674
+ }
675
+ } catch (error) {
676
+ this.showError("Failed to launch agent: " + error.message);
677
+ }
678
+ });
679
+ }
680
+ // ===========================================================================
681
+ // Settings Tab
682
+ // ===========================================================================
683
+ loadSettings() {
684
+ chrome.storage.local.get([
685
+ "mcpPort",
686
+ "cdpPort",
687
+ "zapPorts",
688
+ "hanzo_default_model",
689
+ "hanzo_rag_endpoint",
690
+ "hanzo_rag_api_key",
691
+ "hanzo_rag_kb",
692
+ "hanzo_rag_top_k",
693
+ "hanzo_rag_include_tab_context",
694
+ "hanzo_rag_use_zap",
695
+ "hanzo_chat_rag_enabled",
696
+ "hanzo_chat_tab_context_enabled"
697
+ ], (result) => {
698
+ var _a;
699
+ const mcpPort = document.getElementById("mcp-port-setting");
700
+ const cdpPort = document.getElementById("cdp-port-setting");
701
+ const zapPorts = document.getElementById("zap-ports-setting");
702
+ if (mcpPort) mcpPort.value = result.mcpPort || 3001;
703
+ if (cdpPort) cdpPort.value = result.cdpPort || 9223;
704
+ if (zapPorts) zapPorts.value = (result.zapPorts || [9999, 9998, 9997, 9996, 9995]).join(",");
705
+ if (result.hanzo_default_model && this.el.defaultModel) {
706
+ this.el.defaultModel.value = result.hanzo_default_model;
707
+ }
708
+ if (this.el.ragEndpoint) this.el.ragEndpoint.value = result.hanzo_rag_endpoint || "";
709
+ if (this.el.ragApiKey) this.el.ragApiKey.value = result.hanzo_rag_api_key || "";
710
+ if (this.el.ragKb) this.el.ragKb.value = result.hanzo_rag_kb || "";
711
+ if (this.el.ragTopK) this.el.ragTopK.value = String(result.hanzo_rag_top_k || 5);
712
+ if (this.el.ragIncludeTabContext) this.el.ragIncludeTabContext.checked = result.hanzo_rag_include_tab_context !== false;
713
+ if (this.el.ragUseZap) this.el.ragUseZap.checked = result.hanzo_rag_use_zap !== false;
714
+ if (this.el.ragEnabled) this.el.ragEnabled.checked = result.hanzo_chat_rag_enabled !== false;
715
+ if (this.el.tabContextEnabled) this.el.tabContextEnabled.checked = result.hanzo_chat_tab_context_enabled !== false;
716
+ this.setRagStatus(((_a = this.el.ragEnabled) == null ? void 0 : _a.checked) ? "Ready" : "RAG disabled");
717
+ });
718
+ }
719
+ async saveSettings() {
720
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
721
+ const mcpPort = parseInt((_a = document.getElementById("mcp-port-setting")) == null ? void 0 : _a.value) || 3001;
722
+ const cdpPort = parseInt((_b = document.getElementById("cdp-port-setting")) == null ? void 0 : _b.value) || 9223;
723
+ const zapPorts = (((_c = document.getElementById("zap-ports-setting")) == null ? void 0 : _c.value) || "").split(",").map((p) => parseInt(p.trim())).filter((p) => p > 0 && p < 65536);
724
+ await chrome.storage.local.set({
725
+ mcpPort,
726
+ cdpPort,
727
+ zapPorts: zapPorts.length ? zapPorts : [9999, 9998, 9997, 9996, 9995],
728
+ hanzo_default_model: ((_d = this.el.defaultModel) == null ? void 0 : _d.value) || "gpt-4o",
729
+ "safe-mode": (_e = document.getElementById("safe-mode")) == null ? void 0 : _e.checked,
730
+ "enable-webgpu": (_f = document.getElementById("enable-webgpu")) == null ? void 0 : _f.checked,
731
+ maxAgents: parseInt((_g = document.getElementById("max-agents")) == null ? void 0 : _g.value) || 3,
732
+ hanzo_rag_endpoint: ((_i = (_h = this.el.ragEndpoint) == null ? void 0 : _h.value) == null ? void 0 : _i.trim()) || "",
733
+ hanzo_rag_api_key: ((_k = (_j = this.el.ragApiKey) == null ? void 0 : _j.value) == null ? void 0 : _k.trim()) || "",
734
+ hanzo_rag_kb: ((_m = (_l = this.el.ragKb) == null ? void 0 : _l.value) == null ? void 0 : _m.trim()) || "",
735
+ hanzo_rag_top_k: Math.max(1, Math.min(parseInt(((_n = this.el.ragTopK) == null ? void 0 : _n.value) || "5", 10) || 5, 20)),
736
+ hanzo_rag_include_tab_context: !!((_o = this.el.ragIncludeTabContext) == null ? void 0 : _o.checked),
737
+ hanzo_rag_use_zap: !!((_p = this.el.ragUseZap) == null ? void 0 : _p.checked),
738
+ hanzo_chat_rag_enabled: !!((_q = this.el.ragEnabled) == null ? void 0 : _q.checked),
739
+ hanzo_chat_tab_context_enabled: !!((_r = this.el.tabContextEnabled) == null ? void 0 : _r.checked)
740
+ });
741
+ this.showNotification("Settings saved");
742
+ }
743
+ // ===========================================================================
744
+ // Utility
745
+ // ===========================================================================
746
+ startMonitoring() {
747
+ setInterval(() => this.connectToMCP(), 1e4);
748
+ chrome.tabs.onUpdated.addListener(() => this.refreshTabFilesystem());
749
+ chrome.tabs.onRemoved.addListener(() => this.refreshTabFilesystem());
750
+ }
751
+ handleMessage(request) {
752
+ switch (request.action) {
753
+ case "agentUpdate":
754
+ if (request.agentId && this.agents.has(request.agentId)) {
755
+ this.agents.get(request.agentId).status = request.status;
756
+ this.updateAgentList();
757
+ }
758
+ break;
759
+ }
760
+ }
761
+ showNotification(message) {
762
+ const el = document.createElement("div");
763
+ el.className = "notification";
764
+ el.textContent = message;
765
+ document.body.appendChild(el);
766
+ setTimeout(() => el.remove(), 3e3);
767
+ }
768
+ showError(message) {
769
+ const el = document.createElement("div");
770
+ el.className = "notification error";
771
+ el.textContent = message;
772
+ document.body.appendChild(el);
773
+ setTimeout(() => el.remove(), 5e3);
774
+ }
775
+ };
776
+ var hanzoSidebar = new HanzoSidebar();
777
+ })();
778
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vc3JjL3NpZGViYXIudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbIi8vIEhhbnpvIEFJIEJyb3dzZXIgRXh0ZW5zaW9uIFNpZGViYXIgXHUyMDE0IENoYXQgKyBUb29scyArIFNldHRpbmdzXG5cbmNsYXNzIEhhbnpvU2lkZWJhciB7XG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHRoaXMuYWdlbnRzID0gbmV3IE1hcCgpO1xuICAgIHRoaXMuY3VycmVudFRhYiA9ICdjaGF0JztcbiAgICB0aGlzLm1lc3NhZ2VzID0gW107XG4gICAgdGhpcy5zdHJlYW1pbmcgPSBmYWxzZTtcbiAgICB0aGlzLnN0cmVhbUNvbnRyb2xsZXIgPSBudWxsO1xuICAgIHRoaXMuYXV0aGVudGljYXRlZCA9IGZhbHNlO1xuICAgIHRoaXMucmFnQ29udGV4dCA9IG51bGw7XG5cbiAgICB0aGlzLmluaXRpYWxpemVVSSgpO1xuICAgIHRoaXMuc2V0dXBFdmVudExpc3RlbmVycygpO1xuICAgIHRoaXMuY2hlY2tBdXRoKCk7XG4gIH1cblxuICBpbml0aWFsaXplVUkoKSB7XG4gICAgdGhpcy5lbCA9IHtcbiAgICAgIC8vIEF1dGhcbiAgICAgIGF1dGhTZWN0aW9uOiBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnYXV0aC1zZWN0aW9uJyksXG4gICAgICBhdXRoQnRuOiBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnYXV0aC1idG4nKSxcbiAgICAgIHRhYkJhcjogZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3RhYi1iYXInKSxcbiAgICAgIHVzZXJCYWRnZTogZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3VzZXItYmFkZ2UnKSxcbiAgICAgIGhlYWRlckF2YXRhcjogZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2hlYWRlci1hdmF0YXInKSxcblxuICAgICAgLy8gQ2hhdFxuICAgICAgdGFiQ2hhdDogZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3RhYi1jaGF0JyksXG4gICAgICBjaGF0TWVzc2FnZXM6IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdjaGF0LW1lc3NhZ2VzJyksXG4gICAgICBjaGF0SW5wdXQ6IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdjaGF0LWlucHV0JyksXG4gICAgICBzZW5kQnRuOiBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnc2VuZC1idG4nKSxcbiAgICAgIG1vZGVsU2VsZWN0OiBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnbW9kZWwtc2VsZWN0JyksXG4gICAgICByYWdFbmFibGVkOiBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgncmFnLWVuYWJsZWQnKSxcbiAgICAgIHRhYkNvbnRleHRFbmFibGVkOiBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgndGFiLWNvbnRleHQtZW5hYmxlZCcpLFxuICAgICAgcmFnU3RhdHVzOiBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgncmFnLXN0YXR1cycpLFxuXG4gICAgICAvLyBUb29sc1xuICAgICAgdGFiVG9vbHM6IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCd0YWItdG9vbHMnKSxcbiAgICAgIG1jcFN0YXR1czogZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ21jcC1zdGF0dXMnKSxcbiAgICAgIG1jcFRvb2xzOiBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnbWNwLXRvb2xzJyksXG4gICAgICBtY3BUb29sTGlzdDogZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ21jcC10b29sLWxpc3QnKSxcbiAgICAgIGFnZW50Q291bnQ6IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdhZ2VudC1jb3VudCcpLFxuICAgICAgYWdlbnRMaXN0OiBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnYWdlbnQtbGlzdCcpLFxuICAgICAgdGFiRnM6IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCd0YWItZnMnKSxcbiAgICAgIHJlZnJlc2hUYWJzOiBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgncmVmcmVzaC10YWJzJyksXG4gICAgICBncHVTdGF0dXM6IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdncHUtc3RhdHVzJyksXG4gICAgICBncHVNb2RlbDogZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2dwdS1tb2RlbCcpLFxuICAgICAgbGF1bmNoQWdlbnQ6IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdsYXVuY2gtYWdlbnQnKSxcblxuICAgICAgLy8gU2V0dGluZ3NcbiAgICAgIHRhYlNldHRpbmdzOiBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgndGFiLXNldHRpbmdzJyksXG4gICAgICB1c2VyQXZhdGFyOiBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgndXNlci1hdmF0YXInKSxcbiAgICAgIHVzZXJOYW1lOiBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgndXNlci1uYW1lJyksXG4gICAgICB1c2VyRW1haWw6IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCd1c2VyLWVtYWlsJyksXG4gICAgICBsb2dvdXRCdG46IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdsb2dvdXQtYnRuJyksXG4gICAgICBzYXZlU2V0dGluZ3M6IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdzYXZlLXNldHRpbmdzJyksXG4gICAgICBkZWZhdWx0TW9kZWw6IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdkZWZhdWx0LW1vZGVsJyksXG4gICAgICByYWdVc2VaYXA6IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdyYWctdXNlLXphcCcpLFxuICAgICAgcmFnSW5jbHVkZVRhYkNvbnRleHQ6IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdyYWctaW5jbHVkZS10YWItY29udGV4dCcpLFxuICAgICAgcmFnVG9wSzogZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3JhZy10b3AtaycpLFxuICAgICAgcmFnS2I6IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdyYWcta2InKSxcbiAgICAgIHJhZ0VuZHBvaW50OiBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgncmFnLWVuZHBvaW50JyksXG4gICAgICByYWdBcGlLZXk6IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdyYWctYXBpLWtleScpLFxuICAgIH07XG4gIH1cblxuICBzZXR1cEV2ZW50TGlzdGVuZXJzKCkge1xuICAgIC8vIEF1dGhcbiAgICB0aGlzLmVsLmF1dGhCdG4uYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCAoKSA9PiB0aGlzLmxvZ2luKCkpO1xuXG4gICAgLy8gVGFic1xuICAgIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJy50YWInKS5mb3JFYWNoKHRhYiA9PiB7XG4gICAgICB0YWIuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCAoKSA9PiB0aGlzLnN3aXRjaFRhYih0YWIuZGF0YXNldC50YWIpKTtcbiAgICB9KTtcblxuICAgIC8vIENoYXRcbiAgICB0aGlzLmVsLnNlbmRCdG4uYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCAoKSA9PiB0aGlzLnNlbmRNZXNzYWdlKCkpO1xuICAgIHRoaXMuZWwuY2hhdElucHV0LmFkZEV2ZW50TGlzdGVuZXIoJ2tleWRvd24nLCAoZSkgPT4ge1xuICAgICAgaWYgKGUua2V5ID09PSAnRW50ZXInICYmICFlLnNoaWZ0S2V5KSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgdGhpcy5zZW5kTWVzc2FnZSgpO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHRoaXMuZWwuY2hhdElucHV0LmFkZEV2ZW50TGlzdGVuZXIoJ2lucHV0JywgKCkgPT4gdGhpcy5hdXRvUmVzaXplKCkpO1xuICAgIHRoaXMuZWwucmFnRW5hYmxlZD8uYWRkRXZlbnRMaXN0ZW5lcignY2hhbmdlJywgKCkgPT4ge1xuICAgICAgdGhpcy5zZXRSYWdTdGF0dXModGhpcy5lbC5yYWdFbmFibGVkLmNoZWNrZWQgPyAnUkFHIGVuYWJsZWQnIDogJ1JBRyBkaXNhYmxlZCcpO1xuICAgIH0pO1xuICAgIHRoaXMuZWwudGFiQ29udGV4dEVuYWJsZWQ/LmFkZEV2ZW50TGlzdGVuZXIoJ2NoYW5nZScsICgpID0+IHtcbiAgICAgIGlmICghdGhpcy5lbC5yYWdFbmFibGVkPy5jaGVja2VkKSByZXR1cm47XG4gICAgICB0aGlzLnNldFJhZ1N0YXR1cyh0aGlzLmVsLnRhYkNvbnRleHRFbmFibGVkLmNoZWNrZWQgPyAnVGFiIGNvbnRleHQgb24nIDogJ1RhYiBjb250ZXh0IG9mZicpO1xuICAgIH0pO1xuXG4gICAgLy8gVG9vbHNcbiAgICB0aGlzLmVsLnJlZnJlc2hUYWJzLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgKCkgPT4gdGhpcy5yZWZyZXNoVGFiRmlsZXN5c3RlbSgpKTtcbiAgICB0aGlzLmVsLmxhdW5jaEFnZW50LmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgKCkgPT4gdGhpcy5zaG93QWdlbnRMYXVuY2hlcigpKTtcblxuICAgIC8vIFNldHRpbmdzXG4gICAgdGhpcy5lbC5sb2dvdXRCdG4uYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCAoKSA9PiB0aGlzLmxvZ291dCgpKTtcbiAgICB0aGlzLmVsLnNhdmVTZXR0aW5ncy5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsICgpID0+IHRoaXMuc2F2ZVNldHRpbmdzKCkpO1xuXG4gICAgLy8gQmFja2dyb3VuZCBtZXNzYWdlc1xuICAgIGNocm9tZS5ydW50aW1lLm9uTWVzc2FnZS5hZGRMaXN0ZW5lcigocmVxdWVzdCwgc2VuZGVyLCBzZW5kUmVzcG9uc2UpID0+IHtcbiAgICAgIHRoaXMuaGFuZGxlTWVzc2FnZShyZXF1ZXN0KTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0pO1xuICB9XG5cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIC8vIEF1dGhcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgYXN5bmMgY2hlY2tBdXRoKCkge1xuICAgIC8vIEFsd2F5cyBzaG93IHRhYnMgYW5kIGluaXRpYWxpemUgdG9vbHMgXHUyMDE0IGF1dGggb25seSBnYXRlcyBjaGF0XG4gICAgdGhpcy5lbC50YWJCYXIuY2xhc3NMaXN0LnJlbW92ZSgnaGlkZGVuJyk7XG4gICAgdGhpcy5lbC5hdXRoU2VjdGlvbi5jbGFzc0xpc3QuYWRkKCdoaWRkZW4nKTtcbiAgICB0aGlzLnN3aXRjaFRhYigndG9vbHMnKTsgLy8gRGVmYXVsdCB0byB0b29scyAoYWx3YXlzIHdvcmtzKVxuXG4gICAgLy8gSW5pdGlhbGl6ZSBmZWF0dXJlcyB0aGF0IHdvcmsgd2l0aG91dCBhdXRoXG4gICAgdGhpcy5jb25uZWN0VG9NQ1AoKTtcbiAgICB0aGlzLnJlZnJlc2hUYWJGaWxlc3lzdGVtKCk7XG4gICAgdGhpcy5jaGVja1dlYkdQVSgpO1xuICAgIHRoaXMubG9hZFNldHRpbmdzKCk7XG4gICAgdGhpcy5zdGFydE1vbml0b3JpbmcoKTtcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGNocm9tZS5ydW50aW1lLnNlbmRNZXNzYWdlKHsgYWN0aW9uOiAnYXV0aC5zdGF0dXMnIH0pO1xuICAgICAgaWYgKHJlc3BvbnNlPy5zdWNjZXNzICYmIHJlc3BvbnNlLmF1dGhlbnRpY2F0ZWQpIHtcbiAgICAgICAgdGhpcy5zZXRVc2VyKHJlc3BvbnNlLnVzZXIpO1xuICAgICAgICB0aGlzLnN3aXRjaFRhYignY2hhdCcpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5zaG93Q2hhdExvZ2luUHJvbXB0KCk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ0F1dGggY2hlY2sgZmFpbGVkOicsIGVycm9yKTtcbiAgICAgIHRoaXMuc2hvd0NoYXRMb2dpblByb21wdCgpO1xuICAgIH1cbiAgfVxuXG4gIGFzeW5jIGxvZ2luKCkge1xuICAgIHRoaXMuZWwuYXV0aEJ0bi5kaXNhYmxlZCA9IHRydWU7XG4gICAgdGhpcy5lbC5hdXRoQnRuLnRleHRDb250ZW50ID0gJ1NpZ25pbmcgaW4uLi4nO1xuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgY2hyb21lLnJ1bnRpbWUuc2VuZE1lc3NhZ2UoeyBhY3Rpb246ICdhdXRoLmxvZ2luJyB9KTtcbiAgICAgIGlmIChyZXNwb25zZT8uc3VjY2Vzcykge1xuICAgICAgICB0aGlzLnNldFVzZXIocmVzcG9uc2UudXNlcik7XG4gICAgICAgIHRoaXMuaGlkZUNoYXRMb2dpblByb21wdCgpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5zaG93RXJyb3IocmVzcG9uc2U/LmVycm9yIHx8ICdTaWduIGluIGZhaWxlZCcpO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aGlzLnNob3dFcnJvcignU2lnbiBpbiBmYWlsZWQnKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgdGhpcy5lbC5hdXRoQnRuLmRpc2FibGVkID0gZmFsc2U7XG4gICAgICB0aGlzLmVsLmF1dGhCdG4udGV4dENvbnRlbnQgPSAnU2lnbiBpbiB3aXRoIEhhbnpvJztcbiAgICB9XG4gIH1cblxuICBhc3luYyBsb2dvdXQoKSB7XG4gICAgYXdhaXQgY2hyb21lLnJ1bnRpbWUuc2VuZE1lc3NhZ2UoeyBhY3Rpb246ICdhdXRoLmxvZ291dCcgfSk7XG4gICAgdGhpcy5lbC51c2VyQmFkZ2UuY2xhc3NMaXN0LmFkZCgnaGlkZGVuJyk7XG4gICAgdGhpcy5lbC51c2VyTmFtZS50ZXh0Q29udGVudCA9ICcnO1xuICAgIHRoaXMuZWwudXNlckVtYWlsLnRleHRDb250ZW50ID0gJyc7XG4gICAgdGhpcy5zaG93Q2hhdExvZ2luUHJvbXB0KCk7XG4gICAgdGhpcy5zd2l0Y2hUYWIoJ3Rvb2xzJyk7XG4gIH1cblxuICBzZXRVc2VyKHVzZXIpIHtcbiAgICB0aGlzLmF1dGhlbnRpY2F0ZWQgPSB0cnVlO1xuICAgIGlmICh1c2VyKSB7XG4gICAgICBjb25zdCBhdmF0YXIgPSB1c2VyLnBpY3R1cmUgfHwgdXNlci5hdmF0YXIgfHwgJyc7XG4gICAgICBpZiAoYXZhdGFyKSB7XG4gICAgICAgIHRoaXMuZWwuaGVhZGVyQXZhdGFyLnNyYyA9IGF2YXRhcjtcbiAgICAgICAgdGhpcy5lbC51c2VyQmFkZ2UuY2xhc3NMaXN0LnJlbW92ZSgnaGlkZGVuJyk7XG4gICAgICAgIHRoaXMuZWwudXNlckF2YXRhci5zcmMgPSBhdmF0YXI7XG4gICAgICB9XG4gICAgICB0aGlzLmVsLnVzZXJOYW1lLnRleHRDb250ZW50ID0gdXNlci5uYW1lIHx8IHVzZXIuZGlzcGxheU5hbWUgfHwgJ1VzZXInO1xuICAgICAgdGhpcy5lbC51c2VyRW1haWwudGV4dENvbnRlbnQgPSB1c2VyLmVtYWlsIHx8ICcnO1xuICAgIH1cbiAgICB0aGlzLmxvYWRNb2RlbHMoKTtcbiAgICB0aGlzLmxvYWRDb252ZXJzYXRpb24oKTtcbiAgfVxuXG4gIHNob3dDaGF0TG9naW5Qcm9tcHQoKSB7XG4gICAgdGhpcy5hdXRoZW50aWNhdGVkID0gZmFsc2U7XG4gICAgLy8gU2hvdyBsb2dpbiBwcm9tcHQgaW4gY2hhdCBhcmVhIGluc3RlYWQgb2YgYmxvY2tpbmcgZW50aXJlIHNpZGViYXJcbiAgICBjb25zdCBjaGF0TG9naW4gPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnY2hhdC1sb2dpbi1wcm9tcHQnKTtcbiAgICBpZiAoY2hhdExvZ2luKSBjaGF0TG9naW4uY2xhc3NMaXN0LnJlbW92ZSgnaGlkZGVuJyk7XG4gICAgY29uc3QgY2hhdENvbXBvc2VyID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2NoYXQtY29tcG9zZXInKTtcbiAgICBpZiAoY2hhdENvbXBvc2VyKSBjaGF0Q29tcG9zZXIuY2xhc3NMaXN0LmFkZCgnaGlkZGVuJyk7XG4gIH1cblxuICBoaWRlQ2hhdExvZ2luUHJvbXB0KCkge1xuICAgIHRoaXMuYXV0aGVudGljYXRlZCA9IHRydWU7XG4gICAgY29uc3QgY2hhdExvZ2luID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2NoYXQtbG9naW4tcHJvbXB0Jyk7XG4gICAgaWYgKGNoYXRMb2dpbikgY2hhdExvZ2luLmNsYXNzTGlzdC5hZGQoJ2hpZGRlbicpO1xuICAgIGNvbnN0IGNoYXRDb21wb3NlciA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdjaGF0LWNvbXBvc2VyJyk7XG4gICAgaWYgKGNoYXRDb21wb3NlcikgY2hhdENvbXBvc2VyLmNsYXNzTGlzdC5yZW1vdmUoJ2hpZGRlbicpO1xuICB9XG5cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIC8vIFRhYiBOYXZpZ2F0aW9uXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4gIHN3aXRjaFRhYihuYW1lKSB7XG4gICAgdGhpcy5jdXJyZW50VGFiID0gbmFtZTtcblxuICAgIC8vIFVwZGF0ZSB0YWIgYnV0dG9uc1xuICAgIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJy50YWInKS5mb3JFYWNoKHQgPT4ge1xuICAgICAgdC5jbGFzc0xpc3QudG9nZ2xlKCdhY3RpdmUnLCB0LmRhdGFzZXQudGFiID09PSBuYW1lKTtcbiAgICB9KTtcblxuICAgIC8vIFNob3cvaGlkZSBjb250ZW50XG4gICAgZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnLnRhYi1jb250ZW50JykuZm9yRWFjaCh0ID0+IHQuY2xhc3NMaXN0LmFkZCgnaGlkZGVuJykpO1xuICAgIGNvbnN0IHRhcmdldCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGB0YWItJHtuYW1lfWApO1xuICAgIGlmICh0YXJnZXQpIHRhcmdldC5jbGFzc0xpc3QucmVtb3ZlKCdoaWRkZW4nKTtcbiAgfVxuXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAvLyBDaGF0XG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4gIGFzeW5jIGxvYWRNb2RlbHMoKSB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgY2hyb21lLnJ1bnRpbWUuc2VuZE1lc3NhZ2UoeyBhY3Rpb246ICdjaGF0Lmxpc3RNb2RlbHMnIH0pO1xuICAgICAgaWYgKHJlc3BvbnNlPy5zdWNjZXNzICYmIHJlc3BvbnNlLm1vZGVscz8ubGVuZ3RoKSB7XG4gICAgICAgIGNvbnN0IHNlbGVjdCA9IHRoaXMuZWwubW9kZWxTZWxlY3Q7XG4gICAgICAgIHNlbGVjdC5pbm5lckhUTUwgPSAnJztcbiAgICAgICAgZm9yIChjb25zdCBtb2RlbCBvZiByZXNwb25zZS5tb2RlbHMpIHtcbiAgICAgICAgICBjb25zdCBvcHQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdvcHRpb24nKTtcbiAgICAgICAgICBvcHQudmFsdWUgPSBtb2RlbC5pZDtcbiAgICAgICAgICBvcHQudGV4dENvbnRlbnQgPSBtb2RlbC5uYW1lIHx8IG1vZGVsLmlkO1xuICAgICAgICAgIHNlbGVjdC5hcHBlbmRDaGlsZChvcHQpO1xuICAgICAgICB9XG4gICAgICAgIC8vIEFsc28gcG9wdWxhdGUgc2V0dGluZ3MgZGVmYXVsdCBtb2RlbFxuICAgICAgICB0aGlzLmVsLmRlZmF1bHRNb2RlbC5pbm5lckhUTUwgPSBzZWxlY3QuaW5uZXJIVE1MO1xuICAgICAgfVxuICAgIH0gY2F0Y2gge1xuICAgICAgLy8gS2VlcCBkZWZhdWx0IG9wdGlvbnNcbiAgICB9XG4gIH1cblxuICBhc3luYyBzZW5kTWVzc2FnZSgpIHtcbiAgICBjb25zdCB0ZXh0ID0gdGhpcy5lbC5jaGF0SW5wdXQudmFsdWUudHJpbSgpO1xuICAgIGlmICghdGV4dCB8fCB0aGlzLnN0cmVhbWluZykgcmV0dXJuO1xuICAgIGlmICghdGhpcy5hdXRoZW50aWNhdGVkKSB7XG4gICAgICB0aGlzLnNob3dFcnJvcignUGxlYXNlIHNpZ24gaW4gdG8gdXNlIGNoYXQnKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBHZXQgdG9rZW5cbiAgICBjb25zdCB0b2tlblJlc3AgPSBhd2FpdCBjaHJvbWUucnVudGltZS5zZW5kTWVzc2FnZSh7IGFjdGlvbjogJ2F1dGguZ2V0VG9rZW4nIH0pO1xuICAgIGlmICghdG9rZW5SZXNwPy5zdWNjZXNzIHx8ICF0b2tlblJlc3AudG9rZW4pIHtcbiAgICAgIHRoaXMuc2hvd0Vycm9yKCdQbGVhc2Ugc2lnbiBpbiBhZ2FpbicpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHVzZXJNZXNzYWdlID0geyByb2xlOiAndXNlcicsIGNvbnRlbnQ6IHRleHQgfTtcbiAgICBjb25zdCBtb2RlbCA9IHRoaXMuZWwubW9kZWxTZWxlY3QudmFsdWU7XG4gICAgbGV0IHJlcXVlc3RNZXNzYWdlcyA9IFsuLi50aGlzLm1lc3NhZ2VzLCB1c2VyTWVzc2FnZV07XG5cbiAgICB0aGlzLnJhZ0NvbnRleHQgPSBudWxsO1xuICAgIGlmICh0aGlzLmVsLnJhZ0VuYWJsZWQ/LmNoZWNrZWQpIHtcbiAgICAgIHRoaXMuc2V0UmFnU3RhdHVzKCdSZXRyaWV2aW5nIGNvbnRleHQuLi4nKTtcbiAgICAgIGNvbnN0IHJhZ1Jlc3AgPSBhd2FpdCB0aGlzLnJlcXVlc3RSYWdDb250ZXh0KHRleHQpO1xuICAgICAgaWYgKHJhZ1Jlc3A/LnN1Y2Nlc3MgJiYgQXJyYXkuaXNBcnJheShyYWdSZXNwLnNuaXBwZXRzKSAmJiByYWdSZXNwLnNuaXBwZXRzLmxlbmd0aCkge1xuICAgICAgICB0aGlzLnJhZ0NvbnRleHQgPSByYWdSZXNwO1xuICAgICAgICByZXF1ZXN0TWVzc2FnZXMgPSBbXG4gICAgICAgICAgeyByb2xlOiAnc3lzdGVtJywgY29udGVudDogdGhpcy5idWlsZFJhZ1N5c3RlbVByb21wdChyYWdSZXNwKSB9LFxuICAgICAgICAgIC4uLnJlcXVlc3RNZXNzYWdlcyxcbiAgICAgICAgXTtcbiAgICAgICAgdGhpcy5zZXRSYWdTdGF0dXMoYFJBRzogJHtyYWdSZXNwLnNuaXBwZXRzLmxlbmd0aH0gc25pcHBldChzKSBmcm9tICR7cmFnUmVzcC5zb3VyY2UgfHwgJ2NvbnRleHQnfWApO1xuICAgICAgfSBlbHNlIGlmIChyYWdSZXNwPy5lcnJvcikge1xuICAgICAgICB0aGlzLnNldFJhZ1N0YXR1cyhgUkFHIHVuYXZhaWxhYmxlICgke3JhZ1Jlc3AuZXJyb3J9KWApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5zZXRSYWdTdGF0dXMoJ05vIGNvbnRleHQgZm91bmQnKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5zZXRSYWdTdGF0dXMoJ1JBRyBkaXNhYmxlZCcpO1xuICAgIH1cblxuICAgIC8vIEFkZCB1c2VyIG1lc3NhZ2UgdG8gdHJhbnNjcmlwdFxuICAgIHRoaXMubWVzc2FnZXMucHVzaCh1c2VyTWVzc2FnZSk7XG4gICAgdGhpcy5hcHBlbmRNZXNzYWdlKCd1c2VyJywgdGV4dCk7XG5cbiAgICAvLyBDbGVhciBpbnB1dFxuICAgIHRoaXMuZWwuY2hhdElucHV0LnZhbHVlID0gJyc7XG4gICAgdGhpcy5hdXRvUmVzaXplKCk7XG5cbiAgICAvLyBTaG93IHR5cGluZ1xuICAgIHRoaXMuc3RyZWFtaW5nID0gdHJ1ZTtcbiAgICB0aGlzLmVsLnNlbmRCdG4uZGlzYWJsZWQgPSB0cnVlO1xuICAgIGNvbnN0IHR5cGluZ0VsID0gdGhpcy5zaG93VHlwaW5nKCk7XG5cbiAgICAvLyBDcmVhdGUgYXNzaXN0YW50IG1lc3NhZ2UgZWxlbWVudFxuICAgIGNvbnN0IGFzc2lzdGFudEVsID0gdGhpcy5hcHBlbmRNZXNzYWdlKCdhc3Npc3RhbnQnLCAnJyk7XG4gICAgbGV0IGZ1bGxDb250ZW50ID0gJyc7XG5cbiAgICB0cnkge1xuICAgICAgLy8gU3RyZWFtIHZpYSBkaXJlY3QgZmV0Y2ggKHNpZGViYXIgaGFzIGFjY2VzcyB2aWEgQ1NQKVxuICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaCgnaHR0cHM6Ly9hcGkuaGFuem8uYWkvdjEvY2hhdC9jb21wbGV0aW9ucycsIHtcbiAgICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICAgICdBdXRob3JpemF0aW9uJzogYEJlYXJlciAke3Rva2VuUmVzcC50b2tlbn1gLFxuICAgICAgICB9LFxuICAgICAgICBib2R5OiBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgbW9kZWwsXG4gICAgICAgICAgbWVzc2FnZXM6IHJlcXVlc3RNZXNzYWdlcyxcbiAgICAgICAgICBzdHJlYW06IHRydWUsXG4gICAgICAgIH0pLFxuICAgICAgICBzaWduYWw6ICh0aGlzLnN0cmVhbUNvbnRyb2xsZXIgPSBuZXcgQWJvcnRDb250cm9sbGVyKCkpLnNpZ25hbCxcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoIXJlc3BvbnNlLm9rKSB7XG4gICAgICAgIGNvbnN0IGVyclRleHQgPSBhd2FpdCByZXNwb25zZS50ZXh0KCk7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgQVBJIGVycm9yICR7cmVzcG9uc2Uuc3RhdHVzfTogJHtlcnJUZXh0fWApO1xuICAgICAgfVxuXG4gICAgICB0eXBpbmdFbC5yZW1vdmUoKTtcbiAgICAgIGNvbnN0IHJlYWRlciA9IHJlc3BvbnNlLmJvZHkuZ2V0UmVhZGVyKCk7XG4gICAgICBjb25zdCBkZWNvZGVyID0gbmV3IFRleHREZWNvZGVyKCk7XG4gICAgICBsZXQgYnVmZmVyID0gJyc7XG5cbiAgICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICAgIGNvbnN0IHsgZG9uZSwgdmFsdWUgfSA9IGF3YWl0IHJlYWRlci5yZWFkKCk7XG4gICAgICAgIGlmIChkb25lKSBicmVhaztcblxuICAgICAgICBidWZmZXIgKz0gZGVjb2Rlci5kZWNvZGUodmFsdWUsIHsgc3RyZWFtOiB0cnVlIH0pO1xuICAgICAgICBjb25zdCBsaW5lcyA9IGJ1ZmZlci5zcGxpdCgnXFxuJyk7XG4gICAgICAgIGJ1ZmZlciA9IGxpbmVzLnBvcCgpIHx8ICcnO1xuXG4gICAgICAgIGZvciAoY29uc3QgbGluZSBvZiBsaW5lcykge1xuICAgICAgICAgIGNvbnN0IHRyaW1tZWQgPSBsaW5lLnRyaW0oKTtcbiAgICAgICAgICBpZiAoIXRyaW1tZWQgfHwgdHJpbW1lZC5zdGFydHNXaXRoKCc6JykpIGNvbnRpbnVlO1xuICAgICAgICAgIGlmICh0cmltbWVkLnN0YXJ0c1dpdGgoJ2RhdGE6ICcpKSB7XG4gICAgICAgICAgICBjb25zdCBkYXRhID0gdHJpbW1lZC5zbGljZSg2KTtcbiAgICAgICAgICAgIGlmIChkYXRhID09PSAnW0RPTkVdJykgYnJlYWs7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICBjb25zdCBwYXJzZWQgPSBKU09OLnBhcnNlKGRhdGEpO1xuICAgICAgICAgICAgICBjb25zdCBkZWx0YSA9IHBhcnNlZC5jaG9pY2VzPy5bMF0/LmRlbHRhPy5jb250ZW50O1xuICAgICAgICAgICAgICBpZiAoZGVsdGEpIHtcbiAgICAgICAgICAgICAgICBmdWxsQ29udGVudCArPSBkZWx0YTtcbiAgICAgICAgICAgICAgICBhc3Npc3RhbnRFbC5pbm5lckhUTUwgPSB0aGlzLnJlbmRlck1hcmtkb3duKGZ1bGxDb250ZW50KTtcbiAgICAgICAgICAgICAgICB0aGlzLnNjcm9sbFRvQm90dG9tKCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gY2F0Y2gge31cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMucmFnQ29udGV4dD8uc25pcHBldHM/Lmxlbmd0aCkge1xuICAgICAgICBmdWxsQ29udGVudCArPSB0aGlzLmJ1aWxkUmFnQ2l0YXRpb25CbG9jayh0aGlzLnJhZ0NvbnRleHQpO1xuICAgICAgICBhc3Npc3RhbnRFbC5pbm5lckhUTUwgPSB0aGlzLnJlbmRlck1hcmtkb3duKGZ1bGxDb250ZW50KTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5tZXNzYWdlcy5wdXNoKHsgcm9sZTogJ2Fzc2lzdGFudCcsIGNvbnRlbnQ6IGZ1bGxDb250ZW50IH0pO1xuICAgICAgdGhpcy5zYXZlQ29udmVyc2F0aW9uKCk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHR5cGluZ0VsLnJlbW92ZSgpO1xuICAgICAgaWYgKGVycm9yPy5uYW1lICE9PSAnQWJvcnRFcnJvcicpIHtcbiAgICAgICAgYXNzaXN0YW50RWwucmVtb3ZlKCk7XG4gICAgICAgIHRoaXMuYXBwZW5kRXJyb3IoZXJyb3I/Lm1lc3NhZ2UgfHwgJ0NoYXQgZmFpbGVkJyk7XG4gICAgICB9XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHRoaXMuc3RyZWFtaW5nID0gZmFsc2U7XG4gICAgICB0aGlzLnN0cmVhbUNvbnRyb2xsZXIgPSBudWxsO1xuICAgICAgdGhpcy5lbC5zZW5kQnRuLmRpc2FibGVkID0gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgZ2V0QWN0aXZlVGFiQ29udGV4dCgpIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgW2FjdGl2ZVRhYl0gPSBhd2FpdCBjaHJvbWUudGFicy5xdWVyeSh7IGFjdGl2ZTogdHJ1ZSwgY3VycmVudFdpbmRvdzogdHJ1ZSB9KTtcbiAgICAgIGlmICghYWN0aXZlVGFiKSByZXR1cm4gbnVsbDtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHVybDogYWN0aXZlVGFiLnVybCB8fCAnJyxcbiAgICAgICAgdGl0bGU6IGFjdGl2ZVRhYi50aXRsZSB8fCAnJyxcbiAgICAgIH07XG4gICAgfSBjYXRjaCB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gIH1cblxuICBhc3luYyByZXF1ZXN0UmFnQ29udGV4dChxdWVyeSkge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBwYWdlQ29udGV4dCA9IHRoaXMuZWwudGFiQ29udGV4dEVuYWJsZWQ/LmNoZWNrZWQgPyBhd2FpdCB0aGlzLmdldEFjdGl2ZVRhYkNvbnRleHQoKSA6IG51bGw7XG4gICAgICBjb25zdCB0b3BLID0gTWF0aC5tYXgoMSwgTWF0aC5taW4ocGFyc2VJbnQodGhpcy5lbC5yYWdUb3BLPy52YWx1ZSB8fCAnNScsIDEwKSB8fCA1LCAyMCkpO1xuXG4gICAgICByZXR1cm4gYXdhaXQgY2hyb21lLnJ1bnRpbWUuc2VuZE1lc3NhZ2Uoe1xuICAgICAgICBhY3Rpb246ICdyYWcucXVlcnknLFxuICAgICAgICBxdWVyeSxcbiAgICAgICAgdG9wSyxcbiAgICAgICAgaW5jbHVkZVRhYkNvbnRleHQ6ICEhdGhpcy5lbC50YWJDb250ZXh0RW5hYmxlZD8uY2hlY2tlZCxcbiAgICAgICAgdXNlWmFwTWVtb3J5OiAhIXRoaXMuZWwucmFnVXNlWmFwPy5jaGVja2VkLFxuICAgICAgICBrbm93bGVkZ2VCYXNlOiB0aGlzLmVsLnJhZ0tiPy52YWx1ZSB8fCAnJyxcbiAgICAgICAgZW5kcG9pbnQ6IHRoaXMuZWwucmFnRW5kcG9pbnQ/LnZhbHVlIHx8ICcnLFxuICAgICAgICBhcGlLZXk6IHRoaXMuZWwucmFnQXBpS2V5Py52YWx1ZSB8fCAnJyxcbiAgICAgICAgcGFnZUNvbnRleHQ6IHBhZ2VDb250ZXh0IHx8IHVuZGVmaW5lZCxcbiAgICAgIH0pO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICByZXR1cm4geyBzdWNjZXNzOiBmYWxzZSwgZXJyb3I6IGVycm9yPy5tZXNzYWdlIHx8ICdGYWlsZWQgdG8gcXVlcnkgUkFHJyB9O1xuICAgIH1cbiAgfVxuXG4gIGJ1aWxkUmFnU3lzdGVtUHJvbXB0KHJhZ1Jlc3BvbnNlKSB7XG4gICAgY29uc3Qgc25pcHBldHMgPSAocmFnUmVzcG9uc2U/LnNuaXBwZXRzIHx8IFtdKS5zbGljZSgwLCA4KTtcbiAgICBjb25zdCBsaW5lcyA9IHNuaXBwZXRzLm1hcCgoc25pcHBldCwgaW5kZXgpID0+IHtcbiAgICAgIGNvbnN0IHRpdGxlID0gc25pcHBldC50aXRsZSB8fCBzbmlwcGV0LnNvdXJjZSB8fCBgU25pcHBldCAke2luZGV4ICsgMX1gO1xuICAgICAgY29uc3Qgc2NvcmUgPSB0eXBlb2Ygc25pcHBldC5zY29yZSA9PT0gJ251bWJlcicgPyBgIChzY29yZSAke3NuaXBwZXQuc2NvcmUudG9GaXhlZCgzKX0pYCA6ICcnO1xuICAgICAgY29uc3Qgc291cmNlTGluZSA9IHNuaXBwZXQudXJsID8gYCR7dGl0bGV9JHtzY29yZX0gXHUyMDE0ICR7c25pcHBldC51cmx9YCA6IGAke3RpdGxlfSR7c2NvcmV9YDtcbiAgICAgIHJldHVybiBgWyR7aW5kZXggKyAxfV0gJHtzb3VyY2VMaW5lfVxcbiR7c25pcHBldC5jb250ZW50fWA7XG4gICAgfSk7XG5cbiAgICByZXR1cm4gW1xuICAgICAgJ1lvdSBhcmUgYXNzaXN0aW5nIGluc2lkZSBIYW56byBCcm93c2VyIEV4dGVuc2lvbi4nLFxuICAgICAgJ1VzZSB0aGUgcmV0cmlldmVkIGNvbnRleHQgYmVsb3cgd2hlbiByZWxldmFudCwgYW5kIHN0YXRlIHVuY2VydGFpbnR5IGlmIGNvbnRleHQgaXMgaW5zdWZmaWNpZW50LicsXG4gICAgICAnUmV0cmlldmVkIENvbnRleHQ6JyxcbiAgICAgIC4uLmxpbmVzLFxuICAgIF0uam9pbignXFxuXFxuJyk7XG4gIH1cblxuICBidWlsZFJhZ0NpdGF0aW9uQmxvY2socmFnUmVzcG9uc2UpIHtcbiAgICBjb25zdCBzbmlwcGV0cyA9IChyYWdSZXNwb25zZT8uc25pcHBldHMgfHwgW10pLnNsaWNlKDAsIDUpO1xuICAgIGlmICghc25pcHBldHMubGVuZ3RoKSByZXR1cm4gJyc7XG5cbiAgICBjb25zdCByb3dzID0gc25pcHBldHMubWFwKChzbmlwcGV0LCBpbmRleCkgPT4ge1xuICAgICAgY29uc3QgdGl0bGUgPSBzbmlwcGV0LnRpdGxlIHx8IHNuaXBwZXQuc291cmNlIHx8IGBTbmlwcGV0ICR7aW5kZXggKyAxfWA7XG4gICAgICBpZiAoc25pcHBldC51cmwpIHtcbiAgICAgICAgcmV0dXJuIGAtICR7dGl0bGV9OiAke3NuaXBwZXQudXJsfWA7XG4gICAgICB9XG4gICAgICByZXR1cm4gYC0gJHt0aXRsZX1gO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIGBcXG5cXG4tLS1cXG5Db250ZXh0IFNvdXJjZXM6XFxuJHtyb3dzLmpvaW4oJ1xcbicpfWA7XG4gIH1cblxuICBzZXRSYWdTdGF0dXModGV4dCkge1xuICAgIGlmICghdGhpcy5lbC5yYWdTdGF0dXMpIHJldHVybjtcbiAgICB0aGlzLmVsLnJhZ1N0YXR1cy50ZXh0Q29udGVudCA9IHRleHQgfHwgJ1JlYWR5JztcbiAgfVxuXG4gIGFwcGVuZE1lc3NhZ2Uocm9sZSwgY29udGVudCkge1xuICAgIC8vIFJlbW92ZSB3ZWxjb21lIG1lc3NhZ2VcbiAgICBjb25zdCB3ZWxjb21lID0gdGhpcy5lbC5jaGF0TWVzc2FnZXMucXVlcnlTZWxlY3RvcignLmNoYXQtd2VsY29tZScpO1xuICAgIGlmICh3ZWxjb21lKSB3ZWxjb21lLnJlbW92ZSgpO1xuXG4gICAgY29uc3QgZGl2ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG4gICAgZGl2LmNsYXNzTmFtZSA9IGBtc2cgbXNnLSR7cm9sZX1gO1xuICAgIGRpdi5pbm5lckhUTUwgPSByb2xlID09PSAnYXNzaXN0YW50JyA/IHRoaXMucmVuZGVyTWFya2Rvd24oY29udGVudCkgOiB0aGlzLmVzY2FwZUh0bWwoY29udGVudCk7XG4gICAgdGhpcy5lbC5jaGF0TWVzc2FnZXMuYXBwZW5kQ2hpbGQoZGl2KTtcbiAgICB0aGlzLnNjcm9sbFRvQm90dG9tKCk7XG4gICAgcmV0dXJuIGRpdjtcbiAgfVxuXG4gIGFwcGVuZEVycm9yKG1lc3NhZ2UpIHtcbiAgICBjb25zdCBkaXYgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcbiAgICBkaXYuY2xhc3NOYW1lID0gJ21zZy1lcnJvcic7XG4gICAgZGl2LnRleHRDb250ZW50ID0gbWVzc2FnZTtcbiAgICB0aGlzLmVsLmNoYXRNZXNzYWdlcy5hcHBlbmRDaGlsZChkaXYpO1xuICAgIHRoaXMuc2Nyb2xsVG9Cb3R0b20oKTtcbiAgfVxuXG4gIHNob3dUeXBpbmcoKSB7XG4gICAgY29uc3QgZGl2ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG4gICAgZGl2LmNsYXNzTmFtZSA9ICd0eXBpbmctaW5kaWNhdG9yJztcbiAgICBkaXYuaW5uZXJIVE1MID0gJzxzcGFuPjwvc3Bhbj48c3Bhbj48L3NwYW4+PHNwYW4+PC9zcGFuPic7XG4gICAgdGhpcy5lbC5jaGF0TWVzc2FnZXMuYXBwZW5kQ2hpbGQoZGl2KTtcbiAgICB0aGlzLnNjcm9sbFRvQm90dG9tKCk7XG4gICAgcmV0dXJuIGRpdjtcbiAgfVxuXG4gIHNjcm9sbFRvQm90dG9tKCkge1xuICAgIHRoaXMuZWwuY2hhdE1lc3NhZ2VzLnNjcm9sbFRvcCA9IHRoaXMuZWwuY2hhdE1lc3NhZ2VzLnNjcm9sbEhlaWdodDtcbiAgfVxuXG4gIGF1dG9SZXNpemUoKSB7XG4gICAgY29uc3QgZWwgPSB0aGlzLmVsLmNoYXRJbnB1dDtcbiAgICBlbC5zdHlsZS5oZWlnaHQgPSAnYXV0byc7XG4gICAgZWwuc3R5bGUuaGVpZ2h0ID0gTWF0aC5taW4oZWwuc2Nyb2xsSGVpZ2h0LCAxMjApICsgJ3B4JztcbiAgfVxuXG4gIC8vIE1pbmltYWwgbWFya2Rvd246IGNvZGUgYmxvY2tzLCBpbmxpbmUgY29kZSwgYm9sZCwgaXRhbGljLCBsaW5lIGJyZWFrc1xuICByZW5kZXJNYXJrZG93bih0ZXh0KSB7XG4gICAgaWYgKCF0ZXh0KSByZXR1cm4gJyc7XG4gICAgbGV0IGh0bWwgPSB0aGlzLmVzY2FwZUh0bWwodGV4dCk7XG5cbiAgICAvLyBDb2RlIGJsb2NrczogYGBgbGFuZ1xcbi4uLlxcbmBgYFxuICAgIGh0bWwgPSBodG1sLnJlcGxhY2UoL2BgYChcXHcqKVxcbihbXFxzXFxTXSo/KWBgYC9nLCAoXywgbGFuZywgY29kZSkgPT4ge1xuICAgICAgcmV0dXJuIGA8cHJlPjxjb2RlPiR7Y29kZS50cmltKCl9PC9jb2RlPjwvcHJlPmA7XG4gICAgfSk7XG5cbiAgICAvLyBJbmxpbmUgY29kZTogYC4uLmBcbiAgICBodG1sID0gaHRtbC5yZXBsYWNlKC9gKFteYF0rKWAvZywgJzxjb2RlPiQxPC9jb2RlPicpO1xuXG4gICAgLy8gQm9sZDogKiouLi4qKlxuICAgIGh0bWwgPSBodG1sLnJlcGxhY2UoL1xcKlxcKihbXipdKylcXCpcXCovZywgJzxzdHJvbmc+JDE8L3N0cm9uZz4nKTtcblxuICAgIC8vIEl0YWxpYzogKi4uLipcbiAgICBodG1sID0gaHRtbC5yZXBsYWNlKC9cXCooW14qXSspXFwqL2csICc8ZW0+JDE8L2VtPicpO1xuXG4gICAgLy8gTGluZSBicmVha3NcbiAgICBodG1sID0gaHRtbC5yZXBsYWNlKC9cXG4vZywgJzxicj4nKTtcblxuICAgIHJldHVybiBodG1sO1xuICB9XG5cbiAgZXNjYXBlSHRtbCh0ZXh0KSB7XG4gICAgY29uc3QgZGl2ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG4gICAgZGl2LnRleHRDb250ZW50ID0gdGV4dDtcbiAgICByZXR1cm4gZGl2LmlubmVySFRNTDtcbiAgfVxuXG4gIGFzeW5jIGxvYWRDb252ZXJzYXRpb24oKSB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7XG4gICAgICBjaHJvbWUuc3RvcmFnZS5sb2NhbC5nZXQoWydoYW56b19jaGF0X21lc3NhZ2VzJ10sIChyZXN1bHQpID0+IHtcbiAgICAgICAgaWYgKHJlc3VsdC5oYW56b19jaGF0X21lc3NhZ2VzPy5sZW5ndGgpIHtcbiAgICAgICAgICB0aGlzLm1lc3NhZ2VzID0gcmVzdWx0LmhhbnpvX2NoYXRfbWVzc2FnZXM7XG4gICAgICAgICAgLy8gUmVuZGVyIHN0b3JlZCBtZXNzYWdlc1xuICAgICAgICAgIGNvbnN0IHdlbGNvbWUgPSB0aGlzLmVsLmNoYXRNZXNzYWdlcy5xdWVyeVNlbGVjdG9yKCcuY2hhdC13ZWxjb21lJyk7XG4gICAgICAgICAgaWYgKHdlbGNvbWUpIHdlbGNvbWUucmVtb3ZlKCk7XG4gICAgICAgICAgZm9yIChjb25zdCBtc2cgb2YgdGhpcy5tZXNzYWdlcykge1xuICAgICAgICAgICAgdGhpcy5hcHBlbmRNZXNzYWdlKG1zZy5yb2xlLCBtc2cuY29udGVudCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJlc29sdmUoKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG5cbiAgc2F2ZUNvbnZlcnNhdGlvbigpIHtcbiAgICAvLyBLZWVwIGxhc3QgNTAgbWVzc2FnZXNcbiAgICBjb25zdCB0b1N0b3JlID0gdGhpcy5tZXNzYWdlcy5zbGljZSgtNTApO1xuICAgIGNocm9tZS5zdG9yYWdlLmxvY2FsLnNldCh7IGhhbnpvX2NoYXRfbWVzc2FnZXM6IHRvU3RvcmUgfSk7XG4gIH1cblxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgLy8gVG9vbHMgVGFiXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4gIGFzeW5jIGNvbm5lY3RUb01DUCgpIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgemFwUmVzcG9uc2UgPSBhd2FpdCBjaHJvbWUucnVudGltZS5zZW5kTWVzc2FnZSh7IGFjdGlvbjogJ3phcC5zdGF0dXMnIH0pO1xuICAgICAgaWYgKHphcFJlc3BvbnNlPy5zdWNjZXNzKSB7XG4gICAgICAgIGNvbnN0IHphcCA9IHphcFJlc3BvbnNlLnphcDtcbiAgICAgICAgY29uc3QgdG9vbENvdW50ID0gemFwLm1jcHM/LnJlZHVjZSgoc3VtLCBtKSA9PiBzdW0gKyAobS50b29scz8ubGVuZ3RoIHx8IDApLCAwKSB8fCAwO1xuICAgICAgICB0aGlzLnVwZGF0ZU1DUFN0YXR1cyh6YXAuY29ubmVjdGVkLCB0b29sQ291bnQsIHphcC5tY3BzPy5sZW5ndGggfHwgMCk7XG4gICAgICAgIGlmICh6YXAuY29ubmVjdGVkKSB7XG4gICAgICAgICAgY29uc3QgdG9vbHNSZXNwID0gYXdhaXQgY2hyb21lLnJ1bnRpbWUuc2VuZE1lc3NhZ2UoeyBhY3Rpb246ICd6YXAubGlzdFRvb2xzJyB9KTtcbiAgICAgICAgICB0aGlzLnVwZGF0ZU1DUFRvb2xMaXN0KHRvb2xzUmVzcD8uc3VjY2VzcyA/IHRvb2xzUmVzcC50b29scyA6IFtdKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aGlzLnVwZGF0ZU1DUFRvb2xMaXN0KFtdKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy51cGRhdGVNQ1BTdGF0dXMoZmFsc2UpO1xuICAgICAgICB0aGlzLnVwZGF0ZU1DUFRvb2xMaXN0KFtdKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIHtcbiAgICAgIHRoaXMudXBkYXRlTUNQU3RhdHVzKGZhbHNlKTtcbiAgICAgIHRoaXMudXBkYXRlTUNQVG9vbExpc3QoW10pO1xuICAgIH1cbiAgfVxuXG4gIHVwZGF0ZU1DUFN0YXR1cyhjb25uZWN0ZWQsIHRvb2xDb3VudCA9IDAsIG1jcENvdW50ID0gMCkge1xuICAgIHRoaXMuZWwubWNwU3RhdHVzLmlubmVySFRNTCA9IGNvbm5lY3RlZCA/IGBcbiAgICAgIDxzcGFuIGNsYXNzPVwic3RhdHVzLWluZGljYXRvciBjb25uZWN0ZWRcIj48L3NwYW4+XG4gICAgICAke21jcENvdW50ID4gMCA/IGBaQVA6ICR7bWNwQ291bnR9IE1DUChzKWAgOiAnQ29ubmVjdGVkJ31cbiAgICBgIDogYFxuICAgICAgPHNwYW4gY2xhc3M9XCJzdGF0dXMtaW5kaWNhdG9yIGRpc2Nvbm5lY3RlZFwiPjwvc3Bhbj5cbiAgICAgIERpc2Nvbm5lY3RlZFxuICAgIGA7XG4gICAgdGhpcy5lbC5tY3BUb29scy50ZXh0Q29udGVudCA9IHRvb2xDb3VudDtcbiAgfVxuXG4gIHVwZGF0ZU1DUFRvb2xMaXN0KHRvb2xzKSB7XG4gICAgaWYgKCF0aGlzLmVsLm1jcFRvb2xMaXN0KSByZXR1cm47XG4gICAgaWYgKCF0b29scyB8fCAhdG9vbHMubGVuZ3RoKSB7XG4gICAgICB0aGlzLmVsLm1jcFRvb2xMaXN0LnRleHRDb250ZW50ID0gJ05vIHRvb2xzIGRpc2NvdmVyZWQgeWV0Lic7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgbmFtZXMgPSBBcnJheS5mcm9tKG5ldyBTZXQodG9vbHMubWFwKCh0b29sKSA9PiB0b29sLm5hbWUpKSkuc29ydCgpO1xuICAgIGNvbnN0IHByZXZpZXcgPSBuYW1lcy5zbGljZSgwLCAyMCk7XG4gICAgY29uc3Qgc3VmZml4ID0gbmFtZXMubGVuZ3RoID4gcHJldmlldy5sZW5ndGggPyBgXFxuLi4uICske25hbWVzLmxlbmd0aCAtIHByZXZpZXcubGVuZ3RofSBtb3JlYCA6ICcnO1xuICAgIHRoaXMuZWwubWNwVG9vbExpc3QudGV4dENvbnRlbnQgPSBgJHtwcmV2aWV3LmpvaW4oJ1xcbicpfSR7c3VmZml4fWA7XG4gIH1cblxuICBhc3luYyByZWZyZXNoVGFiRmlsZXN5c3RlbSgpIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgdGFicyA9IGF3YWl0IGNocm9tZS50YWJzLnF1ZXJ5KHt9KTtcbiAgICAgIHRoaXMuZWwudGFiRnMuaW5uZXJIVE1MID0gdGFicy5tYXAoKHRhYiwgaSkgPT4gYFxuICAgICAgICA8ZGl2IGNsYXNzPVwidGFiLWl0ZW0gJHt0YWIuYWN0aXZlID8gJ2FjdGl2ZScgOiAnJ31cIiBkYXRhLXRhYi1pZD1cIiR7dGFiLmlkfVwiPlxuICAgICAgICAgIDxzdmcgd2lkdGg9XCIxMlwiIGhlaWdodD1cIjEyXCIgdmlld0JveD1cIjAgMCAxNiAxNlwiIGZpbGw9XCJjdXJyZW50Q29sb3JcIj5cbiAgICAgICAgICAgIDxwYXRoIGQ9XCJNMiAydjEyaDEyVjJIMnptMSAxaDEwdjEwSDNWM3pcIi8+XG4gICAgICAgICAgPC9zdmc+XG4gICAgICAgICAgPHNwYW4gdGl0bGU9XCIke3RoaXMuZXNjYXBlSHRtbCh0YWIudXJsIHx8ICcnKX1cIj4vdGFicy8ke2l9LyR7dGhpcy5zYW5pdGl6ZVBhdGgodGFiLnRpdGxlIHx8ICd1bnRpdGxlZCcpfTwvc3Bhbj5cbiAgICAgICAgPC9kaXY+XG4gICAgICBgKS5qb2luKCcnKTtcblxuICAgICAgdGhpcy5lbC50YWJGcy5xdWVyeVNlbGVjdG9yQWxsKCcudGFiLWl0ZW0nKS5mb3JFYWNoKGl0ZW0gPT4ge1xuICAgICAgICBpdGVtLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgKCkgPT4ge1xuICAgICAgICAgIGNocm9tZS50YWJzLnVwZGF0ZShwYXJzZUludChpdGVtLmRhdGFzZXQudGFiSWQpLCB7IGFjdGl2ZTogdHJ1ZSB9KTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9IGNhdGNoIHt9XG4gIH1cblxuICBzYW5pdGl6ZVBhdGgodGl0bGUpIHtcbiAgICByZXR1cm4gdGl0bGUucmVwbGFjZSgvW15hLXpBLVowLTktX10vZywgJ18nKS50b0xvd2VyQ2FzZSgpLnN1YnN0cmluZygwLCAzMCk7XG4gIH1cblxuICBhc3luYyBjaGVja1dlYkdQVSgpIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBjaHJvbWUucnVudGltZS5zZW5kTWVzc2FnZSh7IGFjdGlvbjogJ2NoZWNrV2ViR1BVJyB9KTtcbiAgICAgIGlmIChyZXNwb25zZT8uYXZhaWxhYmxlKSB7XG4gICAgICAgIHRoaXMuZWwuZ3B1U3RhdHVzLmlubmVySFRNTCA9IGBcbiAgICAgICAgICA8c3BhbiBjbGFzcz1cInN0YXR1cy1pbmRpY2F0b3IgY29ubmVjdGVkXCI+PC9zcGFuPlxuICAgICAgICAgIEF2YWlsYWJsZVxuICAgICAgICBgO1xuICAgICAgICB0aGlzLmVsLmdwdU1vZGVsLnRleHRDb250ZW50ID0gcmVzcG9uc2UuYWRhcHRlciB8fCAnVW5rbm93bic7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLmVsLmdwdVN0YXR1cy5pbm5lckhUTUwgPSBgXG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJzdGF0dXMtaW5kaWNhdG9yIGRpc2Nvbm5lY3RlZFwiPjwvc3Bhbj5cbiAgICAgICAgICBOb3QgQXZhaWxhYmxlXG4gICAgICAgIGA7XG4gICAgICB9XG4gICAgfSBjYXRjaCB7fVxuICB9XG5cbiAgdXBkYXRlQWdlbnRMaXN0KCkge1xuICAgIGNvbnN0IGFyciA9IEFycmF5LmZyb20odGhpcy5hZ2VudHMudmFsdWVzKCkpO1xuICAgIHRoaXMuZWwuYWdlbnRDb3VudC50ZXh0Q29udGVudCA9IGFyci5sZW5ndGg7XG4gICAgaWYgKGFyci5sZW5ndGggPT09IDApIHtcbiAgICAgIHRoaXMuZWwuYWdlbnRMaXN0LmlubmVySFRNTCA9ICc8ZGl2IGNsYXNzPVwiZW1wdHktc3RhdGVcIj5ObyBhY3RpdmUgYWdlbnRzPC9kaXY+JztcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5lbC5hZ2VudExpc3QuaW5uZXJIVE1MID0gYXJyLm1hcChhID0+IGBcbiAgICAgIDxkaXYgY2xhc3M9XCJhZ2VudC1pdGVtXCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJhZ2VudC1pY29uXCI+XG4gICAgICAgICAgPHN2ZyB3aWR0aD1cIjE2XCIgaGVpZ2h0PVwiMTZcIiB2aWV3Qm94PVwiMCAwIDI0IDI0XCIgZmlsbD1cIm5vbmVcIiBzdHJva2U9XCJjdXJyZW50Q29sb3JcIj5cbiAgICAgICAgICAgIDxjaXJjbGUgY3g9XCIxMlwiIGN5PVwiMTJcIiByPVwiMTBcIiBzdHJva2Utd2lkdGg9XCIyXCIvPlxuICAgICAgICAgICAgPHBhdGggZD1cIk0xMiA2djZsNCAyXCIgc3Ryb2tlLXdpZHRoPVwiMlwiLz5cbiAgICAgICAgICA8L3N2Zz5cbiAgICAgICAgPC9kaXY+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJhZ2VudC1pbmZvXCI+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImFnZW50LW5hbWVcIj4ke3RoaXMuZXNjYXBlSHRtbChhLm5hbWUpfTwvZGl2PlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJhZ2VudC1zdGF0dXNcIj4ke2Euc3RhdHVzfSBcdTIwMjIgVGFiICR7YS50YWJJZH08L2Rpdj5cbiAgICAgICAgPC9kaXY+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJhZ2VudC1hY3Rpb25zXCI+XG4gICAgICAgICAgPGJ1dHRvbiBjbGFzcz1cImljb24tYnRuIHNtYWxsXCIgZGF0YS1zdG9wPVwiJHthLmlkfVwiIHRpdGxlPVwiU3RvcFwiPlxuICAgICAgICAgICAgPHN2ZyB2aWV3Qm94PVwiMCAwIDE2IDE2XCIgZmlsbD1cImN1cnJlbnRDb2xvclwiPlxuICAgICAgICAgICAgICA8cmVjdCB4PVwiNFwiIHk9XCI0XCIgd2lkdGg9XCI4XCIgaGVpZ2h0PVwiOFwiIHN0cm9rZS13aWR0aD1cIjJcIi8+XG4gICAgICAgICAgICA8L3N2Zz5cbiAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L2Rpdj5cbiAgICBgKS5qb2luKCcnKTtcblxuICAgIHRoaXMuZWwuYWdlbnRMaXN0LnF1ZXJ5U2VsZWN0b3JBbGwoJ1tkYXRhLXN0b3BdJykuZm9yRWFjaChidG4gPT4ge1xuICAgICAgYnRuLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgKCkgPT4ge1xuICAgICAgICBjb25zdCBpZCA9IGJ0bi5kYXRhc2V0LnN0b3A7XG4gICAgICAgIGNocm9tZS5ydW50aW1lLnNlbmRNZXNzYWdlKHsgYWN0aW9uOiAnc3RvcEFnZW50JywgYWdlbnRJZDogaWQgfSk7XG4gICAgICAgIHRoaXMuYWdlbnRzLmRlbGV0ZShpZCk7XG4gICAgICAgIHRoaXMudXBkYXRlQWdlbnRMaXN0KCk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIHNob3dBZ2VudExhdW5jaGVyKCkge1xuICAgIC8vIENyZWF0ZSBhZ2VudCBsYXVuY2hlciBtb2RhbCBvdmVybGF5XG4gICAgY29uc3Qgb3ZlcmxheSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuICAgIG92ZXJsYXkuY2xhc3NOYW1lID0gJ21vZGFsLW92ZXJsYXknO1xuICAgIG92ZXJsYXkuaW5uZXJIVE1MID0gYFxuICAgICAgPGRpdiBjbGFzcz1cIm1vZGFsLWNvbnRlbnRcIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cIm1vZGFsLWhlYWRlclwiPlxuICAgICAgICAgIDxoMz5MYXVuY2ggQWdlbnQ8L2gzPlxuICAgICAgICAgIDxidXR0b24gY2xhc3M9XCJpY29uLWJ0biBjbG9zZS1tb2RhbFwiPiZ0aW1lczs8L2J1dHRvbj5cbiAgICAgICAgPC9kaXY+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJtb2RhbC1ib2R5XCI+XG4gICAgICAgICAgPGxhYmVsIGNsYXNzPVwic2V0dGluZy1pdGVtXCI+XG4gICAgICAgICAgICA8c3Bhbj5UYXJnZXQgVGFiPC9zcGFuPlxuICAgICAgICAgICAgPHNlbGVjdCBpZD1cImFnZW50LXRhYi1zZWxlY3RcIj5cbiAgICAgICAgICAgICAgPG9wdGlvbiB2YWx1ZT1cImFjdGl2ZVwiPkFjdGl2ZSBUYWI8L29wdGlvbj5cbiAgICAgICAgICAgIDwvc2VsZWN0PlxuICAgICAgICAgIDwvbGFiZWw+XG4gICAgICAgICAgPGxhYmVsIGNsYXNzPVwic2V0dGluZy1pdGVtXCI+XG4gICAgICAgICAgICA8c3Bhbj5BZ2VudCBUeXBlPC9zcGFuPlxuICAgICAgICAgICAgPHNlbGVjdCBpZD1cImFnZW50LXR5cGUtc2VsZWN0XCI+XG4gICAgICAgICAgICAgIDxvcHRpb24gdmFsdWU9XCJicm93c2VyLWNvbnRyb2xcIj5Ccm93c2VyIEF1dG9tYXRpb248L29wdGlvbj5cbiAgICAgICAgICAgICAgPG9wdGlvbiB2YWx1ZT1cInBhZ2UtYW5hbHl6ZXJcIj5QYWdlIEFuYWx5emVyPC9vcHRpb24+XG4gICAgICAgICAgICAgIDxvcHRpb24gdmFsdWU9XCJmb3JtLWZpbGxlclwiPkZvcm0gRmlsbGVyPC9vcHRpb24+XG4gICAgICAgICAgICAgIDxvcHRpb24gdmFsdWU9XCJkYXRhLWV4dHJhY3RvclwiPkRhdGEgRXh0cmFjdG9yPC9vcHRpb24+XG4gICAgICAgICAgICA8L3NlbGVjdD5cbiAgICAgICAgICA8L2xhYmVsPlxuICAgICAgICAgIDxsYWJlbCBjbGFzcz1cInNldHRpbmctaXRlbVwiPlxuICAgICAgICAgICAgPHNwYW4+SW5zdHJ1Y3Rpb25zPC9zcGFuPlxuICAgICAgICAgICAgPHRleHRhcmVhIGlkPVwiYWdlbnQtaW5zdHJ1Y3Rpb25zXCIgcm93cz1cIjNcIiBwbGFjZWhvbGRlcj1cIkRlc2NyaWJlIHdoYXQgdGhlIGFnZW50IHNob3VsZCBkby4uLlwiPjwvdGV4dGFyZWE+XG4gICAgICAgICAgPC9sYWJlbD5cbiAgICAgICAgPC9kaXY+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJtb2RhbC1mb290ZXJcIj5cbiAgICAgICAgICA8YnV0dG9uIGNsYXNzPVwic2Vjb25kYXJ5LWJ0biBjYW5jZWwtbW9kYWxcIj5DYW5jZWw8L2J1dHRvbj5cbiAgICAgICAgICA8YnV0dG9uIGNsYXNzPVwicHJpbWFyeS1idG4gbGF1bmNoLW1vZGFsXCI+TGF1bmNoPC9idXR0b24+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9kaXY+XG4gICAgYDtcbiAgICBkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKG92ZXJsYXkpO1xuXG4gICAgLy8gUG9wdWxhdGUgdGFic1xuICAgIGNocm9tZS50YWJzLnF1ZXJ5KHt9LCAodGFicykgPT4ge1xuICAgICAgY29uc3Qgc2VsZWN0ID0gb3ZlcmxheS5xdWVyeVNlbGVjdG9yKCcjYWdlbnQtdGFiLXNlbGVjdCcpO1xuICAgICAgdGFicy5mb3JFYWNoKHRhYiA9PiB7XG4gICAgICAgIGlmICh0YWIuaWQpIHtcbiAgICAgICAgICBjb25zdCBvcHQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdvcHRpb24nKTtcbiAgICAgICAgICBvcHQudmFsdWUgPSB0YWIuaWQ7XG4gICAgICAgICAgb3B0LnRleHRDb250ZW50ID0gYCR7dGFiLnRpdGxlPy5zdWJzdHJpbmcoMCwgNDApIHx8ICdVbnRpdGxlZCd9ICR7dGFiLmFjdGl2ZSA/ICcoYWN0aXZlKScgOiAnJ31gO1xuICAgICAgICAgIHNlbGVjdC5hcHBlbmRDaGlsZChvcHQpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIC8vIENsb3NlIGhhbmRsZXJzXG4gICAgb3ZlcmxheS5xdWVyeVNlbGVjdG9yKCcuY2xvc2UtbW9kYWwnKS5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsICgpID0+IG92ZXJsYXkucmVtb3ZlKCkpO1xuICAgIG92ZXJsYXkucXVlcnlTZWxlY3RvcignLmNhbmNlbC1tb2RhbCcpLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgKCkgPT4gb3ZlcmxheS5yZW1vdmUoKSk7XG4gICAgb3ZlcmxheS5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIChlKSA9PiB7IGlmIChlLnRhcmdldCA9PT0gb3ZlcmxheSkgb3ZlcmxheS5yZW1vdmUoKTsgfSk7XG5cbiAgICAvLyBMYXVuY2ggaGFuZGxlclxuICAgIG92ZXJsYXkucXVlcnlTZWxlY3RvcignLmxhdW5jaC1tb2RhbCcpLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgdGFiU2VsZWN0ID0gb3ZlcmxheS5xdWVyeVNlbGVjdG9yKCcjYWdlbnQtdGFiLXNlbGVjdCcpO1xuICAgICAgY29uc3QgdHlwZVNlbGVjdCA9IG92ZXJsYXkucXVlcnlTZWxlY3RvcignI2FnZW50LXR5cGUtc2VsZWN0Jyk7XG4gICAgICBjb25zdCBpbnN0cnVjdGlvbnMgPSBvdmVybGF5LnF1ZXJ5U2VsZWN0b3IoJyNhZ2VudC1pbnN0cnVjdGlvbnMnKTtcblxuICAgICAgbGV0IHRhYklkO1xuICAgICAgaWYgKHRhYlNlbGVjdC52YWx1ZSA9PT0gJ2FjdGl2ZScpIHtcbiAgICAgICAgY29uc3QgW2FjdGl2ZVRhYl0gPSBhd2FpdCBjaHJvbWUudGFicy5xdWVyeSh7IGFjdGl2ZTogdHJ1ZSwgY3VycmVudFdpbmRvdzogdHJ1ZSB9KTtcbiAgICAgICAgdGFiSWQgPSBhY3RpdmVUYWI/LmlkO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGFiSWQgPSBwYXJzZUludCh0YWJTZWxlY3QudmFsdWUpO1xuICAgICAgfVxuXG4gICAgICBpZiAoIXRhYklkKSB7XG4gICAgICAgIHRoaXMuc2hvd0Vycm9yKCdObyB0YWIgc2VsZWN0ZWQnKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBhZ2VudFR5cGUgPSB0eXBlU2VsZWN0LnZhbHVlO1xuICAgICAgY29uc3QgYWdlbnRJbnN0cnVjdGlvbnMgPSBpbnN0cnVjdGlvbnMudmFsdWU/LnRyaW0oKSB8fCAnJztcbiAgICAgIG92ZXJsYXkucmVtb3ZlKCk7XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgY2hyb21lLnJ1bnRpbWUuc2VuZE1lc3NhZ2Uoe1xuICAgICAgICAgIGFjdGlvbjogJ2xhdW5jaEFJV29ya2VyJyxcbiAgICAgICAgICB0YWJJZCxcbiAgICAgICAgICBtb2RlbDogYWdlbnRUeXBlLFxuICAgICAgICAgIGluc3RydWN0aW9uczogYWdlbnRJbnN0cnVjdGlvbnMsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChyZXNwb25zZT8uc3VjY2Vzcykge1xuICAgICAgICAgIGNvbnN0IGFnZW50SWQgPSByZXNwb25zZS5hZ2VudElkIHx8IGBhZ2VudC0ke0RhdGUubm93KCkudG9TdHJpbmcoMzYpfWA7XG4gICAgICAgICAgdGhpcy5hZ2VudHMuc2V0KGFnZW50SWQsIHtcbiAgICAgICAgICAgIGlkOiBhZ2VudElkLFxuICAgICAgICAgICAgbmFtZTogYWdlbnRUeXBlLFxuICAgICAgICAgICAgdGFiSWQsXG4gICAgICAgICAgICBzdGF0dXM6ICdydW5uaW5nJyxcbiAgICAgICAgICB9KTtcbiAgICAgICAgICB0aGlzLnVwZGF0ZUFnZW50TGlzdCgpO1xuICAgICAgICAgIHRoaXMuc2hvd05vdGlmaWNhdGlvbihgQWdlbnQgbGF1bmNoZWQgb24gdGFiICR7dGFiSWR9YCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5zaG93RXJyb3IocmVzcG9uc2U/LmVycm9yIHx8ICdGYWlsZWQgdG8gbGF1bmNoIGFnZW50Jyk7XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIHRoaXMuc2hvd0Vycm9yKCdGYWlsZWQgdG8gbGF1bmNoIGFnZW50OiAnICsgZXJyb3IubWVzc2FnZSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgLy8gU2V0dGluZ3MgVGFiXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4gIGxvYWRTZXR0aW5ncygpIHtcbiAgICBjaHJvbWUuc3RvcmFnZS5sb2NhbC5nZXQoW1xuICAgICAgJ21jcFBvcnQnLFxuICAgICAgJ2NkcFBvcnQnLFxuICAgICAgJ3phcFBvcnRzJyxcbiAgICAgICdoYW56b19kZWZhdWx0X21vZGVsJyxcbiAgICAgICdoYW56b19yYWdfZW5kcG9pbnQnLFxuICAgICAgJ2hhbnpvX3JhZ19hcGlfa2V5JyxcbiAgICAgICdoYW56b19yYWdfa2InLFxuICAgICAgJ2hhbnpvX3JhZ190b3BfaycsXG4gICAgICAnaGFuem9fcmFnX2luY2x1ZGVfdGFiX2NvbnRleHQnLFxuICAgICAgJ2hhbnpvX3JhZ191c2VfemFwJyxcbiAgICAgICdoYW56b19jaGF0X3JhZ19lbmFibGVkJyxcbiAgICAgICdoYW56b19jaGF0X3RhYl9jb250ZXh0X2VuYWJsZWQnLFxuICAgIF0sIChyZXN1bHQpID0+IHtcbiAgICAgIGNvbnN0IG1jcFBvcnQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnbWNwLXBvcnQtc2V0dGluZycpO1xuICAgICAgY29uc3QgY2RwUG9ydCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdjZHAtcG9ydC1zZXR0aW5nJyk7XG4gICAgICBjb25zdCB6YXBQb3J0cyA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCd6YXAtcG9ydHMtc2V0dGluZycpO1xuXG4gICAgICBpZiAobWNwUG9ydCkgbWNwUG9ydC52YWx1ZSA9IHJlc3VsdC5tY3BQb3J0IHx8IDMwMDE7XG4gICAgICBpZiAoY2RwUG9ydCkgY2RwUG9ydC52YWx1ZSA9IHJlc3VsdC5jZHBQb3J0IHx8IDkyMjM7XG4gICAgICBpZiAoemFwUG9ydHMpIHphcFBvcnRzLnZhbHVlID0gKHJlc3VsdC56YXBQb3J0cyB8fCBbOTk5OSw5OTk4LDk5OTcsOTk5Niw5OTk1XSkuam9pbignLCcpO1xuICAgICAgaWYgKHJlc3VsdC5oYW56b19kZWZhdWx0X21vZGVsICYmIHRoaXMuZWwuZGVmYXVsdE1vZGVsKSB7XG4gICAgICAgIHRoaXMuZWwuZGVmYXVsdE1vZGVsLnZhbHVlID0gcmVzdWx0LmhhbnpvX2RlZmF1bHRfbW9kZWw7XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLmVsLnJhZ0VuZHBvaW50KSB0aGlzLmVsLnJhZ0VuZHBvaW50LnZhbHVlID0gcmVzdWx0LmhhbnpvX3JhZ19lbmRwb2ludCB8fCAnJztcbiAgICAgIGlmICh0aGlzLmVsLnJhZ0FwaUtleSkgdGhpcy5lbC5yYWdBcGlLZXkudmFsdWUgPSByZXN1bHQuaGFuem9fcmFnX2FwaV9rZXkgfHwgJyc7XG4gICAgICBpZiAodGhpcy5lbC5yYWdLYikgdGhpcy5lbC5yYWdLYi52YWx1ZSA9IHJlc3VsdC5oYW56b19yYWdfa2IgfHwgJyc7XG4gICAgICBpZiAodGhpcy5lbC5yYWdUb3BLKSB0aGlzLmVsLnJhZ1RvcEsudmFsdWUgPSBTdHJpbmcocmVzdWx0LmhhbnpvX3JhZ190b3BfayB8fCA1KTtcbiAgICAgIGlmICh0aGlzLmVsLnJhZ0luY2x1ZGVUYWJDb250ZXh0KSB0aGlzLmVsLnJhZ0luY2x1ZGVUYWJDb250ZXh0LmNoZWNrZWQgPSByZXN1bHQuaGFuem9fcmFnX2luY2x1ZGVfdGFiX2NvbnRleHQgIT09IGZhbHNlO1xuICAgICAgaWYgKHRoaXMuZWwucmFnVXNlWmFwKSB0aGlzLmVsLnJhZ1VzZVphcC5jaGVja2VkID0gcmVzdWx0LmhhbnpvX3JhZ191c2VfemFwICE9PSBmYWxzZTtcbiAgICAgIGlmICh0aGlzLmVsLnJhZ0VuYWJsZWQpIHRoaXMuZWwucmFnRW5hYmxlZC5jaGVja2VkID0gcmVzdWx0LmhhbnpvX2NoYXRfcmFnX2VuYWJsZWQgIT09IGZhbHNlO1xuICAgICAgaWYgKHRoaXMuZWwudGFiQ29udGV4dEVuYWJsZWQpIHRoaXMuZWwudGFiQ29udGV4dEVuYWJsZWQuY2hlY2tlZCA9IHJlc3VsdC5oYW56b19jaGF0X3RhYl9jb250ZXh0X2VuYWJsZWQgIT09IGZhbHNlO1xuICAgICAgdGhpcy5zZXRSYWdTdGF0dXModGhpcy5lbC5yYWdFbmFibGVkPy5jaGVja2VkID8gJ1JlYWR5JyA6ICdSQUcgZGlzYWJsZWQnKTtcbiAgICB9KTtcbiAgfVxuXG4gIGFzeW5jIHNhdmVTZXR0aW5ncygpIHtcbiAgICBjb25zdCBtY3BQb3J0ID0gcGFyc2VJbnQoZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ21jcC1wb3J0LXNldHRpbmcnKT8udmFsdWUpIHx8IDMwMDE7XG4gICAgY29uc3QgY2RwUG9ydCA9IHBhcnNlSW50KGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdjZHAtcG9ydC1zZXR0aW5nJyk/LnZhbHVlKSB8fCA5MjIzO1xuICAgIGNvbnN0IHphcFBvcnRzID0gKGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCd6YXAtcG9ydHMtc2V0dGluZycpPy52YWx1ZSB8fCAnJylcbiAgICAgIC5zcGxpdCgnLCcpLm1hcChwID0+IHBhcnNlSW50KHAudHJpbSgpKSkuZmlsdGVyKHAgPT4gcCA+IDAgJiYgcCA8IDY1NTM2KTtcblxuICAgIGF3YWl0IGNocm9tZS5zdG9yYWdlLmxvY2FsLnNldCh7XG4gICAgICBtY3BQb3J0LFxuICAgICAgY2RwUG9ydCxcbiAgICAgIHphcFBvcnRzOiB6YXBQb3J0cy5sZW5ndGggPyB6YXBQb3J0cyA6IFs5OTk5LDk5OTgsOTk5Nyw5OTk2LDk5OTVdLFxuICAgICAgaGFuem9fZGVmYXVsdF9tb2RlbDogdGhpcy5lbC5kZWZhdWx0TW9kZWw/LnZhbHVlIHx8ICdncHQtNG8nLFxuICAgICAgJ3NhZmUtbW9kZSc6IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdzYWZlLW1vZGUnKT8uY2hlY2tlZCxcbiAgICAgICdlbmFibGUtd2ViZ3B1JzogZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2VuYWJsZS13ZWJncHUnKT8uY2hlY2tlZCxcbiAgICAgIG1heEFnZW50czogcGFyc2VJbnQoZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ21heC1hZ2VudHMnKT8udmFsdWUpIHx8IDMsXG4gICAgICBoYW56b19yYWdfZW5kcG9pbnQ6IHRoaXMuZWwucmFnRW5kcG9pbnQ/LnZhbHVlPy50cmltKCkgfHwgJycsXG4gICAgICBoYW56b19yYWdfYXBpX2tleTogdGhpcy5lbC5yYWdBcGlLZXk/LnZhbHVlPy50cmltKCkgfHwgJycsXG4gICAgICBoYW56b19yYWdfa2I6IHRoaXMuZWwucmFnS2I/LnZhbHVlPy50cmltKCkgfHwgJycsXG4gICAgICBoYW56b19yYWdfdG9wX2s6IE1hdGgubWF4KDEsIE1hdGgubWluKHBhcnNlSW50KHRoaXMuZWwucmFnVG9wSz8udmFsdWUgfHwgJzUnLCAxMCkgfHwgNSwgMjApKSxcbiAgICAgIGhhbnpvX3JhZ19pbmNsdWRlX3RhYl9jb250ZXh0OiAhIXRoaXMuZWwucmFnSW5jbHVkZVRhYkNvbnRleHQ/LmNoZWNrZWQsXG4gICAgICBoYW56b19yYWdfdXNlX3phcDogISF0aGlzLmVsLnJhZ1VzZVphcD8uY2hlY2tlZCxcbiAgICAgIGhhbnpvX2NoYXRfcmFnX2VuYWJsZWQ6ICEhdGhpcy5lbC5yYWdFbmFibGVkPy5jaGVja2VkLFxuICAgICAgaGFuem9fY2hhdF90YWJfY29udGV4dF9lbmFibGVkOiAhIXRoaXMuZWwudGFiQ29udGV4dEVuYWJsZWQ/LmNoZWNrZWQsXG4gICAgfSk7XG5cbiAgICB0aGlzLnNob3dOb3RpZmljYXRpb24oJ1NldHRpbmdzIHNhdmVkJyk7XG4gIH1cblxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgLy8gVXRpbGl0eVxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuICBzdGFydE1vbml0b3JpbmcoKSB7XG4gICAgc2V0SW50ZXJ2YWwoKCkgPT4gdGhpcy5jb25uZWN0VG9NQ1AoKSwgMTAwMDApO1xuICAgIGNocm9tZS50YWJzLm9uVXBkYXRlZC5hZGRMaXN0ZW5lcigoKSA9PiB0aGlzLnJlZnJlc2hUYWJGaWxlc3lzdGVtKCkpO1xuICAgIGNocm9tZS50YWJzLm9uUmVtb3ZlZC5hZGRMaXN0ZW5lcigoKSA9PiB0aGlzLnJlZnJlc2hUYWJGaWxlc3lzdGVtKCkpO1xuICB9XG5cbiAgaGFuZGxlTWVzc2FnZShyZXF1ZXN0KSB7XG4gICAgc3dpdGNoIChyZXF1ZXN0LmFjdGlvbikge1xuICAgICAgY2FzZSAnYWdlbnRVcGRhdGUnOlxuICAgICAgICBpZiAocmVxdWVzdC5hZ2VudElkICYmIHRoaXMuYWdlbnRzLmhhcyhyZXF1ZXN0LmFnZW50SWQpKSB7XG4gICAgICAgICAgdGhpcy5hZ2VudHMuZ2V0KHJlcXVlc3QuYWdlbnRJZCkuc3RhdHVzID0gcmVxdWVzdC5zdGF0dXM7XG4gICAgICAgICAgdGhpcy51cGRhdGVBZ2VudExpc3QoKTtcbiAgICAgICAgfVxuICAgICAgICBicmVhaztcbiAgICB9XG4gIH1cblxuICBzaG93Tm90aWZpY2F0aW9uKG1lc3NhZ2UpIHtcbiAgICBjb25zdCBlbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuICAgIGVsLmNsYXNzTmFtZSA9ICdub3RpZmljYXRpb24nO1xuICAgIGVsLnRleHRDb250ZW50ID0gbWVzc2FnZTtcbiAgICBkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKGVsKTtcbiAgICBzZXRUaW1lb3V0KCgpID0+IGVsLnJlbW92ZSgpLCAzMDAwKTtcbiAgfVxuXG4gIHNob3dFcnJvcihtZXNzYWdlKSB7XG4gICAgY29uc3QgZWwgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcbiAgICBlbC5jbGFzc05hbWUgPSAnbm90aWZpY2F0aW9uIGVycm9yJztcbiAgICBlbC50ZXh0Q29udGVudCA9IG1lc3NhZ2U7XG4gICAgZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChlbCk7XG4gICAgc2V0VGltZW91dCgoKSA9PiBlbC5yZW1vdmUoKSwgNTAwMCk7XG4gIH1cbn1cblxuLy8gSW5pdGlhbGl6ZVxuY29uc3QgaGFuem9TaWRlYmFyID0gbmV3IEhhbnpvU2lkZWJhcigpO1xuIl0sCiAgIm1hcHBpbmdzIjogIjs7O0FBRUEsTUFBTSxlQUFOLE1BQW1CO0FBQUEsSUFDakIsY0FBYztBQUNaLFdBQUssU0FBUyxvQkFBSSxJQUFJO0FBQ3RCLFdBQUssYUFBYTtBQUNsQixXQUFLLFdBQVcsQ0FBQztBQUNqQixXQUFLLFlBQVk7QUFDakIsV0FBSyxtQkFBbUI7QUFDeEIsV0FBSyxnQkFBZ0I7QUFDckIsV0FBSyxhQUFhO0FBRWxCLFdBQUssYUFBYTtBQUNsQixXQUFLLG9CQUFvQjtBQUN6QixXQUFLLFVBQVU7QUFBQSxJQUNqQjtBQUFBLElBRUEsZUFBZTtBQUNiLFdBQUssS0FBSztB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