@tscircuit/cli 0.1.4 → 0.1.5
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/biome.json +1 -0
- package/bun.lockb +0 -0
- package/cli/dev/DevServer.ts +155 -0
- package/cli/dev/register.ts +9 -82
- package/dist/main.js +225 -232
- package/lib/dependency-analysis/{installNodeModuleTypes.ts → installNodeModuleTypesForSnippet.ts} +1 -1
- package/lib/file-server/FileServerEvent.ts +7 -0
- package/lib/file-server/FileServerRoutes.ts +38 -0
- package/lib/index.ts +1 -1
- package/lib/server/{createServer.ts → createHttpServer.ts} +3 -3
- package/package.json +7 -4
- package/tests/fixtures/get-test-fixture.ts +25 -0
- package/tests/test1-dev-server-basic.test.ts +40 -0
- package/tsconfig.json +2 -1
package/biome.json
CHANGED
package/bun.lockb
CHANGED
|
Binary file
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import ky from "ky"
|
|
2
|
+
import type { FileServerRoutes } from "lib/file-server/FileServerRoutes"
|
|
3
|
+
import { createHttpServer } from "lib/server/createHttpServer"
|
|
4
|
+
import { EventsWatcher } from "lib/server/EventsWatcher"
|
|
5
|
+
import type http from "node:http"
|
|
6
|
+
import type { TypedKyInstance } from "typed-ky"
|
|
7
|
+
import path from "node:path"
|
|
8
|
+
import fs from "node:fs"
|
|
9
|
+
import type { FileUpdatedEvent } from "lib/file-server/FileServerEvent"
|
|
10
|
+
import * as chokidar from "chokidar"
|
|
11
|
+
|
|
12
|
+
export class DevServer {
|
|
13
|
+
port: number
|
|
14
|
+
/**
|
|
15
|
+
* The path to a component that exports a <board /> or <group /> component
|
|
16
|
+
*/
|
|
17
|
+
componentFilePath: string
|
|
18
|
+
|
|
19
|
+
projectDir: string
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The HTTP server that hosts the file server and event bus. You can use
|
|
23
|
+
* fsKy to communicate with the file server/event bus
|
|
24
|
+
*/
|
|
25
|
+
httpServer?: http.Server
|
|
26
|
+
/**
|
|
27
|
+
* Watches for events on the event bus by polling `api/events/list`
|
|
28
|
+
*/
|
|
29
|
+
eventsWatcher?: EventsWatcher
|
|
30
|
+
/**
|
|
31
|
+
* A ky instance that can be used to communicate with the file server and
|
|
32
|
+
* event bus
|
|
33
|
+
*/
|
|
34
|
+
fsKy: TypedKyInstance<keyof FileServerRoutes, FileServerRoutes>
|
|
35
|
+
/**
|
|
36
|
+
* A chokidar instance that watches the project directory for file changes
|
|
37
|
+
*/
|
|
38
|
+
filesystemWatcher?: chokidar.FSWatcher
|
|
39
|
+
|
|
40
|
+
constructor({
|
|
41
|
+
port,
|
|
42
|
+
componentFilePath,
|
|
43
|
+
}: {
|
|
44
|
+
port: number
|
|
45
|
+
componentFilePath: string
|
|
46
|
+
}) {
|
|
47
|
+
this.port = port
|
|
48
|
+
this.componentFilePath = componentFilePath
|
|
49
|
+
this.projectDir = path.dirname(componentFilePath)
|
|
50
|
+
this.fsKy = ky.create({
|
|
51
|
+
prefixUrl: `http://localhost:${port}`,
|
|
52
|
+
}) as any
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async start() {
|
|
56
|
+
const { server } = await createHttpServer(this.port)
|
|
57
|
+
this.httpServer = server
|
|
58
|
+
|
|
59
|
+
this.eventsWatcher = new EventsWatcher(`http://localhost:${this.port}`)
|
|
60
|
+
this.eventsWatcher.start()
|
|
61
|
+
|
|
62
|
+
this.eventsWatcher.on(
|
|
63
|
+
"FILE_UPDATED",
|
|
64
|
+
this.handleFileUpdatedEventFromServer.bind(this),
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
this.filesystemWatcher = chokidar.watch(this.projectDir, {
|
|
68
|
+
persistent: true,
|
|
69
|
+
ignoreInitial: true,
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
this.filesystemWatcher.on("change", (filePath) =>
|
|
73
|
+
this.handleFileChangedOnFilesystem(filePath),
|
|
74
|
+
)
|
|
75
|
+
this.filesystemWatcher.on("add", (filePath) =>
|
|
76
|
+
this.handleFileChangedOnFilesystem(filePath),
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
this.upsertInitialFiles()
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async addEntrypoint() {
|
|
83
|
+
const relativeComponentFilePath = path.relative(
|
|
84
|
+
this.projectDir,
|
|
85
|
+
this.componentFilePath,
|
|
86
|
+
)
|
|
87
|
+
await this.fsKy.post("api/files/upsert", {
|
|
88
|
+
json: {
|
|
89
|
+
file_path: "entrypoint.tsx",
|
|
90
|
+
text_content: `
|
|
91
|
+
import MyCircuit from "./${relativeComponentFilePath}"
|
|
92
|
+
|
|
93
|
+
circuit.add(<MyCircuit />)
|
|
94
|
+
`,
|
|
95
|
+
},
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async handleFileUpdatedEventFromServer(ev: FileUpdatedEvent) {
|
|
100
|
+
if (ev.initiator === "filesystem_change") return
|
|
101
|
+
|
|
102
|
+
if (ev.file_path === "manual-edits.json") {
|
|
103
|
+
console.log("Manual edits updated, updating on filesystem...")
|
|
104
|
+
const { file } = await this.fsKy
|
|
105
|
+
.get("api/files/get", {
|
|
106
|
+
searchParams: { file_path: ev.file_path },
|
|
107
|
+
})
|
|
108
|
+
.json()
|
|
109
|
+
fs.writeFileSync(
|
|
110
|
+
path.join(this.projectDir, "manual-edits.json"),
|
|
111
|
+
file.text_content,
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async handleFileChangedOnFilesystem(absoluteFilePath: string) {
|
|
117
|
+
const relativeFilePath = path.relative(this.projectDir, absoluteFilePath)
|
|
118
|
+
|
|
119
|
+
// We've temporarily disabled upserting manual edits from filesystem changes
|
|
120
|
+
// because it can be edited by the browser
|
|
121
|
+
if (relativeFilePath.includes("manual-edits.json")) return
|
|
122
|
+
|
|
123
|
+
await this.fsKy
|
|
124
|
+
.post("api/files/upsert", {
|
|
125
|
+
json: {
|
|
126
|
+
file_path: relativeFilePath,
|
|
127
|
+
text_content: fs.readFileSync(absoluteFilePath, "utf-8"),
|
|
128
|
+
initiator: "filesystem_change",
|
|
129
|
+
},
|
|
130
|
+
})
|
|
131
|
+
.json()
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async upsertInitialFiles() {
|
|
135
|
+
// Scan project directory for all files and upsert them
|
|
136
|
+
const fileNames = fs.readdirSync(this.projectDir)
|
|
137
|
+
for (const fileName of fileNames) {
|
|
138
|
+
await this.fsKy.post("api/files/upsert", {
|
|
139
|
+
json: {
|
|
140
|
+
file_path: fileName,
|
|
141
|
+
text_content: fs.readFileSync(
|
|
142
|
+
path.join(this.projectDir, fileName),
|
|
143
|
+
"utf-8",
|
|
144
|
+
),
|
|
145
|
+
initiator: "filesystem_change",
|
|
146
|
+
},
|
|
147
|
+
})
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async stop() {
|
|
152
|
+
this.httpServer?.close()
|
|
153
|
+
this.eventsWatcher?.stop()
|
|
154
|
+
}
|
|
155
|
+
}
|
package/cli/dev/register.ts
CHANGED
|
@@ -2,10 +2,11 @@ import type { Command } from "commander"
|
|
|
2
2
|
import * as path from "node:path"
|
|
3
3
|
import * as chokidar from "chokidar"
|
|
4
4
|
import * as fs from "node:fs"
|
|
5
|
-
import {
|
|
5
|
+
import { createHttpServer } from "lib/server/createHttpServer"
|
|
6
6
|
import { getLocalFileDependencies } from "lib/dependency-analysis/getLocalFileDependencies"
|
|
7
|
-
import {
|
|
7
|
+
import { installNodeModuleTypesForSnippet } from "../../lib/dependency-analysis/installNodeModuleTypesForSnippet"
|
|
8
8
|
import { EventsWatcher } from "../../lib/server/EventsWatcher"
|
|
9
|
+
import { DevServer } from "./DevServer"
|
|
9
10
|
|
|
10
11
|
export const registerDev = (program: Command) => {
|
|
11
12
|
program
|
|
@@ -20,92 +21,18 @@ export const registerDev = (program: Command) => {
|
|
|
20
21
|
|
|
21
22
|
try {
|
|
22
23
|
console.log("Installing types for imported snippets...")
|
|
23
|
-
await
|
|
24
|
+
await installNodeModuleTypesForSnippet(absolutePath)
|
|
24
25
|
console.log("Types installed successfully")
|
|
25
26
|
} catch (error) {
|
|
26
27
|
console.warn("Failed to install types:", error)
|
|
27
28
|
}
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const eventsWatcher = new EventsWatcher(`http://localhost:${port}`)
|
|
33
|
-
eventsWatcher.start()
|
|
34
|
-
|
|
35
|
-
await fetch(`http://localhost:${port}/api/files/upsert`, {
|
|
36
|
-
method: "POST",
|
|
37
|
-
headers: { "Content-Type": "application/json" },
|
|
38
|
-
body: JSON.stringify({
|
|
39
|
-
file_path: "entrypoint.tsx",
|
|
40
|
-
text_content: `
|
|
41
|
-
import MyCircuit from "./snippet.tsx"
|
|
42
|
-
|
|
43
|
-
circuit.add(<MyCircuit />)
|
|
44
|
-
`,
|
|
45
|
-
}),
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
// Function to update file content
|
|
49
|
-
const updateFile = async (filePath: string) => {
|
|
50
|
-
try {
|
|
51
|
-
const content = await fs.promises.readFile(filePath, "utf-8")
|
|
52
|
-
const response = await fetch(
|
|
53
|
-
`http://localhost:${port}/api/files/upsert`,
|
|
54
|
-
{
|
|
55
|
-
method: "POST",
|
|
56
|
-
headers: { "Content-Type": "application/json" },
|
|
57
|
-
body: JSON.stringify({
|
|
58
|
-
file_path: path.relative(fileDir, filePath),
|
|
59
|
-
text_content: content,
|
|
60
|
-
}),
|
|
61
|
-
},
|
|
62
|
-
)
|
|
63
|
-
if (!response.ok) {
|
|
64
|
-
console.error(`Failed to update ${filePath}`)
|
|
65
|
-
}
|
|
66
|
-
} catch (error) {
|
|
67
|
-
console.error(`Error updating ${filePath}:`, error)
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Get initial dependencies
|
|
72
|
-
const dependencies = new Set([absolutePath])
|
|
73
|
-
try {
|
|
74
|
-
const deps = getLocalFileDependencies(absolutePath)
|
|
75
|
-
deps.forEach((dep) => dependencies.add(dep))
|
|
76
|
-
} catch (error) {
|
|
77
|
-
console.warn("Failed to analyze dependencies:", error)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Watch the main file and its dependencies
|
|
81
|
-
const filesystemWatcher = chokidar.watch(Array.from(dependencies), {
|
|
82
|
-
persistent: true,
|
|
83
|
-
ignoreInitial: false,
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
filesystemWatcher.on("change", async (filePath) => {
|
|
87
|
-
console.log(`File ${filePath} changed`)
|
|
88
|
-
await updateFile(filePath)
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
filesystemWatcher.on("add", async (filePath) => {
|
|
92
|
-
console.log(`File ${filePath} added`)
|
|
93
|
-
await updateFile(filePath)
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
eventsWatcher.on("FILE_UPDATED", async (ev) => {
|
|
97
|
-
if (ev.file_path === "manual-edits.json") {
|
|
98
|
-
console.log("Manual edits updated, updating on filesystem...")
|
|
99
|
-
const { file } = await fetch(
|
|
100
|
-
`http://localhost:${port}/api/files/get?file_path=manual-edits.json`,
|
|
101
|
-
).then((r) => r.json())
|
|
102
|
-
fs.writeFileSync(
|
|
103
|
-
path.join(fileDir, "manual-edits.json"),
|
|
104
|
-
file.text_content,
|
|
105
|
-
)
|
|
106
|
-
}
|
|
30
|
+
const server = new DevServer({
|
|
31
|
+
port,
|
|
32
|
+
componentFilePath: absolutePath,
|
|
107
33
|
})
|
|
108
34
|
|
|
109
|
-
|
|
35
|
+
await server.start()
|
|
36
|
+
await server.addEntrypoint()
|
|
110
37
|
})
|
|
111
38
|
}
|
package/dist/main.js
CHANGED
|
@@ -5,13 +5,74 @@ import { Command } from "commander";
|
|
|
5
5
|
|
|
6
6
|
// cli/dev/register.ts
|
|
7
7
|
import * as path4 from "node:path";
|
|
8
|
-
import * as chokidar from "chokidar";
|
|
9
|
-
import * as fs4 from "node:fs";
|
|
10
8
|
|
|
11
|
-
// lib/
|
|
12
|
-
import * as http from "node:http";
|
|
9
|
+
// lib/dependency-analysis/installNodeModuleTypesForSnippet.ts
|
|
13
10
|
import * as fs from "node:fs";
|
|
14
11
|
import * as path from "node:path";
|
|
12
|
+
import * as ts from "typescript";
|
|
13
|
+
async function installNodeModuleTypesForSnippet(snippetPath) {
|
|
14
|
+
const content = fs.readFileSync(snippetPath, "utf-8");
|
|
15
|
+
const sourceFile = ts.createSourceFile(
|
|
16
|
+
snippetPath,
|
|
17
|
+
content,
|
|
18
|
+
ts.ScriptTarget.Latest,
|
|
19
|
+
true
|
|
20
|
+
);
|
|
21
|
+
const imports = [];
|
|
22
|
+
function visit(node) {
|
|
23
|
+
if (ts.isImportDeclaration(node)) {
|
|
24
|
+
const moduleSpecifier = node.moduleSpecifier;
|
|
25
|
+
if (moduleSpecifier && ts.isStringLiteral(moduleSpecifier)) {
|
|
26
|
+
const importPath = moduleSpecifier.text;
|
|
27
|
+
if (importPath.startsWith("@tsci/")) {
|
|
28
|
+
imports.push(importPath);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
ts.forEachChild(node, visit);
|
|
33
|
+
}
|
|
34
|
+
visit(sourceFile);
|
|
35
|
+
let projectRoot = path.dirname(snippetPath);
|
|
36
|
+
while (projectRoot !== path.parse(projectRoot).root) {
|
|
37
|
+
if (fs.existsSync(path.join(projectRoot, "package.json"))) {
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
projectRoot = path.dirname(projectRoot);
|
|
41
|
+
}
|
|
42
|
+
for (const importPath of imports) {
|
|
43
|
+
const [owner, name] = importPath.replace("@tsci/", "").split(".");
|
|
44
|
+
try {
|
|
45
|
+
const response = await fetch(
|
|
46
|
+
`https://registry-api.tscircuit.com/snippets/get?owner_name=${owner}&unscoped_name=${name}`
|
|
47
|
+
);
|
|
48
|
+
if (!response.ok) {
|
|
49
|
+
console.warn(`Failed to fetch types for ${importPath}`);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
const data = await response.json();
|
|
53
|
+
if (data.snippet.dts) {
|
|
54
|
+
const packageDir = path.join(
|
|
55
|
+
projectRoot,
|
|
56
|
+
"node_modules",
|
|
57
|
+
"@tsci",
|
|
58
|
+
`${owner}.${name}`
|
|
59
|
+
);
|
|
60
|
+
fs.mkdirSync(packageDir, { recursive: true });
|
|
61
|
+
fs.writeFileSync(path.join(packageDir, "index.d.ts"), data.snippet.dts);
|
|
62
|
+
}
|
|
63
|
+
} catch (error) {
|
|
64
|
+
console.warn(`Error fetching types for ${importPath}:`, error);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// cli/dev/DevServer.ts
|
|
70
|
+
import ky from "ky";
|
|
71
|
+
|
|
72
|
+
// lib/server/createHttpServer.ts
|
|
73
|
+
import * as http from "node:http";
|
|
74
|
+
import * as fs2 from "node:fs";
|
|
75
|
+
import * as path2 from "node:path";
|
|
15
76
|
import { getNodeHandler } from "winterspec/adapters/node";
|
|
16
77
|
|
|
17
78
|
// package.json
|
|
@@ -19,7 +80,7 @@ var package_default = {
|
|
|
19
80
|
name: "@tscircuit/cli",
|
|
20
81
|
main: "dist/main.js",
|
|
21
82
|
type: "module",
|
|
22
|
-
version: "0.1.
|
|
83
|
+
version: "0.1.4",
|
|
23
84
|
bin: {
|
|
24
85
|
tsci: "./dist/main.js"
|
|
25
86
|
},
|
|
@@ -34,16 +95,19 @@ var package_default = {
|
|
|
34
95
|
devDependencies: {
|
|
35
96
|
"@biomejs/biome": "^1.9.4",
|
|
36
97
|
"@tscircuit/core": "^0.0.249",
|
|
37
|
-
"@types/bun": "
|
|
98
|
+
"@types/bun": "^1.1.15",
|
|
38
99
|
"@types/configstore": "^6.0.2",
|
|
39
100
|
"@types/react": "^19.0.1",
|
|
40
|
-
|
|
101
|
+
"get-port": "^7.1.0",
|
|
102
|
+
tempy: "^3.1.0",
|
|
103
|
+
tsup: "^8.3.5",
|
|
104
|
+
"typed-ky": "^0.0.4"
|
|
41
105
|
},
|
|
42
106
|
peerDependencies: {
|
|
43
107
|
typescript: "^5.0.0"
|
|
44
108
|
},
|
|
45
109
|
dependencies: {
|
|
46
|
-
"@tscircuit/file-server": "^0.0.
|
|
110
|
+
"@tscircuit/file-server": "^0.0.13",
|
|
47
111
|
"@tscircuit/runframe": "^0.0.47",
|
|
48
112
|
chokidar: "^4.0.1",
|
|
49
113
|
commander: "^12.1.0",
|
|
@@ -55,7 +119,7 @@ var package_default = {
|
|
|
55
119
|
}
|
|
56
120
|
};
|
|
57
121
|
|
|
58
|
-
// lib/server/
|
|
122
|
+
// lib/server/createHttpServer.ts
|
|
59
123
|
import winterspecBundle from "@tscircuit/file-server/dist/bundle.js";
|
|
60
124
|
|
|
61
125
|
// lib/site/getIndex.ts
|
|
@@ -74,19 +138,19 @@ var getIndex = async () => {
|
|
|
74
138
|
</html>`;
|
|
75
139
|
};
|
|
76
140
|
|
|
77
|
-
// lib/server/
|
|
78
|
-
var
|
|
141
|
+
// lib/server/createHttpServer.ts
|
|
142
|
+
var createHttpServer = async (port = 3e3) => {
|
|
79
143
|
const fileServerHandler = getNodeHandler(winterspecBundle, {});
|
|
80
144
|
const server = http.createServer(async (req, res) => {
|
|
81
145
|
const url = new URL(req.url, `http://${req.headers.host}`);
|
|
82
146
|
if (url.pathname === "/standalone.min.js") {
|
|
83
|
-
const standaloneFilePath = process.env.RUNFRAME_STANDALONE_FILE_PATH ||
|
|
147
|
+
const standaloneFilePath = process.env.RUNFRAME_STANDALONE_FILE_PATH || path2.resolve(
|
|
84
148
|
process.cwd(),
|
|
85
149
|
"node_modules",
|
|
86
150
|
"@tscircuit/runframe/dist/standalone.min.js"
|
|
87
151
|
);
|
|
88
152
|
try {
|
|
89
|
-
const content =
|
|
153
|
+
const content = fs2.readFileSync(standaloneFilePath, "utf8");
|
|
90
154
|
res.writeHead(200, {
|
|
91
155
|
"Content-Type": "application/javascript; charset=utf-8"
|
|
92
156
|
});
|
|
@@ -115,147 +179,14 @@ var createServer2 = async (port = 3e3) => {
|
|
|
115
179
|
res.writeHead(404);
|
|
116
180
|
res.end("Not found");
|
|
117
181
|
});
|
|
118
|
-
return new Promise((
|
|
182
|
+
return new Promise((resolve3) => {
|
|
119
183
|
server.listen(port, () => {
|
|
120
184
|
console.log(`Server running at http://localhost:${port}`);
|
|
121
|
-
|
|
185
|
+
resolve3({ server });
|
|
122
186
|
});
|
|
123
187
|
});
|
|
124
188
|
};
|
|
125
189
|
|
|
126
|
-
// lib/dependency-analysis/getLocalFileDependencies.ts
|
|
127
|
-
import * as ts from "typescript";
|
|
128
|
-
import * as path2 from "path";
|
|
129
|
-
import * as fs2 from "fs";
|
|
130
|
-
function getLocalFileDependencies(pathToTsxFile) {
|
|
131
|
-
const absolutePath = path2.resolve(pathToTsxFile);
|
|
132
|
-
const baseDir = path2.dirname(absolutePath);
|
|
133
|
-
const content = fs2.readFileSync(absolutePath, "utf-8");
|
|
134
|
-
const sourceFile = ts.createSourceFile(
|
|
135
|
-
absolutePath,
|
|
136
|
-
content,
|
|
137
|
-
ts.ScriptTarget.Latest,
|
|
138
|
-
true
|
|
139
|
-
);
|
|
140
|
-
const dependencies = /* @__PURE__ */ new Set();
|
|
141
|
-
function visit(node) {
|
|
142
|
-
if (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) {
|
|
143
|
-
const moduleSpecifier = node.moduleSpecifier;
|
|
144
|
-
if (moduleSpecifier && ts.isStringLiteral(moduleSpecifier)) {
|
|
145
|
-
const importPath = moduleSpecifier.text;
|
|
146
|
-
if (importPath.startsWith(".")) {
|
|
147
|
-
resolveAndAddDependency(importPath);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
if (ts.isCallExpression(node) && node.expression.kind === ts.SyntaxKind.ImportKeyword) {
|
|
152
|
-
const argument = node.arguments[0];
|
|
153
|
-
if (argument && ts.isStringLiteral(argument)) {
|
|
154
|
-
const importPath = argument.text;
|
|
155
|
-
if (importPath.startsWith(".")) {
|
|
156
|
-
resolveAndAddDependency(importPath);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
ts.forEachChild(node, visit);
|
|
161
|
-
}
|
|
162
|
-
function resolveAndAddDependency(importPath) {
|
|
163
|
-
const extensions = [
|
|
164
|
-
".tsx",
|
|
165
|
-
".ts",
|
|
166
|
-
".jsx",
|
|
167
|
-
".js",
|
|
168
|
-
".css",
|
|
169
|
-
".scss",
|
|
170
|
-
".sass",
|
|
171
|
-
".less"
|
|
172
|
-
];
|
|
173
|
-
let resolvedPath = path2.resolve(baseDir, importPath);
|
|
174
|
-
if (fs2.existsSync(resolvedPath)) {
|
|
175
|
-
dependencies.add(resolvedPath);
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
for (const ext of extensions) {
|
|
179
|
-
const pathWithExt = resolvedPath + ext;
|
|
180
|
-
if (fs2.existsSync(pathWithExt)) {
|
|
181
|
-
dependencies.add(pathWithExt);
|
|
182
|
-
return;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
if (fs2.existsSync(resolvedPath) && fs2.statSync(resolvedPath).isDirectory()) {
|
|
186
|
-
for (const ext of extensions) {
|
|
187
|
-
const indexPath = path2.join(resolvedPath, `index${ext}`);
|
|
188
|
-
if (fs2.existsSync(indexPath)) {
|
|
189
|
-
dependencies.add(indexPath);
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
visit(sourceFile);
|
|
196
|
-
return Array.from(dependencies);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// lib/dependency-analysis/installNodeModuleTypes.ts
|
|
200
|
-
import * as fs3 from "node:fs";
|
|
201
|
-
import * as path3 from "node:path";
|
|
202
|
-
import * as ts2 from "typescript";
|
|
203
|
-
async function installTypes(snippetPath) {
|
|
204
|
-
const content = fs3.readFileSync(snippetPath, "utf-8");
|
|
205
|
-
const sourceFile = ts2.createSourceFile(
|
|
206
|
-
snippetPath,
|
|
207
|
-
content,
|
|
208
|
-
ts2.ScriptTarget.Latest,
|
|
209
|
-
true
|
|
210
|
-
);
|
|
211
|
-
const imports = [];
|
|
212
|
-
function visit(node) {
|
|
213
|
-
if (ts2.isImportDeclaration(node)) {
|
|
214
|
-
const moduleSpecifier = node.moduleSpecifier;
|
|
215
|
-
if (moduleSpecifier && ts2.isStringLiteral(moduleSpecifier)) {
|
|
216
|
-
const importPath = moduleSpecifier.text;
|
|
217
|
-
if (importPath.startsWith("@tsci/")) {
|
|
218
|
-
imports.push(importPath);
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
ts2.forEachChild(node, visit);
|
|
223
|
-
}
|
|
224
|
-
visit(sourceFile);
|
|
225
|
-
let projectRoot = path3.dirname(snippetPath);
|
|
226
|
-
while (projectRoot !== path3.parse(projectRoot).root) {
|
|
227
|
-
if (fs3.existsSync(path3.join(projectRoot, "package.json"))) {
|
|
228
|
-
break;
|
|
229
|
-
}
|
|
230
|
-
projectRoot = path3.dirname(projectRoot);
|
|
231
|
-
}
|
|
232
|
-
for (const importPath of imports) {
|
|
233
|
-
const [owner, name] = importPath.replace("@tsci/", "").split(".");
|
|
234
|
-
try {
|
|
235
|
-
const response = await fetch(
|
|
236
|
-
`https://registry-api.tscircuit.com/snippets/get?owner_name=${owner}&unscoped_name=${name}`
|
|
237
|
-
);
|
|
238
|
-
if (!response.ok) {
|
|
239
|
-
console.warn(`Failed to fetch types for ${importPath}`);
|
|
240
|
-
continue;
|
|
241
|
-
}
|
|
242
|
-
const data = await response.json();
|
|
243
|
-
if (data.snippet.dts) {
|
|
244
|
-
const packageDir = path3.join(
|
|
245
|
-
projectRoot,
|
|
246
|
-
"node_modules",
|
|
247
|
-
"@tsci",
|
|
248
|
-
`${owner}.${name}`
|
|
249
|
-
);
|
|
250
|
-
fs3.mkdirSync(packageDir, { recursive: true });
|
|
251
|
-
fs3.writeFileSync(path3.join(packageDir, "index.d.ts"), data.snippet.dts);
|
|
252
|
-
}
|
|
253
|
-
} catch (error) {
|
|
254
|
-
console.warn(`Error fetching types for ${importPath}:`, error);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
190
|
// lib/server/EventsWatcher.ts
|
|
260
191
|
import { EventEmitter } from "events";
|
|
261
192
|
var EventsWatcher = class extends EventEmitter {
|
|
@@ -307,6 +238,130 @@ var EventsWatcher = class extends EventEmitter {
|
|
|
307
238
|
}
|
|
308
239
|
};
|
|
309
240
|
|
|
241
|
+
// cli/dev/DevServer.ts
|
|
242
|
+
import path3 from "node:path";
|
|
243
|
+
import fs3 from "node:fs";
|
|
244
|
+
import * as chokidar from "chokidar";
|
|
245
|
+
var DevServer = class {
|
|
246
|
+
port;
|
|
247
|
+
/**
|
|
248
|
+
* The path to a component that exports a <board /> or <group /> component
|
|
249
|
+
*/
|
|
250
|
+
componentFilePath;
|
|
251
|
+
projectDir;
|
|
252
|
+
/**
|
|
253
|
+
* The HTTP server that hosts the file server and event bus. You can use
|
|
254
|
+
* fsKy to communicate with the file server/event bus
|
|
255
|
+
*/
|
|
256
|
+
httpServer;
|
|
257
|
+
/**
|
|
258
|
+
* Watches for events on the event bus by polling `api/events/list`
|
|
259
|
+
*/
|
|
260
|
+
eventsWatcher;
|
|
261
|
+
/**
|
|
262
|
+
* A ky instance that can be used to communicate with the file server and
|
|
263
|
+
* event bus
|
|
264
|
+
*/
|
|
265
|
+
fsKy;
|
|
266
|
+
/**
|
|
267
|
+
* A chokidar instance that watches the project directory for file changes
|
|
268
|
+
*/
|
|
269
|
+
filesystemWatcher;
|
|
270
|
+
constructor({
|
|
271
|
+
port,
|
|
272
|
+
componentFilePath
|
|
273
|
+
}) {
|
|
274
|
+
this.port = port;
|
|
275
|
+
this.componentFilePath = componentFilePath;
|
|
276
|
+
this.projectDir = path3.dirname(componentFilePath);
|
|
277
|
+
this.fsKy = ky.create({
|
|
278
|
+
prefixUrl: `http://localhost:${port}`
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
async start() {
|
|
282
|
+
const { server } = await createHttpServer(this.port);
|
|
283
|
+
this.httpServer = server;
|
|
284
|
+
this.eventsWatcher = new EventsWatcher(`http://localhost:${this.port}`);
|
|
285
|
+
this.eventsWatcher.start();
|
|
286
|
+
this.eventsWatcher.on(
|
|
287
|
+
"FILE_UPDATED",
|
|
288
|
+
this.handleFileUpdatedEventFromServer.bind(this)
|
|
289
|
+
);
|
|
290
|
+
this.filesystemWatcher = chokidar.watch(this.projectDir, {
|
|
291
|
+
persistent: true,
|
|
292
|
+
ignoreInitial: true
|
|
293
|
+
});
|
|
294
|
+
this.filesystemWatcher.on(
|
|
295
|
+
"change",
|
|
296
|
+
(filePath) => this.handleFileChangedOnFilesystem(filePath)
|
|
297
|
+
);
|
|
298
|
+
this.filesystemWatcher.on(
|
|
299
|
+
"add",
|
|
300
|
+
(filePath) => this.handleFileChangedOnFilesystem(filePath)
|
|
301
|
+
);
|
|
302
|
+
this.upsertInitialFiles();
|
|
303
|
+
}
|
|
304
|
+
async addEntrypoint() {
|
|
305
|
+
const relativeComponentFilePath = path3.relative(
|
|
306
|
+
this.projectDir,
|
|
307
|
+
this.componentFilePath
|
|
308
|
+
);
|
|
309
|
+
await this.fsKy.post("api/files/upsert", {
|
|
310
|
+
json: {
|
|
311
|
+
file_path: "entrypoint.tsx",
|
|
312
|
+
text_content: `
|
|
313
|
+
import MyCircuit from "./${relativeComponentFilePath}"
|
|
314
|
+
|
|
315
|
+
circuit.add(<MyCircuit />)
|
|
316
|
+
`
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
async handleFileUpdatedEventFromServer(ev) {
|
|
321
|
+
if (ev.initiator === "filesystem_change") return;
|
|
322
|
+
if (ev.file_path === "manual-edits.json") {
|
|
323
|
+
console.log("Manual edits updated, updating on filesystem...");
|
|
324
|
+
const { file } = await this.fsKy.get("api/files/get", {
|
|
325
|
+
searchParams: { file_path: ev.file_path }
|
|
326
|
+
}).json();
|
|
327
|
+
fs3.writeFileSync(
|
|
328
|
+
path3.join(this.projectDir, "manual-edits.json"),
|
|
329
|
+
file.text_content
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
async handleFileChangedOnFilesystem(absoluteFilePath) {
|
|
334
|
+
const relativeFilePath = path3.relative(this.projectDir, absoluteFilePath);
|
|
335
|
+
if (relativeFilePath.includes("manual-edits.json")) return;
|
|
336
|
+
await this.fsKy.post("api/files/upsert", {
|
|
337
|
+
json: {
|
|
338
|
+
file_path: relativeFilePath,
|
|
339
|
+
text_content: fs3.readFileSync(absoluteFilePath, "utf-8"),
|
|
340
|
+
initiator: "filesystem_change"
|
|
341
|
+
}
|
|
342
|
+
}).json();
|
|
343
|
+
}
|
|
344
|
+
async upsertInitialFiles() {
|
|
345
|
+
const fileNames = fs3.readdirSync(this.projectDir);
|
|
346
|
+
for (const fileName of fileNames) {
|
|
347
|
+
await this.fsKy.post("api/files/upsert", {
|
|
348
|
+
json: {
|
|
349
|
+
file_path: fileName,
|
|
350
|
+
text_content: fs3.readFileSync(
|
|
351
|
+
path3.join(this.projectDir, fileName),
|
|
352
|
+
"utf-8"
|
|
353
|
+
),
|
|
354
|
+
initiator: "filesystem_change"
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
async stop() {
|
|
360
|
+
this.httpServer?.close();
|
|
361
|
+
this.eventsWatcher?.stop();
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
|
|
310
365
|
// cli/dev/register.ts
|
|
311
366
|
var registerDev = (program2) => {
|
|
312
367
|
program2.command("dev").description("Start development server for a snippet").argument("<file>", "Path to the snippet file").option("-p, --port <number>", "Port to run server on", "3000").action(async (file, options) => {
|
|
@@ -315,79 +370,17 @@ var registerDev = (program2) => {
|
|
|
315
370
|
const port = parseInt(options.port);
|
|
316
371
|
try {
|
|
317
372
|
console.log("Installing types for imported snippets...");
|
|
318
|
-
await
|
|
373
|
+
await installNodeModuleTypesForSnippet(absolutePath);
|
|
319
374
|
console.log("Types installed successfully");
|
|
320
375
|
} catch (error) {
|
|
321
376
|
console.warn("Failed to install types:", error);
|
|
322
377
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
await fetch(`http://localhost:${port}/api/files/upsert`, {
|
|
327
|
-
method: "POST",
|
|
328
|
-
headers: { "Content-Type": "application/json" },
|
|
329
|
-
body: JSON.stringify({
|
|
330
|
-
file_path: "entrypoint.tsx",
|
|
331
|
-
text_content: `
|
|
332
|
-
import MyCircuit from "./snippet.tsx"
|
|
333
|
-
|
|
334
|
-
circuit.add(<MyCircuit />)
|
|
335
|
-
`
|
|
336
|
-
})
|
|
337
|
-
});
|
|
338
|
-
const updateFile = async (filePath) => {
|
|
339
|
-
try {
|
|
340
|
-
const content = await fs4.promises.readFile(filePath, "utf-8");
|
|
341
|
-
const response = await fetch(
|
|
342
|
-
`http://localhost:${port}/api/files/upsert`,
|
|
343
|
-
{
|
|
344
|
-
method: "POST",
|
|
345
|
-
headers: { "Content-Type": "application/json" },
|
|
346
|
-
body: JSON.stringify({
|
|
347
|
-
file_path: path4.relative(fileDir, filePath),
|
|
348
|
-
text_content: content
|
|
349
|
-
})
|
|
350
|
-
}
|
|
351
|
-
);
|
|
352
|
-
if (!response.ok) {
|
|
353
|
-
console.error(`Failed to update ${filePath}`);
|
|
354
|
-
}
|
|
355
|
-
} catch (error) {
|
|
356
|
-
console.error(`Error updating ${filePath}:`, error);
|
|
357
|
-
}
|
|
358
|
-
};
|
|
359
|
-
const dependencies = /* @__PURE__ */ new Set([absolutePath]);
|
|
360
|
-
try {
|
|
361
|
-
const deps = getLocalFileDependencies(absolutePath);
|
|
362
|
-
deps.forEach((dep) => dependencies.add(dep));
|
|
363
|
-
} catch (error) {
|
|
364
|
-
console.warn("Failed to analyze dependencies:", error);
|
|
365
|
-
}
|
|
366
|
-
const filesystemWatcher = chokidar.watch(Array.from(dependencies), {
|
|
367
|
-
persistent: true,
|
|
368
|
-
ignoreInitial: false
|
|
369
|
-
});
|
|
370
|
-
filesystemWatcher.on("change", async (filePath) => {
|
|
371
|
-
console.log(`File ${filePath} changed`);
|
|
372
|
-
await updateFile(filePath);
|
|
373
|
-
});
|
|
374
|
-
filesystemWatcher.on("add", async (filePath) => {
|
|
375
|
-
console.log(`File ${filePath} added`);
|
|
376
|
-
await updateFile(filePath);
|
|
378
|
+
const server = new DevServer({
|
|
379
|
+
port,
|
|
380
|
+
componentFilePath: absolutePath
|
|
377
381
|
});
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
console.log("Manual edits updated, updating on filesystem...");
|
|
381
|
-
const { file: file2 } = await fetch(
|
|
382
|
-
`http://localhost:${port}/api/files/get?file_path=manual-edits.json`
|
|
383
|
-
).then((r) => r.json());
|
|
384
|
-
fs4.writeFileSync(
|
|
385
|
-
path4.join(fileDir, "manual-edits.json"),
|
|
386
|
-
file2.text_content
|
|
387
|
-
);
|
|
388
|
-
}
|
|
389
|
-
});
|
|
390
|
-
console.log(`Watching ${file} and its dependencies...`);
|
|
382
|
+
await server.start();
|
|
383
|
+
await server.addEntrypoint();
|
|
391
384
|
});
|
|
392
385
|
};
|
|
393
386
|
|
|
@@ -404,7 +397,7 @@ var getRegistryApiUrl = () => {
|
|
|
404
397
|
import delay from "delay";
|
|
405
398
|
|
|
406
399
|
// lib/registry-api/get-ky.ts
|
|
407
|
-
import
|
|
400
|
+
import ky2 from "ky";
|
|
408
401
|
var prettyResponseErrorHook = async (_request, _options, response) => {
|
|
409
402
|
if (!response.ok) {
|
|
410
403
|
try {
|
|
@@ -419,7 +412,7 @@ var prettyResponseErrorHook = async (_request, _options, response) => {
|
|
|
419
412
|
}
|
|
420
413
|
};
|
|
421
414
|
var getKy = () => {
|
|
422
|
-
return
|
|
415
|
+
return ky2.create({
|
|
423
416
|
prefixUrl: getRegistryApiUrl(),
|
|
424
417
|
hooks: {
|
|
425
418
|
afterResponse: [prettyResponseErrorHook]
|
|
@@ -430,8 +423,8 @@ var getKy = () => {
|
|
|
430
423
|
// cli/auth/login/register.ts
|
|
431
424
|
var registerAuthLogin = (program2) => {
|
|
432
425
|
program2.commands.find((c) => c.name() === "auth").command("login").description("Authenticate CLI, login to registry").action(async (args) => {
|
|
433
|
-
const
|
|
434
|
-
const { login_page } = await
|
|
426
|
+
const ky3 = getKy();
|
|
427
|
+
const { login_page } = await ky3.post(
|
|
435
428
|
"sessions/login_page/create",
|
|
436
429
|
{
|
|
437
430
|
json: {}
|
|
@@ -440,7 +433,7 @@ var registerAuthLogin = (program2) => {
|
|
|
440
433
|
console.log("Please visit the following URL to log in:");
|
|
441
434
|
console.log(login_page.url);
|
|
442
435
|
while (true) {
|
|
443
|
-
const { login_page: new_login_page } = await
|
|
436
|
+
const { login_page: new_login_page } = await ky3.post(
|
|
444
437
|
"sessions/login_page/get",
|
|
445
438
|
{
|
|
446
439
|
json: {
|
|
@@ -460,7 +453,7 @@ var registerAuthLogin = (program2) => {
|
|
|
460
453
|
}
|
|
461
454
|
await delay(1e3);
|
|
462
455
|
}
|
|
463
|
-
const { session } = await
|
|
456
|
+
const { session } = await ky3.post(
|
|
464
457
|
"sessions/login_page/exchange_for_cli_session",
|
|
465
458
|
{
|
|
466
459
|
json: {
|
|
@@ -501,7 +494,7 @@ var registerConfigPrint = (program2) => {
|
|
|
501
494
|
};
|
|
502
495
|
|
|
503
496
|
// cli/clone/register.ts
|
|
504
|
-
import * as
|
|
497
|
+
import * as fs4 from "node:fs";
|
|
505
498
|
import * as path5 from "node:path";
|
|
506
499
|
var registerClone = (program2) => {
|
|
507
500
|
program2.command("clone").description("Clone a snippet from the registry").argument("<snippet>", "Snippet to clone (e.g. author/snippetName)").action(async (snippetPath) => {
|
|
@@ -522,23 +515,23 @@ var registerClone = (program2) => {
|
|
|
522
515
|
);
|
|
523
516
|
process.exit(1);
|
|
524
517
|
}
|
|
525
|
-
const
|
|
518
|
+
const ky3 = getKy();
|
|
526
519
|
try {
|
|
527
520
|
console.log(`Cloning ${author}/${snippetName}...`);
|
|
528
|
-
const packageFileList = await
|
|
521
|
+
const packageFileList = await ky3.post("package_files/list", {
|
|
529
522
|
json: {
|
|
530
523
|
package_name: `${author}/${snippetName}`,
|
|
531
524
|
use_latest_version: true
|
|
532
525
|
}
|
|
533
526
|
}).json();
|
|
534
527
|
const dirPath = `./${author}.${snippetName}`;
|
|
535
|
-
if (!
|
|
536
|
-
|
|
528
|
+
if (!fs4.existsSync(dirPath)) {
|
|
529
|
+
fs4.mkdirSync(dirPath);
|
|
537
530
|
}
|
|
538
531
|
for (const fileInfo of packageFileList.package_files) {
|
|
539
532
|
const filePath = fileInfo.file_path.startsWith("/") ? fileInfo.file_path.slice(1) : fileInfo.file_path;
|
|
540
533
|
if (filePath.startsWith("dist/")) continue;
|
|
541
|
-
const fileContent = await
|
|
534
|
+
const fileContent = await ky3.post("package_files/get", {
|
|
542
535
|
json: {
|
|
543
536
|
package_name: `${author}/${snippetName}`,
|
|
544
537
|
file_path: fileInfo.file_path
|
|
@@ -546,10 +539,10 @@ var registerClone = (program2) => {
|
|
|
546
539
|
}).json();
|
|
547
540
|
const fullPath = path5.join(dirPath, filePath);
|
|
548
541
|
const dirName = path5.dirname(fullPath);
|
|
549
|
-
if (!
|
|
550
|
-
|
|
542
|
+
if (!fs4.existsSync(dirName)) {
|
|
543
|
+
fs4.mkdirSync(dirName, { recursive: true });
|
|
551
544
|
}
|
|
552
|
-
|
|
545
|
+
fs4.writeFileSync(fullPath, fileContent.package_file.content_text);
|
|
553
546
|
}
|
|
554
547
|
console.log(`Successfully cloned to ./${author}.${snippetName}/`);
|
|
555
548
|
} catch (error) {
|
|
@@ -579,4 +572,4 @@ if (process.argv.length === 2) {
|
|
|
579
572
|
} else {
|
|
580
573
|
program.parse();
|
|
581
574
|
}
|
|
582
|
-
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vY2xpL21haW4udHMiLCAiLi4vY2xpL2Rldi9yZWdpc3Rlci50cyIsICIuLi9saWIvc2VydmVyL2NyZWF0ZVNlcnZlci50cyIsICIuLi9wYWNrYWdlLmpzb24iLCAiLi4vbGliL3NpdGUvZ2V0SW5kZXgudHMiLCAiLi4vbGliL2RlcGVuZGVuY3ktYW5hbHlzaXMvZ2V0TG9jYWxGaWxlRGVwZW5kZW5jaWVzLnRzIiwgIi4uL2xpYi9kZXBlbmRlbmN5LWFuYWx5c2lzL2luc3RhbGxOb2RlTW9kdWxlVHlwZXMudHMiLCAiLi4vbGliL3NlcnZlci9FdmVudHNXYXRjaGVyLnRzIiwgIi4uL2xpYi9jbGktY29uZmlnL2luZGV4LnRzIiwgIi4uL2NsaS9hdXRoL2xvZ2luL3JlZ2lzdGVyLnRzIiwgIi4uL2xpYi9yZWdpc3RyeS1hcGkvZ2V0LWt5LnRzIiwgIi4uL2NsaS9hdXRoL2xvZ291dC9yZWdpc3Rlci50cyIsICIuLi9jbGkvYXV0aC9yZWdpc3Rlci50cyIsICIuLi9jbGkvY29uZmlnL3JlZ2lzdGVyLnRzIiwgIi4uL2NsaS9jb25maWcvcHJpbnQvcmVnaXN0ZXIudHMiLCAiLi4vY2xpL2Nsb25lL3JlZ2lzdGVyLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIjIS91c3IvYmluL2VudiBub2RlXG5pbXBvcnQgeyBDb21tYW5kIH0gZnJvbSBcImNvbW1hbmRlclwiXG5pbXBvcnQgeyByZWdpc3RlckRldiB9IGZyb20gXCIuL2Rldi9yZWdpc3RlclwiXG5pbXBvcnQgeyByZWdpc3RlckF1dGhMb2dpbiB9IGZyb20gXCIuL2F1dGgvbG9naW4vcmVnaXN0ZXJcIlxuaW1wb3J0IHsgcmVnaXN0ZXJBdXRoTG9nb3V0IH0gZnJvbSBcIi4vYXV0aC9sb2dvdXQvcmVnaXN0ZXJcIlxuaW1wb3J0IHsgcmVnaXN0ZXJBdXRoIH0gZnJvbSBcIi4vYXV0aC9yZWdpc3RlclwiXG5pbXBvcnQgeyByZWdpc3RlckNvbmZpZyB9IGZyb20gXCIuL2NvbmZpZy9yZWdpc3RlclwiXG5pbXBvcnQgeyByZWdpc3RlckNvbmZpZ1ByaW50IH0gZnJvbSBcIi4vY29uZmlnL3ByaW50L3JlZ2lzdGVyXCJcbmltcG9ydCB7IHJlZ2lzdGVyQ2xvbmUgfSBmcm9tIFwiLi9jbG9uZS9yZWdpc3RlclwiXG5pbXBvcnQgeyBwZXJmZWN0Q2xpIH0gZnJvbSBcInBlcmZlY3QtY2xpXCJcbmltcG9ydCBwa2cgZnJvbSBcIi4uL3BhY2thZ2UuanNvblwiXG5cbmNvbnN0IHByb2dyYW0gPSBuZXcgQ29tbWFuZCgpXG5cbnByb2dyYW1cbiAgLm5hbWUoXCJ0c2NpXCIpXG4gIC5kZXNjcmlwdGlvbihcIkNMSSBmb3IgZGV2ZWxvcGluZyB0c2NpcmN1aXQgc25pcHBldHNcIilcbiAgLnZlcnNpb24ocGtnLnZlcnNpb24pXG5cbnJlZ2lzdGVyRGV2KHByb2dyYW0pXG5yZWdpc3RlckNsb25lKHByb2dyYW0pXG5cbnJlZ2lzdGVyQXV0aChwcm9ncmFtKVxucmVnaXN0ZXJBdXRoTG9naW4ocHJvZ3JhbSlcbnJlZ2lzdGVyQXV0aExvZ291dChwcm9ncmFtKVxuXG5yZWdpc3RlckNvbmZpZyhwcm9ncmFtKVxucmVnaXN0ZXJDb25maWdQcmludChwcm9ncmFtKVxuXG5pZiAocHJvY2Vzcy5hcmd2Lmxlbmd0aCA9PT0gMikge1xuICBwZXJmZWN0Q2xpKHByb2dyYW0sIHByb2Nlc3MuYXJndilcbn0gZWxzZSB7XG4gIHByb2dyYW0ucGFyc2UoKVxufVxuIiwgImltcG9ydCB0eXBlIHsgQ29tbWFuZCB9IGZyb20gXCJjb21tYW5kZXJcIlxuaW1wb3J0ICogYXMgcGF0aCBmcm9tIFwibm9kZTpwYXRoXCJcbmltcG9ydCAqIGFzIGNob2tpZGFyIGZyb20gXCJjaG9raWRhclwiXG5pbXBvcnQgKiBhcyBmcyBmcm9tIFwibm9kZTpmc1wiXG5pbXBvcnQgeyBjcmVhdGVTZXJ2ZXIgfSBmcm9tIFwibGliL3NlcnZlci9jcmVhdGVTZXJ2ZXJcIlxuaW1wb3J0IHsgZ2V0TG9jYWxGaWxlRGVwZW5kZW5jaWVzIH0gZnJvbSBcImxpYi9kZXBlbmRlbmN5LWFuYWx5c2lzL2dldExvY2FsRmlsZURlcGVuZGVuY2llc1wiXG5pbXBvcnQgeyBpbnN0YWxsVHlwZXMgfSBmcm9tIFwiLi4vLi4vbGliL2RlcGVuZGVuY3ktYW5hbHlzaXMvaW5zdGFsbE5vZGVNb2R1bGVUeXBlc1wiXG5pbXBvcnQgeyBFdmVudHNXYXRjaGVyIH0gZnJvbSBcIi4uLy4uL2xpYi9zZXJ2ZXIvRXZlbnRzV2F0Y2hlclwiXG5cbmV4cG9ydCBjb25zdCByZWdpc3RlckRldiA9IChwcm9ncmFtOiBDb21tYW5kKSA9PiB7XG4gIHByb2dyYW1cbiAgICAuY29tbWFuZChcImRldlwiKVxuICAgIC5kZXNjcmlwdGlvbihcIlN0YXJ0IGRldmVsb3BtZW50IHNlcnZlciBmb3IgYSBzbmlwcGV0XCIpXG4gICAgLmFyZ3VtZW50KFwiPGZpbGU+XCIsIFwiUGF0aCB0byB0aGUgc25pcHBldCBmaWxlXCIpXG4gICAgLm9wdGlvbihcIi1wLCAtLXBvcnQgPG51bWJlcj5cIiwgXCJQb3J0IHRvIHJ1biBzZXJ2ZXIgb25cIiwgXCIzMDAwXCIpXG4gICAgLmFjdGlvbihhc3luYyAoZmlsZTogc3RyaW5nLCBvcHRpb25zOiB7IHBvcnQ6IHN0cmluZyB9KSA9PiB7XG4gICAgICBjb25zdCBhYnNvbHV0ZVBhdGggPSBwYXRoLnJlc29sdmUoZmlsZSlcbiAgICAgIGNvbnN0IGZpbGVEaXIgPSBwYXRoLmRpcm5hbWUoYWJzb2x1dGVQYXRoKVxuICAgICAgY29uc3QgcG9ydCA9IHBhcnNlSW50KG9wdGlvbnMucG9ydClcblxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc29sZS5sb2coXCJJbnN0YWxsaW5nIHR5cGVzIGZvciBpbXBvcnRlZCBzbmlwcGV0cy4uLlwiKVxuICAgICAgICBhd2FpdCBpbnN0YWxsVHlwZXMoYWJzb2x1dGVQYXRoKVxuICAgICAgICBjb25zb2xlLmxvZyhcIlR5cGVzIGluc3RhbGxlZCBzdWNjZXNzZnVsbHlcIilcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGNvbnNvbGUud2FybihcIkZhaWxlZCB0byBpbnN0YWxsIHR5cGVzOlwiLCBlcnJvcilcbiAgICAgIH1cblxuICAgICAgLy8gU3RhcnQgdGhlIHNlcnZlclxuICAgICAgYXdhaXQgY3JlYXRlU2VydmVyKHBvcnQpXG5cbiAgICAgIGNvbnN0IGV2ZW50c1dhdGNoZXIgPSBuZXcgRXZlbnRzV2F0Y2hlcihgaHR0cDovL2xvY2FsaG9zdDoke3BvcnR9YClcbiAgICAgIGV2ZW50c1dhdGNoZXIuc3RhcnQoKVxuXG4gICAgICBhd2FpdCBmZXRjaChgaHR0cDovL2xvY2FsaG9zdDoke3BvcnR9L2FwaS9maWxlcy91cHNlcnRgLCB7XG4gICAgICAgIG1ldGhvZDogXCJQT1NUXCIsXG4gICAgICAgIGhlYWRlcnM6IHsgXCJDb250ZW50LVR5cGVcIjogXCJhcHBsaWNhdGlvbi9qc29uXCIgfSxcbiAgICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgIGZpbGVfcGF0aDogXCJlbnRyeXBvaW50LnRzeFwiLFxuICAgICAgICAgIHRleHRfY29udGVudDogYFxuaW1wb3J0IE15Q2lyY3VpdCBmcm9tIFwiLi9zbmlwcGV0LnRzeFwiXG5cbmNpcmN1aXQuYWRkKDxNeUNpcmN1aXQgLz4pXG5gLFxuICAgICAgICB9KSxcbiAgICAgIH0pXG5cbiAgICAgIC8vIEZ1bmN0aW9uIHRvIHVwZGF0ZSBmaWxlIGNvbnRlbnRcbiAgICAgIGNvbnN0IHVwZGF0ZUZpbGUgPSBhc3luYyAoZmlsZVBhdGg6IHN0cmluZykgPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IGNvbnRlbnQgPSBhd2FpdCBmcy5wcm9taXNlcy5yZWFkRmlsZShmaWxlUGF0aCwgXCJ1dGYtOFwiKVxuICAgICAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goXG4gICAgICAgICAgICBgaHR0cDovL2xvY2FsaG9zdDoke3BvcnR9L2FwaS9maWxlcy91cHNlcnRgLFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBtZXRob2Q6IFwiUE9TVFwiLFxuICAgICAgICAgICAgICBoZWFkZXJzOiB7IFwiQ29udGVudC1UeXBlXCI6IFwiYXBwbGljYXRpb24vanNvblwiIH0sXG4gICAgICAgICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgICAgICBmaWxlX3BhdGg6IHBhdGgucmVsYXRpdmUoZmlsZURpciwgZmlsZVBhdGgpLFxuICAgICAgICAgICAgICAgIHRleHRfY29udGVudDogY29udGVudCxcbiAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIClcbiAgICAgICAgICBpZiAoIXJlc3BvbnNlLm9rKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKGBGYWlsZWQgdG8gdXBkYXRlICR7ZmlsZVBhdGh9YClcbiAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihgRXJyb3IgdXBkYXRpbmcgJHtmaWxlUGF0aH06YCwgZXJyb3IpXG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gR2V0IGluaXRpYWwgZGVwZW5kZW5jaWVzXG4gICAgICBjb25zdCBkZXBlbmRlbmNpZXMgPSBuZXcgU2V0KFthYnNvbHV0ZVBhdGhdKVxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgZGVwcyA9IGdldExvY2FsRmlsZURlcGVuZGVuY2llcyhhYnNvbHV0ZVBhdGgpXG4gICAgICAgIGRlcHMuZm9yRWFjaCgoZGVwKSA9PiBkZXBlbmRlbmNpZXMuYWRkKGRlcCkpXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBjb25zb2xlLndhcm4oXCJGYWlsZWQgdG8gYW5hbHl6ZSBkZXBlbmRlbmNpZXM6XCIsIGVycm9yKVxuICAgICAgfVxuXG4gICAgICAvLyBXYXRjaCB0aGUgbWFpbiBmaWxlIGFuZCBpdHMgZGVwZW5kZW5jaWVzXG4gICAgICBjb25zdCBmaWxlc3lzdGVtV2F0Y2hlciA9IGNob2tpZGFyLndhdGNoKEFycmF5LmZyb20oZGVwZW5kZW5jaWVzKSwge1xuICAgICAgICBwZXJzaXN0ZW50OiB0cnVlLFxuICAgICAgICBpZ25vcmVJbml0aWFsOiBmYWxzZSxcbiAgICAgIH0pXG5cbiAgICAgIGZpbGVzeXN0ZW1XYXRjaGVyLm9uKFwiY2hhbmdlXCIsIGFzeW5jIChmaWxlUGF0aCkgPT4ge1xuICAgICAgICBjb25zb2xlLmxvZyhgRmlsZSAke2ZpbGVQYXRofSBjaGFuZ2VkYClcbiAgICAgICAgYXdhaXQgdXBkYXRlRmlsZShmaWxlUGF0aClcbiAgICAgIH0pXG5cbiAgICAgIGZpbGVzeXN0ZW1XYXRjaGVyLm9uKFwiYWRkXCIsIGFzeW5jIChmaWxlUGF0aCkgPT4ge1xuICAgICAgICBjb25zb2xlLmxvZyhgRmlsZSAke2ZpbGVQYXRofSBhZGRlZGApXG4gICAgICAgIGF3YWl0IHVwZGF0ZUZpbGUoZmlsZVBhdGgpXG4gICAgICB9KVxuXG4gICAgICBldmVudHNXYXRjaGVyLm9uKFwiRklMRV9VUERBVEVEXCIsIGFzeW5jIChldikgPT4ge1xuICAgICAgICBpZiAoZXYuZmlsZV9wYXRoID09PSBcIm1hbnVhbC1lZGl0cy5qc29uXCIpIHtcbiAgICAgICAgICBjb25zb2xlLmxvZyhcIk1hbnVhbCBlZGl0cyB1cGRhdGVkLCB1cGRhdGluZyBvbiBmaWxlc3lzdGVtLi4uXCIpXG4gICAgICAgICAgY29uc3QgeyBmaWxlIH0gPSBhd2FpdCBmZXRjaChcbiAgICAgICAgICAgIGBodHRwOi8vbG9jYWxob3N0OiR7cG9ydH0vYXBpL2ZpbGVzL2dldD9maWxlX3BhdGg9bWFudWFsLWVkaXRzLmpzb25gLFxuICAgICAgICAgICkudGhlbigocikgPT4gci5qc29uKCkpXG4gICAgICAgICAgZnMud3JpdGVGaWxlU3luYyhcbiAgICAgICAgICAgIHBhdGguam9pbihmaWxlRGlyLCBcIm1hbnVhbC1lZGl0cy5qc29uXCIpLFxuICAgICAgICAgICAgZmlsZS50ZXh0X2NvbnRlbnQsXG4gICAgICAgICAgKVxuICAgICAgICB9XG4gICAgICB9KVxuXG4gICAgICBjb25zb2xlLmxvZyhgV2F0Y2hpbmcgJHtmaWxlfSBhbmQgaXRzIGRlcGVuZGVuY2llcy4uLmApXG4gICAgfSlcbn1cbiIsICJpbXBvcnQgKiBhcyBodHRwIGZyb20gXCJub2RlOmh0dHBcIlxuaW1wb3J0ICogYXMgZnMgZnJvbSBcIm5vZGU6ZnNcIlxuaW1wb3J0ICogYXMgcGF0aCBmcm9tIFwibm9kZTpwYXRoXCJcbmltcG9ydCB7IGdldE5vZGVIYW5kbGVyIH0gZnJvbSBcIndpbnRlcnNwZWMvYWRhcHRlcnMvbm9kZVwiXG5pbXBvcnQgcGtnIGZyb20gXCIuLi8uLi9wYWNrYWdlLmpzb25cIlxuXG4vLyBAdHMtaWdub3JlXG5pbXBvcnQgd2ludGVyc3BlY0J1bmRsZSBmcm9tIFwiQHRzY2lyY3VpdC9maWxlLXNlcnZlci9kaXN0L2J1bmRsZS5qc1wiXG5pbXBvcnQgeyBnZXRJbmRleCB9IGZyb20gXCIuLi9zaXRlL2dldEluZGV4XCJcblxuZXhwb3J0IGNvbnN0IGNyZWF0ZVNlcnZlciA9IGFzeW5jIChwb3J0OiBudW1iZXIgPSAzMDAwKSA9PiB7XG4gIGNvbnN0IGZpbGVTZXJ2ZXJIYW5kbGVyID0gZ2V0Tm9kZUhhbmRsZXIod2ludGVyc3BlY0J1bmRsZSBhcyBhbnksIHt9KVxuXG4gIGNvbnN0IHNlcnZlciA9IGh0dHAuY3JlYXRlU2VydmVyKGFzeW5jIChyZXEsIHJlcykgPT4ge1xuICAgIGNvbnN0IHVybCA9IG5ldyBVUkwocmVxLnVybCEsIGBodHRwOi8vJHtyZXEuaGVhZGVycy5ob3N0fWApXG5cbiAgICBpZiAodXJsLnBhdGhuYW1lID09PSBcIi9zdGFuZGFsb25lLm1pbi5qc1wiKSB7XG4gICAgICBjb25zdCBzdGFuZGFsb25lRmlsZVBhdGggPVxuICAgICAgICBwcm9jZXNzLmVudi5SVU5GUkFNRV9TVEFOREFMT05FX0ZJTEVfUEFUSCB8fFxuICAgICAgICBwYXRoLnJlc29sdmUoXG4gICAgICAgICAgcHJvY2Vzcy5jd2QoKSxcbiAgICAgICAgICBcIm5vZGVfbW9kdWxlc1wiLFxuICAgICAgICAgIFwiQHRzY2lyY3VpdC9ydW5mcmFtZS9kaXN0L3N0YW5kYWxvbmUubWluLmpzXCIsXG4gICAgICAgIClcblxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgY29udGVudCA9IGZzLnJlYWRGaWxlU3luYyhzdGFuZGFsb25lRmlsZVBhdGgsIFwidXRmOFwiKVxuICAgICAgICByZXMud3JpdGVIZWFkKDIwMCwge1xuICAgICAgICAgIFwiQ29udGVudC1UeXBlXCI6IFwiYXBwbGljYXRpb24vamF2YXNjcmlwdDsgY2hhcnNldD11dGYtOFwiLFxuICAgICAgICB9KVxuICAgICAgICByZXMuZW5kKGNvbnRlbnQpXG4gICAgICAgIHJldHVyblxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihcIkVycm9yIHNlcnZpbmcgc3RhbmRhbG9uZS5taW4uanM6XCIsIGVycm9yKVxuICAgICAgfVxuXG4gICAgICByZXMud3JpdGVIZWFkKDMwMiwge1xuICAgICAgICBMb2NhdGlvbjogYGh0dHBzOi8vY2RuLmpzZGVsaXZyLm5ldC9ucG0vQHRzY2lyY3VpdC9ydW5mcmFtZUAke3BrZy5kZXBlbmRlbmNpZXNbXCJAdHNjaXJjdWl0L3J1bmZyYW1lXCJdLnJlcGxhY2UoL15bXjAtOV0rLywgXCJcIil9L2Rpc3Qvc3RhbmRhbG9uZS5taW4uanNgLFxuICAgICAgfSlcbiAgICAgIHJlcy5lbmQoKVxuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgaWYgKHVybC5wYXRobmFtZSA9PT0gXCIvXCIpIHtcbiAgICAgIGNvbnN0IGh0bWwgPSBhd2FpdCBnZXRJbmRleCgpXG4gICAgICByZXMud3JpdGVIZWFkKDIwMCwgeyBcIkNvbnRlbnQtVHlwZVwiOiBcInRleHQvaHRtbFwiIH0pXG4gICAgICByZXMuZW5kKGh0bWwpXG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICBpZiAodXJsLnBhdGhuYW1lLnN0YXJ0c1dpdGgoXCIvYXBpL1wiKSkge1xuICAgICAgcmVxLnVybCA9IHJlcS51cmwhLnJlcGxhY2UoXCIvYXBpL1wiLCBcIi9cIilcbiAgICAgIGZpbGVTZXJ2ZXJIYW5kbGVyKHJlcSwgcmVzKVxuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgcmVzLndyaXRlSGVhZCg0MDQpXG4gICAgcmVzLmVuZChcIk5vdCBmb3VuZFwiKVxuICB9KVxuXG4gIHJldHVybiBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSkgPT4ge1xuICAgIHNlcnZlci5saXN0ZW4ocG9ydCwgKCkgPT4ge1xuICAgICAgY29uc29sZS5sb2coYFNlcnZlciBydW5uaW5nIGF0IGh0dHA6Ly9sb2NhbGhvc3Q6JHtwb3J0fWApXG4gICAgICByZXNvbHZlKClcbiAgICB9KVxuICB9KVxufVxuIiwgIntcbiAgXCJuYW1lXCI6IFwiQHRzY2lyY3VpdC9jbGlcIixcbiAgXCJtYWluXCI6IFwiZGlzdC9tYWluLmpzXCIsXG4gIFwidHlwZVwiOiBcIm1vZHVsZVwiLFxuICBcInZlcnNpb25cIjogXCIwLjEuM1wiLFxuICBcImJpblwiOiB7XG4gICAgXCJ0c2NpXCI6IFwiLi9kaXN0L21haW4uanNcIlxuICB9LFxuICBcInNjcmlwdHNcIjoge1xuICAgIFwic3RhcnRcIjogXCJidW4gcnVuIGRldlwiLFxuICAgIFwiZGV2XCI6IFwiYnVuIC0taG90IC4vY2xpL21haW4udHMgZGV2IC4vZXhhbXBsZS1kaXIvc25pcHBldC50c3hcIixcbiAgICBcImJ1aWxkXCI6IFwidHN1cC1ub2RlIGNsaS9tYWluLnRzIC0tZm9ybWF0IGVzbSAtLXNvdXJjZW1hcCBpbmxpbmVcIixcbiAgICBcImZvcm1hdFwiOiBcImJpb21lIGZvcm1hdCAtLXdyaXRlIC5cIixcbiAgICBcImZvcm1hdDpjaGVja1wiOiBcImJpb21lIGZvcm1hdCAuXCIsXG4gICAgXCJjbGlcIjogXCJidW4gLi9jbGkvbWFpbi50c1wiXG4gIH0sXG4gIFwiZGV2RGVwZW5kZW5jaWVzXCI6IHtcbiAgICBcIkBiaW9tZWpzL2Jpb21lXCI6IFwiXjEuOS40XCIsXG4gICAgXCJAdHNjaXJjdWl0L2NvcmVcIjogXCJeMC4wLjI0OVwiLFxuICAgIFwiQHR5cGVzL2J1blwiOiBcImxhdGVzdFwiLFxuICAgIFwiQHR5cGVzL2NvbmZpZ3N0b3JlXCI6IFwiXjYuMC4yXCIsXG4gICAgXCJAdHlwZXMvcmVhY3RcIjogXCJeMTkuMC4xXCIsXG4gICAgXCJ0c3VwXCI6IFwiXjguMy41XCJcbiAgfSxcbiAgXCJwZWVyRGVwZW5kZW5jaWVzXCI6IHtcbiAgICBcInR5cGVzY3JpcHRcIjogXCJeNS4wLjBcIlxuICB9LFxuICBcImRlcGVuZGVuY2llc1wiOiB7XG4gICAgXCJAdHNjaXJjdWl0L2ZpbGUtc2VydmVyXCI6IFwiXjAuMC4xMVwiLFxuICAgIFwiQHRzY2lyY3VpdC9ydW5mcmFtZVwiOiBcIl4wLjAuNDdcIixcbiAgICBcImNob2tpZGFyXCI6IFwiXjQuMC4xXCIsXG4gICAgXCJjb21tYW5kZXJcIjogXCJeMTIuMS4wXCIsXG4gICAgXCJjb25maWdzdG9yZVwiOiBcIl43LjAuMFwiLFxuICAgIFwiY29zbWljb25maWdcIjogXCJeOS4wLjBcIixcbiAgICBcImRlbGF5XCI6IFwiXjYuMC4wXCIsXG4gICAgXCJreVwiOiBcIl4xLjcuNFwiLFxuICAgIFwicGVyZmVjdC1jbGlcIjogXCJeMS4wLjIwXCJcbiAgfVxufVxuIiwgImltcG9ydCBwa2cgZnJvbSBcIi4uLy4uL3BhY2thZ2UuanNvblwiXG5cbmV4cG9ydCBjb25zdCBnZXRJbmRleCA9IGFzeW5jICgpID0+IHtcbiAgcmV0dXJuIGA8aHRtbD5cbiAgICA8aGVhZD5cbiAgICA8L2hlYWQ+XG4gICAgPGJvZHk+XG4gICAgICA8c2NyaXB0IHNyYz1cImh0dHBzOi8vY2RuLnRhaWx3aW5kY3NzLmNvbVwiPjwvc2NyaXB0PlxuICAgICAgPGRpdiBpZD1cInJvb3RcIj5sb2FkaW5nLi4uPC9kaXY+XG4gICAgICA8c2NyaXB0PlxuICAgICAgZ2xvYmFsVGhpcy5wcm9jZXNzID0geyBlbnY6IHsgTk9ERV9FTlY6IFwicHJvZHVjdGlvblwiIH0gfVxuICAgICAgPC9zY3JpcHQ+XG4gICAgICA8c2NyaXB0IHNyYz1cIi9zdGFuZGFsb25lLm1pbi5qc1wiPjwvc2NyaXB0PlxuICAgIDwvYm9keT5cbiAgPC9odG1sPmBcbn1cblxuLy8gPHNjcmlwdCBzcmM9XCJodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL0B0c2NpcmN1aXQvcnVuZnJhbWVAJHtwa2cuZGVwZW5kZW5jaWVzW1wiQHRzY2lyY3VpdC9ydW5mcmFtZVwiXS5yZXBsYWNlKC9eW14wLTldKy8sIFwiXCIpfS9kaXN0L3N0YW5kYWxvbmUubWluLmpzXCI+PC9zY3JpcHQ+XG4iLCAiaW1wb3J0ICogYXMgdHMgZnJvbSBcInR5cGVzY3JpcHRcIlxuaW1wb3J0ICogYXMgcGF0aCBmcm9tIFwicGF0aFwiXG5pbXBvcnQgKiBhcyBmcyBmcm9tIFwiZnNcIlxuXG5mdW5jdGlvbiBnZXRMb2NhbEZpbGVEZXBlbmRlbmNpZXMocGF0aFRvVHN4RmlsZTogc3RyaW5nKTogc3RyaW5nW10ge1xuICAvLyBFbnN1cmUgYWJzb2x1dGUgcGF0aFxuICBjb25zdCBhYnNvbHV0ZVBhdGggPSBwYXRoLnJlc29sdmUocGF0aFRvVHN4RmlsZSlcbiAgY29uc3QgYmFzZURpciA9IHBhdGguZGlybmFtZShhYnNvbHV0ZVBhdGgpXG5cbiAgLy8gUmVhZCBhbmQgcGFyc2UgdGhlIGZpbGVcbiAgY29uc3QgY29udGVudCA9IGZzLnJlYWRGaWxlU3luYyhhYnNvbHV0ZVBhdGgsIFwidXRmLThcIilcbiAgY29uc3Qgc291cmNlRmlsZSA9IHRzLmNyZWF0ZVNvdXJjZUZpbGUoXG4gICAgYWJzb2x1dGVQYXRoLFxuICAgIGNvbnRlbnQsXG4gICAgdHMuU2NyaXB0VGFyZ2V0LkxhdGVzdCxcbiAgICB0cnVlLFxuICApXG5cbiAgY29uc3QgZGVwZW5kZW5jaWVzID0gbmV3IFNldDxzdHJpbmc+KClcblxuICAvLyBSZWN1cnNpdmVseSB2aXNpdCBub2RlcyB0byBmaW5kIGltcG9ydHNcbiAgZnVuY3Rpb24gdmlzaXQobm9kZTogdHMuTm9kZSkge1xuICAgIGlmICh0cy5pc0ltcG9ydERlY2xhcmF0aW9uKG5vZGUpIHx8IHRzLmlzRXhwb3J0RGVjbGFyYXRpb24obm9kZSkpIHtcbiAgICAgIGNvbnN0IG1vZHVsZVNwZWNpZmllciA9IG5vZGUubW9kdWxlU3BlY2lmaWVyXG4gICAgICBpZiAobW9kdWxlU3BlY2lmaWVyICYmIHRzLmlzU3RyaW5nTGl0ZXJhbChtb2R1bGVTcGVjaWZpZXIpKSB7XG4gICAgICAgIGNvbnN0IGltcG9ydFBhdGggPSBtb2R1bGVTcGVjaWZpZXIudGV4dFxuICAgICAgICAvLyBPbmx5IHByb2Nlc3MgbG9jYWwgaW1wb3J0cyAoc3RhcnRpbmcgd2l0aCAuIG9yIC4uKVxuICAgICAgICBpZiAoaW1wb3J0UGF0aC5zdGFydHNXaXRoKFwiLlwiKSkge1xuICAgICAgICAgIHJlc29sdmVBbmRBZGREZXBlbmRlbmN5KGltcG9ydFBhdGgpXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBIYW5kbGUgZHluYW1pYyBpbXBvcnRzXG4gICAgaWYgKFxuICAgICAgdHMuaXNDYWxsRXhwcmVzc2lvbihub2RlKSAmJlxuICAgICAgbm9kZS5leHByZXNzaW9uLmtpbmQgPT09IHRzLlN5bnRheEtpbmQuSW1wb3J0S2V5d29yZFxuICAgICkge1xuICAgICAgY29uc3QgYXJndW1lbnQgPSBub2RlLmFyZ3VtZW50c1swXVxuICAgICAgaWYgKGFyZ3VtZW50ICYmIHRzLmlzU3RyaW5nTGl0ZXJhbChhcmd1bWVudCkpIHtcbiAgICAgICAgY29uc3QgaW1wb3J0UGF0aCA9IGFyZ3VtZW50LnRleHRcbiAgICAgICAgaWYgKGltcG9ydFBhdGguc3RhcnRzV2l0aChcIi5cIikpIHtcbiAgICAgICAgICByZXNvbHZlQW5kQWRkRGVwZW5kZW5jeShpbXBvcnRQYXRoKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgdHMuZm9yRWFjaENoaWxkKG5vZGUsIHZpc2l0KVxuICB9XG5cbiAgLy8gSGVscGVyIHRvIHJlc29sdmUgYW5kIGFkZCBkZXBlbmRlbmN5IHBhdGhzXG4gIGZ1bmN0aW9uIHJlc29sdmVBbmRBZGREZXBlbmRlbmN5KGltcG9ydFBhdGg6IHN0cmluZykge1xuICAgIGNvbnN0IGV4dGVuc2lvbnMgPSBbXG4gICAgICBcIi50c3hcIixcbiAgICAgIFwiLnRzXCIsXG4gICAgICBcIi5qc3hcIixcbiAgICAgIFwiLmpzXCIsXG4gICAgICBcIi5jc3NcIixcbiAgICAgIFwiLnNjc3NcIixcbiAgICAgIFwiLnNhc3NcIixcbiAgICAgIFwiLmxlc3NcIixcbiAgICBdXG4gICAgbGV0IHJlc29sdmVkUGF0aCA9IHBhdGgucmVzb2x2ZShiYXNlRGlyLCBpbXBvcnRQYXRoKVxuXG4gICAgLy8gQ2hlY2sgaWYgcGF0aCBleGlzdHMgYXMtaXNcbiAgICBpZiAoZnMuZXhpc3RzU3luYyhyZXNvbHZlZFBhdGgpKSB7XG4gICAgICBkZXBlbmRlbmNpZXMuYWRkKHJlc29sdmVkUGF0aClcbiAgICAgIHJldHVyblxuICAgIH1cblxuICAgIC8vIFRyeSB3aXRoIGV4dGVuc2lvbnNcbiAgICBmb3IgKGNvbnN0IGV4dCBvZiBleHRlbnNpb25zKSB7XG4gICAgICBjb25zdCBwYXRoV2l0aEV4dCA9IHJlc29sdmVkUGF0aCArIGV4dFxuICAgICAgaWYgKGZzLmV4aXN0c1N5bmMocGF0aFdpdGhFeHQpKSB7XG4gICAgICAgIGRlcGVuZGVuY2llcy5hZGQocGF0aFdpdGhFeHQpXG4gICAgICAgIHJldHVyblxuICAgICAgfVxuICAgIH1cblxuICAgIC8vIENoZWNrIGZvciBpbmRleCBmaWxlcyBpbiBkaXJlY3Rvcmllc1xuICAgIGlmIChcbiAgICAgIGZzLmV4aXN0c1N5bmMocmVzb2x2ZWRQYXRoKSAmJlxuICAgICAgZnMuc3RhdFN5bmMocmVzb2x2ZWRQYXRoKS5pc0RpcmVjdG9yeSgpXG4gICAgKSB7XG4gICAgICBmb3IgKGNvbnN0IGV4dCBvZiBleHRlbnNpb25zKSB7XG4gICAgICAgIGNvbnN0IGluZGV4UGF0aCA9IHBhdGguam9pbihyZXNvbHZlZFBhdGgsIGBpbmRleCR7ZXh0fWApXG4gICAgICAgIGlmIChmcy5leGlzdHNTeW5jKGluZGV4UGF0aCkpIHtcbiAgICAgICAgICBkZXBlbmRlbmNpZXMuYWRkKGluZGV4UGF0aClcbiAgICAgICAgICByZXR1cm5cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8vIFN0YXJ0IHRoZSB0cmF2ZXJzYWxcbiAgdmlzaXQoc291cmNlRmlsZSlcblxuICByZXR1cm4gQXJyYXkuZnJvbShkZXBlbmRlbmNpZXMpXG59XG5cbmV4cG9ydCB7IGdldExvY2FsRmlsZURlcGVuZGVuY2llcyB9XG4iLCAiaW1wb3J0ICogYXMgZnMgZnJvbSBcIm5vZGU6ZnNcIlxuaW1wb3J0ICogYXMgcGF0aCBmcm9tIFwibm9kZTpwYXRoXCJcbmltcG9ydCAqIGFzIHRzIGZyb20gXCJ0eXBlc2NyaXB0XCJcblxuaW50ZXJmYWNlIFNuaXBwZXRBcGlSZXNwb25zZSB7XG4gIHNuaXBwZXQ6IHtcbiAgICBkdHM6IHN0cmluZ1xuICB9XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBpbnN0YWxsVHlwZXMoc25pcHBldFBhdGg6IHN0cmluZykge1xuICBjb25zdCBjb250ZW50ID0gZnMucmVhZEZpbGVTeW5jKHNuaXBwZXRQYXRoLCBcInV0Zi04XCIpXG4gIGNvbnN0IHNvdXJjZUZpbGUgPSB0cy5jcmVhdGVTb3VyY2VGaWxlKFxuICAgIHNuaXBwZXRQYXRoLFxuICAgIGNvbnRlbnQsXG4gICAgdHMuU2NyaXB0VGFyZ2V0LkxhdGVzdCxcbiAgICB0cnVlLFxuICApXG5cbiAgY29uc3QgaW1wb3J0czogc3RyaW5nW10gPSBbXVxuXG4gIGZ1bmN0aW9uIHZpc2l0KG5vZGU6IHRzLk5vZGUpIHtcbiAgICBpZiAodHMuaXNJbXBvcnREZWNsYXJhdGlvbihub2RlKSkge1xuICAgICAgY29uc3QgbW9kdWxlU3BlY2lmaWVyID0gbm9kZS5tb2R1bGVTcGVjaWZpZXJcbiAgICAgIGlmIChtb2R1bGVTcGVjaWZpZXIgJiYgdHMuaXNTdHJpbmdMaXRlcmFsKG1vZHVsZVNwZWNpZmllcikpIHtcbiAgICAgICAgY29uc3QgaW1wb3J0UGF0aCA9IG1vZHVsZVNwZWNpZmllci50ZXh0XG4gICAgICAgIGlmIChpbXBvcnRQYXRoLnN0YXJ0c1dpdGgoXCJAdHNjaS9cIikpIHtcbiAgICAgICAgICBpbXBvcnRzLnB1c2goaW1wb3J0UGF0aClcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICB0cy5mb3JFYWNoQ2hpbGQobm9kZSwgdmlzaXQpXG4gIH1cblxuICB2aXNpdChzb3VyY2VGaWxlKVxuXG4gIGxldCBwcm9qZWN0Um9vdCA9IHBhdGguZGlybmFtZShzbmlwcGV0UGF0aClcbiAgd2hpbGUgKHByb2plY3RSb290ICE9PSBwYXRoLnBhcnNlKHByb2plY3RSb290KS5yb290KSB7XG4gICAgaWYgKGZzLmV4aXN0c1N5bmMocGF0aC5qb2luKHByb2plY3RSb290LCBcInBhY2thZ2UuanNvblwiKSkpIHtcbiAgICAgIGJyZWFrXG4gICAgfVxuICAgIHByb2plY3RSb290ID0gcGF0aC5kaXJuYW1lKHByb2plY3RSb290KVxuICB9XG5cbiAgZm9yIChjb25zdCBpbXBvcnRQYXRoIG9mIGltcG9ydHMpIHtcbiAgICBjb25zdCBbb3duZXIsIG5hbWVdID0gaW1wb3J0UGF0aC5yZXBsYWNlKFwiQHRzY2kvXCIsIFwiXCIpLnNwbGl0KFwiLlwiKVxuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKFxuICAgICAgICBgaHR0cHM6Ly9yZWdpc3RyeS1hcGkudHNjaXJjdWl0LmNvbS9zbmlwcGV0cy9nZXQ/b3duZXJfbmFtZT0ke293bmVyfSZ1bnNjb3BlZF9uYW1lPSR7bmFtZX1gLFxuICAgICAgKVxuXG4gICAgICBpZiAoIXJlc3BvbnNlLm9rKSB7XG4gICAgICAgIGNvbnNvbGUud2FybihgRmFpbGVkIHRvIGZldGNoIHR5cGVzIGZvciAke2ltcG9ydFBhdGh9YClcbiAgICAgICAgY29udGludWVcbiAgICAgIH1cblxuICAgICAgY29uc3QgZGF0YTogU25pcHBldEFwaVJlc3BvbnNlID0gYXdhaXQgcmVzcG9uc2UuanNvbigpXG5cbiAgICAgIGlmIChkYXRhLnNuaXBwZXQuZHRzKSB7XG4gICAgICAgIGNvbnN0IHBhY2thZ2VEaXIgPSBwYXRoLmpvaW4oXG4gICAgICAgICAgcHJvamVjdFJvb3QsXG4gICAgICAgICAgXCJub2RlX21vZHVsZXNcIixcbiAgICAgICAgICBcIkB0c2NpXCIsXG4gICAgICAgICAgYCR7b3duZXJ9LiR7bmFtZX1gLFxuICAgICAgICApXG4gICAgICAgIGZzLm1rZGlyU3luYyhwYWNrYWdlRGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KVxuXG4gICAgICAgIGZzLndyaXRlRmlsZVN5bmMocGF0aC5qb2luKHBhY2thZ2VEaXIsIFwiaW5kZXguZC50c1wiKSwgZGF0YS5zbmlwcGV0LmR0cylcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc29sZS53YXJuKGBFcnJvciBmZXRjaGluZyB0eXBlcyBmb3IgJHtpbXBvcnRQYXRofTpgLCBlcnJvcilcbiAgICB9XG4gIH1cbn1cbiIsICJpbXBvcnQgeyBFdmVudEVtaXR0ZXIgfSBmcm9tIFwiZXZlbnRzXCJcblxuaW50ZXJmYWNlIEV2ZW50IHtcbiAgZXZlbnRfaWQ6IHN0cmluZ1xuICBjcmVhdGVkX2F0OiBzdHJpbmdcbiAgZXZlbnRfdHlwZTogc3RyaW5nXG4gIFtrZXk6IHN0cmluZ106IGFueVxufVxuXG5pbnRlcmZhY2UgRXZlbnRzUmVzcG9uc2Uge1xuICBldmVudF9saXN0OiBFdmVudFtdXG59XG5cbmV4cG9ydCBjbGFzcyBFdmVudHNXYXRjaGVyIGV4dGVuZHMgRXZlbnRFbWl0dGVyIHtcbiAgcHJpdmF0ZSBsYXN0UG9sbFRpbWU6IHN0cmluZ1xuICBwcml2YXRlIHBvbGxJbnRlcnZhbDogbnVtYmVyXG4gIHByaXZhdGUgYmFzZVVybDogc3RyaW5nXG4gIHByaXZhdGUgcG9sbGluZyA9IGZhbHNlXG4gIHByaXZhdGUgdGltZW91dElkPzogTm9kZUpTLlRpbWVvdXRcblxuICBjb25zdHJ1Y3RvcihiYXNlVXJsID0gXCJodHRwOi8vbG9jYWxob3N0OjMwMDBcIiwgcG9sbEludGVydmFsID0gMTAwMCkge1xuICAgIHN1cGVyKClcbiAgICB0aGlzLmJhc2VVcmwgPSBiYXNlVXJsXG4gICAgdGhpcy5wb2xsSW50ZXJ2YWwgPSBwb2xsSW50ZXJ2YWxcbiAgICB0aGlzLmxhc3RQb2xsVGltZSA9IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKVxuICB9XG5cbiAgYXN5bmMgc3RhcnQoKSB7XG4gICAgaWYgKHRoaXMucG9sbGluZykgcmV0dXJuXG4gICAgdGhpcy5wb2xsaW5nID0gdHJ1ZVxuICAgIGF3YWl0IHRoaXMucG9sbCgpXG4gIH1cblxuICBzdG9wKCkge1xuICAgIHRoaXMucG9sbGluZyA9IGZhbHNlXG4gICAgaWYgKHRoaXMudGltZW91dElkKSB7XG4gICAgICBjbGVhclRpbWVvdXQodGhpcy50aW1lb3V0SWQpXG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBwb2xsKCkge1xuICAgIGlmICghdGhpcy5wb2xsaW5nKSByZXR1cm5cblxuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKFxuICAgICAgICBgJHt0aGlzLmJhc2VVcmx9L2FwaS9ldmVudHMvbGlzdD9zaW5jZT0ke2VuY29kZVVSSUNvbXBvbmVudCh0aGlzLmxhc3RQb2xsVGltZSl9YCxcbiAgICAgIClcblxuICAgICAgaWYgKCFyZXNwb25zZS5vaykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEhUVFAgZXJyb3IhIHN0YXR1czogJHtyZXNwb25zZS5zdGF0dXN9YClcbiAgICAgIH1cblxuICAgICAgY29uc3QgZGF0YTogRXZlbnRzUmVzcG9uc2UgPSBhd2FpdCByZXNwb25zZS5qc29uKClcblxuICAgICAgLy8gVXBkYXRlIGxhc3QgcG9sbCB0aW1lIHRvIGxhdGVzdCBldmVudCBvciBjdXJyZW50IHRpbWVcbiAgICAgIGNvbnN0IGxhdGVzdEV2ZW50ID0gZGF0YS5ldmVudF9saXN0W2RhdGEuZXZlbnRfbGlzdC5sZW5ndGggLSAxXVxuICAgICAgdGhpcy5sYXN0UG9sbFRpbWUgPSBsYXRlc3RFdmVudFxuICAgICAgICA/IGxhdGVzdEV2ZW50LmNyZWF0ZWRfYXRcbiAgICAgICAgOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKClcblxuICAgICAgLy8gRW1pdCBldmVudHMgaW4gY2hyb25vbG9naWNhbCBvcmRlclxuICAgICAgZGF0YS5ldmVudF9saXN0LmZvckVhY2goKGV2ZW50KSA9PiB7XG4gICAgICAgIHRoaXMuZW1pdChldmVudC5ldmVudF90eXBlLCBldmVudClcbiAgICAgICAgdGhpcy5lbWl0KFwiKlwiLCBldmVudClcbiAgICAgIH0pXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHRoaXMuZW1pdChcImVycm9yXCIsIGVycm9yKVxuICAgIH1cbiAgICAvLyBTY2hlZHVsZSBuZXh0IHBvbGxcbiAgICB0aGlzLnRpbWVvdXRJZCA9IGdsb2JhbFRoaXMuc2V0VGltZW91dChcbiAgICAgICgpID0+IHRoaXMucG9sbCgpLFxuICAgICAgdGhpcy5wb2xsSW50ZXJ2YWwsXG4gICAgKSBhcyB1bmtub3duIGFzIE5vZGVKUy5UaW1lb3V0XG4gIH1cbn1cbiIsICJpbXBvcnQgQ29uZmlnc3RvcmUgZnJvbSBcImNvbmZpZ3N0b3JlXCJcbmltcG9ydCB0eXBlIHsgVHlwZWRDb25maWdzdG9yZSB9IGZyb20gXCIuL1R5cGVkQ29uZmlnU3RvcmVcIlxuXG5leHBvcnQgaW50ZXJmYWNlIENsaUNvbmZpZyB7XG4gIHNlc3Npb25Ub2tlbj86IHN0cmluZ1xuICBnaXRodWJVc2VybmFtZT86IHN0cmluZ1xuICByZWdpc3RyeUFwaVVybD86IHN0cmluZ1xufVxuXG5leHBvcnQgY29uc3QgY2xpQ29uZmlnOiBUeXBlZENvbmZpZ3N0b3JlPENsaUNvbmZpZz4gPSBuZXcgQ29uZmlnc3RvcmUoXG4gIFwidHNjaXJjdWl0XCIsXG4pXG5cbmV4cG9ydCBjb25zdCBnZXRSZWdpc3RyeUFwaVVybCA9ICgpOiBzdHJpbmcgPT4ge1xuICByZXR1cm4gY2xpQ29uZmlnLmdldChcInJlZ2lzdHJ5QXBpVXJsXCIpID8/IFwiaHR0cHM6Ly9yZWdpc3RyeS1hcGkudHNjaXJjdWl0LmNvbVwiXG59XG4iLCAiaW1wb3J0IHR5cGUgeyBDb21tYW5kIH0gZnJvbSBcImNvbW1hbmRlclwiXG5pbXBvcnQgeyBjbGlDb25maWcgfSBmcm9tIFwibGliL2NsaS1jb25maWdcIlxuaW1wb3J0IGRlbGF5IGZyb20gXCJkZWxheVwiXG5pbXBvcnQgeyBnZXRLeSB9IGZyb20gXCJsaWIvcmVnaXN0cnktYXBpL2dldC1reVwiXG5pbXBvcnQgdHlwZSB7IEVuZHBvaW50UmVzcG9uc2UgfSBmcm9tIFwibGliL3JlZ2lzdHJ5LWFwaS9lbmRwb2ludC10eXBlc1wiXG5cbmV4cG9ydCBjb25zdCByZWdpc3RlckF1dGhMb2dpbiA9IChwcm9ncmFtOiBDb21tYW5kKSA9PiB7XG4gIHByb2dyYW0uY29tbWFuZHNcbiAgICAuZmluZCgoYykgPT4gYy5uYW1lKCkgPT09IFwiYXV0aFwiKSFcbiAgICAuY29tbWFuZChcImxvZ2luXCIpXG4gICAgLmRlc2NyaXB0aW9uKFwiQXV0aGVudGljYXRlIENMSSwgbG9naW4gdG8gcmVnaXN0cnlcIilcbiAgICAuYWN0aW9uKGFzeW5jIChhcmdzKSA9PiB7XG4gICAgICBjb25zdCBreSA9IGdldEt5KClcblxuICAgICAgY29uc3QgeyBsb2dpbl9wYWdlIH0gPSBhd2FpdCBreVxuICAgICAgICAucG9zdDxFbmRwb2ludFJlc3BvbnNlW1wic2Vzc2lvbnMvbG9naW5fcGFnZS9jcmVhdGVcIl0+KFxuICAgICAgICAgIFwic2Vzc2lvbnMvbG9naW5fcGFnZS9jcmVhdGVcIixcbiAgICAgICAgICB7XG4gICAgICAgICAgICBqc29uOiB7fSxcbiAgICAgICAgICB9LFxuICAgICAgICApXG4gICAgICAgIC5qc29uKClcblxuICAgICAgY29uc29sZS5sb2coXCJQbGVhc2UgdmlzaXQgdGhlIGZvbGxvd2luZyBVUkwgdG8gbG9nIGluOlwiKVxuICAgICAgY29uc29sZS5sb2cobG9naW5fcGFnZS51cmwpXG5cbiAgICAgIC8vIFdhaXQgdW50aWwgd2UgcmVjZWl2ZSBjb25maXJtYXRpb25cbiAgICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICAgIGNvbnN0IHsgbG9naW5fcGFnZTogbmV3X2xvZ2luX3BhZ2UgfSA9IGF3YWl0IGt5XG4gICAgICAgICAgLnBvc3Q8RW5kcG9pbnRSZXNwb25zZVtcInNlc3Npb25zL2xvZ2luX3BhZ2UvZ2V0XCJdPihcbiAgICAgICAgICAgIFwic2Vzc2lvbnMvbG9naW5fcGFnZS9nZXRcIixcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAganNvbjoge1xuICAgICAgICAgICAgICAgIGxvZ2luX3BhZ2VfaWQ6IGxvZ2luX3BhZ2UubG9naW5fcGFnZV9pZCxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAgIEF1dGhvcml6YXRpb246IGBCZWFyZXIgJHtsb2dpbl9wYWdlLmxvZ2luX3BhZ2VfYXV0aF90b2tlbn1gLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICApXG4gICAgICAgICAgLmpzb24oKVxuXG4gICAgICAgIGlmIChuZXdfbG9naW5fcGFnZS53YXNfbG9naW5fc3VjY2Vzc2Z1bCkge1xuICAgICAgICAgIGNvbnNvbGUubG9nKFwiTG9nZ2VkIGluISBHZW5lcmF0aW5nIHRva2VuLi4uXCIpXG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChuZXdfbG9naW5fcGFnZS5pc19leHBpcmVkKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTG9naW4gcGFnZSBleHBpcmVkXCIpXG4gICAgICAgIH1cblxuICAgICAgICBhd2FpdCBkZWxheSgxMDAwKVxuICAgICAgfVxuXG4gICAgICBjb25zdCB7IHNlc3Npb24gfSA9IGF3YWl0IGt5XG4gICAgICAgIC5wb3N0PEVuZHBvaW50UmVzcG9uc2VbXCJzZXNzaW9ucy9sb2dpbl9wYWdlL2V4Y2hhbmdlX2Zvcl9jbGlfc2Vzc2lvblwiXT4oXG4gICAgICAgICAgXCJzZXNzaW9ucy9sb2dpbl9wYWdlL2V4Y2hhbmdlX2Zvcl9jbGlfc2Vzc2lvblwiLFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGpzb246IHtcbiAgICAgICAgICAgICAgbG9naW5fcGFnZV9pZDogbG9naW5fcGFnZS5sb2dpbl9wYWdlX2lkLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICAgQXV0aG9yaXphdGlvbjogYEJlYXJlciAke2xvZ2luX3BhZ2UubG9naW5fcGFnZV9hdXRoX3Rva2VufWAsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0sXG4gICAgICAgIClcbiAgICAgICAgLmpzb24oKVxuXG4gICAgICBjbGlDb25maWcuc2V0KFwic2Vzc2lvblRva2VuXCIsIHNlc3Npb24udG9rZW4pXG5cbiAgICAgIGNvbnNvbGUubG9nKFwiUmVhZHkgdG8gdXNlIVwiKVxuICAgIH0pXG59XG4iLCAiaW1wb3J0IHsgZ2V0UmVnaXN0cnlBcGlVcmwgfSBmcm9tIFwibGliL2NsaS1jb25maWdcIlxuaW1wb3J0IGt5LCB7IHR5cGUgQWZ0ZXJSZXNwb25zZUhvb2sgfSBmcm9tIFwia3lcIlxuXG5jb25zdCBwcmV0dHlSZXNwb25zZUVycm9ySG9vazogQWZ0ZXJSZXNwb25zZUhvb2sgPSBhc3luYyAoXG4gIF9yZXF1ZXN0LFxuICBfb3B0aW9ucyxcbiAgcmVzcG9uc2UsXG4pID0+IHtcbiAgaWYgKCFyZXNwb25zZS5vaykge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBlcnJvckRhdGEgPSBhd2FpdCByZXNwb25zZS5qc29uKClcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYEZBSUwgWyR7cmVzcG9uc2Uuc3RhdHVzfV06ICR7X3JlcXVlc3QubWV0aG9kfSAke1xuICAgICAgICAgIG5ldyBVUkwoX3JlcXVlc3QudXJsKS5wYXRobmFtZVxuICAgICAgICB9IFxcblxcbiAke0pTT04uc3RyaW5naWZ5KGVycm9yRGF0YSwgbnVsbCwgMil9YCxcbiAgICAgIClcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAvL2lnbm9yZSwgYWxsb3cgdGhlIGVycm9yIHRvIGJlIHRocm93blxuICAgIH1cbiAgfVxufVxuXG5leHBvcnQgY29uc3QgZ2V0S3kgPSAoKSA9PiB7XG4gIHJldHVybiBreS5jcmVhdGUoe1xuICAgIHByZWZpeFVybDogZ2V0UmVnaXN0cnlBcGlVcmwoKSxcbiAgICBob29rczoge1xuICAgICAgYWZ0ZXJSZXNwb25zZTogW3ByZXR0eVJlc3BvbnNlRXJyb3JIb29rXSxcbiAgICB9LFxuICB9KVxufVxuIiwgImltcG9ydCB0eXBlIHsgQ29tbWFuZCB9IGZyb20gXCJjb21tYW5kZXJcIlxuXG5leHBvcnQgY29uc3QgcmVnaXN0ZXJBdXRoTG9nb3V0ID0gKHByb2dyYW06IENvbW1hbmQpID0+IHtcbiAgcHJvZ3JhbS5jb21tYW5kc1xuICAgIC5maW5kKChjKSA9PiBjLm5hbWUoKSA9PT0gXCJhdXRoXCIpIVxuICAgIC5jb21tYW5kKFwibG9nb3V0XCIpXG4gICAgLmRlc2NyaXB0aW9uKFwiTG9nb3V0IGZyb20gcmVnaXN0cnlcIilcbiAgICAuYWN0aW9uKChhcmdzKSA9PiB7XG4gICAgICBjb25zb2xlLmxvZyhcImxvZ291dFwiKVxuICAgIH0pXG59XG4iLCAiaW1wb3J0IHR5cGUgeyBDb21tYW5kIH0gZnJvbSBcImNvbW1hbmRlclwiXG5cbmV4cG9ydCBjb25zdCByZWdpc3RlckF1dGggPSAocHJvZ3JhbTogQ29tbWFuZCkgPT4ge1xuICBwcm9ncmFtLmNvbW1hbmQoXCJhdXRoXCIpLmRlc2NyaXB0aW9uKFwiTG9naW4vbG9nb3V0XCIpXG59XG4iLCAiaW1wb3J0IHR5cGUgeyBDb21tYW5kIH0gZnJvbSBcImNvbW1hbmRlclwiXG5cbmV4cG9ydCBjb25zdCByZWdpc3RlckNvbmZpZyA9IChwcm9ncmFtOiBDb21tYW5kKSA9PiB7XG4gIHByb2dyYW0uY29tbWFuZChcImNvbmZpZ1wiKS5kZXNjcmlwdGlvbihcIk1hbmFnZSB0c2NpcmN1aXQgQ0xJIGNvbmZpZ3VyYXRpb25cIilcbn1cbiIsICJpbXBvcnQgdHlwZSB7IENvbW1hbmQgfSBmcm9tIFwiY29tbWFuZGVyXCJcbmltcG9ydCB7IGNsaUNvbmZpZyB9IGZyb20gXCJsaWIvY2xpLWNvbmZpZ1wiXG5cbmV4cG9ydCBjb25zdCByZWdpc3RlckNvbmZpZ1ByaW50ID0gKHByb2dyYW06IENvbW1hbmQpID0+IHtcbiAgcHJvZ3JhbS5jb21tYW5kc1xuICAgIC5maW5kKChjKSA9PiBjLm5hbWUoKSA9PT0gXCJjb25maWdcIikhXG4gICAgLmNvbW1hbmQoXCJwcmludFwiKVxuICAgIC5kZXNjcmlwdGlvbihcIlByaW50IHRoZSBjdXJyZW50IGNvbmZpZ1wiKVxuICAgIC5hY3Rpb24oKCkgPT4ge1xuICAgICAgY29uc29sZS5sb2coSlNPTi5zdHJpbmdpZnkoY2xpQ29uZmlnLmFsbCwgbnVsbCwgMikpXG4gICAgfSlcbn1cbiIsICJpbXBvcnQgdHlwZSB7IENvbW1hbmQgfSBmcm9tIFwiY29tbWFuZGVyXCJcbmltcG9ydCB7IGdldEt5IH0gZnJvbSBcImxpYi9yZWdpc3RyeS1hcGkvZ2V0LWt5XCJcbmltcG9ydCAqIGFzIGZzIGZyb20gXCJub2RlOmZzXCJcbmltcG9ydCAqIGFzIHBhdGggZnJvbSBcIm5vZGU6cGF0aFwiXG5cbmV4cG9ydCBjb25zdCByZWdpc3RlckNsb25lID0gKHByb2dyYW06IENvbW1hbmQpID0+IHtcbiAgcHJvZ3JhbVxuICAgIC5jb21tYW5kKFwiY2xvbmVcIilcbiAgICAuZGVzY3JpcHRpb24oXCJDbG9uZSBhIHNuaXBwZXQgZnJvbSB0aGUgcmVnaXN0cnlcIilcbiAgICAuYXJndW1lbnQoXCI8c25pcHBldD5cIiwgXCJTbmlwcGV0IHRvIGNsb25lIChlLmcuIGF1dGhvci9zbmlwcGV0TmFtZSlcIilcbiAgICAuYWN0aW9uKGFzeW5jIChzbmlwcGV0UGF0aDogc3RyaW5nKSA9PiB7XG4gICAgICBsZXQgYXV0aG9yOiBzdHJpbmdcbiAgICAgIGxldCBzbmlwcGV0TmFtZTogc3RyaW5nXG4gICAgICBpZiAoIXNuaXBwZXRQYXRoLnN0YXJ0c1dpdGgoXCJAdHNjaS9cIikgJiYgc25pcHBldFBhdGguaW5jbHVkZXMoXCIvXCIpKSB7XG4gICAgICAgIDtbYXV0aG9yLCBzbmlwcGV0TmFtZV0gPSBzbmlwcGV0UGF0aC5zcGxpdChcIi9cIilcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IHRyaW1tZWRQYXRoID0gc25pcHBldFBhdGgucmVwbGFjZShcIkB0c2NpL1wiLCBcIlwiKVxuICAgICAgICBjb25zdCBmaXJzdERvdEluZGV4ID0gdHJpbW1lZFBhdGguaW5kZXhPZihcIi5cIilcbiAgICAgICAgYXV0aG9yID0gdHJpbW1lZFBhdGguc2xpY2UoMCwgZmlyc3REb3RJbmRleClcbiAgICAgICAgc25pcHBldE5hbWUgPSB0cmltbWVkUGF0aC5zbGljZShmaXJzdERvdEluZGV4ICsgMSlcbiAgICAgIH1cblxuICAgICAgaWYgKCFhdXRob3IgfHwgIXNuaXBwZXROYW1lKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoXG4gICAgICAgICAgXCJJbnZhbGlkIHNuaXBwZXQgcGF0aC4gVXNlIGZvcm1hdDogYXV0aG9yL3NuaXBwZXROYW1lLCBhdXRob3Iuc25pcHBldE5hbWUgb3IgQHRzY2kvYXV0aG9yLnNuaXBwZXROYW1lXCIsXG4gICAgICAgIClcbiAgICAgICAgcHJvY2Vzcy5leGl0KDEpXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGt5ID0gZ2V0S3koKVxuXG4gICAgICB0cnkge1xuICAgICAgICBjb25zb2xlLmxvZyhgQ2xvbmluZyAke2F1dGhvcn0vJHtzbmlwcGV0TmFtZX0uLi5gKVxuXG4gICAgICAgIGNvbnN0IHBhY2thZ2VGaWxlTGlzdCA9IGF3YWl0IGt5XG4gICAgICAgICAgLnBvc3Q8e1xuICAgICAgICAgICAgcGFja2FnZV9maWxlczogQXJyYXk8e1xuICAgICAgICAgICAgICBwYWNrYWdlX2ZpbGVfaWQ6IHN0cmluZ1xuICAgICAgICAgICAgICBwYWNrYWdlX3JlbGVhc2VfaWQ6IHN0cmluZ1xuICAgICAgICAgICAgICBmaWxlX3BhdGg6IHN0cmluZ1xuICAgICAgICAgICAgICBjcmVhdGVkX2F0OiBzdHJpbmdcbiAgICAgICAgICAgIH0+XG4gICAgICAgICAgfT4oXCJwYWNrYWdlX2ZpbGVzL2xpc3RcIiwge1xuICAgICAgICAgICAganNvbjoge1xuICAgICAgICAgICAgICBwYWNrYWdlX25hbWU6IGAke2F1dGhvcn0vJHtzbmlwcGV0TmFtZX1gLFxuICAgICAgICAgICAgICB1c2VfbGF0ZXN0X3ZlcnNpb246IHRydWUsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0pXG4gICAgICAgICAgLmpzb24oKVxuXG4gICAgICAgIC8vIENyZWF0ZSBkaXJlY3RvcnkgaWYgaXQgZG9lc24ndCBleGlzdFxuICAgICAgICBjb25zdCBkaXJQYXRoID0gYC4vJHthdXRob3J9LiR7c25pcHBldE5hbWV9YFxuICAgICAgICBpZiAoIWZzLmV4aXN0c1N5bmMoZGlyUGF0aCkpIHtcbiAgICAgICAgICBmcy5ta2RpclN5bmMoZGlyUGF0aClcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIERvd25sb2FkIGVhY2ggZmlsZSB0aGF0IGRvZXNuJ3Qgc3RhcnQgd2l0aCBkaXN0L1xuICAgICAgICBmb3IgKGNvbnN0IGZpbGVJbmZvIG9mIHBhY2thZ2VGaWxlTGlzdC5wYWNrYWdlX2ZpbGVzKSB7XG4gICAgICAgICAgY29uc3QgZmlsZVBhdGggPSBmaWxlSW5mby5maWxlX3BhdGguc3RhcnRzV2l0aChcIi9cIilcbiAgICAgICAgICAgID8gZmlsZUluZm8uZmlsZV9wYXRoLnNsaWNlKDEpXG4gICAgICAgICAgICA6IGZpbGVJbmZvLmZpbGVfcGF0aFxuXG4gICAgICAgICAgaWYgKGZpbGVQYXRoLnN0YXJ0c1dpdGgoXCJkaXN0L1wiKSkgY29udGludWVcblxuICAgICAgICAgIGNvbnN0IGZpbGVDb250ZW50ID0gYXdhaXQga3lcbiAgICAgICAgICAgIC5wb3N0PHtcbiAgICAgICAgICAgICAgcGFja2FnZV9maWxlOiB7XG4gICAgICAgICAgICAgICAgY29udGVudF90ZXh0OiBzdHJpbmdcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfT4oXCJwYWNrYWdlX2ZpbGVzL2dldFwiLCB7XG4gICAgICAgICAgICAgIGpzb246IHtcbiAgICAgICAgICAgICAgICBwYWNrYWdlX25hbWU6IGAke2F1dGhvcn0vJHtzbmlwcGV0TmFtZX1gLFxuICAgICAgICAgICAgICAgIGZpbGVfcGF0aDogZmlsZUluZm8uZmlsZV9wYXRoLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIC5qc29uKClcblxuICAgICAgICAgIGNvbnN0IGZ1bGxQYXRoID0gcGF0aC5qb2luKGRpclBhdGgsIGZpbGVQYXRoKVxuICAgICAgICAgIGNvbnN0IGRpck5hbWUgPSBwYXRoLmRpcm5hbWUoZnVsbFBhdGgpXG5cbiAgICAgICAgICAvLyBDcmVhdGUgbmVzdGVkIGRpcmVjdG9yaWVzIGlmIHRoZXkgZG9uJ3QgZXhpc3RcbiAgICAgICAgICBpZiAoIWZzLmV4aXN0c1N5bmMoZGlyTmFtZSkpIHtcbiAgICAgICAgICAgIGZzLm1rZGlyU3luYyhkaXJOYW1lLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KVxuICAgICAgICAgIH1cblxuICAgICAgICAgIGZzLndyaXRlRmlsZVN5bmMoZnVsbFBhdGgsIGZpbGVDb250ZW50LnBhY2thZ2VfZmlsZS5jb250ZW50X3RleHQpXG4gICAgICAgIH1cblxuICAgICAgICBjb25zb2xlLmxvZyhgU3VjY2Vzc2Z1bGx5IGNsb25lZCB0byAuLyR7YXV0aG9yfS4ke3NuaXBwZXROYW1lfS9gKVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKFwiRmFpbGVkIHRvIGNsb25lIHNuaXBwZXQ6XCIsIGVycm9yLm1lc3NhZ2UpXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihcIkZhaWxlZCB0byBjbG9uZSBzbmlwcGV0OlwiLCBlcnJvcilcbiAgICAgICAgfVxuICAgICAgICBwcm9jZXNzLmV4aXQoMSlcbiAgICAgIH1cbiAgICB9KVxufVxuIl0sCiAgIm1hcHBpbmdzIjogIjs7O0FBQ0EsU0FBUyxlQUFlOzs7QUNBeEIsWUFBWUEsV0FBVTtBQUN0QixZQUFZLGNBQWM7QUFDMUIsWUFBWUMsU0FBUTs7O0FDSHBCLFlBQVksVUFBVTtBQUN0QixZQUFZLFFBQVE7QUFDcEIsWUFBWSxVQUFVO0FBQ3RCLFNBQVMsc0JBQXNCOzs7QUNIL0I7QUFBQSxFQUNFLE1BQVE7QUFBQSxFQUNSLE1BQVE7QUFBQSxFQUNSLE1BQVE7QUFBQSxFQUNSLFNBQVc7QUFBQSxFQUNYLEtBQU87QUFBQSxJQUNMLE1BQVE7QUFBQSxFQUNWO0FBQUEsRUFDQSxTQUFXO0FBQUEsSUFDVCxPQUFTO0FBQUEsSUFDVCxLQUFPO0FBQUEsSUFDUCxPQUFTO0FBQUEsSUFDVCxRQUFVO0FBQUEsSUFDVixnQkFBZ0I7QUFBQSxJQUNoQixLQUFPO0FBQUEsRUFDVDtBQUFBLEVBQ0EsaUJBQW1CO0FBQUEsSUFDakIsa0JBQWtCO0FBQUEsSUFDbEIsbUJBQW1CO0FBQUEsSUFDbkIsY0FBYztBQUFBLElBQ2Qsc0JBQXNCO0FBQUEsSUFDdEIsZ0JBQWdCO0FBQUEsSUFDaEIsTUFBUTtBQUFBLEVBQ1Y7QUFBQSxFQUNBLGtCQUFvQjtBQUFBLElBQ2xCLFlBQWM7QUFBQSxFQUNoQjtBQUFBLEVBQ0EsY0FBZ0I7QUFBQSxJQUNkLDBCQUEwQjtBQUFBLElBQzFCLHVCQUF1QjtBQUFBLElBQ3ZCLFVBQVk7QUFBQSxJQUNaLFdBQWE7QUFBQSxJQUNiLGFBQWU7QUFBQSxJQUNmLGFBQWU7QUFBQSxJQUNmLE9BQVM7QUFBQSxJQUNULElBQU07QUFBQSxJQUNOLGVBQWU7QUFBQSxFQUNqQjtBQUNGOzs7QUQvQkEsT0FBTyxzQkFBc0I7OztBRUx0QixJQUFNLFdBQVcsWUFBWTtBQUNsQyxTQUFPO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQVlUOzs7QUZMTyxJQUFNQyxnQkFBZSxPQUFPLE9BQWUsUUFBUztBQUN6RCxRQUFNLG9CQUFvQixlQUFlLGtCQUF5QixDQUFDLENBQUM7QUFFcEUsUUFBTSxTQUFjLGtCQUFhLE9BQU8sS0FBSyxRQUFRO0FBQ25ELFVBQU0sTUFBTSxJQUFJLElBQUksSUFBSSxLQUFNLFVBQVUsSUFBSSxRQUFRLElBQUksRUFBRTtBQUUxRCxRQUFJLElBQUksYUFBYSxzQkFBc0I7QUFDekMsWUFBTSxxQkFDSixRQUFRLElBQUksaUNBQ1A7QUFBQSxRQUNILFFBQVEsSUFBSTtBQUFBLFFBQ1o7QUFBQSxRQUNBO0FBQUEsTUFDRjtBQUVGLFVBQUk7QUFDRixjQUFNLFVBQWEsZ0JBQWEsb0JBQW9CLE1BQU07QUFDMUQsWUFBSSxVQUFVLEtBQUs7QUFBQSxVQUNqQixnQkFBZ0I7QUFBQSxRQUNsQixDQUFDO0FBQ0QsWUFBSSxJQUFJLE9BQU87QUFDZjtBQUFBLE1BQ0YsU0FBUyxPQUFPO0FBQ2QsZ0JBQVEsTUFBTSxvQ0FBb0MsS0FBSztBQUFBLE1BQ3pEO0FBRUEsVUFBSSxVQUFVLEtBQUs7QUFBQSxRQUNqQixVQUFVLG9EQUFvRCxnQkFBSSxhQUFhLHFCQUFxQixFQUFFLFFBQVEsWUFBWSxFQUFFLENBQUM7QUFBQSxNQUMvSCxDQUFDO0FBQ0QsVUFBSSxJQUFJO0FBQ1I7QUFBQSxJQUNGO0FBRUEsUUFBSSxJQUFJLGFBQWEsS0FBSztBQUN4QixZQUFNLE9BQU8sTUFBTSxTQUFTO0FBQzVCLFVBQUksVUFBVSxLQUFLLEVBQUUsZ0JBQWdCLFlBQVksQ0FBQztBQUNsRCxVQUFJLElBQUksSUFBSTtBQUNaO0FBQUEsSUFDRjtBQUVBLFFBQUksSUFBSSxTQUFTLFdBQVcsT0FBTyxHQUFHO0FBQ3BDLFVBQUksTUFBTSxJQUFJLElBQUssUUFBUSxTQUFTLEdBQUc7QUFDdkMsd0JBQWtCLEtBQUssR0FBRztBQUMxQjtBQUFBLElBQ0Y7QUFFQSxRQUFJLFVBQVUsR0FBRztBQUNqQixRQUFJLElBQUksV0FBVztBQUFBLEVBQ3JCLENBQUM7QUFFRCxTQUFPLElBQUksUUFBYyxDQUFDQyxhQUFZO0FBQ3BDLFdBQU8sT0FBTyxNQUFNLE1BQU07QUFDeEIsY0FBUSxJQUFJLHNDQUFzQyxJQUFJLEVBQUU7QUFDeEQsTUFBQUEsU0FBUTtBQUFBLElBQ1YsQ0FBQztBQUFBLEVBQ0gsQ0FBQztBQUNIOzs7QUdsRUEsWUFBWSxRQUFRO0FBQ3BCLFlBQVlDLFdBQVU7QUFDdEIsWUFBWUMsU0FBUTtBQUVwQixTQUFTLHlCQUF5QixlQUFpQztBQUVqRSxRQUFNLGVBQW9CLGNBQVEsYUFBYTtBQUMvQyxRQUFNLFVBQWUsY0FBUSxZQUFZO0FBR3pDLFFBQU0sVUFBYSxpQkFBYSxjQUFjLE9BQU87QUFDckQsUUFBTSxhQUFnQjtBQUFBLElBQ3BCO0FBQUEsSUFDQTtBQUFBLElBQ0csZ0JBQWE7QUFBQSxJQUNoQjtBQUFBLEVBQ0Y7QUFFQSxRQUFNLGVBQWUsb0JBQUksSUFBWTtBQUdyQyxXQUFTLE1BQU0sTUFBZTtBQUM1QixRQUFPLHVCQUFvQixJQUFJLEtBQVEsdUJBQW9CLElBQUksR0FBRztBQUNoRSxZQUFNLGtCQUFrQixLQUFLO0FBQzdCLFVBQUksbUJBQXNCLG1CQUFnQixlQUFlLEdBQUc7QUFDMUQsY0FBTSxhQUFhLGdCQUFnQjtBQUVuQyxZQUFJLFdBQVcsV0FBVyxHQUFHLEdBQUc7QUFDOUIsa0NBQXdCLFVBQVU7QUFBQSxRQUNwQztBQUFBLE1BQ0Y7QUFBQSxJQUNGO0FBR0EsUUFDSyxvQkFBaUIsSUFBSSxLQUN4QixLQUFLLFdBQVcsU0FBWSxjQUFXLGVBQ3ZDO0FBQ0EsWUFBTSxXQUFXLEtBQUssVUFBVSxDQUFDO0FBQ2pDLFVBQUksWUFBZSxtQkFBZ0IsUUFBUSxHQUFHO0FBQzVDLGNBQU0sYUFBYSxTQUFTO0FBQzVCLFlBQUksV0FBVyxXQUFXLEdBQUcsR0FBRztBQUM5QixrQ0FBd0IsVUFBVTtBQUFBLFFBQ3BDO0FBQUEsTUFDRjtBQUFBLElBQ0Y7QUFFQSxJQUFHLGdCQUFhLE1BQU0sS0FBSztBQUFBLEVBQzdCO0FBR0EsV0FBUyx3QkFBd0IsWUFBb0I7QUFDbkQsVUFBTSxhQUFhO0FBQUEsTUFDakI7QUFBQSxNQUNBO0FBQUEsTUFDQTtBQUFBLE1BQ0E7QUFBQSxNQUNBO0FBQUEsTUFDQTtBQUFBLE1BQ0E7QUFBQSxNQUNBO0FBQUEsSUFDRjtBQUNBLFFBQUksZUFBb0IsY0FBUSxTQUFTLFVBQVU7QUFHbkQsUUFBTyxlQUFXLFlBQVksR0FBRztBQUMvQixtQkFBYSxJQUFJLFlBQVk7QUFDN0I7QUFBQSxJQUNGO0FBR0EsZUFBVyxPQUFPLFlBQVk7QUFDNUIsWUFBTSxjQUFjLGVBQWU7QUFDbkMsVUFBTyxlQUFXLFdBQVcsR0FBRztBQUM5QixxQkFBYSxJQUFJLFdBQVc7QUFDNUI7QUFBQSxNQUNGO0FBQUEsSUFDRjtBQUdBLFFBQ0ssZUFBVyxZQUFZLEtBQ3ZCLGFBQVMsWUFBWSxFQUFFLFlBQVksR0FDdEM7QUFDQSxpQkFBVyxPQUFPLFlBQVk7QUFDNUIsY0FBTSxZQUFpQixXQUFLLGNBQWMsUUFBUSxHQUFHLEVBQUU7QUFDdkQsWUFBTyxlQUFXLFNBQVMsR0FBRztBQUM1Qix1QkFBYSxJQUFJLFNBQVM7QUFDMUI7QUFBQSxRQUNGO0FBQUEsTUFDRjtBQUFBLElBQ0Y7QUFBQSxFQUNGO0FBR0EsUUFBTSxVQUFVO0FBRWhCLFNBQU8sTUFBTSxLQUFLLFlBQVk7QUFDaEM7OztBQ2xHQSxZQUFZQyxTQUFRO0FBQ3BCLFlBQVlDLFdBQVU7QUFDdEIsWUFBWUMsU0FBUTtBQVFwQixlQUFzQixhQUFhLGFBQXFCO0FBQ3RELFFBQU0sVUFBYSxpQkFBYSxhQUFhLE9BQU87QUFDcEQsUUFBTSxhQUFnQjtBQUFBLElBQ3BCO0FBQUEsSUFDQTtBQUFBLElBQ0csaUJBQWE7QUFBQSxJQUNoQjtBQUFBLEVBQ0Y7QUFFQSxRQUFNLFVBQW9CLENBQUM7QUFFM0IsV0FBUyxNQUFNLE1BQWU7QUFDNUIsUUFBTyx3QkFBb0IsSUFBSSxHQUFHO0FBQ2hDLFlBQU0sa0JBQWtCLEtBQUs7QUFDN0IsVUFBSSxtQkFBc0Isb0JBQWdCLGVBQWUsR0FBRztBQUMxRCxjQUFNLGFBQWEsZ0JBQWdCO0FBQ25DLFlBQUksV0FBVyxXQUFXLFFBQVEsR0FBRztBQUNuQyxrQkFBUSxLQUFLLFVBQVU7QUFBQSxRQUN6QjtBQUFBLE1BQ0Y7QUFBQSxJQUNGO0FBQ0EsSUFBRyxpQkFBYSxNQUFNLEtBQUs7QUFBQSxFQUM3QjtBQUVBLFFBQU0sVUFBVTtBQUVoQixNQUFJLGNBQW1CLGNBQVEsV0FBVztBQUMxQyxTQUFPLGdCQUFxQixZQUFNLFdBQVcsRUFBRSxNQUFNO0FBQ25ELFFBQU8sZUFBZ0IsV0FBSyxhQUFhLGNBQWMsQ0FBQyxHQUFHO0FBQ3pEO0FBQUEsSUFDRjtBQUNBLGtCQUFtQixjQUFRLFdBQVc7QUFBQSxFQUN4QztBQUVBLGFBQVcsY0FBYyxTQUFTO0FBQ2hDLFVBQU0sQ0FBQyxPQUFPLElBQUksSUFBSSxXQUFXLFFBQVEsVUFBVSxFQUFFLEVBQUUsTUFBTSxHQUFHO0FBQ2hFLFFBQUk7QUFDRixZQUFNLFdBQVcsTUFBTTtBQUFBLFFBQ3JCLDhEQUE4RCxLQUFLLGtCQUFrQixJQUFJO0FBQUEsTUFDM0Y7QUFFQSxVQUFJLENBQUMsU0FBUyxJQUFJO0FBQ2hCLGdCQUFRLEtBQUssNkJBQTZCLFVBQVUsRUFBRTtBQUN0RDtBQUFBLE1BQ0Y7QUFFQSxZQUFNLE9BQTJCLE1BQU0sU0FBUyxLQUFLO0FBRXJELFVBQUksS0FBSyxRQUFRLEtBQUs7QUFDcEIsY0FBTSxhQUFrQjtBQUFBLFVBQ3RCO0FBQUEsVUFDQTtBQUFBLFVBQ0E7QUFBQSxVQUNBLEdBQUcsS0FBSyxJQUFJLElBQUk7QUFBQSxRQUNsQjtBQUNBLFFBQUcsY0FBVSxZQUFZLEVBQUUsV0FBVyxLQUFLLENBQUM7QUFFNUMsUUFBRyxrQkFBbUIsV0FBSyxZQUFZLFlBQVksR0FBRyxLQUFLLFFBQVEsR0FBRztBQUFBLE1BQ3hFO0FBQUEsSUFDRixTQUFTLE9BQU87QUFDZCxjQUFRLEtBQUssNEJBQTRCLFVBQVUsS0FBSyxLQUFLO0FBQUEsSUFDL0Q7QUFBQSxFQUNGO0FBQ0Y7OztBQ3pFQSxTQUFTLG9CQUFvQjtBQWF0QixJQUFNLGdCQUFOLGNBQTRCLGFBQWE7QUFBQSxFQUN0QztBQUFBLEVBQ0E7QUFBQSxFQUNBO0FBQUEsRUFDQSxVQUFVO0FBQUEsRUFDVjtBQUFBLEVBRVIsWUFBWSxVQUFVLHlCQUF5QixlQUFlLEtBQU07QUFDbEUsVUFBTTtBQUNOLFNBQUssVUFBVTtBQUNmLFNBQUssZUFBZTtBQUNwQixTQUFLLGdCQUFlLG9CQUFJLEtBQUssR0FBRSxZQUFZO0FBQUEsRUFDN0M7QUFBQSxFQUVBLE1BQU0sUUFBUTtBQUNaLFFBQUksS0FBSyxRQUFTO0FBQ2xCLFNBQUssVUFBVTtBQUNmLFVBQU0sS0FBSyxLQUFLO0FBQUEsRUFDbEI7QUFBQSxFQUVBLE9BQU87QUFDTCxTQUFLLFVBQVU7QUFDZixRQUFJLEtBQUssV0FBVztBQUNsQixtQkFBYSxLQUFLLFNBQVM7QUFBQSxJQUM3QjtBQUFBLEVBQ0Y7QUFBQSxFQUVBLE1BQWMsT0FBTztBQUNuQixRQUFJLENBQUMsS0FBSyxRQUFTO0FBRW5CLFFBQUk7QUFDRixZQUFNLFdBQVcsTUFBTTtBQUFBLFFBQ3JCLEdBQUcsS0FBSyxPQUFPLDBCQUEwQixtQkFBbUIsS0FBSyxZQUFZLENBQUM7QUFBQSxNQUNoRjtBQUVBLFVBQUksQ0FBQyxTQUFTLElBQUk7QUFDaEIsY0FBTSxJQUFJLE1BQU0sdUJBQXVCLFNBQVMsTUFBTSxFQUFFO0FBQUEsTUFDMUQ7QUFFQSxZQUFNLE9BQXVCLE1BQU0sU0FBUyxLQUFLO0FBR2pELFlBQU0sY0FBYyxLQUFLLFdBQVcsS0FBSyxXQUFXLFNBQVMsQ0FBQztBQUM5RCxXQUFLLGVBQWUsY0FDaEIsWUFBWSxjQUNaLG9CQUFJLEtBQUssR0FBRSxZQUFZO0FBRzNCLFdBQUssV0FBVyxRQUFRLENBQUMsVUFBVTtBQUNqQyxhQUFLLEtBQUssTUFBTSxZQUFZLEtBQUs7QUFDakMsYUFBSyxLQUFLLEtBQUssS0FBSztBQUFBLE1BQ3RCLENBQUM7QUFBQSxJQUNILFNBQVMsT0FBTztBQUNkLFdBQUssS0FBSyxTQUFTLEtBQUs7QUFBQSxJQUMxQjtBQUVBLFNBQUssWUFBWSxXQUFXO0FBQUEsTUFDMUIsTUFBTSxLQUFLLEtBQUs7QUFBQSxNQUNoQixLQUFLO0FBQUEsSUFDUDtBQUFBLEVBQ0Y7QUFDRjs7O0FOakVPLElBQU0sY0FBYyxDQUFDQyxhQUFxQjtBQUMvQyxFQUFBQSxTQUNHLFFBQVEsS0FBSyxFQUNiLFlBQVksd0NBQXdDLEVBQ3BELFNBQVMsVUFBVSwwQkFBMEIsRUFDN0MsT0FBTyx1QkFBdUIseUJBQXlCLE1BQU0sRUFDN0QsT0FBTyxPQUFPLE1BQWMsWUFBOEI7QUFDekQsVUFBTSxlQUFvQixjQUFRLElBQUk7QUFDdEMsVUFBTSxVQUFlLGNBQVEsWUFBWTtBQUN6QyxVQUFNLE9BQU8sU0FBUyxRQUFRLElBQUk7QUFFbEMsUUFBSTtBQUNGLGNBQVEsSUFBSSwyQ0FBMkM7QUFDdkQsWUFBTSxhQUFhLFlBQVk7QUFDL0IsY0FBUSxJQUFJLDhCQUE4QjtBQUFBLElBQzVDLFNBQVMsT0FBTztBQUNkLGNBQVEsS0FBSyw0QkFBNEIsS0FBSztBQUFBLElBQ2hEO0FBR0EsVUFBTUMsY0FBYSxJQUFJO0FBRXZCLFVBQU0sZ0JBQWdCLElBQUksY0FBYyxvQkFBb0IsSUFBSSxFQUFFO0FBQ2xFLGtCQUFjLE1BQU07QUFFcEIsVUFBTSxNQUFNLG9CQUFvQixJQUFJLHFCQUFxQjtBQUFBLE1BQ3ZELFFBQVE7QUFBQSxNQUNSLFNBQVMsRUFBRSxnQkFBZ0IsbUJBQW1CO0FBQUEsTUFDOUMsTUFBTSxLQUFLLFVBQVU7QUFBQSxRQUNuQixXQUFXO0FBQUEsUUFDWCxjQUFjO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQSxNQUtoQixDQUFDO0FBQUEsSUFDSCxDQUFDO0FBR0QsVUFBTSxhQUFhLE9BQU8sYUFBcUI7QUFDN0MsVUFBSTtBQUNGLGNBQU0sVUFBVSxNQUFTLGFBQVMsU0FBUyxVQUFVLE9BQU87QUFDNUQsY0FBTSxXQUFXLE1BQU07QUFBQSxVQUNyQixvQkFBb0IsSUFBSTtBQUFBLFVBQ3hCO0FBQUEsWUFDRSxRQUFRO0FBQUEsWUFDUixTQUFTLEVBQUUsZ0JBQWdCLG1CQUFtQjtBQUFBLFlBQzlDLE1BQU0sS0FBSyxVQUFVO0FBQUEsY0FDbkIsV0FBZ0IsZUFBUyxTQUFTLFFBQVE7QUFBQSxjQUMxQyxjQUFjO0FBQUEsWUFDaEIsQ0FBQztBQUFBLFVBQ0g7QUFBQSxRQUNGO0FBQ0EsWUFBSSxDQUFDLFNBQVMsSUFBSTtBQUNoQixrQkFBUSxNQUFNLG9CQUFvQixRQUFRLEVBQUU7QUFBQSxRQUM5QztBQUFBLE1BQ0YsU0FBUyxPQUFPO0FBQ2QsZ0JBQVEsTUFBTSxrQkFBa0IsUUFBUSxLQUFLLEtBQUs7QUFBQSxNQUNwRDtBQUFBLElBQ0Y7QUFHQSxVQUFNLGVBQWUsb0JBQUksSUFBSSxDQUFDLFlBQVksQ0FBQztBQUMzQyxRQUFJO0FBQ0YsWUFBTSxPQUFPLHlCQUF5QixZQUFZO0FBQ2xELFdBQUssUUFBUSxDQUFDLFFBQVEsYUFBYSxJQUFJLEdBQUcsQ0FBQztBQUFBLElBQzdDLFNBQVMsT0FBTztBQUNkLGNBQVEsS0FBSyxtQ0FBbUMsS0FBSztBQUFBLElBQ3ZEO0FBR0EsVUFBTSxvQkFBNkIsZUFBTSxNQUFNLEtBQUssWUFBWSxHQUFHO0FBQUEsTUFDakUsWUFBWTtBQUFBLE1BQ1osZUFBZTtBQUFBLElBQ2pCLENBQUM7QUFFRCxzQkFBa0IsR0FBRyxVQUFVLE9BQU8sYUFBYTtBQUNqRCxjQUFRLElBQUksUUFBUSxRQUFRLFVBQVU7QUFDdEMsWUFBTSxXQUFXLFFBQVE7QUFBQSxJQUMzQixDQUFDO0FBRUQsc0JBQWtCLEdBQUcsT0FBTyxPQUFPLGFBQWE7QUFDOUMsY0FBUSxJQUFJLFFBQVEsUUFBUSxRQUFRO0FBQ3BDLFlBQU0sV0FBVyxRQUFRO0FBQUEsSUFDM0IsQ0FBQztBQUVELGtCQUFjLEdBQUcsZ0JBQWdCLE9BQU8sT0FBTztBQUM3QyxVQUFJLEdBQUcsY0FBYyxxQkFBcUI7QUFDeEMsZ0JBQVEsSUFBSSxpREFBaUQ7QUFDN0QsY0FBTSxFQUFFLE1BQUFDLE1BQUssSUFBSSxNQUFNO0FBQUEsVUFDckIsb0JBQW9CLElBQUk7QUFBQSxRQUMxQixFQUFFLEtBQUssQ0FBQyxNQUFNLEVBQUUsS0FBSyxDQUFDO0FBQ3RCLFFBQUc7QUFBQSxVQUNJLFdBQUssU0FBUyxtQkFBbUI7QUFBQSxVQUN0Q0EsTUFBSztBQUFBLFFBQ1A7QUFBQSxNQUNGO0FBQUEsSUFDRixDQUFDO0FBRUQsWUFBUSxJQUFJLFlBQVksSUFBSSwwQkFBMEI7QUFBQSxFQUN4RCxDQUFDO0FBQ0w7OztBTzlHQSxPQUFPLGlCQUFpQjtBQVNqQixJQUFNLFlBQXlDLElBQUk7QUFBQSxFQUN4RDtBQUNGO0FBRU8sSUFBTSxvQkFBb0IsTUFBYztBQUM3QyxTQUFPLFVBQVUsSUFBSSxnQkFBZ0IsS0FBSztBQUM1Qzs7O0FDYkEsT0FBTyxXQUFXOzs7QUNEbEIsT0FBTyxRQUFvQztBQUUzQyxJQUFNLDBCQUE2QyxPQUNqRCxVQUNBLFVBQ0EsYUFDRztBQUNILE1BQUksQ0FBQyxTQUFTLElBQUk7QUFDaEIsUUFBSTtBQUNGLFlBQU0sWUFBWSxNQUFNLFNBQVMsS0FBSztBQUN0QyxZQUFNLElBQUk7QUFBQSxRQUNSLFNBQVMsU0FBUyxNQUFNLE1BQU0sU0FBUyxNQUFNLElBQzNDLElBQUksSUFBSSxTQUFTLEdBQUcsRUFBRSxRQUN4QjtBQUFBO0FBQUEsR0FBUyxLQUFLLFVBQVUsV0FBVyxNQUFNLENBQUMsQ0FBQztBQUFBLE1BQzdDO0FBQUEsSUFDRixTQUFTLEdBQUc7QUFBQSxJQUVaO0FBQUEsRUFDRjtBQUNGO0FBRU8sSUFBTSxRQUFRLE1BQU07QUFDekIsU0FBTyxHQUFHLE9BQU87QUFBQSxJQUNmLFdBQVcsa0JBQWtCO0FBQUEsSUFDN0IsT0FBTztBQUFBLE1BQ0wsZUFBZSxDQUFDLHVCQUF1QjtBQUFBLElBQ3pDO0FBQUEsRUFDRixDQUFDO0FBQ0g7OztBRHZCTyxJQUFNLG9CQUFvQixDQUFDQyxhQUFxQjtBQUNyRCxFQUFBQSxTQUFRLFNBQ0wsS0FBSyxDQUFDLE1BQU0sRUFBRSxLQUFLLE1BQU0sTUFBTSxFQUMvQixRQUFRLE9BQU8sRUFDZixZQUFZLHFDQUFxQyxFQUNqRCxPQUFPLE9BQU8sU0FBUztBQUN0QixVQUFNQyxNQUFLLE1BQU07QUFFakIsVUFBTSxFQUFFLFdBQVcsSUFBSSxNQUFNQSxJQUMxQjtBQUFBLE1BQ0M7QUFBQSxNQUNBO0FBQUEsUUFDRSxNQUFNLENBQUM7QUFBQSxNQUNUO0FBQUEsSUFDRixFQUNDLEtBQUs7QUFFUixZQUFRLElBQUksMkNBQTJDO0FBQ3ZELFlBQVEsSUFBSSxXQUFXLEdBQUc7QUFHMUIsV0FBTyxNQUFNO0FBQ1gsWUFBTSxFQUFFLFlBQVksZUFBZSxJQUFJLE1BQU1BLElBQzFDO0FBQUEsUUFDQztBQUFBLFFBQ0E7QUFBQSxVQUNFLE1BQU07QUFBQSxZQUNKLGVBQWUsV0FBVztBQUFBLFVBQzVCO0FBQUEsVUFDQSxTQUFTO0FBQUEsWUFDUCxlQUFlLFVBQVUsV0FBVyxxQkFBcUI7QUFBQSxVQUMzRDtBQUFBLFFBQ0Y7QUFBQSxNQUNGLEVBQ0MsS0FBSztBQUVSLFVBQUksZUFBZSxzQkFBc0I7QUFDdkMsZ0JBQVEsSUFBSSxnQ0FBZ0M7QUFDNUM7QUFBQSxNQUNGO0FBRUEsVUFBSSxlQUFlLFlBQVk7QUFDN0IsY0FBTSxJQUFJLE1BQU0sb0JBQW9CO0FBQUEsTUFDdEM7QUFFQSxZQUFNLE1BQU0sR0FBSTtBQUFBLElBQ2xCO0FBRUEsVUFBTSxFQUFFLFFBQVEsSUFBSSxNQUFNQSxJQUN2QjtBQUFBLE1BQ0M7QUFBQSxNQUNBO0FBQUEsUUFDRSxNQUFNO0FBQUEsVUFDSixlQUFlLFdBQVc7QUFBQSxRQUM1QjtBQUFBLFFBQ0EsU0FBUztBQUFBLFVBQ1AsZUFBZSxVQUFVLFdBQVcscUJBQXFCO0FBQUEsUUFDM0Q7QUFBQSxNQUNGO0FBQUEsSUFDRixFQUNDLEtBQUs7QUFFUixjQUFVLElBQUksZ0JBQWdCLFFBQVEsS0FBSztBQUUzQyxZQUFRLElBQUksZUFBZTtBQUFBLEVBQzdCLENBQUM7QUFDTDs7O0FFdEVPLElBQU0scUJBQXFCLENBQUNDLGFBQXFCO0FBQ3RELEVBQUFBLFNBQVEsU0FDTCxLQUFLLENBQUMsTUFBTSxFQUFFLEtBQUssTUFBTSxNQUFNLEVBQy9CLFFBQVEsUUFBUSxFQUNoQixZQUFZLHNCQUFzQixFQUNsQyxPQUFPLENBQUMsU0FBUztBQUNoQixZQUFRLElBQUksUUFBUTtBQUFBLEVBQ3RCLENBQUM7QUFDTDs7O0FDUk8sSUFBTSxlQUFlLENBQUNDLGFBQXFCO0FBQ2hELEVBQUFBLFNBQVEsUUFBUSxNQUFNLEVBQUUsWUFBWSxjQUFjO0FBQ3BEOzs7QUNGTyxJQUFNLGlCQUFpQixDQUFDQyxhQUFxQjtBQUNsRCxFQUFBQSxTQUFRLFFBQVEsUUFBUSxFQUFFLFlBQVksb0NBQW9DO0FBQzVFOzs7QUNETyxJQUFNLHNCQUFzQixDQUFDQyxhQUFxQjtBQUN2RCxFQUFBQSxTQUFRLFNBQ0wsS0FBSyxDQUFDLE1BQU0sRUFBRSxLQUFLLE1BQU0sUUFBUSxFQUNqQyxRQUFRLE9BQU8sRUFDZixZQUFZLDBCQUEwQixFQUN0QyxPQUFPLE1BQU07QUFDWixZQUFRLElBQUksS0FBSyxVQUFVLFVBQVUsS0FBSyxNQUFNLENBQUMsQ0FBQztBQUFBLEVBQ3BELENBQUM7QUFDTDs7O0FDVEEsWUFBWUMsU0FBUTtBQUNwQixZQUFZQyxXQUFVO0FBRWYsSUFBTSxnQkFBZ0IsQ0FBQ0MsYUFBcUI7QUFDakQsRUFBQUEsU0FDRyxRQUFRLE9BQU8sRUFDZixZQUFZLG1DQUFtQyxFQUMvQyxTQUFTLGFBQWEsNENBQTRDLEVBQ2xFLE9BQU8sT0FBTyxnQkFBd0I7QUFDckMsUUFBSTtBQUNKLFFBQUk7QUFDSixRQUFJLENBQUMsWUFBWSxXQUFXLFFBQVEsS0FBSyxZQUFZLFNBQVMsR0FBRyxHQUFHO0FBQ2xFO0FBQUMsT0FBQyxRQUFRLFdBQVcsSUFBSSxZQUFZLE1BQU0sR0FBRztBQUFBLElBQ2hELE9BQU87QUFDTCxZQUFNLGNBQWMsWUFBWSxRQUFRLFVBQVUsRUFBRTtBQUNwRCxZQUFNLGdCQUFnQixZQUFZLFFBQVEsR0FBRztBQUM3QyxlQUFTLFlBQVksTUFBTSxHQUFHLGFBQWE7QUFDM0Msb0JBQWMsWUFBWSxNQUFNLGdCQUFnQixDQUFDO0FBQUEsSUFDbkQ7QUFFQSxRQUFJLENBQUMsVUFBVSxDQUFDLGFBQWE7QUFDM0IsY0FBUTtBQUFBLFFBQ047QUFBQSxNQUNGO0FBQ0EsY0FBUSxLQUFLLENBQUM7QUFBQSxJQUNoQjtBQUVBLFVBQU1DLE1BQUssTUFBTTtBQUVqQixRQUFJO0FBQ0YsY0FBUSxJQUFJLFdBQVcsTUFBTSxJQUFJLFdBQVcsS0FBSztBQUVqRCxZQUFNLGtCQUFrQixNQUFNQSxJQUMzQixLQU9FLHNCQUFzQjtBQUFBLFFBQ3ZCLE1BQU07QUFBQSxVQUNKLGNBQWMsR0FBRyxNQUFNLElBQUksV0FBVztBQUFBLFVBQ3RDLG9CQUFvQjtBQUFBLFFBQ3RCO0FBQUEsTUFDRixDQUFDLEVBQ0EsS0FBSztBQUdSLFlBQU0sVUFBVSxLQUFLLE1BQU0sSUFBSSxXQUFXO0FBQzFDLFVBQUksQ0FBSSxlQUFXLE9BQU8sR0FBRztBQUMzQixRQUFHLGNBQVUsT0FBTztBQUFBLE1BQ3RCO0FBR0EsaUJBQVcsWUFBWSxnQkFBZ0IsZUFBZTtBQUNwRCxjQUFNLFdBQVcsU0FBUyxVQUFVLFdBQVcsR0FBRyxJQUM5QyxTQUFTLFVBQVUsTUFBTSxDQUFDLElBQzFCLFNBQVM7QUFFYixZQUFJLFNBQVMsV0FBVyxPQUFPLEVBQUc7QUFFbEMsY0FBTSxjQUFjLE1BQU1BLElBQ3ZCLEtBSUUscUJBQXFCO0FBQUEsVUFDdEIsTUFBTTtBQUFBLFlBQ0osY0FBYyxHQUFHLE1BQU0sSUFBSSxXQUFXO0FBQUEsWUFDdEMsV0FBVyxTQUFTO0FBQUEsVUFDdEI7QUFBQSxRQUNGLENBQUMsRUFDQSxLQUFLO0FBRVIsY0FBTSxXQUFnQixXQUFLLFNBQVMsUUFBUTtBQUM1QyxjQUFNLFVBQWUsY0FBUSxRQUFRO0FBR3JDLFlBQUksQ0FBSSxlQUFXLE9BQU8sR0FBRztBQUMzQixVQUFHLGNBQVUsU0FBUyxFQUFFLFdBQVcsS0FBSyxDQUFDO0FBQUEsUUFDM0M7QUFFQSxRQUFHLGtCQUFjLFVBQVUsWUFBWSxhQUFhLFlBQVk7QUFBQSxNQUNsRTtBQUVBLGNBQVEsSUFBSSw0QkFBNEIsTUFBTSxJQUFJLFdBQVcsR0FBRztBQUFBLElBQ2xFLFNBQVMsT0FBTztBQUNkLFVBQUksaUJBQWlCLE9BQU87QUFDMUIsZ0JBQVEsTUFBTSw0QkFBNEIsTUFBTSxPQUFPO0FBQUEsTUFDekQsT0FBTztBQUNMLGdCQUFRLE1BQU0sNEJBQTRCLEtBQUs7QUFBQSxNQUNqRDtBQUNBLGNBQVEsS0FBSyxDQUFDO0FBQUEsSUFDaEI7QUFBQSxFQUNGLENBQUM7QUFDTDs7O0FmekZBLFNBQVMsa0JBQWtCO0FBRzNCLElBQU0sVUFBVSxJQUFJLFFBQVE7QUFFNUIsUUFDRyxLQUFLLE1BQU0sRUFDWCxZQUFZLHVDQUF1QyxFQUNuRCxRQUFRLGdCQUFJLE9BQU87QUFFdEIsWUFBWSxPQUFPO0FBQ25CLGNBQWMsT0FBTztBQUVyQixhQUFhLE9BQU87QUFDcEIsa0JBQWtCLE9BQU87QUFDekIsbUJBQW1CLE9BQU87QUFFMUIsZUFBZSxPQUFPO0FBQ3RCLG9CQUFvQixPQUFPO0FBRTNCLElBQUksUUFBUSxLQUFLLFdBQVcsR0FBRztBQUM3QixhQUFXLFNBQVMsUUFBUSxJQUFJO0FBQ2xDLE9BQU87QUFDTCxVQUFRLE1BQU07QUFDaEI7IiwKICAibmFtZXMiOiBbInBhdGgiLCAiZnMiLCAiY3JlYXRlU2VydmVyIiwgInJlc29sdmUiLCAicGF0aCIsICJmcyIsICJmcyIsICJwYXRoIiwgInRzIiwgInByb2dyYW0iLCAiY3JlYXRlU2VydmVyIiwgImZpbGUiLCAicHJvZ3JhbSIsICJreSIsICJwcm9ncmFtIiwgInByb2dyYW0iLCAicHJvZ3JhbSIsICJwcm9ncmFtIiwgImZzIiwgInBhdGgiLCAicHJvZ3JhbSIsICJreSJdCn0K
|
|
575
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vY2xpL21haW4udHMiLCAiLi4vY2xpL2Rldi9yZWdpc3Rlci50cyIsICIuLi9saWIvZGVwZW5kZW5jeS1hbmFseXNpcy9pbnN0YWxsTm9kZU1vZHVsZVR5cGVzRm9yU25pcHBldC50cyIsICIuLi9jbGkvZGV2L0RldlNlcnZlci50cyIsICIuLi9saWIvc2VydmVyL2NyZWF0ZUh0dHBTZXJ2ZXIudHMiLCAiLi4vcGFja2FnZS5qc29uIiwgIi4uL2xpYi9zaXRlL2dldEluZGV4LnRzIiwgIi4uL2xpYi9zZXJ2ZXIvRXZlbnRzV2F0Y2hlci50cyIsICIuLi9saWIvY2xpLWNvbmZpZy9pbmRleC50cyIsICIuLi9jbGkvYXV0aC9sb2dpbi9yZWdpc3Rlci50cyIsICIuLi9saWIvcmVnaXN0cnktYXBpL2dldC1reS50cyIsICIuLi9jbGkvYXV0aC9sb2dvdXQvcmVnaXN0ZXIudHMiLCAiLi4vY2xpL2F1dGgvcmVnaXN0ZXIudHMiLCAiLi4vY2xpL2NvbmZpZy9yZWdpc3Rlci50cyIsICIuLi9jbGkvY29uZmlnL3ByaW50L3JlZ2lzdGVyLnRzIiwgIi4uL2NsaS9jbG9uZS9yZWdpc3Rlci50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiIyEvdXNyL2Jpbi9lbnYgbm9kZVxuaW1wb3J0IHsgQ29tbWFuZCB9IGZyb20gXCJjb21tYW5kZXJcIlxuaW1wb3J0IHsgcmVnaXN0ZXJEZXYgfSBmcm9tIFwiLi9kZXYvcmVnaXN0ZXJcIlxuaW1wb3J0IHsgcmVnaXN0ZXJBdXRoTG9naW4gfSBmcm9tIFwiLi9hdXRoL2xvZ2luL3JlZ2lzdGVyXCJcbmltcG9ydCB7IHJlZ2lzdGVyQXV0aExvZ291dCB9IGZyb20gXCIuL2F1dGgvbG9nb3V0L3JlZ2lzdGVyXCJcbmltcG9ydCB7IHJlZ2lzdGVyQXV0aCB9IGZyb20gXCIuL2F1dGgvcmVnaXN0ZXJcIlxuaW1wb3J0IHsgcmVnaXN0ZXJDb25maWcgfSBmcm9tIFwiLi9jb25maWcvcmVnaXN0ZXJcIlxuaW1wb3J0IHsgcmVnaXN0ZXJDb25maWdQcmludCB9IGZyb20gXCIuL2NvbmZpZy9wcmludC9yZWdpc3RlclwiXG5pbXBvcnQgeyByZWdpc3RlckNsb25lIH0gZnJvbSBcIi4vY2xvbmUvcmVnaXN0ZXJcIlxuaW1wb3J0IHsgcGVyZmVjdENsaSB9IGZyb20gXCJwZXJmZWN0LWNsaVwiXG5pbXBvcnQgcGtnIGZyb20gXCIuLi9wYWNrYWdlLmpzb25cIlxuXG5jb25zdCBwcm9ncmFtID0gbmV3IENvbW1hbmQoKVxuXG5wcm9ncmFtXG4gIC5uYW1lKFwidHNjaVwiKVxuICAuZGVzY3JpcHRpb24oXCJDTEkgZm9yIGRldmVsb3BpbmcgdHNjaXJjdWl0IHNuaXBwZXRzXCIpXG4gIC52ZXJzaW9uKHBrZy52ZXJzaW9uKVxuXG5yZWdpc3RlckRldihwcm9ncmFtKVxucmVnaXN0ZXJDbG9uZShwcm9ncmFtKVxuXG5yZWdpc3RlckF1dGgocHJvZ3JhbSlcbnJlZ2lzdGVyQXV0aExvZ2luKHByb2dyYW0pXG5yZWdpc3RlckF1dGhMb2dvdXQocHJvZ3JhbSlcblxucmVnaXN0ZXJDb25maWcocHJvZ3JhbSlcbnJlZ2lzdGVyQ29uZmlnUHJpbnQocHJvZ3JhbSlcblxuaWYgKHByb2Nlc3MuYXJndi5sZW5ndGggPT09IDIpIHtcbiAgcGVyZmVjdENsaShwcm9ncmFtLCBwcm9jZXNzLmFyZ3YpXG59IGVsc2Uge1xuICBwcm9ncmFtLnBhcnNlKClcbn1cbiIsICJpbXBvcnQgdHlwZSB7IENvbW1hbmQgfSBmcm9tIFwiY29tbWFuZGVyXCJcbmltcG9ydCAqIGFzIHBhdGggZnJvbSBcIm5vZGU6cGF0aFwiXG5pbXBvcnQgKiBhcyBjaG9raWRhciBmcm9tIFwiY2hva2lkYXJcIlxuaW1wb3J0ICogYXMgZnMgZnJvbSBcIm5vZGU6ZnNcIlxuaW1wb3J0IHsgY3JlYXRlSHR0cFNlcnZlciB9IGZyb20gXCJsaWIvc2VydmVyL2NyZWF0ZUh0dHBTZXJ2ZXJcIlxuaW1wb3J0IHsgZ2V0TG9jYWxGaWxlRGVwZW5kZW5jaWVzIH0gZnJvbSBcImxpYi9kZXBlbmRlbmN5LWFuYWx5c2lzL2dldExvY2FsRmlsZURlcGVuZGVuY2llc1wiXG5pbXBvcnQgeyBpbnN0YWxsTm9kZU1vZHVsZVR5cGVzRm9yU25pcHBldCB9IGZyb20gXCIuLi8uLi9saWIvZGVwZW5kZW5jeS1hbmFseXNpcy9pbnN0YWxsTm9kZU1vZHVsZVR5cGVzRm9yU25pcHBldFwiXG5pbXBvcnQgeyBFdmVudHNXYXRjaGVyIH0gZnJvbSBcIi4uLy4uL2xpYi9zZXJ2ZXIvRXZlbnRzV2F0Y2hlclwiXG5pbXBvcnQgeyBEZXZTZXJ2ZXIgfSBmcm9tIFwiLi9EZXZTZXJ2ZXJcIlxuXG5leHBvcnQgY29uc3QgcmVnaXN0ZXJEZXYgPSAocHJvZ3JhbTogQ29tbWFuZCkgPT4ge1xuICBwcm9ncmFtXG4gICAgLmNvbW1hbmQoXCJkZXZcIilcbiAgICAuZGVzY3JpcHRpb24oXCJTdGFydCBkZXZlbG9wbWVudCBzZXJ2ZXIgZm9yIGEgc25pcHBldFwiKVxuICAgIC5hcmd1bWVudChcIjxmaWxlPlwiLCBcIlBhdGggdG8gdGhlIHNuaXBwZXQgZmlsZVwiKVxuICAgIC5vcHRpb24oXCItcCwgLS1wb3J0IDxudW1iZXI+XCIsIFwiUG9ydCB0byBydW4gc2VydmVyIG9uXCIsIFwiMzAwMFwiKVxuICAgIC5hY3Rpb24oYXN5bmMgKGZpbGU6IHN0cmluZywgb3B0aW9uczogeyBwb3J0OiBzdHJpbmcgfSkgPT4ge1xuICAgICAgY29uc3QgYWJzb2x1dGVQYXRoID0gcGF0aC5yZXNvbHZlKGZpbGUpXG4gICAgICBjb25zdCBmaWxlRGlyID0gcGF0aC5kaXJuYW1lKGFic29sdXRlUGF0aClcbiAgICAgIGNvbnN0IHBvcnQgPSBwYXJzZUludChvcHRpb25zLnBvcnQpXG5cbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnNvbGUubG9nKFwiSW5zdGFsbGluZyB0eXBlcyBmb3IgaW1wb3J0ZWQgc25pcHBldHMuLi5cIilcbiAgICAgICAgYXdhaXQgaW5zdGFsbE5vZGVNb2R1bGVUeXBlc0ZvclNuaXBwZXQoYWJzb2x1dGVQYXRoKVxuICAgICAgICBjb25zb2xlLmxvZyhcIlR5cGVzIGluc3RhbGxlZCBzdWNjZXNzZnVsbHlcIilcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGNvbnNvbGUud2FybihcIkZhaWxlZCB0byBpbnN0YWxsIHR5cGVzOlwiLCBlcnJvcilcbiAgICAgIH1cblxuICAgICAgY29uc3Qgc2VydmVyID0gbmV3IERldlNlcnZlcih7XG4gICAgICAgIHBvcnQsXG4gICAgICAgIGNvbXBvbmVudEZpbGVQYXRoOiBhYnNvbHV0ZVBhdGgsXG4gICAgICB9KVxuXG4gICAgICBhd2FpdCBzZXJ2ZXIuc3RhcnQoKVxuICAgICAgYXdhaXQgc2VydmVyLmFkZEVudHJ5cG9pbnQoKVxuICAgIH0pXG59XG4iLCAiaW1wb3J0ICogYXMgZnMgZnJvbSBcIm5vZGU6ZnNcIlxuaW1wb3J0ICogYXMgcGF0aCBmcm9tIFwibm9kZTpwYXRoXCJcbmltcG9ydCAqIGFzIHRzIGZyb20gXCJ0eXBlc2NyaXB0XCJcblxuaW50ZXJmYWNlIFNuaXBwZXRBcGlSZXNwb25zZSB7XG4gIHNuaXBwZXQ6IHtcbiAgICBkdHM6IHN0cmluZ1xuICB9XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBpbnN0YWxsTm9kZU1vZHVsZVR5cGVzRm9yU25pcHBldChzbmlwcGV0UGF0aDogc3RyaW5nKSB7XG4gIGNvbnN0IGNvbnRlbnQgPSBmcy5yZWFkRmlsZVN5bmMoc25pcHBldFBhdGgsIFwidXRmLThcIilcbiAgY29uc3Qgc291cmNlRmlsZSA9IHRzLmNyZWF0ZVNvdXJjZUZpbGUoXG4gICAgc25pcHBldFBhdGgsXG4gICAgY29udGVudCxcbiAgICB0cy5TY3JpcHRUYXJnZXQuTGF0ZXN0LFxuICAgIHRydWUsXG4gIClcblxuICBjb25zdCBpbXBvcnRzOiBzdHJpbmdbXSA9IFtdXG5cbiAgZnVuY3Rpb24gdmlzaXQobm9kZTogdHMuTm9kZSkge1xuICAgIGlmICh0cy5pc0ltcG9ydERlY2xhcmF0aW9uKG5vZGUpKSB7XG4gICAgICBjb25zdCBtb2R1bGVTcGVjaWZpZXIgPSBub2RlLm1vZHVsZVNwZWNpZmllclxuICAgICAgaWYgKG1vZHVsZVNwZWNpZmllciAmJiB0cy5pc1N0cmluZ0xpdGVyYWwobW9kdWxlU3BlY2lmaWVyKSkge1xuICAgICAgICBjb25zdCBpbXBvcnRQYXRoID0gbW9kdWxlU3BlY2lmaWVyLnRleHRcbiAgICAgICAgaWYgKGltcG9ydFBhdGguc3RhcnRzV2l0aChcIkB0c2NpL1wiKSkge1xuICAgICAgICAgIGltcG9ydHMucHVzaChpbXBvcnRQYXRoKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIHRzLmZvckVhY2hDaGlsZChub2RlLCB2aXNpdClcbiAgfVxuXG4gIHZpc2l0KHNvdXJjZUZpbGUpXG5cbiAgbGV0IHByb2plY3RSb290ID0gcGF0aC5kaXJuYW1lKHNuaXBwZXRQYXRoKVxuICB3aGlsZSAocHJvamVjdFJvb3QgIT09IHBhdGgucGFyc2UocHJvamVjdFJvb3QpLnJvb3QpIHtcbiAgICBpZiAoZnMuZXhpc3RzU3luYyhwYXRoLmpvaW4ocHJvamVjdFJvb3QsIFwicGFja2FnZS5qc29uXCIpKSkge1xuICAgICAgYnJlYWtcbiAgICB9XG4gICAgcHJvamVjdFJvb3QgPSBwYXRoLmRpcm5hbWUocHJvamVjdFJvb3QpXG4gIH1cblxuICBmb3IgKGNvbnN0IGltcG9ydFBhdGggb2YgaW1wb3J0cykge1xuICAgIGNvbnN0IFtvd25lciwgbmFtZV0gPSBpbXBvcnRQYXRoLnJlcGxhY2UoXCJAdHNjaS9cIiwgXCJcIikuc3BsaXQoXCIuXCIpXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goXG4gICAgICAgIGBodHRwczovL3JlZ2lzdHJ5LWFwaS50c2NpcmN1aXQuY29tL3NuaXBwZXRzL2dldD9vd25lcl9uYW1lPSR7b3duZXJ9JnVuc2NvcGVkX25hbWU9JHtuYW1lfWAsXG4gICAgICApXG5cbiAgICAgIGlmICghcmVzcG9uc2Uub2spIHtcbiAgICAgICAgY29uc29sZS53YXJuKGBGYWlsZWQgdG8gZmV0Y2ggdHlwZXMgZm9yICR7aW1wb3J0UGF0aH1gKVxuICAgICAgICBjb250aW51ZVxuICAgICAgfVxuXG4gICAgICBjb25zdCBkYXRhOiBTbmlwcGV0QXBpUmVzcG9uc2UgPSBhd2FpdCByZXNwb25zZS5qc29uKClcblxuICAgICAgaWYgKGRhdGEuc25pcHBldC5kdHMpIHtcbiAgICAgICAgY29uc3QgcGFja2FnZURpciA9IHBhdGguam9pbihcbiAgICAgICAgICBwcm9qZWN0Um9vdCxcbiAgICAgICAgICBcIm5vZGVfbW9kdWxlc1wiLFxuICAgICAgICAgIFwiQHRzY2lcIixcbiAgICAgICAgICBgJHtvd25lcn0uJHtuYW1lfWAsXG4gICAgICAgIClcbiAgICAgICAgZnMubWtkaXJTeW5jKHBhY2thZ2VEaXIsIHsgcmVjdXJzaXZlOiB0cnVlIH0pXG5cbiAgICAgICAgZnMud3JpdGVGaWxlU3luYyhwYXRoLmpvaW4ocGFja2FnZURpciwgXCJpbmRleC5kLnRzXCIpLCBkYXRhLnNuaXBwZXQuZHRzKVxuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zb2xlLndhcm4oYEVycm9yIGZldGNoaW5nIHR5cGVzIGZvciAke2ltcG9ydFBhdGh9OmAsIGVycm9yKVxuICAgIH1cbiAgfVxufVxuIiwgImltcG9ydCBreSBmcm9tIFwia3lcIlxuaW1wb3J0IHR5cGUgeyBGaWxlU2VydmVyUm91dGVzIH0gZnJvbSBcImxpYi9maWxlLXNlcnZlci9GaWxlU2VydmVyUm91dGVzXCJcbmltcG9ydCB7IGNyZWF0ZUh0dHBTZXJ2ZXIgfSBmcm9tIFwibGliL3NlcnZlci9jcmVhdGVIdHRwU2VydmVyXCJcbmltcG9ydCB7IEV2ZW50c1dhdGNoZXIgfSBmcm9tIFwibGliL3NlcnZlci9FdmVudHNXYXRjaGVyXCJcbmltcG9ydCB0eXBlIGh0dHAgZnJvbSBcIm5vZGU6aHR0cFwiXG5pbXBvcnQgdHlwZSB7IFR5cGVkS3lJbnN0YW5jZSB9IGZyb20gXCJ0eXBlZC1reVwiXG5pbXBvcnQgcGF0aCBmcm9tIFwibm9kZTpwYXRoXCJcbmltcG9ydCBmcyBmcm9tIFwibm9kZTpmc1wiXG5pbXBvcnQgdHlwZSB7IEZpbGVVcGRhdGVkRXZlbnQgfSBmcm9tIFwibGliL2ZpbGUtc2VydmVyL0ZpbGVTZXJ2ZXJFdmVudFwiXG5pbXBvcnQgKiBhcyBjaG9raWRhciBmcm9tIFwiY2hva2lkYXJcIlxuXG5leHBvcnQgY2xhc3MgRGV2U2VydmVyIHtcbiAgcG9ydDogbnVtYmVyXG4gIC8qKlxuICAgKiBUaGUgcGF0aCB0byBhIGNvbXBvbmVudCB0aGF0IGV4cG9ydHMgYSA8Ym9hcmQgLz4gb3IgPGdyb3VwIC8+IGNvbXBvbmVudFxuICAgKi9cbiAgY29tcG9uZW50RmlsZVBhdGg6IHN0cmluZ1xuXG4gIHByb2plY3REaXI6IHN0cmluZ1xuXG4gIC8qKlxuICAgKiBUaGUgSFRUUCBzZXJ2ZXIgdGhhdCBob3N0cyB0aGUgZmlsZSBzZXJ2ZXIgYW5kIGV2ZW50IGJ1cy4gWW91IGNhbiB1c2VcbiAgICogZnNLeSB0byBjb21tdW5pY2F0ZSB3aXRoIHRoZSBmaWxlIHNlcnZlci9ldmVudCBidXNcbiAgICovXG4gIGh0dHBTZXJ2ZXI/OiBodHRwLlNlcnZlclxuICAvKipcbiAgICogV2F0Y2hlcyBmb3IgZXZlbnRzIG9uIHRoZSBldmVudCBidXMgYnkgcG9sbGluZyBgYXBpL2V2ZW50cy9saXN0YFxuICAgKi9cbiAgZXZlbnRzV2F0Y2hlcj86IEV2ZW50c1dhdGNoZXJcbiAgLyoqXG4gICAqIEEga3kgaW5zdGFuY2UgdGhhdCBjYW4gYmUgdXNlZCB0byBjb21tdW5pY2F0ZSB3aXRoIHRoZSBmaWxlIHNlcnZlciBhbmRcbiAgICogZXZlbnQgYnVzXG4gICAqL1xuICBmc0t5OiBUeXBlZEt5SW5zdGFuY2U8a2V5b2YgRmlsZVNlcnZlclJvdXRlcywgRmlsZVNlcnZlclJvdXRlcz5cbiAgLyoqXG4gICAqIEEgY2hva2lkYXIgaW5zdGFuY2UgdGhhdCB3YXRjaGVzIHRoZSBwcm9qZWN0IGRpcmVjdG9yeSBmb3IgZmlsZSBjaGFuZ2VzXG4gICAqL1xuICBmaWxlc3lzdGVtV2F0Y2hlcj86IGNob2tpZGFyLkZTV2F0Y2hlclxuXG4gIGNvbnN0cnVjdG9yKHtcbiAgICBwb3J0LFxuICAgIGNvbXBvbmVudEZpbGVQYXRoLFxuICB9OiB7XG4gICAgcG9ydDogbnVtYmVyXG4gICAgY29tcG9uZW50RmlsZVBhdGg6IHN0cmluZ1xuICB9KSB7XG4gICAgdGhpcy5wb3J0ID0gcG9ydFxuICAgIHRoaXMuY29tcG9uZW50RmlsZVBhdGggPSBjb21wb25lbnRGaWxlUGF0aFxuICAgIHRoaXMucHJvamVjdERpciA9IHBhdGguZGlybmFtZShjb21wb25lbnRGaWxlUGF0aClcbiAgICB0aGlzLmZzS3kgPSBreS5jcmVhdGUoe1xuICAgICAgcHJlZml4VXJsOiBgaHR0cDovL2xvY2FsaG9zdDoke3BvcnR9YCxcbiAgICB9KSBhcyBhbnlcbiAgfVxuXG4gIGFzeW5jIHN0YXJ0KCkge1xuICAgIGNvbnN0IHsgc2VydmVyIH0gPSBhd2FpdCBjcmVhdGVIdHRwU2VydmVyKHRoaXMucG9ydClcbiAgICB0aGlzLmh0dHBTZXJ2ZXIgPSBzZXJ2ZXJcblxuICAgIHRoaXMuZXZlbnRzV2F0Y2hlciA9IG5ldyBFdmVudHNXYXRjaGVyKGBodHRwOi8vbG9jYWxob3N0OiR7dGhpcy5wb3J0fWApXG4gICAgdGhpcy5ldmVudHNXYXRjaGVyLnN0YXJ0KClcblxuICAgIHRoaXMuZXZlbnRzV2F0Y2hlci5vbihcbiAgICAgIFwiRklMRV9VUERBVEVEXCIsXG4gICAgICB0aGlzLmhhbmRsZUZpbGVVcGRhdGVkRXZlbnRGcm9tU2VydmVyLmJpbmQodGhpcyksXG4gICAgKVxuXG4gICAgdGhpcy5maWxlc3lzdGVtV2F0Y2hlciA9IGNob2tpZGFyLndhdGNoKHRoaXMucHJvamVjdERpciwge1xuICAgICAgcGVyc2lzdGVudDogdHJ1ZSxcbiAgICAgIGlnbm9yZUluaXRpYWw6IHRydWUsXG4gICAgfSlcblxuICAgIHRoaXMuZmlsZXN5c3RlbVdhdGNoZXIub24oXCJjaGFuZ2VcIiwgKGZpbGVQYXRoKSA9PlxuICAgICAgdGhpcy5oYW5kbGVGaWxlQ2hhbmdlZE9uRmlsZXN5c3RlbShmaWxlUGF0aCksXG4gICAgKVxuICAgIHRoaXMuZmlsZXN5c3RlbVdhdGNoZXIub24oXCJhZGRcIiwgKGZpbGVQYXRoKSA9PlxuICAgICAgdGhpcy5oYW5kbGVGaWxlQ2hhbmdlZE9uRmlsZXN5c3RlbShmaWxlUGF0aCksXG4gICAgKVxuXG4gICAgdGhpcy51cHNlcnRJbml0aWFsRmlsZXMoKVxuICB9XG5cbiAgYXN5bmMgYWRkRW50cnlwb2ludCgpIHtcbiAgICBjb25zdCByZWxhdGl2ZUNvbXBvbmVudEZpbGVQYXRoID0gcGF0aC5yZWxhdGl2ZShcbiAgICAgIHRoaXMucHJvamVjdERpcixcbiAgICAgIHRoaXMuY29tcG9uZW50RmlsZVBhdGgsXG4gICAgKVxuICAgIGF3YWl0IHRoaXMuZnNLeS5wb3N0KFwiYXBpL2ZpbGVzL3Vwc2VydFwiLCB7XG4gICAgICBqc29uOiB7XG4gICAgICAgIGZpbGVfcGF0aDogXCJlbnRyeXBvaW50LnRzeFwiLFxuICAgICAgICB0ZXh0X2NvbnRlbnQ6IGBcbmltcG9ydCBNeUNpcmN1aXQgZnJvbSBcIi4vJHtyZWxhdGl2ZUNvbXBvbmVudEZpbGVQYXRofVwiXG5cbmNpcmN1aXQuYWRkKDxNeUNpcmN1aXQgLz4pXG5gLFxuICAgICAgfSxcbiAgICB9KVxuICB9XG5cbiAgYXN5bmMgaGFuZGxlRmlsZVVwZGF0ZWRFdmVudEZyb21TZXJ2ZXIoZXY6IEZpbGVVcGRhdGVkRXZlbnQpIHtcbiAgICBpZiAoZXYuaW5pdGlhdG9yID09PSBcImZpbGVzeXN0ZW1fY2hhbmdlXCIpIHJldHVyblxuXG4gICAgaWYgKGV2LmZpbGVfcGF0aCA9PT0gXCJtYW51YWwtZWRpdHMuanNvblwiKSB7XG4gICAgICBjb25zb2xlLmxvZyhcIk1hbnVhbCBlZGl0cyB1cGRhdGVkLCB1cGRhdGluZyBvbiBmaWxlc3lzdGVtLi4uXCIpXG4gICAgICBjb25zdCB7IGZpbGUgfSA9IGF3YWl0IHRoaXMuZnNLeVxuICAgICAgICAuZ2V0KFwiYXBpL2ZpbGVzL2dldFwiLCB7XG4gICAgICAgICAgc2VhcmNoUGFyYW1zOiB7IGZpbGVfcGF0aDogZXYuZmlsZV9wYXRoIH0sXG4gICAgICAgIH0pXG4gICAgICAgIC5qc29uKClcbiAgICAgIGZzLndyaXRlRmlsZVN5bmMoXG4gICAgICAgIHBhdGguam9pbih0aGlzLnByb2plY3REaXIsIFwibWFudWFsLWVkaXRzLmpzb25cIiksXG4gICAgICAgIGZpbGUudGV4dF9jb250ZW50LFxuICAgICAgKVxuICAgIH1cbiAgfVxuXG4gIGFzeW5jIGhhbmRsZUZpbGVDaGFuZ2VkT25GaWxlc3lzdGVtKGFic29sdXRlRmlsZVBhdGg6IHN0cmluZykge1xuICAgIGNvbnN0IHJlbGF0aXZlRmlsZVBhdGggPSBwYXRoLnJlbGF0aXZlKHRoaXMucHJvamVjdERpciwgYWJzb2x1dGVGaWxlUGF0aClcblxuICAgIC8vIFdlJ3ZlIHRlbXBvcmFyaWx5IGRpc2FibGVkIHVwc2VydGluZyBtYW51YWwgZWRpdHMgZnJvbSBmaWxlc3lzdGVtIGNoYW5nZXNcbiAgICAvLyBiZWNhdXNlIGl0IGNhbiBiZSBlZGl0ZWQgYnkgdGhlIGJyb3dzZXJcbiAgICBpZiAocmVsYXRpdmVGaWxlUGF0aC5pbmNsdWRlcyhcIm1hbnVhbC1lZGl0cy5qc29uXCIpKSByZXR1cm5cblxuICAgIGF3YWl0IHRoaXMuZnNLeVxuICAgICAgLnBvc3QoXCJhcGkvZmlsZXMvdXBzZXJ0XCIsIHtcbiAgICAgICAganNvbjoge1xuICAgICAgICAgIGZpbGVfcGF0aDogcmVsYXRpdmVGaWxlUGF0aCxcbiAgICAgICAgICB0ZXh0X2NvbnRlbnQ6IGZzLnJlYWRGaWxlU3luYyhhYnNvbHV0ZUZpbGVQYXRoLCBcInV0Zi04XCIpLFxuICAgICAgICAgIGluaXRpYXRvcjogXCJmaWxlc3lzdGVtX2NoYW5nZVwiLFxuICAgICAgICB9LFxuICAgICAgfSlcbiAgICAgIC5qc29uKClcbiAgfVxuXG4gIGFzeW5jIHVwc2VydEluaXRpYWxGaWxlcygpIHtcbiAgICAvLyBTY2FuIHByb2plY3QgZGlyZWN0b3J5IGZvciBhbGwgZmlsZXMgYW5kIHVwc2VydCB0aGVtXG4gICAgY29uc3QgZmlsZU5hbWVzID0gZnMucmVhZGRpclN5bmModGhpcy5wcm9qZWN0RGlyKVxuICAgIGZvciAoY29uc3QgZmlsZU5hbWUgb2YgZmlsZU5hbWVzKSB7XG4gICAgICBhd2FpdCB0aGlzLmZzS3kucG9zdChcImFwaS9maWxlcy91cHNlcnRcIiwge1xuICAgICAgICBqc29uOiB7XG4gICAgICAgICAgZmlsZV9wYXRoOiBmaWxlTmFtZSxcbiAgICAgICAgICB0ZXh0X2NvbnRlbnQ6IGZzLnJlYWRGaWxlU3luYyhcbiAgICAgICAgICAgIHBhdGguam9pbih0aGlzLnByb2plY3REaXIsIGZpbGVOYW1lKSxcbiAgICAgICAgICAgIFwidXRmLThcIixcbiAgICAgICAgICApLFxuICAgICAgICAgIGluaXRpYXRvcjogXCJmaWxlc3lzdGVtX2NoYW5nZVwiLFxuICAgICAgICB9LFxuICAgICAgfSlcbiAgICB9XG4gIH1cblxuICBhc3luYyBzdG9wKCkge1xuICAgIHRoaXMuaHR0cFNlcnZlcj8uY2xvc2UoKVxuICAgIHRoaXMuZXZlbnRzV2F0Y2hlcj8uc3RvcCgpXG4gIH1cbn1cbiIsICJpbXBvcnQgKiBhcyBodHRwIGZyb20gXCJub2RlOmh0dHBcIlxuaW1wb3J0ICogYXMgZnMgZnJvbSBcIm5vZGU6ZnNcIlxuaW1wb3J0ICogYXMgcGF0aCBmcm9tIFwibm9kZTpwYXRoXCJcbmltcG9ydCB7IGdldE5vZGVIYW5kbGVyIH0gZnJvbSBcIndpbnRlcnNwZWMvYWRhcHRlcnMvbm9kZVwiXG5pbXBvcnQgcGtnIGZyb20gXCIuLi8uLi9wYWNrYWdlLmpzb25cIlxuXG4vLyBAdHMtaWdub3JlXG5pbXBvcnQgd2ludGVyc3BlY0J1bmRsZSBmcm9tIFwiQHRzY2lyY3VpdC9maWxlLXNlcnZlci9kaXN0L2J1bmRsZS5qc1wiXG5pbXBvcnQgeyBnZXRJbmRleCB9IGZyb20gXCIuLi9zaXRlL2dldEluZGV4XCJcblxuZXhwb3J0IGNvbnN0IGNyZWF0ZUh0dHBTZXJ2ZXIgPSBhc3luYyAocG9ydCA9IDMwMDApID0+IHtcbiAgY29uc3QgZmlsZVNlcnZlckhhbmRsZXIgPSBnZXROb2RlSGFuZGxlcih3aW50ZXJzcGVjQnVuZGxlIGFzIGFueSwge30pXG5cbiAgY29uc3Qgc2VydmVyID0gaHR0cC5jcmVhdGVTZXJ2ZXIoYXN5bmMgKHJlcSwgcmVzKSA9PiB7XG4gICAgY29uc3QgdXJsID0gbmV3IFVSTChyZXEudXJsISwgYGh0dHA6Ly8ke3JlcS5oZWFkZXJzLmhvc3R9YClcblxuICAgIGlmICh1cmwucGF0aG5hbWUgPT09IFwiL3N0YW5kYWxvbmUubWluLmpzXCIpIHtcbiAgICAgIGNvbnN0IHN0YW5kYWxvbmVGaWxlUGF0aCA9XG4gICAgICAgIHByb2Nlc3MuZW52LlJVTkZSQU1FX1NUQU5EQUxPTkVfRklMRV9QQVRIIHx8XG4gICAgICAgIHBhdGgucmVzb2x2ZShcbiAgICAgICAgICBwcm9jZXNzLmN3ZCgpLFxuICAgICAgICAgIFwibm9kZV9tb2R1bGVzXCIsXG4gICAgICAgICAgXCJAdHNjaXJjdWl0L3J1bmZyYW1lL2Rpc3Qvc3RhbmRhbG9uZS5taW4uanNcIixcbiAgICAgICAgKVxuXG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBjb250ZW50ID0gZnMucmVhZEZpbGVTeW5jKHN0YW5kYWxvbmVGaWxlUGF0aCwgXCJ1dGY4XCIpXG4gICAgICAgIHJlcy53cml0ZUhlYWQoMjAwLCB7XG4gICAgICAgICAgXCJDb250ZW50LVR5cGVcIjogXCJhcHBsaWNhdGlvbi9qYXZhc2NyaXB0OyBjaGFyc2V0PXV0Zi04XCIsXG4gICAgICAgIH0pXG4gICAgICAgIHJlcy5lbmQoY29udGVudClcbiAgICAgICAgcmV0dXJuXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBjb25zb2xlLmVycm9yKFwiRXJyb3Igc2VydmluZyBzdGFuZGFsb25lLm1pbi5qczpcIiwgZXJyb3IpXG4gICAgICB9XG5cbiAgICAgIHJlcy53cml0ZUhlYWQoMzAyLCB7XG4gICAgICAgIExvY2F0aW9uOiBgaHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L25wbS9AdHNjaXJjdWl0L3J1bmZyYW1lQCR7cGtnLmRlcGVuZGVuY2llc1tcIkB0c2NpcmN1aXQvcnVuZnJhbWVcIl0ucmVwbGFjZSgvXlteMC05XSsvLCBcIlwiKX0vZGlzdC9zdGFuZGFsb25lLm1pbi5qc2AsXG4gICAgICB9KVxuICAgICAgcmVzLmVuZCgpXG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICBpZiAodXJsLnBhdGhuYW1lID09PSBcIi9cIikge1xuICAgICAgY29uc3QgaHRtbCA9IGF3YWl0IGdldEluZGV4KClcbiAgICAgIHJlcy53cml0ZUhlYWQoMjAwLCB7IFwiQ29udGVudC1UeXBlXCI6IFwidGV4dC9odG1sXCIgfSlcbiAgICAgIHJlcy5lbmQoaHRtbClcbiAgICAgIHJldHVyblxuICAgIH1cblxuICAgIGlmICh1cmwucGF0aG5hbWUuc3RhcnRzV2l0aChcIi9hcGkvXCIpKSB7XG4gICAgICByZXEudXJsID0gcmVxLnVybCEucmVwbGFjZShcIi9hcGkvXCIsIFwiL1wiKVxuICAgICAgZmlsZVNlcnZlckhhbmRsZXIocmVxLCByZXMpXG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICByZXMud3JpdGVIZWFkKDQwNClcbiAgICByZXMuZW5kKFwiTm90IGZvdW5kXCIpXG4gIH0pXG5cbiAgcmV0dXJuIG5ldyBQcm9taXNlPHsgc2VydmVyOiBodHRwLlNlcnZlciB9PigocmVzb2x2ZSkgPT4ge1xuICAgIHNlcnZlci5saXN0ZW4ocG9ydCwgKCkgPT4ge1xuICAgICAgY29uc29sZS5sb2coYFNlcnZlciBydW5uaW5nIGF0IGh0dHA6Ly9sb2NhbGhvc3Q6JHtwb3J0fWApXG4gICAgICByZXNvbHZlKHsgc2VydmVyIH0pXG4gICAgfSlcbiAgfSlcbn1cbiIsICJ7XG4gIFwibmFtZVwiOiBcIkB0c2NpcmN1aXQvY2xpXCIsXG4gIFwibWFpblwiOiBcImRpc3QvbWFpbi5qc1wiLFxuICBcInR5cGVcIjogXCJtb2R1bGVcIixcbiAgXCJ2ZXJzaW9uXCI6IFwiMC4xLjRcIixcbiAgXCJiaW5cIjoge1xuICAgIFwidHNjaVwiOiBcIi4vZGlzdC9tYWluLmpzXCJcbiAgfSxcbiAgXCJzY3JpcHRzXCI6IHtcbiAgICBcInN0YXJ0XCI6IFwiYnVuIHJ1biBkZXZcIixcbiAgICBcImRldlwiOiBcImJ1biAtLWhvdCAuL2NsaS9tYWluLnRzIGRldiAuL2V4YW1wbGUtZGlyL3NuaXBwZXQudHN4XCIsXG4gICAgXCJidWlsZFwiOiBcInRzdXAtbm9kZSBjbGkvbWFpbi50cyAtLWZvcm1hdCBlc20gLS1zb3VyY2VtYXAgaW5saW5lXCIsXG4gICAgXCJmb3JtYXRcIjogXCJiaW9tZSBmb3JtYXQgLS13cml0ZSAuXCIsXG4gICAgXCJmb3JtYXQ6Y2hlY2tcIjogXCJiaW9tZSBmb3JtYXQgLlwiLFxuICAgIFwiY2xpXCI6IFwiYnVuIC4vY2xpL21haW4udHNcIlxuICB9LFxuICBcImRldkRlcGVuZGVuY2llc1wiOiB7XG4gICAgXCJAYmlvbWVqcy9iaW9tZVwiOiBcIl4xLjkuNFwiLFxuICAgIFwiQHRzY2lyY3VpdC9jb3JlXCI6IFwiXjAuMC4yNDlcIixcbiAgICBcIkB0eXBlcy9idW5cIjogXCJeMS4xLjE1XCIsXG4gICAgXCJAdHlwZXMvY29uZmlnc3RvcmVcIjogXCJeNi4wLjJcIixcbiAgICBcIkB0eXBlcy9yZWFjdFwiOiBcIl4xOS4wLjFcIixcbiAgICBcImdldC1wb3J0XCI6IFwiXjcuMS4wXCIsXG4gICAgXCJ0ZW1weVwiOiBcIl4zLjEuMFwiLFxuICAgIFwidHN1cFwiOiBcIl44LjMuNVwiLFxuICAgIFwidHlwZWQta3lcIjogXCJeMC4wLjRcIlxuICB9LFxuICBcInBlZXJEZXBlbmRlbmNpZXNcIjoge1xuICAgIFwidHlwZXNjcmlwdFwiOiBcIl41LjAuMFwiXG4gIH0sXG4gIFwiZGVwZW5kZW5jaWVzXCI6IHtcbiAgICBcIkB0c2NpcmN1aXQvZmlsZS1zZXJ2ZXJcIjogXCJeMC4wLjEzXCIsXG4gICAgXCJAdHNjaXJjdWl0L3J1bmZyYW1lXCI6IFwiXjAuMC40N1wiLFxuICAgIFwiY2hva2lkYXJcIjogXCJeNC4wLjFcIixcbiAgICBcImNvbW1hbmRlclwiOiBcIl4xMi4xLjBcIixcbiAgICBcImNvbmZpZ3N0b3JlXCI6IFwiXjcuMC4wXCIsXG4gICAgXCJjb3NtaWNvbmZpZ1wiOiBcIl45LjAuMFwiLFxuICAgIFwiZGVsYXlcIjogXCJeNi4wLjBcIixcbiAgICBcImt5XCI6IFwiXjEuNy40XCIsXG4gICAgXCJwZXJmZWN0LWNsaVwiOiBcIl4xLjAuMjBcIlxuICB9XG59XG4iLCAiaW1wb3J0IHBrZyBmcm9tIFwiLi4vLi4vcGFja2FnZS5qc29uXCJcblxuZXhwb3J0IGNvbnN0IGdldEluZGV4ID0gYXN5bmMgKCkgPT4ge1xuICByZXR1cm4gYDxodG1sPlxuICAgIDxoZWFkPlxuICAgIDwvaGVhZD5cbiAgICA8Ym9keT5cbiAgICAgIDxzY3JpcHQgc3JjPVwiaHR0cHM6Ly9jZG4udGFpbHdpbmRjc3MuY29tXCI+PC9zY3JpcHQ+XG4gICAgICA8ZGl2IGlkPVwicm9vdFwiPmxvYWRpbmcuLi48L2Rpdj5cbiAgICAgIDxzY3JpcHQ+XG4gICAgICBnbG9iYWxUaGlzLnByb2Nlc3MgPSB7IGVudjogeyBOT0RFX0VOVjogXCJwcm9kdWN0aW9uXCIgfSB9XG4gICAgICA8L3NjcmlwdD5cbiAgICAgIDxzY3JpcHQgc3JjPVwiL3N0YW5kYWxvbmUubWluLmpzXCI+PC9zY3JpcHQ+XG4gICAgPC9ib2R5PlxuICA8L2h0bWw+YFxufVxuXG4vLyA8c2NyaXB0IHNyYz1cImh0dHBzOi8vY2RuLmpzZGVsaXZyLm5ldC9ucG0vQHRzY2lyY3VpdC9ydW5mcmFtZUAke3BrZy5kZXBlbmRlbmNpZXNbXCJAdHNjaXJjdWl0L3J1bmZyYW1lXCJdLnJlcGxhY2UoL15bXjAtOV0rLywgXCJcIil9L2Rpc3Qvc3RhbmRhbG9uZS5taW4uanNcIj48L3NjcmlwdD5cbiIsICJpbXBvcnQgeyBFdmVudEVtaXR0ZXIgfSBmcm9tIFwiZXZlbnRzXCJcblxuaW50ZXJmYWNlIEV2ZW50IHtcbiAgZXZlbnRfaWQ6IHN0cmluZ1xuICBjcmVhdGVkX2F0OiBzdHJpbmdcbiAgZXZlbnRfdHlwZTogc3RyaW5nXG4gIFtrZXk6IHN0cmluZ106IGFueVxufVxuXG5pbnRlcmZhY2UgRXZlbnRzUmVzcG9uc2Uge1xuICBldmVudF9saXN0OiBFdmVudFtdXG59XG5cbmV4cG9ydCBjbGFzcyBFdmVudHNXYXRjaGVyIGV4dGVuZHMgRXZlbnRFbWl0dGVyIHtcbiAgcHJpdmF0ZSBsYXN0UG9sbFRpbWU6IHN0cmluZ1xuICBwcml2YXRlIHBvbGxJbnRlcnZhbDogbnVtYmVyXG4gIHByaXZhdGUgYmFzZVVybDogc3RyaW5nXG4gIHByaXZhdGUgcG9sbGluZyA9IGZhbHNlXG4gIHByaXZhdGUgdGltZW91dElkPzogTm9kZUpTLlRpbWVvdXRcblxuICBjb25zdHJ1Y3RvcihiYXNlVXJsID0gXCJodHRwOi8vbG9jYWxob3N0OjMwMDBcIiwgcG9sbEludGVydmFsID0gMTAwMCkge1xuICAgIHN1cGVyKClcbiAgICB0aGlzLmJhc2VVcmwgPSBiYXNlVXJsXG4gICAgdGhpcy5wb2xsSW50ZXJ2YWwgPSBwb2xsSW50ZXJ2YWxcbiAgICB0aGlzLmxhc3RQb2xsVGltZSA9IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKVxuICB9XG5cbiAgYXN5bmMgc3RhcnQoKSB7XG4gICAgaWYgKHRoaXMucG9sbGluZykgcmV0dXJuXG4gICAgdGhpcy5wb2xsaW5nID0gdHJ1ZVxuICAgIGF3YWl0IHRoaXMucG9sbCgpXG4gIH1cblxuICBzdG9wKCkge1xuICAgIHRoaXMucG9sbGluZyA9IGZhbHNlXG4gICAgaWYgKHRoaXMudGltZW91dElkKSB7XG4gICAgICBjbGVhclRpbWVvdXQodGhpcy50aW1lb3V0SWQpXG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBwb2xsKCkge1xuICAgIGlmICghdGhpcy5wb2xsaW5nKSByZXR1cm5cblxuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKFxuICAgICAgICBgJHt0aGlzLmJhc2VVcmx9L2FwaS9ldmVudHMvbGlzdD9zaW5jZT0ke2VuY29kZVVSSUNvbXBvbmVudCh0aGlzLmxhc3RQb2xsVGltZSl9YCxcbiAgICAgIClcblxuICAgICAgaWYgKCFyZXNwb25zZS5vaykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEhUVFAgZXJyb3IhIHN0YXR1czogJHtyZXNwb25zZS5zdGF0dXN9YClcbiAgICAgIH1cblxuICAgICAgY29uc3QgZGF0YTogRXZlbnRzUmVzcG9uc2UgPSBhd2FpdCByZXNwb25zZS5qc29uKClcblxuICAgICAgLy8gVXBkYXRlIGxhc3QgcG9sbCB0aW1lIHRvIGxhdGVzdCBldmVudCBvciBjdXJyZW50IHRpbWVcbiAgICAgIGNvbnN0IGxhdGVzdEV2ZW50ID0gZGF0YS5ldmVudF9saXN0W2RhdGEuZXZlbnRfbGlzdC5sZW5ndGggLSAxXVxuICAgICAgdGhpcy5sYXN0UG9sbFRpbWUgPSBsYXRlc3RFdmVudFxuICAgICAgICA/IGxhdGVzdEV2ZW50LmNyZWF0ZWRfYXRcbiAgICAgICAgOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKClcblxuICAgICAgLy8gRW1pdCBldmVudHMgaW4gY2hyb25vbG9naWNhbCBvcmRlclxuICAgICAgZGF0YS5ldmVudF9saXN0LmZvckVhY2goKGV2ZW50KSA9PiB7XG4gICAgICAgIHRoaXMuZW1pdChldmVudC5ldmVudF90eXBlLCBldmVudClcbiAgICAgICAgdGhpcy5lbWl0KFwiKlwiLCBldmVudClcbiAgICAgIH0pXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHRoaXMuZW1pdChcImVycm9yXCIsIGVycm9yKVxuICAgIH1cbiAgICAvLyBTY2hlZHVsZSBuZXh0IHBvbGxcbiAgICB0aGlzLnRpbWVvdXRJZCA9IGdsb2JhbFRoaXMuc2V0VGltZW91dChcbiAgICAgICgpID0+IHRoaXMucG9sbCgpLFxuICAgICAgdGhpcy5wb2xsSW50ZXJ2YWwsXG4gICAgKSBhcyB1bmtub3duIGFzIE5vZGVKUy5UaW1lb3V0XG4gIH1cbn1cbiIsICJpbXBvcnQgQ29uZmlnc3RvcmUgZnJvbSBcImNvbmZpZ3N0b3JlXCJcbmltcG9ydCB0eXBlIHsgVHlwZWRDb25maWdzdG9yZSB9IGZyb20gXCIuL1R5cGVkQ29uZmlnU3RvcmVcIlxuXG5leHBvcnQgaW50ZXJmYWNlIENsaUNvbmZpZyB7XG4gIHNlc3Npb25Ub2tlbj86IHN0cmluZ1xuICBnaXRodWJVc2VybmFtZT86IHN0cmluZ1xuICByZWdpc3RyeUFwaVVybD86IHN0cmluZ1xufVxuXG5leHBvcnQgY29uc3QgY2xpQ29uZmlnOiBUeXBlZENvbmZpZ3N0b3JlPENsaUNvbmZpZz4gPSBuZXcgQ29uZmlnc3RvcmUoXG4gIFwidHNjaXJjdWl0XCIsXG4pXG5cbmV4cG9ydCBjb25zdCBnZXRSZWdpc3RyeUFwaVVybCA9ICgpOiBzdHJpbmcgPT4ge1xuICByZXR1cm4gY2xpQ29uZmlnLmdldChcInJlZ2lzdHJ5QXBpVXJsXCIpID8/IFwiaHR0cHM6Ly9yZWdpc3RyeS1hcGkudHNjaXJjdWl0LmNvbVwiXG59XG4iLCAiaW1wb3J0IHR5cGUgeyBDb21tYW5kIH0gZnJvbSBcImNvbW1hbmRlclwiXG5pbXBvcnQgeyBjbGlDb25maWcgfSBmcm9tIFwibGliL2NsaS1jb25maWdcIlxuaW1wb3J0IGRlbGF5IGZyb20gXCJkZWxheVwiXG5pbXBvcnQgeyBnZXRLeSB9IGZyb20gXCJsaWIvcmVnaXN0cnktYXBpL2dldC1reVwiXG5pbXBvcnQgdHlwZSB7IEVuZHBvaW50UmVzcG9uc2UgfSBmcm9tIFwibGliL3JlZ2lzdHJ5LWFwaS9lbmRwb2ludC10eXBlc1wiXG5cbmV4cG9ydCBjb25zdCByZWdpc3RlckF1dGhMb2dpbiA9IChwcm9ncmFtOiBDb21tYW5kKSA9PiB7XG4gIHByb2dyYW0uY29tbWFuZHNcbiAgICAuZmluZCgoYykgPT4gYy5uYW1lKCkgPT09IFwiYXV0aFwiKSFcbiAgICAuY29tbWFuZChcImxvZ2luXCIpXG4gICAgLmRlc2NyaXB0aW9uKFwiQXV0aGVudGljYXRlIENMSSwgbG9naW4gdG8gcmVnaXN0cnlcIilcbiAgICAuYWN0aW9uKGFzeW5jIChhcmdzKSA9PiB7XG4gICAgICBjb25zdCBreSA9IGdldEt5KClcblxuICAgICAgY29uc3QgeyBsb2dpbl9wYWdlIH0gPSBhd2FpdCBreVxuICAgICAgICAucG9zdDxFbmRwb2ludFJlc3BvbnNlW1wic2Vzc2lvbnMvbG9naW5fcGFnZS9jcmVhdGVcIl0+KFxuICAgICAgICAgIFwic2Vzc2lvbnMvbG9naW5fcGFnZS9jcmVhdGVcIixcbiAgICAgICAgICB7XG4gICAgICAgICAgICBqc29uOiB7fSxcbiAgICAgICAgICB9LFxuICAgICAgICApXG4gICAgICAgIC5qc29uKClcblxuICAgICAgY29uc29sZS5sb2coXCJQbGVhc2UgdmlzaXQgdGhlIGZvbGxvd2luZyBVUkwgdG8gbG9nIGluOlwiKVxuICAgICAgY29uc29sZS5sb2cobG9naW5fcGFnZS51cmwpXG5cbiAgICAgIC8vIFdhaXQgdW50aWwgd2UgcmVjZWl2ZSBjb25maXJtYXRpb25cbiAgICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICAgIGNvbnN0IHsgbG9naW5fcGFnZTogbmV3X2xvZ2luX3BhZ2UgfSA9IGF3YWl0IGt5XG4gICAgICAgICAgLnBvc3Q8RW5kcG9pbnRSZXNwb25zZVtcInNlc3Npb25zL2xvZ2luX3BhZ2UvZ2V0XCJdPihcbiAgICAgICAgICAgIFwic2Vzc2lvbnMvbG9naW5fcGFnZS9nZXRcIixcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAganNvbjoge1xuICAgICAgICAgICAgICAgIGxvZ2luX3BhZ2VfaWQ6IGxvZ2luX3BhZ2UubG9naW5fcGFnZV9pZCxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAgIEF1dGhvcml6YXRpb246IGBCZWFyZXIgJHtsb2dpbl9wYWdlLmxvZ2luX3BhZ2VfYXV0aF90b2tlbn1gLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICApXG4gICAgICAgICAgLmpzb24oKVxuXG4gICAgICAgIGlmIChuZXdfbG9naW5fcGFnZS53YXNfbG9naW5fc3VjY2Vzc2Z1bCkge1xuICAgICAgICAgIGNvbnNvbGUubG9nKFwiTG9nZ2VkIGluISBHZW5lcmF0aW5nIHRva2VuLi4uXCIpXG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChuZXdfbG9naW5fcGFnZS5pc19leHBpcmVkKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTG9naW4gcGFnZSBleHBpcmVkXCIpXG4gICAgICAgIH1cblxuICAgICAgICBhd2FpdCBkZWxheSgxMDAwKVxuICAgICAgfVxuXG4gICAgICBjb25zdCB7IHNlc3Npb24gfSA9IGF3YWl0IGt5XG4gICAgICAgIC5wb3N0PEVuZHBvaW50UmVzcG9uc2VbXCJzZXNzaW9ucy9sb2dpbl9wYWdlL2V4Y2hhbmdlX2Zvcl9jbGlfc2Vzc2lvblwiXT4oXG4gICAgICAgICAgXCJzZXNzaW9ucy9sb2dpbl9wYWdlL2V4Y2hhbmdlX2Zvcl9jbGlfc2Vzc2lvblwiLFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGpzb246IHtcbiAgICAgICAgICAgICAgbG9naW5fcGFnZV9pZDogbG9naW5fcGFnZS5sb2dpbl9wYWdlX2lkLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICAgQXV0aG9yaXphdGlvbjogYEJlYXJlciAke2xvZ2luX3BhZ2UubG9naW5fcGFnZV9hdXRoX3Rva2VufWAsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0sXG4gICAgICAgIClcbiAgICAgICAgLmpzb24oKVxuXG4gICAgICBjbGlDb25maWcuc2V0KFwic2Vzc2lvblRva2VuXCIsIHNlc3Npb24udG9rZW4pXG5cbiAgICAgIGNvbnNvbGUubG9nKFwiUmVhZHkgdG8gdXNlIVwiKVxuICAgIH0pXG59XG4iLCAiaW1wb3J0IHsgZ2V0UmVnaXN0cnlBcGlVcmwgfSBmcm9tIFwibGliL2NsaS1jb25maWdcIlxuaW1wb3J0IGt5LCB7IHR5cGUgQWZ0ZXJSZXNwb25zZUhvb2sgfSBmcm9tIFwia3lcIlxuXG5jb25zdCBwcmV0dHlSZXNwb25zZUVycm9ySG9vazogQWZ0ZXJSZXNwb25zZUhvb2sgPSBhc3luYyAoXG4gIF9yZXF1ZXN0LFxuICBfb3B0aW9ucyxcbiAgcmVzcG9uc2UsXG4pID0+IHtcbiAgaWYgKCFyZXNwb25zZS5vaykge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBlcnJvckRhdGEgPSBhd2FpdCByZXNwb25zZS5qc29uKClcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYEZBSUwgWyR7cmVzcG9uc2Uuc3RhdHVzfV06ICR7X3JlcXVlc3QubWV0aG9kfSAke1xuICAgICAgICAgIG5ldyBVUkwoX3JlcXVlc3QudXJsKS5wYXRobmFtZVxuICAgICAgICB9IFxcblxcbiAke0pTT04uc3RyaW5naWZ5KGVycm9yRGF0YSwgbnVsbCwgMil9YCxcbiAgICAgIClcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAvL2lnbm9yZSwgYWxsb3cgdGhlIGVycm9yIHRvIGJlIHRocm93blxuICAgIH1cbiAgfVxufVxuXG5leHBvcnQgY29uc3QgZ2V0S3kgPSAoKSA9PiB7XG4gIHJldHVybiBreS5jcmVhdGUoe1xuICAgIHByZWZpeFVybDogZ2V0UmVnaXN0cnlBcGlVcmwoKSxcbiAgICBob29rczoge1xuICAgICAgYWZ0ZXJSZXNwb25zZTogW3ByZXR0eVJlc3BvbnNlRXJyb3JIb29rXSxcbiAgICB9LFxuICB9KVxufVxuIiwgImltcG9ydCB0eXBlIHsgQ29tbWFuZCB9IGZyb20gXCJjb21tYW5kZXJcIlxuXG5leHBvcnQgY29uc3QgcmVnaXN0ZXJBdXRoTG9nb3V0ID0gKHByb2dyYW06IENvbW1hbmQpID0+IHtcbiAgcHJvZ3JhbS5jb21tYW5kc1xuICAgIC5maW5kKChjKSA9PiBjLm5hbWUoKSA9PT0gXCJhdXRoXCIpIVxuICAgIC5jb21tYW5kKFwibG9nb3V0XCIpXG4gICAgLmRlc2NyaXB0aW9uKFwiTG9nb3V0IGZyb20gcmVnaXN0cnlcIilcbiAgICAuYWN0aW9uKChhcmdzKSA9PiB7XG4gICAgICBjb25zb2xlLmxvZyhcImxvZ291dFwiKVxuICAgIH0pXG59XG4iLCAiaW1wb3J0IHR5cGUgeyBDb21tYW5kIH0gZnJvbSBcImNvbW1hbmRlclwiXG5cbmV4cG9ydCBjb25zdCByZWdpc3RlckF1dGggPSAocHJvZ3JhbTogQ29tbWFuZCkgPT4ge1xuICBwcm9ncmFtLmNvbW1hbmQoXCJhdXRoXCIpLmRlc2NyaXB0aW9uKFwiTG9naW4vbG9nb3V0XCIpXG59XG4iLCAiaW1wb3J0IHR5cGUgeyBDb21tYW5kIH0gZnJvbSBcImNvbW1hbmRlclwiXG5cbmV4cG9ydCBjb25zdCByZWdpc3RlckNvbmZpZyA9IChwcm9ncmFtOiBDb21tYW5kKSA9PiB7XG4gIHByb2dyYW0uY29tbWFuZChcImNvbmZpZ1wiKS5kZXNjcmlwdGlvbihcIk1hbmFnZSB0c2NpcmN1aXQgQ0xJIGNvbmZpZ3VyYXRpb25cIilcbn1cbiIsICJpbXBvcnQgdHlwZSB7IENvbW1hbmQgfSBmcm9tIFwiY29tbWFuZGVyXCJcbmltcG9ydCB7IGNsaUNvbmZpZyB9IGZyb20gXCJsaWIvY2xpLWNvbmZpZ1wiXG5cbmV4cG9ydCBjb25zdCByZWdpc3RlckNvbmZpZ1ByaW50ID0gKHByb2dyYW06IENvbW1hbmQpID0+IHtcbiAgcHJvZ3JhbS5jb21tYW5kc1xuICAgIC5maW5kKChjKSA9PiBjLm5hbWUoKSA9PT0gXCJjb25maWdcIikhXG4gICAgLmNvbW1hbmQoXCJwcmludFwiKVxuICAgIC5kZXNjcmlwdGlvbihcIlByaW50IHRoZSBjdXJyZW50IGNvbmZpZ1wiKVxuICAgIC5hY3Rpb24oKCkgPT4ge1xuICAgICAgY29uc29sZS5sb2coSlNPTi5zdHJpbmdpZnkoY2xpQ29uZmlnLmFsbCwgbnVsbCwgMikpXG4gICAgfSlcbn1cbiIsICJpbXBvcnQgdHlwZSB7IENvbW1hbmQgfSBmcm9tIFwiY29tbWFuZGVyXCJcbmltcG9ydCB7IGdldEt5IH0gZnJvbSBcImxpYi9yZWdpc3RyeS1hcGkvZ2V0LWt5XCJcbmltcG9ydCAqIGFzIGZzIGZyb20gXCJub2RlOmZzXCJcbmltcG9ydCAqIGFzIHBhdGggZnJvbSBcIm5vZGU6cGF0aFwiXG5cbmV4cG9ydCBjb25zdCByZWdpc3RlckNsb25lID0gKHByb2dyYW06IENvbW1hbmQpID0+IHtcbiAgcHJvZ3JhbVxuICAgIC5jb21tYW5kKFwiY2xvbmVcIilcbiAgICAuZGVzY3JpcHRpb24oXCJDbG9uZSBhIHNuaXBwZXQgZnJvbSB0aGUgcmVnaXN0cnlcIilcbiAgICAuYXJndW1lbnQoXCI8c25pcHBldD5cIiwgXCJTbmlwcGV0IHRvIGNsb25lIChlLmcuIGF1dGhvci9zbmlwcGV0TmFtZSlcIilcbiAgICAuYWN0aW9uKGFzeW5jIChzbmlwcGV0UGF0aDogc3RyaW5nKSA9PiB7XG4gICAgICBsZXQgYXV0aG9yOiBzdHJpbmdcbiAgICAgIGxldCBzbmlwcGV0TmFtZTogc3RyaW5nXG4gICAgICBpZiAoIXNuaXBwZXRQYXRoLnN0YXJ0c1dpdGgoXCJAdHNjaS9cIikgJiYgc25pcHBldFBhdGguaW5jbHVkZXMoXCIvXCIpKSB7XG4gICAgICAgIDtbYXV0aG9yLCBzbmlwcGV0TmFtZV0gPSBzbmlwcGV0UGF0aC5zcGxpdChcIi9cIilcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IHRyaW1tZWRQYXRoID0gc25pcHBldFBhdGgucmVwbGFjZShcIkB0c2NpL1wiLCBcIlwiKVxuICAgICAgICBjb25zdCBmaXJzdERvdEluZGV4ID0gdHJpbW1lZFBhdGguaW5kZXhPZihcIi5cIilcbiAgICAgICAgYXV0aG9yID0gdHJpbW1lZFBhdGguc2xpY2UoMCwgZmlyc3REb3RJbmRleClcbiAgICAgICAgc25pcHBldE5hbWUgPSB0cmltbWVkUGF0aC5zbGljZShmaXJzdERvdEluZGV4ICsgMSlcbiAgICAgIH1cblxuICAgICAgaWYgKCFhdXRob3IgfHwgIXNuaXBwZXROYW1lKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoXG4gICAgICAgICAgXCJJbnZhbGlkIHNuaXBwZXQgcGF0aC4gVXNlIGZvcm1hdDogYXV0aG9yL3NuaXBwZXROYW1lLCBhdXRob3Iuc25pcHBldE5hbWUgb3IgQHRzY2kvYXV0aG9yLnNuaXBwZXROYW1lXCIsXG4gICAgICAgIClcbiAgICAgICAgcHJvY2Vzcy5leGl0KDEpXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGt5ID0gZ2V0S3koKVxuXG4gICAgICB0cnkge1xuICAgICAgICBjb25zb2xlLmxvZyhgQ2xvbmluZyAke2F1dGhvcn0vJHtzbmlwcGV0TmFtZX0uLi5gKVxuXG4gICAgICAgIGNvbnN0IHBhY2thZ2VGaWxlTGlzdCA9IGF3YWl0IGt5XG4gICAgICAgICAgLnBvc3Q8e1xuICAgICAgICAgICAgcGFja2FnZV9maWxlczogQXJyYXk8e1xuICAgICAgICAgICAgICBwYWNrYWdlX2ZpbGVfaWQ6IHN0cmluZ1xuICAgICAgICAgICAgICBwYWNrYWdlX3JlbGVhc2VfaWQ6IHN0cmluZ1xuICAgICAgICAgICAgICBmaWxlX3BhdGg6IHN0cmluZ1xuICAgICAgICAgICAgICBjcmVhdGVkX2F0OiBzdHJpbmdcbiAgICAgICAgICAgIH0+XG4gICAgICAgICAgfT4oXCJwYWNrYWdlX2ZpbGVzL2xpc3RcIiwge1xuICAgICAgICAgICAganNvbjoge1xuICAgICAgICAgICAgICBwYWNrYWdlX25hbWU6IGAke2F1dGhvcn0vJHtzbmlwcGV0TmFtZX1gLFxuICAgICAgICAgICAgICB1c2VfbGF0ZXN0X3ZlcnNpb246IHRydWUsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0pXG4gICAgICAgICAgLmpzb24oKVxuXG4gICAgICAgIC8vIENyZWF0ZSBkaXJlY3RvcnkgaWYgaXQgZG9lc24ndCBleGlzdFxuICAgICAgICBjb25zdCBkaXJQYXRoID0gYC4vJHthdXRob3J9LiR7c25pcHBldE5hbWV9YFxuICAgICAgICBpZiAoIWZzLmV4aXN0c1N5bmMoZGlyUGF0aCkpIHtcbiAgICAgICAgICBmcy5ta2RpclN5bmMoZGlyUGF0aClcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIERvd25sb2FkIGVhY2ggZmlsZSB0aGF0IGRvZXNuJ3Qgc3RhcnQgd2l0aCBkaXN0L1xuICAgICAgICBmb3IgKGNvbnN0IGZpbGVJbmZvIG9mIHBhY2thZ2VGaWxlTGlzdC5wYWNrYWdlX2ZpbGVzKSB7XG4gICAgICAgICAgY29uc3QgZmlsZVBhdGggPSBmaWxlSW5mby5maWxlX3BhdGguc3RhcnRzV2l0aChcIi9cIilcbiAgICAgICAgICAgID8gZmlsZUluZm8uZmlsZV9wYXRoLnNsaWNlKDEpXG4gICAgICAgICAgICA6IGZpbGVJbmZvLmZpbGVfcGF0aFxuXG4gICAgICAgICAgaWYgKGZpbGVQYXRoLnN0YXJ0c1dpdGgoXCJkaXN0L1wiKSkgY29udGludWVcblxuICAgICAgICAgIGNvbnN0IGZpbGVDb250ZW50ID0gYXdhaXQga3lcbiAgICAgICAgICAgIC5wb3N0PHtcbiAgICAgICAgICAgICAgcGFja2FnZV9maWxlOiB7XG4gICAgICAgICAgICAgICAgY29udGVudF90ZXh0OiBzdHJpbmdcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfT4oXCJwYWNrYWdlX2ZpbGVzL2dldFwiLCB7XG4gICAgICAgICAgICAgIGpzb246IHtcbiAgICAgICAgICAgICAgICBwYWNrYWdlX25hbWU6IGAke2F1dGhvcn0vJHtzbmlwcGV0TmFtZX1gLFxuICAgICAgICAgICAgICAgIGZpbGVfcGF0aDogZmlsZUluZm8uZmlsZV9wYXRoLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIC5qc29uKClcblxuICAgICAgICAgIGNvbnN0IGZ1bGxQYXRoID0gcGF0aC5qb2luKGRpclBhdGgsIGZpbGVQYXRoKVxuICAgICAgICAgIGNvbnN0IGRpck5hbWUgPSBwYXRoLmRpcm5hbWUoZnVsbFBhdGgpXG5cbiAgICAgICAgICAvLyBDcmVhdGUgbmVzdGVkIGRpcmVjdG9yaWVzIGlmIHRoZXkgZG9uJ3QgZXhpc3RcbiAgICAgICAgICBpZiAoIWZzLmV4aXN0c1N5bmMoZGlyTmFtZSkpIHtcbiAgICAgICAgICAgIGZzLm1rZGlyU3luYyhkaXJOYW1lLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KVxuICAgICAgICAgIH1cblxuICAgICAgICAgIGZzLndyaXRlRmlsZVN5bmMoZnVsbFBhdGgsIGZpbGVDb250ZW50LnBhY2thZ2VfZmlsZS5jb250ZW50X3RleHQpXG4gICAgICAgIH1cblxuICAgICAgICBjb25zb2xlLmxvZyhgU3VjY2Vzc2Z1bGx5IGNsb25lZCB0byAuLyR7YXV0aG9yfS4ke3NuaXBwZXROYW1lfS9gKVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKFwiRmFpbGVkIHRvIGNsb25lIHNuaXBwZXQ6XCIsIGVycm9yLm1lc3NhZ2UpXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihcIkZhaWxlZCB0byBjbG9uZSBzbmlwcGV0OlwiLCBlcnJvcilcbiAgICAgICAgfVxuICAgICAgICBwcm9jZXNzLmV4aXQoMSlcbiAgICAgIH1cbiAgICB9KVxufVxuIl0sCiAgIm1hcHBpbmdzIjogIjs7O0FBQ0EsU0FBUyxlQUFlOzs7QUNBeEIsWUFBWUEsV0FBVTs7O0FDRHRCLFlBQVksUUFBUTtBQUNwQixZQUFZLFVBQVU7QUFDdEIsWUFBWSxRQUFRO0FBUXBCLGVBQXNCLGlDQUFpQyxhQUFxQjtBQUMxRSxRQUFNLFVBQWEsZ0JBQWEsYUFBYSxPQUFPO0FBQ3BELFFBQU0sYUFBZ0I7QUFBQSxJQUNwQjtBQUFBLElBQ0E7QUFBQSxJQUNHLGdCQUFhO0FBQUEsSUFDaEI7QUFBQSxF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QUFZO0FBQUEsTUFDbEU7QUFFQSxjQUFRLElBQUksNEJBQTRCLE1BQU0sSUFBSSxXQUFXLEdBQUc7QUFBQSxJQUNsRSxTQUFTLE9BQU87QUFDZCxVQUFJLGlCQUFpQixPQUFPO0FBQzFCLGdCQUFRLE1BQU0sNEJBQTRCLE1BQU0sT0FBTztBQUFBLE1BQ3pELE9BQU87QUFDTCxnQkFBUSxNQUFNLDRCQUE0QixLQUFLO0FBQUEsTUFDakQ7QUFDQSxjQUFRLEtBQUssQ0FBQztBQUFBLElBQ2hCO0FBQUEsRUFDRixDQUFDO0FBQ0w7OztBZnpGQSxTQUFTLGtCQUFrQjtBQUczQixJQUFNLFVBQVUsSUFBSSxRQUFRO0FBRTVCLFFBQ0csS0FBSyxNQUFNLEVBQ1gsWUFBWSx1Q0FBdUMsRUFDbkQsUUFBUSxnQkFBSSxPQUFPO0FBRXRCLFlBQVksT0FBTztBQUNuQixjQUFjLE9BQU87QUFFckIsYUFBYSxPQUFPO0FBQ3BCLGtCQUFrQixPQUFPO0FBQ3pCLG1CQUFtQixPQUFPO0FBRTFCLGVBQWUsT0FBTztBQUN0QixvQkFBb0IsT0FBTztBQUUzQixJQUFJLFFBQVEsS0FBSyxXQUFXLEdBQUc7QUFDN0IsYUFBVyxTQUFTLFFBQVEsSUFBSTtBQUNsQyxPQUFPO0FBQ0wsVUFBUSxNQUFNO0FBQ2hCOyIsCiAgIm5hbWVzIjogWyJwYXRoIiwgImZzIiwgInBhdGgiLCAicmVzb2x2ZSIsICJwYXRoIiwgImZzIiwgInByb2dyYW0iLCAia3kiLCAicHJvZ3JhbSIsICJreSIsICJwcm9ncmFtIiwgInByb2dyYW0iLCAicHJvZ3JhbSIsICJwcm9ncmFtIiwgImZzIiwgInBhdGgiLCAicHJvZ3JhbSIsICJreSJdCn0K
|
package/lib/dependency-analysis/{installNodeModuleTypes.ts → installNodeModuleTypesForSnippet.ts}
RENAMED
|
@@ -8,7 +8,7 @@ interface SnippetApiResponse {
|
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
export async function
|
|
11
|
+
export async function installNodeModuleTypesForSnippet(snippetPath: string) {
|
|
12
12
|
const content = fs.readFileSync(snippetPath, "utf-8")
|
|
13
13
|
const sourceFile = ts.createSourceFile(
|
|
14
14
|
snippetPath,
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export interface FileServerRoutes {
|
|
2
|
+
"api/files/get": {
|
|
3
|
+
GET: {
|
|
4
|
+
searchParams: {
|
|
5
|
+
file_path: string
|
|
6
|
+
}
|
|
7
|
+
responseJson: {
|
|
8
|
+
file: {
|
|
9
|
+
file_id: string
|
|
10
|
+
file_path: string
|
|
11
|
+
text_content: string
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
"api/files/upsert": {
|
|
17
|
+
POST: {
|
|
18
|
+
requestJson: {
|
|
19
|
+
file_path: string
|
|
20
|
+
text_content: string
|
|
21
|
+
initiator?: "filesystem_change"
|
|
22
|
+
}
|
|
23
|
+
responseJson: {
|
|
24
|
+
file: {
|
|
25
|
+
file_id: string
|
|
26
|
+
file_path: string
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
"api/files/list": {
|
|
32
|
+
GET: {
|
|
33
|
+
responseJson: {
|
|
34
|
+
file_list: { file_id: string; file_path: string }[]
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
package/lib/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { createHttpServer } from "./server/createHttpServer"
|
|
2
2
|
export { getLocalFileDependencies } from "./dependency-analysis/getLocalFileDependencies"
|
|
@@ -8,7 +8,7 @@ import pkg from "../../package.json"
|
|
|
8
8
|
import winterspecBundle from "@tscircuit/file-server/dist/bundle.js"
|
|
9
9
|
import { getIndex } from "../site/getIndex"
|
|
10
10
|
|
|
11
|
-
export const
|
|
11
|
+
export const createHttpServer = async (port = 3000) => {
|
|
12
12
|
const fileServerHandler = getNodeHandler(winterspecBundle as any, {})
|
|
13
13
|
|
|
14
14
|
const server = http.createServer(async (req, res) => {
|
|
@@ -58,10 +58,10 @@ export const createServer = async (port: number = 3000) => {
|
|
|
58
58
|
res.end("Not found")
|
|
59
59
|
})
|
|
60
60
|
|
|
61
|
-
return new Promise<
|
|
61
|
+
return new Promise<{ server: http.Server }>((resolve) => {
|
|
62
62
|
server.listen(port, () => {
|
|
63
63
|
console.log(`Server running at http://localhost:${port}`)
|
|
64
|
-
resolve()
|
|
64
|
+
resolve({ server })
|
|
65
65
|
})
|
|
66
66
|
})
|
|
67
67
|
}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@tscircuit/cli",
|
|
3
3
|
"main": "dist/main.js",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "0.1.
|
|
5
|
+
"version": "0.1.5",
|
|
6
6
|
"bin": {
|
|
7
7
|
"tsci": "./dist/main.js"
|
|
8
8
|
},
|
|
@@ -17,16 +17,19 @@
|
|
|
17
17
|
"devDependencies": {
|
|
18
18
|
"@biomejs/biome": "^1.9.4",
|
|
19
19
|
"@tscircuit/core": "^0.0.249",
|
|
20
|
-
"@types/bun": "
|
|
20
|
+
"@types/bun": "^1.1.15",
|
|
21
21
|
"@types/configstore": "^6.0.2",
|
|
22
22
|
"@types/react": "^19.0.1",
|
|
23
|
-
"
|
|
23
|
+
"get-port": "^7.1.0",
|
|
24
|
+
"tempy": "^3.1.0",
|
|
25
|
+
"tsup": "^8.3.5",
|
|
26
|
+
"typed-ky": "^0.0.4"
|
|
24
27
|
},
|
|
25
28
|
"peerDependencies": {
|
|
26
29
|
"typescript": "^5.0.0"
|
|
27
30
|
},
|
|
28
31
|
"dependencies": {
|
|
29
|
-
"@tscircuit/file-server": "^0.0.
|
|
32
|
+
"@tscircuit/file-server": "^0.0.13",
|
|
30
33
|
"@tscircuit/runframe": "^0.0.47",
|
|
31
34
|
"chokidar": "^4.0.1",
|
|
32
35
|
"commander": "^12.1.0",
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as tempy from "tempy"
|
|
2
|
+
import getPort from "get-port"
|
|
3
|
+
|
|
4
|
+
interface Params {
|
|
5
|
+
vfs?: Record<string, string>
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const getTestFixture = async (params: Params) => {
|
|
9
|
+
// Create temp directory
|
|
10
|
+
const tempDirPath = await tempy.temporaryDirectory()
|
|
11
|
+
const devServerPort = await getPort()
|
|
12
|
+
|
|
13
|
+
// Write virtual filesystem files
|
|
14
|
+
if (params.vfs) {
|
|
15
|
+
for (const [filePath, content] of Object.entries(params.vfs)) {
|
|
16
|
+
await Bun.write(`${tempDirPath}/${filePath}`, content)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
tempDirPath,
|
|
22
|
+
devServerPort,
|
|
23
|
+
devServerUrl: `http://localhost:${devServerPort}`,
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { test, expect, afterEach } from "bun:test"
|
|
2
|
+
import { DevServer } from "cli/dev/DevServer"
|
|
3
|
+
import { getTestFixture } from "tests/fixtures/get-test-fixture"
|
|
4
|
+
|
|
5
|
+
test("test1 basic dev server filesystem watching", async () => {
|
|
6
|
+
const { tempDirPath, devServerPort, devServerUrl } = await getTestFixture({
|
|
7
|
+
vfs: {
|
|
8
|
+
"snippet.tsx": `
|
|
9
|
+
export const MyCircuit = () => (
|
|
10
|
+
<board width="10mm" height="10mm">
|
|
11
|
+
<chip name="U1" footprint="soic8" />
|
|
12
|
+
</board>
|
|
13
|
+
)
|
|
14
|
+
`,
|
|
15
|
+
"manual-edits.json": "{}",
|
|
16
|
+
},
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
const devServer = new DevServer({
|
|
20
|
+
port: devServerPort,
|
|
21
|
+
componentFilePath: `${tempDirPath}/snippet.tsx`,
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
await devServer.start()
|
|
25
|
+
await devServer.addEntrypoint()
|
|
26
|
+
|
|
27
|
+
const { file_list } = await devServer.fsKy.get("api/files/list").json()
|
|
28
|
+
|
|
29
|
+
expect(file_list.map((f) => f.file_path).sort()).toMatchInlineSnapshot(`
|
|
30
|
+
[
|
|
31
|
+
"entrypoint.tsx",
|
|
32
|
+
"manual-edits.json",
|
|
33
|
+
"snippet.tsx",
|
|
34
|
+
]
|
|
35
|
+
`)
|
|
36
|
+
|
|
37
|
+
afterEach(async () => {
|
|
38
|
+
await devServer.stop()
|
|
39
|
+
})
|
|
40
|
+
})
|