@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.
- package/LICENSE +9 -18
- package/dist/browser-extension/content-script.js +1642 -123
- package/images/icon128.png +0 -0
- package/images/icon16.png +0 -0
- package/images/icon48.png +0 -0
- package/manifest.json +7 -2
- package/package.json +28 -10
- package/src/answer/AnswerEngine.tsx +553 -0
- package/src/chat-widget.tsx +96 -0
- package/src/gui-primitives.tsx +116 -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 +32 -13
- package/src/manifest.json +35 -11
- package/src/newtab.css +277 -0
- package/src/newtab.html +13 -0
- package/src/package.json +1 -1
- package/src/popup.css +352 -110
- package/src/popup.html +186 -47
- package/src/popup.js +196 -0
- package/src/sidebar.css +772 -156
- package/src/sidebar.html +268 -85
- package/src/sidebar.js +885 -0
- package/.github/workflows/docs.yml +0 -44
- package/.github/workflows/release.yml +0 -55
- package/README.md +0 -126
- package/dist/browser-extension/README.md +0 -43
- package/dist/browser-extension/ai-worker.js +0 -30
- package/dist/browser-extension/background-firefox.js +0 -875
- package/dist/browser-extension/background.js +0 -2732
- package/dist/browser-extension/browser-control.js +0 -683
- package/dist/browser-extension/cdp-bridge-server.js +0 -444
- package/dist/browser-extension/chrome/ai-worker.js +0 -571
- package/dist/browser-extension/chrome/background.js +0 -2732
- package/dist/browser-extension/chrome/callback.html +0 -17
- package/dist/browser-extension/chrome/content-script.js +0 -1270
- 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 +0 -57
- package/dist/browser-extension/chrome/popup.css +0 -519
- package/dist/browser-extension/chrome/popup.html +0 -242
- package/dist/browser-extension/chrome/popup.js +0 -278
- package/dist/browser-extension/chrome/sidebar.css +0 -1176
- package/dist/browser-extension/chrome/sidebar.html +0 -280
- package/dist/browser-extension/chrome/sidebar.js +0 -779
- package/dist/browser-extension/cli.js +0 -233
- package/dist/browser-extension/firefox/ai-worker.js +0 -571
- package/dist/browser-extension/firefox/background.js +0 -875
- package/dist/browser-extension/firefox/callback.html +0 -17
- package/dist/browser-extension/firefox/content-script.js +0 -1270
- 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 +0 -66
- package/dist/browser-extension/firefox/popup.css +0 -519
- package/dist/browser-extension/firefox/popup.html +0 -242
- package/dist/browser-extension/firefox/popup.js +0 -278
- package/dist/browser-extension/firefox/sidebar.css +0 -1176
- package/dist/browser-extension/firefox/sidebar.html +0 -280
- package/dist/browser-extension/firefox/sidebar.js +0 -779
- 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 +0 -57
- package/dist/browser-extension/package.json +0 -41
- package/dist/browser-extension/popup.css +0 -468
- package/dist/browser-extension/popup.html +0 -191
- package/dist/browser-extension/popup.js +0 -278
- package/dist/browser-extension/safari/Info.plist +0 -21
- package/dist/browser-extension/safari/ai-worker.js +0 -571
- package/dist/browser-extension/safari/background.js +0 -2732
- package/dist/browser-extension/safari/callback.html +0 -17
- package/dist/browser-extension/safari/content-script.js +0 -1270
- 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 +0 -519
- package/dist/browser-extension/safari/popup.html +0 -242
- package/dist/browser-extension/safari/popup.js +0 -278
- package/dist/browser-extension/safari/sidebar.css +0 -1176
- package/dist/browser-extension/safari/sidebar.html +0 -280
- package/dist/browser-extension/safari/sidebar.js +0 -779
- package/dist/browser-extension/sidebar.css +0 -718
- package/dist/browser-extension/sidebar.html +0 -184
- package/dist/browser-extension/sidebar.js +0 -779
- package/dist/browser-extension/webgpu-ai.js +0 -495
- package/dist/cdp-bridge-server.js +0 -411
- package/dist/hanzo-ai-chrome-1.7.2.zip +0 -0
- package/dist/hanzo-ai-chrome-1.7.3.zip +0 -0
- package/dist/hanzo-ai-firefox-1.7.2.zip +0 -0
- package/dist/hanzo-ai-firefox-1.7.3.zip +0 -0
- package/dist/safari/Hanzo AI/Hanzo AI.xcodeproj/project.pbxproj +0 -1047
- package/dist/safari/Hanzo AI/Hanzo AI.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AccentColor.colorset/Contents.json +0 -11
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/AppIcon.appiconset/Contents.json +0 -98
- 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 +0 -6
- package/dist/safari/Hanzo AI/Shared (App)/Assets.xcassets/LargeIcon.imageset/Contents.json +0 -21
- 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 +0 -20
- package/dist/safari/Hanzo AI/Shared (App)/Resources/Icon.png +0 -0
- package/dist/safari/Hanzo AI/Shared (App)/Resources/Script.js +0 -24
- package/dist/safari/Hanzo AI/Shared (App)/Resources/Style.css +0 -61
- package/dist/safari/Hanzo AI/Shared (App)/ViewController.swift +0 -81
- package/dist/safari/Hanzo AI/Shared (Extension)/SafariWebExtensionHandler.swift +0 -42
- package/dist/safari/Hanzo AI/iOS (App)/AppDelegate.swift +0 -24
- package/dist/safari/Hanzo AI/iOS (App)/Base.lproj/LaunchScreen.storyboard +0 -36
- package/dist/safari/Hanzo AI/iOS (App)/Base.lproj/Main.storyboard +0 -38
- package/dist/safari/Hanzo AI/iOS (App)/Info.plist +0 -27
- package/dist/safari/Hanzo AI/iOS (App)/SceneDelegate.swift +0 -18
- package/dist/safari/Hanzo AI/iOS (Extension)/Info.plist +0 -13
- package/dist/safari/Hanzo AI/macOS (App)/AppDelegate.swift +0 -21
- package/dist/safari/Hanzo AI/macOS (App)/Base.lproj/Main.storyboard +0 -124
- package/dist/safari/Hanzo AI/macOS (App)/Info.plist +0 -8
- package/dist/safari/Hanzo AI/macOS (Extension)/Info.plist +0 -13
- package/docs/_config.yml +0 -13
- package/docs/_layouts/default.html +0 -435
- package/docs/index.md +0 -54
- package/hanzo-ai-chrome-v1.7.6.zip +0 -0
- package/hanzo-ai-firefox-v1.7.6.zip +0 -0
- package/install-extension.sh +0 -75
- package/test/claude-integration.test.ts +0 -251
- package/test/server-frameworks-edge-cases.test.ts +0 -145
- package/test/server-frameworks.test.ts +0 -395
- package/test-cdp-connection.js +0 -140
- 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">×</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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
|