@hanzo/browser-extension 1.7.6 → 1.9.33

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