@nlabs/lex 1.48.6 → 1.49.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/.storybook/main.ts +9 -2
  2. package/.vscode/settings.json +1 -6
  3. package/README.md +276 -4
  4. package/eslint.config.mjs +24 -0
  5. package/examples/lex.config.js +18 -8
  6. package/examples/serverless-example/README.md +109 -0
  7. package/examples/serverless-example/dist/handlers/echo.js +15 -0
  8. package/examples/serverless-example/dist/handlers/graphql.js +137 -0
  9. package/examples/serverless-example/dist/handlers/hello.js +15 -0
  10. package/examples/serverless-example/dist/handlers/test.js +17 -0
  11. package/examples/serverless-example/dist/handlers/websocket.js +14 -0
  12. package/examples/serverless-example/lex.config.mjs +74 -0
  13. package/jest.config.mjs +13 -12
  14. package/{dist → lib}/LexConfig.d.ts +14 -6
  15. package/lib/LexConfig.js +268 -0
  16. package/lib/commands/ai/ai.js +303 -0
  17. package/{dist → lib}/commands/build/build.d.ts +3 -0
  18. package/lib/commands/build/build.js +494 -0
  19. package/{dist → lib}/commands/clean/clean.js +1 -1
  20. package/lib/commands/compile/compile.js +241 -0
  21. package/lib/commands/copy/copy.js +38 -0
  22. package/{dist → lib}/commands/create/create.js +1 -1
  23. package/{dist → lib}/commands/dev/dev.d.ts +2 -0
  24. package/lib/commands/dev/dev.js +286 -0
  25. package/{dist → lib}/commands/init/init.js +1 -1
  26. package/{dist → lib}/commands/lint/lint.d.ts +4 -1
  27. package/lib/commands/lint/lint.js +993 -0
  28. package/{dist → lib}/commands/migrate/migrate.js +1 -1
  29. package/lib/commands/publish/publish.js +104 -0
  30. package/lib/commands/serverless/serverless.d.ts +17 -0
  31. package/lib/commands/serverless/serverless.js +662 -0
  32. package/lib/commands/storybook/storybook.js +249 -0
  33. package/lib/commands/test/test.js +428 -0
  34. package/lib/commands/update/update.js +128 -0
  35. package/lib/commands/versions/versions.js +41 -0
  36. package/{dist → lib}/create/changelog.js +1 -1
  37. package/{dist → lib}/index.d.ts +2 -0
  38. package/{dist → lib}/index.js +3 -1
  39. package/lib/lex.js +73 -0
  40. package/lib/storybook/index.d.ts +5 -0
  41. package/lib/types.js +1 -0
  42. package/lib/utils/aiService.d.ts +9 -0
  43. package/lib/utils/aiService.js +299 -0
  44. package/{dist → lib}/utils/app.d.ts +3 -0
  45. package/lib/utils/app.js +296 -0
  46. package/lib/utils/deepMerge.js +26 -0
  47. package/{dist → lib}/utils/file.d.ts +7 -3
  48. package/lib/utils/file.js +229 -0
  49. package/lib/utils/translations.d.ts +1 -0
  50. package/lib/utils/translations.js +74 -0
  51. package/package.json +62 -50
  52. package/postcss.config.js +5 -3
  53. package/tsconfig.build.json +2 -2
  54. package/webpack.config.js +229 -39
  55. package/dist/LexConfig.js +0 -286
  56. package/dist/commands/ai/ai.js +0 -303
  57. package/dist/commands/build/build.js +0 -404
  58. package/dist/commands/compile/compile.js +0 -234
  59. package/dist/commands/copy/copy.js +0 -38
  60. package/dist/commands/dev/dev.js +0 -74
  61. package/dist/commands/lint/lint.js +0 -811
  62. package/dist/commands/publish/publish.js +0 -104
  63. package/dist/commands/storybook/storybook.js +0 -249
  64. package/dist/commands/test/test.js +0 -429
  65. package/dist/commands/update/update.js +0 -132
  66. package/dist/commands/versions/versions.js +0 -41
  67. package/dist/lex.js +0 -70
  68. package/dist/utils/aiService.d.ts +0 -9
  69. package/dist/utils/aiService.js +0 -299
  70. package/dist/utils/app.js +0 -267
  71. package/dist/utils/deepMerge.js +0 -24
  72. package/dist/utils/file.js +0 -185
  73. package/emptyModule.js +0 -0
  74. package/eslint.config.js +0 -7
  75. /package/{dist → lib}/Button.stories.d.ts +0 -0
  76. /package/{dist → lib}/commands/ai/ai.d.ts +0 -0
  77. /package/{dist → lib}/commands/ai/index.d.ts +0 -0
  78. /package/{dist → lib}/commands/ai/index.js +0 -0
  79. /package/{dist → lib}/commands/clean/clean.d.ts +0 -0
  80. /package/{dist → lib}/commands/compile/compile.d.ts +0 -0
  81. /package/{dist → lib}/commands/config/config.d.ts +0 -0
  82. /package/{dist → lib}/commands/config/config.js +0 -0
  83. /package/{dist → lib}/commands/copy/copy.d.ts +0 -0
  84. /package/{dist → lib}/commands/create/create.d.ts +0 -0
  85. /package/{dist → lib}/commands/init/init.d.ts +0 -0
  86. /package/{dist → lib}/commands/link/link.d.ts +0 -0
  87. /package/{dist → lib}/commands/link/link.js +0 -0
  88. /package/{dist → lib}/commands/lint/autofix.d.ts +0 -0
  89. /package/{dist → lib}/commands/migrate/migrate.d.ts +0 -0
  90. /package/{dist → lib}/commands/publish/publish.d.ts +0 -0
  91. /package/{dist → lib}/commands/storybook/storybook.d.ts +0 -0
  92. /package/{dist → lib}/commands/test/test.d.ts +0 -0
  93. /package/{dist → lib}/commands/update/update.d.ts +0 -0
  94. /package/{dist → lib}/commands/upgrade/upgrade.d.ts +0 -0
  95. /package/{dist → lib}/commands/upgrade/upgrade.js +0 -0
  96. /package/{dist → lib}/commands/versions/versions.d.ts +0 -0
  97. /package/{dist → lib}/create/changelog.d.ts +0 -0
  98. /package/{dist → lib}/lex.d.ts +0 -0
  99. /package/{dist/types.js → lib/storybook/index.js} +0 -0
  100. /package/{dist → lib}/test-react/index.d.ts +0 -0
  101. /package/{dist → lib}/test-react/index.js +0 -0
  102. /package/{dist → lib}/types.d.ts +0 -0
  103. /package/{dist → lib}/utils/deepMerge.d.ts +0 -0
  104. /package/{dist → lib}/utils/log.d.ts +0 -0
  105. /package/{dist → lib}/utils/log.js +0 -0
  106. /package/{dist → lib}/utils/reactShim.d.ts +0 -0
  107. /package/{dist → lib}/utils/reactShim.js +0 -0
