@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.
- package/.github/workflows/docs.yml +44 -0
- package/.github/workflows/release.yml +55 -0
- package/LICENSE +21 -0
- package/README.md +126 -0
- package/dist/browser-extension/README.md +43 -0
- package/dist/browser-extension/ai-worker.js +30 -0
- package/dist/browser-extension/background-firefox.js +617 -0
- package/dist/browser-extension/background.js +2737 -0
- package/dist/browser-extension/browser-control.js +683 -0
- package/dist/browser-extension/cdp-bridge-server.js +444 -0
- package/dist/browser-extension/chrome/ai-worker.js +571 -0
- package/dist/browser-extension/chrome/background.js +2737 -0
- package/dist/browser-extension/chrome/callback.html +17 -0
- package/dist/browser-extension/chrome/content-script.js +1270 -0
- package/dist/browser-extension/chrome/icon128.png +0 -0
- package/dist/browser-extension/chrome/icon16.png +0 -0
- package/dist/browser-extension/chrome/icon32.png +0 -0
- package/dist/browser-extension/chrome/icon48.png +0 -0
- package/dist/browser-extension/chrome/manifest.json +57 -0
- package/dist/browser-extension/chrome/popup.css +519 -0
- package/dist/browser-extension/chrome/popup.html +242 -0
- package/dist/browser-extension/chrome/popup.js +267 -0
- package/dist/browser-extension/chrome/sidebar.css +1176 -0
- package/dist/browser-extension/chrome/sidebar.html +280 -0
- package/dist/browser-extension/chrome/sidebar.js +778 -0
- package/dist/browser-extension/cli.js +233 -0
- package/dist/browser-extension/content-script.js +1270 -0
- package/dist/browser-extension/firefox/ai-worker.js +571 -0
- package/dist/browser-extension/firefox/background.js +617 -0
- package/dist/browser-extension/firefox/callback.html +17 -0
- package/dist/browser-extension/firefox/content-script.js +1270 -0
- package/dist/browser-extension/firefox/icon128.png +0 -0
- package/dist/browser-extension/firefox/icon16.png +0 -0
- package/dist/browser-extension/firefox/icon32.png +0 -0
- package/dist/browser-extension/firefox/icon48.png +0 -0
- package/dist/browser-extension/firefox/manifest.json +66 -0
- package/dist/browser-extension/firefox/popup.css +519 -0
- package/dist/browser-extension/firefox/popup.html +242 -0
- package/dist/browser-extension/firefox/popup.js +267 -0
- package/dist/browser-extension/firefox/sidebar.css +1176 -0
- package/dist/browser-extension/firefox/sidebar.html +280 -0
- package/dist/browser-extension/firefox/sidebar.js +778 -0
- package/dist/browser-extension/hanzo-browser-extension-firefox-1.1.0.zip +0 -0
- package/dist/browser-extension/icon128.png +0 -0
- package/dist/browser-extension/icon16.png +0 -0
- package/dist/browser-extension/icon32.png +0 -0
- package/dist/browser-extension/icon48.png +0 -0
- package/dist/browser-extension/manifest.json +57 -0
- package/dist/browser-extension/package.json +41 -0
- package/dist/browser-extension/popup.css +468 -0
- package/dist/browser-extension/popup.html +191 -0
- package/dist/browser-extension/popup.js +267 -0
- package/dist/browser-extension/safari/Info.plist +21 -0
- package/dist/browser-extension/safari/ai-worker.js +571 -0
- package/dist/browser-extension/safari/background.js +2737 -0
- package/dist/browser-extension/safari/callback.html +17 -0
- package/dist/browser-extension/safari/content-script.js +1270 -0
- package/dist/browser-extension/safari/icon128.png +0 -0
- package/dist/browser-extension/safari/icon16.png +0 -0
- package/dist/browser-extension/safari/icon32.png +0 -0
- package/dist/browser-extension/safari/icon48.png +0 -0
- package/dist/browser-extension/safari/popup.css +519 -0
- package/dist/browser-extension/safari/popup.html +242 -0
- package/dist/browser-extension/safari/popup.js +267 -0
- package/dist/browser-extension/safari/sidebar.css +1176 -0
- package/dist/browser-extension/safari/sidebar.html +280 -0
- package/dist/browser-extension/safari/sidebar.js +778 -0
- package/dist/browser-extension/sidebar.css +718 -0
- package/dist/browser-extension/sidebar.html +184 -0
- package/dist/browser-extension/sidebar.js +778 -0
- package/dist/browser-extension/webgpu-ai.js +495 -0
- package/dist/cdp-bridge-server.js +411 -0
- package/dist/safari/Hanzo AI/Hanzo AI.xcodeproj/project.pbxproj +1047 -0
- package/dist/safari/Hanzo AI/Hanzo AI.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/Contents.json +98 -0
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-128@1x.png +0 -0
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-128@2x.png +0 -0
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-16@1x.png +0 -0
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-16@2x.png +0 -0
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-256@1x.png +0 -0
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-256@2x.png +0 -0
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-32@1x.png +0 -0
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-32@2x.png +0 -0
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-512@1x.png +0 -0
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/mac-icon-512@2x.png +0 -0
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/universal-icon-1024@1x.png +0 -0
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/Contents.json +6 -0
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/LargeIcon.imageset/Contents.json +21 -0
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/LargeIcon.imageset/icon128.png +0 -0
- package/dist/safari/Hanzo AI/Shared (App)/Resources/Base.lproj/Main.html +20 -0
- package/dist/safari/Hanzo AI/Shared (App)/Resources/Icon.png +0 -0
- package/dist/safari/Hanzo AI/Shared (App)/Resources/Script.js +24 -0
- package/dist/safari/Hanzo AI/Shared (App)/Resources/Style.css +61 -0
- package/dist/safari/Hanzo AI/Shared (App)/ViewController.swift +81 -0
- package/dist/safari/Hanzo AI/Shared (Extension)/SafariWebExtensionHandler.swift +42 -0
- package/dist/safari/Hanzo AI/iOS (App)/AppDelegate.swift +24 -0
- package/dist/safari/Hanzo AI/iOS (App)/Base.lproj/LaunchScreen.storyboard +36 -0
- package/dist/safari/Hanzo AI/iOS (App)/Base.lproj/Main.storyboard +38 -0
- package/dist/safari/Hanzo AI/iOS (App)/Info.plist +27 -0
- package/dist/safari/Hanzo AI/iOS (App)/SceneDelegate.swift +18 -0
- package/dist/safari/Hanzo AI/iOS (Extension)/Info.plist +13 -0
- package/dist/safari/Hanzo AI/macOS (App)/AppDelegate.swift +21 -0
- package/dist/safari/Hanzo AI/macOS (App)/Base.lproj/Main.storyboard +124 -0
- package/dist/safari/Hanzo AI/macOS (App)/Info.plist +8 -0
- package/dist/safari/Hanzo AI/macOS (Extension)/Info.plist +13 -0
- package/docs/_config.yml +13 -0
- package/docs/_layouts/default.html +435 -0
- package/docs/index.md +54 -0
- package/install-extension.sh +75 -0
- package/manifest.json +29 -0
- package/package.json +32 -0
- package/src/ai-worker.js +571 -0
- package/src/callback.html +17 -0
- package/src/chat-widget.tsx +93 -0
- package/src/icon128.png +0 -0
- package/src/icon16.png +0 -0
- package/src/icon32.png +0 -0
- package/src/icon48.png +0 -0
- package/src/manifest-firefox.json +66 -0
- package/src/manifest.json +57 -0
- package/src/package.json +41 -0
- package/src/popup.css +519 -0
- package/src/popup.html +242 -0
- package/src/popup.js +192 -0
- package/src/sidebar.css +1176 -0
- package/src/sidebar.html +280 -0
- package/src/sidebar.js +884 -0
- package/src/webgpu.d.ts +131 -0
- package/test/claude-integration.test.ts +251 -0
- package/test/server-frameworks-edge-cases.test.ts +145 -0
- package/test/server-frameworks.test.ts +395 -0
- package/test-cdp-connection.js +140 -0
- 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">×</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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
|