@local-labs-jpollock/local-cli 0.0.1
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/addon-dist/bin/mcp-stdio.js +2808 -0
- package/addon-dist/lib/common/constants.d.ts +22 -0
- package/addon-dist/lib/common/constants.js +26 -0
- package/addon-dist/lib/common/theme.d.ts +68 -0
- package/addon-dist/lib/common/theme.js +126 -0
- package/addon-dist/lib/common/types.d.ts +298 -0
- package/addon-dist/lib/common/types.js +6 -0
- package/addon-dist/lib/main/config/ConnectionInfo.d.ts +25 -0
- package/addon-dist/lib/main/config/ConnectionInfo.js +82 -0
- package/addon-dist/lib/main/index.d.ts +12 -0
- package/addon-dist/lib/main/index.js +3322 -0
- package/addon-dist/lib/main/mcp/McpAuth.d.ts +37 -0
- package/addon-dist/lib/main/mcp/McpAuth.js +87 -0
- package/addon-dist/lib/main/mcp/McpServer.d.ts +67 -0
- package/addon-dist/lib/main/mcp/McpServer.js +343 -0
- package/addon-dist/lib/main/mcp/tools/changePhpVersion.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/changePhpVersion.js +81 -0
- package/addon-dist/lib/main/mcp/tools/cloneSite.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/cloneSite.js +66 -0
- package/addon-dist/lib/main/mcp/tools/createSite.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/createSite.js +137 -0
- package/addon-dist/lib/main/mcp/tools/deleteSite.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/deleteSite.js +72 -0
- package/addon-dist/lib/main/mcp/tools/exportDatabase.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/exportDatabase.js +72 -0
- package/addon-dist/lib/main/mcp/tools/exportSite.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/exportSite.js +103 -0
- package/addon-dist/lib/main/mcp/tools/getLocalInfo.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/getLocalInfo.js +72 -0
- package/addon-dist/lib/main/mcp/tools/getSite.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/getSite.js +68 -0
- package/addon-dist/lib/main/mcp/tools/getSiteLogs.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/getSiteLogs.js +149 -0
- package/addon-dist/lib/main/mcp/tools/helpers.d.ts +59 -0
- package/addon-dist/lib/main/mcp/tools/helpers.js +179 -0
- package/addon-dist/lib/main/mcp/tools/importDatabase.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/importDatabase.js +109 -0
- package/addon-dist/lib/main/mcp/tools/importSite.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/importSite.js +149 -0
- package/addon-dist/lib/main/mcp/tools/index.d.ts +26 -0
- package/addon-dist/lib/main/mcp/tools/index.js +117 -0
- package/addon-dist/lib/main/mcp/tools/listBlueprints.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/listBlueprints.js +54 -0
- package/addon-dist/lib/main/mcp/tools/listServices.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/listServices.js +112 -0
- package/addon-dist/lib/main/mcp/tools/listSites.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/listSites.js +62 -0
- package/addon-dist/lib/main/mcp/tools/openAdminer.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/openAdminer.js +59 -0
- package/addon-dist/lib/main/mcp/tools/openSite.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/openSite.js +62 -0
- package/addon-dist/lib/main/mcp/tools/renameSite.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/renameSite.js +70 -0
- package/addon-dist/lib/main/mcp/tools/restartSite.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/restartSite.js +56 -0
- package/addon-dist/lib/main/mcp/tools/saveBlueprint.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/saveBlueprint.js +89 -0
- package/addon-dist/lib/main/mcp/tools/startSite.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/startSite.js +54 -0
- package/addon-dist/lib/main/mcp/tools/stopSite.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/stopSite.js +54 -0
- package/addon-dist/lib/main/mcp/tools/toggleXdebug.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/toggleXdebug.js +69 -0
- package/addon-dist/lib/main/mcp/tools/trustSsl.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/trustSsl.js +59 -0
- package/addon-dist/lib/main/mcp/tools/wpCli.d.ts +7 -0
- package/addon-dist/lib/main/mcp/tools/wpCli.js +110 -0
- package/addon-dist/lib/main.d.ts +1 -0
- package/addon-dist/lib/main.js +10 -0
- package/addon-dist/lib/renderer/index.d.ts +7 -0
- package/addon-dist/lib/renderer/index.js +479 -0
- package/addon-dist/package.json +73 -0
- package/bin/lwp.js +10 -0
- package/lib/bootstrap/index.d.ts +98 -0
- package/lib/bootstrap/index.js +493 -0
- package/lib/bootstrap/paths.d.ts +28 -0
- package/lib/bootstrap/paths.js +96 -0
- package/lib/client/GraphQLClient.d.ts +38 -0
- package/lib/client/GraphQLClient.js +71 -0
- package/lib/client/index.d.ts +4 -0
- package/lib/client/index.js +10 -0
- package/lib/formatters/index.d.ts +75 -0
- package/lib/formatters/index.js +139 -0
- package/lib/index.d.ts +8 -0
- package/lib/index.js +1173 -0
- package/package.json +72 -0
package/lib/index.js
ADDED
|
@@ -0,0 +1,1173 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* Local CLI (lwp)
|
|
5
|
+
*
|
|
6
|
+
* Command-line interface for managing Local WordPress sites.
|
|
7
|
+
* Connects directly to Local's GraphQL server.
|
|
8
|
+
*/
|
|
9
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
10
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
const commander_1 = require("commander");
|
|
14
|
+
const ora_1 = __importDefault(require("ora"));
|
|
15
|
+
const bootstrap_1 = require("./bootstrap");
|
|
16
|
+
const client_1 = require("./client");
|
|
17
|
+
const formatters_1 = require("./formatters");
|
|
18
|
+
const program = new commander_1.Command();
|
|
19
|
+
// Store client globally after bootstrap
|
|
20
|
+
let client = null;
|
|
21
|
+
/**
|
|
22
|
+
* Ensure we're connected to Local's GraphQL server
|
|
23
|
+
*/
|
|
24
|
+
async function ensureConnected(options) {
|
|
25
|
+
if (client) {
|
|
26
|
+
return client;
|
|
27
|
+
}
|
|
28
|
+
const spinner = options.quiet ? null : (0, ora_1.default)('Connecting to Local...').start();
|
|
29
|
+
try {
|
|
30
|
+
const result = await (0, bootstrap_1.bootstrap)({
|
|
31
|
+
verbose: false,
|
|
32
|
+
onStatus: (status) => {
|
|
33
|
+
if (spinner)
|
|
34
|
+
spinner.text = status;
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
if (!result.success || !result.connectionInfo) {
|
|
38
|
+
spinner?.fail('Failed to connect');
|
|
39
|
+
console.error((0, formatters_1.formatError)(result.error || 'Unknown error'));
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
spinner?.succeed('Connected to Local');
|
|
43
|
+
client = new client_1.GraphQLClient(result.connectionInfo);
|
|
44
|
+
return client;
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
spinner?.fail('Failed to connect');
|
|
48
|
+
console.error((0, formatters_1.formatError)(error.message));
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Helper to run site-specific commands with common boilerplate
|
|
54
|
+
*
|
|
55
|
+
* Handles: connection, spinner, site lookup, error formatting
|
|
56
|
+
*/
|
|
57
|
+
async function runSiteCommand(siteName, config, execute) {
|
|
58
|
+
const globalOpts = program.opts();
|
|
59
|
+
const spinner = globalOpts.quiet ? null : (0, ora_1.default)(`${config.action} "${siteName}"...`).start();
|
|
60
|
+
try {
|
|
61
|
+
const gql = await ensureConnected(globalOpts);
|
|
62
|
+
const siteId = await findSiteId(gql, siteName);
|
|
63
|
+
const result = await execute(gql, siteId);
|
|
64
|
+
const message = config.successMessage
|
|
65
|
+
? config.successMessage(result)
|
|
66
|
+
: `${config.action} "${siteName}" completed`;
|
|
67
|
+
spinner?.succeed(message);
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
spinner?.fail(`Failed to ${config.action.toLowerCase()} "${siteName}"`);
|
|
71
|
+
console.error((0, formatters_1.formatError)(error.message));
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
program
|
|
76
|
+
.name('lwp')
|
|
77
|
+
.description('Command-line interface for Local WordPress development')
|
|
78
|
+
.version('0.1.0');
|
|
79
|
+
// Global options
|
|
80
|
+
program
|
|
81
|
+
.option('--json', 'Output results as JSON')
|
|
82
|
+
.option('--quiet', 'Minimal output (IDs/names only)')
|
|
83
|
+
.option('--no-color', 'Disable colored output');
|
|
84
|
+
// ===========================================
|
|
85
|
+
// Sites Commands
|
|
86
|
+
// ===========================================
|
|
87
|
+
const sites = program.command('sites').description('Manage WordPress sites');
|
|
88
|
+
sites
|
|
89
|
+
.command('list')
|
|
90
|
+
.description('List all WordPress sites')
|
|
91
|
+
.option('--status <status>', 'Filter by status (running|stopped|all)', 'all')
|
|
92
|
+
.action(async (cmdOptions) => {
|
|
93
|
+
const globalOpts = program.opts();
|
|
94
|
+
const format = (0, formatters_1.getOutputFormat)(globalOpts);
|
|
95
|
+
try {
|
|
96
|
+
const gql = await ensureConnected(globalOpts);
|
|
97
|
+
const data = await gql.query(`
|
|
98
|
+
query {
|
|
99
|
+
sites {
|
|
100
|
+
id
|
|
101
|
+
name
|
|
102
|
+
domain
|
|
103
|
+
status
|
|
104
|
+
path
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
`);
|
|
108
|
+
let sitesToShow = data.sites.map((s) => ({
|
|
109
|
+
id: s.id,
|
|
110
|
+
name: s.name,
|
|
111
|
+
domain: s.domain,
|
|
112
|
+
status: s.status.toLowerCase(),
|
|
113
|
+
path: s.path,
|
|
114
|
+
}));
|
|
115
|
+
// Filter by status if specified
|
|
116
|
+
if (cmdOptions.status !== 'all') {
|
|
117
|
+
sitesToShow = sitesToShow.filter((s) => s.status === cmdOptions.status);
|
|
118
|
+
}
|
|
119
|
+
console.log((0, formatters_1.formatSiteList)(sitesToShow, format, { noColor: globalOpts.noColor }));
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
console.error((0, formatters_1.formatError)(error.message));
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
sites
|
|
127
|
+
.command('get <site>')
|
|
128
|
+
.description('Get detailed info about a site')
|
|
129
|
+
.action(async (site) => {
|
|
130
|
+
const globalOpts = program.opts();
|
|
131
|
+
const format = (0, formatters_1.getOutputFormat)(globalOpts);
|
|
132
|
+
try {
|
|
133
|
+
const gql = await ensureConnected(globalOpts);
|
|
134
|
+
// First find the site by name or ID
|
|
135
|
+
const sitesData = await gql.query(`
|
|
136
|
+
query { sites { id name } }
|
|
137
|
+
`);
|
|
138
|
+
const foundSite = sitesData.sites.find((s) => s.id === site || s.name.toLowerCase().includes(site.toLowerCase()));
|
|
139
|
+
if (!foundSite) {
|
|
140
|
+
console.error((0, formatters_1.formatError)(`Site not found: "${site}"`));
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
const data = await gql.query(`
|
|
144
|
+
query($id: ID!) {
|
|
145
|
+
site(id: $id) {
|
|
146
|
+
id
|
|
147
|
+
name
|
|
148
|
+
domain
|
|
149
|
+
status
|
|
150
|
+
path
|
|
151
|
+
url
|
|
152
|
+
host
|
|
153
|
+
httpPort
|
|
154
|
+
xdebugEnabled
|
|
155
|
+
services {
|
|
156
|
+
name
|
|
157
|
+
version
|
|
158
|
+
role
|
|
159
|
+
}
|
|
160
|
+
hostConnections {
|
|
161
|
+
hostId
|
|
162
|
+
remoteSiteId
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
`, { id: foundSite.id });
|
|
167
|
+
console.log((0, formatters_1.formatSiteDetail)(data.site, format, { noColor: globalOpts.noColor }));
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
console.error((0, formatters_1.formatError)(error.message));
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
sites
|
|
175
|
+
.command('start <site>')
|
|
176
|
+
.description('Start a site')
|
|
177
|
+
.action(async (site) => {
|
|
178
|
+
await runSiteCommand(site, { action: 'Starting', successMessage: () => `Started "${site}"` }, async (gql, siteId) => {
|
|
179
|
+
return gql.mutate(`mutation($id: ID!) { startSite(id: $id) { id status } }`, { id: siteId });
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
sites
|
|
183
|
+
.command('stop <site>')
|
|
184
|
+
.description('Stop a site')
|
|
185
|
+
.action(async (site) => {
|
|
186
|
+
await runSiteCommand(site, { action: 'Stopping', successMessage: () => `Stopped "${site}"` }, async (gql, siteId) => {
|
|
187
|
+
return gql.mutate(`mutation($id: ID!) { stopSite(id: $id) { id status } }`, { id: siteId });
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
sites
|
|
191
|
+
.command('restart <site>')
|
|
192
|
+
.description('Restart a site')
|
|
193
|
+
.action(async (site) => {
|
|
194
|
+
await runSiteCommand(site, { action: 'Restarting', successMessage: () => `Restarted "${site}"` }, async (gql, siteId) => {
|
|
195
|
+
return gql.mutate(`mutation($id: ID!) { restartSite(id: $id) { id status } }`, { id: siteId });
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
sites
|
|
199
|
+
.command('open <site>')
|
|
200
|
+
.description('Open site in browser')
|
|
201
|
+
.option('--admin', 'Open WP Admin instead of frontend')
|
|
202
|
+
.action(async (site, cmdOptions) => {
|
|
203
|
+
await runSiteCommand(site, { action: 'Opening', successMessage: () => `Opened "${site}"` }, async (gql, siteId) => {
|
|
204
|
+
return gql.mutate(`
|
|
205
|
+
mutation($input: OpenSiteInput!) {
|
|
206
|
+
openSite(input: $input) { success error }
|
|
207
|
+
}
|
|
208
|
+
`, { input: { siteId, openAdmin: cmdOptions.admin || false } });
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
sites
|
|
212
|
+
.command('create <name>')
|
|
213
|
+
.description('Create a new WordPress site')
|
|
214
|
+
.option('--php <version>', 'PHP version (e.g., 8.2.10)')
|
|
215
|
+
.option('--web <server>', 'Web server (nginx|apache)')
|
|
216
|
+
.option('--db <database>', 'Database (mysql|mariadb)')
|
|
217
|
+
.option('--blueprint <name>', 'Use a blueprint')
|
|
218
|
+
.option('--wp-user <username>', 'WordPress admin username', 'admin')
|
|
219
|
+
.option('--wp-email <email>', 'WordPress admin email')
|
|
220
|
+
.action(async (name, cmdOptions) => {
|
|
221
|
+
const globalOpts = program.opts();
|
|
222
|
+
const spinner = globalOpts.quiet ? null : (0, ora_1.default)(`Creating "${name}"...`).start();
|
|
223
|
+
try {
|
|
224
|
+
const gql = await ensureConnected(globalOpts);
|
|
225
|
+
const input = { name };
|
|
226
|
+
if (cmdOptions.php)
|
|
227
|
+
input.phpVersion = cmdOptions.php;
|
|
228
|
+
if (cmdOptions.web)
|
|
229
|
+
input.webServer = cmdOptions.web;
|
|
230
|
+
if (cmdOptions.db)
|
|
231
|
+
input.database = cmdOptions.db;
|
|
232
|
+
if (cmdOptions.blueprint)
|
|
233
|
+
input.blueprint = cmdOptions.blueprint;
|
|
234
|
+
if (cmdOptions.wpUser)
|
|
235
|
+
input.wpAdminUsername = cmdOptions.wpUser;
|
|
236
|
+
if (cmdOptions.wpEmail)
|
|
237
|
+
input.wpAdminEmail = cmdOptions.wpEmail;
|
|
238
|
+
const data = await gql.mutate(`
|
|
239
|
+
mutation($input: CreateSiteInput!) {
|
|
240
|
+
createSite(input: $input) { success siteId siteName error }
|
|
241
|
+
}
|
|
242
|
+
`, { input });
|
|
243
|
+
if (!data.createSite.success) {
|
|
244
|
+
spinner?.fail('Create failed');
|
|
245
|
+
console.error((0, formatters_1.formatError)(data.createSite.error || 'Failed to create site'));
|
|
246
|
+
process.exit(1);
|
|
247
|
+
}
|
|
248
|
+
spinner?.succeed(`Created "${data.createSite.siteName}" (${data.createSite.siteId})`);
|
|
249
|
+
}
|
|
250
|
+
catch (error) {
|
|
251
|
+
spinner?.fail('Create failed');
|
|
252
|
+
console.error((0, formatters_1.formatError)(error.message));
|
|
253
|
+
process.exit(1);
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
sites
|
|
257
|
+
.command('delete <site>')
|
|
258
|
+
.description('Delete a site')
|
|
259
|
+
.option('-y, --yes', 'Skip confirmation')
|
|
260
|
+
.option('--keep-files', 'Keep site files (only remove from Local)')
|
|
261
|
+
.action(async (site, cmdOptions) => {
|
|
262
|
+
await runSiteCommand(site, { action: 'Deleting', successMessage: () => `Deleted "${site}"` }, async (gql, siteId) => {
|
|
263
|
+
const data = await gql.mutate(`
|
|
264
|
+
mutation($input: DeleteSiteInput!) {
|
|
265
|
+
deleteSite(input: $input) { success error }
|
|
266
|
+
}
|
|
267
|
+
`, { input: { id: siteId, trashFiles: !cmdOptions.keepFiles } });
|
|
268
|
+
if (!data.deleteSite.success) {
|
|
269
|
+
throw new Error(data.deleteSite.error || 'Failed to delete site');
|
|
270
|
+
}
|
|
271
|
+
return data;
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
sites
|
|
275
|
+
.command('clone <site> <newName>')
|
|
276
|
+
.description('Clone a site')
|
|
277
|
+
.action(async (site, newName) => {
|
|
278
|
+
await runSiteCommand(site, { action: `Cloning`, successMessage: (data) => `Cloned to "${data.cloneSite.newSiteName}" (${data.cloneSite.newSiteId})` }, async (gql, siteId) => {
|
|
279
|
+
const data = await gql.mutate(`
|
|
280
|
+
mutation($input: CloneSiteInput!) {
|
|
281
|
+
cloneSite(input: $input) { success newSiteId newSiteName error }
|
|
282
|
+
}
|
|
283
|
+
`, { input: { siteId, newName } });
|
|
284
|
+
if (!data.cloneSite.success) {
|
|
285
|
+
throw new Error(data.cloneSite.error || 'Failed to clone site');
|
|
286
|
+
}
|
|
287
|
+
return data;
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
sites
|
|
291
|
+
.command('export <site>')
|
|
292
|
+
.description('Export site to zip file')
|
|
293
|
+
.option('-o, --output <path>', 'Output file path')
|
|
294
|
+
.action(async (site, cmdOptions) => {
|
|
295
|
+
await runSiteCommand(site, { action: 'Exporting', successMessage: (data) => `Exported to ${data.exportSite.outputPath}` }, async (gql, siteId) => {
|
|
296
|
+
const data = await gql.mutate(`
|
|
297
|
+
mutation($input: ExportSiteInput!) {
|
|
298
|
+
exportSite(input: $input) { success outputPath error }
|
|
299
|
+
}
|
|
300
|
+
`, { input: { siteId, outputPath: cmdOptions.output } });
|
|
301
|
+
if (!data.exportSite.success) {
|
|
302
|
+
throw new Error(data.exportSite.error || 'Failed to export site');
|
|
303
|
+
}
|
|
304
|
+
return data;
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
sites
|
|
308
|
+
.command('import <zipFile>')
|
|
309
|
+
.description('Import site from zip file')
|
|
310
|
+
.option('-n, --name <name>', 'Site name (defaults to zip filename)')
|
|
311
|
+
.action(async (zipFile, cmdOptions) => {
|
|
312
|
+
const globalOpts = program.opts();
|
|
313
|
+
const spinner = globalOpts.quiet ? null : (0, ora_1.default)(`Importing site...`).start();
|
|
314
|
+
try {
|
|
315
|
+
const gql = await ensureConnected(globalOpts);
|
|
316
|
+
const data = await gql.mutate(`
|
|
317
|
+
mutation($input: ImportSiteInput!) {
|
|
318
|
+
importSite(input: $input) { success siteId siteName error }
|
|
319
|
+
}
|
|
320
|
+
`, { input: { zipPath: zipFile, siteName: cmdOptions.name } });
|
|
321
|
+
if (!data.importSite.success) {
|
|
322
|
+
spinner?.fail('Import failed');
|
|
323
|
+
console.error((0, formatters_1.formatError)(data.importSite.error || 'Failed to import site'));
|
|
324
|
+
process.exit(1);
|
|
325
|
+
}
|
|
326
|
+
spinner?.succeed(`Imported "${data.importSite.siteName}" (${data.importSite.siteId})`);
|
|
327
|
+
}
|
|
328
|
+
catch (error) {
|
|
329
|
+
spinner?.fail('Import failed');
|
|
330
|
+
console.error((0, formatters_1.formatError)(error.message));
|
|
331
|
+
process.exit(1);
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
sites
|
|
335
|
+
.command('rename <site> <newName>')
|
|
336
|
+
.description('Rename a site')
|
|
337
|
+
.action(async (site, newName) => {
|
|
338
|
+
await runSiteCommand(site, { action: 'Renaming', successMessage: () => `Renamed to "${newName}"` }, async (gql, siteId) => {
|
|
339
|
+
const data = await gql.mutate(`
|
|
340
|
+
mutation($input: McpRenameSiteInput!) {
|
|
341
|
+
mcpRenameSite(input: $input) { success error }
|
|
342
|
+
}
|
|
343
|
+
`, { input: { siteId, newName } });
|
|
344
|
+
if (!data.mcpRenameSite.success) {
|
|
345
|
+
throw new Error(data.mcpRenameSite.error || 'Failed to rename site');
|
|
346
|
+
}
|
|
347
|
+
return data;
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
sites
|
|
351
|
+
.command('ssl <site>')
|
|
352
|
+
.description('Trust SSL certificate for a site')
|
|
353
|
+
.action(async (site) => {
|
|
354
|
+
await runSiteCommand(site, { action: 'Trusting SSL for', successMessage: () => `SSL certificate trusted for "${site}"` }, async (gql, siteId) => {
|
|
355
|
+
const data = await gql.mutate(`
|
|
356
|
+
mutation($input: TrustSslInput!) {
|
|
357
|
+
trustSsl(input: $input) { success error }
|
|
358
|
+
}
|
|
359
|
+
`, { input: { siteId } });
|
|
360
|
+
if (!data.trustSsl.success) {
|
|
361
|
+
throw new Error(data.trustSsl.error || 'Failed to trust SSL');
|
|
362
|
+
}
|
|
363
|
+
return data;
|
|
364
|
+
});
|
|
365
|
+
});
|
|
366
|
+
sites
|
|
367
|
+
.command('php <site> <version>')
|
|
368
|
+
.description('Change PHP version for a site')
|
|
369
|
+
.action(async (site, version) => {
|
|
370
|
+
await runSiteCommand(site, { action: `Changing PHP to ${version} for`, successMessage: () => `PHP version changed to ${version}` }, async (gql, siteId) => {
|
|
371
|
+
const data = await gql.mutate(`
|
|
372
|
+
mutation($input: ChangePhpVersionInput!) {
|
|
373
|
+
changePhpVersion(input: $input) { success error }
|
|
374
|
+
}
|
|
375
|
+
`, { input: { siteId, phpVersion: version } });
|
|
376
|
+
if (!data.changePhpVersion.success) {
|
|
377
|
+
throw new Error(data.changePhpVersion.error || 'Failed to change PHP version');
|
|
378
|
+
}
|
|
379
|
+
return data;
|
|
380
|
+
});
|
|
381
|
+
});
|
|
382
|
+
sites
|
|
383
|
+
.command('xdebug <site>')
|
|
384
|
+
.description('Toggle Xdebug for a site')
|
|
385
|
+
.option('--on', 'Enable Xdebug')
|
|
386
|
+
.option('--off', 'Disable Xdebug')
|
|
387
|
+
.action(async (site, cmdOptions) => {
|
|
388
|
+
const enabled = cmdOptions.on ? true : cmdOptions.off ? false : undefined;
|
|
389
|
+
const action = enabled === undefined ? 'Toggling' : enabled ? 'Enabling' : 'Disabling';
|
|
390
|
+
await runSiteCommand(site, { action: `${action} Xdebug for`, successMessage: (data) => `Xdebug ${data.toggleXdebug.enabled ? 'enabled' : 'disabled'}` }, async (gql, siteId) => {
|
|
391
|
+
// If no flag specified, get current state and toggle
|
|
392
|
+
let targetEnabled = enabled;
|
|
393
|
+
if (targetEnabled === undefined) {
|
|
394
|
+
const siteData = await gql.query(`
|
|
395
|
+
query($id: ID!) { site(id: $id) { xdebugEnabled } }
|
|
396
|
+
`, { id: siteId });
|
|
397
|
+
targetEnabled = !siteData.site.xdebugEnabled;
|
|
398
|
+
}
|
|
399
|
+
const data = await gql.mutate(`
|
|
400
|
+
mutation($input: ToggleXdebugInput!) {
|
|
401
|
+
toggleXdebug(input: $input) { success enabled error }
|
|
402
|
+
}
|
|
403
|
+
`, { input: { siteId, enabled: targetEnabled } });
|
|
404
|
+
if (!data.toggleXdebug.success) {
|
|
405
|
+
throw new Error(data.toggleXdebug.error || 'Failed to toggle Xdebug');
|
|
406
|
+
}
|
|
407
|
+
return data;
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
sites
|
|
411
|
+
.command('logs <site>')
|
|
412
|
+
.description('Get site logs')
|
|
413
|
+
.option('-t, --type <type>', 'Log type (php|nginx|mysql)', 'php')
|
|
414
|
+
.option('-n, --lines <n>', 'Number of lines', '50')
|
|
415
|
+
.action(async (site, cmdOptions) => {
|
|
416
|
+
const globalOpts = program.opts();
|
|
417
|
+
const format = (0, formatters_1.getOutputFormat)(globalOpts);
|
|
418
|
+
try {
|
|
419
|
+
const gql = await ensureConnected(globalOpts);
|
|
420
|
+
const siteId = await findSiteId(gql, site);
|
|
421
|
+
const data = await gql.mutate(`
|
|
422
|
+
mutation($input: GetSiteLogsInput!) {
|
|
423
|
+
getSiteLogs(input: $input) { success logs error }
|
|
424
|
+
}
|
|
425
|
+
`, { input: { siteId, logType: cmdOptions.type, lines: parseInt(cmdOptions.lines, 10) } });
|
|
426
|
+
if (!data.getSiteLogs.success) {
|
|
427
|
+
console.error((0, formatters_1.formatError)(data.getSiteLogs.error || 'Failed to get logs'));
|
|
428
|
+
process.exit(1);
|
|
429
|
+
}
|
|
430
|
+
if (format === 'json') {
|
|
431
|
+
console.log(JSON.stringify(data.getSiteLogs.logs, null, 2));
|
|
432
|
+
}
|
|
433
|
+
else if (data.getSiteLogs.logs.length === 0) {
|
|
434
|
+
console.log('No logs found.');
|
|
435
|
+
}
|
|
436
|
+
else {
|
|
437
|
+
data.getSiteLogs.logs.forEach((line) => console.log(line));
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
catch (error) {
|
|
441
|
+
console.error((0, formatters_1.formatError)(error.message));
|
|
442
|
+
process.exit(1);
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
// ===========================================
|
|
446
|
+
// WP-CLI Command
|
|
447
|
+
// ===========================================
|
|
448
|
+
program
|
|
449
|
+
.command('wp <site> [args...]')
|
|
450
|
+
.description('Run WP-CLI commands against a site')
|
|
451
|
+
.action(async (site, args) => {
|
|
452
|
+
const globalOpts = program.opts();
|
|
453
|
+
try {
|
|
454
|
+
const gql = await ensureConnected(globalOpts);
|
|
455
|
+
const siteId = await findSiteId(gql, site);
|
|
456
|
+
const data = await gql.mutate(`
|
|
457
|
+
mutation($input: WpCliInput!) {
|
|
458
|
+
wpCli(input: $input) { success output error }
|
|
459
|
+
}
|
|
460
|
+
`, { input: { siteId, args } });
|
|
461
|
+
if (!data.wpCli.success) {
|
|
462
|
+
console.error((0, formatters_1.formatError)(data.wpCli.error || 'WP-CLI command failed'));
|
|
463
|
+
process.exit(1);
|
|
464
|
+
}
|
|
465
|
+
console.log(data.wpCli.output);
|
|
466
|
+
}
|
|
467
|
+
catch (error) {
|
|
468
|
+
console.error((0, formatters_1.formatError)(error.message));
|
|
469
|
+
process.exit(1);
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
// ===========================================
|
|
473
|
+
// Info Command
|
|
474
|
+
// ===========================================
|
|
475
|
+
program
|
|
476
|
+
.command('info')
|
|
477
|
+
.description('Show Local application info')
|
|
478
|
+
.action(async () => {
|
|
479
|
+
const globalOpts = program.opts();
|
|
480
|
+
const format = (0, formatters_1.getOutputFormat)(globalOpts);
|
|
481
|
+
try {
|
|
482
|
+
const gql = await ensureConnected(globalOpts);
|
|
483
|
+
// Get sites count and basic info
|
|
484
|
+
const data = await gql.query(`
|
|
485
|
+
query { sites { id status } }
|
|
486
|
+
`);
|
|
487
|
+
const running = data.sites.filter((s) => s.status.toLowerCase() === 'running').length;
|
|
488
|
+
const stopped = data.sites.filter((s) => s.status.toLowerCase() !== 'running').length;
|
|
489
|
+
const info = {
|
|
490
|
+
totalSites: data.sites.length,
|
|
491
|
+
runningSites: running,
|
|
492
|
+
stoppedSites: stopped,
|
|
493
|
+
graphqlEndpoint: client?.['url'] || 'connected',
|
|
494
|
+
};
|
|
495
|
+
console.log((0, formatters_1.formatSiteDetail)(info, format, { noColor: globalOpts.noColor }));
|
|
496
|
+
}
|
|
497
|
+
catch (error) {
|
|
498
|
+
console.error((0, formatters_1.formatError)(error.message));
|
|
499
|
+
process.exit(1);
|
|
500
|
+
}
|
|
501
|
+
});
|
|
502
|
+
// ===========================================
|
|
503
|
+
// Services Command
|
|
504
|
+
// ===========================================
|
|
505
|
+
program
|
|
506
|
+
.command('services')
|
|
507
|
+
.description('List available service versions')
|
|
508
|
+
.action(async () => {
|
|
509
|
+
const globalOpts = program.opts();
|
|
510
|
+
const format = (0, formatters_1.getOutputFormat)(globalOpts);
|
|
511
|
+
try {
|
|
512
|
+
const gql = await ensureConnected(globalOpts);
|
|
513
|
+
const data = await gql.query(`
|
|
514
|
+
query {
|
|
515
|
+
listServices {
|
|
516
|
+
success
|
|
517
|
+
services { role name version }
|
|
518
|
+
error
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
`);
|
|
522
|
+
if (!data.listServices.success) {
|
|
523
|
+
console.error((0, formatters_1.formatError)(data.listServices.error || 'Failed to list services'));
|
|
524
|
+
process.exit(1);
|
|
525
|
+
}
|
|
526
|
+
if (format === 'json') {
|
|
527
|
+
console.log(JSON.stringify(data.listServices.services, null, 2));
|
|
528
|
+
}
|
|
529
|
+
else {
|
|
530
|
+
const grouped = {};
|
|
531
|
+
for (const svc of data.listServices.services) {
|
|
532
|
+
if (!grouped[svc.role])
|
|
533
|
+
grouped[svc.role] = [];
|
|
534
|
+
grouped[svc.role].push(`${svc.version} (${svc.name})`);
|
|
535
|
+
}
|
|
536
|
+
for (const [role, versions] of Object.entries(grouped)) {
|
|
537
|
+
console.log(`\n${role.charAt(0).toUpperCase() + role.slice(1)} Versions:`);
|
|
538
|
+
versions.forEach((v) => console.log(` - ${v}`));
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
catch (error) {
|
|
543
|
+
console.error((0, formatters_1.formatError)(error.message));
|
|
544
|
+
process.exit(1);
|
|
545
|
+
}
|
|
546
|
+
});
|
|
547
|
+
// ===========================================
|
|
548
|
+
// Blueprints Command
|
|
549
|
+
// ===========================================
|
|
550
|
+
const blueprints = program.command('blueprints').description('Manage blueprints');
|
|
551
|
+
blueprints
|
|
552
|
+
.command('list')
|
|
553
|
+
.description('List available blueprints')
|
|
554
|
+
.action(async () => {
|
|
555
|
+
const globalOpts = program.opts();
|
|
556
|
+
const format = (0, formatters_1.getOutputFormat)(globalOpts);
|
|
557
|
+
try {
|
|
558
|
+
const gql = await ensureConnected(globalOpts);
|
|
559
|
+
const data = await gql.query(`
|
|
560
|
+
query {
|
|
561
|
+
blueprints {
|
|
562
|
+
success
|
|
563
|
+
blueprints { name }
|
|
564
|
+
error
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
`);
|
|
568
|
+
if (!data.blueprints.success) {
|
|
569
|
+
console.error((0, formatters_1.formatError)(data.blueprints.error || 'Failed to list blueprints'));
|
|
570
|
+
process.exit(1);
|
|
571
|
+
}
|
|
572
|
+
if (format === 'json') {
|
|
573
|
+
console.log(JSON.stringify(data.blueprints.blueprints, null, 2));
|
|
574
|
+
}
|
|
575
|
+
else if (data.blueprints.blueprints.length === 0) {
|
|
576
|
+
console.log('No blueprints found.');
|
|
577
|
+
}
|
|
578
|
+
else {
|
|
579
|
+
console.log('Blueprints:');
|
|
580
|
+
data.blueprints.blueprints.forEach((b) => console.log(` - ${b.name}`));
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
catch (error) {
|
|
584
|
+
console.error((0, formatters_1.formatError)(error.message));
|
|
585
|
+
process.exit(1);
|
|
586
|
+
}
|
|
587
|
+
});
|
|
588
|
+
blueprints
|
|
589
|
+
.command('save <site> <name>')
|
|
590
|
+
.description('Save a site as a blueprint')
|
|
591
|
+
.action(async (site, name) => {
|
|
592
|
+
await runSiteCommand(site, { action: 'Saving blueprint from', successMessage: () => `Saved blueprint "${name}"` }, async (gql, siteId) => {
|
|
593
|
+
const data = await gql.mutate(`
|
|
594
|
+
mutation($input: SaveBlueprintInput!) {
|
|
595
|
+
saveBlueprint(input: $input) { success error }
|
|
596
|
+
}
|
|
597
|
+
`, { input: { siteId, name } });
|
|
598
|
+
if (!data.saveBlueprint.success) {
|
|
599
|
+
throw new Error(data.saveBlueprint.error || 'Failed to save blueprint');
|
|
600
|
+
}
|
|
601
|
+
return data;
|
|
602
|
+
});
|
|
603
|
+
});
|
|
604
|
+
// ===========================================
|
|
605
|
+
// Database Commands
|
|
606
|
+
// ===========================================
|
|
607
|
+
const db = program.command('db').description('Database operations');
|
|
608
|
+
db
|
|
609
|
+
.command('export <site>')
|
|
610
|
+
.description('Export database to SQL file')
|
|
611
|
+
.option('-o, --output <path>', 'Output file path')
|
|
612
|
+
.action(async (site, cmdOptions) => {
|
|
613
|
+
await runSiteCommand(site, { action: 'Exporting database for', successMessage: (data) => `Exported to ${data.exportDatabase.outputPath}` }, async (gql, siteId) => {
|
|
614
|
+
const data = await gql.mutate(`
|
|
615
|
+
mutation($input: ExportDatabaseInput!) {
|
|
616
|
+
exportDatabase(input: $input) { success outputPath error }
|
|
617
|
+
}
|
|
618
|
+
`, { input: { siteId, outputPath: cmdOptions.output } });
|
|
619
|
+
if (!data.exportDatabase.success) {
|
|
620
|
+
throw new Error(data.exportDatabase.error || 'Failed to export database');
|
|
621
|
+
}
|
|
622
|
+
return data;
|
|
623
|
+
});
|
|
624
|
+
});
|
|
625
|
+
db
|
|
626
|
+
.command('import <site> <sqlFile>')
|
|
627
|
+
.description('Import SQL file into database')
|
|
628
|
+
.action(async (site, sqlFile) => {
|
|
629
|
+
await runSiteCommand(site, { action: 'Importing database for', successMessage: () => 'Database imported successfully' }, async (gql, siteId) => {
|
|
630
|
+
const data = await gql.mutate(`
|
|
631
|
+
mutation($input: ImportDatabaseInput!) {
|
|
632
|
+
importDatabase(input: $input) { success error }
|
|
633
|
+
}
|
|
634
|
+
`, { input: { siteId, sqlPath: sqlFile } });
|
|
635
|
+
if (!data.importDatabase.success) {
|
|
636
|
+
throw new Error(data.importDatabase.error || 'Failed to import database');
|
|
637
|
+
}
|
|
638
|
+
return data;
|
|
639
|
+
});
|
|
640
|
+
});
|
|
641
|
+
db
|
|
642
|
+
.command('adminer <site>')
|
|
643
|
+
.description('Open Adminer database UI')
|
|
644
|
+
.action(async (site) => {
|
|
645
|
+
await runSiteCommand(site, { action: 'Opening Adminer for', successMessage: () => 'Opened Adminer' }, async (gql, siteId) => {
|
|
646
|
+
return gql.mutate(`
|
|
647
|
+
mutation($input: OpenAdminerInput!) {
|
|
648
|
+
openAdminer(input: $input) { success error }
|
|
649
|
+
}
|
|
650
|
+
`, { input: { siteId } });
|
|
651
|
+
});
|
|
652
|
+
});
|
|
653
|
+
// ===========================================
|
|
654
|
+
// Backups Commands
|
|
655
|
+
// ===========================================
|
|
656
|
+
const backups = program.command('backups').description('Cloud backup operations');
|
|
657
|
+
backups
|
|
658
|
+
.command('status')
|
|
659
|
+
.description('Check backup service availability')
|
|
660
|
+
.action(async () => {
|
|
661
|
+
const globalOpts = program.opts();
|
|
662
|
+
const format = (0, formatters_1.getOutputFormat)(globalOpts);
|
|
663
|
+
try {
|
|
664
|
+
const gql = await ensureConnected(globalOpts);
|
|
665
|
+
const data = await gql.query(`
|
|
666
|
+
query {
|
|
667
|
+
backupStatus {
|
|
668
|
+
available
|
|
669
|
+
featureEnabled
|
|
670
|
+
dropbox { authenticated accountId email }
|
|
671
|
+
googleDrive { authenticated accountId email }
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
`);
|
|
675
|
+
if (format === 'json') {
|
|
676
|
+
console.log(JSON.stringify(data.backupStatus, null, 2));
|
|
677
|
+
}
|
|
678
|
+
else {
|
|
679
|
+
const status = data.backupStatus;
|
|
680
|
+
console.log(`\nBackup Status:`);
|
|
681
|
+
console.log(` Available: ${status.available ? 'Yes' : 'No'}`);
|
|
682
|
+
console.log(` Feature Enabled: ${status.featureEnabled ? 'Yes' : 'No'}`);
|
|
683
|
+
if (status.dropbox) {
|
|
684
|
+
console.log(`\n Dropbox: ${status.dropbox.authenticated ? `Connected (${status.dropbox.email})` : 'Not connected'}`);
|
|
685
|
+
}
|
|
686
|
+
if (status.googleDrive) {
|
|
687
|
+
console.log(` Google Drive: ${status.googleDrive.authenticated ? `Connected (${status.googleDrive.email})` : 'Not connected'}`);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
catch (error) {
|
|
692
|
+
console.error((0, formatters_1.formatError)(error.message));
|
|
693
|
+
process.exit(1);
|
|
694
|
+
}
|
|
695
|
+
});
|
|
696
|
+
backups
|
|
697
|
+
.command('list <site>')
|
|
698
|
+
.description('List backups for a site')
|
|
699
|
+
.option('-p, --provider <provider>', 'Backup provider (dropbox|googleDrive)', 'dropbox')
|
|
700
|
+
.action(async (site, cmdOptions) => {
|
|
701
|
+
const globalOpts = program.opts();
|
|
702
|
+
const format = (0, formatters_1.getOutputFormat)(globalOpts);
|
|
703
|
+
try {
|
|
704
|
+
const gql = await ensureConnected(globalOpts);
|
|
705
|
+
const siteId = await findSiteId(gql, site);
|
|
706
|
+
const data = await gql.query(`
|
|
707
|
+
query($siteId: ID!, $provider: String!) {
|
|
708
|
+
listBackups(siteId: $siteId, provider: $provider) {
|
|
709
|
+
success
|
|
710
|
+
backups { snapshotId timestamp note }
|
|
711
|
+
error
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
`, { siteId, provider: cmdOptions.provider });
|
|
715
|
+
if (!data.listBackups.success) {
|
|
716
|
+
console.error((0, formatters_1.formatError)(data.listBackups.error || 'Failed to list backups'));
|
|
717
|
+
process.exit(1);
|
|
718
|
+
}
|
|
719
|
+
if (format === 'json') {
|
|
720
|
+
console.log(JSON.stringify(data.listBackups.backups, null, 2));
|
|
721
|
+
}
|
|
722
|
+
else if (data.listBackups.backups.length === 0) {
|
|
723
|
+
console.log('No backups found.');
|
|
724
|
+
}
|
|
725
|
+
else {
|
|
726
|
+
console.log(`\nBackups (${cmdOptions.provider}):`);
|
|
727
|
+
for (const backup of data.listBackups.backups) {
|
|
728
|
+
const date = new Date(backup.timestamp).toLocaleString();
|
|
729
|
+
console.log(` ${backup.snapshotId} - ${date}${backup.note ? ` - ${backup.note}` : ''}`);
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
catch (error) {
|
|
734
|
+
console.error((0, formatters_1.formatError)(error.message));
|
|
735
|
+
process.exit(1);
|
|
736
|
+
}
|
|
737
|
+
});
|
|
738
|
+
backups
|
|
739
|
+
.command('create <site>')
|
|
740
|
+
.description('Create a backup')
|
|
741
|
+
.option('-p, --provider <provider>', 'Backup provider (dropbox|googleDrive)', 'dropbox')
|
|
742
|
+
.option('-n, --note <note>', 'Backup note')
|
|
743
|
+
.action(async (site, cmdOptions) => {
|
|
744
|
+
await runSiteCommand(site, { action: 'Creating backup for', successMessage: (data) => `Backup created: ${data.createBackup.snapshotId}` }, async (gql, siteId) => {
|
|
745
|
+
const data = await gql.mutate(`
|
|
746
|
+
mutation($siteId: ID!, $provider: String!, $note: String) {
|
|
747
|
+
createBackup(siteId: $siteId, provider: $provider, note: $note) {
|
|
748
|
+
success snapshotId error
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
`, { siteId, provider: cmdOptions.provider, note: cmdOptions.note });
|
|
752
|
+
if (!data.createBackup.success) {
|
|
753
|
+
throw new Error(data.createBackup.error || 'Failed to create backup');
|
|
754
|
+
}
|
|
755
|
+
return data;
|
|
756
|
+
});
|
|
757
|
+
});
|
|
758
|
+
backups
|
|
759
|
+
.command('restore <site> <snapshotId>')
|
|
760
|
+
.description('Restore from backup')
|
|
761
|
+
.option('-p, --provider <provider>', 'Backup provider (dropbox|googleDrive)', 'dropbox')
|
|
762
|
+
.option('-y, --yes', 'Skip confirmation')
|
|
763
|
+
.action(async (site, snapshotId, cmdOptions) => {
|
|
764
|
+
await runSiteCommand(site, { action: 'Restoring backup for', successMessage: (data) => data.restoreBackup.message || 'Backup restored successfully' }, async (gql, siteId) => {
|
|
765
|
+
const data = await gql.mutate(`
|
|
766
|
+
mutation($siteId: ID!, $provider: String!, $snapshotId: String!, $confirm: Boolean) {
|
|
767
|
+
restoreBackup(siteId: $siteId, provider: $provider, snapshotId: $snapshotId, confirm: $confirm) {
|
|
768
|
+
success message error
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
`, { siteId, provider: cmdOptions.provider, snapshotId, confirm: cmdOptions.yes || false });
|
|
772
|
+
if (!data.restoreBackup.success) {
|
|
773
|
+
throw new Error(data.restoreBackup.error || 'Failed to restore backup');
|
|
774
|
+
}
|
|
775
|
+
return data;
|
|
776
|
+
});
|
|
777
|
+
});
|
|
778
|
+
backups
|
|
779
|
+
.command('delete <site> <snapshotId>')
|
|
780
|
+
.description('Delete a backup')
|
|
781
|
+
.option('-p, --provider <provider>', 'Backup provider (dropbox|googleDrive)', 'dropbox')
|
|
782
|
+
.option('-y, --yes', 'Skip confirmation')
|
|
783
|
+
.action(async (site, snapshotId, cmdOptions) => {
|
|
784
|
+
await runSiteCommand(site, { action: 'Deleting backup for', successMessage: () => 'Backup deleted' }, async (gql, siteId) => {
|
|
785
|
+
const data = await gql.mutate(`
|
|
786
|
+
mutation($siteId: ID!, $provider: String!, $snapshotId: String!, $confirm: Boolean) {
|
|
787
|
+
deleteBackup(siteId: $siteId, provider: $provider, snapshotId: $snapshotId, confirm: $confirm) {
|
|
788
|
+
success error
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
`, { siteId, provider: cmdOptions.provider, snapshotId, confirm: cmdOptions.yes || false });
|
|
792
|
+
if (!data.deleteBackup.success) {
|
|
793
|
+
throw new Error(data.deleteBackup.error || 'Failed to delete backup');
|
|
794
|
+
}
|
|
795
|
+
return data;
|
|
796
|
+
});
|
|
797
|
+
});
|
|
798
|
+
// ===========================================
|
|
799
|
+
// WP Engine Commands
|
|
800
|
+
// ===========================================
|
|
801
|
+
const wpe = program.command('wpe').description('WP Engine sync operations');
|
|
802
|
+
wpe
|
|
803
|
+
.command('status')
|
|
804
|
+
.description('Check WP Engine authentication status')
|
|
805
|
+
.action(async () => {
|
|
806
|
+
const globalOpts = program.opts();
|
|
807
|
+
const format = (0, formatters_1.getOutputFormat)(globalOpts);
|
|
808
|
+
try {
|
|
809
|
+
const gql = await ensureConnected(globalOpts);
|
|
810
|
+
const data = await gql.query(`
|
|
811
|
+
query {
|
|
812
|
+
wpeStatus {
|
|
813
|
+
authenticated
|
|
814
|
+
email
|
|
815
|
+
accountId
|
|
816
|
+
accountName
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
`);
|
|
820
|
+
if (format === 'json') {
|
|
821
|
+
console.log(JSON.stringify(data.wpeStatus, null, 2));
|
|
822
|
+
}
|
|
823
|
+
else {
|
|
824
|
+
const status = data.wpeStatus;
|
|
825
|
+
if (status.authenticated) {
|
|
826
|
+
console.log(`\nWP Engine: Connected`);
|
|
827
|
+
console.log(` Email: ${status.email}`);
|
|
828
|
+
console.log(` Account: ${status.accountName} (${status.accountId})`);
|
|
829
|
+
}
|
|
830
|
+
else {
|
|
831
|
+
console.log(`\nWP Engine: Not connected`);
|
|
832
|
+
console.log(` Run 'lwp wpe login' to authenticate`);
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
catch (error) {
|
|
837
|
+
console.error((0, formatters_1.formatError)(error.message));
|
|
838
|
+
process.exit(1);
|
|
839
|
+
}
|
|
840
|
+
});
|
|
841
|
+
wpe
|
|
842
|
+
.command('login')
|
|
843
|
+
.description('Authenticate with WP Engine')
|
|
844
|
+
.action(async () => {
|
|
845
|
+
const globalOpts = program.opts();
|
|
846
|
+
const spinner = globalOpts.quiet ? null : (0, ora_1.default)(`Opening WP Engine login...`).start();
|
|
847
|
+
try {
|
|
848
|
+
const gql = await ensureConnected(globalOpts);
|
|
849
|
+
const data = await gql.mutate(`
|
|
850
|
+
mutation {
|
|
851
|
+
wpeAuthenticate { success email message error }
|
|
852
|
+
}
|
|
853
|
+
`);
|
|
854
|
+
if (!data.wpeAuthenticate.success) {
|
|
855
|
+
spinner?.fail('Authentication failed');
|
|
856
|
+
console.error((0, formatters_1.formatError)(data.wpeAuthenticate.error || 'Failed to authenticate'));
|
|
857
|
+
process.exit(1);
|
|
858
|
+
}
|
|
859
|
+
spinner?.succeed(`Authenticated as ${data.wpeAuthenticate.email}`);
|
|
860
|
+
}
|
|
861
|
+
catch (error) {
|
|
862
|
+
spinner?.fail('Authentication failed');
|
|
863
|
+
console.error((0, formatters_1.formatError)(error.message));
|
|
864
|
+
process.exit(1);
|
|
865
|
+
}
|
|
866
|
+
});
|
|
867
|
+
wpe
|
|
868
|
+
.command('logout')
|
|
869
|
+
.description('Logout from WP Engine')
|
|
870
|
+
.action(async () => {
|
|
871
|
+
const globalOpts = program.opts();
|
|
872
|
+
const spinner = globalOpts.quiet ? null : (0, ora_1.default)(`Logging out...`).start();
|
|
873
|
+
try {
|
|
874
|
+
const gql = await ensureConnected(globalOpts);
|
|
875
|
+
const data = await gql.mutate(`
|
|
876
|
+
mutation {
|
|
877
|
+
wpeLogout { success error }
|
|
878
|
+
}
|
|
879
|
+
`);
|
|
880
|
+
if (!data.wpeLogout.success) {
|
|
881
|
+
spinner?.fail('Logout failed');
|
|
882
|
+
console.error((0, formatters_1.formatError)(data.wpeLogout.error || 'Failed to logout'));
|
|
883
|
+
process.exit(1);
|
|
884
|
+
}
|
|
885
|
+
spinner?.succeed('Logged out from WP Engine');
|
|
886
|
+
}
|
|
887
|
+
catch (error) {
|
|
888
|
+
spinner?.fail('Logout failed');
|
|
889
|
+
console.error((0, formatters_1.formatError)(error.message));
|
|
890
|
+
process.exit(1);
|
|
891
|
+
}
|
|
892
|
+
});
|
|
893
|
+
wpe
|
|
894
|
+
.command('sites')
|
|
895
|
+
.description('List WP Engine sites')
|
|
896
|
+
.action(async () => {
|
|
897
|
+
const globalOpts = program.opts();
|
|
898
|
+
const format = (0, formatters_1.getOutputFormat)(globalOpts);
|
|
899
|
+
try {
|
|
900
|
+
const gql = await ensureConnected(globalOpts);
|
|
901
|
+
const data = await gql.query(`
|
|
902
|
+
query {
|
|
903
|
+
listWpeSites {
|
|
904
|
+
success
|
|
905
|
+
sites { id name environment primaryDomain }
|
|
906
|
+
error
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
`);
|
|
910
|
+
if (!data.listWpeSites.success) {
|
|
911
|
+
console.error((0, formatters_1.formatError)(data.listWpeSites.error || 'Failed to list sites'));
|
|
912
|
+
process.exit(1);
|
|
913
|
+
}
|
|
914
|
+
if (format === 'json') {
|
|
915
|
+
console.log(JSON.stringify(data.listWpeSites.sites, null, 2));
|
|
916
|
+
}
|
|
917
|
+
else if (data.listWpeSites.sites.length === 0) {
|
|
918
|
+
console.log('No WP Engine sites found.');
|
|
919
|
+
}
|
|
920
|
+
else {
|
|
921
|
+
console.log('\nWP Engine Sites:');
|
|
922
|
+
for (const site of data.listWpeSites.sites) {
|
|
923
|
+
console.log(` ${site.name} (${site.environment}) - ${site.primaryDomain}`);
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
catch (error) {
|
|
928
|
+
console.error((0, formatters_1.formatError)(error.message));
|
|
929
|
+
process.exit(1);
|
|
930
|
+
}
|
|
931
|
+
});
|
|
932
|
+
wpe
|
|
933
|
+
.command('link <site>')
|
|
934
|
+
.description('Show WP Engine connection for a local site')
|
|
935
|
+
.action(async (site) => {
|
|
936
|
+
const globalOpts = program.opts();
|
|
937
|
+
const format = (0, formatters_1.getOutputFormat)(globalOpts);
|
|
938
|
+
try {
|
|
939
|
+
const gql = await ensureConnected(globalOpts);
|
|
940
|
+
const siteId = await findSiteId(gql, site);
|
|
941
|
+
const data = await gql.query(`
|
|
942
|
+
query($siteId: ID!) {
|
|
943
|
+
getWpeLink(siteId: $siteId) {
|
|
944
|
+
linked
|
|
945
|
+
siteName
|
|
946
|
+
connections { remoteInstallId installName environment primaryDomain }
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
`, { siteId });
|
|
950
|
+
if (format === 'json') {
|
|
951
|
+
console.log(JSON.stringify(data.getWpeLink, null, 2));
|
|
952
|
+
}
|
|
953
|
+
else {
|
|
954
|
+
const link = data.getWpeLink;
|
|
955
|
+
if (!link.linked || link.connections.length === 0) {
|
|
956
|
+
console.log(`\n"${link.siteName}" is not linked to WP Engine`);
|
|
957
|
+
}
|
|
958
|
+
else {
|
|
959
|
+
console.log(`\n"${link.siteName}" WP Engine Connections:`);
|
|
960
|
+
for (const conn of link.connections) {
|
|
961
|
+
console.log(` ${conn.installName} (${conn.environment}) - ${conn.primaryDomain}`);
|
|
962
|
+
console.log(` ID: ${conn.remoteInstallId}`);
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
catch (error) {
|
|
968
|
+
console.error((0, formatters_1.formatError)(error.message));
|
|
969
|
+
process.exit(1);
|
|
970
|
+
}
|
|
971
|
+
});
|
|
972
|
+
wpe
|
|
973
|
+
.command('push <site>')
|
|
974
|
+
.description('Push local site to WP Engine')
|
|
975
|
+
.option('-r, --remote <installId>', 'Remote install ID')
|
|
976
|
+
.option('--sql', 'Include database')
|
|
977
|
+
.option('-y, --yes', 'Skip confirmation')
|
|
978
|
+
.action(async (site, cmdOptions) => {
|
|
979
|
+
await runSiteCommand(site, { action: 'Pushing to WP Engine', successMessage: (data) => data.pushToWpe.message || 'Pushed to WP Engine' }, async (gql, siteId) => {
|
|
980
|
+
// Get remote install ID if not provided
|
|
981
|
+
let remoteInstallId = cmdOptions.remote;
|
|
982
|
+
if (!remoteInstallId) {
|
|
983
|
+
const linkData = await gql.query(`
|
|
984
|
+
query($siteId: ID!) {
|
|
985
|
+
getWpeLink(siteId: $siteId) {
|
|
986
|
+
connections { remoteInstallId }
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
`, { siteId });
|
|
990
|
+
if (linkData.getWpeLink.connections.length === 0) {
|
|
991
|
+
throw new Error('Site is not linked to WP Engine. Use --remote to specify install ID.');
|
|
992
|
+
}
|
|
993
|
+
remoteInstallId = linkData.getWpeLink.connections[0].remoteInstallId;
|
|
994
|
+
}
|
|
995
|
+
const data = await gql.mutate(`
|
|
996
|
+
mutation($localSiteId: ID!, $remoteInstallId: ID!, $includeSql: Boolean, $confirm: Boolean) {
|
|
997
|
+
pushToWpe(localSiteId: $localSiteId, remoteInstallId: $remoteInstallId, includeSql: $includeSql, confirm: $confirm) {
|
|
998
|
+
success message error
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
`, { localSiteId: siteId, remoteInstallId, includeSql: cmdOptions.sql || false, confirm: cmdOptions.yes || false });
|
|
1002
|
+
if (!data.pushToWpe.success) {
|
|
1003
|
+
throw new Error(data.pushToWpe.error || 'Failed to push to WP Engine');
|
|
1004
|
+
}
|
|
1005
|
+
return data;
|
|
1006
|
+
});
|
|
1007
|
+
});
|
|
1008
|
+
wpe
|
|
1009
|
+
.command('pull <site>')
|
|
1010
|
+
.description('Pull from WP Engine to local site')
|
|
1011
|
+
.option('-r, --remote <installId>', 'Remote install ID')
|
|
1012
|
+
.option('--sql', 'Include database')
|
|
1013
|
+
.action(async (site, cmdOptions) => {
|
|
1014
|
+
await runSiteCommand(site, { action: 'Pulling from WP Engine for', successMessage: (data) => data.pullFromWpe.message || 'Pulled from WP Engine' }, async (gql, siteId) => {
|
|
1015
|
+
// Get remote install ID if not provided
|
|
1016
|
+
let remoteInstallId = cmdOptions.remote;
|
|
1017
|
+
if (!remoteInstallId) {
|
|
1018
|
+
const linkData = await gql.query(`
|
|
1019
|
+
query($siteId: ID!) {
|
|
1020
|
+
getWpeLink(siteId: $siteId) {
|
|
1021
|
+
connections { remoteInstallId }
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
`, { siteId });
|
|
1025
|
+
if (linkData.getWpeLink.connections.length === 0) {
|
|
1026
|
+
throw new Error('Site is not linked to WP Engine. Use --remote to specify install ID.');
|
|
1027
|
+
}
|
|
1028
|
+
remoteInstallId = linkData.getWpeLink.connections[0].remoteInstallId;
|
|
1029
|
+
}
|
|
1030
|
+
const data = await gql.mutate(`
|
|
1031
|
+
mutation($localSiteId: ID!, $remoteInstallId: ID!, $includeSql: Boolean) {
|
|
1032
|
+
pullFromWpe(localSiteId: $localSiteId, remoteInstallId: $remoteInstallId, includeSql: $includeSql) {
|
|
1033
|
+
success message error
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
`, { localSiteId: siteId, remoteInstallId, includeSql: cmdOptions.sql || false });
|
|
1037
|
+
if (!data.pullFromWpe.success) {
|
|
1038
|
+
throw new Error(data.pullFromWpe.error || 'Failed to pull from WP Engine');
|
|
1039
|
+
}
|
|
1040
|
+
return data;
|
|
1041
|
+
});
|
|
1042
|
+
});
|
|
1043
|
+
wpe
|
|
1044
|
+
.command('history <site>')
|
|
1045
|
+
.description('Show sync history for a site')
|
|
1046
|
+
.option('-l, --limit <n>', 'Number of events to show', '10')
|
|
1047
|
+
.action(async (site, cmdOptions) => {
|
|
1048
|
+
const globalOpts = program.opts();
|
|
1049
|
+
const format = (0, formatters_1.getOutputFormat)(globalOpts);
|
|
1050
|
+
try {
|
|
1051
|
+
const gql = await ensureConnected(globalOpts);
|
|
1052
|
+
const siteId = await findSiteId(gql, site);
|
|
1053
|
+
const data = await gql.query(`
|
|
1054
|
+
query($siteId: ID!, $limit: Int) {
|
|
1055
|
+
getSyncHistory(siteId: $siteId, limit: $limit) {
|
|
1056
|
+
success
|
|
1057
|
+
events { remoteInstallName timestamp direction status }
|
|
1058
|
+
error
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
`, { siteId, limit: parseInt(cmdOptions.limit, 10) });
|
|
1062
|
+
if (!data.getSyncHistory.success) {
|
|
1063
|
+
console.error((0, formatters_1.formatError)(data.getSyncHistory.error || 'Failed to get sync history'));
|
|
1064
|
+
process.exit(1);
|
|
1065
|
+
}
|
|
1066
|
+
if (format === 'json') {
|
|
1067
|
+
console.log(JSON.stringify(data.getSyncHistory.events, null, 2));
|
|
1068
|
+
}
|
|
1069
|
+
else if (data.getSyncHistory.events.length === 0) {
|
|
1070
|
+
console.log('No sync history found.');
|
|
1071
|
+
}
|
|
1072
|
+
else {
|
|
1073
|
+
console.log('\nSync History:');
|
|
1074
|
+
for (const event of data.getSyncHistory.events) {
|
|
1075
|
+
const date = new Date(event.timestamp).toLocaleString();
|
|
1076
|
+
const arrow = event.direction === 'push' ? '→' : '←';
|
|
1077
|
+
console.log(` ${date} ${arrow} ${event.remoteInstallName} (${event.status})`);
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
catch (error) {
|
|
1082
|
+
console.error((0, formatters_1.formatError)(error.message));
|
|
1083
|
+
process.exit(1);
|
|
1084
|
+
}
|
|
1085
|
+
});
|
|
1086
|
+
wpe
|
|
1087
|
+
.command('diff <site>')
|
|
1088
|
+
.description('Show file changes between local and WP Engine')
|
|
1089
|
+
.option('-d, --direction <dir>', 'Direction (push|pull)', 'push')
|
|
1090
|
+
.action(async (site, cmdOptions) => {
|
|
1091
|
+
const globalOpts = program.opts();
|
|
1092
|
+
const format = (0, formatters_1.getOutputFormat)(globalOpts);
|
|
1093
|
+
try {
|
|
1094
|
+
const gql = await ensureConnected(globalOpts);
|
|
1095
|
+
const siteId = await findSiteId(gql, site);
|
|
1096
|
+
const data = await gql.query(`
|
|
1097
|
+
query($siteId: ID!, $direction: String) {
|
|
1098
|
+
getSiteChanges(siteId: $siteId, direction: $direction) {
|
|
1099
|
+
success
|
|
1100
|
+
added { path }
|
|
1101
|
+
modified { path }
|
|
1102
|
+
deleted { path }
|
|
1103
|
+
totalChanges
|
|
1104
|
+
error
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
`, { siteId, direction: cmdOptions.direction });
|
|
1108
|
+
if (!data.getSiteChanges.success) {
|
|
1109
|
+
console.error((0, formatters_1.formatError)(data.getSiteChanges.error || 'Failed to get changes'));
|
|
1110
|
+
process.exit(1);
|
|
1111
|
+
}
|
|
1112
|
+
if (format === 'json') {
|
|
1113
|
+
console.log(JSON.stringify(data.getSiteChanges, null, 2));
|
|
1114
|
+
}
|
|
1115
|
+
else {
|
|
1116
|
+
const changes = data.getSiteChanges;
|
|
1117
|
+
console.log(`\nChanges to ${cmdOptions.direction} (${changes.totalChanges} total):`);
|
|
1118
|
+
if (changes.added.length > 0) {
|
|
1119
|
+
console.log('\n Added:');
|
|
1120
|
+
changes.added.forEach((f) => console.log(` + ${f.path}`));
|
|
1121
|
+
}
|
|
1122
|
+
if (changes.modified.length > 0) {
|
|
1123
|
+
console.log('\n Modified:');
|
|
1124
|
+
changes.modified.forEach((f) => console.log(` ~ ${f.path}`));
|
|
1125
|
+
}
|
|
1126
|
+
if (changes.deleted.length > 0) {
|
|
1127
|
+
console.log('\n Deleted:');
|
|
1128
|
+
changes.deleted.forEach((f) => console.log(` - ${f.path}`));
|
|
1129
|
+
}
|
|
1130
|
+
if (changes.totalChanges === 0) {
|
|
1131
|
+
console.log(' No changes detected.');
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
catch (error) {
|
|
1136
|
+
console.error((0, formatters_1.formatError)(error.message));
|
|
1137
|
+
process.exit(1);
|
|
1138
|
+
}
|
|
1139
|
+
});
|
|
1140
|
+
// ===========================================
|
|
1141
|
+
// Helper Functions
|
|
1142
|
+
// ===========================================
|
|
1143
|
+
/**
|
|
1144
|
+
* Find site ID by name or ID
|
|
1145
|
+
*
|
|
1146
|
+
* Optimization: First tries direct ID lookup (O(1)) before falling back to
|
|
1147
|
+
* fetching all sites for name matching (O(n)). This significantly improves
|
|
1148
|
+
* performance when users specify site IDs directly.
|
|
1149
|
+
*/
|
|
1150
|
+
async function findSiteId(gql, siteQuery) {
|
|
1151
|
+
// Try direct ID lookup first - much faster for exact ID matches
|
|
1152
|
+
try {
|
|
1153
|
+
const directLookup = await gql.query(`query GetSiteById($id: ID!) { site(id: $id) { id } }`, { id: siteQuery });
|
|
1154
|
+
if (directLookup.site) {
|
|
1155
|
+
return directLookup.site.id;
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
catch {
|
|
1159
|
+
// ID lookup failed, fall through to name search
|
|
1160
|
+
}
|
|
1161
|
+
// Fall back to fetching all sites for name matching
|
|
1162
|
+
const data = await gql.query(`
|
|
1163
|
+
query { sites { id name } }
|
|
1164
|
+
`);
|
|
1165
|
+
const site = data.sites.find((s) => s.name.toLowerCase().includes(siteQuery.toLowerCase()));
|
|
1166
|
+
if (!site) {
|
|
1167
|
+
throw new Error(`Site not found: "${siteQuery}"`);
|
|
1168
|
+
}
|
|
1169
|
+
return site.id;
|
|
1170
|
+
}
|
|
1171
|
+
// Parse and execute
|
|
1172
|
+
program.parse();
|
|
1173
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFFQTs7Ozs7R0FLRzs7Ozs7QUFFSCx5Q0FBb0M7QUFDcEMsOENBQXNCO0FBQ3RCLDJDQUF3RDtBQUN4RCxxQ0FBeUM7QUFDekMsNkNBUXNCO0FBRXRCLE1BQU0sT0FBTyxHQUFHLElBQUksbUJBQU8sRUFBRSxDQUFDO0FBRTlCLHdDQUF3QztBQUN4QyxJQUFJLE1BQU0sR0FBeUIsSUFBSSxDQUFDO0FBRXhDOztHQUVHO0FBQ0gsS0FBSyxVQUFVLGVBQWUsQ0FBQyxPQUF5QjtJQUN0RCxJQUFJLE1BQU0sRUFBRSxDQUFDO1FBQ1gsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQztJQUVELE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBQSxhQUFHLEVBQUMsd0JBQXdCLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUU3RSxJQUFJLENBQUM7UUFDSCxNQUFNLE1BQU0sR0FBRyxNQUFNLElBQUEscUJBQVMsRUFBQztZQUM3QixPQUFPLEVBQUUsS0FBSztZQUNkLFFBQVEsRUFBRSxDQUFDLE1BQU0sRUFBRSxFQUFFO2dCQUNuQixJQUFJLE9BQU87b0JBQUUsT0FBTyxDQUFDLElBQUksR0FBRyxNQUFNLENBQUM7WUFDckMsQ0FBQztTQUNGLENBQUMsQ0FBQztRQUVILElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQzlDLE9BQU8sRUFBRSxJQUFJLENBQUMsbUJBQW1CLENBQUMsQ0FBQztZQUNuQyxPQUFPLENBQUMsS0FBSyxDQUFDLElBQUEsd0JBQVcsRUFBQyxNQUFNLENBQUMsS0FBSyxJQUFJLGVBQWUsQ0FBQyxDQUFDLENBQUM7WUFDNUQsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFD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SSxLQUFLLENBQUMsb0JBQW9CLFNBQVMsR0FBRyxDQUFDLENBQUM7SUFDcEQsQ0FBQztJQUVELE9BQU8sSUFBSSxDQUFDLEVBQUUsQ0FBQztBQUNqQixDQUFDO0FBRUQsb0JBQW9CO0FBQ3BCLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIiMhL3Vzci9iaW4vZW52IG5vZGVcblxuLyoqXG4gKiBMb2NhbCBDTEkgKGx3cClcbiAqXG4gKiBDb21tYW5kLWxpbmUgaW50ZXJmYWNlIGZvciBtYW5hZ2luZyBMb2NhbCBXb3JkUHJlc3Mgc2l0ZXMuXG4gKiBDb25uZWN0cyBkaXJlY3RseSB0byBMb2NhbCdzIEdyYXBoUUwgc2VydmVyLlxuICovXG5cbmltcG9ydCB7IENvbW1hbmQgfSBmcm9tICdjb21tYW5kZXInO1xuaW1wb3J0IG9yYSBmcm9tICdvcmEnO1xuaW1wb3J0IHsgYm9vdHN0cmFwLCBDb25uZWN0aW9uSW5mbyB9IGZyb20gJy4vYm9vdHN0cmFwJztcbmltcG9ydCB7IEdyYXBoUUxDbGllbnQgfSBmcm9tICcuL2NsaWVudCc7XG5pbXBvcnQge1xuICBmb3JtYXRTaXRlTGlzdCxcbiAgZm9ybWF0U2l0ZURldGFpbCxcbiAgZm9ybWF0U3VjY2VzcyxcbiAgZm9ybWF0RXJyb3IsXG4gIGdldE91dHB1dEZvcm1hdCxcbiAgRm9ybWF0dGVyT3B0aW9ucyxcbiAgU2l0ZUluZm8sXG59IGZyb20gJy4vZm9ybWF0dGVycyc7XG5cbmNvbnN0IHByb2dyYW0gPSBuZXcgQ29tbWFuZCgpO1xuXG4vLyBTdG9yZSBjbGllbnQgZ2xvYmFsbHkgYWZ0ZXIgYm9vdHN0cmFwXG5sZXQgY2xpZW50OiBHcmFwaFFMQ2xpZW50IHwgbnVsbCA9IG51bGw7XG5cbi8qKlxuICogRW5zdXJlIHdlJ3JlIGNvbm5lY3RlZCB0byBMb2NhbCdzIEdyYXBoUUwgc2VydmVyXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGVuc3VyZUNvbm5lY3RlZChvcHRpb25zOiBGb3JtYXR0ZXJPcHRpb25zKTogUHJvbWlzZTxHcmFwaFFMQ2xpZW50PiB7XG4gIGlmIChjbGllbnQpIHtcbiAgICByZXR1cm4gY2xpZW50O1xuICB9XG5cbiAgY29uc3Qgc3Bpbm5lciA9IG9wdGlvbnMucXVpZXQgPyBudWxsIDogb3JhKCdDb25uZWN0aW5nIHRvIExvY2FsLi4uJykuc3RhcnQoKTtcblxuICB0cnkge1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGJvb3RzdHJhcCh7XG4gICAgICB2ZXJib3NlOiBmYWxzZSxcbiAgICAgIG9uU3RhdHVzOiAoc3RhdHVzKSA9PiB7XG4gICAgICAgIGlmIChzcGlubmVyKSBzcGlubmVyLnRleHQgPSBzdGF0dXM7XG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgaWYgKCFyZXN1bHQuc3VjY2VzcyB8fCAhcmVzdWx0LmNvbm5lY3Rpb25JbmZvKSB7XG4gICAgICBzcGlubmVyPy5mYWlsKCdGYWlsZWQgdG8gY29ubmVjdCcpO1xuICAgICAgY29uc29sZS5lcnJvcihmb3JtYXRFcnJvcihyZXN1bHQuZXJyb3IgfHwgJ1Vua25vd24gZXJyb3InKSk7XG4gICAgICBwcm9jZXNzLmV4aXQoMSk7XG4gICAgfVxuXG4gICAgc3Bpbm5lcj8uc3VjY2VlZCgnQ29ubmVjdGVkIHRvIExvY2FsJyk7XG4gICAgY2xpZW50ID0gbmV3IEdyYXBoUUxDbGllbnQocmVzdWx0LmNvbm5lY3Rpb25JbmZvKTtcbiAgICByZXR1cm4gY2xpZW50O1xuICB9IGNhdGNoIChlcnJvcjogYW55KSB7XG4gICAgc3Bpbm5lcj8uZmFpbCgnRmFpbGVkIHRvIGNvbm5lY3QnKTtcbiAgICBjb25zb2xlLmVycm9yKGZvcm1hdEVycm9yKGVycm9yLm1lc3NhZ2UpKTtcbiAgICBwcm9jZXNzLmV4aXQoMSk7XG4gIH1cbn1cblxuLyoqXG4gKiBIZWxwZXIgdG8gcnVuIHNpdGUtc3BlY2lmaWMgY29tbWFuZHMgd2l0aCBjb21tb24gYm9pbGVycGxhdGVcbiAqXG4gKiBIYW5kbGVzOiBjb25uZWN0aW9uLCBzcGlubmVyLCBzaXRlIGxvb2t1cCwgZXJyb3IgZm9ybWF0dGluZ1xuICovXG5hc3luYyBmdW5jdGlvbiBydW5TaXRlQ29tbWFuZDxUPihcbiAgc2l0ZU5hbWU6IHN0cmluZyxcbiAgY29uZmlnOiB7XG4gICAgYWN0aW9uOiBzdHJpbmc7XG4gICAgc3VjY2Vzc01lc3NhZ2U/OiAocmVzdWx0OiBUKSA9PiBzdHJpbmc7XG4gIH0sXG4gIGV4ZWN1dGU6IChncWw6IEdyYXBoUUxDbGllbnQsIHNpdGVJZDogc3RyaW5nKSA9PiBQcm9taXNlPFQ+XG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgZ2xvYmFsT3B0cyA9IHByb2dyYW0ub3B0cygpIGFzIEZvcm1hdHRlck9wdGlvbnM7XG4gIGNvbnN0IHNwaW5uZXIgPSBnbG9iYWxPcHRzLnF1aWV0ID8gbnVsbCA6IG9yYShgJHtjb25maWcuYWN0aW9ufSBcIiR7c2l0ZU5hbWV9XCIuLi5gKS5zdGFydCgpO1xuXG4gIHRyeSB7XG4gICAgY29uc3QgZ3FsID0gYXdhaXQgZW5zdXJlQ29ubmVjdGVkKGdsb2JhbE9wdHMpO1xuICAgIGNvbnN0IHNpdGVJZCA9IGF3YWl0IGZpbmRTaXRlSWQoZ3FsLCBzaXRlTmFtZSk7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgZXhlY3V0ZShncWwsIHNpdGVJZCk7XG5cbiAgICBjb25zdCBtZXNzYWdlID0gY29uZmlnLnN1Y2Nlc3NNZXNzYWdlXG4gICAgICA/IGNvbmZpZy5zdWNjZXNzTWVzc2FnZShyZXN1bHQpXG4gICAgICA6IGAke2NvbmZpZy5hY3Rpb259IFwiJHtzaXRlTmFtZX1cIiBjb21wbGV0ZWRgO1xuICAgIHNwaW5uZXI/LnN1Y2NlZWQobWVzc2FnZSk7XG4gIH0gY2F0Y2ggKGVycm9yOiBhbnkpIHtcbiAgICBzcGlubmVyPy5mYWlsKGBGYWlsZWQgdG8gJHtjb25maWcuYWN0aW9uLnRvTG93ZXJDYXNlKCl9IFwiJHtzaXRlTmFtZX1cImApO1xuICAgIGNvbnNvbGUuZXJyb3IoZm9ybWF0RXJyb3IoZXJyb3IubWVzc2FnZSkpO1xuICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgfVxufVxuXG5wcm9ncmFtXG4gIC5uYW1lKCdsd3AnKVxuICAuZGVzY3JpcHRpb24oJ0NvbW1hbmQtbGluZSBpbnRlcmZhY2UgZm9yIExvY2FsIFdvcmRQcmVzcyBkZXZlbG9wbWVudCcpXG4gIC52ZXJzaW9uKCcwLjEuMCcpO1xuXG4vLyBHbG9iYWwgb3B0aW9uc1xucHJvZ3JhbVxuICAub3B0aW9uKCctLWpzb24nLCAnT3V0cHV0IHJlc3VsdHMgYXMgSlNPTicpXG4gIC5vcHRpb24oJy0tcXVpZXQnLCAnTWluaW1hbCBvdXRwdXQgKElEcy9uYW1lcyBvbmx5KScpXG4gIC5vcHRpb24oJy0tbm8tY29sb3InLCAnRGlzYWJsZSBjb2xvcmVkIG91dHB1dCcpO1xuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBTaXRlcyBDb21tYW5kc1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5jb25zdCBzaXRlcyA9IHByb2dyYW0uY29tbWFuZCgnc2l0ZXMnKS5kZXNjcmlwdGlvbignTWFuYWdlIFdvcmRQcmVzcyBzaXRlcycpO1xuXG5zaXRlc1xuICAuY29tbWFuZCgnbGlzdCcpXG4gIC5kZXNjcmlwdGlvbignTGlzdCBhbGwgV29yZFByZXNzIHNpdGVzJylcbiAgLm9wdGlvbignLS1zdGF0dXMgPHN0YXR1cz4nLCAnRmlsdGVyIGJ5IHN0YXR1cyAocnVubmluZ3xzdG9wcGVkfGFsbCknLCAnYWxsJylcbiAgLmFjdGlvbihhc3luYyAoY21kT3B0aW9ucykgPT4ge1xuICAgIGNvbnN0IGdsb2JhbE9wdHMgPSBwcm9ncmFtLm9wdHMoKSBhcyBGb3JtYXR0ZXJPcHRpb25zO1xuICAgIGNvbnN0IGZvcm1hdCA9IGdldE91dHB1dEZvcm1hdChnbG9iYWxPcHRzKTtcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCBncWwgPSBhd2FpdCBlbnN1cmVDb25uZWN0ZWQoZ2xvYmFsT3B0cyk7XG4gICAgICBjb25zdCBkYXRhID0gYXdhaXQgZ3FsLnF1ZXJ5PHsgc2l0ZXM6IEFycmF5PHsgaWQ6IHN0cmluZzsgbmFtZTogc3RyaW5nOyBkb21haW46IHN0cmluZzsgc3RhdHVzOiBzdHJpbmc7IHBhdGg6IHN0cmluZyB9PiB9PihgXG4gICAgICAgIHF1ZXJ5IHtcbiAgICAgICAgICBzaXRlcyB7XG4gICAgICAgICAgICBpZFxuICAgICAgICAgICAgbmFtZVxuICAgICAgICAgICAgZG9tYWluXG4gICAgICAgICAgICBzdGF0dXNcbiAgICAgICAgICAgIHBhdGhcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIGApO1xuXG4gICAgICBsZXQgc2l0ZXNUb1Nob3cgPSBkYXRhLnNpdGVzLm1hcCgocykgPT4gKHtcbiAgICAgICAgaWQ6IHMuaWQsXG4gICAgICAgIG5hbWU6IHMubmFtZSxcbiAgICAgICAgZG9tYWluOiBzLmRvbWFpbixcbiAgICAgICAgc3RhdHVzOiBzLnN0YXR1cy50b0xvd2VyQ2FzZSgpLFxuICAgICAgICBwYXRoOiBzLnBhdGgsXG4gICAgICB9KSk7XG5cbiAgICAgIC8vIEZpbHRlciBieSBzdGF0dXMgaWYgc3BlY2lmaWVkXG4gICAgICBpZiAoY21kT3B0aW9ucy5zdGF0dXMgIT09ICdhbGwnKSB7XG4gICAgICAgIHNpdGVzVG9TaG93ID0gc2l0ZXNUb1Nob3cuZmlsdGVyKChzKSA9PiBzLnN0YXR1cyA9PT0gY21kT3B0aW9ucy5zdGF0dXMpO1xuICAgICAgfVxuXG4gICAgICBjb25zb2xlLmxvZyhmb3JtYXRTaXRlTGlzdChzaXRlc1RvU2hvdywgZm9ybWF0LCB7IG5vQ29sb3I6IGdsb2JhbE9wdHMubm9Db2xvciB9KSk7XG4gICAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgICAgY29uc29sZS5lcnJvcihmb3JtYXRFcnJvcihlcnJvci5tZXNzYWdlKSk7XG4gICAgICBwcm9jZXNzLmV4aXQoMSk7XG4gICAgfVxuICB9KTtcblxuc2l0ZXNcbiAgLmNvbW1hbmQoJ2dldCA8c2l0ZT4nKVxuICAuZGVzY3JpcHRpb24oJ0dldCBkZXRhaWxlZCBpbmZvIGFib3V0IGEgc2l0ZScpXG4gIC5hY3Rpb24oYXN5bmMgKHNpdGUpID0+IHtcbiAgICBjb25zdCBnbG9iYWxPcHRzID0gcHJvZ3JhbS5vcHRzKCkgYXMgRm9ybWF0dGVyT3B0aW9ucztcbiAgICBjb25zdCBmb3JtYXQgPSBnZXRPdXRwdXRGb3JtYXQoZ2xvYmFsT3B0cyk7XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgZ3FsID0gYXdhaXQgZW5zdXJlQ29ubmVjdGVkKGdsb2JhbE9wdHMpO1xuXG4gICAgICAvLyBGaXJzdCBmaW5kIHRoZSBzaXRlIGJ5IG5hbWUgb3IgSURcbiAgICAgIGNvbnN0IHNpdGVzRGF0YSA9IGF3YWl0IGdxbC5xdWVyeTx7IHNpdGVzOiBBcnJheTx7IGlkOiBzdHJpbmc7IG5hbWU6IHN0cmluZyB9PiB9PihgXG4gICAgICAgIHF1ZXJ5IHsgc2l0ZXMgeyBpZCBuYW1lIH0gfVxuICAgICAgYCk7XG5cbiAgICAgIGNvbnN0IGZvdW5kU2l0ZSA9IHNpdGVzRGF0YS5zaXRlcy5maW5kKFxuICAgICAgICAocykgPT4gcy5pZCA9PT0gc2l0ZSB8fCBzLm5hbWUudG9Mb3dlckNhc2UoKS5pbmNsdWRlcyhzaXRlLnRvTG93ZXJDYXNlKCkpXG4gICAgICApO1xuXG4gICAgICBpZiAoIWZvdW5kU2l0ZSkge1xuICAgICAgICBjb25zb2xlLmVycm9yKGZvcm1hdEVycm9yKGBTaXRlIG5vdCBmb3VuZDogXCIke3NpdGV9XCJgKSk7XG4gICAgICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZGF0YSA9IGF3YWl0IGdxbC5xdWVyeTx7IHNpdGU6IGFueSB9PihgXG4gICAgICAgIHF1ZXJ5KCRpZDogSUQhKSB7XG4gICAgICAgICAgc2l0ZShpZDogJGlkKSB7XG4gICAgICAgICAgICBpZFxuICAgICAgICAgICAgbmFtZVxuICAgICAgICAgICAgZG9tYWluXG4gICAgICAgICAgICBzdGF0dXNcbiAgICAgICAgICAgIHBhdGhcbiAgICAgICAgICAgIHVybFxuICAgICAgICAgICAgaG9zdFxuICAgICAgICAgICAgaHR0cFBvcnRcbiAgICAgICAgICAgIHhkZWJ1Z0VuYWJsZWRcbiAgICAgICAgICAgIHNlcnZpY2VzIHtcbiAgICAgICAgICAgICAgbmFtZVxuICAgICAgICAgICAgICB2ZXJzaW9uXG4gICAgICAgICAgICAgIHJvbGVcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGhvc3RDb25uZWN0aW9ucyB7XG4gICAgICAgICAgICAgIGhvc3RJZFxuICAgICAgICAgICAgICByZW1vdGVTaXRlSWRcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIGAsIHsgaWQ6IGZvdW5kU2l0ZS5pZCB9KTtcblxuICAgICAgY29uc29sZS5sb2coZm9ybWF0U2l0ZURldGFpbChkYXRhLnNpdGUsIGZvcm1hdCwgeyBub0NvbG9yOiBnbG9iYWxPcHRzLm5vQ29sb3IgfSkpO1xuICAgIH0gY2F0Y2ggKGVycm9yOiBhbnkpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoZm9ybWF0RXJyb3IoZXJyb3IubWVzc2FnZSkpO1xuICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgIH1cbiAgfSk7XG5cbnNpdGVzXG4gIC5jb21tYW5kKCdzdGFydCA8c2l0ZT4nKVxuICAuZGVzY3JpcHRpb24oJ1N0YXJ0IGEgc2l0ZScpXG4gIC5hY3Rpb24oYXN5bmMgKHNpdGUpID0+IHtcbiAgICBhd2FpdCBydW5TaXRlQ29tbWFuZChzaXRlLCB7IGFjdGlvbjogJ1N0YXJ0aW5nJywgc3VjY2Vzc01lc3NhZ2U6ICgpID0+IGBTdGFydGVkIFwiJHtzaXRlfVwiYCB9LCBhc3luYyAoZ3FsLCBzaXRlSWQpID0+IHtcbiAgICAgIHJldHVybiBncWwubXV0YXRlKGBtdXRhdGlvbigkaWQ6IElEISkgeyBzdGFydFNpdGUoaWQ6ICRpZCkgeyBpZCBzdGF0dXMgfSB9YCwgeyBpZDogc2l0ZUlkIH0pO1xuICAgIH0pO1xuICB9KTtcblxuc2l0ZXNcbiAgLmNvbW1hbmQoJ3N0b3AgPHNpdGU+JylcbiAgLmRlc2NyaXB0aW9uKCdTdG9wIGEgc2l0ZScpXG4gIC5hY3Rpb24oYXN5bmMgKHNpdGUpID0+IHtcbiAgICBhd2FpdCBydW5TaXRlQ29tbWFuZChzaXRlLCB7IGFjdGlvbjogJ1N0b3BwaW5nJywgc3VjY2Vzc01lc3NhZ2U6ICgpID0+IGBTdG9wcGVkIFwiJHtzaXRlfVwiYCB9LCBhc3luYyAoZ3FsLCBzaXRlSWQpID0+IHtcbiAgICAgIHJldHVybiBncWwubXV0YXRlKGBtdXRhdGlvbigkaWQ6IElEISkgeyBzdG9wU2l0ZShpZDogJGlkKSB7IGlkIHN0YXR1cyB9IH1gLCB7IGlkOiBzaXRlSWQgfSk7XG4gICAgfSk7XG4gIH0pO1xuXG5zaXRlc1xuICAuY29tbWFuZCgncmVzdGFydCA8c2l0ZT4nKVxuICAuZGVzY3JpcHRpb24oJ1Jlc3RhcnQgYSBzaXRlJylcbiAgLmFjdGlvbihhc3luYyAoc2l0ZSkgPT4ge1xuICAgIGF3YWl0IHJ1blNpdGVDb21tYW5kKHNpdGUsIHsgYWN0aW9uOiAnUmVzdGFydGluZycsIHN1Y2Nlc3NNZXNzYWdlOiAoKSA9PiBgUmVzdGFydGVkIFwiJHtzaXRlfVwiYCB9LCBhc3luYyAoZ3FsLCBzaXRlSWQpID0+IHtcbiAgICAgIHJldHVybiBncWwubXV0YXRlKGBtdXRhdGlvbigkaWQ6IElEISkgeyByZXN0YXJ0U2l0ZShpZDogJGlkKSB7IGlkIHN0YXR1cyB9IH1gLCB7IGlkOiBzaXRlSWQgfSk7XG4gICAgfSk7XG4gIH0pO1xuXG5zaXRlc1xuICAuY29tbWFuZCgnb3BlbiA8c2l0ZT4nKVxuICAuZGVzY3JpcHRpb24oJ09wZW4gc2l0ZSBpbiBicm93c2VyJylcbiAgLm9wdGlvbignLS1hZG1pbicsICdPcGVuIFdQIEFkbWluIGluc3RlYWQgb2YgZnJvbnRlbmQnKVxuICAuYWN0aW9uKGFzeW5jIChzaXRlLCBjbWRPcHRpb25zKSA9PiB7XG4gICAgYXdhaXQgcnVuU2l0ZUNvbW1hbmQoc2l0ZSwgeyBhY3Rpb246ICdPcGVuaW5nJywgc3VjY2Vzc01lc3NhZ2U6ICgpID0+IGBPcGVuZWQgXCIke3NpdGV9XCJgIH0sIGFzeW5jIChncWwsIHNpdGVJZCkgPT4ge1xuICAgICAgcmV0dXJuIGdxbC5tdXRhdGUoYFxuICAgICAgICBtdXRhdGlvbigkaW5wdXQ6IE9wZW5TaXRlSW5wdXQhKSB7XG4gICAgICAgICAgb3BlblNpdGUoaW5wdXQ6ICRpbnB1dCkgeyBzdWNjZXNzIGVycm9yIH1cbiAgICAgICAgfVxuICAgICAgYCwgeyBpbnB1dDogeyBzaXRlSWQsIG9wZW5BZG1pbjogY21kT3B0aW9ucy5hZG1pbiB8fCBmYWxzZSB9IH0pO1xuICAgIH0pO1xuICB9KTtcblxuc2l0ZXNcbiAgLmNvbW1hbmQoJ2NyZWF0ZSA8bmFtZT4nKVxuICAuZGVzY3JpcHRpb24oJ0NyZWF0ZSBhIG5ldyBXb3JkUHJlc3Mgc2l0ZScpXG4gIC5vcHRpb24oJy0tcGhwIDx2ZXJzaW9uPicsICdQSFAgdmVyc2lvbiAoZS5nLiwgOC4yLjEwKScpXG4gIC5vcHRpb24oJy0td2ViIDxzZXJ2ZXI+JywgJ1dlYiBzZXJ2ZXIgKG5naW54fGFwYWNoZSknKVxuICAub3B0aW9uKCctLWRiIDxkYXRhYmFzZT4nLCAnRGF0YWJhc2UgKG15c3FsfG1hcmlhZGIpJylcbiAgLm9wdGlvbignLS1ibHVlcHJpbnQgPG5hbWU+JywgJ1VzZSBhIGJsdWVwcmludCcpXG4gIC5vcHRpb24oJy0td3AtdXNlciA8dXNlcm5hbWU+JywgJ1dvcmRQcmVzcyBhZG1pbiB1c2VybmFtZScsICdhZG1pbicpXG4gIC5vcHRpb24oJy0td3AtZW1haWwgPGVtYWlsPicsICdXb3JkUHJlc3MgYWRtaW4gZW1haWwnKVxuICAuYWN0aW9uKGFzeW5jIChuYW1lLCBjbWRPcHRpb25zKSA9PiB7XG4gICAgY29uc3QgZ2xvYmFsT3B0cyA9IHByb2dyYW0ub3B0cygpIGFzIEZvcm1hdHRlck9wdGlvbnM7XG4gICAgY29uc3Qgc3Bpbm5lciA9IGdsb2JhbE9wdHMucXVpZXQgPyBudWxsIDogb3JhKGBDcmVhdGluZyBcIiR7bmFtZX1cIi4uLmApLnN0YXJ0KCk7XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgZ3FsID0gYXdhaXQgZW5zdXJlQ29ubmVjdGVkKGdsb2JhbE9wdHMpO1xuXG4gICAgICBjb25zdCBpbnB1dDogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7IG5hbWUgfTtcbiAgICAgIGlmIChjbWRPcHRpb25zLnBocCkgaW5wdXQucGhwVmVyc2lvbiA9IGNtZE9wdGlvbnMucGhwO1xuICAgICAgaWYgKGNtZE9wdGlvbnMud2ViKSBpbnB1dC53ZWJTZXJ2ZXIgPSBjbWRPcHRpb25zLndlYjtcbiAgICAgIGlmIChjbWRPcHRpb25zLmRiKSBpbnB1dC5kYXRhYmFzZSA9IGNtZE9wdGlvbnMuZGI7XG4gICAgICBpZiAoY21kT3B0aW9ucy5ibHVlcHJpbnQpIGlucHV0LmJsdWVwcmludCA9IGNtZE9wdGlvbnMuYmx1ZXByaW50O1xuICAgICAgaWYgKGNtZE9wdGlvbnMud3BVc2VyKSBpbnB1dC53cEFkbWluVXNlcm5hbWUgPSBjbWRPcHRpb25zLndwVXNlcjtcbiAgICAgIGlmIChjbWRPcHRpb25zLndwRW1haWwpIGlucHV0LndwQWRtaW5FbWFpbCA9IGNtZE9wdGlvbnMud3BFbWFpbDtcblxuICAgICAgY29uc3QgZGF0YSA9IGF3YWl0IGdxbC5tdXRhdGU8eyBjcmVhdGVTaXRlOiB7IHN1Y2Nlc3M6IGJvb2xlYW47IHNpdGVJZDogc3RyaW5nOyBzaXRlTmFtZTogc3RyaW5nOyBlcnJvcjogc3RyaW5nIHwgbnVsbCB9IH0+KGBcbiAgICAgICAgbXV0YXRpb24oJGlucHV0OiBDcmVhdGVTaXRlSW5wdXQhKSB7XG4gICAgICAgICAgY3JlYXRlU2l0ZShpbnB1dDogJGlucHV0KSB7IHN1Y2Nlc3Mgc2l0ZUlkIHNpdGVOYW1lIGVycm9yIH1cbiAgICAgICAgfVxuICAgICAgYCwgeyBpbnB1dCB9KTtcblxuICAgICAgaWYgKCFkYXRhLmNyZWF0ZVNpdGUuc3VjY2Vzcykge1xuICAgICAgICBzcGlubmVyPy5mYWlsKCdDcmVhdGUgZmFpbGVkJyk7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoZm9ybWF0RXJyb3IoZGF0YS5jcmVhdGVTaXRlLmVycm9yIHx8ICdGYWlsZWQgdG8gY3JlYXRlIHNpdGUnKSk7XG4gICAgICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgICAgIH1cblxuICAgICAgc3Bpbm5lcj8uc3VjY2VlZChgQ3JlYXRlZCBcIiR7ZGF0YS5jcmVhdGVTaXRlLnNpdGVOYW1lfVwiICgke2RhdGEuY3JlYXRlU2l0ZS5zaXRlSWR9KWApO1xuICAgIH0gY2F0Y2ggKGVycm9yOiBhbnkpIHtcbiAgICAgIHNwaW5uZXI/LmZhaWwoJ0NyZWF0ZSBmYWlsZWQnKTtcbiAgICAgIGNvbnNvbGUuZXJyb3IoZm9ybWF0RXJyb3IoZXJyb3IubWVzc2FnZSkpO1xuICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgIH1cbiAgfSk7XG5cbnNpdGVzXG4gIC5jb21tYW5kKCdkZWxldGUgPHNpdGU+JylcbiAgLmRlc2NyaXB0aW9uKCdEZWxldGUgYSBzaXRlJylcbiAgLm9wdGlvbignLXksIC0teWVzJywgJ1NraXAgY29uZmlybWF0aW9uJylcbiAgLm9wdGlvbignLS1rZWVwLWZpbGVzJywgJ0tlZXAgc2l0ZSBmaWxlcyAob25seSByZW1vdmUgZnJvbSBMb2NhbCknKVxuICAuYWN0aW9uKGFzeW5jIChzaXRlLCBjbWRPcHRpb25zKSA9PiB7XG4gICAgYXdhaXQgcnVuU2l0ZUNvbW1hbmQoc2l0ZSwgeyBhY3Rpb246ICdEZWxldGluZycsIHN1Y2Nlc3NNZXNzYWdlOiAoKSA9PiBgRGVsZXRlZCBcIiR7c2l0ZX1cImAgfSwgYXN5bmMgKGdxbCwgc2l0ZUlkKSA9PiB7XG4gICAgICBjb25zdCBkYXRhID0gYXdhaXQgZ3FsLm11dGF0ZTx7IGRlbGV0ZVNpdGU6IHsgc3VjY2VzczogYm9vbGVhbjsgZXJyb3I6IHN0cmluZyB8IG51bGwgfSB9PihgXG4gICAgICAgIG11dGF0aW9uKCRpbnB1dDogRGVsZXRlU2l0ZUlucHV0ISkge1xuICAgICAgICAgIGRlbGV0ZVNpdGUoaW5wdXQ6ICRpbnB1dCkgeyBzdWNjZXNzIGVycm9yIH1cbiAgICAgICAgfVxuICAgICAgYCwgeyBpbnB1dDogeyBpZDogc2l0ZUlkLCB0cmFzaEZpbGVzOiAhY21kT3B0aW9ucy5rZWVwRmlsZXMgfSB9KTtcbiAgICAgIGlmICghZGF0YS5kZWxldGVTaXRlLnN1Y2Nlc3MpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGRhdGEuZGVsZXRlU2l0ZS5lcnJvciB8fCAnRmFpbGVkIHRvIGRlbGV0ZSBzaXRlJyk7XG4gICAgICB9XG4gICAgICByZXR1cm4gZGF0YTtcbiAgICB9KTtcbiAgfSk7XG5cbnNpdGVzXG4gIC5jb21tYW5kKCdjbG9uZSA8c2l0ZT4gPG5ld05hbWU+JylcbiAgLmRlc2NyaXB0aW9uKCdDbG9uZSBhIHNpdGUnKVxuICAuYWN0aW9uKGFzeW5jIChzaXRlLCBuZXdOYW1lKSA9PiB7XG4gICAgYXdhaXQgcnVuU2l0ZUNvbW1hbmQoc2l0ZSwgeyBhY3Rpb246IGBDbG9uaW5nYCwgc3VjY2Vzc01lc3NhZ2U6IChkYXRhOiB7IGNsb25lU2l0ZTogeyBuZXdTaXRlTmFtZTogc3RyaW5nOyBuZXdTaXRlSWQ6IHN0cmluZyB9IH0pID0+IGBDbG9uZWQgdG8gXCIke2RhdGEuY2xvbmVTaXRlLm5ld1NpdGVOYW1lfVwiICgke2RhdGEuY2xvbmVTaXRlLm5ld1NpdGVJZH0pYCB9LCBhc3luYyAoZ3FsLCBzaXRlSWQpID0+IHtcbiAgICAgIGNvbnN0IGRhdGEgPSBhd2FpdCBncWwubXV0YXRlPHsgY2xvbmVTaXRlOiB7IHN1Y2Nlc3M6IGJvb2xlYW47IG5ld1NpdGVJZDogc3RyaW5nOyBuZXdTaXRlTmFtZTogc3RyaW5nOyBlcnJvcjogc3RyaW5nIHwgbnVsbCB9IH0+KGBcbiAgICAgICAgbXV0YXRpb24oJGlucHV0OiBDbG9uZVNpdGVJbnB1dCEpIHtcbiAgICAgICAgICBjbG9uZVNpdGUoaW5wdXQ6ICRpbnB1dCkgeyBzdWNjZXNzIG5ld1NpdGVJZCBuZXdTaXRlTmFtZSBlcnJvciB9XG4gICAgICAgIH1cbiAgICAgIGAsIHsgaW5wdXQ6IHsgc2l0ZUlkLCBuZXdOYW1lIH0gfSk7XG4gICAgICBpZiAoIWRhdGEuY2xvbmVTaXRlLnN1Y2Nlc3MpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGRhdGEuY2xvbmVTaXRlLmVycm9yIHx8ICdGYWlsZWQgdG8gY2xvbmUgc2l0ZScpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGRhdGE7XG4gICAgfSk7XG4gIH0pO1xuXG5zaXRlc1xuICAuY29tbWFuZCgnZXhwb3J0IDxzaXRlPicpXG4gIC5kZXNjcmlwdGlvbignRXhwb3J0IHNpdGUgdG8gemlwIGZpbGUnKVxuICAub3B0aW9uKCctbywgLS1vdXRwdXQgPHBhdGg+JywgJ091dHB1dCBmaWxlIHBhdGgnKVxuICAuYWN0aW9uKGFzeW5jIChzaXRlLCBjbWRPcHRpb25zKSA9PiB7XG4gICAgYXdhaXQgcnVuU2l0ZUNvbW1hbmQoc2l0ZSwgeyBhY3Rpb246ICdFeHBvcnRpbmcnLCBzdWNjZXNzTWVzc2FnZTogKGRhdGE6IHsgZXhwb3J0U2l0ZTogeyBvdXRwdXRQYXRoOiBzdHJpbmcgfSB9KSA9PiBgRXhwb3J0ZWQgdG8gJHtkYXRhLmV4cG9ydFNpdGUub3V0cHV0UGF0aH1gIH0sIGFzeW5jIChncWwsIHNpdGVJZCkgPT4ge1xuICAgICAgY29uc3QgZGF0YSA9IGF3YWl0IGdxbC5tdXRhdGU8eyBleHBvcnRTaXRlOiB7IHN1Y2Nlc3M6IGJvb2xlYW47IG91dHB1dFBhdGg6IHN0cmluZzsgZXJyb3I6IHN0cmluZyB8IG51bGwgfSB9PihgXG4gICAgICAgIG11dGF0aW9uKCRpbnB1dDogRXhwb3J0U2l0ZUlucHV0ISkge1xuICAgICAgICAgIGV4cG9ydFNpdGUoaW5wdXQ6ICRpbnB1dCkgeyBzdWNjZXNzIG91dHB1dFBhdGggZXJyb3IgfVxuICAgICAgICB9XG4gICAgICBgLCB7IGlucHV0OiB7IHNpdGVJZCwgb3V0cHV0UGF0aDogY21kT3B0aW9ucy5vdXRwdXQgfSB9KTtcbiAgICAgIGlmICghZGF0YS5leHBvcnRTaXRlLnN1Y2Nlc3MpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGRhdGEuZXhwb3J0U2l0ZS5lcnJvciB8fCAnRmFpbGVkIHRvIGV4cG9ydCBzaXRlJyk7XG4gICAgICB9XG4gICAgICByZXR1cm4gZGF0YTtcbiAgICB9KTtcbiAgfSk7XG5cbnNpdGVzXG4gIC5jb21tYW5kKCdpbXBvcnQgPHppcEZpbGU+JylcbiAgLmRlc2NyaXB0aW9uKCdJbXBvcnQgc2l0ZSBmcm9tIHppcCBmaWxlJylcbiAgLm9wdGlvbignLW4sIC0tbmFtZSA8bmFtZT4nLCAnU2l0ZSBuYW1lIChkZWZhdWx0cyB0byB6aXAgZmlsZW5hbWUpJylcbiAgLmFjdGlvbihhc3luYyAoemlwRmlsZSwgY21kT3B0aW9ucykgPT4ge1xuICAgIGNvbnN0IGdsb2JhbE9wdHMgPSBwcm9ncmFtLm9wdHMoKSBhcyBGb3JtYXR0ZXJPcHRpb25zO1xuICAgIGNvbnN0IHNwaW5uZXIgPSBnbG9iYWxPcHRzLnF1aWV0ID8gbnVsbCA6IG9yYShgSW1wb3J0aW5nIHNpdGUuLi5gKS5zdGFydCgpO1xuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGdxbCA9IGF3YWl0IGVuc3VyZUNvbm5lY3RlZChnbG9iYWxPcHRzKTtcblxuICAgICAgY29uc3QgZGF0YSA9IGF3YWl0IGdxbC5tdXRhdGU8eyBpbXBvcnRTaXRlOiB7IHN1Y2Nlc3M6IGJvb2xlYW47IHNpdGVJZDogc3RyaW5nOyBzaXRlTmFtZTogc3RyaW5nOyBlcnJvcjogc3RyaW5nIHwgbnVsbCB9IH0+KGBcbiAgICAgICAgbXV0YXRpb24oJGlucHV0OiBJbXBvcnRTaXRlSW5wdXQhKSB7XG4gICAgICAgICAgaW1wb3J0U2l0ZShpbnB1dDogJGlucHV0KSB7IHN1Y2Nlc3Mgc2l0ZUlkIHNpdGVOYW1lIGVycm9yIH1cbiAgICAgICAgfVxuICAgICAgYCwgeyBpbnB1dDogeyB6aXBQYXRoOiB6aXBGaWxlLCBzaXRlTmFtZTogY21kT3B0aW9ucy5uYW1lIH0gfSk7XG5cbiAgICAgIGlmICghZGF0YS5pbXBvcnRTaXRlLnN1Y2Nlc3MpIHtcbiAgICAgICAgc3Bpbm5lcj8uZmFpbCgnSW1wb3J0IGZhaWxlZCcpO1xuICAgICAgICBjb25zb2xlLmVycm9yKGZvcm1hdEVycm9yKGRhdGEuaW1wb3J0U2l0ZS5lcnJvciB8fCAnRmFpbGVkIHRvIGltcG9ydCBzaXRlJykpO1xuICAgICAgICBwcm9jZXNzLmV4aXQoMSk7XG4gICAgICB9XG5cbiAgICAgIHNwaW5uZXI/LnN1Y2NlZWQoYEltcG9ydGVkIFwiJHtkYXRhLmltcG9ydFNpdGUuc2l0ZU5hbWV9XCIgKCR7ZGF0YS5pbXBvcnRTaXRlLnNpdGVJZH0pYCk7XG4gICAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgICAgc3Bpbm5lcj8uZmFpbCgnSW1wb3J0IGZhaWxlZCcpO1xuICAgICAgY29uc29sZS5lcnJvcihmb3JtYXRFcnJvcihlcnJvci5tZXNzYWdlKSk7XG4gICAgICBwcm9jZXNzLmV4aXQoMSk7XG4gICAgfVxuICB9KTtcblxuc2l0ZXNcbiAgLmNvbW1hbmQoJ3JlbmFtZSA8c2l0ZT4gPG5ld05hbWU+JylcbiAgLmRlc2NyaXB0aW9uKCdSZW5hbWUgYSBzaXRlJylcbiAgLmFjdGlvbihhc3luYyAoc2l0ZSwgbmV3TmFtZSkgPT4ge1xuICAgIGF3YWl0IHJ1blNpdGVDb21tYW5kKHNpdGUsIHsgYWN0aW9uOiAnUmVuYW1pbmcnLCBzdWNjZXNzTWVzc2FnZTogKCkgPT4gYFJlbmFtZWQgdG8gXCIke25ld05hbWV9XCJgIH0sIGFzeW5jIChncWwsIHNpdGVJZCkgPT4ge1xuICAgICAgY29uc3QgZGF0YSA9IGF3YWl0IGdxbC5tdXRhdGU8eyBtY3BSZW5hbWVTaXRlOiB7IHN1Y2Nlc3M6IGJvb2xlYW47IGVycm9yOiBzdHJpbmcgfCBudWxsIH0gfT4oYFxuICAgICAgICBtdXRhdGlvbigkaW5wdXQ6IE1jcFJlbmFtZVNpdGVJbnB1dCEpIHtcbiAgICAgICAgICBtY3BSZW5hbWVTaXRlKGlucHV0OiAkaW5wdXQpIHsgc3VjY2VzcyBlcnJvciB9XG4gICAgICAgIH1cbiAgICAgIGAsIHsgaW5wdXQ6IHsgc2l0ZUlkLCBuZXdOYW1lIH0gfSk7XG4gICAgICBpZiAoIWRhdGEubWNwUmVuYW1lU2l0ZS5zdWNjZXNzKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihkYXRhLm1jcFJlbmFtZVNpdGUuZXJyb3IgfHwgJ0ZhaWxlZCB0byByZW5hbWUgc2l0ZScpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGRhdGE7XG4gICAgfSk7XG4gIH0pO1xuXG5zaXRlc1xuICAuY29tbWFuZCgnc3NsIDxzaXRlPicpXG4gIC5kZXNjcmlwdGlvbignVHJ1c3QgU1NMIGNlcnRpZmljYXRlIGZvciBhIHNpdGUnKVxuICAuYWN0aW9uKGFzeW5jIChzaXRlKSA9PiB7XG4gICAgYXdhaXQgcnVuU2l0ZUNvbW1hbmQoc2l0ZSwgeyBhY3Rpb246ICdUcnVzdGluZyBTU0wgZm9yJywgc3VjY2Vzc01lc3NhZ2U6ICgpID0+IGBTU0wgY2VydGlmaWNhdGUgdHJ1c3RlZCBmb3IgXCIke3NpdGV9XCJgIH0sIGFzeW5jIChncWwsIHNpdGVJZCkgPT4ge1xuICAgICAgY29uc3QgZGF0YSA9IGF3YWl0IGdxbC5tdXRhdGU8eyB0cnVzdFNzbDogeyBzdWNjZXNzOiBib29sZWFuOyBlcnJvcjogc3RyaW5nIHwgbnVsbCB9IH0+KGBcbiAgICAgICAgbXV0YXRpb24oJGlucHV0OiBUcnVzdFNzbElucHV0ISkge1xuICAgICAgICAgIHRydXN0U3NsKGlucHV0OiAkaW5wdXQpIHsgc3VjY2VzcyBlcnJvciB9XG4gICAgICAgIH1cbiAgICAgIGAsIHsgaW5wdXQ6IHsgc2l0ZUlkIH0gfSk7XG4gICAgICBpZiAoIWRhdGEudHJ1c3RTc2wuc3VjY2Vzcykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoZGF0YS50cnVzdFNzbC5lcnJvciB8fCAnRmFpbGVkIHRvIHRydXN0IFNTTCcpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGRhdGE7XG4gICAgfSk7XG4gIH0pO1xuXG5zaXRlc1xuICAuY29tbWFuZCgncGhwIDxzaXRlPiA8dmVyc2lvbj4nKVxuICAuZGVzY3JpcHRpb24oJ0NoYW5nZSBQSFAgdmVyc2lvbiBmb3IgYSBzaXRlJylcbiAgLmFjdGlvbihhc3luYyAoc2l0ZSwgdmVyc2lvbikgPT4ge1xuICAgIGF3YWl0IHJ1blNpdGVDb21tYW5kKHNpdGUsIHsgYWN0aW9uOiBgQ2hhbmdpbmcgUEhQIHRvICR7dmVyc2lvbn0gZm9yYCwgc3VjY2Vzc01lc3NhZ2U6ICgpID0+IGBQSFAgdmVyc2lvbiBjaGFuZ2VkIHRvICR7dmVyc2lvbn1gIH0sIGFzeW5jIChncWwsIHNpdGVJZCkgPT4ge1xuICAgICAgY29uc3QgZGF0YSA9IGF3YWl0IGdxbC5tdXRhdGU8eyBjaGFuZ2VQaHBWZXJzaW9uOiB7IHN1Y2Nlc3M6IGJvb2xlYW47IGVycm9yOiBzdHJpbmcgfCBudWxsIH0gfT4oYFxuICAgICAgICBtdXRhdGlvbigkaW5wdXQ6IENoYW5nZVBocFZlcnNpb25JbnB1dCEpIHtcbiAgICAgICAgICBjaGFuZ2VQaHBWZXJzaW9uKGlucHV0OiAkaW5wdXQpIHsgc3VjY2VzcyBlcnJvciB9XG4gICAgICAgIH1cbiAgICAgIGAsIHsgaW5wdXQ6IHsgc2l0ZUlkLCBwaHBWZXJzaW9uOiB2ZXJzaW9uIH0gfSk7XG4gICAgICBpZiAoIWRhdGEuY2hhbmdlUGhwVmVyc2lvbi5zdWNjZXNzKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihkYXRhLmNoYW5nZVBocFZlcnNpb24uZXJyb3IgfHwgJ0ZhaWxlZCB0byBjaGFuZ2UgUEhQIHZlcnNpb24nKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBkYXRhO1xuICAgIH0pO1xuICB9KTtcblxuc2l0ZXNcbiAgLmNvbW1hbmQoJ3hkZWJ1ZyA8c2l0ZT4nKVxuICAuZGVzY3JpcHRpb24oJ1RvZ2dsZSBYZGVidWcgZm9yIGEgc2l0ZScpXG4gIC5vcHRpb24oJy0tb24nLCAnRW5hYmxlIFhkZWJ1ZycpXG4gIC5vcHRpb24oJy0tb2ZmJywgJ0Rpc2FibGUgWGRlYnVnJylcbiAgLmFjdGlvbihhc3luYyAoc2l0ZSwgY21kT3B0aW9ucykgPT4ge1xuICAgIGNvbnN0IGVuYWJsZWQgPSBjbWRPcHRpb25zLm9uID8gdHJ1ZSA6IGNtZE9wdGlvbnMub2ZmID8gZmFsc2UgOiB1bmRlZmluZWQ7XG4gICAgY29uc3QgYWN0aW9uID0gZW5hYmxlZCA9PT0gdW5kZWZpbmVkID8gJ1RvZ2dsaW5nJyA6IGVuYWJsZWQgPyAnRW5hYmxpbmcnIDogJ0Rpc2FibGluZyc7XG4gICAgYXdhaXQgcnVuU2l0ZUNvbW1hbmQoc2l0ZSwgeyBhY3Rpb246IGAke2FjdGlvbn0gWGRlYnVnIGZvcmAsIHN1Y2Nlc3NNZXNzYWdlOiAoZGF0YTogeyB0b2dnbGVYZGVidWc6IHsgZW5hYmxlZDogYm9vbGVhbiB9IH0pID0+IGBYZGVidWcgJHtkYXRhLnRvZ2dsZVhkZWJ1Zy5lbmFibGVkID8gJ2VuYWJsZWQnIDogJ2Rpc2FibGVkJ31gIH0sIGFzeW5jIChncWwsIHNpdGVJZCkgPT4ge1xuICAgICAgLy8gSWYgbm8gZmxhZyBzcGVjaWZpZWQsIGdldCBjdXJyZW50IHN0YXRlIGFuZCB0b2dnbGVcbiAgICAgIGxldCB0YXJnZXRFbmFibGVkID0gZW5hYmxlZDtcbiAgICAgIGlmICh0YXJnZXRFbmFibGVkID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgY29uc3Qgc2l0ZURhdGEgPSBhd2FpdCBncWwucXVlcnk8eyBzaXRlOiB7IHhkZWJ1Z0VuYWJsZWQ6IGJvb2xlYW4gfSB9PihgXG4gICAgICAgICAgcXVlcnkoJGlkOiBJRCEpIHsgc2l0ZShpZDogJGlkKSB7IHhkZWJ1Z0VuYWJsZWQgfSB9XG4gICAgICAgIGAsIHsgaWQ6IHNpdGVJZCB9KTtcbiAgICAgICAgdGFyZ2V0RW5hYmxlZCA9ICFzaXRlRGF0YS5zaXRlLnhkZWJ1Z0VuYWJsZWQ7XG4gICAgICB9XG4gICAgICBjb25zdCBkYXRhID0gYXdhaXQgZ3FsLm11dGF0ZTx7IHRvZ2dsZVhkZWJ1ZzogeyBzdWNjZXNzOiBib29sZWFuOyBlbmFibGVkOiBib29sZWFuOyBlcnJvcjogc3RyaW5nIHwgbnVsbCB9IH0+KGBcbiAgICAgICAgbXV0YXRpb24oJGlucHV0OiBUb2dnbGVYZGVidWdJbnB1dCEpIHtcbiAgICAgICAgICB0b2dnbGVYZGVidWcoaW5wdXQ6ICRpbnB1dCkgeyBzdWNjZXNzIGVuYWJsZWQgZXJyb3IgfVxuICAgICAgICB9XG4gICAgICBgLCB7IGlucHV0OiB7IHNpdGVJZCwgZW5hYmxlZDogdGFyZ2V0RW5hYmxlZCB9IH0pO1xuICAgICAgaWYgKCFkYXRhLnRvZ2dsZVhkZWJ1Zy5zdWNjZXNzKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihkYXRhLnRvZ2dsZVhkZWJ1Zy5lcnJvciB8fCAnRmFpbGVkIHRvIHRvZ2dsZSBYZGVidWcnKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBkYXRhO1xuICAgIH0pO1xuICB9KTtcblxuc2l0ZXNcbiAgLmNvbW1hbmQoJ2xvZ3MgPHNpdGU+JylcbiAgLmRlc2NyaXB0aW9uKCdHZXQgc2l0ZSBsb2dzJylcbiAgLm9wdGlvbignLXQsIC0tdHlwZSA8dHlwZT4nLCAnTG9nIHR5cGUgKHBocHxuZ2lueHxteXNxbCknLCAncGhwJylcbiAgLm9wdGlvbignLW4sIC0tbGluZXMgPG4+JywgJ051bWJlciBvZiBsaW5lcycsICc1MCcpXG4gIC5hY3Rpb24oYXN5bmMgKHNpdGUsIGNtZE9wdGlvbnMpID0+IHtcbiAgICBjb25zdCBnbG9iYWxPcHRzID0gcHJvZ3JhbS5vcHRzKCkgYXMgRm9ybWF0dGVyT3B0aW9ucztcbiAgICBjb25zdCBmb3JtYXQgPSBnZXRPdXRwdXRGb3JtYXQoZ2xvYmFsT3B0cyk7XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgZ3FsID0gYXdhaXQgZW5zdXJlQ29ubmVjdGVkKGdsb2JhbE9wdHMpO1xuICAgICAgY29uc3Qgc2l0ZUlkID0gYXdhaXQgZmluZFNpdGVJZChncWwsIHNpdGUpO1xuXG4gICAgICBjb25zdCBkYXRhID0gYXdhaXQgZ3FsLm11dGF0ZTx7IGdldFNpdGVMb2dzOiB7IHN1Y2Nlc3M6IGJvb2xlYW47IGxvZ3M6IHN0cmluZ1tdOyBlcnJvcjogc3RyaW5nIHwgbnVsbCB9IH0+KGBcbiAgICAgICAgbXV0YXRpb24oJGlucHV0OiBHZXRTaXRlTG9nc0lucHV0ISkge1xuICAgICAgICAgIGdldFNpdGVMb2dzKGlucHV0OiAkaW5wdXQpIHsgc3VjY2VzcyBsb2dzIGVycm9yIH1cbiAgICAgICAgfVxuICAgICAgYCwgeyBpbnB1dDogeyBzaXRlSWQsIGxvZ1R5cGU6IGNtZE9wdGlvbnMudHlwZSwgbGluZXM6IHBhcnNlSW50KGNtZE9wdGlvbnMubGluZXMsIDEwKSB9IH0pO1xuXG4gICAgICBpZiAoIWRhdGEuZ2V0U2l0ZUxvZ3Muc3VjY2Vzcykge1xuICAgICAgICBjb25zb2xlLmVycm9yKGZvcm1hdEVycm9yKGRhdGEuZ2V0U2l0ZUxvZ3MuZXJyb3IgfHwgJ0ZhaWxlZCB0byBnZXQgbG9ncycpKTtcbiAgICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgICAgfVxuXG4gICAgICBpZiAoZm9ybWF0ID09PSAnanNvbicpIHtcbiAgICAgICAgY29uc29sZS5sb2coSlNPTi5zdHJpbmdpZnkoZGF0YS5nZXRTaXRlTG9ncy5sb2dzLCBudWxsLCAyKSk7XG4gICAgICB9IGVsc2UgaWYgKGRhdGEuZ2V0U2l0ZUxvZ3MubG9ncy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgY29uc29sZS5sb2coJ05vIGxvZ3MgZm91bmQuJyk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBkYXRhLmdldFNpdGVMb2dzLmxvZ3MuZm9yRWFjaCgobGluZSkgPT4gY29uc29sZS5sb2cobGluZSkpO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yOiBhbnkpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoZm9ybWF0RXJyb3IoZXJyb3IubWVzc2FnZSkpO1xuICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgIH1cbiAgfSk7XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIFdQLUNMSSBDb21tYW5kXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbnByb2dyYW1cbiAgLmNvbW1hbmQoJ3dwIDxzaXRlPiBbYXJncy4uLl0nKVxuICAuZGVzY3JpcHRpb24oJ1J1biBXUC1DTEkgY29tbWFuZHMgYWdhaW5zdCBhIHNpdGUnKVxuICAuYWN0aW9uKGFzeW5jIChzaXRlLCBhcmdzKSA9PiB7XG4gICAgY29uc3QgZ2xvYmFsT3B0cyA9IHByb2dyYW0ub3B0cygpIGFzIEZvcm1hdHRlck9wdGlvbnM7XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgZ3FsID0gYXdhaXQgZW5zdXJlQ29ubmVjdGVkKGdsb2JhbE9wdHMpO1xuICAgICAgY29uc3Qgc2l0ZUlkID0gYXdhaXQgZmluZFNpdGVJZChncWwsIHNpdGUpO1xuXG4gICAgICBjb25zdCBkYXRhID0gYXdhaXQgZ3FsLm11dGF0ZTx7IHdwQ2xpOiB7IHN1Y2Nlc3M6IGJvb2xlYW47IG91dHB1dDogc3RyaW5nOyBlcnJvcjogc3RyaW5nIHwgbnVsbCB9IH0+KGBcbiAgICAgICAgbXV0YXRpb24oJGlucHV0OiBXcENsaUlucHV0ISkge1xuICAgICAgICAgIHdwQ2xpKGlucHV0OiAkaW5wdXQpIHsgc3VjY2VzcyBvdXRwdXQgZXJyb3IgfVxuICAgICAgICB9XG4gICAgICBgLCB7IGlucHV0OiB7IHNpdGVJZCwgYXJncyB9IH0pO1xuXG4gICAgICBpZiAoIWRhdGEud3BDbGkuc3VjY2Vzcykge1xuICAgICAgICBjb25zb2xlLmVycm9yKGZvcm1hdEVycm9yKGRhdGEud3BDbGkuZXJyb3IgfHwgJ1dQLUNMSSBjb21tYW5kIGZhaWxlZCcpKTtcbiAgICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgICAgfVxuXG4gICAgICBjb25zb2xlLmxvZyhkYXRhLndwQ2xpLm91dHB1dCk7XG4gICAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgICAgY29uc29sZS5lcnJvcihmb3JtYXRFcnJvcihlcnJvci5tZXNzYWdlKSk7XG4gICAgICBwcm9jZXNzLmV4aXQoMSk7XG4gICAgfVxuICB9KTtcblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gSW5mbyBDb21tYW5kXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbnByb2dyYW1cbiAgLmNvbW1hbmQoJ2luZm8nKVxuICAuZGVzY3JpcHRpb24oJ1Nob3cgTG9jYWwgYXBwbGljYXRpb24gaW5mbycpXG4gIC5hY3Rpb24oYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGdsb2JhbE9wdHMgPSBwcm9ncmFtLm9wdHMoKSBhcyBGb3JtYXR0ZXJPcHRpb25zO1xuICAgIGNvbnN0IGZvcm1hdCA9IGdldE91dHB1dEZvcm1hdChnbG9iYWxPcHRzKTtcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCBncWwgPSBhd2FpdCBlbnN1cmVDb25uZWN0ZWQoZ2xvYmFsT3B0cyk7XG5cbiAgICAgIC8vIEdldCBzaXRlcyBjb3VudCBhbmQgYmFzaWMgaW5mb1xuICAgICAgY29uc3QgZGF0YSA9IGF3YWl0IGdxbC5xdWVyeTx7IHNpdGVzOiBBcnJheTx7IGlkOiBzdHJpbmc7IHN0YXR1czogc3RyaW5nIH0+IH0+KGBcbiAgICAgICAgcXVlcnkgeyBzaXRlcyB7IGlkIHN0YXR1cyB9IH1cbiAgICAgIGApO1xuXG4gICAgICBjb25zdCBydW5uaW5nID0gZGF0YS5zaXRlcy5maWx0ZXIoKHMpID0+IHMuc3RhdHVzLnRvTG93ZXJDYXNlKCkgPT09ICdydW5uaW5nJykubGVuZ3RoO1xuICAgICAgY29uc3Qgc3RvcHBlZCA9IGRhdGEuc2l0ZXMuZmlsdGVyKChzKSA9PiBzLnN0YXR1cy50b0xvd2VyQ2FzZSgpICE9PSAncnVubmluZycpLmxlbmd0aDtcblxuICAgICAgY29uc3QgaW5mbyA9IHtcbiAgICAgICAgdG90YWxTaXRlczogZGF0YS5zaXRlcy5sZW5ndGgsXG4gICAgICAgIHJ1bm5pbmdTaXRlczogcnVubmluZyxcbiAgICAgICAgc3RvcHBlZFNpdGVzOiBzdG9wcGVkLFxuICAgICAgICBncmFwaHFsRW5kcG9pbnQ6IGNsaWVudD8uWyd1cmwnXSB8fCAnY29ubmVjdGVkJyxcbiAgICAgIH07XG5cbiAgICAgIGNvbnNvbGUubG9nKGZvcm1hdFNpdGVEZXRhaWwoaW5mbywgZm9ybWF0LCB7IG5vQ29sb3I6IGdsb2JhbE9wdHMubm9Db2xvciB9KSk7XG4gICAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgICAgY29uc29sZS5lcnJvcihmb3JtYXRFcnJvcihlcnJvci5tZXNzYWdlKSk7XG4gICAgICBwcm9jZXNzLmV4aXQoMSk7XG4gICAgfVxuICB9KTtcblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gU2VydmljZXMgQ29tbWFuZFxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5wcm9ncmFtXG4gIC5jb21tYW5kKCdzZXJ2aWNlcycpXG4gIC5kZXNjcmlwdGlvbignTGlzdCBhdmFpbGFibGUgc2VydmljZSB2ZXJzaW9ucycpXG4gIC5hY3Rpb24oYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGdsb2JhbE9wdHMgPSBwcm9ncmFtLm9wdHMoKSBhcyBGb3JtYXR0ZXJPcHRpb25zO1xuICAgIGNvbnN0IGZvcm1hdCA9IGdldE91dHB1dEZvcm1hdChnbG9iYWxPcHRzKTtcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCBncWwgPSBhd2FpdCBlbnN1cmVDb25uZWN0ZWQoZ2xvYmFsT3B0cyk7XG5cbiAgICAgIGNvbnN0IGRhdGEgPSBhd2FpdCBncWwucXVlcnk8eyBsaXN0U2VydmljZXM6IHsgc3VjY2VzczogYm9vbGVhbjsgc2VydmljZXM6IEFycmF5PHsgcm9sZTogc3RyaW5nOyBuYW1lOiBzdHJpbmc7IHZlcnNpb246IHN0cmluZyB9PjsgZXJyb3I6IHN0cmluZyB8IG51bGwgfSB9PihgXG4gICAgICAgIHF1ZXJ5IHtcbiAgICAgICAgICBsaXN0U2VydmljZXMge1xuICAgICAgICAgICAgc3VjY2Vzc1xuICAgICAgICAgICAgc2VydmljZXMgeyByb2xlIG5hbWUgdmVyc2lvbiB9XG4gICAgICAgICAgICBlcnJvclxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgYCk7XG5cbiAgICAgIGlmICghZGF0YS5saXN0U2VydmljZXMuc3VjY2Vzcykge1xuICAgICAgICBjb25zb2xlLmVycm9yKGZvcm1hdEVycm9yKGRhdGEubGlzdFNlcnZpY2VzLmVycm9yIHx8ICdGYWlsZWQgdG8gbGlzdCBzZXJ2aWNlcycpKTtcbiAgICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgICAgfVxuXG4gICAgICBpZiAoZm9ybWF0ID09PSAnanNvbicpIHtcbiAgICAgICAgY29uc29sZS5sb2coSlNPTi5zdHJpbmdpZnkoZGF0YS5saXN0U2VydmljZXMuc2VydmljZXMsIG51bGwsIDIpKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IGdyb3VwZWQ6IFJlY29yZDxzdHJpbmcsIHN0cmluZ1tdPiA9IHt9O1xuICAgICAgICBmb3IgKGNvbnN0IHN2YyBvZiBkYXRhLmxpc3RTZXJ2aWNlcy5zZXJ2aWNlcykge1xuICAgICAgICAgIGlmICghZ3JvdXBlZFtzdmMucm9sZV0pIGdyb3VwZWRbc3ZjLnJvbGVdID0gW107XG4gICAgICAgICAgZ3JvdXBlZFtzdmMucm9sZV0ucHVzaChgJHtzdmMudmVyc2lvbn0gKCR7c3ZjLm5hbWV9KWApO1xuICAgICAgICB9XG5cbiAgICAgICAgZm9yIChjb25zdCBbcm9sZSwgdmVyc2lvbnNdIG9mIE9iamVjdC5lbnRyaWVzKGdyb3VwZWQpKSB7XG4gICAgICAgICAgY29uc29sZS5sb2coYFxcbiR7cm9sZS5jaGFyQXQoMCkudG9VcHBlckNhc2UoKSArIHJvbGUuc2xpY2UoMSl9IFZlcnNpb25zOmApO1xuICAgICAgICAgIHZlcnNpb25zLmZvckVhY2goKHYpID0+IGNvbnNvbGUubG9nKGAgIC0gJHt2fWApKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yOiBhbnkpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoZm9ybWF0RXJyb3IoZXJyb3IubWVzc2FnZSkpO1xuICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgIH1cbiAgfSk7XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIEJsdWVwcmludHMgQ29tbWFuZFxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5jb25zdCBibHVlcHJpbnRzID0gcHJvZ3JhbS5jb21tYW5kKCdibHVlcHJpbnRzJykuZGVzY3JpcHRpb24oJ01hbmFnZSBibHVlcHJpbnRzJyk7XG5cbmJsdWVwcmludHNcbiAgLmNvbW1hbmQoJ2xpc3QnKVxuICAuZGVzY3JpcHRpb24oJ0xpc3QgYXZhaWxhYmxlIGJsdWVwcmludHMnKVxuICAuYWN0aW9uKGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBnbG9iYWxPcHRzID0gcHJvZ3JhbS5vcHRzKCkgYXMgRm9ybWF0dGVyT3B0aW9ucztcbiAgICBjb25zdCBmb3JtYXQgPSBnZXRPdXRwdXRGb3JtYXQoZ2xvYmFsT3B0cyk7XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgZ3FsID0gYXdhaXQgZW5zdXJlQ29ubmVjdGVkKGdsb2JhbE9wdHMpO1xuXG4gICAgICBjb25zdCBkYXRhID0gYXdhaXQgZ3FsLnF1ZXJ5PHsgYmx1ZXByaW50czogeyBzdWNjZXNzOiBib29sZWFuOyBibHVlcHJpbnRzOiBBcnJheTx7IG5hbWU6IHN0cmluZyB9PjsgZXJyb3I6IHN0cmluZyB8IG51bGwgfSB9PihgXG4gICAgICAgIHF1ZXJ5IHtcbiAgICAgICAgICBibHVlcHJpbnRzIHtcbiAgICAgICAgICAgIHN1Y2Nlc3NcbiAgICAgICAgICAgIGJsdWVwcmludHMgeyBuYW1lIH1cbiAgICAgICAgICAgIGVycm9yXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBgKTtcblxuICAgICAgaWYgKCFkYXRhLmJsdWVwcmludHMuc3VjY2Vzcykge1xuICAgICAgICBjb25zb2xlLmVycm9yKGZvcm1hdEVycm9yKGRhdGEuYmx1ZXByaW50cy5lcnJvciB8fCAnRmFpbGVkIHRvIGxpc3QgYmx1ZXByaW50cycpKTtcbiAgICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgICAgfVxuXG4gICAgICBpZiAoZm9ybWF0ID09PSAnanNvbicpIHtcbiAgICAgICAgY29uc29sZS5sb2coSlNPTi5zdHJpbmdpZnkoZGF0YS5ibHVlcHJpbnRzLmJsdWVwcmludHMsIG51bGwsIDIpKTtcbiAgICAgIH0gZWxzZSBpZiAoZGF0YS5ibHVlcHJpbnRzLmJsdWVwcmludHMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCdObyBibHVlcHJpbnRzIGZvdW5kLicpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc29sZS5sb2coJ0JsdWVwcmludHM6Jyk7XG4gICAgICAgIGRhdGEuYmx1ZXByaW50cy5ibHVlcHJpbnRzLmZvckVhY2goKGIpID0+IGNvbnNvbGUubG9nKGAgIC0gJHtiLm5hbWV9YCkpO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yOiBhbnkpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoZm9ybWF0RXJyb3IoZXJyb3IubWVzc2FnZSkpO1xuICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgIH1cbiAgfSk7XG5cbmJsdWVwcmludHNcbiAgLmNvbW1hbmQoJ3NhdmUgPHNpdGU+IDxuYW1lPicpXG4gIC5kZXNjcmlwdGlvbignU2F2ZSBhIHNpdGUgYXMgYSBibHVlcHJpbnQnKVxuICAuYWN0aW9uKGFzeW5jIChzaXRlLCBuYW1lKSA9PiB7XG4gICAgYXdhaXQgcnVuU2l0ZUNvbW1hbmQoc2l0ZSwgeyBhY3Rpb246ICdTYXZpbmcgYmx1ZXByaW50IGZyb20nLCBzdWNjZXNzTWVzc2FnZTogKCkgPT4gYFNhdmVkIGJsdWVwcmludCBcIiR7bmFtZX1cImAgfSwgYXN5bmMgKGdxbCwgc2l0ZUlkKSA9PiB7XG4gICAgICBjb25zdCBkYXRhID0gYXdhaXQgZ3FsLm11dGF0ZTx7IHNhdmVCbHVlcHJpbnQ6IHsgc3VjY2VzczogYm9vbGVhbjsgZXJyb3I6IHN0cmluZyB8IG51bGwgfSB9PihgXG4gICAgICAgIG11dGF0aW9uKCRpbnB1dDogU2F2ZUJsdWVwcmludElucHV0ISkge1xuICAgICAgICAgIHNhdmVCbHVlcHJpbnQoaW5wdXQ6ICRpbnB1dCkgeyBzdWNjZXNzIGVycm9yIH1cbiAgICAgICAgfVxuICAgICAgYCwgeyBpbnB1dDogeyBzaXRlSWQsIG5hbWUgfSB9KTtcbiAgICAgIGlmICghZGF0YS5zYXZlQmx1ZXByaW50LnN1Y2Nlc3MpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGRhdGEuc2F2ZUJsdWVwcmludC5lcnJvciB8fCAnRmFpbGVkIHRvIHNhdmUgYmx1ZXByaW50Jyk7XG4gICAgICB9XG4gICAgICByZXR1cm4gZGF0YTtcbiAgICB9KTtcbiAgfSk7XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIERhdGFiYXNlIENvbW1hbmRzXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbmNvbnN0IGRiID0gcHJvZ3JhbS5jb21tYW5kKCdkYicpLmRlc2NyaXB0aW9uKCdEYXRhYmFzZSBvcGVyYXRpb25zJyk7XG5cbmRiXG4gIC5jb21tYW5kKCdleHBvcnQgPHNpdGU+JylcbiAgLmRlc2NyaXB0aW9uKCdFeHBvcnQgZGF0YWJhc2UgdG8gU1FMIGZpbGUnKVxuICAub3B0aW9uKCctbywgLS1vdXRwdXQgPHBhdGg+JywgJ091dHB1dCBmaWxlIHBhdGgnKVxuICAuYWN0aW9uKGFzeW5jIChzaXRlLCBjbWRPcHRpb25zKSA9PiB7XG4gICAgYXdhaXQgcnVuU2l0ZUNvbW1hbmQoc2l0ZSwgeyBhY3Rpb246ICdFeHBvcnRpbmcgZGF0YWJhc2UgZm9yJywgc3VjY2Vzc01lc3NhZ2U6IChkYXRhOiB7IGV4cG9ydERhdGFiYXNlOiB7IG91dHB1dFBhdGg6IHN0cmluZyB9IH0pID0+IGBFeHBvcnRlZCB0byAke2RhdGEuZXhwb3J0RGF0YWJhc2Uub3V0cHV0UGF0aH1gIH0sIGFzeW5jIChncWwsIHNpdGVJZCkgPT4ge1xuICAgICAgY29uc3QgZGF0YSA9IGF3YWl0IGdxbC5tdXRhdGU8eyBleHBvcnREYXRhYmFzZTogeyBzdWNjZXNzOiBib29sZWFuOyBvdXRwdXRQYXRoOiBzdHJpbmc7IGVycm9yOiBzdHJpbmcgfCBudWxsIH0gfT4oYFxuICAgICAgICBtdXRhdGlvbigkaW5wdXQ6IEV4cG9ydERhdGFiYXNlSW5wdXQhKSB7XG4gICAgICAgICAgZXhwb3J0RGF0YWJhc2UoaW5wdXQ6ICRpbnB1dCkgeyBzdWNjZXNzIG91dHB1dFBhdGggZXJyb3IgfVxuICAgICAgICB9XG4gICAgICBgLCB7IGlucHV0OiB7IHNpdGVJZCwgb3V0cHV0UGF0aDogY21kT3B0aW9ucy5vdXRwdXQgfSB9KTtcbiAgICAgIGlmICghZGF0YS5leHBvcnREYXRhYmFzZS5zdWNjZXNzKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihkYXRhLmV4cG9ydERhdGFiYXNlLmVycm9yIHx8ICdGYWlsZWQgdG8gZXhwb3J0IGRhdGFiYXNlJyk7XG4gICAgICB9XG4gICAgICByZXR1cm4gZGF0YTtcbiAgICB9KTtcbiAgfSk7XG5cbmRiXG4gIC5jb21tYW5kKCdpbXBvcnQgPHNpdGU+IDxzcWxGaWxlPicpXG4gIC5kZXNjcmlwdGlvbignSW1wb3J0IFNRTCBmaWxlIGludG8gZGF0YWJhc2UnKVxuICAuYWN0aW9uKGFzeW5jIChzaXRlLCBzcWxGaWxlKSA9PiB7XG4gICAgYXdhaXQgcnVuU2l0ZUNvbW1hbmQoc2l0ZSwgeyBhY3Rpb246ICdJbXBvcnRpbmcgZGF0YWJhc2UgZm9yJywgc3VjY2Vzc01lc3NhZ2U6ICgpID0+ICdEYXRhYmFzZSBpbXBvcnRlZCBzdWNjZXNzZnVsbHknIH0sIGFzeW5jIChncWwsIHNpdGVJZCkgPT4ge1xuICAgICAgY29uc3QgZGF0YSA9IGF3YWl0IGdxbC5tdXRhdGU8eyBpbXBvcnREYXRhYmFzZTogeyBzdWNjZXNzOiBib29sZWFuOyBlcnJvcjogc3RyaW5nIHwgbnVsbCB9IH0+KGBcbiAgICAgICAgbXV0YXRpb24oJGlucHV0OiBJbXBvcnREYXRhYmFzZUlucHV0ISkge1xuICAgICAgICAgIGltcG9ydERhdGFiYXNlKGlucHV0OiAkaW5wdXQpIHsgc3VjY2VzcyBlcnJvciB9XG4gICAgICAgIH1cbiAgICAgIGAsIHsgaW5wdXQ6IHsgc2l0ZUlkLCBzcWxQYXRoOiBzcWxGaWxlIH0gfSk7XG4gICAgICBpZiAoIWRhdGEuaW1wb3J0RGF0YWJhc2Uuc3VjY2Vzcykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoZGF0YS5pbXBvcnREYXRhYmFzZS5lcnJvciB8fCAnRmFpbGVkIHRvIGltcG9ydCBkYXRhYmFzZScpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGRhdGE7XG4gICAgfSk7XG4gIH0pO1xuXG5kYlxuICAuY29tbWFuZCgnYWRtaW5lciA8c2l0ZT4nKVxuICAuZGVzY3JpcHRpb24oJ09wZW4gQWRtaW5lciBkYXRhYmFzZSBVSScpXG4gIC5hY3Rpb24oYXN5bmMgKHNpdGUpID0+IHtcbiAgICBhd2FpdCBydW5TaXRlQ29tbWFuZChzaXRlLCB7IGFjdGlvbjogJ09wZW5pbmcgQWRtaW5lciBmb3InLCBzdWNjZXNzTWVzc2FnZTogKCkgPT4gJ09wZW5lZCBBZG1pbmVyJyB9LCBhc3luYyAoZ3FsLCBzaXRlSWQpID0+IHtcbiAgICAgIHJldHVybiBncWwubXV0YXRlKGBcbiAgICAgICAgbXV0YXRpb24oJGlucHV0OiBPcGVuQWRtaW5lcklucHV0ISkge1xuICAgICAgICAgIG9wZW5BZG1pbmVyKGlucHV0OiAkaW5wdXQpIHsgc3VjY2VzcyBlcnJvciB9XG4gICAgICAgIH1cbiAgICAgIGAsIHsgaW5wdXQ6IHsgc2l0ZUlkIH0gfSk7XG4gICAgfSk7XG4gIH0pO1xuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBCYWNrdXBzIENvbW1hbmRzXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbmNvbnN0IGJhY2t1cHMgPSBwcm9ncmFtLmNvbW1hbmQoJ2JhY2t1cHMnKS5kZXNjcmlwdGlvbignQ2xvdWQgYmFja3VwIG9wZXJhdGlvbnMnKTtcblxuYmFja3Vwc1xuICAuY29tbWFuZCgnc3RhdHVzJylcbiAgLmRlc2NyaXB0aW9uKCdDaGVjayBiYWNrdXAgc2VydmljZSBhdmFpbGFiaWxpdHknKVxuICAuYWN0aW9uKGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBnbG9iYWxPcHRzID0gcHJvZ3JhbS5vcHRzKCkgYXMgRm9ybWF0dGVyT3B0aW9ucztcbiAgICBjb25zdCBmb3JtYXQgPSBnZXRPdXRwdXRGb3JtYXQoZ2xvYmFsT3B0cyk7XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgZ3FsID0gYXdhaXQgZW5zdXJlQ29ubmVjdGVkKGdsb2JhbE9wdHMpO1xuXG4gICAgICBjb25zdCBkYXRhID0gYXdhaXQgZ3FsLnF1ZXJ5PHsgYmFja3VwU3RhdHVzOiB7IGF2YWlsYWJsZTogYm9vbGVhbjsgZmVhdHVyZUVuYWJsZWQ6IGJvb2xlYW47IGRyb3Bib3g6IGFueTsgZ29vZ2xlRHJpdmU6IGFueSB9IH0+KGBcbiAgICAgICAgcXVlcnkge1xuICAgICAgICAgIGJhY2t1cFN0YXR1cyB7XG4gICAgICAgICAgICBhdmFpbGFibGVcbiAgICAgICAgICAgIGZlYXR1cmVFbmFibGVkXG4gICAgICAgICAgICBkcm9wYm94IHsgYXV0aGVudGljYXRlZCBhY2NvdW50SWQgZW1haWwgfVxuICAgICAgICAgICAgZ29vZ2xlRHJpdmUgeyBhdXRoZW50aWNhdGVkIGFjY291bnRJZCBlbWFpbCB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBgKTtcblxuICAgICAgaWYgKGZvcm1hdCA9PT0gJ2pzb24nKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKEpTT04uc3RyaW5naWZ5KGRhdGEuYmFja3VwU3RhdHVzLCBudWxsLCAyKSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBzdGF0dXMgPSBkYXRhLmJhY2t1cFN0YXR1cztcbiAgICAgICAgY29uc29sZS5sb2coYFxcbkJhY2t1cCBTdGF0dXM6YCk7XG4gICAgICAgIGNvbnNvbGUubG9nKGAgIEF2YWlsYWJsZTogJHtzdGF0dXMuYXZhaWxhYmxlID8gJ1llcycgOiAnTm8nfWApO1xuICAgICAgICBjb25zb2xlLmxvZyhgICBGZWF0dXJlIEVuYWJsZWQ6ICR7c3RhdHVzLmZlYXR1cmVFbmFibGVkID8gJ1llcycgOiAnTm8nfWApO1xuICAgICAgICBpZiAoc3RhdHVzLmRyb3Bib3gpIHtcbiAgICAgICAgICBjb25zb2xlLmxvZyhgXFxuICBEcm9wYm94OiAke3N0YXR1cy5kcm9wYm94LmF1dGhlbnRpY2F0ZWQgPyBgQ29ubmVjdGVkICgke3N0YXR1cy5kcm9wYm94LmVtYWlsfSlgIDogJ05vdCBjb25uZWN0ZWQnfWApO1xuICAgICAgICB9XG4gICAgICAgIGlmIChzdGF0dXMuZ29vZ2xlRHJpdmUpIHtcbiAgICAgICAgICBjb25zb2xlLmxvZyhgICBHb29nbGUgRHJpdmU6ICR7c3RhdHVzLmdvb2dsZURyaXZlLmF1dGhlbnRpY2F0ZWQgPyBgQ29ubmVjdGVkICgke3N0YXR1cy5nb29nbGVEcml2ZS5lbWFpbH0pYCA6ICdOb3QgY29ubmVjdGVkJ31gKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yOiBhbnkpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoZm9ybWF0RXJyb3IoZXJyb3IubWVzc2FnZSkpO1xuICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgIH1cbiAgfSk7XG5cbmJhY2t1cHNcbiAgLmNvbW1hbmQoJ2xpc3QgPHNpdGU+JylcbiAgLmRlc2NyaXB0aW9uKCdMaXN0IGJhY2t1cHMgZm9yIGEgc2l0ZScpXG4gIC5vcHRpb24oJy1wLCAtLXByb3ZpZGVyIDxwcm92aWRlcj4nLCAnQmFja3VwIHByb3ZpZGVyIChkcm9wYm94fGdvb2dsZURyaXZlKScsICdkcm9wYm94JylcbiAgLmFjdGlvbihhc3luYyAoc2l0ZSwgY21kT3B0aW9ucykgPT4ge1xuICAgIGNvbnN0IGdsb2JhbE9wdHMgPSBwcm9ncmFtLm9wdHMoKSBhcyBGb3JtYXR0ZXJPcHRpb25zO1xuICAgIGNvbnN0IGZvcm1hdCA9IGdldE91dHB1dEZvcm1hdChnbG9iYWxPcHRzKTtcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCBncWwgPSBhd2FpdCBlbnN1cmVDb25uZWN0ZWQoZ2xvYmFsT3B0cyk7XG4gICAgICBjb25zdCBzaXRlSWQgPSBhd2FpdCBmaW5kU2l0ZUlkKGdxbCwgc2l0ZSk7XG5cbiAgICAgIGNvbnN0IGRhdGEgPSBhd2FpdCBncWwucXVlcnk8eyBsaXN0QmFja3VwczogeyBzdWNjZXNzOiBib29sZWFuOyBiYWNrdXBzOiBBcnJheTx7IHNuYXBzaG90SWQ6IHN0cmluZzsgdGltZXN0YW1wOiBzdHJpbmc7IG5vdGU6IHN0cmluZyB9PjsgZXJyb3I6IHN0cmluZyB8IG51bGwgfSB9PihgXG4gICAgICAgIHF1ZXJ5KCRzaXRlSWQ6IElEISwgJHByb3ZpZGVyOiBTdHJpbmchKSB7XG4gICAgICAgICAgbGlzdEJhY2t1cHMoc2l0ZUlkOiAkc2l0ZUlkLCBwcm92aWRlcjogJHByb3ZpZGVyKSB7XG4gICAgICAgICAgICBzdWNjZXNzXG4gICAgICAgICAgICBiYWNrdXBzIHsgc25hcHNob3RJZCB0aW1lc3RhbXAgbm90ZSB9XG4gICAgICAgICAgICBlcnJvclxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgYCwgeyBzaXRlSWQsIHByb3ZpZGVyOiBjbWRPcHRpb25zLnByb3ZpZGVyIH0pO1xuXG4gICAgICBpZiAoIWRhdGEubGlzdEJhY2t1cHMuc3VjY2Vzcykge1xuICAgICAgICBjb25zb2xlLmVycm9yKGZvcm1hdEVycm9yKGRhdGEubGlzdEJhY2t1cHMuZXJyb3IgfHwgJ0ZhaWxlZCB0byBsaXN0IGJhY2t1cHMnKSk7XG4gICAgICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGZvcm1hdCA9PT0gJ2pzb24nKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKEpTT04uc3RyaW5naWZ5KGRhdGEubGlzdEJhY2t1cHMuYmFja3VwcywgbnVsbCwgMikpO1xuICAgICAgfSBlbHNlIGlmIChkYXRhLmxpc3RCYWNrdXBzLmJhY2t1cHMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCdObyBiYWNrdXBzIGZvdW5kLicpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc29sZS5sb2coYFxcbkJhY2t1cHMgKCR7Y21kT3B0aW9ucy5wcm92aWRlcn0pOmApO1xuICAgICAgICBmb3IgKGNvbnN0IGJhY2t1cCBvZiBkYXRhLmxpc3RCYWNrdXBzLmJhY2t1cHMpIHtcbiAgICAgICAgICBjb25zdCBkYXRlID0gbmV3IERhdGUoYmFja3VwLnRpbWVzdGFtcCkudG9Mb2NhbGVTdHJpbmcoKTtcbiAgICAgICAgICBjb25zb2xlLmxvZyhgICAke2JhY2t1cC5zbmFwc2hvdElkfSAtICR7ZGF0ZX0ke2JhY2t1cC5ub3RlID8gYCAtICR7YmFja3VwLm5vdGV9YCA6ICcnfWApO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgICAgY29uc29sZS5lcnJvcihmb3JtYXRFcnJvcihlcnJvci5tZXNzYWdlKSk7XG4gICAgICBwcm9jZXNzLmV4aXQoMSk7XG4gICAgfVxuICB9KTtcblxuYmFja3Vwc1xuICAuY29tbWFuZCgnY3JlYXRlIDxzaXRlPicpXG4gIC5kZXNjcmlwdGlvbignQ3JlYXRlIGEgYmFja3VwJylcbiAgLm9wdGlvbignLXAsIC0tcHJvdmlkZXIgPHByb3ZpZGVyPicsICdCYWNrdXAgcHJvdmlkZXIgKGRyb3Bib3h8Z29vZ2xlRHJpdmUpJywgJ2Ryb3Bib3gnKVxuICAub3B0aW9uKCctbiwgLS1ub3RlIDxub3RlPicsICdCYWNrdXAgbm90ZScpXG4gIC5hY3Rpb24oYXN5bmMgKHNpdGUsIGNtZE9wdGlvbnMpID0+IHtcbiAgICBhd2FpdCBydW5TaXRlQ29tbWFuZChzaXRlLCB7IGFjdGlvbjogJ0NyZWF0aW5nIGJhY2t1cCBmb3InLCBzdWNjZXNzTWVzc2FnZTogKGRhdGE6IHsgY3JlYXRlQmFja3VwOiB7IHNuYXBzaG90SWQ6IHN0cmluZyB9IH0pID0+IGBCYWNrdXAgY3JlYXRlZDogJHtkYXRhLmNyZWF0ZUJhY2t1cC5zbmFwc2hvdElkfWAgfSwgYXN5bmMgKGdxbCwgc2l0ZUlkKSA9PiB7XG4gICAgICBjb25zdCBkYXRhID0gYXdhaXQgZ3FsLm11dGF0ZTx7IGNyZWF0ZUJhY2t1cDogeyBzdWNjZXNzOiBib29sZWFuOyBzbmFwc2hvdElkOiBzdHJpbmc7IGVycm9yOiBzdHJpbmcgfCBudWxsIH0gfT4oYFxuICAgICAgICBtdXRhdGlvbigkc2l0ZUlkOiBJRCEsICRwcm92aWRlcjogU3RyaW5nISwgJG5vdGU6IFN0cmluZykge1xuICAgICAgICAgIGNyZWF0ZUJhY2t1cChzaXRlSWQ6ICRzaXRlSWQsIHByb3ZpZGVyOiAkcHJvdmlkZXIsIG5vdGU6ICRub3RlKSB7XG4gICAgICAgICAgICBzdWNjZXNzIHNuYXBzaG90SWQgZXJyb3JcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIGAsIHsgc2l0ZUlkLCBwcm92aWRlcjogY21kT3B0aW9ucy5wcm92aWRlciwgbm90ZTogY21kT3B0aW9ucy5ub3RlIH0pO1xuICAgICAgaWYgKCFkYXRhLmNyZWF0ZUJhY2t1cC5zdWNjZXNzKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihkYXRhLmNyZWF0ZUJhY2t1cC5lcnJvciB8fCAnRmFpbGVkIHRvIGNyZWF0ZSBiYWNrdXAnKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBkYXRhO1xuICAgIH0pO1xuICB9KTtcblxuYmFja3Vwc1xuICAuY29tbWFuZCgncmVzdG9yZSA8c2l0ZT4gPHNuYXBzaG90SWQ+JylcbiAgLmRlc2NyaXB0aW9uKCdSZXN0b3JlIGZyb20gYmFja3VwJylcbiAgLm9wdGlvbignLXAsIC0tcHJvdmlkZXIgPHByb3ZpZGVyPicsICdCYWNrdXAgcHJvdmlkZXIgKGRyb3Bib3h8Z29vZ2xlRHJpdmUpJywgJ2Ryb3Bib3gnKVxuICAub3B0aW9uKCcteSwgLS15ZXMnLCAnU2tpcCBjb25maXJtYXRpb24nKVxuICAuYWN0aW9uKGFzeW5jIChzaXRlLCBzbmFwc2hvdElkLCBjbWRPcHRpb25zKSA9PiB7XG4gICAgYXdhaXQgcnVuU2l0ZUNvbW1hbmQoc2l0ZSwgeyBhY3Rpb246ICdSZXN0b3JpbmcgYmFja3VwIGZvcicsIHN1Y2Nlc3NNZXNzYWdlOiAoZGF0YTogeyByZXN0b3JlQmFja3VwOiB7IG1lc3NhZ2U6IHN0cmluZyB9IH0pID0+IGRhdGEucmVzdG9yZUJhY2t1cC5tZXNzYWdlIHx8ICdCYWNrdXAgcmVzdG9yZWQgc3VjY2Vzc2Z1bGx5JyB9LCBhc3luYyAoZ3FsLCBzaXRlSWQpID0+IHtcbiAgICAgIGNvbnN0IGRhdGEgPSBhd2FpdCBncWwubXV0YXRlPHsgcmVzdG9yZUJhY2t1cDogeyBzdWNjZXNzOiBib29sZWFuOyBtZXNzYWdlOiBzdHJpbmc7IGVycm9yOiBzdHJpbmcgfCBudWxsIH0gfT4oYFxuICAgICAgICBtdXRhdGlvbigkc2l0ZUlkOiBJRCEsICRwcm92aWRlcjogU3RyaW5nISwgJHNuYXBzaG90SWQ6IFN0cmluZyEsICRjb25maXJtOiBCb29sZWFuKSB7XG4gICAgICAgICAgcmVzdG9yZUJhY2t1cChzaXRlSWQ6ICRzaXRlSWQsIHByb3ZpZGVyOiAkcHJvdmlkZXIsIHNuYXBzaG90SWQ6ICRzbmFwc2hvdElkLCBjb25maXJtOiAkY29uZmlybSkge1xuICAgICAgICAgICAgc3VjY2VzcyBtZXNzYWdlIGVycm9yXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBgLCB7IHNpdGVJZCwgcHJvdmlkZXI6IGNtZE9wdGlvbnMucHJvdmlkZXIsIHNuYXBzaG90SWQsIGNvbmZpcm06IGNtZE9wdGlvbnMueWVzIHx8IGZhbHNlIH0pO1xuICAgICAgaWYgKCFkYXRhLnJlc3RvcmVCYWNrdXAuc3VjY2Vzcykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoZGF0YS5yZXN0b3JlQmFja3VwLmVycm9yIHx8ICdGYWlsZWQgdG8gcmVzdG9yZSBiYWNrdXAnKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBkYXRhO1xuICAgIH0pO1xuICB9KTtcblxuYmFja3Vwc1xuICAuY29tbWFuZCgnZGVsZXRlIDxzaXRlPiA8c25hcHNob3RJZD4nKVxuICAuZGVzY3JpcHRpb24oJ0RlbGV0ZSBhIGJhY2t1cCcpXG4gIC5vcHRpb24oJy1wLCAtLXByb3ZpZGVyIDxwcm92aWRlcj4nLCAnQmFja3VwIHByb3ZpZGVyIChkcm9wYm94fGdvb2dsZURyaXZlKScsICdkcm9wYm94JylcbiAgLm9wdGlvbignLXksIC0teWVzJywgJ1NraXAgY29uZmlybWF0aW9uJylcbiAgLmFjdGlvbihhc3luYyAoc2l0ZSwgc25hcHNob3RJZCwgY21kT3B0aW9ucykgPT4ge1xuICAgIGF3YWl0IHJ1blNpdGVDb21tYW5kKHNpdGUsIHsgYWN0aW9uOiAnRGVsZXRpbmcgYmFja3VwIGZvcicsIHN1Y2Nlc3NNZXNzYWdlOiAoKSA9PiAnQmFja3VwIGRlbGV0ZWQnIH0sIGFzeW5jIChncWwsIHNpdGVJZCkgPT4ge1xuICAgICAgY29uc3QgZGF0YSA9IGF3YWl0IGdxbC5tdXRhdGU8eyBkZWxldGVCYWNrdXA6IHsgc3VjY2VzczogYm9vbGVhbjsgZXJyb3I6IHN0cmluZyB8IG51bGwgfSB9PihgXG4gICAgICAgIG11dGF0aW9uKCRzaXRlSWQ6IElEISwgJHByb3ZpZGVyOiBTdHJpbmchLCAkc25hcHNob3RJZDogU3RyaW5nISwgJGNvbmZpcm06IEJvb2xlYW4pIHtcbiAgICAgICAgICBkZWxldGVCYWNrdXAoc2l0ZUlkOiAkc2l0ZUlkLCBwcm92aWRlcjogJHByb3ZpZGVyLCBzbmFwc2hvdElkOiAkc25hcHNob3RJZCwgY29uZmlybTogJGNvbmZpcm0pIHtcbiAgICAgICAgICAgIHN1Y2Nlc3MgZXJyb3JcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIGAsIHsgc2l0ZUlkLCBwcm92aWRlcjogY21kT3B0aW9ucy5wcm92aWRlciwgc25hcHNob3RJZCwgY29uZmlybTogY21kT3B0aW9ucy55ZXMgfHwgZmFsc2UgfSk7XG4gICAgICBpZiAoIWRhdGEuZGVsZXRlQmFja3VwLnN1Y2Nlc3MpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGRhdGEuZGVsZXRlQmFja3VwLmVycm9yIHx8ICdGYWlsZWQgdG8gZGVsZXRlIGJhY2t1cCcpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGRhdGE7XG4gICAgfSk7XG4gIH0pO1xuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBXUCBFbmdpbmUgQ29tbWFuZHNcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuY29uc3Qgd3BlID0gcHJvZ3JhbS5jb21tYW5kKCd3cGUnKS5kZXNjcmlwdGlvbignV1AgRW5naW5lIHN5bmMgb3BlcmF0aW9ucycpO1xuXG53cGVcbiAgLmNvbW1hbmQoJ3N0YXR1cycpXG4gIC5kZXNjcmlwdGlvbignQ2hlY2sgV1AgRW5naW5lIGF1dGhlbnRpY2F0aW9uIHN0YXR1cycpXG4gIC5hY3Rpb24oYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGdsb2JhbE9wdHMgPSBwcm9ncmFtLm9wdHMoKSBhcyBGb3JtYXR0ZXJPcHRpb25zO1xuICAgIGNvbnN0IGZvcm1hdCA9IGdldE91dHB1dEZvcm1hdChnbG9iYWxPcHRzKTtcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCBncWwgPSBhd2FpdCBlbnN1cmVDb25uZWN0ZWQoZ2xvYmFsT3B0cyk7XG5cbiAgICAgIGNvbnN0IGRhdGEgPSBhd2FpdCBncWwucXVlcnk8eyB3cGVTdGF0dXM6IHsgYXV0aGVudGljYXRlZDogYm9vbGVhbjsgZW1haWw6IHN0cmluZzsgYWNjb3VudElkOiBzdHJpbmc7IGFjY291bnROYW1lOiBzdHJpbmcgfSB9PihgXG4gICAgICAgIHF1ZXJ5IHtcbiAgICAgICAgICB3cGVTdGF0dXMge1xuICAgICAgICAgICAgYXV0aGVudGljYXRlZFxuICAgICAgICAgICAgZW1haWxcbiAgICAgICAgICAgIGFjY291bnRJZFxuICAgICAgICAgICAgYWNjb3VudE5hbWVcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIGApO1xuXG4gICAgICBpZiAoZm9ybWF0ID09PSAnanNvbicpIHtcbiAgICAgICAgY29uc29sZS5sb2coSlNPTi5zdHJpbmdpZnkoZGF0YS53cGVTdGF0dXMsIG51bGwsIDIpKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IHN0YXR1cyA9IGRhdGEud3BlU3RhdHVzO1xuICAgICAgICBpZiAoc3RhdHVzLmF1dGhlbnRpY2F0ZWQpIHtcbiAgICAgICAgICBjb25zb2xlLmxvZyhgXFxuV1AgRW5naW5lOiBDb25uZWN0ZWRgKTtcbiAgICAgICAgICBjb25zb2xlLmxvZyhgICBFbWFpbDogJHtzdGF0dXMuZW1haWx9YCk7XG4gICAgICAgICAgY29uc29sZS5sb2coYCAgQWNjb3VudDogJHtzdGF0dXMuYWNjb3VudE5hbWV9ICgke3N0YXR1cy5hY2NvdW50SWR9KWApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGNvbnNvbGUubG9nKGBcXG5XUCBFbmdpbmU6IE5vdCBjb25uZWN0ZWRgKTtcbiAgICAgICAgICBjb25zb2xlLmxvZyhgICBSdW4gJ2x3cCB3cGUgbG9naW4nIHRvIGF1dGhlbnRpY2F0ZWApO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgICAgY29uc29sZS5lcnJvcihmb3JtYXRFcnJvcihlcnJvci5tZXNzYWdlKSk7XG4gICAgICBwcm9jZXNzLmV4aXQoMSk7XG4gICAgfVxuICB9KTtcblxud3BlXG4gIC5jb21tYW5kKCdsb2dpbicpXG4gIC5kZXNjcmlwdGlvbignQXV0aGVudGljYXRlIHdpdGggV1AgRW5naW5lJylcbiAgLmFjdGlvbihhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgZ2xvYmFsT3B0cyA9IHByb2dyYW0ub3B0cygpIGFzIEZvcm1hdHRlck9wdGlvbnM7XG4gICAgY29uc3Qgc3Bpbm5lciA9IGdsb2JhbE9wdHMucXVpZXQgPyBudWxsIDogb3JhKGBPcGVuaW5nIFdQIEVuZ2luZSBsb2dpbi4uLmApLnN0YXJ0KCk7XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgZ3FsID0gYXdhaXQgZW5zdXJlQ29ubmVjdGVkKGdsb2JhbE9wdHMpO1xuXG4gICAgICBjb25zdCBkYXRhID0gYXdhaXQgZ3FsLm11dGF0ZTx7IHdwZUF1dGhlbnRpY2F0ZTogeyBzdWNjZXNzOiBib29sZWFuOyBlbWFpbDogc3RyaW5nOyBtZXNzYWdlOiBzdHJpbmc7IGVycm9yOiBzdHJpbmcgfCBudWxsIH0gfT4oYFxuICAgICAgICBtdXRhdGlvbiB7XG4gICAgICAgICAgd3BlQXV0aGVudGljYXRlIHsgc3VjY2VzcyBlbWFpbCBtZXNzYWdlIGVycm9yIH1cbiAgICAgICAgfVxuICAgICAgYCk7XG5cbiAgICAgIGlmICghZGF0YS53cGVBdXRoZW50aWNhdGUuc3VjY2Vzcykge1xuICAgICAgICBzcGlubmVyPy5mYWlsKCdBdXRoZW50aWNhdGlvbiBmYWlsZWQnKTtcbiAgICAgICAgY29uc29sZS5lcnJvcihmb3JtYXRFcnJvcihkYXRhLndwZUF1dGhlbnRpY2F0ZS5lcnJvciB8fCAnRmFpbGVkIHRvIGF1dGhlbnRpY2F0ZScpKTtcbiAgICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgICAgfVxuXG4gICAgICBzcGlubmVyPy5zdWNjZWVkKGBBdXRoZW50aWNhdGVkIGFzICR7ZGF0YS53cGVBdXRoZW50aWNhdGUuZW1haWx9YCk7XG4gICAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgICAgc3Bpbm5lcj8uZmFpbCgnQXV0aGVudGljYXRpb24gZmFpbGVkJyk7XG4gICAgICBjb25zb2xlLmVycm9yKGZvcm1hdEVycm9yKGVycm9yLm1lc3NhZ2UpKTtcbiAgICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgICB9XG4gIH0pO1xuXG53cGVcbiAgLmNvbW1hbmQoJ2xvZ291dCcpXG4gIC5kZXNjcmlwdGlvbignTG9nb3V0IGZyb20gV1AgRW5naW5lJylcbiAgLmFjdGlvbihhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgZ2xvYmFsT3B0cyA9IHByb2dyYW0ub3B0cygpIGFzIEZvcm1hdHRlck9wdGlvbnM7XG4gICAgY29uc3Qgc3Bpbm5lciA9IGdsb2JhbE9wdHMucXVpZXQgPyBudWxsIDogb3JhKGBMb2dnaW5nIG91dC4uLmApLnN0YXJ0KCk7XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgZ3FsID0gYXdhaXQgZW5zdXJlQ29ubmVjdGVkKGdsb2JhbE9wdHMpO1xuXG4gICAgICBjb25zdCBkYXRhID0gYXdhaXQgZ3FsLm11dGF0ZTx7IHdwZUxvZ291dDogeyBzdWNjZXNzOiBib29sZWFuOyBlcnJvcjogc3RyaW5nIHwgbnVsbCB9IH0+KGBcbiAgICAgICAgbXV0YXRpb24ge1xuICAgICAgICAgIHdwZUxvZ291dCB7IHN1Y2Nlc3MgZXJyb3IgfVxuICAgICAgICB9XG4gICAgICBgKTtcblxuICAgICAgaWYgKCFkYXRhLndwZUxvZ291dC5zdWNjZXNzKSB7XG4gICAgICAgIHNwaW5uZXI/LmZhaWwoJ0xvZ291dCBmYWlsZWQnKTtcbiAgICAgICAgY29uc29sZS5lcnJvcihmb3JtYXRFcnJvcihkYXRhLndwZUxvZ291dC5lcnJvciB8fCAnRmFpbGVkIHRvIGxvZ291dCcpKTtcbiAgICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgICAgfVxuXG4gICAgICBzcGlubmVyPy5zdWNjZWVkKCdMb2dnZWQgb3V0IGZyb20gV1AgRW5naW5lJyk7XG4gICAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgICAgc3Bpbm5lcj8uZmFpbCgnTG9nb3V0IGZhaWxlZCcpO1xuICAgICAgY29uc29sZS5lcnJvcihmb3JtYXRFcnJvcihlcnJvci5tZXNzYWdlKSk7XG4gICAgICBwcm9jZXNzLmV4aXQoMSk7XG4gICAgfVxuICB9KTtcblxud3BlXG4gIC5jb21tYW5kKCdzaXRlcycpXG4gIC5kZXNjcmlwdGlvbignTGlzdCBXUCBFbmdpbmUgc2l0ZXMnKVxuICAuYWN0aW9uKGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBnbG9iYWxPcHRzID0gcHJvZ3JhbS5vcHRzKCkgYXMgRm9ybWF0dGVyT3B0aW9ucztcbiAgICBjb25zdCBmb3JtYXQgPSBnZXRPdXRwdXRGb3JtYXQoZ2xvYmFsT3B0cyk7XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgZ3FsID0gYXdhaXQgZW5zdXJlQ29ubmVjdGVkKGdsb2JhbE9wdHMpO1xuXG4gICAgICBjb25zdCBkYXRhID0gYXdhaXQgZ3FsLnF1ZXJ5PHsgbGlzdFdwZVNpdGVzOiB7IHN1Y2Nlc3M6IGJvb2xlYW47IHNpdGVzOiBBcnJheTx7IGlkOiBzdHJpbmc7IG5hbWU6IHN0cmluZzsgZW52aXJvbm1lbnQ6IHN0cmluZzsgcHJpbWFyeURvbWFpbjogc3RyaW5nIH0+OyBlcnJvcjogc3RyaW5nIHwgbnVsbCB9IH0+KGBcbiAgICAgICAgcXVlcnkge1xuICAgICAgICAgIGxpc3RXcGVTaXRlcyB7XG4gICAgICAgICAgICBzdWNjZXNzXG4gICAgICAgICAgICBzaXRlcyB7IGlkIG5hbWUgZW52aXJvbm1lbnQgcHJpbWFyeURvbWFpbiB9XG4gICAgICAgICAgICBlcnJvclxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgYCk7XG5cbiAgICAgIGlmICghZGF0YS5saXN0V3BlU2l0ZXMuc3VjY2Vzcykge1xuICAgICAgICBjb25zb2xlLmVycm9yKGZvcm1hdEVycm9yKGRhdGEubGlzdFdwZVNpdGVzLmVycm9yIHx8ICdGYWlsZWQgdG8gbGlzdCBzaXRlcycpKTtcbiAgICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgICAgfVxuXG4gICAgICBpZiAoZm9ybWF0ID09PSAnanNvbicpIHtcbiAgICAgICAgY29uc29sZS5sb2coSlNPTi5zdHJpbmdpZnkoZGF0YS5saXN0V3BlU2l0ZXMuc2l0ZXMsIG51bGwsIDIpKTtcbiAgICAgIH0gZWxzZSBpZiAoZGF0YS5saXN0V3BlU2l0ZXMuc2l0ZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCdObyBXUCBFbmdpbmUgc2l0ZXMgZm91bmQuJyk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zb2xlLmxvZygnXFxuV1AgRW5naW5lIFNpdGVzOicpO1xuICAgICAgICBmb3IgKGNvbnN0IHNpdGUgb2YgZGF0YS5saXN0V3BlU2l0ZXMuc2l0ZXMpIHtcbiAgICAgICAgICBjb25zb2xlLmxvZyhgICAke3NpdGUubmFtZX0gKCR7c2l0ZS5lbnZpcm9ubWVudH0pIC0gJHtzaXRlLnByaW1hcnlEb21haW59YCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcjogYW55KSB7XG4gICAgICBjb25zb2xlLmVycm9yKGZvcm1hdEVycm9yKGVycm9yLm1lc3NhZ2UpKTtcbiAgICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgICB9XG4gIH0pO1xuXG53cGVcbiAgLmNvbW1hbmQoJ2xpbmsgPHNpdGU+JylcbiAgLmRlc2NyaXB0aW9uKCdTaG93IFdQIEVuZ2luZSBjb25uZWN0aW9uIGZvciBhIGxvY2FsIHNpdGUnKVxuICAuYWN0aW9uKGFzeW5jIChzaXRlKSA9PiB7XG4gICAgY29uc3QgZ2xvYmFsT3B0cyA9IHByb2dyYW0ub3B0cygpIGFzIEZvcm1hdHRlck9wdGlvbnM7XG4gICAgY29uc3QgZm9ybWF0ID0gZ2V0T3V0cHV0Rm9ybWF0KGdsb2JhbE9wdHMpO1xuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGdxbCA9IGF3YWl0IGVuc3VyZUNvbm5lY3RlZChnbG9iYWxPcHRzKTtcbiAgICAgIGNvbnN0IHNpdGVJZCA9IGF3YWl0IGZpbmRTaXRlSWQoZ3FsLCBzaXRlKTtcblxuICAgICAgY29uc3QgZGF0YSA9IGF3YWl0IGdxbC5xdWVyeTx7IGdldFdwZUxpbms6IHsgbGlua2VkOiBib29sZWFuOyBzaXRlTmFtZTogc3RyaW5nOyBjb25uZWN0aW9uczogQXJyYXk8eyByZW1vdGVJbnN0YWxsSWQ6IHN0cmluZzsgaW5zdGFsbE5hbWU6IHN0cmluZzsgZW52aXJvbm1lbnQ6IHN0cmluZzsgcHJpbWFyeURvbWFpbjogc3RyaW5nIH0+IH0gfT4oYFxuICAgICAgICBxdWVyeSgkc2l0ZUlkOiBJRCEpIHtcbiAgICAgICAgICBnZXRXcGVMaW5rKHNpdGVJZDogJHNpdGVJZCkge1xuICAgICAgICAgICAgbGlua2VkXG4gICAgICAgICAgICBzaXRlTmFtZVxuICAgICAgICAgICAgY29ubmVjdGlvbnMgeyByZW1vdGVJbnN0YWxsSWQgaW5zdGFsbE5hbWUgZW52aXJvbm1lbnQgcHJpbWFyeURvbWFpbiB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBgLCB7IHNpdGVJZCB9KTtcblxuICAgICAgaWYgKGZvcm1hdCA9PT0gJ2pzb24nKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKEpTT04uc3RyaW5naWZ5KGRhdGEuZ2V0V3BlTGluaywgbnVsbCwgMikpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgbGluayA9IGRhdGEuZ2V0V3BlTGluaztcbiAgICAgICAgaWYgKCFsaW5rLmxpbmtlZCB8fCBsaW5rLmNvbm5lY3Rpb25zLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgIGNvbnNvbGUubG9nKGBcXG5cIiR7bGluay5zaXRlTmFtZX1cIiBpcyBub3QgbGlua2VkIHRvIFdQIEVuZ2luZWApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGNvbnNvbGUubG9nKGBcXG5cIiR7bGluay5zaXRlTmFtZX1cIiBXUCBFbmdpbmUgQ29ubmVjdGlvbnM6YCk7XG4gICAgICAgICAgZm9yIChjb25zdCBjb25uIG9mIGxpbmsuY29ubmVjdGlvbnMpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKGAgICR7Y29ubi5pbnN0YWxsTmFtZX0gKCR7Y29ubi5lbnZpcm9ubWVudH0pIC0gJHtjb25uLnByaW1hcnlEb21haW59YCk7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgICAgIElEOiAke2Nvbm4ucmVtb3RlSW5zdGFsbElkfWApO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yOiBhbnkpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoZm9ybWF0RXJyb3IoZXJyb3IubWVzc2FnZSkpO1xuICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgIH1cbiAgfSk7XG5cbndwZVxuICAuY29tbWFuZCgncHVzaCA8c2l0ZT4nKVxuICAuZGVzY3JpcHRpb24oJ1B1c2ggbG9jYWwgc2l0ZSB0byBXUCBFbmdpbmUnKVxuICAub3B0aW9uKCctciwgLS1yZW1vdGUgPGluc3RhbGxJZD4nLCAnUmVtb3RlIGluc3RhbGwgSUQnKVxuICAub3B0aW9uKCctLXNxbCcsICdJbmNsdWRlIGRhdGFiYXNlJylcbiAgLm9wdGlvbignLXksIC0teWVzJywgJ1NraXAgY29uZmlybWF0aW9uJylcbiAgLmFjdGlvbihhc3luYyAoc2l0ZSwgY21kT3B0aW9ucykgPT4ge1xuICAgIGF3YWl0IHJ1blNpdGVDb21tYW5kKHNpdGUsIHsgYWN0aW9uOiAnUHVzaGluZyB0byBXUCBFbmdpbmUnLCBzdWNjZXNzTWVzc2FnZTogKGRhdGE6IHsgcHVzaFRvV3BlOiB7IG1lc3NhZ2U6IHN0cmluZyB9IH0pID0+IGRhdGEucHVzaFRvV3BlLm1lc3NhZ2UgfHwgJ1B1c2hlZCB0byBXUCBFbmdpbmUnIH0sIGFzeW5jIChncWwsIHNpdGVJZCkgPT4ge1xuICAgICAgLy8gR2V0IHJlbW90ZSBpbnN0YWxsIElEIGlmIG5vdCBwcm92aWRlZFxuICAgICAgbGV0IHJlbW90ZUluc3RhbGxJZCA9IGNtZE9wdGlvbnMucmVtb3RlO1xuICAgICAgaWYgKCFyZW1vdGVJbnN0YWxsSWQpIHtcbiAgICAgICAgY29uc3QgbGlua0RhdGEgPSBhd2FpdCBncWwucXVlcnk8eyBnZXRXcGVMaW5rOiB7IGNvbm5lY3Rpb25zOiBBcnJheTx7IHJlbW90ZUluc3RhbGxJZDogc3RyaW5nIH0+IH0gfT4oYFxuICAgICAgICAgIHF1ZXJ5KCRzaXRlSWQ6IElEISkge1xuICAgICAgICAgICAgZ2V0V3BlTGluayhzaXRlSWQ6ICRzaXRlSWQpIHtcbiAgICAgICAgICAgICAgY29ubmVjdGlvbnMgeyByZW1vdGVJbnN0YWxsSWQgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgYCwgeyBzaXRlSWQgfSk7XG4gICAgICAgIGlmIChsaW5rRGF0YS5nZXRXcGVMaW5rLmNvbm5lY3Rpb25zLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignU2l0ZSBpcyBub3QgbGlua2VkIHRvIFdQIEVuZ2luZS4gVXNlIC0tcmVtb3RlIHRvIHNwZWNpZnkgaW5zdGFsbCBJRC4nKTtcbiAgICAgICAgfVxuICAgICAgICByZW1vdGVJbnN0YWxsSWQgPSBsaW5rRGF0YS5nZXRXcGVMaW5rLmNvbm5lY3Rpb25zWzBdLnJlbW90ZUluc3RhbGxJZDtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGRhdGEgPSBhd2FpdCBncWwubXV0YXRlPHsgcHVzaFRvV3BlOiB7IHN1Y2Nlc3M6IGJvb2xlYW47IG1lc3NhZ2U6IHN0cmluZzsgZXJyb3I6IHN0cmluZyB8IG51bGwgfSB9PihgXG4gICAgICAgIG11dGF0aW9uKCRsb2NhbFNpdGVJZDogSUQhLCAkcmVtb3RlSW5zdGFsbElkOiBJRCEsICRpbmNsdWRlU3FsOiBCb29sZWFuLCAkY29uZmlybTogQm9vbGVhbikge1xuICAgICAgICAgIHB1c2hUb1dwZShsb2NhbFNpdGVJZDogJGxvY2FsU2l0ZUlkLCByZW1vdGVJbnN0YWxsSWQ6ICRyZW1vdGVJbnN0YWxsSWQsIGluY2x1ZGVTcWw6ICRpbmNsdWRlU3FsLCBjb25maXJtOiAkY29uZmlybSkge1xuICAgICAgICAgICAgc3VjY2VzcyBtZXNzYWdlIGVycm9yXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBgLCB7IGxvY2FsU2l0ZUlkOiBzaXRlSWQsIHJlbW90ZUluc3RhbGxJZCwgaW5jbHVkZVNxbDogY21kT3B0aW9ucy5zcWwgfHwgZmFsc2UsIGNvbmZpcm06IGNtZE9wdGlvbnMueWVzIHx8IGZhbHNlIH0pO1xuICAgICAgaWYgKCFkYXRhLnB1c2hUb1dwZS5zdWNjZXNzKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihkYXRhLnB1c2hUb1dwZS5lcnJvciB8fCAnRmFpbGVkIHRvIHB1c2ggdG8gV1AgRW5naW5lJyk7XG4gICAgICB9XG4gICAgICByZXR1cm4gZGF0YTtcbiAgICB9KTtcbiAgfSk7XG5cbndwZVxuICAuY29tbWFuZCgncHVsbCA8c2l0ZT4nKVxuICAuZGVzY3JpcHRpb24oJ1B1bGwgZnJvbSBXUCBFbmdpbmUgdG8gbG9jYWwgc2l0ZScpXG4gIC5vcHRpb24oJy1yLCAtLXJlbW90ZSA8aW5zdGFsbElkPicsICdSZW1vdGUgaW5zdGFsbCBJRCcpXG4gIC5vcHRpb24oJy0tc3FsJywgJ0luY2x1ZGUgZGF0YWJhc2UnKVxuICAuYWN0aW9uKGFzeW5jIChzaXRlLCBjbWRPcHRpb25zKSA9PiB7XG4gICAgYXdhaXQgcnVuU2l0ZUNvbW1hbmQoc2l0ZSwgeyBhY3Rpb246ICdQdWxsaW5nIGZyb20gV1AgRW5naW5lIGZvcicsIHN1Y2Nlc3NNZXNzYWdlOiAoZGF0YTogeyBwdWxsRnJvbVdwZTogeyBtZXNzYWdlOiBzdHJpbmcgfSB9KSA9PiBkYXRhLnB1bGxGcm9tV3BlLm1lc3NhZ2UgfHwgJ1B1bGxlZCBmcm9tIFdQIEVuZ2luZScgfSwgYXN5bmMgKGdxbCwgc2l0ZUlkKSA9PiB7XG4gICAgICAvLyBHZXQgcmVtb3RlIGluc3RhbGwgSUQgaWYgbm90IHByb3ZpZGVkXG4gICAgICBsZXQgcmVtb3RlSW5zdGFsbElkID0gY21kT3B0aW9ucy5yZW1vdGU7XG4gICAgICBpZiAoIXJlbW90ZUluc3RhbGxJZCkge1xuICAgICAgICBjb25zdCBsaW5rRGF0YSA9IGF3YWl0IGdxbC5xdWVyeTx7IGdldFdwZUxpbms6IHsgY29ubmVjdGlvbnM6IEFycmF5PHsgcmVtb3RlSW5zdGFsbElkOiBzdHJpbmcgfT4gfSB9PihgXG4gICAgICAgICAgcXVlcnkoJHNpdGVJZDogSUQhKSB7XG4gICAgICAgICAgICBnZXRXcGVMaW5rKHNpdGVJZDogJHNpdGVJZCkge1xuICAgICAgICAgICAgICBjb25uZWN0aW9ucyB7IHJlbW90ZUluc3RhbGxJZCB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICBgLCB7IHNpdGVJZCB9KTtcbiAgICAgICAgaWYgKGxpbmtEYXRhLmdldFdwZUxpbmsuY29ubmVjdGlvbnMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdTaXRlIGlzIG5vdCBsaW5rZWQgdG8gV1AgRW5naW5lLiBVc2UgLS1yZW1vdGUgdG8gc3BlY2lmeSBpbnN0YWxsIElELicpO1xuICAgICAgICB9XG4gICAgICAgIHJlbW90ZUluc3RhbGxJZCA9IGxpbmtEYXRhLmdldFdwZUxpbmsuY29ubmVjdGlvbnNbMF0ucmVtb3RlSW5zdGFsbElkO1xuICAgICAgfVxuICAgICAgY29uc3QgZGF0YSA9IGF3YWl0IGdxbC5tdXRhdGU8eyBwdWxsRnJvbVdwZTogeyBzdWNjZXNzOiBib29sZWFuOyBtZXNzYWdlOiBzdHJpbmc7IGVycm9yOiBzdHJpbmcgfCBudWxsIH0gfT4oYFxuICAgICAgICBtdXRhdGlvbigkbG9jYWxTaXRlSWQ6IElEISwgJHJlbW90ZUluc3RhbGxJZDogSUQhLCAkaW5jbHVkZVNxbDogQm9vbGVhbikge1xuICAgICAgICAgIHB1bGxGcm9tV3BlKGxvY2FsU2l0ZUlkOiAkbG9jYWxTaXRlSWQsIHJlbW90ZUluc3RhbGxJZDogJHJlbW90ZUluc3RhbGxJZCwgaW5jbHVkZVNxbDogJGluY2x1ZGVTcWwpIHtcbiAgICAgICAgICAgIHN1Y2Nlc3MgbWVzc2FnZSBlcnJvclxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgYCwgeyBsb2NhbFNpdGVJZDogc2l0ZUlkLCByZW1vdGVJbnN0YWxsSWQsIGluY2x1ZGVTcWw6IGNtZE9wdGlvbnMuc3FsIHx8IGZhbHNlIH0pO1xuICAgICAgaWYgKCFkYXRhLnB1bGxGcm9tV3BlLnN1Y2Nlc3MpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGRhdGEucHVsbEZyb21XcGUuZXJyb3IgfHwgJ0ZhaWxlZCB0byBwdWxsIGZyb20gV1AgRW5naW5lJyk7XG4gICAgICB9XG4gICAgICByZXR1cm4gZGF0YTtcbiAgICB9KTtcbiAgfSk7XG5cbndwZVxuICAuY29tbWFuZCgnaGlzdG9yeSA8c2l0ZT4nKVxuICAuZGVzY3JpcHRpb24oJ1Nob3cgc3luYyBoaXN0b3J5IGZvciBhIHNpdGUnKVxuICAub3B0aW9uKCctbCwgLS1saW1pdCA8bj4nLCAnTnVtYmVyIG9mIGV2ZW50cyB0byBzaG93JywgJzEwJylcbiAgLmFjdGlvbihhc3luYyAoc2l0ZSwgY21kT3B0aW9ucykgPT4ge1xuICAgIGNvbnN0IGdsb2JhbE9wdHMgPSBwcm9ncmFtLm9wdHMoKSBhcyBGb3JtYXR0ZXJPcHRpb25zO1xuICAgIGNvbnN0IGZvcm1hdCA9IGdldE91dHB1dEZvcm1hdChnbG9iYWxPcHRzKTtcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCBncWwgPSBhd2FpdCBlbnN1cmVDb25uZWN0ZWQoZ2xvYmFsT3B0cyk7XG4gICAgICBjb25zdCBzaXRlSWQgPSBhd2FpdCBmaW5kU2l0ZUlkKGdxbCwgc2l0ZSk7XG5cbiAgICAgIGNvbnN0IGRhdGEgPSBhd2FpdCBncWwucXVlcnk8eyBnZXRTeW5jSGlzdG9yeTogeyBzdWNjZXNzOiBib29sZWFuOyBldmVudHM6IEFycmF5PHsgcmVtb3RlSW5zdGFsbE5hbWU6IHN0cmluZzsgdGltZXN0YW1wOiBzdHJpbmc7IGRpcmVjdGlvbjogc3RyaW5nOyBzdGF0dXM6IHN0cmluZyB9PjsgZXJyb3I6IHN0cmluZyB8IG51bGwgfSB9PihgXG4gICAgICAgIHF1ZXJ5KCRzaXRlSWQ6IElEISwgJGxpbWl0OiBJbnQpIHtcbiAgICAgICAgICBnZXRTeW5jSGlzdG9yeShzaXRlSWQ6ICRzaXRlSWQsIGxpbWl0OiAkbGltaXQpIHtcbiAgICAgICAgICAgIHN1Y2Nlc3NcbiAgICAgICAgICAgIGV2ZW50cyB7IHJlbW90ZUluc3RhbGxOYW1lIHRpbWVzdGFtcCBkaXJlY3Rpb24gc3RhdHVzIH1cbiAgICAgICAgICAgIGVycm9yXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBgLCB7IHNpdGVJZCwgbGltaXQ6IHBhcnNlSW50KGNtZE9wdGlvbnMubGltaXQsIDEwKSB9KTtcblxuICAgICAgaWYgKCFkYXRhLmdldFN5bmNIaXN0b3J5LnN1Y2Nlc3MpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihmb3JtYXRFcnJvcihkYXRhLmdldFN5bmNIaXN0b3J5LmVycm9yIHx8ICdGYWlsZWQgdG8gZ2V0IHN5bmMgaGlzdG9yeScpKTtcbiAgICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgICAgfVxuXG4gICAgICBpZiAoZm9ybWF0ID09PSAnanNvbicpIHtcbiAgICAgICAgY29uc29sZS5sb2coSlNPTi5zdHJpbmdpZnkoZGF0YS5nZXRTeW5jSGlzdG9yeS5ldmVudHMsIG51bGwsIDIpKTtcbiAgICAgIH0gZWxzZSBpZiAoZGF0YS5nZXRTeW5jSGlzdG9yeS5ldmVudHMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCdObyBzeW5jIGhpc3RvcnkgZm91bmQuJyk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zb2xlLmxvZygnXFxuU3luYyBIaXN0b3J5OicpO1xuICAgICAgICBmb3IgKGNvbnN0IGV2ZW50IG9mIGRhdGEuZ2V0U3luY0hpc3RvcnkuZXZlbnRzKSB7XG4gICAgICAgICAgY29uc3QgZGF0ZSA9IG5ldyBEYXRlKGV2ZW50LnRpbWVzdGFtcCkudG9Mb2NhbGVTdHJpbmcoKTtcbiAgICAgICAgICBjb25zdCBhcnJvdyA9IGV2ZW50LmRpcmVjdGlvbiA9PT0gJ3B1c2gnID8gJ+KGkicgOiAn4oaQJztcbiAgICAgICAgICBjb25zb2xlLmxvZyhgICAke2RhdGV9ICR7YXJyb3d9ICR7ZXZlbnQucmVtb3RlSW5zdGFsbE5hbWV9ICgke2V2ZW50LnN0YXR1c30pYCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcjogYW55KSB7XG4gICAgICBjb25zb2xlLmVycm9yKGZvcm1hdEVycm9yKGVycm9yLm1lc3NhZ2UpKTtcbiAgICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgICB9XG4gIH0pO1xuXG53cGVcbiAgLmNvbW1hbmQoJ2RpZmYgPHNpdGU+JylcbiAgLmRlc2NyaXB0aW9uKCdTaG93IGZpbGUgY2hhbmdlcyBiZXR3ZWVuIGxvY2FsIGFuZCBXUCBFbmdpbmUnKVxuICAub3B0aW9uKCctZCwgLS1kaXJlY3Rpb24gPGRpcj4nLCAnRGlyZWN0aW9uIChwdXNofHB1bGwpJywgJ3B1c2gnKVxuICAuYWN0aW9uKGFzeW5jIChzaXRlLCBjbWRPcHRpb25zKSA9PiB7XG4gICAgY29uc3QgZ2xvYmFsT3B0cyA9IHByb2dyYW0ub3B0cygpIGFzIEZvcm1hdHRlck9wdGlvbnM7XG4gICAgY29uc3QgZm9ybWF0ID0gZ2V0T3V0cHV0Rm9ybWF0KGdsb2JhbE9wdHMpO1xuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGdxbCA9IGF3YWl0IGVuc3VyZUNvbm5lY3RlZChnbG9iYWxPcHRzKTtcbiAgICAgIGNvbnN0IHNpdGVJZCA9IGF3YWl0IGZpbmRTaXRlSWQoZ3FsLCBzaXRlKTtcblxuICAgICAgY29uc3QgZGF0YSA9IGF3YWl0IGdxbC5xdWVyeTx7IGdldFNpdGVDaGFuZ2VzOiB7IHN1Y2Nlc3M6IGJvb2xlYW47IGFkZGVkOiBBcnJheTx7IHBhdGg6IHN0cmluZyB9PjsgbW9kaWZpZWQ6IEFycmF5PHsgcGF0aDogc3RyaW5nIH0+OyBkZWxldGVkOiBBcnJheTx7IHBhdGg6IHN0cmluZyB9PjsgdG90YWxDaGFuZ2VzOiBudW1iZXI7IGVycm9yOiBzdHJpbmcgfCBudWxsIH0gfT4oYFxuICAgICAgICBxdWVyeSgkc2l0ZUlkOiBJRCEsICRkaXJlY3Rpb246IFN0cmluZykge1xuICAgICAgICAgIGdldFNpdGVDaGFuZ2VzKHNpdGVJZDogJHNpdGVJZCwgZGlyZWN0aW9uOiAkZGlyZWN0aW9uKSB7XG4gICAgICAgICAgICBzdWNjZXNzXG4gICAgICAgICAgICBhZGRlZCB7IHBhdGggfVxuICAgICAgICAgICAgbW9kaWZpZWQgeyBwYXRoIH1cbiAgICAgICAgICAgIGRlbGV0ZWQgeyBwYXRoIH1cbiAgICAgICAgICAgIHRvdGFsQ2hhbmdlc1xuICAgICAgICAgICAgZXJyb3JcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIGAsIHsgc2l0ZUlkLCBkaXJlY3Rpb246IGNtZE9wdGlvbnMuZGlyZWN0aW9uIH0pO1xuXG4gICAgICBpZiAoIWRhdGEuZ2V0U2l0ZUNoYW5nZXMuc3VjY2Vzcykge1xuICAgICAgICBjb25zb2xlLmVycm9yKGZvcm1hdEVycm9yKGRhdGEuZ2V0U2l0ZUNoYW5nZXMuZXJyb3IgfHwgJ0ZhaWxlZCB0byBnZXQgY2hhbmdlcycpKTtcbiAgICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgICAgfVxuXG4gICAgICBpZiAoZm9ybWF0ID09PSAnanNvbicpIHtcbiAgICAgICAgY29uc29sZS5sb2coSlNPTi5zdHJpbmdpZnkoZGF0YS5nZXRTaXRlQ2hhbmdlcywgbnVsbCwgMikpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgY2hhbmdlcyA9IGRhdGEuZ2V0U2l0ZUNoYW5nZXM7XG4gICAgICAgIGNvbnNvbGUubG9nKGBcXG5DaGFuZ2VzIHRvICR7Y21kT3B0aW9ucy5kaXJlY3Rpb259ICgke2NoYW5nZXMudG90YWxDaGFuZ2VzfSB0b3RhbCk6YCk7XG5cbiAgICAgICAgaWYgKGNoYW5nZXMuYWRkZWQubGVuZ3RoID4gMCkge1xuICAgICAgICAgIGNvbnNvbGUubG9nKCdcXG4gIEFkZGVkOicpO1xuICAgICAgICAgIGNoYW5nZXMuYWRkZWQuZm9yRWFjaCgoZikgPT4gY29uc29sZS5sb2coYCAgICArICR7Zi5wYXRofWApKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoY2hhbmdlcy5tb2RpZmllZC5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgY29uc29sZS5sb2coJ1xcbiAgTW9kaWZpZWQ6Jyk7XG4gICAgICAgICAgY2hhbmdlcy5tb2RpZmllZC5mb3JFYWNoKChmKSA9PiBjb25zb2xlLmxvZyhgICAgIH4gJHtmLnBhdGh9YCkpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChjaGFuZ2VzLmRlbGV0ZWQubGVuZ3RoID4gMCkge1xuICAgICAgICAgIGNvbnNvbGUubG9nKCdcXG4gIERlbGV0ZWQ6Jyk7XG4gICAgICAgICAgY2hhbmdlcy5kZWxldGVkLmZvckVhY2goKGYpID0+IGNvbnNvbGUubG9nKGAgICAgLSAke2YucGF0aH1gKSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGNoYW5nZXMudG90YWxDaGFuZ2VzID09PSAwKSB7XG4gICAgICAgICAgY29uc29sZS5sb2coJyAgTm8gY2hhbmdlcyBkZXRlY3RlZC4nKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yOiBhbnkpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoZm9ybWF0RXJyb3IoZXJyb3IubWVzc2FnZSkpO1xuICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgIH1cbiAgfSk7XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIEhlbHBlciBGdW5jdGlvbnNcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuLyoqXG4gKiBGaW5kIHNpdGUgSUQgYnkgbmFtZSBvciBJRFxuICpcbiAqIE9wdGltaXphdGlvbjogRmlyc3QgdHJpZXMgZGlyZWN0IElEIGxvb2t1cCAoTygxKSkgYmVmb3JlIGZhbGxpbmcgYmFjayB0b1xuICogZmV0Y2hpbmcgYWxsIHNpdGVzIGZvciBuYW1lIG1hdGNoaW5nIChPKG4pKS4gVGhpcyBzaWduaWZpY2FudGx5IGltcHJvdmVzXG4gKiBwZXJmb3JtYW5jZSB3aGVuIHVzZXJzIHNwZWNpZnkgc2l0ZSBJRHMgZGlyZWN0bHkuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGZpbmRTaXRlSWQoZ3FsOiBHcmFwaFFMQ2xpZW50LCBzaXRlUXVlcnk6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gIC8vIFRyeSBkaXJlY3QgSUQgbG9va3VwIGZpcnN0IC0gbXVjaCBmYXN0ZXIgZm9yIGV4YWN0IElEIG1hdGNoZXNcbiAgdHJ5IHtcbiAgICBjb25zdCBkaXJlY3RMb29rdXAgPSBhd2FpdCBncWwucXVlcnk8eyBzaXRlOiB7IGlkOiBzdHJpbmcgfSB8IG51bGwgfT4oXG4gICAgICBgcXVlcnkgR2V0U2l0ZUJ5SWQoJGlkOiBJRCEpIHsgc2l0ZShpZDogJGlkKSB7IGlkIH0gfWAsXG4gICAgICB7IGlkOiBzaXRlUXVlcnkgfVxuICAgICk7XG5cbiAgICBpZiAoZGlyZWN0TG9va3VwLnNpdGUpIHtcbiAgICAgIHJldHVybiBkaXJlY3RMb29rdXAuc2l0ZS5pZDtcbiAgICB9XG4gIH0gY2F0Y2gge1xuICAgIC8vIElEIGxvb2t1cCBmYWlsZWQsIGZhbGwgdGhyb3VnaCB0byBuYW1lIHNlYXJjaFxuICB9XG5cbiAgLy8gRmFsbCBiYWNrIHRvIGZldGNoaW5nIGFsbCBzaXRlcyBmb3IgbmFtZSBtYXRjaGluZ1xuICBjb25zdCBkYXRhID0gYXdhaXQgZ3FsLnF1ZXJ5PHsgc2l0ZXM6IEFycmF5PHsgaWQ6IHN0cmluZzsgbmFtZTogc3RyaW5nIH0+IH0+KGBcbiAgICBxdWVyeSB7IHNpdGVzIHsgaWQgbmFtZSB9IH1cbiAgYCk7XG5cbiAgY29uc3Qgc2l0ZSA9IGRhdGEuc2l0ZXMuZmluZChcbiAgICAocykgPT4gcy5uYW1lLnRvTG93ZXJDYXNlKCkuaW5jbHVkZXMoc2l0ZVF1ZXJ5LnRvTG93ZXJDYXNlKCkpXG4gICk7XG5cbiAgaWYgKCFzaXRlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBTaXRlIG5vdCBmb3VuZDogXCIke3NpdGVRdWVyeX1cImApO1xuICB9XG5cbiAgcmV0dXJuIHNpdGUuaWQ7XG59XG5cbi8vIFBhcnNlIGFuZCBleGVjdXRlXG5wcm9ncmFtLnBhcnNlKCk7XG4iXX0=
|