@@ -0,0 +1,662 @@
1
+ import boxen from "boxen";
2
+ import chalk from "chalk";
3
+ import express from "express";
4
+ import { readFileSync, existsSync, mkdirSync, writeFileSync } from "fs";
5
+ import { networkInterfaces, homedir } from "os";
6
+ import { resolve as pathResolve, join } from "path";
7
+ import { WebSocketServer } from "ws";
8
+ import { LexConfig } from "../../LexConfig.js";
9
+ import { createSpinner, removeFiles } from "../../utils/app.js";
10
+ import { log } from "../../utils/log.js";
11
+ const getCacheDir = () => {
12
+ const cacheDir = join(homedir(), ".lex-cache");
13
+ if (!existsSync(cacheDir)) {
14
+ mkdirSync(cacheDir, { recursive: true });
15
+ }
16
+ return cacheDir;
17
+ };
18
+ const getCachePath = () => join(getCacheDir(), "public-ip.json");
19
+ const readPublicIpCache = () => {
20
+ const cachePath = getCachePath();
21
+ if (!existsSync(cachePath)) {
22
+ return null;
23
+ }
24
+ try {
25
+ const cacheData = readFileSync(cachePath, "utf8");
26
+ const cache = JSON.parse(cacheData);
27
+ const oneWeekMs = 7 * 24 * 60 * 60 * 1e3;
28
+ if (Date.now() - cache.timestamp > oneWeekMs) {
29
+ return null;
30
+ }
31
+ return cache;
32
+ } catch {
33
+ return null;
34
+ }
35
+ };
36
+ const writePublicIpCache = (ip) => {
37
+ const cachePath = getCachePath();
38
+ const cache = {
39
+ ip,
40
+ timestamp: Date.now()
41
+ };
42
+ writeFileSync(cachePath, JSON.stringify(cache, null, 2));
43
+ };
44
+ const fetchPublicIp = (forceRefresh = false) => new Promise((resolve) => {
45
+ if (!forceRefresh) {
46
+ const cached = readPublicIpCache();
47
+ if (cached) {
48
+ resolve(cached.ip);
49
+ return;
50
+ }
51
+ }
52
+ fetch("https://api.ipify.org").then((res) => res.text()).then((data) => {
53
+ const ip = data.trim();
54
+ if (ip) {
55
+ writePublicIpCache(ip);
56
+ }
57
+ resolve(ip);
58
+ }).catch(() => resolve(void 0));
59
+ });
60
+ const getNetworkAddresses = () => {
61
+ const interfaces = networkInterfaces();
62
+ const addresses = {
63
+ local: "localhost",
64
+ private: null,
65
+ public: null
66
+ };
67
+ for (const name of Object.keys(interfaces)) {
68
+ const networkInterface = interfaces[name];
69
+ if (!networkInterface) {
70
+ continue;
71
+ }
72
+ for (const iface of networkInterface) {
73
+ if (iface.family === "IPv4" && !iface.internal) {
74
+ const ip = iface.address;
75
+ if (ip.startsWith("10.") || ip.startsWith("192.168.") || ip.startsWith("172.")) {
76
+ if (!addresses.private) {
77
+ addresses.private = ip;
78
+ }
79
+ } else {
80
+ if (!addresses.public) {
81
+ addresses.public = ip;
82
+ }
83
+ }
84
+ }
85
+ }
86
+ }
87
+ return addresses;
88
+ };
89
+ const displayServerStatus = (httpPort, httpsPort, wsPort, host, quiet, publicIp) => {
90
+ if (quiet) {
91
+ return;
92
+ }
93
+ const httpUrl = `http://${host}:${httpPort}`;
94
+ const httpsUrl = `https://${host}:${httpsPort}`;
95
+ const wsUrl = `ws://${host}:${wsPort}`;
96
+ const wssUrl = `wss://${host}:${wsPort}`;
97
+ let urlLines = `${chalk.green("HTTP:")} ${chalk.underline(httpUrl)}
98
+ `;
99
+ urlLines += `${chalk.green("HTTPS:")} ${chalk.underline(httpsUrl)}
100
+ `;
101
+ urlLines += `${chalk.green("WebSocket:")} ${chalk.underline(wsUrl)}
102
+ `;
103
+ urlLines += `${chalk.green("WSS:")} ${chalk.underline(wssUrl)}
104
+ `;
105
+ if (publicIp) {
106
+ urlLines += `
107
+ ${chalk.green("Public:")} ${chalk.underline(`http://${publicIp}:${httpPort}`)}
108
+ `;
109
+ }
110
+ const statusBox = boxen(
111
+ `${chalk.cyan.bold("\u{1F680} Serverless Development Server Running")}
112
+
113
+ ${urlLines}
114
+ ${chalk.yellow("Press Ctrl+C to stop the server")}`,
115
+ {
116
+ padding: 1,
117
+ margin: 1,
118
+ borderStyle: "round",
119
+ borderColor: "cyan",
120
+ backgroundColor: "#1a1a1a"
121
+ }
122
+ );
123
+ console.log(`
124
+ ${statusBox}
125
+ `);
126
+ };
127
+ const loadHandler = async (handlerPath, outputDir) => {
128
+ try {
129
+ const fullPath = pathResolve(outputDir, handlerPath);
130
+ log(`Loading handler from: ${fullPath}`, "info", false);
131
+ if (!existsSync(fullPath)) {
132
+ throw new Error(`Handler file not found: ${fullPath}`);
133
+ }
134
+ try {
135
+ const handlerModule = await import(fullPath);
136
+ log(`Handler module loaded: ${Object.keys(handlerModule)}`, "info", false);
137
+ const handler = handlerModule.default || handlerModule.handler || handlerModule;
138
+ log(`Handler found: ${typeof handler}`, "info", false);
139
+ return handler;
140
+ } catch (importError) {
141
+ log(`Import error for handler ${handlerPath}: ${importError.message}`, "error", false);
142
+ return null;
143
+ }
144
+ } catch (error) {
145
+ log(`Error loading handler ${handlerPath}: ${error.message}`, "error", false);
146
+ return null;
147
+ }
148
+ };
149
+ const captureConsoleLogs = (handler, quiet) => {
150
+ if (quiet) {
151
+ return handler;
152
+ }
153
+ return async (event, context) => {
154
+ const originalConsoleLog = console.log;
155
+ const originalConsoleError = console.error;
156
+ const originalConsoleWarn = console.warn;
157
+ const originalConsoleInfo = console.info;
158
+ const logs = [];
159
+ console.log = (...args) => {
160
+ logs.push(`[LOG] ${args.join(" ")}`);
161
+ originalConsoleLog(...args);
162
+ };
163
+ console.error = (...args) => {
164
+ logs.push(`[ERROR] ${args.join(" ")}`);
165
+ originalConsoleError(...args);
166
+ };
167
+ console.warn = (...args) => {
168
+ logs.push(`[WARN] ${args.join(" ")}`);
169
+ originalConsoleWarn(...args);
170
+ };
171
+ console.info = (...args) => {
172
+ logs.push(`[INFO] ${args.join(" ")}`);
173
+ originalConsoleInfo(...args);
174
+ };
175
+ try {
176
+ const result = await handler(event, context);
177
+ if (logs.length > 0) {
178
+ console.log(chalk.gray("--- Handler Console Output ---"));
179
+ logs.forEach((log2) => console.log(chalk.gray(log2)));
180
+ console.log(chalk.gray("--- End Handler Console Output ---"));
181
+ }
182
+ return result;
183
+ } finally {
184
+ console.log = originalConsoleLog;
185
+ console.error = originalConsoleError;
186
+ console.warn = originalConsoleWarn;
187
+ console.info = originalConsoleInfo;
188
+ }
189
+ };
190
+ };
191
+ const createExpressServer = async (config, outputDir, httpPort, host, quiet, debug, printOutput) => {
192
+ const app = express();
193
+ app.use((req, res, next) => {
194
+ res.header("Access-Control-Allow-Origin", "*");
195
+ res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS");
196
+ res.header("Access-Control-Allow-Headers", "*");
197
+ res.header("Access-Control-Allow-Credentials", "true");
198
+ if (req.method === "OPTIONS") {
199
+ res.sendStatus(200);
200
+ } else {
201
+ next();
202
+ }
203
+ });
204
+ app.use(express.json());
205
+ const loadGraphQLSchema = async () => {
206
+ try {
207
+ let graphqlHandler = null;
208
+ if (config.functions) {
209
+ for (const [functionName, functionConfig] of Object.entries(config.functions)) {
210
+ if (functionConfig.events) {
211
+ for (const event of functionConfig.events) {
212
+ if (event.http && event.http.path) {
213
+ if (event.http.path === "/public" || event.http.path === "/graphql") {
214
+ graphqlHandler = await loadHandler(functionConfig.handler, outputDir);
215
+ break;
216
+ }
217
+ }
218
+ }
219
+ }
220
+ if (graphqlHandler) {
221
+ break;
222
+ }
223
+ }
224
+ }
225
+ if (graphqlHandler) {
226
+ log("Found GraphQL handler", "info", quiet);
227
+ return graphqlHandler;
228
+ }
229
+ return null;
230
+ } catch (error) {
231
+ log(`Error loading GraphQL handler: ${error.message}`, "error", quiet);
232
+ return null;
233
+ }
234
+ };
235
+ try {
236
+ const graphqlHandler = await loadGraphQLSchema();
237
+ if (graphqlHandler) {
238
+ let graphqlPath = "/graphql";
239
+ if (config.functions) {
240
+ for (const [_functionName, functionConfig] of Object.entries(config.functions)) {
241
+ if (functionConfig.events) {
242
+ for (const event of functionConfig.events) {
243
+ if (event?.http?.path) {
244
+ graphqlPath = event.http.path;
245
+ break;
246
+ }
247
+ }
248
+ }
249
+ if (graphqlPath !== "/graphql") {
250
+ break;
251
+ }
252
+ }
253
+ }
254
+ app.use(graphqlPath, async (req, res) => {
255
+ if (debug && req.body && req.body.query) {
256
+ log("\u{1F50D} GraphQL Debug Mode: Analyzing request...", "info", false);
257
+ log(`\u{1F4DD} GraphQL Query: ${req.body.query}`, "info", false);
258
+ if (req.body.variables) {
259
+ log(`\u{1F4CA} GraphQL Variables: ${JSON.stringify(req.body.variables, null, 2)}`, "info", false);
260
+ }
261
+ if (req.body.operationName) {
262
+ log(`\u{1F3F7}\uFE0F GraphQL Operation: ${req.body.operationName}`, "info", false);
263
+ }
264
+ }
265
+ const originalConsoleLog = console.log;
266
+ const logs = [];
267
+ console.log = (...args) => {
268
+ const logMessage = args.map(
269
+ (arg) => typeof arg === "object" ? JSON.stringify(arg, null, 2) : String(arg)
270
+ ).join(" ");
271
+ logs.push(logMessage);
272
+ originalConsoleLog(`[GraphQL] ${logMessage}`);
273
+ };
274
+ const context = {
275
+ req,
276
+ res,
277
+ functionName: "graphql",
278
+ functionVersion: "$LATEST",
279
+ invokedFunctionArn: "arn:aws:lambda:us-east-1:123456789012:function:graphql",
280
+ memoryLimitInMB: "128",
281
+ awsRequestId: "test-request-id",
282
+ logGroupName: "/aws/lambda/graphql",
283
+ logStreamName: "test-log-stream",
284
+ getRemainingTimeInMillis: () => 3e4
285
+ };
286
+ const wrappedHandler = captureConsoleLogs(graphqlHandler, quiet);
287
+ try {
288
+ const result = await wrappedHandler({
289
+ httpMethod: "POST",
290
+ path: graphqlPath,
291
+ headers: req.headers,
292
+ queryStringParameters: {},
293
+ body: JSON.stringify(req.body)
294
+ }, context);
295
+ console.log = originalConsoleLog;
296
+ if (result && typeof result === "object" && result.statusCode) {
297
+ res.status(result.statusCode);
298
+ if (result.headers) {
299
+ Object.entries(result.headers).forEach(([key, value]) => {
300
+ res.setHeader(key, String(value));
301
+ });
302
+ }
303
+ res.send(result.body);
304
+ } else {
305
+ res.json(result);
306
+ }
307
+ } catch (error) {
308
+ console.log = originalConsoleLog;
309
+ log(`GraphQL handler error: ${error.message}`, "error", false);
310
+ res.status(500).json({ error: error.message });
311
+ }
312
+ });
313
+ log(`GraphQL endpoint available at http://${host}:${httpPort}${graphqlPath}`, "info", quiet);
314
+ }
315
+ } catch (error) {
316
+ log(`Error setting up GraphQL: ${error.message}`, "error", quiet);
317
+ }
318
+ app.use("/", async (req, res) => {
319
+ try {
320
+ const url = req.url || "/";
321
+ const method = req.method || "GET";
322
+ log(`${method} ${url}`, "info", false);
323
+ let matchedFunction = null;
324
+ if (config.functions) {
325
+ for (const [functionName, functionConfig] of Object.entries(config.functions)) {
326
+ if (functionConfig.events) {
327
+ for (const event of functionConfig.events) {
328
+ if (event.http) {
329
+ const eventPath = event.http.path || "/";
330
+ const eventMethod = event.http.method || "GET";
331
+ if (eventPath && eventPath === url && eventMethod === method) {
332
+ matchedFunction = functionName;
333
+ break;
334
+ }
335
+ }
336
+ }
337
+ }
338
+ if (matchedFunction) {
339
+ break;
340
+ }
341
+ }
342
+ }
343
+ if (matchedFunction && config.functions[matchedFunction]) {
344
+ const handlerPath = config.functions[matchedFunction].handler;
345
+ const handler = await loadHandler(handlerPath, outputDir);
346
+ if (handler) {
347
+ const wrappedHandler = captureConsoleLogs(handler, quiet);
348
+ const event = {
349
+ body: req.body,
350
+ headers: req.headers,
351
+ httpMethod: method,
352
+ path: url,
353
+ queryStringParameters: req.query
354
+ };
355
+ const context = {
356
+ functionName: matchedFunction,
357
+ functionVersion: "$LATEST",
358
+ invokedFunctionArn: `arn:aws:lambda:us-east-1:123456789012:function:${matchedFunction}`,
359
+ memoryLimitInMB: "128",
360
+ awsRequestId: "test-request-id",
361
+ logGroupName: `/aws/lambda/${matchedFunction}`,
362
+ logStreamName: "test-log-stream",
363
+ getRemainingTimeInMillis: () => 3e4
364
+ };
365
+ try {
366
+ const result = await wrappedHandler(event, context);
367
+ if (result && typeof result === "object" && result.statusCode) {
368
+ res.status(result.statusCode);
369
+ if (result.headers) {
370
+ Object.entries(result.headers).forEach(([key, value]) => {
371
+ res.setHeader(key, String(value));
372
+ });
373
+ }
374
+ res.send(result.body);
375
+ } else {
376
+ res.json(result);
377
+ }
378
+ } catch (error) {
379
+ log(`Handler error: ${error.message}`, "error", false);
380
+ res.status(500).json({ error: error.message });
381
+ }
382
+ } else {
383
+ res.status(404).json({ error: "Handler not found" });
384
+ }
385
+ } else {
386
+ res.status(404).json({ error: "Function not found" });
387
+ }
388
+ } catch (error) {
389
+ log(`Route handling error: ${error.message}`, "error", false);
390
+ res.status(500).json({ error: error.message });
391
+ }
392
+ });
393
+ return app;
394
+ };
395
+ const createWebSocketServer = (config, outputDir, wsPort, quiet, debug, printOutput) => {
396
+ const wss = new WebSocketServer({ port: wsPort });
397
+ wss.on("connection", async (ws, req) => {
398
+ log(`WebSocket connection established: ${req.url}`, "info", false);
399
+ ws.on("message", async (message) => {
400
+ try {
401
+ const data = JSON.parse(message.toString());
402
+ let matchedFunction = null;
403
+ if (config.functions) {
404
+ for (const [functionName, functionConfig] of Object.entries(config.functions)) {
405
+ if (functionConfig.events) {
406
+ for (const event of functionConfig.events) {
407
+ if (event.websocket) {
408
+ const route = event.websocket.route || "$connect";
409
+ if (route === "$default" || route === data.action) {
410
+ matchedFunction = functionName;
411
+ break;
412
+ }
413
+ }
414
+ }
415
+ }
416
+ if (matchedFunction) {
417
+ break;
418
+ }
419
+ }
420
+ }
421
+ if (matchedFunction && config.functions[matchedFunction]) {
422
+ const handler = await loadHandler(config.functions[matchedFunction].handler, outputDir);
423
+ if (handler) {
424
+ const wrappedHandler = captureConsoleLogs(handler, quiet);
425
+ const event = {
426
+ requestContext: {
427
+ routeKey: data.action || "$default",
428
+ connectionId: "test-connection-id",
429
+ apiGateway: {
430
+ endpoint: `ws://localhost:${wsPort}`
431
+ }
432
+ },
433
+ body: data.body || null
434
+ };
435
+ const context = {
436
+ functionName: matchedFunction,
437
+ functionVersion: "$LATEST",
438
+ invokedFunctionArn: `arn:aws:lambda:us-east-1:123456789012:function:${matchedFunction}`,
439
+ memoryLimitInMB: "128",
440
+ awsRequestId: "test-request-id",
441
+ logGroupName: `/aws/lambda/${matchedFunction}`,
442
+ logStreamName: "test-log-stream",
443
+ getRemainingTimeInMillis: () => 3e4
444
+ };
445
+ const result = await wrappedHandler(event, context);
446
+ if (result && typeof result === "object" && result.statusCode) {
447
+ const body = result.body || "";
448
+ ws.send(body);
449
+ } else {
450
+ ws.send(JSON.stringify(result));
451
+ }
452
+ } else {
453
+ ws.send(JSON.stringify({ error: "Handler not found" }));
454
+ }
455
+ } else {
456
+ ws.send(JSON.stringify({ error: "WebSocket function not found" }));
457
+ }
458
+ } catch (error) {
459
+ log(`WebSocket error: ${error.message}`, "error", false);
460
+ ws.send(JSON.stringify({ error: error.message }));
461
+ }
462
+ });
463
+ ws.on("close", () => {
464
+ log("WebSocket connection closed", "info", false);
465
+ });
466
+ });
467
+ return wss;
468
+ };
469
+ const loadEnvFile = (envPath) => {
470
+ const envVars = {};
471
+ if (!existsSync(envPath)) {
472
+ return envVars;
473
+ }
474
+ try {
475
+ const envContent = readFileSync(envPath, "utf8");
476
+ const lines = envContent.split("\n");
477
+ for (const line of lines) {
478
+ const trimmedLine = line.trim();
479
+ if (!trimmedLine || trimmedLine.startsWith("#")) {
480
+ continue;
481
+ }
482
+ const equalIndex = trimmedLine.indexOf("=");
483
+ if (equalIndex > 0) {
484
+ const key = trimmedLine.substring(0, equalIndex).trim();
485
+ const value = trimmedLine.substring(equalIndex + 1).trim();
486
+ const cleanValue = value.replace(/^["']|["']$/g, "");
487
+ if (key) {
488
+ envVars[key] = cleanValue;
489
+ }
490
+ }
491
+ }
492
+ } catch (error) {
493
+ log(`Warning: Could not load .env file at ${envPath}: ${error.message}`, "warn", false);
494
+ }
495
+ return envVars;
496
+ };
497
+ const serverless = async (cmd, callback = () => ({})) => {
498
+ const {
499
+ cliName = "Lex",
500
+ config,
501
+ host = "localhost",
502
+ httpPort = 3e3,
503
+ httpsPort = 3001,
504
+ wsPort = 3002,
505
+ quiet = false,
506
+ remove = false,
507
+ usePublicIp,
508
+ variables,
509
+ debug = false,
510
+ printOutput = false,
511
+ test = false
512
+ } = cmd;
513
+ const spinner = createSpinner(quiet);
514
+ log(`${cliName} starting serverless development server...`, "info", quiet);
515
+ await LexConfig.parseConfig(cmd);
516
+ const { outputFullPath } = LexConfig.config;
517
+ const envPaths = [
518
+ pathResolve(process.cwd(), ".env"),
519
+ pathResolve(process.cwd(), ".env.local"),
520
+ pathResolve(process.cwd(), ".env.development")
521
+ ];
522
+ let envVars = {};
523
+ for (const envPath of envPaths) {
524
+ const fileEnvVars = loadEnvFile(envPath);
525
+ if (Object.keys(fileEnvVars).length > 0) {
526
+ log(`Loaded environment variables from: ${envPath}`, "info", quiet);
527
+ }
528
+ envVars = { ...envVars, ...fileEnvVars };
529
+ }
530
+ let variablesObj = { NODE_ENV: "development", ...envVars };
531
+ if (variables) {
532
+ try {
533
+ const cliVars = JSON.parse(variables);
534
+ variablesObj = { ...variablesObj, ...cliVars };
535
+ } catch (_error) {
536
+ log(`
537
+ ${cliName} Error: Environment variables option is not a valid JSON object.`, "error", quiet);
538
+ callback(1);
539
+ return 1;
540
+ }
541
+ }
542
+ process.env = { ...process.env, ...variablesObj };
543
+ if (test) {
544
+ log("Test mode: Environment variables loaded, exiting", "info", quiet);
545
+ callback(0);
546
+ return 0;
547
+ }
548
+ if (remove) {
549
+ spinner.start("Cleaning output directory...");
550
+ await removeFiles(outputFullPath || "");
551
+ spinner.succeed("Successfully cleaned output directory!");
552
+ }
553
+ let serverlessConfig = {};
554
+ try {
555
+ const configPath = config || pathResolve(process.cwd(), "lex.config.mjs");
556
+ log(`Loading serverless config from: ${configPath}`, "info", quiet);
557
+ if (existsSync(configPath)) {
558
+ const configModule = await import(configPath);
559
+ serverlessConfig = configModule.default?.serverless || configModule.serverless || {};
560
+ log("Serverless config loaded successfully", "info", quiet);
561
+ log(`Loaded functions: ${Object.keys(serverlessConfig.functions || {}).join(", ")}`, "info", quiet);
562
+ } else {
563
+ log(`No serverless config found at ${configPath}, using defaults`, "warn", quiet);
564
+ }
565
+ } catch (error) {
566
+ log(`Error loading serverless config: ${error.message}`, "error", quiet);
567
+ }
568
+ const finalConfig = {
569
+ ...serverlessConfig,
570
+ custom: {
571
+ "serverless-offline": {
572
+ httpPort: serverlessConfig.custom?.["serverless-offline"]?.httpPort || httpPort,
573
+ httpsPort: serverlessConfig.custom?.["serverless-offline"]?.httpsPort || httpsPort,
574
+ wsPort: serverlessConfig.custom?.["serverless-offline"]?.wsPort || wsPort,
575
+ host: serverlessConfig.custom?.["serverless-offline"]?.host || host,
576
+ cors: serverlessConfig.custom?.["serverless-offline"]?.cors !== false
577
+ }
578
+ }
579
+ };
580
+ const outputDir = outputFullPath || "dist";
581
+ log(`Using output directory: ${outputDir}`, "info", quiet);
582
+ try {
583
+ spinner.start("Starting serverless development server...");
584
+ const httpPort2 = finalConfig.custom["serverless-offline"].httpPort;
585
+ const wsPort2 = finalConfig.custom["serverless-offline"].wsPort;
586
+ const host2 = finalConfig.custom["serverless-offline"].host;
587
+ log(`Creating HTTP server on ${host2}:${httpPort2}`, "info", quiet);
588
+ log(`Creating WebSocket server on port ${wsPort2}`, "info", quiet);
589
+ const expressApp = await createExpressServer(
590
+ finalConfig,
591
+ outputDir,
592
+ httpPort2,
593
+ host2,
594
+ quiet,
595
+ debug,
596
+ printOutput
597
+ );
598
+ const wsServer = createWebSocketServer(
599
+ finalConfig,
600
+ outputDir,
601
+ wsPort2,
602
+ quiet,
603
+ debug,
604
+ printOutput
605
+ );
606
+ wsServer.on("error", (error) => {
607
+ log(`WebSocket server error: ${error.message}`, "error", quiet);
608
+ spinner.fail("Failed to start WebSocket server.");
609
+ callback(1);
610
+ return;
611
+ });
612
+ const server = expressApp.listen(httpPort2, host2, () => {
613
+ spinner.succeed("Serverless development server started.");
614
+ displayServerStatus(
615
+ httpPort2,
616
+ finalConfig.custom["serverless-offline"].httpsPort,
617
+ wsPort2,
618
+ host2,
619
+ quiet
620
+ );
621
+ fetchPublicIp(usePublicIp).then((publicIp) => {
622
+ if (publicIp) {
623
+ displayServerStatus(
624
+ httpPort2,
625
+ finalConfig.custom["serverless-offline"].httpsPort,
626
+ wsPort2,
627
+ host2,
628
+ quiet,
629
+ publicIp
630
+ );
631
+ }
632
+ });
633
+ });
634
+ server.on("error", (error) => {
635
+ log(`Express server error: ${error.message}`, "error", quiet);
636
+ spinner.fail("Failed to start Express server.");
637
+ callback(1);
638
+ return;
639
+ });
640
+ const shutdown = () => {
641
+ log("\nShutting down serverless development server...", "info", quiet);
642
+ server.close();
643
+ wsServer.close();
644
+ callback(0);
645
+ };
646
+ process.on("SIGINT", shutdown);
647
+ process.on("SIGTERM", shutdown);
648
+ process.stdin.resume();
649
+ log("Serverless development server is running. Press Ctrl+C to stop.", "info", quiet);
650
+ return 0;
651
+ } catch (error) {
652
+ log(`
653
+ ${cliName} Error: ${error.message}`, "error", quiet);
654
+ spinner.fail("Failed to start serverless development server.");
655
+ callback(1);
656
+ return 1;
657
+ }
658
+ };
659
+ export {
660
+ serverless
661
+ };
662
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL2NvbW1hbmRzL3NlcnZlcmxlc3Mvc2VydmVybGVzcy50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiLyoqXG4gKiBDb3B5cmlnaHQgKGMpIDIwMTgtUHJlc2VudCwgTml0cm9nZW4gTGFicywgSW5jLlxuICogQ29weXJpZ2h0cyBsaWNlbnNlZCB1bmRlciB0aGUgTUlUIExpY2Vuc2UuIFNlZSB0aGUgYWNjb21wYW55aW5nIExJQ0VOU0UgZmlsZSBmb3IgdGVybXMuXG4gKi9cbmltcG9ydCBib3hlbiBmcm9tICdib3hlbic7XG5pbXBvcnQgY2hhbGsgZnJvbSAnY2hhbGsnO1xuaW1wb3J0IGV4cHJlc3MgZnJvbSAnZXhwcmVzcyc7XG5pbXBvcnQge3JlYWRGaWxlU3luYywgZXhpc3RzU3luYywgbWtkaXJTeW5jLCB3cml0ZUZpbGVTeW5jfSBmcm9tICdmcyc7XG5pbXBvcnQge25ldHdvcmtJbnRlcmZhY2VzLCBob21lZGlyfSBmcm9tICdvcyc7XG5pbXBvcnQge3Jlc29sdmUgYXMgcGF0aFJlc29sdmUsIGpvaW59IGZyb20gJ3BhdGgnO1xuaW1wb3J0IHtXZWJTb2NrZXRTZXJ2ZXJ9IGZyb20gJ3dzJztcblxuaW1wb3J0IHtMZXhDb25maWd9IGZyb20gJy4uLy4uL0xleENvbmZpZy5qcyc7XG5pbXBvcnQge2NyZWF0ZVNwaW5uZXIsIHJlbW92ZUZpbGVzfSBmcm9tICcuLi8uLi91dGlscy9hcHAuanMnO1xuaW1wb3J0IHtsb2d9IGZyb20gJy4uLy4uL3V0aWxzL2xvZy5qcyc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2VydmVybGVzc09wdGlvbnMge1xuICByZWFkb25seSBjbGlOYW1lPzogc3RyaW5nO1xuICByZWFkb25seSBjb25maWc/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGhvc3Q/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGh0dHBQb3J0PzogbnVtYmVyO1xuICByZWFkb25seSBodHRwc1BvcnQ/OiBudW1iZXI7XG4gIHJlYWRvbmx5IHdzUG9ydD86IG51bWJlcjtcbiAgcmVhZG9ubHkgcXVpZXQ/OiBib29sZWFuO1xuICByZWFkb25seSByZW1vdmU/OiBib29sZWFuO1xuICByZWFkb25seSB2YXJpYWJsZXM/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHVzZVB1YmxpY0lwPzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgZGVidWc/OiBib29sZWFuO1xuICByZWFkb25seSBwcmludE91dHB1dD86IGJvb2xlYW47XG4gIHJlYWRvbmx5IHRlc3Q/OiBib29sZWFuO1xufVxuXG5leHBvcnQgdHlwZSBTZXJ2ZXJsZXNzQ2FsbGJhY2sgPSAoc3RhdHVzOiBudW1iZXIpID0+IHZvaWQ7XG5cbmludGVyZmFjZSBQdWJsaWNJcENhY2hlIHtcbiAgaXA6IHN0cmluZztcbiAgdGltZXN0YW1wOiBudW1iZXI7XG59XG5cbmludGVyZmFjZSBTZXJ2ZXJsZXNzSGFuZGxlciB7XG4gIHJlYWRvbmx5IGhhbmRsZXI6IHN0cmluZztcbiAgcmVhZG9ubHkgZXZlbnRzPzogQXJyYXk8e1xuICAgIHJlYWRvbmx5IGh0dHA/OiB7XG4gICAgICByZWFkb25seSBwYXRoPzogc3RyaW5nO1xuICAgICAgcmVhZG9ubHkgbWV0aG9kPzogc3RyaW5nO1xuICAgICAgcmVhZG9ubHkgY29ycz86IGJvb2xlYW47XG4gICAgfTtcbiAgICByZWFkb25seSB3ZWJzb2NrZXQ/OiB7XG4gICAgICByZWFkb25seSByb3V0ZT86IHN0cmluZztcbiAgICB9O1xuICB9Pjtcbn1cblxuaW50ZXJmYWNlIFNlcnZlcmxlc3NDb25maWcge1xuICByZWFkb25seSBmdW5jdGlvbnM/OiBSZWNvcmQ8c3RyaW5nLCBTZXJ2ZXJsZXNzSGFuZGxlcj47XG4gIHJlYWRvbmx5IGN1c3RvbT86IHtcbiAgICByZWFkb25seSAnc2VydmVybGVzcy1vZmZsaW5lJz86IHtcbiAgICAgIHJlYWRvbmx5IGh0dHBQb3J0PzogbnVtYmVyO1xuICAgICAgcmVhZG9ubHkgaHR0cHNQb3J0PzogbnVtYmVyO1xuICAgICAgcmVhZG9ubHkgd3NQb3J0PzogbnVtYmVyO1xuICAgICAgcmVhZG9ubHkgaG9zdD86IHN0cmluZztcbiAgICAgIHJlYWRvbmx5IGNvcnM/OiBib29sZWFuO1xuICAgIH07XG4gIH07XG59XG5cbmNvbnN0IGdldENhY2hlRGlyID0gKCk6IHN0cmluZyA9PiB7XG4gIGNvbnN0IGNhY2hlRGlyID0gam9pbihob21lZGlyKCksICcubGV4LWNhY2hlJyk7XG4gIGlmKCFleGlzdHNTeW5jKGNhY2hlRGlyKSkge1xuICAgIG1rZGlyU3luYyhjYWNoZURpciwge3JlY3Vyc2l2ZTogdHJ1ZX0pO1xuICB9XG4gIHJldHVybiBjYWNoZURpcjtcbn07XG5cbmNvbnN0IGdldENhY2hlUGF0aCA9ICgpOiBzdHJpbmcgPT4gam9pbihnZXRDYWNoZURpcigpLCAncHVibGljLWlwLmpzb24nKTtcblxuY29uc3QgcmVhZFB1YmxpY0lwQ2FjaGUgPSAoKTogUHVibGljSXBDYWNoZSB8IG51bGwgPT4ge1xuICBjb25zdCBjYWNoZVBhdGggPSBnZXRDYWNoZVBhdGgoKTtcbiAgaWYoIWV4aXN0c1N5bmMoY2FjaGVQYXRoKSkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgdHJ5IHtcbiAgICBjb25zdCBjYWNoZURhdGEgPSByZWFkRmlsZVN5bmMoY2FjaGVQYXRoLCAndXRmOCcpO1xuICAgIGNvbnN0IGNhY2hlOiBQdWJsaWNJcENhY2hlID0gSlNPTi5wYXJzZShjYWNoZURhdGEpO1xuXG4gICAgLy8gQ2hlY2sgaWYgY2FjaGUgaXMgb2xkZXIgdGhhbiAxIHdlZWtcbiAgICBjb25zdCBvbmVXZWVrTXMgPSA3ICogMjQgKiA2MCAqIDYwICogMTAwMDtcbiAgICBpZihEYXRlLm5vdygpIC0gY2FjaGUudGltZXN0YW1wID4gb25lV2Vla01zKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICByZXR1cm4gY2FjaGU7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiBudWxsO1xuICB9XG59O1xuXG5jb25zdCB3cml0ZVB1YmxpY0lwQ2FjaGUgPSAoaXA6IHN0cmluZyk6IHZvaWQgPT4ge1xuICBjb25zdCBjYWNoZVBhdGggPSBnZXRDYWNoZVBhdGgoKTtcbiAgY29uc3QgY2FjaGU6IFB1YmxpY0lwQ2FjaGUgPSB7XG4gICAgaXAsXG4gICAgdGltZXN0YW1wOiBEYXRlLm5vdygpXG4gIH07XG4gIHdyaXRlRmlsZVN5bmMoY2FjaGVQYXRoLCBKU09OLnN0cmluZ2lmeShjYWNoZSwgbnVsbCwgMikpO1xufTtcblxuY29uc3QgZmV0Y2hQdWJsaWNJcCA9IChmb3JjZVJlZnJlc2g6IGJvb2xlYW4gPSBmYWxzZSk6IFByb21pc2U8c3RyaW5nIHwgdW5kZWZpbmVkPiA9PiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xuICBpZighZm9yY2VSZWZyZXNoKSB7XG4gICAgY29uc3QgY2FjaGVkID0gcmVhZFB1YmxpY0lwQ2FjaGUoKTtcbiAgICBpZihjYWNoZWQpIHtcbiAgICAgIHJlc29sdmUoY2FjaGVkLmlwKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gIH1cblxuICAvLyBVc2UgZmV0Y2ggaW5zdGVhZCBvZiBodHRwc1xuICBmZXRjaCgnaHR0cHM6Ly9hcGkuaXBpZnkub3JnJylcbiAgICAudGhlbigocmVzKSA9PiByZXMudGV4dCgpKVxuICAgIC50aGVuKChkYXRhKSA9PiB7XG4gICAgICBjb25zdCBpcCA9IGRhdGEudHJpbSgpO1xuICAgICAgaWYoaXApIHtcbiAgICAgICAgd3JpdGVQdWJsaWNJcENhY2hlKGlwKTtcbiAgICAgIH1cbiAgICAgIHJlc29sdmUoaXApO1xuICAgIH0pXG4gICAgLmNhdGNoKCgpID0+IHJlc29sdmUodW5kZWZpbmVkKSk7XG59KTtcblxuY29uc3QgZ2V0TmV0d29ya0FkZHJlc3NlcyA9ICgpID0+IHtcbiAgY29uc3QgaW50ZXJmYWNlcyA9IG5ldHdvcmtJbnRlcmZhY2VzKCk7XG4gIGNvbnN0IGFkZHJlc3NlcyA9IHtcbiAgICBsb2NhbDogJ2xvY2FsaG9zdCcsXG4gICAgcHJpdmF0ZTogbnVsbCxcbiAgICBwdWJsaWM6IG51bGxcbiAgfTtcblxuICBmb3IoY29uc3QgbmFtZSBvZiBPYmplY3Qua2V5cyhpbnRlcmZhY2VzKSkge1xuICAgIGNvbnN0IG5ldHdvcmtJbnRlcmZhY2UgPSBpbnRlcmZhY2VzW25hbWVdO1xuICAgIGlmKCFuZXR3b3JrSW50ZXJmYWNlKSB7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICBmb3IoY29uc3QgaWZhY2Ugb2YgbmV0d29ya0ludGVyZmFjZSkge1xuICAgICAgaWYoaWZhY2UuZmFtaWx5ID09PSAnSVB2NCcgJiYgIWlmYWNlLmludGVybmFsKSB7XG4gICAgICAgIGNvbnN0IGlwID0gaWZhY2UuYWRkcmVzcztcblxuICAgICAgICBpZihpcC5zdGFydHNXaXRoKCcxMC4nKSB8fCBpcC5zdGFydHNXaXRoKCcxOTIuMTY4LicpIHx8IGlwLnN0YXJ0c1dpdGgoJzE3Mi4nKSkge1xuICAgICAgICAgIGlmKCFhZGRyZXNzZXMucHJpdmF0ZSkge1xuICAgICAgICAgICAgYWRkcmVzc2VzLnByaXZhdGUgPSBpcDtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgaWYoIWFkZHJlc3Nlcy5wdWJsaWMpIHtcbiAgICAgICAgICAgIGFkZHJlc3Nlcy5wdWJsaWMgPSBpcDtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICByZXR1cm4gYWRkcmVzc2VzO1xufTtcblxuY29uc3QgZGlzcGxheVNlcnZlclN0YXR1cyA9IChcbiAgaHR0cFBvcnQ6IG51bWJlcixcbiAgaHR0cHNQb3J0OiBudW1iZXIsXG4gIHdzUG9ydDogbnVtYmVyLFxuICBob3N0OiBzdHJpbmcsXG4gIHF1aWV0OiBib29sZWFuLFxuICBwdWJsaWNJcD86IHN0cmluZ1xuKSA9PiB7XG4gIGlmKHF1aWV0KSB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgY29uc3QgaHR0cFVybCA9IGBodHRwOi8vJHtob3N0fToke2h0dHBQb3J0fWA7XG4gIGNvbnN0IGh0dHBzVXJsID0gYGh0dHBzOi8vJHtob3N0fToke2h0dHBzUG9ydH1gO1xuICBjb25zdCB3c1VybCA9IGB3czovLyR7aG9zdH06JHt3c1BvcnR9YDtcbiAgY29uc3Qgd3NzVXJsID0gYHdzczovLyR7aG9zdH06JHt3c1BvcnR9YDtcblxuICBsZXQgdXJsTGluZXMgPSBgJHtjaGFsay5ncmVlbignSFRUUDonKX0gICAgICAke2NoYWxrLnVuZGVybGluZShodHRwVXJsKX1cXG5gO1xuICB1cmxMaW5lcyArPSBgJHtjaGFsay5ncmVlbignSFRUUFM6Jyl9ICAgICAke2NoYWxrLnVuZGVybGluZShodHRwc1VybCl9XFxuYDtcbiAgdXJsTGluZXMgKz0gYCR7Y2hhbGsuZ3JlZW4oJ1dlYlNvY2tldDonKX0gJHtjaGFsay51bmRlcmxpbmUod3NVcmwpfVxcbmA7XG4gIHVybExpbmVzICs9IGAke2NoYWxrLmdyZWVuKCdXU1M6Jyl9ICAgICAgICR7Y2hhbGsudW5kZXJsaW5lKHdzc1VybCl9XFxuYDtcblxuICBpZihwdWJsaWNJcCkge1xuICAgIHVybExpbmVzICs9IGBcXG4ke2NoYWxrLmdyZWVuKCdQdWJsaWM6Jyl9ICAgICR7Y2hhbGsudW5kZXJsaW5lKGBodHRwOi8vJHtwdWJsaWNJcH06JHtodHRwUG9ydH1gKX1cXG5gO1xuICB9XG5cbiAgY29uc3Qgc3RhdHVzQm94ID0gYm94ZW4oXG4gICAgYCR7Y2hhbGsuY3lhbi5ib2xkKCdcdUQ4M0RcdURFODAgU2VydmVybGVzcyBEZXZlbG9wbWVudCBTZXJ2ZXIgUnVubmluZycpfVxcblxcbiR7dXJsTGluZXN9XFxuYCArXG4gICAgYCR7Y2hhbGsueWVsbG93KCdQcmVzcyBDdHJsK0MgdG8gc3RvcCB0aGUgc2VydmVyJyl9YCxcbiAgICB7XG4gICAgICBwYWRkaW5nOiAxLFxuICAgICAgbWFyZ2luOiAxLFxuICAgICAgYm9yZGVyU3R5bGU6ICdyb3VuZCcsXG4gICAgICBib3JkZXJDb2xvcjogJ2N5YW4nLFxuICAgICAgYmFja2dyb3VuZENvbG9yOiAnIzFhMWExYSdcbiAgICB9XG4gICk7XG5cbiAgY29uc29sZS5sb2coYFxcbiR7c3RhdHVzQm94fVxcbmApO1xufTtcblxuY29uc3QgbG9hZEhhbmRsZXIgPSBhc3luYyAoaGFuZGxlclBhdGg6IHN0cmluZywgb3V0cHV0RGlyOiBzdHJpbmcpID0+IHtcbiAgdHJ5IHtcbiAgICBjb25zdCBmdWxsUGF0aCA9IHBhdGhSZXNvbHZlKG91dHB1dERpciwgaGFuZGxlclBhdGgpO1xuICAgIGxvZyhgTG9hZGluZyBoYW5kbGVyIGZyb206ICR7ZnVsbFBhdGh9YCwgJ2luZm8nLCBmYWxzZSk7XG5cbiAgICBpZighZXhpc3RzU3luYyhmdWxsUGF0aCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgSGFuZGxlciBmaWxlIG5vdCBmb3VuZDogJHtmdWxsUGF0aH1gKTtcbiAgICB9XG5cbiAgICAvLyBEeW5hbWljIGltcG9ydCBvZiB0aGUgaGFuZGxlciB3aXRoIGJldHRlciBlcnJvciBoYW5kbGluZ1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBoYW5kbGVyTW9kdWxlID0gYXdhaXQgaW1wb3J0KGZ1bGxQYXRoKTtcbiAgICAgIGxvZyhgSGFuZGxlciBtb2R1bGUgbG9hZGVkOiAke09iamVjdC5rZXlzKGhhbmRsZXJNb2R1bGUpfWAsICdpbmZvJywgZmFsc2UpO1xuXG4gICAgICBjb25zdCBoYW5kbGVyID0gaGFuZGxlck1vZHVsZS5kZWZhdWx0IHx8IGhhbmRsZXJNb2R1bGUuaGFuZGxlciB8fCBoYW5kbGVyTW9kdWxlO1xuICAgICAgbG9nKGBIYW5kbGVyIGZvdW5kOiAke3R5cGVvZiBoYW5kbGVyfWAsICdpbmZvJywgZmFsc2UpO1xuXG4gICAgICByZXR1cm4gaGFuZGxlcjtcbiAgICB9IGNhdGNoIChpbXBvcnRFcnJvcikge1xuICAgICAgbG9nKGBJbXBvcnQgZXJyb3IgZm9yIGhhbmRsZXIgJHtoYW5kbGVyUGF0aH06ICR7aW1wb3J0RXJyb3IubWVzc2FnZX1gLCAnZXJyb3InLCBmYWxzZSk7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgbG9nKGBFcnJvciBsb2FkaW5nIGhhbmRsZXIgJHtoYW5kbGVyUGF0aH06ICR7ZXJyb3IubWVzc2FnZX1gLCAnZXJyb3InLCBmYWxzZSk7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cbn07XG5cbmNvbnN0IGNhcHR1cmVDb25zb2xlTG9ncyA9IChoYW5kbGVyOiBGdW5jdGlvbiwgcXVpZXQ6IGJvb2xlYW4pID0+IHtcbiAgaWYocXVpZXQpIHtcbiAgICByZXR1cm4gaGFuZGxlcjtcbiAgfVxuXG4gIHJldHVybiBhc3luYyAoZXZlbnQ6IGFueSwgY29udGV4dDogYW55KSA9PiB7XG4gICAgLy8gQ2FwdHVyZSBjb25zb2xlLmxvZywgY29uc29sZS5lcnJvciwgZXRjLlxuICAgIGNvbnN0IG9yaWdpbmFsQ29uc29sZUxvZyA9IGNvbnNvbGUubG9nO1xuICAgIGNvbnN0IG9yaWdpbmFsQ29uc29sZUVycm9yID0gY29uc29sZS5lcnJvcjtcbiAgICBjb25zdCBvcmlnaW5hbENvbnNvbGVXYXJuID0gY29uc29sZS53YXJuO1xuICAgIGNvbnN0IG9yaWdpbmFsQ29uc29sZUluZm8gPSBjb25zb2xlLmluZm87XG5cbiAgICBjb25zdCBsb2dzOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgY29uc29sZS5sb2cgPSAoLi4uYXJnczogYW55W10pID0+IHtcbiAgICAgIGxvZ3MucHVzaChgW0xPR10gJHthcmdzLmpvaW4oJyAnKX1gKTtcbiAgICAgIG9yaWdpbmFsQ29uc29sZUxvZyguLi5hcmdzKTtcbiAgICB9O1xuXG4gICAgY29uc29sZS5lcnJvciA9ICguLi5hcmdzOiBhbnlbXSkgPT4ge1xuICAgICAgbG9ncy5wdXNoKGBbRVJST1JdICR7YXJncy5qb2luKCcgJyl9YCk7XG4gICAgICBvcmlnaW5hbENvbnNvbGVFcnJvciguLi5hcmdzKTtcbiAgICB9O1xuXG4gICAgY29uc29sZS53YXJuID0gKC4uLmFyZ3M6IGFueVtdKSA9PiB7XG4gICAgICBsb2dzLnB1c2goYFtXQVJOXSAke2FyZ3Muam9pbignICcpfWApO1xuICAgICAgb3JpZ2luYWxDb25zb2xlV2FybiguLi5hcmdzKTtcbiAgICB9O1xuXG4gICAgY29uc29sZS5pbmZvID0gKC4uLmFyZ3M6IGFueVtdKSA9PiB7XG4gICAgICBsb2dzLnB1c2goYFtJTkZPXSAke2FyZ3Muam9pbignICcpfWApO1xuICAgICAgb3JpZ2luYWxDb25zb2xlSW5mbyguLi5hcmdzKTtcbiAgICB9O1xuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGhhbmRsZXIoZXZlbnQsIGNvbnRleHQpO1xuXG4gICAgICAvLyBPdXRwdXQgY2FwdHVyZWQgbG9nc1xuICAgICAgaWYobG9ncy5sZW5ndGggPiAwKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKGNoYWxrLmdyYXkoJy0tLSBIYW5kbGVyIENvbnNvbGUgT3V0cHV0IC0tLScpKTtcbiAgICAgICAgbG9ncy5mb3JFYWNoKChsb2cpID0+IGNvbnNvbGUubG9nKGNoYWxrLmdyYXkobG9nKSkpO1xuICAgICAgICBjb25zb2xlLmxvZyhjaGFsay5ncmF5KCctLS0gRW5kIEhhbmRsZXIgQ29uc29sZSBPdXRwdXQgLS0tJykpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH0gZmluYWxseSB7XG4gICAgICAvLyBSZXN0b3JlIG9yaWdpbmFsIGNvbnNvbGUgbWV0aG9kc1xuICAgICAgY29uc29sZS5sb2cgPSBvcmlnaW5hbENvbnNvbGVMb2c7XG4gICAgICBjb25zb2xlLmVycm9yID0gb3JpZ2luYWxDb25zb2xlRXJyb3I7XG4gICAgICBjb25zb2xlLndhcm4gPSBvcmlnaW5hbENvbnNvbGVXYXJuO1xuICAgICAgY29uc29sZS5pbmZvID0gb3JpZ2luYWxDb25zb2xlSW5mbztcbiAgICB9XG4gIH07XG59O1xuXG5jb25zdCBjcmVhdGVFeHByZXNzU2VydmVyID0gYXN5bmMgKGNvbmZpZzogU2VydmVybGVzc0NvbmZpZywgb3V0cHV0RGlyOiBzdHJpbmcsIGh0dHBQb3J0OiBudW1iZXIsIGhvc3Q6IHN0cmluZywgcXVpZXQ6IGJvb2xlYW4sIGRlYnVnOiBib29sZWFuLCBwcmludE91dHB1dDogYm9vbGVhbikgPT4ge1xuICBjb25zdCBhcHAgPSBleHByZXNzKCk7XG5cbiAgLy8gRW5hYmxlIENPUlNcbiAgYXBwLnVzZSgocmVxLCByZXMsIG5leHQpID0+IHtcbiAgICByZXMuaGVhZGVyKCdBY2Nlc3MtQ29udHJvbC1BbGxvdy1PcmlnaW4nLCAnKicpO1xuICAgIHJlcy5oZWFkZXIoJ0FjY2Vzcy1Db250cm9sLUFsbG93LU1ldGhvZHMnLCAnR0VULCBQT1NULCBQVVQsIERFTEVURSwgUEFUQ0gsIE9QVElPTlMnKTtcbiAgICByZXMuaGVhZGVyKCdBY2Nlc3MtQ29udHJvbC1BbGxvdy1IZWFkZXJzJywgJyonKTtcbiAgICByZXMuaGVhZGVyKCdBY2Nlc3MtQ29udHJvbC1BbGxvdy1DcmVkZW50aWFscycsICd0cnVlJyk7XG5cbiAgICBpZihyZXEubWV0aG9kID09PSAnT1BUSU9OUycpIHtcbiAgICAgIHJlcy5zZW5kU3RhdHVzKDIwMCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIG5leHQoKTtcbiAgICB9XG4gIH0pO1xuXG4gIC8vIFBhcnNlIEpTT04gYm9kaWVzXG4gIGFwcC51c2UoZXhwcmVzcy5qc29uKCkpO1xuXG4gIC8vIExvYWQgR3JhcGhRTCBoYW5kbGVyXG4gIGNvbnN0IGxvYWRHcmFwaFFMU2NoZW1hID0gYXN5bmMgKCkgPT4ge1xuICAgIHRyeSB7XG4gICAgICAvLyBUcnkgdG8gZmluZCBhIEdyYXBoUUwgaGFuZGxlclxuICAgICAgbGV0IGdyYXBocWxIYW5kbGVyID0gbnVsbDtcblxuICAgICAgaWYoY29uZmlnLmZ1bmN0aW9ucykge1xuICAgICAgICBmb3IoY29uc3QgW2Z1bmN0aW9uTmFtZSwgZnVuY3Rpb25Db25maWddIG9mIE9iamVjdC5lbnRyaWVzKGNvbmZpZy5mdW5jdGlvbnMpKSB7XG4gICAgICAgICAgaWYoZnVuY3Rpb25Db25maWcuZXZlbnRzKSB7XG4gICAgICAgICAgICBmb3IoY29uc3QgZXZlbnQgb2YgZnVuY3Rpb25Db25maWcuZXZlbnRzKSB7XG4gICAgICAgICAgICAgIGlmKGV2ZW50Lmh0dHAgJiYgZXZlbnQuaHR0cC5wYXRoKSB7XG4gICAgICAgICAgICAgICAgLy8gTG9vayBmb3IgR3JhcGhRTCBlbmRwb2ludHNcbiAgICAgICAgICAgICAgICBpZihldmVudC5odHRwLnBhdGggPT09ICcvcHVibGljJyB8fCBldmVudC5odHRwLnBhdGggPT09ICcvZ3JhcGhxbCcpIHtcbiAgICAgICAgICAgICAgICAgIGdyYXBocWxIYW5kbGVyID0gYXdhaXQgbG9hZEhhbmRsZXIoZnVuY3Rpb25Db25maWcuaGFuZGxlciwgb3V0cHV0RGlyKTtcbiAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBpZihncmFwaHFsSGFuZGxlcikge1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmKGdyYXBocWxIYW5kbGVyKSB7XG4gICAgICAgIGxvZygnRm91bmQgR3JhcGhRTCBoYW5kbGVyJywgJ2luZm8nLCBxdWlldCk7XG4gICAgICAgIHJldHVybiBncmFwaHFsSGFuZGxlcjtcbiAgICAgIH1cbiAgICAgIHJldHVybiBudWxsO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2coYEVycm9yIGxvYWRpbmcgR3JhcGhRTCBoYW5kbGVyOiAke2Vycm9yLm1lc3NhZ2V9YCwgJ2Vycm9yJywgcXVpZXQpO1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICB9O1xuXG4gIC8vIFNldCB1cCBHcmFwaFFMIGhhbmRsZXIgZm9yIEdyYXBoUUwgcmVxdWVzdHNcbiAgdHJ5IHtcbiAgICBjb25zdCBncmFwaHFsSGFuZGxlciA9IGF3YWl0IGxvYWRHcmFwaFFMU2NoZW1hKCk7XG4gICAgaWYoZ3JhcGhxbEhhbmRsZXIpIHtcbiAgICAgIC8vIEZpbmQgdGhlIEdyYXBoUUwgcGF0aCBmcm9tIHRoZSBzZXJ2ZXJsZXNzIGNvbmZpZ1xuICAgICAgbGV0IGdyYXBocWxQYXRoID0gJy9ncmFwaHFsJzsgLy8gZGVmYXVsdCBmYWxsYmFja1xuXG4gICAgICBpZihjb25maWcuZnVuY3Rpb25zKSB7XG4gICAgICAgIGZvcihjb25zdCBbX2Z1bmN0aW9uTmFtZSwgZnVuY3Rpb25Db25maWddIG9mIE9iamVjdC5lbnRyaWVzKGNvbmZpZy5mdW5jdGlvbnMpKSB7XG4gICAgICAgICAgaWYoZnVuY3Rpb25Db25maWcuZXZlbnRzKSB7XG4gICAgICAgICAgICBmb3IoY29uc3QgZXZlbnQgb2YgZnVuY3Rpb25Db25maWcuZXZlbnRzKSB7XG4gICAgICAgICAgICAgIGlmKGV2ZW50Py5odHRwPy5wYXRoKSB7XG4gICAgICAgICAgICAgICAgZ3JhcGhxbFBhdGggPSBldmVudC5odHRwLnBhdGg7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgaWYoZ3JhcGhxbFBhdGggIT09ICcvZ3JhcGhxbCcpIHtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBTZXQgdXAgR3JhcGhRTCBlbmRwb2ludCB3aXRoIGVuaGFuY2VkIGNvbnNvbGUubG9nIGNhcHR1cmVcbiAgICAgIGFwcC51c2UoZ3JhcGhxbFBhdGgsIGFzeW5jIChyZXEsIHJlcykgPT4ge1xuICAgICAgICAvLyBHcmFwaFFMIERlYnVnIExvZ2dpbmdcbiAgICAgICAgaWYoZGVidWcgJiYgcmVxLmJvZHkgJiYgcmVxLmJvZHkucXVlcnkpIHtcbiAgICAgICAgICBsb2coJ1x1RDgzRFx1REQwRCBHcmFwaFFMIERlYnVnIE1vZGU6IEFuYWx5emluZyByZXF1ZXN0Li4uJywgJ2luZm8nLCBmYWxzZSk7XG4gICAgICAgICAgbG9nKGBcdUQ4M0RcdURDREQgR3JhcGhRTCBRdWVyeTogJHtyZXEuYm9keS5xdWVyeX1gLCAnaW5mbycsIGZhbHNlKTtcbiAgICAgICAgICBpZihyZXEuYm9keS52YXJpYWJsZXMpIHtcbiAgICAgICAgICAgIGxvZyhgXHVEODNEXHVEQ0NBIEdyYXBoUUwgVmFyaWFibGVzOiAke0pTT04uc3RyaW5naWZ5KHJlcS5ib2R5LnZhcmlhYmxlcywgbnVsbCwgMil9YCwgJ2luZm8nLCBmYWxzZSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmKHJlcS5ib2R5Lm9wZXJhdGlvbk5hbWUpIHtcbiAgICAgICAgICAgIGxvZyhgXHVEODNDXHVERkY3XHVGRTBGICBHcmFwaFFMIE9wZXJhdGlvbjogJHtyZXEuYm9keS5vcGVyYXRpb25OYW1lfWAsICdpbmZvJywgZmFsc2UpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEVuaGFuY2VkIGNvbnNvbGUubG9nIGNhcHR1cmVcbiAgICAgICAgY29uc3Qgb3JpZ2luYWxDb25zb2xlTG9nID0gY29uc29sZS5sb2c7XG4gICAgICAgIGNvbnN0IGxvZ3M6IHN0cmluZ1tdID0gW107XG5cbiAgICAgICAgY29uc29sZS5sb2cgPSAoLi4uYXJncykgPT4ge1xuICAgICAgICAgIGNvbnN0IGxvZ01lc3NhZ2UgPSBhcmdzLm1hcCgoYXJnKSA9PlxuICAgICAgICAgICAgKHR5cGVvZiBhcmcgPT09ICdvYmplY3QnID8gSlNPTi5zdHJpbmdpZnkoYXJnLCBudWxsLCAyKSA6IFN0cmluZyhhcmcpKVxuICAgICAgICAgICkuam9pbignICcpO1xuICAgICAgICAgIGxvZ3MucHVzaChsb2dNZXNzYWdlKTtcbiAgICAgICAgICBvcmlnaW5hbENvbnNvbGVMb2coYFtHcmFwaFFMXSAke2xvZ01lc3NhZ2V9YCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgLy8gQ3JlYXRlIGNvbnRleHQgZm9yIHRoZSBoYW5kbGVyXG4gICAgICAgIGNvbnN0IGNvbnRleHQgPSB7XG4gICAgICAgICAgcmVxLFxuICAgICAgICAgIHJlcyxcbiAgICAgICAgICBmdW5jdGlvbk5hbWU6ICdncmFwaHFsJyxcbiAgICAgICAgICBmdW5jdGlvblZlcnNpb246ICckTEFURVNUJyxcbiAgICAgICAgICBpbnZva2VkRnVuY3Rpb25Bcm46ICdhcm46YXdzOmxhbWJkYTp1cy1lYXN0LTE6MTIzNDU2Nzg5MDEyOmZ1bmN0aW9uOmdyYXBocWwnLFxuICAgICAgICAgIG1lbW9yeUxpbWl0SW5NQjogJzEyOCcsXG4gICAgICAgICAgYXdzUmVxdWVzdElkOiAndGVzdC1yZXF1ZXN0LWlkJyxcbiAgICAgICAgICBsb2dHcm91cE5hbWU6ICcvYXdzL2xhbWJkYS9ncmFwaHFsJyxcbiAgICAgICAgICBsb2dTdHJlYW1OYW1lOiAndGVzdC1sb2ctc3RyZWFtJyxcbiAgICAgICAgICBnZXRSZW1haW5pbmdUaW1lSW5NaWxsaXM6ICgpID0+IDMwMDAwXG4gICAgICAgIH07XG5cbiAgICAgICAgLy8gV3JhcCBoYW5kbGVyIHdpdGggY29uc29sZSBsb2cgY2FwdHVyZVxuICAgICAgICBjb25zdCB3cmFwcGVkSGFuZGxlciA9IGNhcHR1cmVDb25zb2xlTG9ncyhncmFwaHFsSGFuZGxlciwgcXVpZXQpO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgLy8gQ2FsbCB0aGUgaGFuZGxlciB3aXRoIEdyYXBoUUwgcGFyYW1ldGVyc1xuICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHdyYXBwZWRIYW5kbGVyKHtcbiAgICAgICAgICAgIGh0dHBNZXRob2Q6ICdQT1NUJyxcbiAgICAgICAgICAgIHBhdGg6IGdyYXBocWxQYXRoLFxuICAgICAgICAgICAgaGVhZGVyczogcmVxLmhlYWRlcnMsXG4gICAgICAgICAgICBxdWVyeVN0cmluZ1BhcmFtZXRlcnM6IHt9LFxuICAgICAgICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkocmVxLmJvZHkpXG4gICAgICAgICAgfSwgY29udGV4dCk7XG5cbiAgICAgICAgICAvLyBSZXN0b3JlIGNvbnNvbGUubG9nXG4gICAgICAgICAgY29uc29sZS5sb2cgPSBvcmlnaW5hbENvbnNvbGVMb2c7XG5cbiAgICAgICAgICAvLyBIYW5kbGUgdGhlIHJlc3VsdFxuICAgICAgICAgIGlmKHJlc3VsdCAmJiB0eXBlb2YgcmVzdWx0ID09PSAnb2JqZWN0JyAmJiByZXN1bHQuc3RhdHVzQ29kZSkge1xuICAgICAgICAgICAgcmVzLnN0YXR1cyhyZXN1bHQuc3RhdHVzQ29kZSk7XG4gICAgICAgICAgICBpZihyZXN1bHQuaGVhZGVycykge1xuICAgICAgICAgICAgICBPYmplY3QuZW50cmllcyhyZXN1bHQuaGVhZGVycykuZm9yRWFjaCgoW2tleSwgdmFsdWVdKSA9PiB7XG4gICAgICAgICAgICAgICAgcmVzLnNldEhlYWRlcihrZXksIFN0cmluZyh2YWx1ZSkpO1xuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJlcy5zZW5kKHJlc3VsdC5ib2R5KTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmVzLmpzb24ocmVzdWx0KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgLy8gUmVzdG9yZSBjb25zb2xlLmxvZ1xuICAgICAgICAgIGNvbnNvbGUubG9nID0gb3JpZ2luYWxDb25zb2xlTG9nO1xuICAgICAgICAgIGxvZyhgR3JhcGhRTCBoYW5kbGVyIGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCwgJ2Vycm9yJywgZmFsc2UpO1xuICAgICAgICAgIHJlcy5zdGF0dXMoNTAwKS5qc29uKHtlcnJvcjogZXJyb3IubWVzc2FnZX0pO1xuICAgICAgICB9XG4gICAgICB9KTtcblxuICAgICAgbG9nKGBHcmFwaFFMIGVuZHBvaW50IGF2YWlsYWJsZSBhdCBodHRwOi8vJHtob3N0fToke2h0dHBQb3J0fSR7Z3JhcGhxbFBhdGh9YCwgJ2luZm8nLCBxdWlldCk7XG4gICAgfVxuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGxvZyhgRXJyb3Igc2V0dGluZyB1cCBHcmFwaFFMOiAke2Vycm9yLm1lc3NhZ2V9YCwgJ2Vycm9yJywgcXVpZXQpO1xuICB9XG5cbiAgLy8gRmFsbGJhY2sgZm9yIG5vbi1HcmFwaFFMIHJvdXRlcyAtIGhhbmRsZSBhbGwgcmVtYWluaW5nIHJvdXRlc1xuICBhcHAudXNlKCcvJywgYXN5bmMgKHJlcSwgcmVzKSA9PiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHVybCA9IHJlcS51cmwgfHwgJy8nO1xuICAgICAgY29uc3QgbWV0aG9kID0gcmVxLm1ldGhvZCB8fCAnR0VUJztcblxuICAgICAgbG9nKGAke21ldGhvZH0gJHt1cmx9YCwgJ2luZm8nLCBmYWxzZSk7XG5cbiAgICAgIC8vIEZpbmQgbWF0Y2hpbmcgZnVuY3Rpb25cbiAgICAgIGxldCBtYXRjaGVkRnVuY3Rpb24gPSBudWxsO1xuXG4gICAgICBpZihjb25maWcuZnVuY3Rpb25zKSB7XG4gICAgICAgIGZvcihjb25zdCBbZnVuY3Rpb25OYW1lLCBmdW5jdGlvbkNvbmZpZ10gb2YgT2JqZWN0LmVudHJpZXMoY29uZmlnLmZ1bmN0aW9ucykpIHtcbiAgICAgICAgICBpZihmdW5jdGlvbkNvbmZpZy5ldmVudHMpIHtcbiAgICAgICAgICAgIGZvcihjb25zdCBldmVudCBvZiBmdW5jdGlvbkNvbmZpZy5ldmVudHMpIHtcbiAgICAgICAgICAgICAgaWYoZXZlbnQuaHR0cCkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGV2ZW50UGF0aCA9IGV2ZW50Lmh0dHAucGF0aCB8fCAnLyc7XG4gICAgICAgICAgICAgICAgY29uc3QgZXZlbnRNZXRob2QgPSBldmVudC5odHRwLm1ldGhvZCB8fCAnR0VUJztcblxuICAgICAgICAgICAgICAgIC8vIFNpbXBsZSBwYXRoIG1hdGNoaW5nIC0gYXZvaWQgY29tcGxleCByZWdleFxuICAgICAgICAgICAgICAgIGlmKGV2ZW50UGF0aCAmJiBldmVudFBhdGggPT09IHVybCAmJiBldmVudE1ldGhvZCA9PT0gbWV0aG9kKSB7XG4gICAgICAgICAgICAgICAgICBtYXRjaGVkRnVuY3Rpb24gPSBmdW5jdGlvbk5hbWU7XG4gICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgaWYobWF0Y2hlZEZ1bmN0aW9uKSB7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYobWF0Y2hlZEZ1bmN0aW9uICYmIGNvbmZpZy5mdW5jdGlvbnNbbWF0Y2hlZEZ1bmN0aW9uXSkge1xuICAgICAgICAvLyBSZXNvbHZlIGhhbmRsZXIgcGF0aCByZWxhdGl2ZSB0byBvdXRwdXQgZGlyZWN0b3J5XG4gICAgICAgIGNvbnN0IGhhbmRsZXJQYXRoID0gY29uZmlnLmZ1bmN0aW9uc1ttYXRjaGVkRnVuY3Rpb25dLmhhbmRsZXI7XG4gICAgICAgIGNvbnN0IGhhbmRsZXIgPSBhd2FpdCBsb2FkSGFuZGxlcihoYW5kbGVyUGF0aCwgb3V0cHV0RGlyKTtcblxuICAgICAgICBpZihoYW5kbGVyKSB7XG4gICAgICAgICAgY29uc3Qgd3JhcHBlZEhhbmRsZXIgPSBjYXB0dXJlQ29uc29sZUxvZ3MoaGFuZGxlciwgcXVpZXQpO1xuXG4gICAgICAgICAgY29uc3QgZXZlbnQgPSB7XG4gICAgICAgICAgICBib2R5OiByZXEuYm9keSxcbiAgICAgICAgICAgIGhlYWRlcnM6IHJlcS5oZWFkZXJzLFxuICAgICAgICAgICAgaHR0cE1ldGhvZDogbWV0aG9kLFxuICAgICAgICAgICAgcGF0aDogdXJsLFxuICAgICAgICAgICAgcXVlcnlTdHJpbmdQYXJhbWV0ZXJzOiByZXEucXVlcnlcbiAgICAgICAgICB9O1xuXG4gICAgICAgICAgY29uc3QgY29udGV4dCA9IHtcbiAgICAgICAgICAgIGZ1bmN0aW9uTmFtZTogbWF0Y2hlZEZ1bmN0aW9uLFxuICAgICAgICAgICAgZnVuY3Rpb25WZXJzaW9uOiAnJExBVEVTVCcsXG4gICAgICAgICAgICBpbnZva2VkRnVuY3Rpb25Bcm46IGBhcm46YXdzOmxhbWJkYTp1cy1lYXN0LTE6MTIzNDU2Nzg5MDEyOmZ1bmN0aW9uOiR7bWF0Y2hlZEZ1bmN0aW9ufWAsXG4gICAgICAgICAgICBtZW1vcnlMaW1pdEluTUI6ICcxMjgnLFxuICAgICAgICAgICAgYXdzUmVxdWVzdElkOiAndGVzdC1yZXF1ZXN0LWlkJyxcbiAgICAgICAgICAgIGxvZ0dyb3VwTmFtZTogYC9hd3MvbGFtYmRhLyR7bWF0Y2hlZEZ1bmN0aW9ufWAsXG4gICAgICAgICAgICBsb2dTdHJlYW1OYW1lOiAndGVzdC1sb2ctc3RyZWFtJyxcbiAgICAgICAgICAgIGdldFJlbWFpbmluZ1RpbWVJbk1pbGxpczogKCkgPT4gMzAwMDBcbiAgICAgICAgICB9O1xuXG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHdyYXBwZWRIYW5kbGVyKGV2ZW50LCBjb250ZXh0KTtcblxuICAgICAgICAgICAgaWYocmVzdWx0ICYmIHR5cGVvZiByZXN1bHQgPT09ICdvYmplY3QnICYmIHJlc3VsdC5zdGF0dXNDb2RlKSB7XG4gICAgICAgICAgICAgIHJlcy5zdGF0dXMocmVzdWx0LnN0YXR1c0NvZGUpO1xuICAgICAgICAgICAgICBpZihyZXN1bHQuaGVhZGVycykge1xuICAgICAgICAgICAgICAgIE9iamVjdC5lbnRyaWVzKHJlc3VsdC5oZWFkZXJzKS5mb3JFYWNoKChba2V5LCB2YWx1ZV0pID0+IHtcbiAgICAgICAgICAgICAgICAgIHJlcy5zZXRIZWFkZXIoa2V5LCBTdHJpbmcodmFsdWUpKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICByZXMuc2VuZChyZXN1bHQuYm9keSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICByZXMuanNvbihyZXN1bHQpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgICBsb2coYEhhbmRsZXIgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gLCAnZXJyb3InLCBmYWxzZSk7XG4gICAgICAgICAgICByZXMuc3RhdHVzKDUwMCkuanNvbih7ZXJyb3I6IGVycm9yLm1lc3NhZ2V9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcmVzLnN0YXR1cyg0MDQpLmpzb24oe2Vycm9yOiAnSGFuZGxlciBub3QgZm91bmQnfSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJlcy5zdGF0dXMoNDA0KS5qc29uKHtlcnJvcjogJ0Z1bmN0aW9uIG5vdCBmb3VuZCd9KTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nKGBSb3V0ZSBoYW5kbGluZyBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWAsICdlcnJvcicsIGZhbHNlKTtcbiAgICAgIHJlcy5zdGF0dXMoNTAwKS5qc29uKHtlcnJvcjogZXJyb3IubWVzc2FnZX0pO1xuICAgIH1cbiAgfSk7XG5cbiAgcmV0dXJuIGFwcDtcbn07XG5cbmNvbnN0IGNyZWF0ZVdlYlNvY2tldFNlcnZlciA9IChjb25maWc6IFNlcnZlcmxlc3NDb25maWcsIG91dHB1dERpcjogc3RyaW5nLCB3c1BvcnQ6IG51bWJlciwgcXVpZXQ6IGJvb2xlYW4sIGRlYnVnOiBib29sZWFuLCBwcmludE91dHB1dDogYm9vbGVhbikgPT4ge1xuICBjb25zdCB3c3MgPSBuZXcgV2ViU29ja2V0U2VydmVyKHtwb3J0OiB3c1BvcnR9KTtcblxuICB3c3Mub24oJ2Nvbm5lY3Rpb24nLCBhc3luYyAod3MsIHJlcSkgPT4ge1xuICAgIGxvZyhgV2ViU29ja2V0IGNvbm5lY3Rpb24gZXN0YWJsaXNoZWQ6ICR7cmVxLnVybH1gLCAnaW5mbycsIGZhbHNlKTtcblxuICAgIHdzLm9uKCdtZXNzYWdlJywgYXN5bmMgKG1lc3NhZ2UpID0+IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IGRhdGEgPSBKU09OLnBhcnNlKG1lc3NhZ2UudG9TdHJpbmcoKSk7XG5cbiAgICAgICAgLy8gRmluZCBtYXRjaGluZyBXZWJTb2NrZXQgZnVuY3Rpb25cbiAgICAgICAgbGV0IG1hdGNoZWRGdW5jdGlvbiA9IG51bGw7XG5cbiAgICAgICAgaWYoY29uZmlnLmZ1bmN0aW9ucykge1xuICAgICAgICAgIGZvcihjb25zdCBbZnVuY3Rpb25OYW1lLCBmdW5jdGlvbkNvbmZpZ10gb2YgT2JqZWN0LmVudHJpZXMoY29uZmlnLmZ1bmN0aW9ucykpIHtcbiAgICAgICAgICAgIGlmKGZ1bmN0aW9uQ29uZmlnLmV2ZW50cykge1xuICAgICAgICAgICAgICBmb3IoY29uc3QgZXZlbnQgb2YgZnVuY3Rpb25Db25maWcuZXZlbnRzKSB7XG4gICAgICAgICAgICAgICAgaWYoZXZlbnQud2Vic29ja2V0KSB7XG4gICAgICAgICAgICAgICAgICBjb25zdCByb3V0ZSA9IGV2ZW50LndlYnNvY2tldC5yb3V0ZSB8fCAnJGNvbm5lY3QnO1xuICAgICAgICAgICAgICAgICAgaWYocm91dGUgPT09ICckZGVmYXVsdCcgfHwgcm91dGUgPT09IGRhdGEuYWN0aW9uKSB7XG4gICAgICAgICAgICAgICAgICAgIG1hdGNoZWRGdW5jdGlvbiA9IGZ1bmN0aW9uTmFtZTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZihtYXRjaGVkRnVuY3Rpb24pIHtcbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYobWF0Y2hlZEZ1bmN0aW9uICYmIGNvbmZpZy5mdW5jdGlvbnNbbWF0Y2hlZEZ1bmN0aW9uXSkge1xuICAgICAgICAgIGNvbnN0IGhhbmRsZXIgPSBhd2FpdCBsb2FkSGFuZGxlcihjb25maWcuZnVuY3Rpb25zW21hdGNoZWRGdW5jdGlvbl0uaGFuZGxlciwgb3V0cHV0RGlyKTtcblxuICAgICAgICAgIGlmKGhhbmRsZXIpIHtcbiAgICAgICAgICAgIC8vIFdyYXAgaGFuZGxlciB3aXRoIGNvbnNvbGUgbG9nIGNhcHR1cmVcbiAgICAgICAgICAgIGNvbnN0IHdyYXBwZWRIYW5kbGVyID0gY2FwdHVyZUNvbnNvbGVMb2dzKGhhbmRsZXIsIHF1aWV0KTtcbiAgICAgICAgICAgIGNvbnN0IGV2ZW50ID0ge1xuICAgICAgICAgICAgICByZXF1ZXN0Q29udGV4dDoge1xuICAgICAgICAgICAgICAgIHJvdXRlS2V5OiBkYXRhLmFjdGlvbiB8fCAnJGRlZmF1bHQnLFxuICAgICAgICAgICAgICAgIGNvbm5lY3Rpb25JZDogJ3Rlc3QtY29ubmVjdGlvbi1pZCcsXG4gICAgICAgICAgICAgICAgYXBpR2F0ZXdheToge1xuICAgICAgICAgICAgICAgICAgZW5kcG9pbnQ6IGB3czovL2xvY2FsaG9zdDoke3dzUG9ydH1gXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICBib2R5OiBkYXRhLmJvZHkgfHwgbnVsbFxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgY29uc3QgY29udGV4dCA9IHtcbiAgICAgICAgICAgICAgZnVuY3Rpb25OYW1lOiBtYXRjaGVkRnVuY3Rpb24sXG4gICAgICAgICAgICAgIGZ1bmN0aW9uVmVyc2lvbjogJyRMQVRFU1QnLFxuICAgICAgICAgICAgICBpbnZva2VkRnVuY3Rpb25Bcm46IGBhcm46YXdzOmxhbWJkYTp1cy1lYXN0LTE6MTIzNDU2Nzg5MDEyOmZ1bmN0aW9uOiR7bWF0Y2hlZEZ1bmN0aW9ufWAsXG4gICAgICAgICAgICAgIG1lbW9yeUxpbWl0SW5NQjogJzEyOCcsXG4gICAgICAgICAgICAgIGF3c1JlcXVlc3RJZDogJ3Rlc3QtcmVxdWVzdC1pZCcsXG4gICAgICAgICAgICAgIGxvZ0dyb3VwTmFtZTogYC9hd3MvbGFtYmRhLyR7bWF0Y2hlZEZ1bmN0aW9ufWAsXG4gICAgICAgICAgICAgIGxvZ1N0cmVhbU5hbWU6ICd0ZXN0LWxvZy1zdHJlYW0nLFxuICAgICAgICAgICAgICBnZXRSZW1haW5pbmdUaW1lSW5NaWxsaXM6ICgpID0+IDMwMDAwXG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB3cmFwcGVkSGFuZGxlcihldmVudCwgY29udGV4dCk7XG5cbiAgICAgICAgICAgIC8vIEhhbmRsZSBMYW1iZGEgcmVzcG9uc2UgZm9ybWF0IGZvciBXZWJTb2NrZXRcbiAgICAgICAgICAgIGlmKHJlc3VsdCAmJiB0eXBlb2YgcmVzdWx0ID09PSAnb2JqZWN0JyAmJiByZXN1bHQuc3RhdHVzQ29kZSkge1xuICAgICAgICAgICAgICAvLyBUaGlzIGlzIGEgTGFtYmRhIHJlc3BvbnNlIG9iamVjdCwgZXh0cmFjdCB0aGUgYm9keVxuICAgICAgICAgICAgICBjb25zdCBib2R5ID0gcmVzdWx0LmJvZHkgfHwgJyc7XG4gICAgICAgICAgICAgIHdzLnNlbmQoYm9keSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAvLyBUaGlzIGlzIGEgZGlyZWN0IHJlc3BvbnNlLCBzdHJpbmdpZnkgaXRcbiAgICAgICAgICAgICAgd3Muc2VuZChKU09OLnN0cmluZ2lmeShyZXN1bHQpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgd3Muc2VuZChKU09OLnN0cmluZ2lmeSh7ZXJyb3I6ICdIYW5kbGVyIG5vdCBmb3VuZCd9KSk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHdzLnNlbmQoSlNPTi5zdHJpbmdpZnkoe2Vycm9yOiAnV2ViU29ja2V0IGZ1bmN0aW9uIG5vdCBmb3VuZCd9KSk7XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGxvZyhgV2ViU29ja2V0IGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCwgJ2Vycm9yJywgZmFsc2UpO1xuICAgICAgICB3cy5zZW5kKEpTT04uc3RyaW5naWZ5KHtlcnJvcjogZXJyb3IubWVzc2FnZX0pKTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHdzLm9uKCdjbG9zZScsICgpID0+IHtcbiAgICAgIGxvZygnV2ViU29ja2V0IGNvbm5lY3Rpb24gY2xvc2VkJywgJ2luZm8nLCBmYWxzZSk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIHJldHVybiB3c3M7XG59O1xuXG5jb25zdCBsb2FkRW52RmlsZSA9IChlbnZQYXRoOiBzdHJpbmcpOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0+IHtcbiAgY29uc3QgZW52VmFyczogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHt9O1xuXG4gIGlmKCFleGlzdHNTeW5jKGVudlBhdGgpKSB7XG4gICAgcmV0dXJuIGVudlZhcnM7XG4gIH1cblxuICB0cnkge1xuICAgIGNvbnN0IGVudkNvbnRlbnQgPSByZWFkRmlsZVN5bmMoZW52UGF0aCwgJ3V0ZjgnKTtcbiAgICBjb25zdCBsaW5lcyA9IGVudkNvbnRlbnQuc3BsaXQoJ1xcbicpO1xuXG4gICAgZm9yKGNvbnN0IGxpbmUgb2YgbGluZXMpIHtcbiAgICAgIGNvbnN0IHRyaW1tZWRMaW5lID0gbGluZS50cmltKCk7XG5cbiAgICAgIC8vIFNraXAgZW1wdHkgbGluZXMgYW5kIGNvbW1lbnRzXG4gICAgICBpZighdHJpbW1lZExpbmUgfHwgdHJpbW1lZExpbmUuc3RhcnRzV2l0aCgnIycpKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICAvLyBQYXJzZSBLRVk9dmFsdWUgZm9ybWF0XG4gICAgICBjb25zdCBlcXVhbEluZGV4ID0gdHJpbW1lZExpbmUuaW5kZXhPZignPScpO1xuICAgICAgaWYoZXF1YWxJbmRleCA+IDApIHtcbiAgICAgICAgY29uc3Qga2V5ID0gdHJpbW1lZExpbmUuc3Vic3RyaW5nKDAsIGVxdWFsSW5kZXgpLnRyaW0oKTtcbiAgICAgICAgY29uc3QgdmFsdWUgPSB0cmltbWVkTGluZS5zdWJzdHJpbmcoZXF1YWxJbmRleCArIDEpLnRyaW0oKTtcblxuICAgICAgICAvLyBSZW1vdmUgcXVvdGVzIGlmIHByZXNlbnRcbiAgICAgICAgY29uc3QgY2xlYW5WYWx1ZSA9IHZhbHVlLnJlcGxhY2UoL15bXCInXXxbXCInXSQvZywgJycpO1xuXG4gICAgICAgIGlmKGtleSkge1xuICAgICAgICAgIGVudlZhcnNba2V5XSA9IGNsZWFuVmFsdWU7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgbG9nKGBXYXJuaW5nOiBDb3VsZCBub3QgbG9hZCAuZW52IGZpbGUgYXQgJHtlbnZQYXRofTogJHtlcnJvci5tZXNzYWdlfWAsICd3YXJuJywgZmFsc2UpO1xuICB9XG5cbiAgcmV0dXJuIGVudlZhcnM7XG59O1xuXG5leHBvcnQgY29uc3Qgc2VydmVybGVzcyA9IGFzeW5jIChjbWQ6IFNlcnZlcmxlc3NPcHRpb25zLCBjYWxsYmFjazogU2VydmVybGVzc0NhbGxiYWNrID0gKCkgPT4gKHt9KSk6IFByb21pc2U8bnVtYmVyPiA9PiB7XG4gIGNvbnN0IHtcbiAgICBjbGlOYW1lID0gJ0xleCcsXG4gICAgY29uZmlnLFxuICAgIGhvc3QgPSAnbG9jYWxob3N0JyxcbiAgICBodHRwUG9ydCA9IDMwMDAsXG4gICAgaHR0cHNQb3J0ID0gMzAwMSxcbiAgICB3c1BvcnQgPSAzMDAyLFxuICAgIHF1aWV0ID0gZmFsc2UsXG4gICAgcmVtb3ZlID0gZmFsc2UsXG4gICAgdXNlUHVibGljSXAsXG4gICAgdmFyaWFibGVzLFxuICAgIGRlYnVnID0gZmFsc2UsXG4gICAgcHJpbnRPdXRwdXQgPSBmYWxzZSxcbiAgICB0ZXN0ID0gZmFsc2VcbiAgfSA9IGNtZDtcblxuICBjb25zdCBzcGlubmVyID0gY3JlYXRlU3Bpbm5lcihxdWlldCk7XG5cbiAgbG9nKGAke2NsaU5hbWV9IHN0YXJ0aW5nIHNlcnZlcmxlc3MgZGV2ZWxvcG1lbnQgc2VydmVyLi4uYCwgJ2luZm8nLCBxdWlldCk7XG5cbiAgYXdhaXQgTGV4Q29uZmlnLnBhcnNlQ29uZmlnKGNtZCk7XG5cbiAgY29uc3Qge291dHB1dEZ1bGxQYXRofSA9IExleENvbmZpZy5jb25maWc7XG5cbiAgLy8gTG9hZCBlbnZpcm9ubWVudCB2YXJpYWJsZXMgZnJvbSAuZW52IGZpbGVzXG4gIGNvbnN0IGVudlBhdGhzID0gW1xuICAgIHBhdGhSZXNvbHZlKHByb2Nlc3MuY3dkKCksICcuZW52JyksXG4gICAgcGF0aFJlc29sdmUocHJvY2Vzcy5jd2QoKSwgJy5lbnYubG9jYWwnKSxcbiAgICBwYXRoUmVzb2x2ZShwcm9jZXNzLmN3ZCgpLCAnLmVudi5kZXZlbG9wbWVudCcpXG4gIF07XG5cbiAgbGV0IGVudlZhcnM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7fTtcblxuICAvLyBMb2FkIGZyb20gLmVudiBmaWxlcyBpbiBvcmRlciAobGF0ZXIgZmlsZXMgb3ZlcnJpZGUgZWFybGllciBvbmVzKVxuICBmb3IoY29uc3QgZW52UGF0aCBvZiBlbnZQYXRocykge1xuICAgIGNvbnN0IGZpbGVFbnZWYXJzID0gbG9hZEVudkZpbGUoZW52UGF0aCk7XG4gICAgaWYoT2JqZWN0LmtleXMoZmlsZUVudlZhcnMpLmxlbmd0aCA+IDApIHtcbiAgICAgIGxvZyhgTG9hZGVkIGVudmlyb25tZW50IHZhcmlhYmxlcyBmcm9tOiAke2VudlBhdGh9YCwgJ2luZm8nLCBxdWlldCk7XG4gICAgfVxuICAgIGVudlZhcnMgPSB7Li4uZW52VmFycywgLi4uZmlsZUVudlZhcnN9O1xuICB9XG5cbiAgLy8gU3RhcnQgd2l0aCBkZWZhdWx0IE5PREVfRU5WIGFuZCBsb2FkZWQgLmVudiB2YXJpYWJsZXNcbiAgbGV0IHZhcmlhYmxlc09iajogb2JqZWN0ID0ge05PREVfRU5WOiAnZGV2ZWxvcG1lbnQnLCAuLi5lbnZWYXJzfTtcblxuICAvLyBPdmVycmlkZSB3aXRoIGNvbW1hbmQgbGluZSB2YXJpYWJsZXMgaWYgcHJvdmlkZWRcbiAgaWYodmFyaWFibGVzKSB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGNsaVZhcnMgPSBKU09OLnBhcnNlKHZhcmlhYmxlcyk7XG4gICAgICB2YXJpYWJsZXNPYmogPSB7Li4udmFyaWFibGVzT2JqLCAuLi5jbGlWYXJzfTtcbiAgICB9IGNhdGNoIChfZXJyb3IpIHtcbiAgICAgIGxvZyhgXFxuJHtjbGlOYW1lfSBFcnJvcjogRW52aXJvbm1lbnQgdmFyaWFibGVzIG9wdGlvbiBpcyBub3QgYSB2YWxpZCBKU09OIG9iamVjdC5gLCAnZXJyb3InLCBxdWlldCk7XG4gICAgICBjYWxsYmFjaygxKTtcbiAgICAgIHJldHVybiAxO1xuICAgIH1cbiAgfVxuXG4gIHByb2Nlc3MuZW52ID0gey4uLnByb2Nlc3MuZW52LCAuLi52YXJpYWJsZXNPYmp9O1xuXG4gIC8vIElmIGluIHRlc3QgbW9kZSwgZXhpdCBlYXJseSBhZnRlciBsb2FkaW5nIGVudmlyb25tZW50IHZhcmlhYmxlc1xuICBpZih0ZXN0KSB7XG4gICAgbG9nKCdUZXN0IG1vZGU6IEVudmlyb25tZW50IHZhcmlhYmxlcyBsb2FkZWQsIGV4aXRpbmcnLCAnaW5mbycsIHF1aWV0KTtcbiAgICBjYWxsYmFjaygwKTtcbiAgICByZXR1cm4gMDtcbiAgfVxuXG4gIGlmKHJlbW92ZSkge1xuICAgIHNwaW5uZXIuc3RhcnQoJ0NsZWFuaW5nIG91dHB1dCBkaXJlY3RvcnkuLi4nKTtcbiAgICBhd2FpdCByZW1vdmVGaWxlcyhvdXRwdXRGdWxsUGF0aCB8fCAnJyk7XG4gICAgc3Bpbm5lci5zdWNjZWVkKCdTdWNjZXNzZnVsbHkgY2xlYW5lZCBvdXRwdXQgZGlyZWN0b3J5IScpO1xuICB9XG5cbiAgLy8gTG9hZCBzZXJ2ZXJsZXNzIGNvbmZpZ3VyYXRpb25cbiAgbGV0IHNlcnZlcmxlc3NDb25maWc6IFNlcnZlcmxlc3NDb25maWcgPSB7fTtcblxuICB0cnkge1xuICAgIGNvbnN0IGNvbmZpZ1BhdGggPSBjb25maWcgfHwgcGF0aFJlc29sdmUocHJvY2Vzcy5jd2QoKSwgJ2xleC5jb25maWcubWpzJyk7XG4gICAgbG9nKGBMb2FkaW5nIHNlcnZlcmxlc3MgY29uZmlnIGZyb206ICR7Y29uZmlnUGF0aH1gLCAnaW5mbycsIHF1aWV0KTtcblxuICAgIGlmKGV4aXN0c1N5bmMoY29uZmlnUGF0aCkpIHtcbiAgICAgIGNvbnN0IGNvbmZpZ01vZHVsZSA9IGF3YWl0IGltcG9ydChjb25maWdQYXRoKTtcbiAgICAgIHNlcnZlcmxlc3NDb25maWcgPSBjb25maWdNb2R1bGUuZGVmYXVsdD8uc2VydmVybGVzcyB8fCBjb25maWdNb2R1bGUuc2VydmVybGVzcyB8fCB7fTtcbiAgICAgIGxvZygnU2VydmVybGVzcyBjb25maWcgbG9hZGVkIHN1Y2Nlc3NmdWxseScsICdpbmZvJywgcXVpZXQpO1xuICAgICAgbG9nKGBMb2FkZWQgZnVuY3Rpb25zOiAke09iamVjdC5rZXlzKHNlcnZlcmxlc3NDb25maWcuZnVuY3Rpb25zIHx8IHt9KS5qb2luKCcsICcpfWAsICdpbmZvJywgcXVpZXQpO1xuICAgIH0gZWxzZSB7XG4gICAgICBsb2coYE5vIHNlcnZlcmxlc3MgY29uZmlnIGZvdW5kIGF0ICR7Y29uZmlnUGF0aH0sIHVzaW5nIGRlZmF1bHRzYCwgJ3dhcm4nLCBxdWlldCk7XG4gICAgfVxuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGxvZyhgRXJyb3IgbG9hZGluZyBzZXJ2ZXJsZXNzIGNvbmZpZzogJHtlcnJvci5tZXNzYWdlfWAsICdlcnJvcicsIHF1aWV0KTtcbiAgICAvLyBEb24ndCBleGl0LCBjb250aW51ZSB3aXRoIGVtcHR5IGNvbmZpZ1xuICB9XG5cbiAgLy8gTWVyZ2UgY29uZmlnIHdpdGggY29tbWFuZCBsaW5lIG9wdGlvbnNcbiAgY29uc3QgZmluYWxDb25maWc6IFNlcnZlcmxlc3NDb25maWcgPSB7XG4gICAgLi4uc2VydmVybGVzc0NvbmZpZyxcbiAgICBjdXN0b206IHtcbiAgICAgICdzZXJ2ZXJsZXNzLW9mZmxpbmUnOiB7XG4gICAgICAgIGh0dHBQb3J0OiBzZXJ2ZXJsZXNzQ29uZmlnLmN1c3RvbT8uWydzZXJ2ZXJsZXNzLW9mZmxpbmUnXT8uaHR0cFBvcnQgfHwgaHR0cFBvcnQsXG4gICAgICAgIGh0dHBzUG9ydDogc2VydmVybGVzc0NvbmZpZy5jdXN0b20/Llsnc2VydmVybGVzcy1vZmZsaW5lJ10/Lmh0dHBzUG9ydCB8fCBodHRwc1BvcnQsXG4gICAgICAgIHdzUG9ydDogc2VydmVybGVzc0NvbmZpZy5jdXN0b20/Llsnc2VydmVybGVzcy1vZmZsaW5lJ10/LndzUG9ydCB8fCB3c1BvcnQsXG4gICAgICAgIGhvc3Q6IHNlcnZlcmxlc3NDb25maWcuY3VzdG9tPy5bJ3NlcnZlcmxlc3Mtb2ZmbGluZSddPy5ob3N0IHx8IGhvc3QsXG4gICAgICAgIGNvcnM6IHNlcnZlcmxlc3NDb25maWcuY3VzdG9tPy5bJ3NlcnZlcmxlc3Mtb2ZmbGluZSddPy5jb3JzICE9PSBmYWxzZVxuICAgICAgfVxuICAgIH1cbiAgfTtcblxuICBjb25zdCBvdXRwdXREaXIgPSBvdXRwdXRGdWxsUGF0aCB8fCAnZGlzdCc7XG4gIGxvZyhgVXNpbmcgb3V0cHV0IGRpcmVjdG9yeTogJHtvdXRwdXREaXJ9YCwgJ2luZm8nLCBxdWlldCk7XG5cbiAgdHJ5IHtcbiAgICBzcGlubmVyLnN0YXJ0KCdTdGFydGluZyBzZXJ2ZXJsZXNzIGRldmVsb3BtZW50IHNlcnZlci4uLicpO1xuXG4gICAgY29uc3QgaHR0cFBvcnQgPSBmaW5hbENvbmZpZy5jdXN0b20hWydzZXJ2ZXJsZXNzLW9mZmxpbmUnXSEuaHR0cFBvcnQhO1xuICAgIGNvbnN0IHdzUG9ydCA9IGZpbmFsQ29uZmlnLmN1c3RvbSFbJ3NlcnZlcmxlc3Mtb2ZmbGluZSddIS53c1BvcnQhO1xuICAgIGNvbnN0IGhvc3QgPSBmaW5hbENvbmZpZy5jdXN0b20hWydzZXJ2ZXJsZXNzLW9mZmxpbmUnXSEuaG9zdCE7XG5cbiAgICBsb2coYENyZWF0aW5nIEhUVFAgc2VydmVyIG9uICR7aG9zdH06JHtodHRwUG9ydH1gLCAnaW5mbycsIHF1aWV0KTtcbiAgICBsb2coYENyZWF0aW5nIFdlYlNvY2tldCBzZXJ2ZXIgb24gcG9ydCAke3dzUG9ydH1gLCAnaW5mbycsIHF1aWV0KTtcblxuICAgIC8vIENyZWF0ZSBFeHByZXNzIHNlcnZlclxuICAgIGNvbnN0IGV4cHJlc3NBcHAgPSBhd2FpdCBjcmVhdGVFeHByZXNzU2VydmVyKFxuICAgICAgZmluYWxDb25maWcsXG4gICAgICBvdXRwdXREaXIsXG4gICAgICBodHRwUG9ydCxcbiAgICAgIGhvc3QsXG4gICAgICBxdWlldCxcbiAgICAgIGRlYnVnLFxuICAgICAgcHJpbnRPdXRwdXRcbiAgICApO1xuXG4gICAgLy8gQ3JlYXRlIFdlYlNvY2tldCBzZXJ2ZXJcbiAgICBjb25zdCB3c1NlcnZlciA9IGNyZWF0ZVdlYlNvY2tldFNlcnZlcihcbiAgICAgIGZpbmFsQ29uZmlnLFxuICAgICAgb3V0cHV0RGlyLFxuICAgICAgd3NQb3J0LFxuICAgICAgcXVpZXQsXG4gICAgICBkZWJ1ZyxcbiAgICAgIHByaW50T3V0cHV0XG4gICAgKTtcblxuICAgIC8vIEhhbmRsZSBzZXJ2ZXIgZXJyb3JzXG4gICAgd3NTZXJ2ZXIub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XG4gICAgICBsb2coYFdlYlNvY2tldCBzZXJ2ZXIgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gLCAnZXJyb3InLCBxdWlldCk7XG4gICAgICBzcGlubmVyLmZhaWwoJ0ZhaWxlZCB0byBzdGFydCBXZWJTb2NrZXQgc2VydmVyLicpO1xuICAgICAgY2FsbGJhY2soMSk7XG4gICAgICByZXR1cm47XG4gICAgfSk7XG5cbiAgICAvLyBTdGFydCBFeHByZXNzIHNlcnZlclxuICAgIGNvbnN0IHNlcnZlciA9IGV4cHJlc3NBcHAubGlzdGVuKGh0dHBQb3J0LCBob3N0LCAoKSA9PiB7XG4gICAgICBzcGlubmVyLnN1Y2NlZWQoJ1NlcnZlcmxlc3MgZGV2ZWxvcG1lbnQgc2VydmVyIHN0YXJ0ZWQuJyk7XG5cbiAgICAgIGRpc3BsYXlTZXJ2ZXJTdGF0dXMoXG4gICAgICAgIGh0dHBQb3J0LFxuICAgICAgICBmaW5hbENvbmZpZy5jdXN0b20hWydzZXJ2ZXJsZXNzLW9mZmxpbmUnXSEuaHR0cHNQb3J0ISxcbiAgICAgICAgd3NQb3J0LFxuICAgICAgICBob3N0LFxuICAgICAgICBxdWlldFxuICAgICAgKTtcblxuICAgICAgZmV0Y2hQdWJsaWNJcCh1c2VQdWJsaWNJcCkudGhlbigocHVibGljSXApID0+IHtcbiAgICAgICAgaWYocHVibGljSXApIHtcbiAgICAgICAgICBkaXNwbGF5U2VydmVyU3RhdHVzKFxuICAgICAgICAgICAgaHR0cFBvcnQsXG4gICAgICAgICAgICBmaW5hbENvbmZpZy5jdXN0b20hWydzZXJ2ZXJsZXNzLW9mZmxpbmUnXSEuaHR0cHNQb3J0ISxcbiAgICAgICAgICAgIHdzUG9ydCxcbiAgICAgICAgICAgIGhvc3QsXG4gICAgICAgICAgICBxdWlldCxcbiAgICAgICAgICAgIHB1YmxpY0lwXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICAvLyBIYW5kbGUgRXhwcmVzcyBzZXJ2ZXIgZXJyb3JzXG4gICAgc2VydmVyLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xuICAgICAgbG9nKGBFeHByZXNzIHNlcnZlciBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWAsICdlcnJvcicsIHF1aWV0KTtcbiAgICAgIHNwaW5uZXIuZmFpbCgnRmFpbGVkIHRvIHN0YXJ0IEV4cHJlc3Mgc2VydmVyLicpO1xuICAgICAgY2FsbGJhY2soMSk7XG4gICAgICByZXR1cm47XG4gICAgfSk7XG5cbiAgICAvLyBIYW5kbGUgZ3JhY2VmdWwgc2h1dGRvd25cbiAgICBjb25zdCBzaHV0ZG93biA9ICgpID0+IHtcbiAgICAgIGxvZygnXFxuU2h1dHRpbmcgZG93biBzZXJ2ZXJsZXNzIGRldmVsb3BtZW50IHNlcnZlci4uLicsICdpbmZvJywgcXVpZXQpO1xuICAgICAgc2VydmVyLmNsb3NlKCk7XG4gICAgICB3c1NlcnZlci5jbG9zZSgpO1xuICAgICAgY2FsbGJhY2soMCk7XG4gICAgfTtcblxuICAgIHByb2Nlc3Mub24oJ1NJR0lOVCcsIHNodXRkb3duKTtcbiAgICBwcm9jZXNzLm9uKCdTSUdURVJNJywgc2h1dGRvd24pO1xuXG4gICAgLy8gS2VlcCB0aGUgcHJvY2VzcyBhbGl2ZVxuICAgIHByb2Nlc3Muc3RkaW4ucmVzdW1lKCk7XG5cbiAgICBsb2coJ1NlcnZlcmxlc3MgZGV2ZWxvcG1lbnQgc2VydmVyIGlzIHJ1bm5pbmcuIFByZXNzIEN0cmwrQyB0byBzdG9wLicsICdpbmZvJywgcXVpZXQpO1xuXG4gICAgLy8gRG9uJ3QgY2FsbCBjYWxsYmFjayBoZXJlLCBsZXQgdGhlIHByb2Nlc3Mgc3RheSBhbGl2ZVxuICAgIHJldHVybiAwO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGxvZyhgXFxuJHtjbGlOYW1lfSBFcnJvcjogJHtlcnJvci5tZXNzYWdlfWAsICdlcnJvcicsIHF1aWV0KTtcbiAgICBzcGlubmVyLmZhaWwoJ0ZhaWxlZCB0byBzdGFydCBzZXJ2ZXJsZXNzIGRldmVsb3BtZW50IHNlcnZlci4nKTtcbiAgICBjYWxsYmFjaygxKTtcbiAgICByZXR1cm4gMTtcbiAgfVxufTsiXSwKICAibWFwcGluZ3MiOiAiQUFJQSxPQUFPLFdBQVc7QUFDbEIsT0FBTyxXQUFXO0FBQ2xCLE9BQU8sYUFBYTtBQUNwQixTQUFRLGNBQWMsWUFBWSxXQUFXLHFCQUFvQjtBQUNqRSxTQUFRLG1CQUFtQixlQUFjO0FBQ3pDLFNBQVEsV0FBVyxhQUFhLFlBQVc7QUFDM0MsU0FBUSx1QkFBc0I7QUFFOUIsU0FBUSxpQkFBZ0I7QUFDeEIsU0FBUSxlQUFlLG1CQUFrQjtBQUN6QyxTQUFRLFdB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