xpine 0.0.4 → 0.0.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/dist/index.js +659 -0
- package/dist/src/scripts/xpine-build.js +421 -0
- package/dist/src/scripts/xpine-dev.js +482 -0
- package/dist/src/static/dev-server.js +10 -0
- package/dist/src/static/spa.js +152 -0
- package/package.json +1 -1
package/dist/index.js
ADDED
|
@@ -0,0 +1,659 @@
|
|
|
1
|
+
// src/runDevServer.ts
|
|
2
|
+
import expressWs from "express-ws";
|
|
3
|
+
import http from "http";
|
|
4
|
+
import express from "express";
|
|
5
|
+
import EventEmitter from "events";
|
|
6
|
+
import chokidar from "chokidar";
|
|
7
|
+
|
|
8
|
+
// src/scripts/build.ts
|
|
9
|
+
import path3 from "path";
|
|
10
|
+
import fs2 from "fs-extra";
|
|
11
|
+
import { build } from "esbuild";
|
|
12
|
+
import builtinModules from "builtin-modules";
|
|
13
|
+
import ts2 from "typescript";
|
|
14
|
+
|
|
15
|
+
// src/build/typescript-builder.ts
|
|
16
|
+
import ts from "typescript";
|
|
17
|
+
import fs from "fs-extra";
|
|
18
|
+
import path from "path";
|
|
19
|
+
function findDataAttributesAndFunctions(node, sourceFile, foundDataAttributes = [], foundFunctions = []) {
|
|
20
|
+
if (node.kind === ts.SyntaxKind.JsxAttribute) {
|
|
21
|
+
const attribute = getAttributeValuePair(node, sourceFile);
|
|
22
|
+
if (attribute?.[0] === "x-data" && attribute?.[1]) {
|
|
23
|
+
foundDataAttributes.push(attribute[1].replace(/[^a-zA-Z0-9]/g, ""));
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (node.kind === ts.SyntaxKind.SourceFile) {
|
|
27
|
+
node.forEachChild((child) => {
|
|
28
|
+
if ([ts.SyntaxKind.FunctionDeclaration, ts.SyntaxKind.VariableDeclaration].includes(child.kind)) {
|
|
29
|
+
const functions = getFunctionDeclarationValue(child, sourceFile);
|
|
30
|
+
foundFunctions.push(functions);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
node.forEachChild((child) => {
|
|
35
|
+
findDataAttributesAndFunctions(child, sourceFile, foundDataAttributes, foundFunctions);
|
|
36
|
+
});
|
|
37
|
+
return {
|
|
38
|
+
foundDataAttributes,
|
|
39
|
+
foundFunctions
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function getAttributeValuePair(node, sourceFile) {
|
|
43
|
+
const result = [];
|
|
44
|
+
node.forEachChild((child) => {
|
|
45
|
+
result.push(child.getText(sourceFile));
|
|
46
|
+
});
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
function getFunctionDeclarationValue(node, sourceFile) {
|
|
50
|
+
const result = {
|
|
51
|
+
name: null,
|
|
52
|
+
isDefaultExport: false,
|
|
53
|
+
hasExport: false
|
|
54
|
+
};
|
|
55
|
+
node.forEachChild((child) => {
|
|
56
|
+
if (child.kind === ts.SyntaxKind.ExportKeyword) {
|
|
57
|
+
result.hasExport = true;
|
|
58
|
+
}
|
|
59
|
+
if (child.kind === ts.SyntaxKind.DefaultKeyword) {
|
|
60
|
+
result.isDefaultExport = true;
|
|
61
|
+
}
|
|
62
|
+
if (child.kind === ts.SyntaxKind.Identifier) {
|
|
63
|
+
result.name = child.getText(sourceFile);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
function convertEntryPointsToSingleFile(entryPoints, tempWritePath) {
|
|
69
|
+
fs.writeFileSync(
|
|
70
|
+
tempWritePath,
|
|
71
|
+
entryPoints.map((entry) => `import "${entry}"`).join(";\n")
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
function removeClientScriptInTSXFile(pathName) {
|
|
75
|
+
const content = fs.readFileSync(pathName, "utf-8");
|
|
76
|
+
const source = ts.createSourceFile(
|
|
77
|
+
pathName,
|
|
78
|
+
content,
|
|
79
|
+
ts.ScriptTarget.Latest
|
|
80
|
+
);
|
|
81
|
+
let toRemoveFrom;
|
|
82
|
+
let clientDataStart;
|
|
83
|
+
const clientImportsToHoist = [];
|
|
84
|
+
const clientImportsToReplace = [];
|
|
85
|
+
source.forEachChild((child) => {
|
|
86
|
+
if (child.kind === ts.SyntaxKind.ExpressionStatement) {
|
|
87
|
+
const text = child.getText(source);
|
|
88
|
+
if (text.startsWith("<script")) {
|
|
89
|
+
toRemoveFrom = child.pos;
|
|
90
|
+
clientDataStart = child.end;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (child.kind === ts.SyntaxKind.ImportDeclaration && child.pos >= clientDataStart) {
|
|
94
|
+
const text = child.getText(source);
|
|
95
|
+
child.forEachChild((child2) => {
|
|
96
|
+
if (child2.kind === ts.SyntaxKind.StringLiteral) {
|
|
97
|
+
const text2 = child2.getText(source);
|
|
98
|
+
const importPath = text2.replace(/[\"\']/g, "");
|
|
99
|
+
const isRelativeImport = importPath.startsWith(".") || importPath.startsWith("/");
|
|
100
|
+
if (!isRelativeImport) return;
|
|
101
|
+
clientImportsToReplace.push({
|
|
102
|
+
old: importPath,
|
|
103
|
+
new: path.join(path.dirname(pathName), importPath)
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
clientImportsToHoist.push(text);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
let clientContent = !isNaN(clientDataStart) ? content.slice(clientDataStart) : "";
|
|
111
|
+
for (const clientImport of clientImportsToReplace) {
|
|
112
|
+
clientContent = clientContent.replace(clientImport.old, clientImport.new);
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
content: !isNaN(toRemoveFrom) ? clientImportsToHoist.join("\n") + content.slice(0, toRemoveFrom) : content,
|
|
116
|
+
clientContent,
|
|
117
|
+
fullContent: content,
|
|
118
|
+
toRemoveFrom,
|
|
119
|
+
clientDataStart
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// src/scripts/build.ts
|
|
124
|
+
import { globSync } from "glob";
|
|
125
|
+
import postcss from "postcss";
|
|
126
|
+
import tailwindPostcss from "@tailwindcss/postcss";
|
|
127
|
+
|
|
128
|
+
// src/util/get-config.ts
|
|
129
|
+
import path2 from "path";
|
|
130
|
+
|
|
131
|
+
// src/util/require.ts
|
|
132
|
+
import { createRequire } from "module";
|
|
133
|
+
var require2 = createRequire(import.meta.url);
|
|
134
|
+
var require_default = require2;
|
|
135
|
+
|
|
136
|
+
// src/util/get-config.ts
|
|
137
|
+
var rootDir = process.cwd();
|
|
138
|
+
function fromRoot(pathName) {
|
|
139
|
+
if (!pathName) return rootDir;
|
|
140
|
+
return path2.join(rootDir, pathName);
|
|
141
|
+
}
|
|
142
|
+
var userConfig = require_default(path2.join(process.cwd(), "./xpine.config.mjs")).default;
|
|
143
|
+
var configDefaults = {
|
|
144
|
+
rootDir: fromRoot(),
|
|
145
|
+
srcDir: fromRoot("./src"),
|
|
146
|
+
distDir: fromRoot("./dist"),
|
|
147
|
+
packageJsonPath: fromRoot("package.json"),
|
|
148
|
+
// We need to use getters here in the event someone wants to change folders, such as the dist folder
|
|
149
|
+
get distPublicDir() {
|
|
150
|
+
return path2.join(this.distDir, "./public");
|
|
151
|
+
},
|
|
152
|
+
get distPublicScriptsDir() {
|
|
153
|
+
return path2.join(this.distPublicDir, "./scripts");
|
|
154
|
+
},
|
|
155
|
+
get distTempFolder() {
|
|
156
|
+
return path2.join(this.distDir, "./temp");
|
|
157
|
+
},
|
|
158
|
+
get clientJSBundlePath() {
|
|
159
|
+
return path2.join(this.distPublicScriptsDir, "./app.js");
|
|
160
|
+
},
|
|
161
|
+
get alpineDataPath() {
|
|
162
|
+
return path2.join(this.distTempFolder, "./alpine-data.ts");
|
|
163
|
+
},
|
|
164
|
+
get serverDistDir() {
|
|
165
|
+
return path2.join(this.distDir, "./server");
|
|
166
|
+
},
|
|
167
|
+
get serverDistAppPath() {
|
|
168
|
+
return path2.join(this.serverDistDir, "./app.js");
|
|
169
|
+
},
|
|
170
|
+
// Important dirs/paths
|
|
171
|
+
get pagesDir() {
|
|
172
|
+
return path2.join(this.srcDir, "./pages");
|
|
173
|
+
},
|
|
174
|
+
get publicDir() {
|
|
175
|
+
return path2.join(this.srcDir, "./public");
|
|
176
|
+
},
|
|
177
|
+
get serverDir() {
|
|
178
|
+
return path2.join(this.srcDir, "./server");
|
|
179
|
+
},
|
|
180
|
+
get runDir() {
|
|
181
|
+
return path2.join(this.serverDir, "./run");
|
|
182
|
+
},
|
|
183
|
+
get serverAppPath() {
|
|
184
|
+
return path2.join(this.serverDir, "./app.ts");
|
|
185
|
+
},
|
|
186
|
+
get globalCSSFile() {
|
|
187
|
+
return path2.join(this.publicDir, "./styles/global.css");
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
var config = {
|
|
191
|
+
...configDefaults,
|
|
192
|
+
...userConfig
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
// src/scripts/build.ts
|
|
196
|
+
var extensions = [".ts", ".tsx"];
|
|
197
|
+
var packageJson = JSON.parse(fs2.readFileSync(config.packageJsonPath, "utf-8"));
|
|
198
|
+
var allPackages = Object.keys(packageJson.devDependencies).concat(Object.keys(packageJson.dependencies));
|
|
199
|
+
var allPackagesIncludingNode = allPackages.concat(builtinModules);
|
|
200
|
+
async function buildApp(isDev = false) {
|
|
201
|
+
try {
|
|
202
|
+
const srcDirFiles = globSync(config.srcDir + "/**/*.{js,ts,tsx,jsx}");
|
|
203
|
+
const { componentData, dataFiles } = await buildAppFiles(srcDirFiles, isDev);
|
|
204
|
+
const alpineDataFile = await buildAlpineDataFile(componentData, dataFiles);
|
|
205
|
+
await buildClientSideFiles([alpineDataFile], isDev);
|
|
206
|
+
fs2.removeSync(config.distTempFolder);
|
|
207
|
+
await buildCSS();
|
|
208
|
+
await buildPublicFolderSymlinks();
|
|
209
|
+
} catch (err) {
|
|
210
|
+
console.error("Build failed");
|
|
211
|
+
console.error(err);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
async function buildAppFiles(files, isDev) {
|
|
215
|
+
const componentData = [];
|
|
216
|
+
const dataFiles = [];
|
|
217
|
+
const backendFiles = files.filter((file) => extensions.find((ext) => file.endsWith(ext))).filter((file) => !file.startsWith(config.publicDir));
|
|
218
|
+
fs2.ensureDirSync(config.distDir);
|
|
219
|
+
await build({
|
|
220
|
+
entryPoints: backendFiles,
|
|
221
|
+
format: "esm",
|
|
222
|
+
platform: "node",
|
|
223
|
+
outdir: config.distDir,
|
|
224
|
+
bundle: true,
|
|
225
|
+
sourcemap: isDev ? "inline" : false,
|
|
226
|
+
external: allPackages,
|
|
227
|
+
jsx: "transform",
|
|
228
|
+
minify: !isDev,
|
|
229
|
+
plugins: [
|
|
230
|
+
{
|
|
231
|
+
name: "add-dot-js",
|
|
232
|
+
setup(build2) {
|
|
233
|
+
build2.onResolve({ filter: /.*/ }, (args) => {
|
|
234
|
+
const hasAtSign = args.path.startsWith("@");
|
|
235
|
+
const isPackage = hasAtSign ? allPackagesIncludingNode.includes(args.path) : allPackagesIncludingNode.includes(args.path.split("/").shift());
|
|
236
|
+
if (args.importer && !isPackage) {
|
|
237
|
+
const calculatedDir = path3.join(args.resolveDir, args.path);
|
|
238
|
+
let existsAsFile = false;
|
|
239
|
+
for (const extension of extensions) {
|
|
240
|
+
const asFile = calculatedDir + extension;
|
|
241
|
+
const exists = fs2.existsSync(asFile);
|
|
242
|
+
if (exists) existsAsFile = true;
|
|
243
|
+
}
|
|
244
|
+
let outputPath = args.path + (existsAsFile ? "" : "/index") + ".js";
|
|
245
|
+
outputPath = args.path.endsWith(".js") || args.path.endsWith(".mjs") ? args.path : outputPath;
|
|
246
|
+
return { path: outputPath, external: true };
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
name: "insert-html-banner-and-remove-client-scripts",
|
|
253
|
+
setup(build2) {
|
|
254
|
+
build2.onLoad({ filter: /.tsx/ }, (args) => {
|
|
255
|
+
const cleanedContent = removeClientScriptInTSXFile(args.path);
|
|
256
|
+
const htmlImportStart = "import { html } from 'xpine';\n";
|
|
257
|
+
const newContent = `${htmlImportStart}${cleanedContent.content}`;
|
|
258
|
+
componentData.push({
|
|
259
|
+
...args,
|
|
260
|
+
contents: `${htmlImportStart}${cleanedContent.fullContent}`,
|
|
261
|
+
clientContent: cleanedContent.clientContent
|
|
262
|
+
});
|
|
263
|
+
return {
|
|
264
|
+
contents: newContent,
|
|
265
|
+
loader: "tsx"
|
|
266
|
+
};
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
name: "get-data-files",
|
|
272
|
+
setup(build2) {
|
|
273
|
+
build2.onLoad({ filter: /\.data\.(js|mjs|ts)$/ }, (args) => {
|
|
274
|
+
const contents = fs2.readFileSync(args.path, "utf-8");
|
|
275
|
+
dataFiles.push({
|
|
276
|
+
...args,
|
|
277
|
+
contents
|
|
278
|
+
});
|
|
279
|
+
return {
|
|
280
|
+
contents,
|
|
281
|
+
loader: "ts"
|
|
282
|
+
};
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
]
|
|
287
|
+
});
|
|
288
|
+
await logSize(config.distDir, "app");
|
|
289
|
+
return {
|
|
290
|
+
componentData,
|
|
291
|
+
dataFiles
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
async function buildClientSideFiles(alpineDataFiles = [], isDev) {
|
|
295
|
+
const tempFilePath = path3.join(config.distTempFolder, "./app.ts");
|
|
296
|
+
fs2.ensureFileSync(tempFilePath);
|
|
297
|
+
const pagesScriptsGlob = config.publicDir + "/scripts/pages/**/*.{js,ts}";
|
|
298
|
+
const clientFiles = globSync(
|
|
299
|
+
config.publicDir + "/**/*.{js,ts}",
|
|
300
|
+
{
|
|
301
|
+
ignore: pagesScriptsGlob
|
|
302
|
+
}
|
|
303
|
+
);
|
|
304
|
+
convertEntryPointsToSingleFile(alpineDataFiles.concat(clientFiles), tempFilePath);
|
|
305
|
+
if (isDev) writeDevServerClientSideCode(tempFilePath);
|
|
306
|
+
writeSpaClientSideCode(tempFilePath);
|
|
307
|
+
await build({
|
|
308
|
+
entryPoints: [tempFilePath],
|
|
309
|
+
bundle: true,
|
|
310
|
+
outdir: config.distPublicScriptsDir,
|
|
311
|
+
minify: !isDev,
|
|
312
|
+
sourcemap: isDev ? "inline" : false
|
|
313
|
+
});
|
|
314
|
+
const pagesFiles = globSync(pagesScriptsGlob);
|
|
315
|
+
await build({
|
|
316
|
+
entryPoints: pagesFiles || [],
|
|
317
|
+
bundle: true,
|
|
318
|
+
outdir: config.distPublicScriptsDir + "/pages",
|
|
319
|
+
minify: !isDev,
|
|
320
|
+
sourcemap: isDev ? "inline" : false
|
|
321
|
+
});
|
|
322
|
+
await logSize(config.distPublicDir, "client");
|
|
323
|
+
}
|
|
324
|
+
function writeDevServerClientSideCode(tempFilePath) {
|
|
325
|
+
const devServerPath = path3.join(import.meta.dirname, "../static/dev-server.js");
|
|
326
|
+
const content = fs2.readFileSync(devServerPath, "utf-8");
|
|
327
|
+
fs2.appendFileSync(tempFilePath, `
|
|
328
|
+
` + content);
|
|
329
|
+
}
|
|
330
|
+
function writeSpaClientSideCode(tempFilePath) {
|
|
331
|
+
const spaPath = path3.join(import.meta.dirname, "../static/spa.js");
|
|
332
|
+
const content = fs2.readFileSync(spaPath, "utf-8");
|
|
333
|
+
fs2.appendFileSync(tempFilePath, `
|
|
334
|
+
` + content);
|
|
335
|
+
}
|
|
336
|
+
async function buildAlpineDataFile(componentData, dataFiles) {
|
|
337
|
+
const output = {
|
|
338
|
+
imports: [
|
|
339
|
+
"import Alpine from 'alpinejs';"
|
|
340
|
+
],
|
|
341
|
+
code: [],
|
|
342
|
+
end: [
|
|
343
|
+
"window.Alpine = Alpine;"
|
|
344
|
+
]
|
|
345
|
+
};
|
|
346
|
+
const dataFunctionResults = {
|
|
347
|
+
foundDataAttributes: [],
|
|
348
|
+
foundFunctions: [],
|
|
349
|
+
foundImports: []
|
|
350
|
+
};
|
|
351
|
+
const componentsAndDataFiles = componentData.concat(dataFiles);
|
|
352
|
+
for (const component of componentsAndDataFiles) {
|
|
353
|
+
const sourceFile = ts2.createSourceFile(
|
|
354
|
+
component.path,
|
|
355
|
+
component.contents,
|
|
356
|
+
ts2.ScriptTarget.Latest
|
|
357
|
+
);
|
|
358
|
+
const dataFunctionResult = findDataAttributesAndFunctions(sourceFile, sourceFile);
|
|
359
|
+
dataFunctionResults.foundDataAttributes.push(...dataFunctionResult.foundDataAttributes);
|
|
360
|
+
const foundFunctionsWithPath = dataFunctionResult.foundFunctions.map((item) => {
|
|
361
|
+
return {
|
|
362
|
+
...item,
|
|
363
|
+
path: component.path,
|
|
364
|
+
content: component.clientContent
|
|
365
|
+
};
|
|
366
|
+
});
|
|
367
|
+
dataFunctionResults.foundFunctions.push(...foundFunctionsWithPath);
|
|
368
|
+
}
|
|
369
|
+
const validDataFunctions = dataFunctionResults.foundFunctions.filter((item) => {
|
|
370
|
+
return dataFunctionResults.foundDataAttributes.includes(item.name) && item.content;
|
|
371
|
+
});
|
|
372
|
+
for (const dataFunction of validDataFunctions) {
|
|
373
|
+
if (!dataFunction.hasExport) continue;
|
|
374
|
+
output.code.push(dataFunction.content);
|
|
375
|
+
output.code.push(`Alpine.data('${dataFunction.name}', ${dataFunction.name});`);
|
|
376
|
+
}
|
|
377
|
+
const result = output.imports.join("\n") + "\n" + output.code.join("\n") + "\n" + output.end.join("\n");
|
|
378
|
+
fs2.ensureFileSync(config.alpineDataPath);
|
|
379
|
+
fs2.writeFileSync(config.alpineDataPath, result);
|
|
380
|
+
return config.alpineDataPath;
|
|
381
|
+
}
|
|
382
|
+
async function buildCSS() {
|
|
383
|
+
const cssFiles = globSync(config.srcDir + "/**/*.css");
|
|
384
|
+
for (const file of cssFiles) {
|
|
385
|
+
const fileContents = fs2.readFileSync(file, "utf-8");
|
|
386
|
+
const result = await postcss([tailwindPostcss()]).process(fileContents, { from: file });
|
|
387
|
+
const newPath = file.replace(config.srcDir, config.distDir);
|
|
388
|
+
fs2.ensureFileSync(newPath);
|
|
389
|
+
fs2.writeFileSync(newPath, result.css);
|
|
390
|
+
}
|
|
391
|
+
logSize(config.distPublicDir, "css");
|
|
392
|
+
}
|
|
393
|
+
async function buildPublicFolderSymlinks() {
|
|
394
|
+
const files = globSync(config.publicDir + "/**/*.*", {
|
|
395
|
+
ignore: "/**/*.{css,js,ts,tsx,jsx}"
|
|
396
|
+
});
|
|
397
|
+
for (const file of files) {
|
|
398
|
+
try {
|
|
399
|
+
const newPath = file.replace(config.srcDir, config.distDir);
|
|
400
|
+
const splitNewPath = newPath.split("/");
|
|
401
|
+
splitNewPath.pop();
|
|
402
|
+
const newDir = splitNewPath.join("/");
|
|
403
|
+
fs2.ensureDirSync(newDir);
|
|
404
|
+
fs2.symlinkSync(file, newPath);
|
|
405
|
+
} catch {
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
async function logSize(pathName, type, validExtensions = [".js", ".css"]) {
|
|
410
|
+
const files = globSync(pathName + "/**/*" + (type === "css" ? ".css" : ""));
|
|
411
|
+
const fileSizes = files.map((file) => {
|
|
412
|
+
if (!validExtensions.find((ext) => file.endsWith(ext))) return false;
|
|
413
|
+
return {
|
|
414
|
+
file,
|
|
415
|
+
size: fs2.statSync(file).size / (1024 * 1e3)
|
|
416
|
+
};
|
|
417
|
+
}).filter(Boolean);
|
|
418
|
+
const totalSize = fileSizes.reduce((total, current) => {
|
|
419
|
+
return current.size + total;
|
|
420
|
+
}, 0);
|
|
421
|
+
console.info(`[${totalSize.toFixed(3)} MB] Built ${type}`);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// src/runDevServer.ts
|
|
425
|
+
import path5 from "path";
|
|
426
|
+
|
|
427
|
+
// src/util/env.ts
|
|
428
|
+
import dotenv from "dotenv";
|
|
429
|
+
import path4 from "path";
|
|
430
|
+
function setupEnv() {
|
|
431
|
+
dotenv.config({ path: path4.join(config.rootDir, `./.env.${process.env.STAGE || "dev"}`) });
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// src/runDevServer.ts
|
|
435
|
+
setupEnv();
|
|
436
|
+
async function runDevServer() {
|
|
437
|
+
process.env.NODE_ENV = "development";
|
|
438
|
+
const startServer = await import(config.serverDistAppPath + `?cache=${Date.now()}`);
|
|
439
|
+
await buildApp(true);
|
|
440
|
+
let appServer = await startServer.default();
|
|
441
|
+
const watcher = chokidar.watch(config.srcDir, {
|
|
442
|
+
ignoreInitial: true,
|
|
443
|
+
// Ignore map and prisma files
|
|
444
|
+
ignored: (pathName) => pathName.endsWith(".map") || pathName.startsWith(path5.join(config.serverDir, "./prisma"))
|
|
445
|
+
});
|
|
446
|
+
watcher.on("all", async (event, path6) => {
|
|
447
|
+
const shouldReloadServer = path6.startsWith(config.serverDir) && !path6.startsWith(config.runDir) || ["add", "unlink"].includes(event) && path6.startsWith(config.pagesDir);
|
|
448
|
+
if (shouldReloadServer) {
|
|
449
|
+
appServer.server.close();
|
|
450
|
+
await buildApp(true);
|
|
451
|
+
const startServer2 = await import(config.serverDistAppPath + `?cache=${Date.now()}`);
|
|
452
|
+
appServer = await startServer2.default();
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
await buildApp(true);
|
|
456
|
+
refreshEmitter.emit("refresh");
|
|
457
|
+
});
|
|
458
|
+
const wsApp = express();
|
|
459
|
+
const wsServer = http.createServer(wsApp);
|
|
460
|
+
expressWs(wsApp, wsServer);
|
|
461
|
+
class RefreshEmitter extends EventEmitter {
|
|
462
|
+
}
|
|
463
|
+
;
|
|
464
|
+
const refreshEmitter = new RefreshEmitter();
|
|
465
|
+
wsApp.ws("/dev-server", function(ws) {
|
|
466
|
+
refreshEmitter.removeAllListeners();
|
|
467
|
+
refreshEmitter.on("refresh", () => {
|
|
468
|
+
ws.send("refresh:client");
|
|
469
|
+
});
|
|
470
|
+
});
|
|
471
|
+
const wsPort = 3001;
|
|
472
|
+
wsServer.listen(wsPort);
|
|
473
|
+
wsServer.on("listening", () => {
|
|
474
|
+
console.info(`Dev server listening on port ${wsPort}`);
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// src/express.ts
|
|
479
|
+
import express2 from "express";
|
|
480
|
+
import { globSync as globSync2 } from "glob";
|
|
481
|
+
|
|
482
|
+
// src/auth.ts
|
|
483
|
+
import jsonwebtoken from "jsonwebtoken";
|
|
484
|
+
var { verify, sign } = jsonwebtoken;
|
|
485
|
+
async function signUser(email, username) {
|
|
486
|
+
return new Promise((resolve, reject) => {
|
|
487
|
+
sign(
|
|
488
|
+
{
|
|
489
|
+
user: {
|
|
490
|
+
email,
|
|
491
|
+
username
|
|
492
|
+
}
|
|
493
|
+
},
|
|
494
|
+
// @ts-ignore
|
|
495
|
+
process.env.JWT_PRIVATE_KEY,
|
|
496
|
+
{ expiresIn: "30d" },
|
|
497
|
+
(err, token) => {
|
|
498
|
+
if (err) reject(err);
|
|
499
|
+
resolve(token);
|
|
500
|
+
}
|
|
501
|
+
);
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
async function verifyUser(token) {
|
|
505
|
+
return new Promise((resolve, reject) => {
|
|
506
|
+
verify(token, process.env.JWT_PRIVATE_KEY, (err, authorizedData) => {
|
|
507
|
+
if (err) reject(err);
|
|
508
|
+
resolve(authorizedData);
|
|
509
|
+
});
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
function getTokenFromRequest(req) {
|
|
513
|
+
const { authorization } = req.headers;
|
|
514
|
+
if (!authorization) return null;
|
|
515
|
+
const token = authorization.split(" ").pop() || "";
|
|
516
|
+
return token || null;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// src/express.ts
|
|
520
|
+
import requestIP from "request-ip";
|
|
521
|
+
var doctypeHTML = "<!DOCTYPE html>";
|
|
522
|
+
async function createRouter() {
|
|
523
|
+
const methods = ["get", "post", "put", "patch", "delete"];
|
|
524
|
+
const router = express2.Router();
|
|
525
|
+
const routes = globSync2(config.pagesDir + "/**/*.{tsx,ts}");
|
|
526
|
+
const routeMap = routes.map((route) => {
|
|
527
|
+
return {
|
|
528
|
+
route: route.split(config.pagesDir).pop().replace(".tsx", "").replace(".js", "").replace(".ts", "").replace("/index", "/"),
|
|
529
|
+
path: route.replace(config.srcDir, config.distDir).replace(".tsx", ".js").replace(".ts", ".js"),
|
|
530
|
+
originalRoute: route
|
|
531
|
+
};
|
|
532
|
+
});
|
|
533
|
+
const routeResults = [];
|
|
534
|
+
for (const route of routeMap) {
|
|
535
|
+
const isJSX = route.originalRoute.endsWith(".tsx") || route.originalRoute.endsWith(".jsx");
|
|
536
|
+
const routeItem = process.env.NODE_ENV === "development" ? null : (await import(route.path)).default;
|
|
537
|
+
const slugRoute = route.route.toLowerCase().replace(/[ ]/g, "");
|
|
538
|
+
const foundMethod = methods.find((method) => slugRoute.endsWith(`.${method}`));
|
|
539
|
+
const isDynamicRoute = slugRoute.match(/\[(.*)\]/g);
|
|
540
|
+
let formattedRouteItem = slugRoute;
|
|
541
|
+
if (foundMethod) formattedRouteItem = formattedRouteItem.split(".").shift();
|
|
542
|
+
if (isDynamicRoute) {
|
|
543
|
+
const result = [...formattedRouteItem.matchAll(/(\[)(.*?)(\])/g)];
|
|
544
|
+
for (const match of result) {
|
|
545
|
+
formattedRouteItem = formattedRouteItem.replace(match[0], ":" + match[2]);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
routeResults.push({
|
|
549
|
+
formattedRouteItem,
|
|
550
|
+
foundMethod,
|
|
551
|
+
route
|
|
552
|
+
});
|
|
553
|
+
router[foundMethod || "get"](formattedRouteItem, async (req, res) => {
|
|
554
|
+
try {
|
|
555
|
+
if (routeItem) {
|
|
556
|
+
if (isJSX) {
|
|
557
|
+
res.send(doctypeHTML + await routeItem(req, res));
|
|
558
|
+
} else {
|
|
559
|
+
await routeItem(req, res);
|
|
560
|
+
}
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
const defaultRouteImport = (await import(route.path + `?cache=${Date.now()}`)).default;
|
|
564
|
+
if (isJSX) {
|
|
565
|
+
res.send(doctypeHTML + await defaultRouteImport(req, res));
|
|
566
|
+
} else {
|
|
567
|
+
await defaultRouteImport(req, res);
|
|
568
|
+
}
|
|
569
|
+
} catch (err) {
|
|
570
|
+
console.error(err);
|
|
571
|
+
res.status(err?.status || 500).send(err?.message || "Error");
|
|
572
|
+
}
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
return {
|
|
576
|
+
router,
|
|
577
|
+
routeResults
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
async function verifyUserMiddleware(req, _res, next) {
|
|
581
|
+
const { usertoken } = req.cookies;
|
|
582
|
+
if (!usertoken) {
|
|
583
|
+
req.user = null;
|
|
584
|
+
}
|
|
585
|
+
try {
|
|
586
|
+
const { user } = await verifyUser(usertoken);
|
|
587
|
+
req.user = user;
|
|
588
|
+
} catch (err) {
|
|
589
|
+
req.user = null;
|
|
590
|
+
}
|
|
591
|
+
next();
|
|
592
|
+
}
|
|
593
|
+
async function createXPineRouter(app, beforeErrorRoute) {
|
|
594
|
+
app.use(express2.static(config.distPublicDir));
|
|
595
|
+
app.use(verifyUserMiddleware);
|
|
596
|
+
app.use(requestIP.mw());
|
|
597
|
+
const { router, routeResults } = await createRouter();
|
|
598
|
+
app.use(function replaceableRouter(req, res, next) {
|
|
599
|
+
router(req, res, next);
|
|
600
|
+
});
|
|
601
|
+
const found404 = routeResults?.find((item) => item?.formattedRouteItem === "/404");
|
|
602
|
+
const import404 = process.env.NODE_ENV === "development" ? null : (await import(found404.route.path)).default;
|
|
603
|
+
if (beforeErrorRoute) beforeErrorRoute(app);
|
|
604
|
+
app.use(async function(req, res) {
|
|
605
|
+
res.status(404);
|
|
606
|
+
if (import404) {
|
|
607
|
+
res.send(doctypeHTML + await import404(req, res));
|
|
608
|
+
} else if (found404 && process.env.NODE_ENV === "development") {
|
|
609
|
+
const import404Item = (await import(found404.route.path + `?cache=${Date.now()}`)).default;
|
|
610
|
+
res.send(doctypeHTML + await import404Item(req, res));
|
|
611
|
+
} else {
|
|
612
|
+
res.send("Error");
|
|
613
|
+
}
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// src/util/html.ts
|
|
618
|
+
var html = class {
|
|
619
|
+
static attributeObjectToString(props) {
|
|
620
|
+
if (!props) return "";
|
|
621
|
+
return Object.entries(props).filter(([, value]) => value !== null && value !== void 0).map(([key, value], index) => {
|
|
622
|
+
const start = index === 0 ? " " : "";
|
|
623
|
+
return `${start}${key}="${value}"`;
|
|
624
|
+
}).join(" ");
|
|
625
|
+
}
|
|
626
|
+
static async fragment(props) {
|
|
627
|
+
const childrenResult = await Promise.all(props.children.flat());
|
|
628
|
+
return childrenResult.filter(Boolean).join("");
|
|
629
|
+
}
|
|
630
|
+
static async createElement(type, props, ...children) {
|
|
631
|
+
const childrenResult = await Promise.all(children.flat());
|
|
632
|
+
if (typeof type === "function") {
|
|
633
|
+
const result = await type({ ...props, children: childrenResult });
|
|
634
|
+
return result;
|
|
635
|
+
}
|
|
636
|
+
return `<${type}${this.attributeObjectToString(props)}>${childrenResult.filter(Boolean).join("")}</${type}>`;
|
|
637
|
+
}
|
|
638
|
+
};
|
|
639
|
+
function JSXRuntime() {
|
|
640
|
+
return true;
|
|
641
|
+
}
|
|
642
|
+
export {
|
|
643
|
+
JSXRuntime,
|
|
644
|
+
buildApp,
|
|
645
|
+
buildCSS,
|
|
646
|
+
buildPublicFolderSymlinks,
|
|
647
|
+
config,
|
|
648
|
+
createRouter,
|
|
649
|
+
createXPineRouter,
|
|
650
|
+
fromRoot,
|
|
651
|
+
getTokenFromRequest,
|
|
652
|
+
html,
|
|
653
|
+
logSize,
|
|
654
|
+
runDevServer,
|
|
655
|
+
setupEnv,
|
|
656
|
+
signUser,
|
|
657
|
+
verifyUser
|
|
658
|
+
};
|
|
659
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vc3JjL3J1bkRldlNlcnZlci50cyIsICIuLi9zcmMvc2NyaXB0cy9idWlsZC50cyIsICIuLi9zcmMvYnVpbGQvdHlwZXNjcmlwdC1idWlsZGVyLnRzIiwgIi4uL3NyYy91dGlsL2dldC1jb25maWcudHMiLCAiLi4vc3JjL3V0aWwvcmVxdWlyZS50cyIsICIuLi9zcmMvdXRpbC9lbnYudHMiLCAiLi4vc3JjL2V4cHJlc3MudHMiLCAiLi4vc3JjL2F1dGgudHMiLCAiLi4vc3JjL3V0aWwvaHRtbC50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiaW1wb3J0IGV4cHJlc3NXcyBmcm9tICdleHByZXNzLXdzJztcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xuaW1wb3J0IGV4cHJlc3MgZnJvbSAnZXhwcmVzcyc7XG5pbXBvcnQgRXZlbnRFbWl0dGVyIGZyb20gJ2V2ZW50cyc7XG5pbXBvcnQgY2hva2lkYXIgZnJvbSAnY2hva2lkYXInO1xuaW1wb3J0IHsgYnVpbGRBcHAgfSBmcm9tICcuL3NjcmlwdHMvYnVpbGQnO1xuaW1wb3J0IHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgeyBjb25maWcgfSBmcm9tICcuL3V0aWwvZ2V0LWNvbmZpZyc7XG5pbXBvcnQgeyBzZXR1cEVudiB9IGZyb20gJy4vdXRpbC9lbnYnO1xuXG5zZXR1cEVudigpO1xuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcnVuRGV2U2VydmVyKCkge1xuICBwcm9jZXNzLmVudi5OT0RFX0VOViA9ICdkZXZlbG9wbWVudCc7XG4gIGNvbnN0IHN0YXJ0U2VydmVyID0gYXdhaXQgaW1wb3J0KGNvbmZpZy5zZXJ2ZXJEaXN0QXBwUGF0aCArIGA/Y2FjaGU9JHtEYXRlLm5vdygpfWApO1xuXG4gIC8vIEluaXRpYWwgc2VydmVyIHNldCB1cFxuICBhd2FpdCBidWlsZEFwcCh0cnVlKTtcbiAgbGV0IGFwcFNlcnZlciA9IGF3YWl0IHN0YXJ0U2VydmVyLmRlZmF1bHQoKTtcblxuICAvLyBXYXRjaCBmaWxlc1xuICBjb25zdCB3YXRjaGVyID0gY2hva2lkYXIud2F0Y2goY29uZmlnLnNyY0Rpciwge1xuICAgIGlnbm9yZUluaXRpYWw6IHRydWUsXG4gICAgLy8gSWdub3JlIG1hcCBhbmQgcHJpc21hIGZpbGVzXG4gICAgaWdub3JlZDogKHBhdGhOYW1lKSA9PiBwYXRoTmFtZS5lbmRzV2l0aCgnLm1hcCcpIHx8IHBhdGhOYW1lLnN0YXJ0c1dpdGgocGF0aC5qb2luKGNvbmZpZy5zZXJ2ZXJEaXIsICcuL3ByaXNtYScpKSxcbiAgfSk7XG4gIHdhdGNoZXIub24oJ2FsbCcsIGFzeW5jIChldmVudCwgcGF0aCkgPT4ge1xuICAgIGNvbnN0IHNob3VsZFJlbG9hZFNlcnZlciA9IChwYXRoLnN0YXJ0c1dpdGgoY29uZmlnLnNlcnZlckRpcikgJiYgIXBhdGguc3RhcnRzV2l0aChjb25maWcucnVuRGlyKSkgfHxcbiAgICAgIFsnYWRkJywgJ3VubGluayddLmluY2x1ZGVzKGV2ZW50KSAmJiBwYXRoLnN0YXJ0c1dpdGgoY29uZmlnLnBhZ2VzRGlyKTtcbiAgICBpZiAoc2hvdWxkUmVsb2FkU2VydmVyKSB7XG4gICAgICAvLyBXZSBtb2RpZmllZCBmaWxlcyBpbiB0aGUgc2VydmVyLCByZXN0YXJ0IHRoZSBzZXJ2ZXJcbiAgICAgIGFwcFNlcnZlci5zZXJ2ZXIuY2xvc2UoKTtcbiAgICAgIGF3YWl0IGJ1aWxkQXBwKHRydWUpO1xuICAgICAgY29uc3Qgc3RhcnRTZXJ2ZXIgPSBhd2FpdCBpbXBvcnQoY29uZmlnLnNlcnZlckRpc3RBcHBQYXRoICsgYD9jYWNoZT0ke0RhdGUubm93KCl9YCk7XG4gICAgICBhcHBTZXJ2ZXIgPSBhd2FpdCBzdGFydFNlcnZlci5kZWZhdWx0KCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGF3YWl0IGJ1aWxkQXBwKHRydWUpO1xuICAgIHJlZnJlc2hFbWl0dGVyLmVtaXQoJ3JlZnJlc2gnKTtcbiAgfSk7XG5cbiAgLy8gQ3JlYXRlIHdlYiBzb2NrZXQgc2V2ZXJcbiAgY29uc3Qgd3NBcHAgPSBleHByZXNzKCk7XG4gIGNvbnN0IHdzU2VydmVyID0gaHR0cC5jcmVhdGVTZXJ2ZXIod3NBcHApO1xuICBleHByZXNzV3Mod3NBcHAsIHdzU2VydmVyKTtcbiAgY2xhc3MgUmVmcmVzaEVtaXR0ZXIgZXh0ZW5kcyBFdmVudEVtaXR0ZXIgeyB9O1xuICBjb25zdCByZWZyZXNoRW1pdHRlciA9IG5ldyBSZWZyZXNoRW1pdHRlcigpO1xuXG4gIC8vIEB0cy1pZ25vcmVcbiAgd3NBcHAud3MoJy9kZXYtc2VydmVyJywgZnVuY3Rpb24gKHdzKSB7XG4gICAgcmVmcmVzaEVtaXR0ZXIucmVtb3ZlQWxsTGlzdGVuZXJzKCk7XG4gICAgcmVmcmVzaEVtaXR0ZXIub24oJ3JlZnJlc2gnLCAoKSA9PiB7XG4gICAgICB3cy5zZW5kKCdyZWZyZXNoOmNsaWVudCcpO1xuICAgIH0pO1xuICB9KTtcblxuICBjb25zdCB3c1BvcnQgPSAzMDAxO1xuICB3c1NlcnZlci5saXN0ZW4od3NQb3J0KTtcbiAgd3NTZXJ2ZXIub24oJ2xpc3RlbmluZycsICgpID0+IHtcbiAgICBjb25zb2xlLmluZm8oYERldiBzZXJ2ZXIgbGlzdGVuaW5nIG9uIHBvcnQgJHt3c1BvcnR9YCk7XG4gIH0pO1xufVxuXG5cbiIsICJpbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCBmcyBmcm9tICdmcy1leHRyYSc7XG5pbXBvcnQgeyBidWlsZCB9IGZyb20gJ2VzYnVpbGQnO1xuaW1wb3J0IGJ1aWx0aW5Nb2R1bGVzIGZyb20gJ2J1aWx0aW4tbW9kdWxlcyc7XG5pbXBvcnQgdHMgZnJvbSAndHlwZXNjcmlwdCc7XG5pbXBvcnQge1xuICBjb252ZXJ0RW50cnlQb2ludHNUb1NpbmdsZUZpbGUsXG4gIGZpbmREYXRhQXR0cmlidXRlc0FuZEZ1bmN0aW9ucyxcbiAgcmVtb3ZlQ2xpZW50U2NyaXB0SW5UU1hGaWxlXG59IGZyb20gJy4uL2J1aWxkL3R5cGVzY3JpcHQtYnVpbGRlcic7XG5pbXBvcnQgeyBnbG9iU3luYyB9IGZyb20gJ2dsb2InO1xuaW1wb3J0IHBvc3Rjc3MgZnJvbSAncG9zdGNzcyc7XG4vLyBAdHMtaWdub3JlXG5pbXBvcnQgdGFpbHdpbmRQb3N0Y3NzIGZyb20gJ0B0YWlsd2luZGNzcy9wb3N0Y3NzJztcbmltcG9ydCB7IGNvbmZpZyB9IGZyb20gJy4uL3V0aWwvZ2V0LWNvbmZpZyc7XG5cbi8vIEV4dGVuc2lvbnMgdG8gbG9vayBmb3IgaW4gdGhlIGJ1bmRsZVxuY29uc3QgZXh0ZW5zaW9ucyA9IFsnLnRzJywgJy50c3gnXTtcbmNvbnN0IHBhY2thZ2VKc29uID0gSlNPTi5wYXJzZShmcy5yZWFkRmlsZVN5bmMoY29uZmlnLnBhY2thZ2VKc29uUGF0aCwgJ3V0Zi04JykpO1xuY29uc3QgYWxsUGFja2FnZXMgPSBPYmplY3Qua2V5cyhwYWNrYWdlSnNvbi5kZXZEZXBlbmRlbmNpZXMpLmNvbmNhdChPYmplY3Qua2V5cyhwYWNrYWdlSnNvbi5kZXBlbmRlbmNpZXMpKTtcbmNvbnN0IGFsbFBhY2thZ2VzSW5jbHVkaW5nTm9kZSA9IGFsbFBhY2thZ2VzLmNvbmNhdChidWlsdGluTW9kdWxlcyk7XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBidWlsZEFwcChpc0RldiA9IGZhbHNlKSB7XG4gIHRyeSB7XG4gICAgY29uc3Qgc3JjRGlyRmlsZXMgPSBnbG9iU3luYyhjb25maWcuc3JjRGlyICsgJy8qKi8qLntqcyx0cyx0c3gsanN4fScpO1xuICAgIGNvbnN0IHsgY29tcG9uZW50RGF0YSwgZGF0YUZpbGVzLCB9ID0gYXdhaXQgYnVpbGRBcHBGaWxlcyhzcmNEaXJGaWxlcywgaXNEZXYpO1xuICAgIGNvbnN0IGFscGluZURhdGFGaWxlID0gYXdhaXQgYnVpbGRBbHBpbmVEYXRhRmlsZShjb21wb25lbnREYXRhLCBkYXRhRmlsZXMpO1xuICAgIGF3YWl0IGJ1aWxkQ2xpZW50U2lkZUZpbGVzKFthbHBpbmVEYXRhRmlsZV0sIGlzRGV2KTtcbiAgICBmcy5yZW1vdmVTeW5jKGNvbmZpZy5kaXN0VGVtcEZvbGRlcik7XG4gICAgYXdhaXQgYnVpbGRDU1MoKTtcbiAgICBhd2FpdCBidWlsZFB1YmxpY0ZvbGRlclN5bWxpbmtzKCk7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGNvbnNvbGUuZXJyb3IoJ0J1aWxkIGZhaWxlZCcpO1xuICAgIGNvbnNvbGUuZXJyb3IoZXJyKTtcbiAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBidWlsZEFwcEZpbGVzKGZpbGVzOiBzdHJpbmdbXSwgaXNEZXY/OiBib29sZWFuKSB7XG4gIGNvbnN0IGNvbXBvbmVudERhdGEgPSBbXTtcbiAgY29uc3QgZGF0YUZpbGVzID0gW107XG4gIC8vIEZpbHRlciBvdXQgY2xpZW50IHNpZGUgZmlsZXMgYW5kIGZpbGVzIHRoYXQgYXJlbid0IG9mIHRoZSBhbGxvd2VkIGV4dGVuc2lvbnNcbiAgY29uc3QgYmFja2VuZEZpbGVzID0gZmlsZXNcbiAgICAuZmlsdGVyKChmaWxlKSA9PiBleHRlbnNpb25zLmZpbmQoZXh0ID0+IGZpbGUuZW5kc1dpdGgoZXh0KSkpXG4gICAgLmZpbHRlcigoZmlsZSkgPT4gIWZpbGUuc3RhcnRzV2l0aChjb25maWcucHVibGljRGlyKSk7XG4gIGZzLmVuc3VyZURpclN5bmMoY29uZmlnLmRpc3REaXIpO1xuICAvLyBCdWlsZCBiYWNrZW5kL1NTUiBUU1ggbW9kdWxlc1xuICBhd2FpdCBidWlsZCh7XG4gICAgZW50cnlQb2ludHM6IGJhY2tlbmRGaWxlcyxcbiAgICBmb3JtYXQ6ICdlc20nLFxuICAgIHBsYXRmb3JtOiAnbm9kZScsXG4gICAgb3V0ZGlyOiBjb25maWcuZGlzdERpcixcbiAgICBidW5kbGU6IHRydWUsXG4gICAgc291cmNlbWFwOiBpc0RldiA/ICdpbmxpbmUnIDogZmFsc2UsXG4gICAgZXh0ZXJuYWw6IGFsbFBhY2thZ2VzLFxuICAgIGpzeDogJ3RyYW5zZm9ybScsXG4gICAgbWluaWZ5OiAhaXNEZXYsXG4gICAgcGx1Z2luczogW1xuICAgICAge1xuICAgICAgICBuYW1lOiAnYWRkLWRvdC1qcycsXG4gICAgICAgIHNldHVwKGJ1aWxkKSB7XG4gICAgICAgICAgYnVpbGQub25SZXNvbHZlKHsgZmlsdGVyOiAvLiovLCB9LCBhcmdzID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGhhc0F0U2lnbiA9IGFyZ3MucGF0aC5zdGFydHNXaXRoKCdAJyk7XG4gICAgICAgICAgICBjb25zdCBpc1BhY2thZ2UgPSBoYXNBdFNpZ24gP1xuICAgICAgICAgICAgICBhbGxQYWNrYWdlc0luY2x1ZGluZ05vZGUuaW5jbHVkZXMoYXJncy5wYXRoKSA6XG4gICAgICAgICAgICAgIGFsbFBhY2thZ2VzSW5jbHVkaW5nTm9kZS5pbmNsdWRlcyhhcmdzLnBhdGguc3BsaXQoJy8nKS5zaGlmdCgpKTtcbiAgICAgICAgICAgIGlmIChhcmdzLmltcG9ydGVyICYmICFpc1BhY2thZ2UpIHtcbiAgICAgICAgICAgICAgLy8gSWYgd2UncmUgZG9pbmcgYW4gaW5kZXggaW1wb3J0IHdlIG5lZWQgL2luZGV4LmpzXG4gICAgICAgICAgICAgIGNvbnN0IGNhbGN1bGF0ZWREaXIgPSBwYXRoLmpvaW4oYXJncy5yZXNvbHZlRGlyLCBhcmdzLnBhdGgpO1xuICAgICAgICAgICAgICBsZXQgZXhpc3RzQXNGaWxlID0gZmFsc2U7XG4gICAgICAgICAgICAgIGZvciAoY29uc3QgZXh0ZW5zaW9uIG9mIGV4dGVuc2lvbnMpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBhc0ZpbGUgPSBjYWxjdWxhdGVkRGlyICsgZXh0ZW5zaW9uO1xuICAgICAgICAgICAgICAgIGNvbnN0IGV4aXN0cyA9IGZzLmV4aXN0c1N5bmMoYXNGaWxlKTtcbiAgICAgICAgICAgICAgICBpZiAoZXhpc3RzKSBleGlzdHNBc0ZpbGUgPSB0cnVlO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIGxldCBvdXRwdXRQYXRoID0gYXJncy5wYXRoICsgKGV4aXN0c0FzRmlsZSA/ICcnIDogJy9pbmRleCcpICsgJy5qcyc7XG4gICAgICAgICAgICAgIG91dHB1dFBhdGggPSBhcmdzLnBhdGguZW5kc1dpdGgoJy5qcycpIHx8IGFyZ3MucGF0aC5lbmRzV2l0aCgnLm1qcycpID8gYXJncy5wYXRoIDogb3V0cHV0UGF0aDtcbiAgICAgICAgICAgICAgcmV0dXJuIHsgcGF0aDogb3V0cHV0UGF0aCwgZXh0ZXJuYWw6IHRydWUsIH07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBuYW1lOiAnaW5zZXJ0LWh0bWwtYmFubmVyLWFuZC1yZW1vdmUtY2xpZW50LXNjcmlwdHMnLFxuICAgICAgICBzZXR1cChidWlsZCkge1xuICAgICAgICAgIGJ1aWxkLm9uTG9hZCh7IGZpbHRlcjogLy50c3gvLCB9LCBhcmdzID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGNsZWFuZWRDb250ZW50ID0gcmVtb3ZlQ2xpZW50U2NyaXB0SW5UU1hGaWxlKGFyZ3MucGF0aCk7XG4gICAgICAgICAgICBjb25zdCBodG1sSW1wb3J0U3RhcnQgPSAnaW1wb3J0IHsgaHRtbCB9IGZyb20gXFwneHBpbmVcXCc7XFxuJztcbiAgICAgICAgICAgIGNvbnN0IG5ld0NvbnRlbnQgPSBgJHtodG1sSW1wb3J0U3RhcnR9JHtjbGVhbmVkQ29udGVudC5jb250ZW50fWA7XG4gICAgICAgICAgICBjb21wb25lbnREYXRhLnB1c2goe1xuICAgICAgICAgICAgICAuLi5hcmdzLFxuICAgICAgICAgICAgICBjb250ZW50czogYCR7aHRtbEltcG9ydFN0YXJ0fSR7Y2xlYW5lZENvbnRlbnQuZnVsbENvbnRlbnR9YCxcbiAgICAgICAgICAgICAgY2xpZW50Q29udGVudDogY2xlYW5lZENvbnRlbnQuY2xpZW50Q29udGVudCxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgY29udGVudHM6IG5ld0NvbnRlbnQsXG4gICAgICAgICAgICAgIGxvYWRlcjogJ3RzeCcsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH0pO1xuICAgICAgICB9LFxuICAgICAgfSxcbiAgICAgIHtcbiAgICAgICAgbmFtZTogJ2dldC1kYXRhLWZpbGVzJyxcbiAgICAgICAgc2V0dXAoYnVpbGQpIHtcbiAgICAgICAgICBidWlsZC5vbkxvYWQoeyBmaWx0ZXI6IC9cXC5kYXRhXFwuKGpzfG1qc3x0cykkLywgfSwgYXJncyA9PiB7XG4gICAgICAgICAgICBjb25zdCBjb250ZW50cyA9IGZzLnJlYWRGaWxlU3luYyhhcmdzLnBhdGgsICd1dGYtOCcpO1xuICAgICAgICAgICAgZGF0YUZpbGVzLnB1c2goe1xuICAgICAgICAgICAgICAuLi5hcmdzLFxuICAgICAgICAgICAgICBjb250ZW50cyxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgY29udGVudHMsXG4gICAgICAgICAgICAgIGxvYWRlcjogJ3RzJyxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0sXG4gICAgICB9XG4gICAgXSxcbiAgfSk7XG4gIGF3YWl0IGxvZ1NpemUoY29uZmlnLmRpc3REaXIsICdhcHAnKTtcbiAgcmV0dXJuIHtcbiAgICBjb21wb25lbnREYXRhLFxuICAgIGRhdGFGaWxlcyxcbiAgfTtcbn1cblxuLy8gQnVpbGQgY2xpZW50IHNpZGUgZmlsZXNcbmFzeW5jIGZ1bmN0aW9uIGJ1aWxkQ2xpZW50U2lkZUZpbGVzKGFscGluZURhdGFGaWxlczogc3RyaW5nW10gPSBbXSwgaXNEZXY/OiBib29sZWFuKSB7XG4gIC8vIFdyaXRlIHRoZSB0ZW1wIGZpbGUgdG8gdXNlXG4gIGNvbnN0IHRlbXBGaWxlUGF0aCA9IHBhdGguam9pbihjb25maWcuZGlzdFRlbXBGb2xkZXIsICcuL2FwcC50cycpO1xuICBmcy5lbnN1cmVGaWxlU3luYyh0ZW1wRmlsZVBhdGgpO1xuICAvLyBHZXQgYWxsIHRzL2pzIGZpbGVzIGluIHB1YmxpYyBmb2xkZXIgYnV0IGlnbm9yZSB0aGUgcGFnZXMgc2NyaXB0c1xuICBjb25zdCBwYWdlc1NjcmlwdHNHbG9iID0gY29uZmlnLnB1YmxpY0RpciArICcvc2NyaXB0cy9wYWdlcy8qKi8qLntqcyx0c30nO1xuICBjb25zdCBjbGllbnRGaWxlcyA9IGdsb2JTeW5jKFxuICAgIGNvbmZpZy5wdWJsaWNEaXIgKyAnLyoqLyoue2pzLHRzfScsXG4gICAge1xuICAgICAgaWdub3JlOiBwYWdlc1NjcmlwdHNHbG9iLFxuICAgIH1cbiAgKTtcbiAgLy8gRmlsdGVyIG91dCBhbGwgcHVibGljL3BhZ2VzIGZpbGVzXG4gIGNvbnZlcnRFbnRyeVBvaW50c1RvU2luZ2xlRmlsZShhbHBpbmVEYXRhRmlsZXMuY29uY2F0KGNsaWVudEZpbGVzKSwgdGVtcEZpbGVQYXRoKTtcbiAgLy8gV3JpdGUgZGV2IHNlcnZlciBjb2RlIHRvIHRoZSB0ZW1wIGZpbGUgcGF0aFxuICBpZiAoaXNEZXYpIHdyaXRlRGV2U2VydmVyQ2xpZW50U2lkZUNvZGUodGVtcEZpbGVQYXRoKTtcbiAgLy8gV3JpdGUgc3BhIGZ1bmN0aW9uYWxpdHkgdG8gdGhlIHRlbXAgZmlsZSBwYXRoXG4gIHdyaXRlU3BhQ2xpZW50U2lkZUNvZGUodGVtcEZpbGVQYXRoKTtcbiAgYXdhaXQgYnVpbGQoe1xuICAgIGVudHJ5UG9pbnRzOiBbdGVtcEZpbGVQYXRoXSxcbiAgICBidW5kbGU6IHRydWUsXG4gICAgb3V0ZGlyOiBjb25maWcuZGlzdFB1YmxpY1NjcmlwdHNEaXIsXG4gICAgbWluaWZ5OiAhaXNEZXYsXG4gICAgc291cmNlbWFwOiBpc0RldiA/ICdpbmxpbmUnIDogZmFsc2UsXG4gIH0pO1xuICAvLyBCdWlsZCBwYWdlcyBmaWxlcyBzY3JpcHRzXG4gIGNvbnN0IHBhZ2VzRmlsZXMgPSBnbG9iU3luYyhwYWdlc1NjcmlwdHNHbG9iKTtcbiAgYXdhaXQgYnVpbGQoe1xuICAgIGVudHJ5UG9pbnRzOiBwYWdlc0ZpbGVzIHx8IFtdLFxuICAgIGJ1bmRsZTogdHJ1ZSxcbiAgICBvdXRkaXI6IGNvbmZpZy5kaXN0UHVibGljU2NyaXB0c0RpciArICcvcGFnZXMnLFxuICAgIG1pbmlmeTogIWlzRGV2LFxuICAgIHNvdXJjZW1hcDogaXNEZXYgPyAnaW5saW5lJyA6IGZhbHNlLFxuICB9KTtcbiAgYXdhaXQgbG9nU2l6ZShjb25maWcuZGlzdFB1YmxpY0RpciwgJ2NsaWVudCcpO1xufVxuXG5mdW5jdGlvbiB3cml0ZURldlNlcnZlckNsaWVudFNpZGVDb2RlKHRlbXBGaWxlUGF0aDogc3RyaW5nKSB7XG4gIGNvbnN0IGRldlNlcnZlclBhdGggPSBwYXRoLmpvaW4oaW1wb3J0Lm1ldGEuZGlybmFtZSwgJy4uL3N0YXRpYy9kZXYtc2VydmVyLmpzJyk7XG4gIGNvbnN0IGNvbnRlbnQgPSBmcy5yZWFkRmlsZVN5bmMoZGV2U2VydmVyUGF0aCwgJ3V0Zi04Jyk7XG4gIGZzLmFwcGVuZEZpbGVTeW5jKHRlbXBGaWxlUGF0aCwgYFxcbmAgKyBjb250ZW50KTtcbn1cblxuZnVuY3Rpb24gd3JpdGVTcGFDbGllbnRTaWRlQ29kZSh0ZW1wRmlsZVBhdGg6IHN0cmluZykge1xuICBjb25zdCBzcGFQYXRoID0gcGF0aC5qb2luKGltcG9ydC5tZXRhLmRpcm5hbWUsICcuLi9zdGF0aWMvc3BhLmpzJyk7XG4gIGNvbnN0IGNvbnRlbnQgPSBmcy5yZWFkRmlsZVN5bmMoc3BhUGF0aCwgJ3V0Zi04Jyk7XG4gIGZzLmFwcGVuZEZpbGVTeW5jKHRlbXBGaWxlUGF0aCwgYFxcbmAgKyBjb250ZW50KTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gYnVpbGRBbHBpbmVEYXRhRmlsZShjb21wb25lbnREYXRhOiBhbnlbXSwgZGF0YUZpbGVzOiBhbnlbXSkge1xuICBjb25zdCBvdXRwdXQgPSB7XG4gICAgaW1wb3J0czogW1xuICAgICAgJ2ltcG9ydCBBbHBpbmUgZnJvbSBcXCdhbHBpbmVqc1xcJzsnXG4gICAgXSxcbiAgICBjb2RlOiBbXSxcbiAgICBlbmQ6IFtcbiAgICAgICd3aW5kb3cuQWxwaW5lID0gQWxwaW5lOydcbiAgICBdLFxuICB9O1xuICBjb25zdCBkYXRhRnVuY3Rpb25SZXN1bHRzID0ge1xuICAgIGZvdW5kRGF0YUF0dHJpYnV0ZXM6IFtdLFxuICAgIGZvdW5kRnVuY3Rpb25zOiBbXSxcbiAgICBmb3VuZEltcG9ydHM6IFtdLFxuICB9O1xuICBjb25zdCBjb21wb25lbnRzQW5kRGF0YUZpbGVzID0gY29tcG9uZW50RGF0YS5jb25jYXQoZGF0YUZpbGVzKTtcbiAgZm9yIChjb25zdCBjb21wb25lbnQgb2YgY29tcG9uZW50c0FuZERhdGFGaWxlcykge1xuICAgIC8vIFNpbmdsZSBzb3VyY2UgZmlsZVxuICAgIGNvbnN0IHNvdXJjZUZpbGUgPSB0cy5jcmVhdGVTb3VyY2VGaWxlKFxuICAgICAgY29tcG9uZW50LnBhdGgsXG4gICAgICBjb21wb25lbnQuY29udGVudHMsXG4gICAgICB0cy5TY3JpcHRUYXJnZXQuTGF0ZXN0XG4gICAgKTtcbiAgICBjb25zdCBkYXRhRnVuY3Rpb25SZXN1bHQgPSBmaW5kRGF0YUF0dHJpYnV0ZXNBbmRGdW5jdGlvbnMoc291cmNlRmlsZSwgc291cmNlRmlsZSk7XG4gICAgZGF0YUZ1bmN0aW9uUmVzdWx0cy5mb3VuZERhdGFBdHRyaWJ1dGVzLnB1c2goLi4uZGF0YUZ1bmN0aW9uUmVzdWx0LmZvdW5kRGF0YUF0dHJpYnV0ZXMpO1xuICAgIGNvbnN0IGZvdW5kRnVuY3Rpb25zV2l0aFBhdGggPSBkYXRhRnVuY3Rpb25SZXN1bHQuZm91bmRGdW5jdGlvbnMubWFwKGl0ZW0gPT4ge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgLi4uaXRlbSxcbiAgICAgICAgcGF0aDogY29tcG9uZW50LnBhdGgsXG4gICAgICAgIGNvbnRlbnQ6IGNvbXBvbmVudC5jbGllbnRDb250ZW50LFxuICAgICAgfTtcbiAgICB9KTtcbiAgICBkYXRhRnVuY3Rpb25SZXN1bHRzLmZvdW5kRnVuY3Rpb25zLnB1c2goLi4uZm91bmRGdW5jdGlvbnNXaXRoUGF0aCk7XG4gIH1cbiAgY29uc3QgdmFsaWREYXRhRnVuY3Rpb25zID0gZGF0YUZ1bmN0aW9uUmVzdWx0cy5mb3VuZEZ1bmN0aW9ucy5maWx0ZXIoaXRlbSA9PiB7XG4gICAgcmV0dXJuIGRhdGFGdW5jdGlvblJlc3VsdHMuZm91bmREYXRhQXR0cmlidXRlcy5pbmNsdWRlcyhpdGVtLm5hbWUpICYmIGl0ZW0uY29udGVudDtcbiAgfSk7XG4gIGZvciAoY29uc3QgZGF0YUZ1bmN0aW9uIG9mIHZhbGlkRGF0YUZ1bmN0aW9ucykge1xuICAgIGlmICghZGF0YUZ1bmN0aW9uLmhhc0V4cG9ydCkgY29udGludWU7XG4gICAgb3V0cHV0LmNvZGUucHVzaChkYXRhRnVuY3Rpb24uY29udGVudCk7XG4gICAgb3V0cHV0LmNvZGUucHVzaChgQWxwaW5lLmRhdGEoJyR7ZGF0YUZ1bmN0aW9uLm5hbWV9JywgJHtkYXRhRnVuY3Rpb24ubmFtZX0pO2ApO1xuICB9XG4gIGNvbnN0IHJlc3VsdCA9IG91dHB1dC5pbXBvcnRzLmpvaW4oJ1xcbicpICsgJ1xcbicgKyBvdXRwdXQuY29kZS5qb2luKCdcXG4nKSArICdcXG4nICsgb3V0cHV0LmVuZC5qb2luKCdcXG4nKTtcbiAgZnMuZW5zdXJlRmlsZVN5bmMoY29uZmlnLmFscGluZURhdGFQYXRoKTtcbiAgZnMud3JpdGVGaWxlU3luYyhjb25maWcuYWxwaW5lRGF0YVBhdGgsIHJlc3VsdCk7XG4gIHJldHVybiBjb25maWcuYWxwaW5lRGF0YVBhdGg7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBidWlsZENTUygpIHtcbiAgY29uc3QgY3NzRmlsZXMgPSBnbG9iU3luYyhjb25maWcuc3JjRGlyICsgJy8qKi8qLmNzcycpO1xuICBmb3IgKGNvbnN0IGZpbGUgb2YgY3NzRmlsZXMpIHtcbiAgICBjb25zdCBmaWxlQ29udGVudHMgPSBmcy5yZWFkRmlsZVN5bmMoZmlsZSwgJ3V0Zi04Jyk7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcG9zdGNzcyhbdGFpbHdpbmRQb3N0Y3NzKCldKS5wcm9jZXNzKGZpbGVDb250ZW50cywgeyBmcm9tOiBmaWxlLCB9KTtcbiAgICAvLyBXcml0ZSB0byBkaXN0IGZvbGRlclxuICAgIGNvbnN0IG5ld1BhdGggPSBmaWxlLnJlcGxhY2UoY29uZmlnLnNyY0RpciwgY29uZmlnLmRpc3REaXIpO1xuICAgIGZzLmVuc3VyZUZpbGVTeW5jKG5ld1BhdGgpO1xuICAgIGZzLndyaXRlRmlsZVN5bmMobmV3UGF0aCwgcmVzdWx0LmNzcyk7XG4gIH1cbiAgbG9nU2l6ZShjb25maWcuZGlzdFB1YmxpY0RpciwgJ2NzcycpO1xufVxuXG4vLyBXZSBuZWVkIHRvIHN5bWxpbmsgdGhlIG5vbiBDU1Mgb3IgSlMgZmlsZXMgZnJvbSB0aGUgc3JjL3B1YmxpYyBmb2xkZXIgaW50byB0aGUgZGlzdCBmb2xkZXJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBidWlsZFB1YmxpY0ZvbGRlclN5bWxpbmtzKCkge1xuICBjb25zdCBmaWxlcyA9IGdsb2JTeW5jKGNvbmZpZy5wdWJsaWNEaXIgKyAnLyoqLyouKicsIHtcbiAgICBpZ25vcmU6ICcvKiovKi57Y3NzLGpzLHRzLHRzeCxqc3h9JyxcbiAgfSk7XG5cbiAgLy8gQ3JlYXRlIHN5bWxpbmtzIGluIGRpc3QgZGlyZWN0b3J5XG4gIGZvciAoY29uc3QgZmlsZSBvZiBmaWxlcykge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBuZXdQYXRoID0gZmlsZS5yZXBsYWNlKGNvbmZpZy5zcmNEaXIsIGNvbmZpZy5kaXN0RGlyKTtcbiAgICAgIGNvbnN0IHNwbGl0TmV3UGF0aCA9IG5ld1BhdGguc3BsaXQoJy8nKTtcbiAgICAgIHNwbGl0TmV3UGF0aC5wb3AoKTtcbiAgICAgIGNvbnN0IG5ld0RpciA9IHNwbGl0TmV3UGF0aC5qb2luKCcvJyk7XG4gICAgICBmcy5lbnN1cmVEaXJTeW5jKG5ld0Rpcik7XG4gICAgICBmcy5zeW1saW5rU3luYyhmaWxlLCBuZXdQYXRoKTtcbiAgICB9IGNhdGNoIHsgfVxuICB9XG59XG5cbnR5cGUgRmlsZUl0ZW0gPSB7XG4gIGZpbGU6IHN0cmluZztcbiAgc2l6ZTogbnVtYmVyO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbG9nU2l6ZShwYXRoTmFtZTogc3RyaW5nLCB0eXBlOiAnYXBwJyB8ICdjbGllbnQnIHwgJ2NzcycsIHZhbGlkRXh0ZW5zaW9ucyA9IFsnLmpzJywgJy5jc3MnXSkge1xuICBjb25zdCBmaWxlcyA9IGdsb2JTeW5jKHBhdGhOYW1lICsgJy8qKi8qJyArICh0eXBlID09PSAnY3NzJyA/ICcuY3NzJyA6ICcnKSk7XG4gIGNvbnN0IGZpbGVTaXplcyA9IGZpbGVzLm1hcCgoZmlsZSkgPT4ge1xuICAgIGlmICghdmFsaWRFeHRlbnNpb25zLmZpbmQoZXh0ID0+IGZpbGUuZW5kc1dpdGgoZXh0KSkpIHJldHVybiBmYWxzZTtcbiAgICByZXR1cm4ge1xuICAgICAgZmlsZSxcbiAgICAgIHNpemU6IChmcy5zdGF0U3luYyhmaWxlKS5zaXplKSAvICgxMDI0ICogMTAwMCksXG4gICAgfTtcbiAgfSkuZmlsdGVyKEJvb2xlYW4pO1xuICBjb25zdCB0b3RhbFNpemUgPSBmaWxlU2l6ZXMucmVkdWNlKCh0b3RhbCwgY3VycmVudDogRmlsZUl0ZW0pID0+IHtcbiAgICByZXR1cm4gY3VycmVudC5zaXplICsgdG90YWw7XG4gIH0sIDApO1xuICBjb25zb2xlLmluZm8oYFske3RvdGFsU2l6ZS50b0ZpeGVkKDMpfSBNQl0gQnVpbHQgJHt0eXBlfWApO1xufVxuIiwgImltcG9ydCB0cyBmcm9tICd0eXBlc2NyaXB0JztcbmltcG9ydCBmcyBmcm9tICdmcy1leHRyYSc7XG5pbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcblxudHlwZSBJbXBvcnREZWNsYXJhdGlvbiA9IHtcbiAgbm9kZTogdHMuTm9kZTtcbiAgaW1wb3J0UGF0aDogc3RyaW5nO1xufVxuXG4vLyBub2RlIGFyZyBzaG91bGQgaW5pdGlhbGx5IGJlIHRoZSBzb3VyY2Ugbm9kZVxuZXhwb3J0IGZ1bmN0aW9uIGdldEltcG9ydERlY2xhcmF0aW9uTm9kZXMobm9kZTogdHMuTm9kZSwgc291cmNlRmlsZTogdHMuU291cmNlRmlsZSwgaW1wb3J0RGVjbGFyYXRpb25zOiBJbXBvcnREZWNsYXJhdGlvbltdID0gW10pIHtcbiAgaWYgKG5vZGUua2luZCA9PT0gdHMuU3ludGF4S2luZC5JbXBvcnREZWNsYXJhdGlvbikge1xuICAgIGxldCBpbXBvcnRQYXRoID0gbnVsbDtcbiAgICBub2RlLmZvckVhY2hDaGlsZChjaGlsZCA9PiB7XG4gICAgICBpZiAoY2hpbGQua2luZCA9PT0gdHMuU3ludGF4S2luZC5TdHJpbmdMaXRlcmFsKSB7XG4gICAgICAgIGltcG9ydFBhdGggPSBjaGlsZC5nZXRUZXh0KHNvdXJjZUZpbGUpLnJlcGxhY2UoL1tcXFwiXFwnXS9nLCAnJyk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgaW1wb3J0RGVjbGFyYXRpb25zLnB1c2goe1xuICAgICAgbm9kZSxcbiAgICAgIGltcG9ydFBhdGgsXG4gICAgfSk7XG4gIH1cbiAgbm9kZS5mb3JFYWNoQ2hpbGQoY2hpbGQgPT4ge1xuICAgIGdldEltcG9ydERlY2xhcmF0aW9uTm9kZXMoY2hpbGQsIHNvdXJjZUZpbGUsIGltcG9ydERlY2xhcmF0aW9ucyk7XG4gIH0pO1xuICByZXR1cm4gaW1wb3J0RGVjbGFyYXRpb25zO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gc3RyaXBJbXBvcnRzTm9kZXNGcm9tRmlsZShpbXBvcnRzVG9TdHJpcDogc3RyaW5nW10sIGNvbnRlbnQ6IHN0cmluZywgaW1wb3J0RGVjbGFyYXRpb25zOiBJbXBvcnREZWNsYXJhdGlvbltdKSB7XG4gIGxldCBvdXRwdXRDb250ZW50ID0gY29udGVudDtcbiAgY29uc3QgZmlsdGVyZWRJbXBvcnRzID0gaW1wb3J0RGVjbGFyYXRpb25zLmZpbHRlcihpdGVtID0+IGltcG9ydHNUb1N0cmlwLmluY2x1ZGVzKGl0ZW0uaW1wb3J0UGF0aCkpO1xuICBmb3IgKGNvbnN0IGltcG9ydEl0ZW0gb2YgZmlsdGVyZWRJbXBvcnRzKSB7XG4gICAgb3V0cHV0Q29udGVudCA9IG91dHB1dENvbnRlbnQuc2xpY2UoMCwgaW1wb3J0SXRlbS5ub2RlLnBvcykgKyBvdXRwdXRDb250ZW50LnNsaWNlKGltcG9ydEl0ZW0ubm9kZS5lbmQpO1xuICB9XG4gIHJldHVybiBvdXRwdXRDb250ZW50O1xufVxuXG50eXBlIEZvdW5kQWxwaW5lRnVuY3Rpb24gPSB7XG4gIG5hbWU6IHN0cmluZztcbiAgaXNEZWZhdWx0RXhwb3J0OiBib29sZWFuO1xuICBoYXNFeHBvcnQ6IGJvb2xlYW47XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBmaW5kRGF0YUF0dHJpYnV0ZXNBbmRGdW5jdGlvbnMoXG4gIG5vZGU6IHRzLk5vZGUsXG4gIHNvdXJjZUZpbGU6IHRzLlNvdXJjZUZpbGUsXG4gIGZvdW5kRGF0YUF0dHJpYnV0ZXM6IHN0cmluZ1tdID0gW10sXG4gIGZvdW5kRnVuY3Rpb25zOiBGb3VuZEFscGluZUZ1bmN0aW9uW10gPSBbXVxuKSB7XG4gIGlmIChub2RlLmtpbmQgPT09IHRzLlN5bnRheEtpbmQuSnN4QXR0cmlidXRlKSB7XG4gICAgY29uc3QgYXR0cmlidXRlID0gZ2V0QXR0cmlidXRlVmFsdWVQYWlyKG5vZGUsIHNvdXJjZUZpbGUpO1xuICAgIGlmIChhdHRyaWJ1dGU/LlswXSA9PT0gJ3gtZGF0YScgJiYgYXR0cmlidXRlPy5bMV0pIHtcbiAgICAgIC8vIFdlIGZvdW5kIGEgZGF0YSBhdHRyaWJ1dGUsIFxuICAgICAgLy8gc28gbm93IHdlIGhhdmUgdG8gc2VhcmNoIHRocm91Z2hvdXQgdGhlIGZpbGUgZm9yIGEgZnVuY3Rpb24gZGVjbGFyYXRpb24gb2YgdGhlIHNhbWUgbmFtZVxuICAgICAgZm91bmREYXRhQXR0cmlidXRlcy5wdXNoKGF0dHJpYnV0ZVsxXS5yZXBsYWNlKC9bXmEtekEtWjAtOV0vZywgJycpKTtcbiAgICB9XG4gIH1cbiAgaWYgKG5vZGUua2luZCA9PT0gdHMuU3ludGF4S2luZC5Tb3VyY2VGaWxlKSB7XG4gICAgbm9kZS5mb3JFYWNoQ2hpbGQoY2hpbGQgPT4ge1xuICAgICAgaWYgKFt0cy5TeW50YXhLaW5kLkZ1bmN0aW9uRGVjbGFyYXRpb24sIHRzLlN5bnRheEtpbmQuVmFyaWFibGVEZWNsYXJhdGlvbl0uaW5jbHVkZXMoY2hpbGQua2luZCkpIHtcbiAgICAgICAgY29uc3QgZnVuY3Rpb25zID0gZ2V0RnVuY3Rpb25EZWNsYXJhdGlvblZhbHVlKGNoaWxkLCBzb3VyY2VGaWxlKTtcbiAgICAgICAgZm91bmRGdW5jdGlvbnMucHVzaChmdW5jdGlvbnMpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgbm9kZS5mb3JFYWNoQ2hpbGQoY2hpbGQgPT4ge1xuICAgIGZpbmREYXRhQXR0cmlidXRlc0FuZEZ1bmN0aW9ucyhjaGlsZCwgc291cmNlRmlsZSwgZm91bmREYXRhQXR0cmlidXRlcywgZm91bmRGdW5jdGlvbnMpO1xuICB9KTtcbiAgcmV0dXJuIHtcbiAgICBmb3VuZERhdGFBdHRyaWJ1dGVzLFxuICAgIGZvdW5kRnVuY3Rpb25zLFxuICB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0QXR0cmlidXRlVmFsdWVQYWlyKG5vZGU6IHRzLk5vZGUsIHNvdXJjZUZpbGU6IHRzLlNvdXJjZUZpbGUpOiBzdHJpbmdbXSB7XG4gIGNvbnN0IHJlc3VsdCA9IFtdO1xuICBub2RlLmZvckVhY2hDaGlsZChjaGlsZCA9PiB7XG4gICAgcmVzdWx0LnB1c2goY2hpbGQuZ2V0VGV4dChzb3VyY2VGaWxlKSk7XG4gIH0pO1xuICByZXR1cm4gcmVzdWx0O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0RnVuY3Rpb25EZWNsYXJhdGlvblZhbHVlKG5vZGU6IHRzLk5vZGUsIHNvdXJjZUZpbGU6IHRzLlNvdXJjZUZpbGUpOiBGb3VuZEFscGluZUZ1bmN0aW9uIHtcbiAgY29uc3QgcmVzdWx0ID0ge1xuICAgIG5hbWU6IG51bGwsXG4gICAgaXNEZWZhdWx0RXhwb3J0OiBmYWxzZSxcbiAgICBoYXNFeHBvcnQ6IGZhbHNlLFxuICB9O1xuICBub2RlLmZvckVhY2hDaGlsZChjaGlsZCA9PiB7XG4gICAgaWYgKGNoaWxkLmtpbmQgPT09IHRzLlN5bnRheEtpbmQuRXhwb3J0S2V5d29yZCkge1xuICAgICAgcmVzdWx0Lmhhc0V4cG9ydCA9IHRydWU7XG4gICAgfVxuICAgIGlmIChjaGlsZC5raW5kID09PSB0cy5TeW50YXhLaW5kLkRlZmF1bHRLZXl3b3JkKSB7XG4gICAgICByZXN1bHQuaXNEZWZhdWx0RXhwb3J0ID0gdHJ1ZTtcbiAgICB9XG4gICAgaWYgKGNoaWxkLmtpbmQgPT09IHRzLlN5bnRheEtpbmQuSWRlbnRpZmllcikge1xuICAgICAgcmVzdWx0Lm5hbWUgPSBjaGlsZC5nZXRUZXh0KHNvdXJjZUZpbGUpO1xuICAgIH1cbiAgfSk7XG4gIHJldHVybiByZXN1bHQ7XG59XG5cbi8vIENvbnZlcnQgZW50cnkgcG9pbnQgZmlsZXMgaW50byBvbmUgYmlnIGJ1bmRsZSBmaWxlXG5leHBvcnQgZnVuY3Rpb24gY29udmVydEVudHJ5UG9pbnRzVG9TaW5nbGVGaWxlKGVudHJ5UG9pbnRzOiBzdHJpbmdbXSwgdGVtcFdyaXRlUGF0aDogc3RyaW5nKSB7XG4gIGZzLndyaXRlRmlsZVN5bmMoXG4gICAgdGVtcFdyaXRlUGF0aCxcbiAgICBlbnRyeVBvaW50c1xuICAgICAgLm1hcChlbnRyeSA9PiBgaW1wb3J0IFwiJHtlbnRyeX1cImApXG4gICAgICAuam9pbignO1xcbicpXG4gICk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByZW1vdmVDbGllbnRTY3JpcHRJblRTWEZpbGUocGF0aE5hbWU6IHN0cmluZykge1xuICBjb25zdCBjb250ZW50ID0gZnMucmVhZEZpbGVTeW5jKHBhdGhOYW1lLCAndXRmLTgnKTtcbiAgY29uc3Qgc291cmNlID0gdHMuY3JlYXRlU291cmNlRmlsZShcbiAgICBwYXRoTmFtZSxcbiAgICBjb250ZW50LFxuICAgIHRzLlNjcmlwdFRhcmdldC5MYXRlc3RcbiAgKTtcbiAgbGV0IHRvUmVtb3ZlRnJvbTogbnVtYmVyO1xuICBsZXQgY2xpZW50RGF0YVN0YXJ0OiBudW1iZXI7XG4gIGNvbnN0IGNsaWVudEltcG9ydHNUb0hvaXN0ID0gW107XG4gIGNvbnN0IGNsaWVudEltcG9ydHNUb1JlcGxhY2UgPSBbXTtcbiAgc291cmNlLmZvckVhY2hDaGlsZCgoY2hpbGQpID0+IHtcbiAgICBpZiAoY2hpbGQua2luZCA9PT0gdHMuU3ludGF4S2luZC5FeHByZXNzaW9uU3RhdGVtZW50KSB7XG4gICAgICBjb25zdCB0ZXh0ID0gY2hpbGQuZ2V0VGV4dChzb3VyY2UpO1xuICAgICAgLy8gUmVtb3ZlIGZyb20gaGVyZVxuICAgICAgaWYgKHRleHQuc3RhcnRzV2l0aCgnPHNjcmlwdCcpKSB7XG4gICAgICAgIHRvUmVtb3ZlRnJvbSA9IGNoaWxkLnBvcztcbiAgICAgICAgY2xpZW50RGF0YVN0YXJ0ID0gY2hpbGQuZW5kO1xuICAgICAgfVxuICAgIH1cbiAgICAvLyBIb2lzdCB0aGUgY2xpZW50IGltcG9ydHMgdG8gYWJvdmUgdGhlIDxzY3JpcHQgLz4gdGFnXG4gICAgaWYgKGNoaWxkLmtpbmQgPT09IHRzLlN5bnRheEtpbmQuSW1wb3J0RGVjbGFyYXRpb24gJiYgY2hpbGQucG9zID49IGNsaWVudERhdGFTdGFydCkge1xuICAgICAgY29uc3QgdGV4dCA9IGNoaWxkLmdldFRleHQoc291cmNlKTtcbiAgICAgIGNoaWxkLmZvckVhY2hDaGlsZChjaGlsZCA9PiB7XG4gICAgICAgIGlmIChjaGlsZC5raW5kID09PSB0cy5TeW50YXhLaW5kLlN0cmluZ0xpdGVyYWwpIHtcbiAgICAgICAgICAvLyBLZWVwIHRyYWNrIG9mIGNsaWVudCBpbXBvcnRzIG5lZWRlZCBmb3IgcGF0aCByZXBsYWNlbWVudCB0byBiZSBhYnNvbHV0ZVxuICAgICAgICAgIGNvbnN0IHRleHQgPSBjaGlsZC5nZXRUZXh0KHNvdXJjZSk7XG4gICAgICAgICAgY29uc3QgaW1wb3J0UGF0aCA9IHRleHQucmVwbGFjZSgvW1xcXCJcXCddL2csICcnKTtcbiAgICAgICAgICBjb25zdCBpc1JlbGF0aXZlSW1wb3J0ID0gaW1wb3J0UGF0aC5zdGFydHNXaXRoKCcuJykgfHwgaW1wb3J0UGF0aC5zdGFydHNXaXRoKCcvJyk7XG4gICAgICAgICAgaWYgKCFpc1JlbGF0aXZlSW1wb3J0KSByZXR1cm47XG4gICAgICAgICAgY2xpZW50SW1wb3J0c1RvUmVwbGFjZS5wdXNoKHtcbiAgICAgICAgICAgIG9sZDogaW1wb3J0UGF0aCxcbiAgICAgICAgICAgIG5ldzogcGF0aC5qb2luKHBhdGguZGlybmFtZShwYXRoTmFtZSksIGltcG9ydFBhdGgpLFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIGNsaWVudEltcG9ydHNUb0hvaXN0LnB1c2godGV4dCk7XG4gICAgfVxuICB9KTtcbiAgbGV0IGNsaWVudENvbnRlbnQgPSAhaXNOYU4oY2xpZW50RGF0YVN0YXJ0KSA/IGNvbnRlbnQuc2xpY2UoY2xpZW50RGF0YVN0YXJ0KSA6ICcnO1xuICBmb3IgKGNvbnN0IGNsaWVudEltcG9ydCBvZiBjbGllbnRJbXBvcnRzVG9SZXBsYWNlKSB7XG4gICAgY2xpZW50Q29udGVudCA9IGNsaWVudENvbnRlbnQucmVwbGFjZShjbGllbnRJbXBvcnQub2xkLCBjbGllbnRJbXBvcnQubmV3KTtcbiAgfVxuICByZXR1cm4ge1xuICAgIGNvbnRlbnQ6ICFpc05hTih0b1JlbW92ZUZyb20pID9cbiAgICAgIGNsaWVudEltcG9ydHNUb0hvaXN0LmpvaW4oJ1xcbicpICsgY29udGVudC5zbGljZSgwLCB0b1JlbW92ZUZyb20pIDpcbiAgICAgIGNvbnRlbnQsXG4gICAgY2xpZW50Q29udGVudCxcbiAgICBmdWxsQ29udGVudDogY29udGVudCxcbiAgICB0b1JlbW92ZUZyb20sXG4gICAgY2xpZW50RGF0YVN0YXJ0LFxuICB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcHJpbnRSZWN1cnNpdmVGcm9tKFxuICBub2RlOiB0cy5Ob2RlLCBpbmRlbnRMZXZlbDogbnVtYmVyLCBzb3VyY2VGaWxlOiB0cy5Tb3VyY2VGaWxlXG4pIHtcbiAgY29uc3QgaW5kZW50YXRpb24gPSAnLScucmVwZWF0KGluZGVudExldmVsKTtcbiAgY29uc3Qgc3ludGF4S2luZCA9IHRzLlN5bnRheEtpbmRbbm9kZS5raW5kXTtcbiAgY29uc3Qgbm9kZVRleHQgPSBub2RlLmdldFRleHQoc291cmNlRmlsZSk7XG4gIGNvbnNvbGUubG9nKGAke2luZGVudGF0aW9ufSR7c3ludGF4S2luZH06ICR7bm9kZVRleHR9YCk7XG5cbiAgbm9kZS5mb3JFYWNoQ2hpbGQoY2hpbGQgPT5cbiAgICBwcmludFJlY3Vyc2l2ZUZyb20oY2hpbGQsIGluZGVudExldmVsICsgMSwgc291cmNlRmlsZSlcbiAgKTtcbn1cbiIsICJpbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCByZXF1aXJlIGZyb20gJy4vcmVxdWlyZSc7XG5pbXBvcnQgeyBYUGluZUNvbmZpZyB9IGZyb20gJy4uLy4uL3R5cGVzJztcblxuY29uc3Qgcm9vdERpciA9IHByb2Nlc3MuY3dkKCk7XG5cbmV4cG9ydCBmdW5jdGlvbiBmcm9tUm9vdChwYXRoTmFtZT86IHN0cmluZykge1xuICBpZiAoIXBhdGhOYW1lKSByZXR1cm4gcm9vdERpcjtcbiAgcmV0dXJuIHBhdGguam9pbihyb290RGlyLCBwYXRoTmFtZSk7XG59XG5cbmNvbnN0IHVzZXJDb25maWcgPSByZXF1aXJlKHBhdGguam9pbihwcm9jZXNzLmN3ZCgpLCAnLi94cGluZS5jb25maWcubWpzJykpLmRlZmF1bHQ7XG5cbmNvbnN0IGNvbmZpZ0RlZmF1bHRzID0ge1xuICByb290RGlyOiBmcm9tUm9vdCgpLFxuICBzcmNEaXI6IGZyb21Sb290KCcuL3NyYycpLFxuICBkaXN0RGlyOiBmcm9tUm9vdCgnLi9kaXN0JyksXG4gIHBhY2thZ2VKc29uUGF0aDogZnJvbVJvb3QoJ3BhY2thZ2UuanNvbicpLFxuICAvLyBXZSBuZWVkIHRvIHVzZSBnZXR0ZXJzIGhlcmUgaW4gdGhlIGV2ZW50IHNvbWVvbmUgd2FudHMgdG8gY2hhbmdlIGZvbGRlcnMsIHN1Y2ggYXMgdGhlIGRpc3QgZm9sZGVyXG4gIGdldCBkaXN0UHVibGljRGlyKCkge1xuICAgIHJldHVybiBwYXRoLmpvaW4odGhpcy5kaXN0RGlyLCAnLi9wdWJsaWMnKTtcbiAgfSxcbiAgZ2V0IGRpc3RQdWJsaWNTY3JpcHRzRGlyKCkge1xuICAgIHJldHVybiBwYXRoLmpvaW4odGhpcy5kaXN0UHVibGljRGlyLCAnLi9zY3JpcHRzJyk7XG4gIH0sXG4gIGdldCBkaXN0VGVtcEZvbGRlcigpIHtcbiAgICByZXR1cm4gcGF0aC5qb2luKHRoaXMuZGlzdERpciwgJy4vdGVtcCcpO1xuICB9LFxuICBnZXQgY2xpZW50SlNCdW5kbGVQYXRoKCkge1xuICAgIHJldHVybiBwYXRoLmpvaW4odGhpcy5kaXN0UHVibGljU2NyaXB0c0RpciwgJy4vYXBwLmpzJyk7XG4gIH0sXG4gIGdldCBhbHBpbmVEYXRhUGF0aCgpIHtcbiAgICByZXR1cm4gcGF0aC5qb2luKHRoaXMuZGlzdFRlbXBGb2xkZXIsICcuL2FscGluZS1kYXRhLnRzJyk7XG4gIH0sXG4gIGdldCBzZXJ2ZXJEaXN0RGlyKCkge1xuICAgIHJldHVybiBwYXRoLmpvaW4odGhpcy5kaXN0RGlyLCAnLi9zZXJ2ZXInKTtcbiAgfSxcbiAgZ2V0IHNlcnZlckRpc3RBcHBQYXRoKCkge1xuICAgIHJldHVybiBwYXRoLmpvaW4odGhpcy5zZXJ2ZXJEaXN0RGlyLCAnLi9hcHAuanMnKTtcbiAgfSxcbiAgLy8gSW1wb3J0YW50IGRpcnMvcGF0aHNcbiAgZ2V0IHBhZ2VzRGlyKCkge1xuICAgIHJldHVybiBwYXRoLmpvaW4odGhpcy5zcmNEaXIsICcuL3BhZ2VzJyk7XG4gIH0sXG4gIGdldCBwdWJsaWNEaXIoKSB7XG4gICAgcmV0dXJuIHBhdGguam9pbih0aGlzLnNyY0RpciwgJy4vcHVibGljJyk7XG4gIH0sXG4gIGdldCBzZXJ2ZXJEaXIoKSB7XG4gICAgcmV0dXJuIHBhdGguam9pbih0aGlzLnNyY0RpciwgJy4vc2VydmVyJyk7XG4gIH0sXG4gIGdldCBydW5EaXIoKSB7XG4gICAgcmV0dXJuIHBhdGguam9pbih0aGlzLnNlcnZlckRpciwgJy4vcnVuJyk7XG4gIH0sXG4gIGdldCBzZXJ2ZXJBcHBQYXRoKCkge1xuICAgIHJldHVybiBwYXRoLmpvaW4odGhpcy5zZXJ2ZXJEaXIsICcuL2FwcC50cycpO1xuICB9LFxuICBnZXQgZ2xvYmFsQ1NTRmlsZSgpIHtcbiAgICByZXR1cm4gcGF0aC5qb2luKHRoaXMucHVibGljRGlyLCAnLi9zdHlsZXMvZ2xvYmFsLmNzcycpO1xuICB9LFxufTtcblxuZXhwb3J0IGNvbnN0IGNvbmZpZzogWFBpbmVDb25maWcgPSB7XG4gIC4uLmNvbmZpZ0RlZmF1bHRzLFxuICAuLi51c2VyQ29uZmlnLFxufTsiLCAiaW1wb3J0IHsgY3JlYXRlUmVxdWlyZSB9IGZyb20gJ21vZHVsZSc7XG5cbmNvbnN0IHJlcXVpcmUgPSBjcmVhdGVSZXF1aXJlKGltcG9ydC5tZXRhLnVybCk7XG5cbmV4cG9ydCBkZWZhdWx0IHJlcXVpcmU7IiwgImltcG9ydCBkb3RlbnYgZnJvbSAnZG90ZW52JztcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgY29uZmlnIH0gZnJvbSAnLi9nZXQtY29uZmlnJztcblxuZXhwb3J0IGZ1bmN0aW9uIHNldHVwRW52KCkge1xuICBkb3RlbnYuY29uZmlnKHsgcGF0aDogcGF0aC5qb2luKGNvbmZpZy5yb290RGlyLCBgLi8uZW52LiR7cHJvY2Vzcy5lbnYuU1RBR0UgfHwgJ2Rldid9YCksfSk7XG59XG4iLCAiaW1wb3J0IGV4cHJlc3MsIHsgTmV4dEZ1bmN0aW9uLCBFeHByZXNzLCBSZXF1ZXN0LCBSZXNwb25zZSB9IGZyb20gJ2V4cHJlc3MnO1xuaW1wb3J0IHsgZ2xvYlN5bmMgfSBmcm9tICdnbG9iJztcbmltcG9ydCB7IGNvbmZpZyB9IGZyb20gJy4vdXRpbC9nZXQtY29uZmlnJztcbmltcG9ydCB7IHZlcmlmeVVzZXIgfSBmcm9tICcuL2F1dGgnO1xuaW1wb3J0IHJlcXVlc3RJUCBmcm9tICdyZXF1ZXN0LWlwJztcbmltcG9ydCB7IFNlcnZlclJlcXVlc3QgfSBmcm9tICcuLi90eXBlcyc7XG5cbmNvbnN0IGRvY3R5cGVIVE1MID0gJzwhRE9DVFlQRSBodG1sPic7XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGVSb3V0ZXIoKSB7XG4gIGNvbnN0IG1ldGhvZHMgPSBbJ2dldCcsICdwb3N0JywgJ3B1dCcsICdwYXRjaCcsICdkZWxldGUnXTtcbiAgY29uc3Qgcm91dGVyID0gZXhwcmVzcy5Sb3V0ZXIoKTtcbiAgY29uc3Qgcm91dGVzID0gZ2xvYlN5bmMoY29uZmlnLnBhZ2VzRGlyICsgJy8qKi8qLnt0c3gsdHN9Jyk7XG4gIGNvbnN0IHJvdXRlTWFwID0gcm91dGVzLm1hcChyb3V0ZSA9PiB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHJvdXRlOiByb3V0ZS5zcGxpdChjb25maWcucGFnZXNEaXIpLnBvcCgpLnJlcGxhY2UoJy50c3gnLCAnJykucmVwbGFjZSgnLmpzJywgJycpLnJlcGxhY2UoJy50cycsICcnKS5yZXBsYWNlKCcvaW5kZXgnLCAnLycpLFxuICAgICAgcGF0aDogcm91dGUucmVwbGFjZShjb25maWcuc3JjRGlyLCBjb25maWcuZGlzdERpcikucmVwbGFjZSgnLnRzeCcsICcuanMnKS5yZXBsYWNlKCcudHMnLCAnLmpzJyksXG4gICAgICBvcmlnaW5hbFJvdXRlOiByb3V0ZSxcbiAgICB9O1xuICB9KTtcbiAgY29uc3Qgcm91dGVSZXN1bHRzID0gW107XG5cbiAgZm9yIChjb25zdCByb3V0ZSBvZiByb3V0ZU1hcCkge1xuICAgIGNvbnN0IGlzSlNYID0gcm91dGUub3JpZ2luYWxSb3V0ZS5lbmRzV2l0aCgnLnRzeCcpIHx8IHJvdXRlLm9yaWdpbmFsUm91dGUuZW5kc1dpdGgoJy5qc3gnKTtcbiAgICAvLyBJbXBvcnQgcm91dGVcbiAgICBjb25zdCByb3V0ZUl0ZW0gPSBwcm9jZXNzLmVudi5OT0RFX0VOViA9PT0gJ2RldmVsb3BtZW50JyA/IG51bGwgOiAoYXdhaXQgaW1wb3J0KHJvdXRlLnBhdGgpKS5kZWZhdWx0O1xuICAgIC8vIENvbmZpZ3VyZSByZXN1bHQsbWV0aG9kcyBmb3IgdGhlIHJvdXRlXG4gICAgY29uc3Qgc2x1Z1JvdXRlID0gcm91dGUucm91dGUudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC9bIF0vZywgJycpO1xuICAgIGNvbnN0IGZvdW5kTWV0aG9kID0gbWV0aG9kcy5maW5kKG1ldGhvZCA9PiBzbHVnUm91dGUuZW5kc1dpdGgoYC4ke21ldGhvZH1gKSk7XG4gICAgY29uc3QgaXNEeW5hbWljUm91dGUgPSBzbHVnUm91dGUubWF0Y2goL1xcWyguKilcXF0vZyk7XG4gICAgbGV0IGZvcm1hdHRlZFJvdXRlSXRlbSA9IHNsdWdSb3V0ZTtcbiAgICBpZiAoZm91bmRNZXRob2QpIGZvcm1hdHRlZFJvdXRlSXRlbSA9IGZvcm1hdHRlZFJvdXRlSXRlbS5zcGxpdCgnLicpLnNoaWZ0KCk7XG4gICAgLy8gSGFuZGxlIGR5bmFtaWMgcm91dGluZ1xuICAgIGlmIChpc0R5bmFtaWNSb3V0ZSkge1xuICAgICAgY29uc3QgcmVzdWx0ID0gWy4uLmZvcm1hdHRlZFJvdXRlSXRlbS5tYXRjaEFsbCgvKFxcWykoLio/KShcXF0pL2cpXTtcbiAgICAgIGZvciAoY29uc3QgbWF0Y2ggb2YgcmVzdWx0KSB7XG4gICAgICAgIGZvcm1hdHRlZFJvdXRlSXRlbSA9IGZvcm1hdHRlZFJvdXRlSXRlbS5yZXBsYWNlKG1hdGNoWzBdLCAnOicgKyBtYXRjaFsyXSk7XG4gICAgICB9XG4gICAgfVxuICAgIC8vIFB1c2ggdG8gdGhlIHJvdXRlIHJlc3VsdHMgYXJyYXlcbiAgICByb3V0ZVJlc3VsdHMucHVzaCh7XG4gICAgICBmb3JtYXR0ZWRSb3V0ZUl0ZW0sXG4gICAgICBmb3VuZE1ldGhvZCxcbiAgICAgIHJvdXRlLFxuICAgIH0pO1xuICAgIHJvdXRlcltmb3VuZE1ldGhvZCB8fCAnZ2V0J10oZm9ybWF0dGVkUm91dGVJdGVtLCBhc3luYyAocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlKSA9PiB7XG4gICAgICB0cnkge1xuICAgICAgICAvLyBDaGVjayBpZiBpdCdzIGEgc3RyaW5nIHJlc3BvbnNlIGZyb20gdGhlIHJvdXRlSXRlbSBvciBpcyBhIGRpZmZlcmVudCByZXNwb25zZVxuICAgICAgICBpZiAocm91dGVJdGVtKSB7XG4gICAgICAgICAgaWYgKGlzSlNYKSB7XG4gICAgICAgICAgICByZXMuc2VuZChkb2N0eXBlSFRNTCArIChhd2FpdCByb3V0ZUl0ZW0ocmVxLCByZXMpKSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGF3YWl0IHJvdXRlSXRlbShyZXEsIHJlcyk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBkZWZhdWx0Um91dGVJbXBvcnQgPSAoYXdhaXQgaW1wb3J0KHJvdXRlLnBhdGggKyBgP2NhY2hlPSR7RGF0ZS5ub3coKX1gKSkuZGVmYXVsdDtcbiAgICAgICAgLy8gUmVxdWlyZSBldmVyeSB0aW1lIG9ubHkgaWYgaW4gZGV2ZWxvcG1lbnQgbW9kZVxuICAgICAgICBpZiAoaXNKU1gpIHtcbiAgICAgICAgICByZXMuc2VuZChkb2N0eXBlSFRNTCArIChhd2FpdCBkZWZhdWx0Um91dGVJbXBvcnQocmVxLCByZXMpKSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgYXdhaXQgZGVmYXVsdFJvdXRlSW1wb3J0KHJlcSwgcmVzKTtcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyKTtcbiAgICAgICAgcmVzLnN0YXR1cyhlcnI/LnN0YXR1cyB8fCA1MDApLnNlbmQoZXJyPy5tZXNzYWdlIHx8ICdFcnJvcicpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG4gIHJldHVybiB7XG4gICAgcm91dGVyLFxuICAgIHJvdXRlUmVzdWx0cyxcbiAgfTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gdmVyaWZ5VXNlck1pZGRsZXdhcmUocmVxOiBTZXJ2ZXJSZXF1ZXN0LCBfcmVzOiBSZXNwb25zZSwgbmV4dDogTmV4dEZ1bmN0aW9uKSB7XG4gIC8vIEB0cy1pZ25vcmVcbiAgY29uc3QgeyB1c2VydG9rZW4sIH0gPSByZXEuY29va2llcztcbiAgaWYgKCF1c2VydG9rZW4pIHtcbiAgICByZXEudXNlciA9IG51bGw7XG4gIH1cbiAgdHJ5IHtcbiAgICBjb25zdCB7IHVzZXIsIH0gPSBhd2FpdCB2ZXJpZnlVc2VyKHVzZXJ0b2tlbik7XG4gICAgcmVxLnVzZXIgPSB1c2VyO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICByZXEudXNlciA9IG51bGw7XG4gIH1cbiAgbmV4dCgpO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlWFBpbmVSb3V0ZXIoYXBwOiBhbnksIGJlZm9yZUVycm9yUm91dGU/OiAoYXBwOiBFeHByZXNzKSA9PiB2b2lkKSB7XG4gIGFwcC51c2UoZXhwcmVzcy5zdGF0aWMoY29uZmlnLmRpc3RQdWJsaWNEaXIpKTtcbiAgYXBwLnVzZSh2ZXJpZnlVc2VyTWlkZGxld2FyZSk7XG4gIGFwcC51c2UocmVxdWVzdElQLm13KCkpO1xuXG4gIGNvbnN0IHsgcm91dGVyLCByb3V0ZVJlc3VsdHMsIH0gPSBhd2FpdCBjcmVhdGVSb3V0ZXIoKTtcbiAgYXBwLnVzZShmdW5jdGlvbiByZXBsYWNlYWJsZVJvdXRlcihyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UsIG5leHQ6IE5leHRGdW5jdGlvbikge1xuICAgIHJvdXRlcihyZXEsIHJlcywgbmV4dCk7XG4gIH0pO1xuXG4gIGNvbnN0IGZvdW5kNDA0ID0gcm91dGVSZXN1bHRzPy5maW5kKGl0ZW0gPT4gaXRlbT8uZm9ybWF0dGVkUm91dGVJdGVtID09PSAnLzQwNCcpO1xuICBjb25zdCBpbXBvcnQ0MDQgPSBwcm9jZXNzLmVudi5OT0RFX0VOViA9PT0gJ2RldmVsb3BtZW50JyA/IG51bGwgOiAoYXdhaXQgaW1wb3J0KGZvdW5kNDA0LnJvdXRlLnBhdGgpKS5kZWZhdWx0O1xuXG4gIGlmIChiZWZvcmVFcnJvclJvdXRlKSBiZWZvcmVFcnJvclJvdXRlKGFwcCk7XG5cbiAgLy8gZXJyb3IgaGFuZGxlclxuICBhcHAudXNlKGFzeW5jIGZ1bmN0aW9uIChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UpIHtcbiAgICAvLyByZW5kZXIgdGhlIGVycm9yIHBhZ2VcbiAgICByZXMuc3RhdHVzKDQwNCk7XG5cbiAgICBpZiAoaW1wb3J0NDA0KSB7XG4gICAgICByZXMuc2VuZChkb2N0eXBlSFRNTCArIChhd2FpdCBpbXBvcnQ0MDQocmVxLCByZXMpKSk7XG4gICAgfSBlbHNlIGlmIChmb3VuZDQwNCAmJiBwcm9jZXNzLmVudi5OT0RFX0VOViA9PT0gJ2RldmVsb3BtZW50Jykge1xuICAgICAgY29uc3QgaW1wb3J0NDA0SXRlbSA9IChhd2FpdCBpbXBvcnQoZm91bmQ0MDQucm91dGUucGF0aCArIGA/Y2FjaGU9JHtEYXRlLm5vdygpfWApKS5kZWZhdWx0XG4gICAgICByZXMuc2VuZChkb2N0eXBlSFRNTCArIChhd2FpdCBpbXBvcnQ0MDRJdGVtKHJlcSwgcmVzKSkpO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXMuc2VuZCgnRXJyb3InKTtcbiAgICB9XG4gIH0pO1xufSIsICJpbXBvcnQganNvbndlYnRva2VuIGZyb20gJ2pzb253ZWJ0b2tlbic7XG5pbXBvcnQgeyBTZXJ2ZXJSZXF1ZXN0IH0gZnJvbSAnLi4vdHlwZXMnO1xuY29uc3QgeyB2ZXJpZnksIHNpZ24sIH0gPSBqc29ud2VidG9rZW47XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzaWduVXNlcihlbWFpbDogc3RyaW5nLCB1c2VybmFtZTogc3RyaW5nKSB7XG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgc2lnbihcbiAgICAgIHtcbiAgICAgICAgdXNlcjoge1xuICAgICAgICAgIGVtYWlsLFxuICAgICAgICAgIHVzZXJuYW1lLFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICAgIC8vIEB0cy1pZ25vcmVcbiAgICAgIHByb2Nlc3MuZW52LkpXVF9QUklWQVRFX0tFWSxcbiAgICAgIHsgZXhwaXJlc0luOiAnMzBkJywgfSxcbiAgICAgIChlcnIsIHRva2VuKSA9PiB7XG4gICAgICAgIGlmIChlcnIpIHJlamVjdChlcnIpO1xuICAgICAgICByZXNvbHZlKHRva2VuKTtcbiAgICAgIH0pO1xuICB9KTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHZlcmlmeVVzZXIodG9rZW46IHN0cmluZyk6IFByb21pc2U8YW55PiB7XG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgLy8gQHRzLWlnbm9yZVxuICAgIHZlcmlmeSh0b2tlbiwgcHJvY2Vzcy5lbnYuSldUX1BSSVZBVEVfS0VZLCAoZXJyLCBhdXRob3JpemVkRGF0YSkgPT4ge1xuICAgICAgaWYgKGVycikgcmVqZWN0KGVycik7XG4gICAgICByZXNvbHZlKGF1dGhvcml6ZWREYXRhKTtcbiAgICB9KTtcbiAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRUb2tlbkZyb21SZXF1ZXN0KHJlcTogU2VydmVyUmVxdWVzdCkge1xuICAvLyBAdHMtaWdub3JlXG4gIGNvbnN0IHsgYXV0aG9yaXphdGlvbiwgfSA9IHJlcS5oZWFkZXJzO1xuICBpZiAoIWF1dGhvcml6YXRpb24pIHJldHVybiBudWxsO1xuICBjb25zdCB0b2tlbiA9IGF1dGhvcml6YXRpb24uc3BsaXQoJyAnKS5wb3AoKSB8fCAnJztcbiAgcmV0dXJuIHRva2VuIHx8IG51bGw7XG59IiwgImV4cG9ydCBjbGFzcyBodG1sIHtcblxuICBzdGF0aWMgYXR0cmlidXRlT2JqZWN0VG9TdHJpbmcocHJvcHMpIHtcbiAgICBpZiAoIXByb3BzKSByZXR1cm4gJyc7XG4gICAgcmV0dXJuIE9iamVjdC5lbnRyaWVzKHByb3BzKVxuICAgICAgLmZpbHRlcigoWywgdmFsdWVdKSA9PiB2YWx1ZSAhPT0gbnVsbCAmJiB2YWx1ZSAhPT0gdW5kZWZpbmVkKVxuICAgICAgLm1hcCgoW2tleSwgdmFsdWVdLCBpbmRleCkgPT4ge1xuICAgICAgICBjb25zdCBzdGFydCA9IGluZGV4ID09PSAwID8gJyAnIDogJyc7XG4gICAgICAgIHJldHVybiBgJHtzdGFydH0ke2tleX09XCIke3ZhbHVlfVwiYDtcbiAgICAgIH0pXG4gICAgICAuam9pbignICcpO1xuICB9XG5cbiAgc3RhdGljIGFzeW5jIGZyYWdtZW50KHByb3BzKSB7XG4gICAgY29uc3QgY2hpbGRyZW5SZXN1bHQgPSBhd2FpdCBQcm9taXNlLmFsbChwcm9wcy5jaGlsZHJlbi5mbGF0KCkpO1xuICAgIHJldHVybiBjaGlsZHJlblJlc3VsdC5maWx0ZXIoQm9vbGVhbikuam9pbignJyk7XG4gIH1cblxuICBzdGF0aWMgYXN5bmMgY3JlYXRlRWxlbWVudCh0eXBlLCBwcm9wcywgLi4uY2hpbGRyZW4pIHtcbiAgICBjb25zdCBjaGlsZHJlblJlc3VsdCA9IGF3YWl0IFByb21pc2UuYWxsKGNoaWxkcmVuLmZsYXQoKSk7XG4gICAgLy8gSGFuZGxlIHBhc3NpbmcgaW4gYW5vdGhlciBlbGVtZW50XG4gICAgaWYgKHR5cGVvZiB0eXBlID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0eXBlKHsgLi4ucHJvcHMsIGNoaWxkcmVuOiBjaGlsZHJlblJlc3VsdCwgfSk7XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cbiAgICByZXR1cm4gYDwke3R5cGV9JHt0aGlzLmF0dHJpYnV0ZU9iamVjdFRvU3RyaW5nKHByb3BzKX0+JHtjaGlsZHJlblJlc3VsdC5maWx0ZXIoQm9vbGVhbikuam9pbignJyl9PC8ke3R5cGV9PmA7XG4gIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIEpTWFJ1bnRpbWUoKSB7XG4gIHJldHVybiB0cnVlO1xufSJdLAogICJtYXBwaW5ncyI6ICI7QUFBQSxPQUFPLGVBQWU7QUFDdEIsT0FBTyxVQUFVO0FBQ2pCLE9BQU8sYUFBYTtBQUNwQixPQUFPLGtCQUFrQjtBQUN6QixPQUFP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LEtBQUssQ0FBQztBQUM5RCxXQUFPLGVBQWUsT0FBTyxPQUFPLEVBQUUsS0FBSyxFQUFFO0FBQUEsRUFDL0M7QUFBQSxFQUVBLGFBQWEsY0FBYyxNQUFNLFVBQVUsVUFBVTtBQUNuRCxVQUFNLGlCQUFpQixNQUFNLFFBQVEsSUFBSSxTQUFTLEtBQUssQ0FBQztBQUV4RCxRQUFJLE9BQU8sU0FBUyxZQUFZO0FBQzlCLFlBQU0sU0FBUyxNQUFNLEtBQUssRUFBRSxHQUFHLE9BQU8sVUFBVSxlQUFnQixDQUFDO0FBQ2pFLGFBQU87QUFBQSxJQUNUO0FBQ0EsV0FBTyxJQUFJLElBQUksR0FBRyxLQUFLLHdCQUF3QixLQUFLLENBQUMsSUFBSSxlQUFlLE9BQU8sT0FBTyxFQUFFLEtBQUssRUFBRSxDQUFDLEtBQUssSUFBSTtBQUFBLEVBQzNHO0FBQ0Y7QUFFTyxTQUFTLGFBQWE7QUFDM0IsU0FBTztBQUNUOyIsCiAgIm5hbWVzIjogWyJwYXRoIiwgImZzIiwgInRzIiwgImNoaWxkIiwgInRleHQiLCAicGF0aCIsICJyZXF1aXJlIiwgInBhdGgiLCAiZnMiLCAiYnVpbGQiLCAicGF0aCIsICJ0cyIsICJwYXRoIiwgInBhdGgiLCAicGF0aCIsICJwYXRoIiwgInN0YXJ0U2VydmVyIiwgImV4cHJlc3MiLCAiZ2xvYlN5bmMiLCAiZXhwcmVzcyIsICJnbG9iU3luYyJdCn0K
|