@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.
Files changed (86) hide show
  1. package/addon-dist/bin/mcp-stdio.js +2808 -0
  2. package/addon-dist/lib/common/constants.d.ts +22 -0
  3. package/addon-dist/lib/common/constants.js +26 -0
  4. package/addon-dist/lib/common/theme.d.ts +68 -0
  5. package/addon-dist/lib/common/theme.js +126 -0
  6. package/addon-dist/lib/common/types.d.ts +298 -0
  7. package/addon-dist/lib/common/types.js +6 -0
  8. package/addon-dist/lib/main/config/ConnectionInfo.d.ts +25 -0
  9. package/addon-dist/lib/main/config/ConnectionInfo.js +82 -0
  10. package/addon-dist/lib/main/index.d.ts +12 -0
  11. package/addon-dist/lib/main/index.js +3322 -0
  12. package/addon-dist/lib/main/mcp/McpAuth.d.ts +37 -0
  13. package/addon-dist/lib/main/mcp/McpAuth.js +87 -0
  14. package/addon-dist/lib/main/mcp/McpServer.d.ts +67 -0
  15. package/addon-dist/lib/main/mcp/McpServer.js +343 -0
  16. package/addon-dist/lib/main/mcp/tools/changePhpVersion.d.ts +7 -0
  17. package/addon-dist/lib/main/mcp/tools/changePhpVersion.js +81 -0
  18. package/addon-dist/lib/main/mcp/tools/cloneSite.d.ts +7 -0
  19. package/addon-dist/lib/main/mcp/tools/cloneSite.js +66 -0
  20. package/addon-dist/lib/main/mcp/tools/createSite.d.ts +7 -0
  21. package/addon-dist/lib/main/mcp/tools/createSite.js +137 -0
  22. package/addon-dist/lib/main/mcp/tools/deleteSite.d.ts +7 -0
  23. package/addon-dist/lib/main/mcp/tools/deleteSite.js +72 -0
  24. package/addon-dist/lib/main/mcp/tools/exportDatabase.d.ts +7 -0
  25. package/addon-dist/lib/main/mcp/tools/exportDatabase.js +72 -0
  26. package/addon-dist/lib/main/mcp/tools/exportSite.d.ts +7 -0
  27. package/addon-dist/lib/main/mcp/tools/exportSite.js +103 -0
  28. package/addon-dist/lib/main/mcp/tools/getLocalInfo.d.ts +7 -0
  29. package/addon-dist/lib/main/mcp/tools/getLocalInfo.js +72 -0
  30. package/addon-dist/lib/main/mcp/tools/getSite.d.ts +7 -0
  31. package/addon-dist/lib/main/mcp/tools/getSite.js +68 -0
  32. package/addon-dist/lib/main/mcp/tools/getSiteLogs.d.ts +7 -0
  33. package/addon-dist/lib/main/mcp/tools/getSiteLogs.js +149 -0
  34. package/addon-dist/lib/main/mcp/tools/helpers.d.ts +59 -0
  35. package/addon-dist/lib/main/mcp/tools/helpers.js +179 -0
  36. package/addon-dist/lib/main/mcp/tools/importDatabase.d.ts +7 -0
  37. package/addon-dist/lib/main/mcp/tools/importDatabase.js +109 -0
  38. package/addon-dist/lib/main/mcp/tools/importSite.d.ts +7 -0
  39. package/addon-dist/lib/main/mcp/tools/importSite.js +149 -0
  40. package/addon-dist/lib/main/mcp/tools/index.d.ts +26 -0
  41. package/addon-dist/lib/main/mcp/tools/index.js +117 -0
  42. package/addon-dist/lib/main/mcp/tools/listBlueprints.d.ts +7 -0
  43. package/addon-dist/lib/main/mcp/tools/listBlueprints.js +54 -0
  44. package/addon-dist/lib/main/mcp/tools/listServices.d.ts +7 -0
  45. package/addon-dist/lib/main/mcp/tools/listServices.js +112 -0
  46. package/addon-dist/lib/main/mcp/tools/listSites.d.ts +7 -0
  47. package/addon-dist/lib/main/mcp/tools/listSites.js +62 -0
  48. package/addon-dist/lib/main/mcp/tools/openAdminer.d.ts +7 -0
  49. package/addon-dist/lib/main/mcp/tools/openAdminer.js +59 -0
  50. package/addon-dist/lib/main/mcp/tools/openSite.d.ts +7 -0
  51. package/addon-dist/lib/main/mcp/tools/openSite.js +62 -0
  52. package/addon-dist/lib/main/mcp/tools/renameSite.d.ts +7 -0
  53. package/addon-dist/lib/main/mcp/tools/renameSite.js +70 -0
  54. package/addon-dist/lib/main/mcp/tools/restartSite.d.ts +7 -0
  55. package/addon-dist/lib/main/mcp/tools/restartSite.js +56 -0
  56. package/addon-dist/lib/main/mcp/tools/saveBlueprint.d.ts +7 -0
  57. package/addon-dist/lib/main/mcp/tools/saveBlueprint.js +89 -0
  58. package/addon-dist/lib/main/mcp/tools/startSite.d.ts +7 -0
  59. package/addon-dist/lib/main/mcp/tools/startSite.js +54 -0
  60. package/addon-dist/lib/main/mcp/tools/stopSite.d.ts +7 -0
  61. package/addon-dist/lib/main/mcp/tools/stopSite.js +54 -0
  62. package/addon-dist/lib/main/mcp/tools/toggleXdebug.d.ts +7 -0
  63. package/addon-dist/lib/main/mcp/tools/toggleXdebug.js +69 -0
  64. package/addon-dist/lib/main/mcp/tools/trustSsl.d.ts +7 -0
  65. package/addon-dist/lib/main/mcp/tools/trustSsl.js +59 -0
  66. package/addon-dist/lib/main/mcp/tools/wpCli.d.ts +7 -0
  67. package/addon-dist/lib/main/mcp/tools/wpCli.js +110 -0
  68. package/addon-dist/lib/main.d.ts +1 -0
  69. package/addon-dist/lib/main.js +10 -0
  70. package/addon-dist/lib/renderer/index.d.ts +7 -0
  71. package/addon-dist/lib/renderer/index.js +479 -0
  72. package/addon-dist/package.json +73 -0
  73. package/bin/lwp.js +10 -0
  74. package/lib/bootstrap/index.d.ts +98 -0
  75. package/lib/bootstrap/index.js +493 -0
  76. package/lib/bootstrap/paths.d.ts +28 -0
  77. package/lib/bootstrap/paths.js +96 -0
  78. package/lib/client/GraphQLClient.d.ts +38 -0
  79. package/lib/client/GraphQLClient.js +71 -0
  80. package/lib/client/index.d.ts +4 -0
  81. package/lib/client/index.js +10 -0
  82. package/lib/formatters/index.d.ts +75 -0
  83. package/lib/formatters/index.js +139 -0
  84. package/lib/index.d.ts +8 -0
  85. package/lib/index.js +1173 -0
  86. package/package.json +72 -0
@@ -0,0 +1,3322 @@
1
+ "use strict";
2
+ /**
3
+ * CLI Bridge Addon - Main Process Entry Point
4
+ *
5
+ * This addon extends Local's capabilities:
6
+ * - GraphQL mutations for deleteSite, wpCli (for local-cli)
7
+ * - MCP Server for AI tool integration (Claude Code, ChatGPT, etc.)
8
+ */
9
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
+ desc = { enumerable: true, get: function() { return m[k]; } };
14
+ }
15
+ Object.defineProperty(o, k2, desc);
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
22
+ }) : function(o, v) {
23
+ o["default"] = v;
24
+ });
25
+ var __importStar = (this && this.__importStar) || (function () {
26
+ var ownKeys = function(o) {
27
+ ownKeys = Object.getOwnPropertyNames || function (o) {
28
+ var ar = [];
29
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
30
+ return ar;
31
+ };
32
+ return ownKeys(o);
33
+ };
34
+ return function (mod) {
35
+ if (mod && mod.__esModule) return mod;
36
+ var result = {};
37
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
38
+ __setModuleDefault(result, mod);
39
+ return result;
40
+ };
41
+ })();
42
+ var __importDefault = (this && this.__importDefault) || function (mod) {
43
+ return (mod && mod.__esModule) ? mod : { "default": mod };
44
+ };
45
+ Object.defineProperty(exports, "__esModule", { value: true });
46
+ exports.default = default_1;
47
+ const LocalMain = __importStar(require("@getflywheel/local/main"));
48
+ const electron_1 = require("electron");
49
+ const graphql_tag_1 = __importDefault(require("graphql-tag"));
50
+ const McpServer_1 = require("./mcp/McpServer");
51
+ const constants_1 = require("../common/constants");
52
+ const ADDON_NAME = 'MCP Server';
53
+ let mcpServer = null;
54
+ /**
55
+ * GraphQL type definitions for CLI Bridge
56
+ */
57
+ const typeDefs = (0, graphql_tag_1.default) `
58
+ input DeleteSiteInput {
59
+ "The site ID to delete"
60
+ id: ID!
61
+ "Whether to move site files to trash (true) or just remove from Local (false)"
62
+ trashFiles: Boolean = true
63
+ "Whether to update the hosts file"
64
+ updateHosts: Boolean = true
65
+ }
66
+
67
+ type DeleteSiteResult {
68
+ "Whether the deletion was successful"
69
+ success: Boolean!
70
+ "Error message if deletion failed"
71
+ error: String
72
+ "The ID of the deleted site"
73
+ siteId: ID
74
+ }
75
+
76
+ input WpCliInput {
77
+ "The site ID to run WP-CLI against"
78
+ siteId: ID!
79
+ "WP-CLI command and arguments (e.g., ['plugin', 'list', '--format=json'])"
80
+ args: [String!]!
81
+ "Skip loading plugins (default: true)"
82
+ skipPlugins: Boolean = true
83
+ "Skip loading themes (default: true)"
84
+ skipThemes: Boolean = true
85
+ }
86
+
87
+ type WpCliResult {
88
+ "Whether the command executed successfully"
89
+ success: Boolean!
90
+ "Command output (stdout)"
91
+ output: String
92
+ "Error message if command failed"
93
+ error: String
94
+ }
95
+
96
+ input CreateSiteInput {
97
+ "Site name (required)"
98
+ name: String!
99
+ "PHP version (e.g., '8.2.10'). Uses Local default if not specified."
100
+ phpVersion: String
101
+ "Web server type"
102
+ webServer: String
103
+ "Database type"
104
+ database: String
105
+ "WordPress admin username (default: admin)"
106
+ wpAdminUsername: String
107
+ "WordPress admin password (default: password)"
108
+ wpAdminPassword: String
109
+ "WordPress admin email (default: admin@local.test)"
110
+ wpAdminEmail: String
111
+ "Blueprint name to create site from. Use list_blueprints to see available blueprints."
112
+ blueprint: String
113
+ }
114
+
115
+ type CreateSiteResult {
116
+ "Whether site creation was initiated successfully"
117
+ success: Boolean!
118
+ "Error message if creation failed"
119
+ error: String
120
+ "The created site ID"
121
+ siteId: ID
122
+ "The site name"
123
+ siteName: String
124
+ "The site domain"
125
+ siteDomain: String
126
+ }
127
+
128
+ input OpenSiteInput {
129
+ "The site ID to open"
130
+ siteId: ID!
131
+ "Path to open (default: /, use /wp-admin for admin)"
132
+ path: String = "/"
133
+ }
134
+
135
+ type OpenSiteResult {
136
+ "Whether the site was opened successfully"
137
+ success: Boolean!
138
+ "Error message if failed"
139
+ error: String
140
+ "The URL that was opened"
141
+ url: String
142
+ }
143
+
144
+ input CloneSiteInput {
145
+ "The site ID to clone"
146
+ siteId: ID!
147
+ "Name for the cloned site"
148
+ newName: String!
149
+ }
150
+
151
+ type CloneSiteResult {
152
+ "Whether cloning was successful"
153
+ success: Boolean!
154
+ "Error message if failed"
155
+ error: String
156
+ "The new site ID"
157
+ newSiteId: ID
158
+ "The new site name"
159
+ newSiteName: String
160
+ "The new site domain"
161
+ newSiteDomain: String
162
+ }
163
+
164
+ input ExportSiteInput {
165
+ "The site ID to export"
166
+ siteId: ID!
167
+ "Output directory path (default: ~/Downloads)"
168
+ outputPath: String
169
+ }
170
+
171
+ type ExportSiteResult {
172
+ "Whether export was successful"
173
+ success: Boolean!
174
+ "Error message if failed"
175
+ error: String
176
+ "Path to the exported zip file"
177
+ exportPath: String
178
+ }
179
+
180
+ type Blueprint {
181
+ "Blueprint name"
182
+ name: String!
183
+ "Last modified date"
184
+ lastModified: String
185
+ "PHP version"
186
+ phpVersion: String
187
+ "Web server type"
188
+ webServer: String
189
+ "Database type"
190
+ database: String
191
+ }
192
+
193
+ type BlueprintsResult {
194
+ "Whether query was successful"
195
+ success: Boolean!
196
+ "Error message if failed"
197
+ error: String
198
+ "List of blueprints"
199
+ blueprints: [Blueprint!]
200
+ }
201
+
202
+ input SaveBlueprintInput {
203
+ "The site ID to save as blueprint"
204
+ siteId: ID!
205
+ "Name for the blueprint"
206
+ name: String!
207
+ }
208
+
209
+ type SaveBlueprintResult {
210
+ "Whether save was successful"
211
+ success: Boolean!
212
+ "Error message if failed"
213
+ error: String
214
+ "The blueprint name"
215
+ blueprintName: String
216
+ }
217
+
218
+ # Phase 8: WordPress Development Tools
219
+ input ExportDatabaseInput {
220
+ "The site ID"
221
+ siteId: ID!
222
+ "Output file path (optional, defaults to ~/Downloads/<site-name>.sql)"
223
+ outputPath: String
224
+ }
225
+
226
+ type ExportDatabaseResult {
227
+ "Whether export was successful"
228
+ success: Boolean!
229
+ "Error message if failed"
230
+ error: String
231
+ "Path to the exported SQL file"
232
+ outputPath: String
233
+ }
234
+
235
+ input ImportDatabaseInput {
236
+ "The site ID"
237
+ siteId: ID!
238
+ "Path to the SQL file to import"
239
+ sqlPath: String!
240
+ }
241
+
242
+ type ImportDatabaseResult {
243
+ "Whether import was successful"
244
+ success: Boolean!
245
+ "Error message if failed"
246
+ error: String
247
+ }
248
+
249
+ input OpenAdminerInput {
250
+ "The site ID"
251
+ siteId: ID!
252
+ }
253
+
254
+ type OpenAdminerResult {
255
+ "Whether opening was successful"
256
+ success: Boolean!
257
+ "Error message if failed"
258
+ error: String
259
+ }
260
+
261
+ input TrustSslInput {
262
+ "The site ID"
263
+ siteId: ID!
264
+ }
265
+
266
+ type TrustSslResult {
267
+ "Whether trust was successful"
268
+ success: Boolean!
269
+ "Error message if failed"
270
+ error: String
271
+ }
272
+
273
+ input McpRenameSiteInput {
274
+ "The site ID"
275
+ siteId: ID!
276
+ "New name for the site"
277
+ newName: String!
278
+ }
279
+
280
+ type McpRenameSiteResult {
281
+ "Whether rename was successful"
282
+ success: Boolean!
283
+ "Error message if failed"
284
+ error: String
285
+ "The new name"
286
+ newName: String
287
+ }
288
+
289
+ input ChangePhpVersionInput {
290
+ "The site ID"
291
+ siteId: ID!
292
+ "Target PHP version"
293
+ phpVersion: String!
294
+ }
295
+
296
+ type ChangePhpVersionResult {
297
+ "Whether change was successful"
298
+ success: Boolean!
299
+ "Error message if failed"
300
+ error: String
301
+ "The new PHP version"
302
+ phpVersion: String
303
+ }
304
+
305
+ input ImportSiteInput {
306
+ "Path to the zip file to import"
307
+ zipPath: String!
308
+ "Name for the imported site (optional)"
309
+ siteName: String
310
+ }
311
+
312
+ type ImportSiteResult {
313
+ "Whether import was successful"
314
+ success: Boolean!
315
+ "Error message if failed"
316
+ error: String
317
+ "The imported site ID"
318
+ siteId: ID
319
+ "The imported site name"
320
+ siteName: String
321
+ }
322
+
323
+ # Phase 9: Site Configuration & Dev Tools
324
+ input ToggleXdebugInput {
325
+ "The site ID"
326
+ siteId: ID!
327
+ "Whether to enable or disable Xdebug"
328
+ enabled: Boolean!
329
+ }
330
+
331
+ type ToggleXdebugResult {
332
+ "Whether toggle was successful"
333
+ success: Boolean!
334
+ "Error message if failed"
335
+ error: String
336
+ "Current Xdebug state"
337
+ enabled: Boolean
338
+ }
339
+
340
+ input GetSiteLogsInput {
341
+ "The site ID"
342
+ siteId: ID!
343
+ "Type of logs to retrieve (php, nginx, mysql, all)"
344
+ logType: String = "php"
345
+ "Number of lines to return"
346
+ lines: Int = 100
347
+ }
348
+
349
+ type LogEntry {
350
+ "Log type"
351
+ type: String!
352
+ "Log content"
353
+ content: String!
354
+ "Log file path"
355
+ path: String!
356
+ }
357
+
358
+ type GetSiteLogsResult {
359
+ "Whether retrieval was successful"
360
+ success: Boolean!
361
+ "Error message if failed"
362
+ error: String
363
+ "Log entries"
364
+ logs: [LogEntry!]
365
+ }
366
+
367
+ type ServiceInfo {
368
+ "Service role (php, database, webserver)"
369
+ role: String!
370
+ "Service name"
371
+ name: String!
372
+ "Service version"
373
+ version: String!
374
+ }
375
+
376
+ type ListServicesResult {
377
+ "Whether listing was successful"
378
+ success: Boolean!
379
+ "Error message if failed"
380
+ error: String
381
+ "Available services"
382
+ services: [ServiceInfo!]
383
+ }
384
+
385
+ extend type Mutation {
386
+ "Create a new WordPress site with full WordPress installation"
387
+ createSite(input: CreateSiteInput!): CreateSiteResult!
388
+
389
+ "Delete a site from Local"
390
+ deleteSite(input: DeleteSiteInput!): DeleteSiteResult!
391
+
392
+ "Delete multiple sites from Local"
393
+ deleteSites(ids: [ID!]!, trashFiles: Boolean = true): DeleteSiteResult!
394
+
395
+ "Run a WP-CLI command against a site"
396
+ wpCli(input: WpCliInput!): WpCliResult!
397
+
398
+ "Open a site in the default browser"
399
+ openSite(input: OpenSiteInput!): OpenSiteResult!
400
+
401
+ "Clone an existing site"
402
+ cloneSite(input: CloneSiteInput!): CloneSiteResult!
403
+
404
+ "Export a site to a zip file"
405
+ exportSite(input: ExportSiteInput!): ExportSiteResult!
406
+
407
+ "Save a site as a blueprint"
408
+ saveBlueprint(input: SaveBlueprintInput!): SaveBlueprintResult!
409
+
410
+ # Phase 8: WordPress Development Tools
411
+ "Export site database to SQL file"
412
+ exportDatabase(input: ExportDatabaseInput!): ExportDatabaseResult!
413
+
414
+ "Import SQL file into site database"
415
+ importDatabase(input: ImportDatabaseInput!): ImportDatabaseResult!
416
+
417
+ "Open Adminer database management UI"
418
+ openAdminer(input: OpenAdminerInput!): OpenAdminerResult!
419
+
420
+ "Trust site SSL certificate"
421
+ trustSsl(input: TrustSslInput!): TrustSslResult!
422
+
423
+ "Rename a site (MCP version)"
424
+ mcpRenameSite(input: McpRenameSiteInput!): McpRenameSiteResult!
425
+
426
+ "Change site PHP version"
427
+ changePhpVersion(input: ChangePhpVersionInput!): ChangePhpVersionResult!
428
+
429
+ "Import site from zip file"
430
+ importSite(input: ImportSiteInput!): ImportSiteResult!
431
+
432
+ # Phase 9: Site Configuration & Dev Tools
433
+ "Toggle Xdebug for a site"
434
+ toggleXdebug(input: ToggleXdebugInput!): ToggleXdebugResult!
435
+
436
+ "Get site log files"
437
+ getSiteLogs(input: GetSiteLogsInput!): GetSiteLogsResult!
438
+ }
439
+
440
+ extend type Query {
441
+ "Run a WP-CLI command against a site (read-only operations)"
442
+ wpCliQuery(input: WpCliInput!): WpCliResult!
443
+
444
+ "List all available blueprints"
445
+ blueprints: BlueprintsResult!
446
+
447
+ "List available service versions"
448
+ listServices(type: String): ListServicesResult!
449
+
450
+ # Phase 11: WP Engine Connect
451
+ "Check WP Engine authentication status"
452
+ wpeStatus: WpeAuthStatus!
453
+
454
+ "List all sites from WP Engine account"
455
+ listWpeSites(accountId: String): ListWpeSitesResult!
456
+
457
+ # Phase 11b: Site Linking
458
+ "Get WP Engine connection details for a local site"
459
+ getWpeLink(siteId: ID!): GetWpeLinkResult!
460
+ }
461
+
462
+ # Phase 11: WP Engine Connect Types
463
+ type WpeAuthStatus {
464
+ "Whether authenticated with WP Engine"
465
+ authenticated: Boolean!
466
+ "User email if authenticated"
467
+ email: String
468
+ "Account ID if authenticated"
469
+ accountId: String
470
+ "Account name if authenticated"
471
+ accountName: String
472
+ "Token expiry time"
473
+ tokenExpiry: String
474
+ "Error message if status check failed"
475
+ error: String
476
+ }
477
+
478
+ type WpeAuthResult {
479
+ "Whether authentication was successful"
480
+ success: Boolean!
481
+ "User email if successful"
482
+ email: String
483
+ "Message about the authentication result"
484
+ message: String
485
+ "Error message if failed"
486
+ error: String
487
+ }
488
+
489
+ type WpeLogoutResult {
490
+ "Whether logout was successful"
491
+ success: Boolean!
492
+ "Message about the logout result"
493
+ message: String
494
+ "Error message if failed"
495
+ error: String
496
+ }
497
+
498
+ type WpeSite {
499
+ "Install ID"
500
+ id: String!
501
+ "Install name"
502
+ name: String!
503
+ "Environment (production, staging, development)"
504
+ environment: String!
505
+ "PHP version"
506
+ phpVersion: String
507
+ "Primary domain"
508
+ primaryDomain: String
509
+ "Account ID"
510
+ accountId: String
511
+ "Account name"
512
+ accountName: String
513
+ "SFTP host"
514
+ sftpHost: String
515
+ "SFTP user"
516
+ sftpUser: String
517
+ }
518
+
519
+ type ListWpeSitesResult {
520
+ "Whether query was successful"
521
+ success: Boolean!
522
+ "Error message if failed"
523
+ error: String
524
+ "List of WP Engine sites"
525
+ sites: [WpeSite!]
526
+ "Total count of sites"
527
+ count: Int
528
+ }
529
+
530
+ # Phase 11b: Site Linking Types
531
+ type WpeConnection {
532
+ "Remote install ID (UUID from WP Engine)"
533
+ remoteInstallId: String!
534
+ "Install name (human-readable, used in portal URLs)"
535
+ installName: String
536
+ "Environment (production, staging, development)"
537
+ environment: String
538
+ "Account ID"
539
+ accountId: String
540
+ "WP Engine portal URL"
541
+ portalUrl: String
542
+ "Primary domain/CNAME"
543
+ primaryDomain: String
544
+ }
545
+
546
+ "Sync capabilities available for WPE-connected sites"
547
+ type WpeSyncCapabilities {
548
+ "Whether user can push to WP Engine"
549
+ canPush: Boolean!
550
+ "Whether user can pull from WP Engine"
551
+ canPull: Boolean!
552
+ "Available sync modes"
553
+ syncModes: [String!]!
554
+ "Whether Magic Sync (select files) is available"
555
+ magicSyncAvailable: Boolean!
556
+ "Whether database sync is available"
557
+ databaseSyncAvailable: Boolean!
558
+ }
559
+
560
+ type GetWpeLinkResult {
561
+ "Whether site is linked to WP Engine"
562
+ linked: Boolean!
563
+ "Site name"
564
+ siteName: String
565
+ "WP Engine connections"
566
+ connections: [WpeConnection!]
567
+ "Number of connections"
568
+ connectionCount: Int
569
+ "Sync capabilities (only present if linked)"
570
+ capabilities: WpeSyncCapabilities
571
+ "Message (for unlinked sites)"
572
+ message: String
573
+ "Error message if failed"
574
+ error: String
575
+ }
576
+
577
+ # Phase 11c: Sync Operations Types
578
+ type SyncHistoryEvent {
579
+ "Remote install name"
580
+ remoteInstallName: String
581
+ "Unix timestamp"
582
+ timestamp: Float!
583
+ "Environment (production, staging, development)"
584
+ environment: String!
585
+ "Sync direction"
586
+ direction: String!
587
+ "Sync status"
588
+ status: String
589
+ }
590
+
591
+ type GetSyncHistoryResult {
592
+ "Whether the query was successful"
593
+ success: Boolean!
594
+ "Site name"
595
+ siteName: String
596
+ "Sync history events"
597
+ events: [SyncHistoryEvent!]
598
+ "Number of events"
599
+ count: Int
600
+ "Error message if failed"
601
+ error: String
602
+ }
603
+
604
+ type SyncResult {
605
+ "Whether the sync was initiated successfully"
606
+ success: Boolean!
607
+ "Status message"
608
+ message: String
609
+ "Error message if failed"
610
+ error: String
611
+ }
612
+
613
+ # File change detection
614
+ type FileChange {
615
+ "File path relative to site root"
616
+ path: String!
617
+ "Change type: create, upload, download, delete, modify"
618
+ instruction: String!
619
+ "File size in bytes"
620
+ size: Int
621
+ "File type: - (file) or d (directory)"
622
+ type: String
623
+ }
624
+
625
+ type GetSiteChangesResult {
626
+ "Whether the query was successful"
627
+ success: Boolean!
628
+ "Site name"
629
+ siteName: String
630
+ "Direction of comparison"
631
+ direction: String
632
+ "Files that would be added/uploaded"
633
+ added: [FileChange!]
634
+ "Files that would be modified"
635
+ modified: [FileChange!]
636
+ "Files that would be deleted"
637
+ deleted: [FileChange!]
638
+ "Total number of changes"
639
+ totalChanges: Int
640
+ "Summary message"
641
+ message: String
642
+ "Error message if failed"
643
+ error: String
644
+ }
645
+
646
+ # Phase 10: Cloud Backup Types
647
+ type BackupProviderStatus {
648
+ "Whether authenticated with provider"
649
+ authenticated: Boolean!
650
+ "Account ID"
651
+ accountId: String
652
+ "Account email"
653
+ email: String
654
+ }
655
+
656
+ type BackupStatusResult {
657
+ "Whether backups are available"
658
+ available: Boolean!
659
+ "Whether the feature is enabled"
660
+ featureEnabled: Boolean!
661
+ "Dropbox authentication status"
662
+ dropbox: BackupProviderStatus
663
+ "Google Drive authentication status"
664
+ googleDrive: BackupProviderStatus
665
+ "Message if backups unavailable"
666
+ message: String
667
+ "Error message if failed"
668
+ error: String
669
+ }
670
+
671
+ type BackupMetadata {
672
+ "Snapshot ID"
673
+ snapshotId: String!
674
+ "Backup timestamp (ISO format)"
675
+ timestamp: String
676
+ "Backup note/description"
677
+ note: String
678
+ "Site domain"
679
+ siteDomain: String
680
+ "Services info (JSON)"
681
+ services: String
682
+ }
683
+
684
+ type ListBackupsResult {
685
+ "Whether query was successful"
686
+ success: Boolean!
687
+ "Site name"
688
+ siteName: String
689
+ "Backup provider"
690
+ provider: String
691
+ "List of backups"
692
+ backups: [BackupMetadata!]
693
+ "Number of backups"
694
+ count: Int
695
+ "Error message if failed"
696
+ error: String
697
+ }
698
+
699
+ type CreateBackupResult {
700
+ "Whether backup was created successfully"
701
+ success: Boolean!
702
+ "Snapshot ID"
703
+ snapshotId: String
704
+ "Backup timestamp"
705
+ timestamp: String
706
+ "Status message"
707
+ message: String
708
+ "Error message if failed"
709
+ error: String
710
+ }
711
+
712
+ type RestoreBackupResult {
713
+ "Whether restore was successful"
714
+ success: Boolean!
715
+ "Status message"
716
+ message: String
717
+ "Error message if failed"
718
+ error: String
719
+ }
720
+
721
+ type DeleteBackupResult {
722
+ "Whether deletion was successful"
723
+ success: Boolean!
724
+ "Deleted snapshot ID"
725
+ deletedSnapshotId: String
726
+ "Status message"
727
+ message: String
728
+ "Error message if failed"
729
+ error: String
730
+ }
731
+
732
+ type DownloadBackupResult {
733
+ "Whether download was successful"
734
+ success: Boolean!
735
+ "Path to downloaded file"
736
+ filePath: String
737
+ "Status message"
738
+ message: String
739
+ "Error message if failed"
740
+ error: String
741
+ }
742
+
743
+ type EditBackupNoteResult {
744
+ "Whether edit was successful"
745
+ success: Boolean!
746
+ "Updated snapshot ID"
747
+ snapshotId: String
748
+ "Updated note"
749
+ note: String
750
+ "Error message if failed"
751
+ error: String
752
+ }
753
+
754
+ extend type Query {
755
+ # Phase 10: Cloud Backups
756
+ "Check if cloud backups are available and authenticated"
757
+ backupStatus: BackupStatusResult!
758
+
759
+ "List all backups for a site"
760
+ listBackups(siteId: ID!, provider: String!): ListBackupsResult!
761
+
762
+ # Phase 11c: Sync Operations
763
+ "Get sync history for a local site"
764
+ getSyncHistory(siteId: ID!, limit: Int): GetSyncHistoryResult!
765
+
766
+ "Get file changes between local site and WP Engine (dry-run comparison)"
767
+ getSiteChanges(siteId: ID!, direction: String = "push"): GetSiteChangesResult!
768
+ }
769
+
770
+ extend type Mutation {
771
+ # Phase 10: Cloud Backups
772
+ "Create a backup of a site to cloud storage"
773
+ createBackup(siteId: ID!, provider: String!, note: String): CreateBackupResult!
774
+
775
+ "Restore a site from a cloud backup"
776
+ restoreBackup(
777
+ siteId: ID!
778
+ provider: String!
779
+ snapshotId: String!
780
+ confirm: Boolean = false
781
+ ): RestoreBackupResult!
782
+
783
+ "Delete a backup from cloud storage"
784
+ deleteBackup(
785
+ siteId: ID!
786
+ provider: String!
787
+ snapshotId: String!
788
+ confirm: Boolean = false
789
+ ): DeleteBackupResult!
790
+
791
+ "Download a backup as a ZIP file"
792
+ downloadBackup(siteId: ID!, provider: String!, snapshotId: String!): DownloadBackupResult!
793
+
794
+ "Update the note/description for a backup"
795
+ editBackupNote(
796
+ siteId: ID!
797
+ provider: String!
798
+ snapshotId: String!
799
+ note: String!
800
+ ): EditBackupNoteResult!
801
+
802
+ # Phase 11: WP Engine Connect
803
+ "Authenticate with WP Engine (opens browser for OAuth)"
804
+ wpeAuthenticate: WpeAuthResult!
805
+
806
+ "Logout from WP Engine"
807
+ wpeLogout: WpeLogoutResult!
808
+
809
+ # Phase 11c: Sync Operations
810
+ "Push local site to WP Engine"
811
+ pushToWpe(
812
+ localSiteId: ID!
813
+ remoteInstallId: ID!
814
+ includeSql: Boolean = false
815
+ confirm: Boolean = false
816
+ ): SyncResult!
817
+
818
+ "Pull from WP Engine to local site"
819
+ pullFromWpe(localSiteId: ID!, remoteInstallId: ID!, includeSql: Boolean = false): SyncResult!
820
+ }
821
+ `;
822
+ /**
823
+ * Create GraphQL resolvers that use Local's internal services
824
+ */
825
+ function createResolvers(services) {
826
+ const { deleteSite: deleteSiteService, siteData, localLogger, wpCli, siteProcessManager, addSite: addSiteService, cloneSite: cloneSiteService, exportSite: exportSiteService, blueprints: blueprintsService, browserManager, adminer, x509Cert, siteProvisioner, importSite: importSiteService, lightningServices, siteDatabase, importSQLFile: importSQLFileService,
827
+ // Phase 11: WP Engine Connect
828
+ wpeOAuth: wpeOAuthService, capi: capiService,
829
+ // Phase 11c: Sync services
830
+ wpePush: wpePushService, wpePull: wpePullService, connectHistory: connectHistoryService, wpeConnectBase: wpeConnectBaseService,
831
+ // Note: Phase 10 Cloud Backup services are accessed via IPC to the Cloud Backups addon
832
+ // (backupService, dropbox, googleDrive, featureFlags, userData)
833
+ } = services;
834
+ // Helper to invoke IPC calls to the Cloud Backups addon
835
+ // This uses the same pattern as the BackupAIBridge
836
+ // Timeout constants for backup operations (in milliseconds)
837
+ const BACKUP_IPC_TIMEOUT = 600000; // 10 minutes for backup operations
838
+ const DEFAULT_IPC_TIMEOUT = 30000; // 30 seconds for quick operations
839
+ const invokeBackupIPC = async (channel, timeoutMs = BACKUP_IPC_TIMEOUT, ...args) => {
840
+ return new Promise((resolve, reject) => {
841
+ const timestamp = Date.now();
842
+ const random = Math.random().toString(36).substr(2, 9);
843
+ const successReplyChannel = `${channel}-success-${timestamp}-${random}`;
844
+ const errorReplyChannel = `${channel}-error-${timestamp}-${random}`;
845
+ const timeoutSeconds = Math.round(timeoutMs / 1000);
846
+ const timeout = setTimeout(() => {
847
+ electron_1.ipcMain.removeAllListeners(successReplyChannel);
848
+ electron_1.ipcMain.removeAllListeners(errorReplyChannel);
849
+ reject(new Error(`IPC call to ${channel} timed out after ${timeoutSeconds} seconds`));
850
+ }, timeoutMs);
851
+ electron_1.ipcMain.once(successReplyChannel, (_event, result) => {
852
+ clearTimeout(timeout);
853
+ electron_1.ipcMain.removeAllListeners(errorReplyChannel);
854
+ localLogger.info(`[${ADDON_NAME}] IPC success from ${channel}`);
855
+ resolve({ result });
856
+ });
857
+ electron_1.ipcMain.once(errorReplyChannel, (_event, error) => {
858
+ clearTimeout(timeout);
859
+ electron_1.ipcMain.removeAllListeners(successReplyChannel);
860
+ localLogger.error(`[${ADDON_NAME}] IPC error from ${channel}: ${error?.message}`);
861
+ resolve({ error });
862
+ });
863
+ const mockEvent = {
864
+ reply: (replyChannel, data) => {
865
+ electron_1.ipcMain.emit(replyChannel, null, data);
866
+ },
867
+ sender: {
868
+ send: (replyChannel, data) => {
869
+ electron_1.ipcMain.emit(replyChannel, null, data);
870
+ },
871
+ },
872
+ };
873
+ const replyChannels = { successReplyChannel, errorReplyChannel };
874
+ localLogger.info(`[${ADDON_NAME}] Invoking backup IPC: ${channel}`);
875
+ electron_1.ipcMain.emit(channel, mockEvent, replyChannels, ...args);
876
+ });
877
+ };
878
+ // Helper to get backup providers from the Cloud Backups addon
879
+ const getBackupProviders = async () => {
880
+ try {
881
+ const result = await invokeBackupIPC('backups:enabled-providers', DEFAULT_IPC_TIMEOUT);
882
+ localLogger.info(`[${ADDON_NAME}] Raw IPC result: ${JSON.stringify(result)}`);
883
+ if (result.error) {
884
+ localLogger.error(`[${ADDON_NAME}] Failed to get backup providers: ${result.error.message}`);
885
+ return [];
886
+ }
887
+ // The response is double-nested: result.result.result contains the array
888
+ // Structure: { result: { result: [providers...] } }
889
+ let providers = result.result;
890
+ // Unwrap nested result if present
891
+ if (providers && typeof providers === 'object' && !Array.isArray(providers)) {
892
+ if (Array.isArray(providers.result)) {
893
+ providers = providers.result;
894
+ }
895
+ else if (providers.result && typeof providers.result === 'object') {
896
+ // Even deeper nesting
897
+ providers = providers.result;
898
+ }
899
+ }
900
+ localLogger.info(`[${ADDON_NAME}] Extracted providers: ${JSON.stringify(providers)}`);
901
+ if (Array.isArray(providers)) {
902
+ localLogger.info(`[${ADDON_NAME}] Got ${providers.length} backup providers`);
903
+ return providers;
904
+ }
905
+ localLogger.warn(`[${ADDON_NAME}] Unexpected providers format after unwrapping: ${typeof providers}`);
906
+ return [];
907
+ }
908
+ catch (error) {
909
+ localLogger.error(`[${ADDON_NAME}] Error getting backup providers: ${error.message}`);
910
+ return [];
911
+ }
912
+ };
913
+ // Shared WP-CLI execution logic
914
+ const executeWpCli = async (_parent, args) => {
915
+ const { siteId, args: wpArgs, skipPlugins = true, skipThemes = true } = args.input;
916
+ try {
917
+ localLogger.info(`[${ADDON_NAME}] Running WP-CLI: wp ${wpArgs.join(' ')}`);
918
+ const site = siteData.getSite(siteId);
919
+ if (!site) {
920
+ return {
921
+ success: false,
922
+ output: null,
923
+ error: `Site not found: ${siteId}`,
924
+ };
925
+ }
926
+ const status = await siteProcessManager.getSiteStatus(site);
927
+ if (status !== 'running') {
928
+ return {
929
+ success: false,
930
+ output: null,
931
+ error: `Site "${site.name}" is not running. Start it first with: local-cli start ${site.name}`,
932
+ };
933
+ }
934
+ const output = await wpCli.run(site, wpArgs, {
935
+ skipPlugins,
936
+ skipThemes,
937
+ ignoreErrors: false,
938
+ });
939
+ localLogger.info(`[${ADDON_NAME}] WP-CLI completed successfully`);
940
+ return {
941
+ success: true,
942
+ output: output?.trim() || '',
943
+ error: null,
944
+ };
945
+ }
946
+ catch (error) {
947
+ localLogger.error(`[${ADDON_NAME}] WP-CLI failed:`, error);
948
+ return {
949
+ success: false,
950
+ output: null,
951
+ error: error.message || 'Unknown error',
952
+ };
953
+ }
954
+ };
955
+ return {
956
+ Query: {
957
+ wpCliQuery: executeWpCli,
958
+ blueprints: async () => {
959
+ try {
960
+ localLogger.info(`[${ADDON_NAME}] Fetching blueprints`);
961
+ const blueprintsList = await blueprintsService.getBlueprints();
962
+ return {
963
+ success: true,
964
+ error: null,
965
+ blueprints: blueprintsList.map((bp) => ({
966
+ name: bp.name,
967
+ lastModified: bp.lastModified,
968
+ // Handle nested objects - extract just the name/type string
969
+ phpVersion: typeof bp.phpVersion === 'object'
970
+ ? bp.phpVersion?.name || bp.phpVersion?.version
971
+ : bp.phpVersion,
972
+ webServer: typeof bp.webServer === 'object'
973
+ ? bp.webServer?.name || bp.webServer?.type
974
+ : bp.webServer,
975
+ database: typeof bp.database === 'object'
976
+ ? bp.database?.name || bp.database?.type
977
+ : bp.database,
978
+ })),
979
+ };
980
+ }
981
+ catch (error) {
982
+ localLogger.error(`[${ADDON_NAME}] Failed to fetch blueprints:`, error);
983
+ return {
984
+ success: false,
985
+ error: error.message || 'Unknown error',
986
+ blueprints: [],
987
+ };
988
+ }
989
+ },
990
+ listServices: async (_parent, args) => {
991
+ const { type = 'all' } = args;
992
+ try {
993
+ localLogger.info(`[${ADDON_NAME}] Listing services (type: ${type})`);
994
+ if (!lightningServices) {
995
+ return {
996
+ success: false,
997
+ error: 'Lightning services not available',
998
+ services: [],
999
+ };
1000
+ }
1001
+ const roleMap = {
1002
+ php: 'php',
1003
+ database: 'mysql',
1004
+ webserver: 'nginx',
1005
+ };
1006
+ const roleFilter = type !== 'all' ? roleMap[type] : undefined;
1007
+ const registeredServices = lightningServices.getRegisteredServices(roleFilter);
1008
+ const serviceList = [];
1009
+ for (const [role, versions] of Object.entries(registeredServices)) {
1010
+ for (const [version, info] of Object.entries(versions)) {
1011
+ serviceList.push({
1012
+ role,
1013
+ name: info?.name || role,
1014
+ version,
1015
+ });
1016
+ }
1017
+ }
1018
+ return {
1019
+ success: true,
1020
+ error: null,
1021
+ services: serviceList,
1022
+ };
1023
+ }
1024
+ catch (error) {
1025
+ localLogger.error(`[${ADDON_NAME}] Failed to list services:`, error);
1026
+ return {
1027
+ success: false,
1028
+ error: error.message || 'Unknown error',
1029
+ services: [],
1030
+ };
1031
+ }
1032
+ },
1033
+ // Phase 11: WP Engine Connect
1034
+ wpeStatus: async () => {
1035
+ try {
1036
+ localLogger.info(`[${ADDON_NAME}] Checking WP Engine authentication status`);
1037
+ if (!wpeOAuthService) {
1038
+ return {
1039
+ authenticated: false,
1040
+ email: null,
1041
+ accountId: null,
1042
+ accountName: null,
1043
+ tokenExpiry: null,
1044
+ error: 'WP Engine OAuth service not available',
1045
+ };
1046
+ }
1047
+ // Check if we have valid credentials by trying to get access token
1048
+ const accessToken = await wpeOAuthService.getAccessToken();
1049
+ if (!accessToken) {
1050
+ return {
1051
+ authenticated: false,
1052
+ email: null,
1053
+ accountId: null,
1054
+ accountName: null,
1055
+ tokenExpiry: null,
1056
+ error: null,
1057
+ };
1058
+ }
1059
+ // Try to get user info from CAPI if available
1060
+ let email = null;
1061
+ if (capiService) {
1062
+ try {
1063
+ const currentUser = await capiService.getCurrentUser();
1064
+ email = currentUser?.email || null;
1065
+ }
1066
+ catch {
1067
+ // User info not available, but still authenticated
1068
+ }
1069
+ }
1070
+ return {
1071
+ authenticated: true,
1072
+ email,
1073
+ accountId: null,
1074
+ accountName: null,
1075
+ tokenExpiry: null,
1076
+ error: null,
1077
+ };
1078
+ }
1079
+ catch (error) {
1080
+ localLogger.error(`[${ADDON_NAME}] Failed to check WPE status:`, error);
1081
+ return {
1082
+ authenticated: false,
1083
+ email: null,
1084
+ accountId: null,
1085
+ accountName: null,
1086
+ tokenExpiry: null,
1087
+ error: error.message || 'Unknown error',
1088
+ };
1089
+ }
1090
+ },
1091
+ listWpeSites: async (_parent, args) => {
1092
+ const { accountId } = args;
1093
+ try {
1094
+ localLogger.info(`[${ADDON_NAME}] Listing WP Engine sites${accountId ? ` for account ${accountId}` : ''}`);
1095
+ if (!wpeOAuthService) {
1096
+ return {
1097
+ success: false,
1098
+ error: 'WP Engine OAuth service not available',
1099
+ sites: [],
1100
+ count: 0,
1101
+ };
1102
+ }
1103
+ // Check if authenticated by trying to get access token
1104
+ const accessToken = await wpeOAuthService.getAccessToken();
1105
+ if (!accessToken) {
1106
+ return {
1107
+ success: false,
1108
+ error: 'Not authenticated with WP Engine. Use wpe_authenticate first.',
1109
+ sites: [],
1110
+ count: 0,
1111
+ };
1112
+ }
1113
+ if (!capiService) {
1114
+ return {
1115
+ success: false,
1116
+ error: 'WP Engine CAPI service not available',
1117
+ sites: [],
1118
+ count: 0,
1119
+ };
1120
+ }
1121
+ // Get installs from CAPI using getInstallList
1122
+ const installs = await capiService.getInstallList();
1123
+ if (!installs) {
1124
+ return {
1125
+ success: true,
1126
+ error: null,
1127
+ sites: [],
1128
+ count: 0,
1129
+ };
1130
+ }
1131
+ const sites = installs.map((install) => ({
1132
+ id: install.id,
1133
+ name: install.name,
1134
+ environment: install.environment || 'production',
1135
+ phpVersion: install.phpVersion || null,
1136
+ primaryDomain: install.primaryDomain || install.cname || null,
1137
+ accountId: install.accountId || accountId || null,
1138
+ accountName: install.accountName || null,
1139
+ sftpHost: `${install.name}.ssh.wpengine.net`,
1140
+ sftpUser: install.name,
1141
+ }));
1142
+ return {
1143
+ success: true,
1144
+ error: null,
1145
+ sites,
1146
+ count: sites.length,
1147
+ };
1148
+ }
1149
+ catch (error) {
1150
+ localLogger.error(`[${ADDON_NAME}] Failed to list WPE sites:`, error);
1151
+ return {
1152
+ success: false,
1153
+ error: error.message || 'Unknown error',
1154
+ sites: [],
1155
+ count: 0,
1156
+ };
1157
+ }
1158
+ },
1159
+ // Phase 11b: Site Linking
1160
+ getWpeLink: async (_parent, args) => {
1161
+ const { siteId } = args;
1162
+ try {
1163
+ localLogger.info(`[${ADDON_NAME}] Getting WP Engine link for site ${siteId}`);
1164
+ // Get site from siteData
1165
+ const site = siteData.getSite(siteId);
1166
+ if (!site) {
1167
+ return {
1168
+ linked: false,
1169
+ siteName: null,
1170
+ connections: [],
1171
+ connectionCount: 0,
1172
+ message: null,
1173
+ error: `Site not found: ${siteId}`,
1174
+ };
1175
+ }
1176
+ // Get hostConnections from site
1177
+ const hostConnections = site.hostConnections || [];
1178
+ const wpeConnections = hostConnections.filter((c) => c.hostId === 'wpe');
1179
+ if (wpeConnections.length === 0) {
1180
+ return {
1181
+ linked: false,
1182
+ siteName: site.name,
1183
+ connections: [],
1184
+ connectionCount: 0,
1185
+ message: 'Site is not linked to any WP Engine environment. Use Connect in Local to pull a site from WPE.',
1186
+ error: null,
1187
+ };
1188
+ }
1189
+ // Transform connections for output, enriching with CAPI data if available
1190
+ const connections = await Promise.all(wpeConnections.map(async (c) => {
1191
+ let installName = c.remoteSiteId; // Default to UUID
1192
+ let portalUrl = null;
1193
+ let primaryDomain = null;
1194
+ // Try to get install details from CAPI to get the actual name
1195
+ // remoteSiteId matches install.site.id (WPE Site ID), not install.id
1196
+ if (capiService && typeof capiService.getInstallList === 'function') {
1197
+ try {
1198
+ localLogger.info(`[${ADDON_NAME}] Looking for install with site.id=${c.remoteSiteId}, env=${c.remoteSiteEnv}`);
1199
+ const installs = await capiService.getInstallList();
1200
+ localLogger.info(`[${ADDON_NAME}] Got ${installs?.length || 0} installs from CAPI`);
1201
+ if (installs && installs.length > 0) {
1202
+ // Log first install structure for debugging
1203
+ localLogger.info(`[${ADDON_NAME}] Sample install structure: ${JSON.stringify(installs[0], null, 2)}`);
1204
+ // Match by site.id (remoteSiteId is the WPE Site ID, not Install ID)
1205
+ // Also filter by environment if available
1206
+ const matchingInstall = installs.find((i) => i.site?.id === c.remoteSiteId &&
1207
+ (!c.remoteSiteEnv || i.environment === c.remoteSiteEnv));
1208
+ if (matchingInstall) {
1209
+ localLogger.info(`[${ADDON_NAME}] Found match: ${matchingInstall.name}`);
1210
+ installName = matchingInstall.name;
1211
+ portalUrl = `https://my.wpengine.com/installs/${matchingInstall.name}`;
1212
+ primaryDomain =
1213
+ matchingInstall.primary_domain || matchingInstall.cname || null;
1214
+ }
1215
+ else {
1216
+ localLogger.warn(`[${ADDON_NAME}] No matching install found for site.id=${c.remoteSiteId}`);
1217
+ }
1218
+ }
1219
+ }
1220
+ catch (e) {
1221
+ localLogger.warn(`[${ADDON_NAME}] Could not look up install from CAPI: ${e.message}`);
1222
+ }
1223
+ }
1224
+ else {
1225
+ localLogger.warn(`[${ADDON_NAME}] capiService or getInstallList not available`);
1226
+ }
1227
+ return {
1228
+ remoteInstallId: c.remoteSiteId,
1229
+ installName,
1230
+ environment: c.remoteSiteEnv || null,
1231
+ accountId: c.accountId || null,
1232
+ portalUrl,
1233
+ primaryDomain,
1234
+ };
1235
+ }));
1236
+ // Capabilities are always the same for WPE-connected sites
1237
+ const capabilities = {
1238
+ canPush: true,
1239
+ canPull: true,
1240
+ syncModes: ['all_files', 'select_files', 'database_only'],
1241
+ magicSyncAvailable: true,
1242
+ databaseSyncAvailable: true,
1243
+ };
1244
+ return {
1245
+ linked: true,
1246
+ siteName: site.name,
1247
+ connections,
1248
+ connectionCount: connections.length,
1249
+ capabilities,
1250
+ message: null,
1251
+ error: null,
1252
+ };
1253
+ }
1254
+ catch (error) {
1255
+ localLogger.error(`[${ADDON_NAME}] Failed to get WPE link:`, error);
1256
+ return {
1257
+ linked: false,
1258
+ siteName: null,
1259
+ connections: [],
1260
+ connectionCount: 0,
1261
+ message: null,
1262
+ error: error.message || 'Unknown error',
1263
+ };
1264
+ }
1265
+ },
1266
+ // Phase 10: Cloud Backups
1267
+ backupStatus: async () => {
1268
+ try {
1269
+ localLogger.info(`[${ADDON_NAME}] Checking backup status`);
1270
+ // Get providers from Cloud Backups addon via IPC
1271
+ const providers = await getBackupProviders();
1272
+ localLogger.info(`[${ADDON_NAME}] Got ${providers.length} backup providers`);
1273
+ if (providers.length === 0) {
1274
+ return {
1275
+ available: false,
1276
+ featureEnabled: false,
1277
+ dropbox: null,
1278
+ googleDrive: null,
1279
+ message: 'No cloud storage providers configured. Connect Google Drive or Dropbox in Local Hub (hub.localwp.com/addons/cloud-backups).',
1280
+ error: null,
1281
+ };
1282
+ }
1283
+ // Map provider info to our response format
1284
+ const dropboxProvider = providers.find((p) => p.id === 'dropbox' || p.name?.toLowerCase().includes('dropbox'));
1285
+ const googleProvider = providers.find((p) => p.id === 'google' || p.name?.toLowerCase().includes('google'));
1286
+ const dropboxStatus = dropboxProvider
1287
+ ? {
1288
+ authenticated: true,
1289
+ accountId: dropboxProvider.id,
1290
+ email: dropboxProvider.email || null,
1291
+ }
1292
+ : {
1293
+ authenticated: false,
1294
+ accountId: null,
1295
+ email: null,
1296
+ };
1297
+ const googleDriveStatus = googleProvider
1298
+ ? {
1299
+ authenticated: true,
1300
+ accountId: googleProvider.id,
1301
+ email: googleProvider.email || null,
1302
+ }
1303
+ : {
1304
+ authenticated: false,
1305
+ accountId: null,
1306
+ email: null,
1307
+ };
1308
+ const hasProvider = providers.length > 0;
1309
+ return {
1310
+ available: hasProvider,
1311
+ featureEnabled: true,
1312
+ dropbox: dropboxStatus,
1313
+ googleDrive: googleDriveStatus,
1314
+ message: hasProvider
1315
+ ? null
1316
+ : 'No cloud storage provider authenticated. Connect Dropbox or Google Drive in Local settings.',
1317
+ error: null,
1318
+ };
1319
+ }
1320
+ catch (error) {
1321
+ localLogger.error(`[${ADDON_NAME}] Failed to check backup status:`, error);
1322
+ return {
1323
+ available: false,
1324
+ featureEnabled: false,
1325
+ dropbox: null,
1326
+ googleDrive: null,
1327
+ message: null,
1328
+ error: error.message || 'Unknown error',
1329
+ };
1330
+ }
1331
+ },
1332
+ listBackups: async (_parent, args) => {
1333
+ const { siteId, provider } = args;
1334
+ try {
1335
+ localLogger.info(`[${ADDON_NAME}] Listing backups for site ${siteId} from ${provider}`);
1336
+ // Get site
1337
+ const site = siteData.getSite(siteId);
1338
+ if (!site) {
1339
+ return {
1340
+ success: false,
1341
+ siteName: null,
1342
+ provider,
1343
+ backups: [],
1344
+ count: 0,
1345
+ error: `Site not found: ${siteId}`,
1346
+ };
1347
+ }
1348
+ // Get providers from Cloud Backups addon
1349
+ const providers = await getBackupProviders();
1350
+ if (providers.length === 0) {
1351
+ return {
1352
+ success: false,
1353
+ siteName: site.name,
1354
+ provider,
1355
+ backups: [],
1356
+ count: 0,
1357
+ error: 'No cloud storage providers configured. Connect Google Drive or Dropbox in Local Hub.',
1358
+ };
1359
+ }
1360
+ // Find the matching provider (map 'googleDrive' to 'google' for the addon)
1361
+ const providerMap = { googleDrive: 'google', dropbox: 'dropbox' };
1362
+ const providerId = providerMap[provider] || provider;
1363
+ const matchedProvider = providers.find((p) => p.id === providerId);
1364
+ if (!matchedProvider) {
1365
+ return {
1366
+ success: false,
1367
+ siteName: site.name,
1368
+ provider,
1369
+ backups: [],
1370
+ count: 0,
1371
+ error: `Provider '${provider}' not configured. Available: ${providers.map((p) => p.name).join(', ')}`,
1372
+ };
1373
+ }
1374
+ // For listing snapshots, use the Hub provider ID directly (e.g., 'google')
1375
+ // NOT the rclone backend name ('drive') - the Hub queries expect the OAuth provider name
1376
+ // Also pass pageOffset parameter (0 for first page)
1377
+ const result = await invokeBackupIPC('backups:provider-snapshots', DEFAULT_IPC_TIMEOUT, siteId, matchedProvider.id, 0);
1378
+ localLogger.info(`[${ADDON_NAME}] Provider snapshots raw result: ${JSON.stringify(result)}`);
1379
+ if (result.error) {
1380
+ return {
1381
+ success: false,
1382
+ siteName: site.name,
1383
+ provider,
1384
+ backups: [],
1385
+ count: 0,
1386
+ error: result.error.message || 'Failed to list backups',
1387
+ };
1388
+ }
1389
+ // Unwrap nested result structure (similar to providers)
1390
+ let backupsData = result.result;
1391
+ if (backupsData && typeof backupsData === 'object' && !Array.isArray(backupsData)) {
1392
+ // Check for nested result or snapshots array
1393
+ if (Array.isArray(backupsData.result)) {
1394
+ backupsData = backupsData.result;
1395
+ }
1396
+ else if (Array.isArray(backupsData.snapshots)) {
1397
+ backupsData = backupsData.snapshots;
1398
+ }
1399
+ else if (backupsData.result && Array.isArray(backupsData.result.snapshots)) {
1400
+ backupsData = backupsData.result.snapshots;
1401
+ }
1402
+ }
1403
+ const backups = Array.isArray(backupsData) ? backupsData : [];
1404
+ localLogger.info(`[${ADDON_NAME}] Extracted ${backups.length} backups`);
1405
+ return {
1406
+ success: true,
1407
+ siteName: site.name,
1408
+ provider,
1409
+ backups: backups.map((b) => ({
1410
+ // Use hash for snapshotId as that's what restic uses for restore/delete operations
1411
+ // The Hub ID (b.id) is just a database identifier
1412
+ snapshotId: b.hash || b.snapshotId || b.short_id,
1413
+ timestamp: b.updatedAt || b.createdAt || b.timestamp || b.time || b.created,
1414
+ note: b.configObject?.description || b.note || b.description || b.tags?.description || '',
1415
+ siteDomain: b.configObject?.name
1416
+ ? `${b.configObject.name}.local`
1417
+ : b.siteDomain || site.domain,
1418
+ services: JSON.stringify(b.configObject?.services || b.services || {}),
1419
+ })),
1420
+ count: backups.length,
1421
+ error: null,
1422
+ };
1423
+ }
1424
+ catch (error) {
1425
+ localLogger.error(`[${ADDON_NAME}] Failed to list backups:`, error);
1426
+ return {
1427
+ success: false,
1428
+ siteName: null,
1429
+ provider,
1430
+ backups: [],
1431
+ count: 0,
1432
+ error: error.message || 'Unknown error',
1433
+ };
1434
+ }
1435
+ },
1436
+ // Phase 11c: Sync History
1437
+ getSyncHistory: async (_parent, args) => {
1438
+ const { siteId, limit = 30 } = args;
1439
+ try {
1440
+ localLogger.info(`[${ADDON_NAME}] Getting sync history for site ${siteId}`);
1441
+ // Get site to verify it exists
1442
+ const site = siteData.getSite(siteId);
1443
+ if (!site) {
1444
+ return {
1445
+ success: false,
1446
+ siteName: null,
1447
+ events: [],
1448
+ count: 0,
1449
+ error: `Site not found: ${siteId}`,
1450
+ };
1451
+ }
1452
+ // Check if connectHistory service is available
1453
+ if (!connectHistoryService || typeof connectHistoryService.getEvents !== 'function') {
1454
+ return {
1455
+ success: false,
1456
+ siteName: site.name,
1457
+ events: [],
1458
+ count: 0,
1459
+ error: 'Sync history service not available',
1460
+ };
1461
+ }
1462
+ const events = connectHistoryService.getEvents(siteId);
1463
+ const limitedEvents = events.slice(0, limit);
1464
+ return {
1465
+ success: true,
1466
+ siteName: site.name,
1467
+ events: limitedEvents.map((e) => ({
1468
+ remoteInstallName: e.remoteInstallName || null,
1469
+ timestamp: e.timestamp,
1470
+ environment: e.environment,
1471
+ direction: e.direction,
1472
+ status: e.status || null,
1473
+ })),
1474
+ count: limitedEvents.length,
1475
+ error: null,
1476
+ };
1477
+ }
1478
+ catch (error) {
1479
+ localLogger.error(`[${ADDON_NAME}] Failed to get sync history:`, error);
1480
+ return {
1481
+ success: false,
1482
+ siteName: null,
1483
+ events: [],
1484
+ count: 0,
1485
+ error: error.message || 'Unknown error',
1486
+ };
1487
+ }
1488
+ },
1489
+ // Get file changes between local and WPE (dry-run comparison)
1490
+ getSiteChanges: async (_parent, args) => {
1491
+ const { siteId, direction = 'push' } = args;
1492
+ try {
1493
+ localLogger.info(`[${ADDON_NAME}] Getting site changes for ${siteId}, direction=${direction}`);
1494
+ // Validate direction
1495
+ if (direction !== 'push' && direction !== 'pull') {
1496
+ return {
1497
+ success: false,
1498
+ siteName: null,
1499
+ direction,
1500
+ added: [],
1501
+ modified: [],
1502
+ deleted: [],
1503
+ totalChanges: 0,
1504
+ message: null,
1505
+ error: 'Invalid direction. Must be "push" or "pull".',
1506
+ };
1507
+ }
1508
+ // Get site
1509
+ const site = siteData.getSite(siteId);
1510
+ if (!site) {
1511
+ return {
1512
+ success: false,
1513
+ siteName: null,
1514
+ direction,
1515
+ added: [],
1516
+ modified: [],
1517
+ deleted: [],
1518
+ totalChanges: 0,
1519
+ message: null,
1520
+ error: `Site not found: ${siteId}`,
1521
+ };
1522
+ }
1523
+ // Check WPE connection
1524
+ const wpeConnection = site.hostConnections?.find((c) => c.hostId === 'wpe');
1525
+ if (!wpeConnection) {
1526
+ return {
1527
+ success: false,
1528
+ siteName: site.name,
1529
+ direction,
1530
+ added: [],
1531
+ modified: [],
1532
+ deleted: [],
1533
+ totalChanges: 0,
1534
+ message: null,
1535
+ error: 'Site is not linked to WP Engine. Use Connect in Local to link the site first.',
1536
+ };
1537
+ }
1538
+ // Check service availability
1539
+ if (!wpeConnectBaseService ||
1540
+ typeof wpeConnectBaseService.listModifications !== 'function') {
1541
+ return {
1542
+ success: false,
1543
+ siteName: site.name,
1544
+ direction,
1545
+ added: [],
1546
+ modified: [],
1547
+ deleted: [],
1548
+ totalChanges: 0,
1549
+ message: null,
1550
+ error: 'WPE Connect service not available',
1551
+ };
1552
+ }
1553
+ // Get install details from CAPI
1554
+ let installName = wpeConnection.remoteSiteId;
1555
+ let primaryDomain = '';
1556
+ let installId = '';
1557
+ if (capiService && typeof capiService.getInstallList === 'function') {
1558
+ const installs = await capiService.getInstallList();
1559
+ const matchingInstall = installs?.find((i) => i.site?.id === wpeConnection.remoteSiteId &&
1560
+ (!wpeConnection.remoteSiteEnv || i.environment === wpeConnection.remoteSiteEnv));
1561
+ if (matchingInstall) {
1562
+ installName = matchingInstall.name;
1563
+ primaryDomain =
1564
+ matchingInstall.primary_domain ||
1565
+ matchingInstall.cname ||
1566
+ `${matchingInstall.name}.wpengine.com`;
1567
+ installId = matchingInstall.id;
1568
+ }
1569
+ }
1570
+ if (!primaryDomain) {
1571
+ return {
1572
+ success: false,
1573
+ siteName: site.name,
1574
+ direction,
1575
+ added: [],
1576
+ modified: [],
1577
+ deleted: [],
1578
+ totalChanges: 0,
1579
+ message: null,
1580
+ error: 'Could not determine WP Engine install details. Please ensure you are authenticated.',
1581
+ };
1582
+ }
1583
+ // Call listModifications (dry-run rsync comparison)
1584
+ localLogger.info(`[${ADDON_NAME}] Calling listModifications for ${installName}`);
1585
+ const modifications = await wpeConnectBaseService.listModifications({
1586
+ connectArgs: {
1587
+ wpengineInstallName: installName,
1588
+ wpengineInstallId: installId,
1589
+ wpengineSiteId: wpeConnection.remoteSiteId,
1590
+ wpenginePrimaryDomain: primaryDomain,
1591
+ localSiteId: site.id,
1592
+ },
1593
+ direction: direction,
1594
+ includeIgnored: false,
1595
+ });
1596
+ // Categorize changes
1597
+ const added = modifications
1598
+ .filter((f) => f.instruction === 'create' ||
1599
+ f.instruction === 'upload' ||
1600
+ f.instruction === 'download')
1601
+ .map((f) => ({
1602
+ path: f.path,
1603
+ instruction: f.instruction,
1604
+ size: f.size,
1605
+ type: f.type,
1606
+ }));
1607
+ const modified = modifications
1608
+ .filter((f) => f.instruction === 'modify')
1609
+ .map((f) => ({
1610
+ path: f.path,
1611
+ instruction: f.instruction,
1612
+ size: f.size,
1613
+ type: f.type,
1614
+ }));
1615
+ const deleted = modifications
1616
+ .filter((f) => f.instruction === 'delete')
1617
+ .map((f) => ({
1618
+ path: f.path,
1619
+ instruction: f.instruction,
1620
+ size: f.size,
1621
+ type: f.type,
1622
+ }));
1623
+ const totalChanges = added.length + modified.length + deleted.length;
1624
+ const directionLabel = direction === 'push' ? 'local → WPE' : 'WPE → local';
1625
+ return {
1626
+ success: true,
1627
+ siteName: site.name,
1628
+ direction,
1629
+ added,
1630
+ modified,
1631
+ deleted,
1632
+ totalChanges,
1633
+ message: totalChanges > 0
1634
+ ? `${totalChanges} file(s) changed (${directionLabel}): ${added.length} added, ${modified.length} modified, ${deleted.length} deleted`
1635
+ : `No changes detected (${directionLabel})`,
1636
+ error: null,
1637
+ };
1638
+ }
1639
+ catch (error) {
1640
+ localLogger.error(`[${ADDON_NAME}] Failed to get site changes:`, error);
1641
+ return {
1642
+ success: false,
1643
+ siteName: null,
1644
+ direction,
1645
+ added: [],
1646
+ modified: [],
1647
+ deleted: [],
1648
+ totalChanges: 0,
1649
+ message: null,
1650
+ error: error.message || 'Unknown error',
1651
+ };
1652
+ }
1653
+ },
1654
+ },
1655
+ Mutation: {
1656
+ wpCli: executeWpCli,
1657
+ createSite: async (_parent, args) => {
1658
+ // DEBUG: Log raw args received
1659
+ localLogger.info(`[${ADDON_NAME}] createSite called with args: ${JSON.stringify(args)}`);
1660
+ const { name, phpVersion, webServer = 'nginx', database = 'mysql', wpAdminUsername = 'admin', wpAdminPassword = 'password', wpAdminEmail = 'admin@local.test', blueprint, } = args.input;
1661
+ // DEBUG: Log destructured values
1662
+ localLogger.info(`[${ADDON_NAME}] Destructured - name: ${name}, blueprint: ${blueprint}, typeof blueprint: ${typeof blueprint}`);
1663
+ try {
1664
+ localLogger.info(`[${ADDON_NAME}] Creating site: ${name}${blueprint ? ` from blueprint: ${blueprint}` : ''}`);
1665
+ // Generate slug and domain from name
1666
+ const siteSlug = name
1667
+ .toLowerCase()
1668
+ .replace(/[^a-z0-9]+/g, '-')
1669
+ .replace(/^-|-$/g, '');
1670
+ const siteDomain = `${siteSlug}.local`;
1671
+ const os = require('os');
1672
+ const path = require('path');
1673
+ const fs = require('fs');
1674
+ const sitePath = path.join(os.homedir(), 'Local Sites', siteSlug);
1675
+ // If blueprint is provided, use importSiteService instead of addSiteService
1676
+ if (blueprint) {
1677
+ localLogger.info(`[${ADDON_NAME}] Blueprint parameter received: ${blueprint}`);
1678
+ // Get the userDataPath from electron app
1679
+ const { app } = require('electron');
1680
+ const userDataPath = app.getPath('userData');
1681
+ const blueprintZipPath = path.join(userDataPath, 'blueprints', `${blueprint}.zip`);
1682
+ localLogger.info(`[${ADDON_NAME}] Looking for blueprint at: ${blueprintZipPath}`);
1683
+ // Verify blueprint exists
1684
+ if (!fs.existsSync(blueprintZipPath)) {
1685
+ localLogger.error(`[${ADDON_NAME}] Blueprint not found at: ${blueprintZipPath}`);
1686
+ return {
1687
+ success: false,
1688
+ error: `Blueprint not found: ${blueprint}. Use list_blueprints to see available blueprints.`,
1689
+ siteId: null,
1690
+ siteName: name,
1691
+ siteDomain: null,
1692
+ };
1693
+ }
1694
+ localLogger.info(`[${ADDON_NAME}] Found blueprint at: ${blueprintZipPath}`);
1695
+ // Read the local-site.json from the blueprint zip to get manifest
1696
+ let localSiteJSON;
1697
+ try {
1698
+ const StreamZip = require('node-stream-zip');
1699
+ localLogger.info(`[${ADDON_NAME}] node-stream-zip loaded successfully`);
1700
+ const zip = new StreamZip.async({ file: blueprintZipPath });
1701
+ const entries = await zip.entries();
1702
+ localLogger.info(`[${ADDON_NAME}] Zip entries loaded, count: ${Object.keys(entries).length}`);
1703
+ const filename = entries['local-site.json']
1704
+ ? 'local-site.json'
1705
+ : 'pressmatic-site.json';
1706
+ localLogger.info(`[${ADDON_NAME}] Reading manifest file: ${filename}`);
1707
+ const data = await zip.entryData(filename);
1708
+ localSiteJSON = JSON.parse(data.toString('utf8'));
1709
+ await zip.close();
1710
+ localLogger.info(`[${ADDON_NAME}] Successfully read manifest:`, JSON.stringify(localSiteJSON).substring(0, 200));
1711
+ }
1712
+ catch (zipError) {
1713
+ localLogger.error(`[${ADDON_NAME}] Failed to read blueprint zip: ${zipError.message}`, zipError);
1714
+ return {
1715
+ success: false,
1716
+ error: `Failed to read blueprint manifest: ${zipError.message}`,
1717
+ siteId: null,
1718
+ siteName: name,
1719
+ siteDomain: null,
1720
+ };
1721
+ }
1722
+ // Build import settings
1723
+ const importSettings = {
1724
+ siteName: name,
1725
+ siteDomain: siteDomain,
1726
+ sitePath: sitePath,
1727
+ zip: blueprintZipPath,
1728
+ importData: {
1729
+ type: 'local-blueprint',
1730
+ oldSite: localSiteJSON,
1731
+ },
1732
+ environment: localSiteJSON.environment || 'flywheel',
1733
+ blueprint: blueprint,
1734
+ };
1735
+ // Copy service versions from blueprint if available
1736
+ if (localSiteJSON.services) {
1737
+ // Extract PHP version
1738
+ const phpService = Object.values(localSiteJSON.services).find((s) => s.role === 'php');
1739
+ if (phpService) {
1740
+ importSettings.phpVersion = phpService.version;
1741
+ }
1742
+ // Extract database
1743
+ const dbService = Object.values(localSiteJSON.services).find((s) => s.role === 'database' || s.role === 'db');
1744
+ if (dbService) {
1745
+ importSettings.database = `${dbService.name}-${dbService.version}`;
1746
+ }
1747
+ // Extract web server
1748
+ const webService = Object.values(localSiteJSON.services).find((s) => s.role === 'http' || s.role === 'web');
1749
+ if (webService) {
1750
+ importSettings.webServer = `${webService.name}-${webService.version}`;
1751
+ }
1752
+ }
1753
+ else if (localSiteJSON.phpVersion) {
1754
+ importSettings.phpVersion = localSiteJSON.phpVersion;
1755
+ }
1756
+ localLogger.info(`[${ADDON_NAME}] Import settings prepared:`, JSON.stringify(importSettings).substring(0, 500));
1757
+ if (!importSiteService) {
1758
+ localLogger.error(`[${ADDON_NAME}] importSiteService is not available!`);
1759
+ return {
1760
+ success: false,
1761
+ error: 'Import service not available',
1762
+ siteId: null,
1763
+ siteName: name,
1764
+ siteDomain: null,
1765
+ };
1766
+ }
1767
+ localLogger.info(`[${ADDON_NAME}] Calling importSiteService.run()...`);
1768
+ // Use the importSiteService to create from blueprint
1769
+ const importResult = await importSiteService.run(importSettings);
1770
+ localLogger.info(`[${ADDON_NAME}] Import result:`, JSON.stringify(importResult || 'null').substring(0, 500));
1771
+ if (importResult && importResult.id) {
1772
+ localLogger.info(`[${ADDON_NAME}] Successfully created site from blueprint: ${name} (${importResult.id})`);
1773
+ return {
1774
+ success: true,
1775
+ error: null,
1776
+ siteId: importResult.id,
1777
+ siteName: name,
1778
+ siteDomain: siteDomain,
1779
+ };
1780
+ }
1781
+ else {
1782
+ localLogger.warn(`[${ADDON_NAME}] Import returned but no site ID found`);
1783
+ return {
1784
+ success: true,
1785
+ error: null,
1786
+ siteId: null,
1787
+ siteName: name,
1788
+ siteDomain: siteDomain,
1789
+ };
1790
+ }
1791
+ }
1792
+ // No blueprint - create a fresh site
1793
+ const newSiteInfo = {
1794
+ siteName: name,
1795
+ siteDomain: siteDomain,
1796
+ sitePath: sitePath,
1797
+ webServer: webServer,
1798
+ database: database,
1799
+ };
1800
+ if (phpVersion) {
1801
+ newSiteInfo.phpVersion = phpVersion;
1802
+ }
1803
+ const wpCredentials = {
1804
+ adminUsername: wpAdminUsername,
1805
+ adminPassword: wpAdminPassword,
1806
+ adminEmail: wpAdminEmail,
1807
+ };
1808
+ const site = await addSiteService.addSite({
1809
+ newSiteInfo,
1810
+ wpCredentials,
1811
+ goToSite: false,
1812
+ });
1813
+ localLogger.info(`[${ADDON_NAME}] Successfully created site: ${name} (${site.id})`);
1814
+ return {
1815
+ success: true,
1816
+ error: null,
1817
+ siteId: site.id,
1818
+ siteName: name,
1819
+ siteDomain: siteDomain,
1820
+ };
1821
+ }
1822
+ catch (error) {
1823
+ localLogger.error(`[${ADDON_NAME}] Failed to create site:`, error);
1824
+ return {
1825
+ success: false,
1826
+ error: error.message || 'Unknown error',
1827
+ siteId: null,
1828
+ siteName: name,
1829
+ siteDomain: null,
1830
+ };
1831
+ }
1832
+ },
1833
+ deleteSite: async (_parent, args) => {
1834
+ const { id, trashFiles = true, updateHosts = true } = args.input;
1835
+ try {
1836
+ localLogger.info(`[${ADDON_NAME}] Deleting site: ${id}`);
1837
+ const site = siteData.getSite(id);
1838
+ if (!site) {
1839
+ return {
1840
+ success: false,
1841
+ error: `Site not found: ${id}`,
1842
+ siteId: id,
1843
+ };
1844
+ }
1845
+ await deleteSiteService.deleteSite({
1846
+ site,
1847
+ trashFiles,
1848
+ updateHosts,
1849
+ });
1850
+ localLogger.info(`[${ADDON_NAME}] Successfully deleted site: ${site.name}`);
1851
+ return {
1852
+ success: true,
1853
+ error: null,
1854
+ siteId: id,
1855
+ };
1856
+ }
1857
+ catch (error) {
1858
+ localLogger.error(`[${ADDON_NAME}] Failed to delete site:`, error);
1859
+ return {
1860
+ success: false,
1861
+ error: error.message || 'Unknown error',
1862
+ siteId: id,
1863
+ };
1864
+ }
1865
+ },
1866
+ deleteSites: async (_parent, args) => {
1867
+ const { ids, trashFiles = true } = args;
1868
+ try {
1869
+ localLogger.info(`[${ADDON_NAME}] Deleting ${ids.length} sites`);
1870
+ await deleteSiteService.deleteSites({
1871
+ siteIds: ids,
1872
+ trashFiles,
1873
+ updateHosts: true,
1874
+ });
1875
+ localLogger.info(`[${ADDON_NAME}] Successfully deleted ${ids.length} sites`);
1876
+ return {
1877
+ success: true,
1878
+ error: null,
1879
+ siteId: ids.join(','),
1880
+ };
1881
+ }
1882
+ catch (error) {
1883
+ localLogger.error(`[${ADDON_NAME}] Failed to delete sites:`, error);
1884
+ return {
1885
+ success: false,
1886
+ error: error.message || 'Unknown error',
1887
+ siteId: ids.join(','),
1888
+ };
1889
+ }
1890
+ },
1891
+ openSite: async (_parent, args) => {
1892
+ const { siteId, path = '/' } = args.input;
1893
+ try {
1894
+ const site = siteData.getSite(siteId);
1895
+ if (!site) {
1896
+ return {
1897
+ success: false,
1898
+ error: `Site not found: ${siteId}`,
1899
+ url: null,
1900
+ };
1901
+ }
1902
+ // Check if site is running
1903
+ const status = await siteProcessManager.getSiteStatus(site);
1904
+ if (status !== 'running') {
1905
+ return {
1906
+ success: false,
1907
+ error: `Site "${site.name}" must be running to open in browser. Start it first.`,
1908
+ url: null,
1909
+ };
1910
+ }
1911
+ const protocol = site.isStarred ? 'https' : 'http';
1912
+ const url = `${protocol}://${site.domain}${path}`;
1913
+ localLogger.info(`[${ADDON_NAME}] Opening site in browser: ${url}`);
1914
+ if (browserManager) {
1915
+ await browserManager.openInBrowser(url);
1916
+ }
1917
+ else {
1918
+ // Fallback to shell.openExternal
1919
+ const { shell } = require('electron');
1920
+ await shell.openExternal(url);
1921
+ }
1922
+ return {
1923
+ success: true,
1924
+ error: null,
1925
+ url,
1926
+ };
1927
+ }
1928
+ catch (error) {
1929
+ localLogger.error(`[${ADDON_NAME}] Failed to open site:`, error);
1930
+ return {
1931
+ success: false,
1932
+ error: error.message || 'Unknown error',
1933
+ url: null,
1934
+ };
1935
+ }
1936
+ },
1937
+ cloneSite: async (_parent, args) => {
1938
+ const { siteId, newName } = args.input;
1939
+ try {
1940
+ const site = siteData.getSite(siteId);
1941
+ if (!site) {
1942
+ return {
1943
+ success: false,
1944
+ error: `Site not found: ${siteId}`,
1945
+ newSiteId: null,
1946
+ newSiteName: null,
1947
+ newSiteDomain: null,
1948
+ };
1949
+ }
1950
+ // Check if site is running - needed for database cloning
1951
+ const status = await siteProcessManager.getSiteStatus(site);
1952
+ if (status !== 'running') {
1953
+ return {
1954
+ success: false,
1955
+ error: `Site "${site.name}" must be running to clone. Start it first.`,
1956
+ newSiteId: null,
1957
+ newSiteName: null,
1958
+ newSiteDomain: null,
1959
+ };
1960
+ }
1961
+ localLogger.info(`[${ADDON_NAME}] Cloning site ${site.name} to ${newName}`);
1962
+ const newSite = await cloneSiteService.cloneSite({
1963
+ site,
1964
+ newSiteName: newName,
1965
+ });
1966
+ localLogger.info(`[${ADDON_NAME}] Successfully cloned site: ${newSite.name} (${newSite.id})`);
1967
+ return {
1968
+ success: true,
1969
+ error: null,
1970
+ newSiteId: newSite.id,
1971
+ newSiteName: newSite.name,
1972
+ newSiteDomain: newSite.domain,
1973
+ };
1974
+ }
1975
+ catch (error) {
1976
+ localLogger.error(`[${ADDON_NAME}] Failed to clone site:`, error);
1977
+ return {
1978
+ success: false,
1979
+ error: error.message || 'Unknown error',
1980
+ newSiteId: null,
1981
+ newSiteName: null,
1982
+ newSiteDomain: null,
1983
+ };
1984
+ }
1985
+ },
1986
+ exportSite: async (_parent, args) => {
1987
+ const { siteId, outputPath } = args.input;
1988
+ const os = require('os');
1989
+ const path = require('path');
1990
+ try {
1991
+ const site = siteData.getSite(siteId);
1992
+ if (!site) {
1993
+ return {
1994
+ success: false,
1995
+ error: `Site not found: ${siteId}`,
1996
+ exportPath: null,
1997
+ };
1998
+ }
1999
+ // Check if site is running - needed for database export
2000
+ const status = await siteProcessManager.getSiteStatus(site);
2001
+ if (status !== 'running') {
2002
+ return {
2003
+ success: false,
2004
+ error: `Site "${site.name}" must be running to export. Start it first.`,
2005
+ exportPath: null,
2006
+ };
2007
+ }
2008
+ // Default to Downloads folder
2009
+ const outputDir = outputPath || path.join(os.homedir(), 'Downloads');
2010
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
2011
+ const fileName = `${site.name}-${timestamp}.zip`;
2012
+ const fullPath = path.join(outputDir, fileName);
2013
+ localLogger.info(`[${ADDON_NAME}] Exporting site ${site.name} to ${fullPath}`);
2014
+ // Use default export filter (excludes archive files)
2015
+ const defaultExportFilter = '*.zip, *.tar.gz, *.bz2, *.tgz';
2016
+ await exportSiteService.exportSite({
2017
+ site,
2018
+ outputPath: fullPath,
2019
+ filter: defaultExportFilter,
2020
+ });
2021
+ localLogger.info(`[${ADDON_NAME}] Successfully exported site to: ${fullPath}`);
2022
+ return {
2023
+ success: true,
2024
+ error: null,
2025
+ exportPath: fullPath,
2026
+ };
2027
+ }
2028
+ catch (error) {
2029
+ localLogger.error(`[${ADDON_NAME}] Failed to export site:`, error);
2030
+ return {
2031
+ success: false,
2032
+ error: error.message || 'Unknown error',
2033
+ exportPath: null,
2034
+ };
2035
+ }
2036
+ },
2037
+ saveBlueprint: async (_parent, args) => {
2038
+ const { siteId, name } = args.input;
2039
+ try {
2040
+ const site = siteData.getSite(siteId);
2041
+ if (!site) {
2042
+ return {
2043
+ success: false,
2044
+ error: `Site not found: ${siteId}`,
2045
+ blueprintName: null,
2046
+ };
2047
+ }
2048
+ // Check if site is running - needed for database export
2049
+ const status = await siteProcessManager.getSiteStatus(site);
2050
+ if (status !== 'running') {
2051
+ return {
2052
+ success: false,
2053
+ error: `Site "${site.name}" must be running to save as blueprint. Start it first.`,
2054
+ blueprintName: null,
2055
+ };
2056
+ }
2057
+ localLogger.info(`[${ADDON_NAME}] Saving site ${site.name} as blueprint: ${name}`);
2058
+ // Use default export filter (excludes archive files)
2059
+ const defaultFilter = '*.zip, *.tar.gz, *.bz2, *.tgz';
2060
+ await blueprintsService.saveBlueprint({
2061
+ name,
2062
+ siteId,
2063
+ filter: defaultFilter,
2064
+ });
2065
+ localLogger.info(`[${ADDON_NAME}] Successfully saved blueprint: ${name}`);
2066
+ return {
2067
+ success: true,
2068
+ error: null,
2069
+ blueprintName: name,
2070
+ };
2071
+ }
2072
+ catch (error) {
2073
+ localLogger.error(`[${ADDON_NAME}] Failed to save blueprint:`, error);
2074
+ return {
2075
+ success: false,
2076
+ error: error.message || 'Unknown error',
2077
+ blueprintName: null,
2078
+ };
2079
+ }
2080
+ },
2081
+ // Phase 8: WordPress Development Tools
2082
+ exportDatabase: async (_parent, args) => {
2083
+ const { siteId, outputPath } = args.input;
2084
+ const os = require('os');
2085
+ const pathModule = require('path');
2086
+ try {
2087
+ const site = siteData.getSite(siteId);
2088
+ if (!site) {
2089
+ return {
2090
+ success: false,
2091
+ error: `Site not found: ${siteId}`,
2092
+ outputPath: null,
2093
+ };
2094
+ }
2095
+ // Check if site is running - database must be accessible
2096
+ const status = await siteProcessManager.getSiteStatus(site);
2097
+ if (status !== 'running') {
2098
+ return {
2099
+ success: false,
2100
+ error: `Site "${site.name}" must be running to export database. Start it first.`,
2101
+ outputPath: null,
2102
+ };
2103
+ }
2104
+ // Default to Downloads folder with site name
2105
+ const defaultPath = pathModule.join(os.homedir(), 'Downloads', `${site.name.replace(/[^a-z0-9]/gi, '-')}.sql`);
2106
+ const finalPath = outputPath || defaultPath;
2107
+ localLogger.info(`[${ADDON_NAME}] Exporting database for ${site.name} to ${finalPath}`);
2108
+ // Use siteDatabase.dump() which properly sets up MySQL environment
2109
+ if (!siteDatabase) {
2110
+ return {
2111
+ success: false,
2112
+ error: 'Database service not available',
2113
+ outputPath: null,
2114
+ };
2115
+ }
2116
+ await siteDatabase.dump(site, finalPath);
2117
+ localLogger.info(`[${ADDON_NAME}] Successfully exported database to: ${finalPath}`);
2118
+ return {
2119
+ success: true,
2120
+ error: null,
2121
+ outputPath: finalPath,
2122
+ };
2123
+ }
2124
+ catch (error) {
2125
+ localLogger.error(`[${ADDON_NAME}] Failed to export database:`, error);
2126
+ return {
2127
+ success: false,
2128
+ error: error.message || 'Unknown error',
2129
+ outputPath: null,
2130
+ };
2131
+ }
2132
+ },
2133
+ importDatabase: async (_parent, args) => {
2134
+ const { siteId, sqlPath } = args.input;
2135
+ const fs = require('fs');
2136
+ try {
2137
+ const site = siteData.getSite(siteId);
2138
+ if (!site) {
2139
+ return {
2140
+ success: false,
2141
+ error: `Site not found: ${siteId}`,
2142
+ };
2143
+ }
2144
+ if (!fs.existsSync(sqlPath)) {
2145
+ return {
2146
+ success: false,
2147
+ error: `SQL file not found: ${sqlPath}`,
2148
+ };
2149
+ }
2150
+ // Check if site is running - database must be accessible
2151
+ const status = await siteProcessManager.getSiteStatus(site);
2152
+ if (status !== 'running') {
2153
+ return {
2154
+ success: false,
2155
+ error: `Site "${site.name}" must be running to import database. Start it first.`,
2156
+ };
2157
+ }
2158
+ localLogger.info(`[${ADDON_NAME}] Importing database for ${site.name} from ${sqlPath}`);
2159
+ // Use importSQLFile service which properly sets up MySQL environment
2160
+ if (!importSQLFileService) {
2161
+ return {
2162
+ success: false,
2163
+ error: 'Import SQL file service not available',
2164
+ };
2165
+ }
2166
+ await importSQLFileService(site, sqlPath);
2167
+ localLogger.info(`[${ADDON_NAME}] Successfully imported database from: ${sqlPath}`);
2168
+ return {
2169
+ success: true,
2170
+ error: null,
2171
+ };
2172
+ }
2173
+ catch (error) {
2174
+ localLogger.error(`[${ADDON_NAME}] Failed to import database:`, error);
2175
+ return {
2176
+ success: false,
2177
+ error: error.message || 'Unknown error',
2178
+ };
2179
+ }
2180
+ },
2181
+ openAdminer: async (_parent, args) => {
2182
+ const { siteId } = args.input;
2183
+ try {
2184
+ const site = siteData.getSite(siteId);
2185
+ if (!site) {
2186
+ return {
2187
+ success: false,
2188
+ error: `Site not found: ${siteId}`,
2189
+ };
2190
+ }
2191
+ // Check if site is running - database must be accessible
2192
+ const status = await siteProcessManager.getSiteStatus(site);
2193
+ if (status !== 'running') {
2194
+ return {
2195
+ success: false,
2196
+ error: `Site "${site.name}" must be running to open Adminer. Start it first.`,
2197
+ };
2198
+ }
2199
+ localLogger.info(`[${ADDON_NAME}] Opening Adminer for ${site.name}`);
2200
+ if (adminer) {
2201
+ await adminer.open(site);
2202
+ }
2203
+ else {
2204
+ return {
2205
+ success: false,
2206
+ error: 'Adminer service not available',
2207
+ };
2208
+ }
2209
+ return {
2210
+ success: true,
2211
+ error: null,
2212
+ };
2213
+ }
2214
+ catch (error) {
2215
+ localLogger.error(`[${ADDON_NAME}] Failed to open Adminer:`, error);
2216
+ return {
2217
+ success: false,
2218
+ error: error.message || 'Unknown error',
2219
+ };
2220
+ }
2221
+ },
2222
+ trustSsl: async (_parent, args) => {
2223
+ const { siteId } = args.input;
2224
+ try {
2225
+ const site = siteData.getSite(siteId);
2226
+ if (!site) {
2227
+ return {
2228
+ success: false,
2229
+ error: `Site not found: ${siteId}`,
2230
+ };
2231
+ }
2232
+ localLogger.info(`[${ADDON_NAME}] Trusting SSL for ${site.name}`);
2233
+ if (x509Cert) {
2234
+ await x509Cert.trustCert(site);
2235
+ }
2236
+ else {
2237
+ return {
2238
+ success: false,
2239
+ error: 'X509 certificate service not available',
2240
+ };
2241
+ }
2242
+ return {
2243
+ success: true,
2244
+ error: null,
2245
+ };
2246
+ }
2247
+ catch (error) {
2248
+ localLogger.error(`[${ADDON_NAME}] Failed to trust SSL:`, error);
2249
+ return {
2250
+ success: false,
2251
+ error: error.message || 'Unknown error',
2252
+ };
2253
+ }
2254
+ },
2255
+ mcpRenameSite: async (_parent, args) => {
2256
+ const { siteId, newName } = args.input;
2257
+ try {
2258
+ const site = siteData.getSite(siteId);
2259
+ if (!site) {
2260
+ return {
2261
+ success: false,
2262
+ error: `Site not found: ${siteId}`,
2263
+ newName: null,
2264
+ };
2265
+ }
2266
+ localLogger.info(`[${ADDON_NAME}] Renaming ${site.name} to ${newName}`);
2267
+ // Update site name via siteData
2268
+ site.name = newName;
2269
+ await siteData.updateSite(siteId, { name: newName });
2270
+ localLogger.info(`[${ADDON_NAME}] Successfully renamed site to: ${newName}`);
2271
+ return {
2272
+ success: true,
2273
+ error: null,
2274
+ newName,
2275
+ };
2276
+ }
2277
+ catch (error) {
2278
+ localLogger.error(`[${ADDON_NAME}] Failed to rename site:`, error);
2279
+ return {
2280
+ success: false,
2281
+ error: error.message || 'Unknown error',
2282
+ newName: null,
2283
+ };
2284
+ }
2285
+ },
2286
+ changePhpVersion: async (_parent, args) => {
2287
+ const { siteId, phpVersion } = args.input;
2288
+ try {
2289
+ const site = siteData.getSite(siteId);
2290
+ if (!site) {
2291
+ return {
2292
+ success: false,
2293
+ error: `Site not found: ${siteId}`,
2294
+ phpVersion: null,
2295
+ };
2296
+ }
2297
+ localLogger.info(`[${ADDON_NAME}] Changing PHP version for ${site.name} to ${phpVersion}`);
2298
+ if (siteProvisioner) {
2299
+ await siteProvisioner.swapService(site, 'php', phpVersion);
2300
+ }
2301
+ else {
2302
+ return {
2303
+ success: false,
2304
+ error: 'Site provisioner service not available',
2305
+ phpVersion: null,
2306
+ };
2307
+ }
2308
+ localLogger.info(`[${ADDON_NAME}] Successfully changed PHP version to: ${phpVersion}`);
2309
+ return {
2310
+ success: true,
2311
+ error: null,
2312
+ phpVersion,
2313
+ };
2314
+ }
2315
+ catch (error) {
2316
+ localLogger.error(`[${ADDON_NAME}] Failed to change PHP version:`, error);
2317
+ return {
2318
+ success: false,
2319
+ error: error.message || 'Unknown error',
2320
+ phpVersion: null,
2321
+ };
2322
+ }
2323
+ },
2324
+ importSite: async (_parent, args) => {
2325
+ const { zipPath, siteName } = args.input;
2326
+ const fs = require('fs');
2327
+ try {
2328
+ if (!fs.existsSync(zipPath)) {
2329
+ return {
2330
+ success: false,
2331
+ error: `Zip file not found: ${zipPath}`,
2332
+ siteId: null,
2333
+ siteName: null,
2334
+ };
2335
+ }
2336
+ localLogger.info(`[${ADDON_NAME}] Importing site from ${zipPath}`);
2337
+ if (!importSiteService) {
2338
+ return {
2339
+ success: false,
2340
+ error: 'Import site service not available',
2341
+ siteId: null,
2342
+ siteName: null,
2343
+ };
2344
+ }
2345
+ const result = await importSiteService.run({
2346
+ zipPath,
2347
+ siteName: siteName || undefined,
2348
+ });
2349
+ localLogger.info(`[${ADDON_NAME}] Successfully imported site: ${result.name}`);
2350
+ return {
2351
+ success: true,
2352
+ error: null,
2353
+ siteId: result.id,
2354
+ siteName: result.name,
2355
+ };
2356
+ }
2357
+ catch (error) {
2358
+ localLogger.error(`[${ADDON_NAME}] Failed to import site:`, error);
2359
+ return {
2360
+ success: false,
2361
+ error: error.message || 'Unknown error',
2362
+ siteId: null,
2363
+ siteName: null,
2364
+ };
2365
+ }
2366
+ },
2367
+ // Phase 9: Site Configuration & Dev Tools
2368
+ toggleXdebug: async (_parent, args) => {
2369
+ const { siteId, enabled } = args.input;
2370
+ try {
2371
+ const site = siteData.getSite(siteId);
2372
+ if (!site) {
2373
+ return {
2374
+ success: false,
2375
+ error: `Site not found: ${siteId}`,
2376
+ enabled: null,
2377
+ };
2378
+ }
2379
+ localLogger.info(`[${ADDON_NAME}] ${enabled ? 'Enabling' : 'Disabling'} Xdebug for ${site.name}`);
2380
+ // Update the site's xdebugEnabled property
2381
+ await siteData.updateSite(siteId, { xdebugEnabled: enabled });
2382
+ // Restart the site if it's running to apply the change
2383
+ const status = await siteProcessManager.getSiteStatus(site);
2384
+ if (status === 'running') {
2385
+ localLogger.info(`[${ADDON_NAME}] Restarting site to apply Xdebug change`);
2386
+ await siteProcessManager.restart(site);
2387
+ }
2388
+ localLogger.info(`[${ADDON_NAME}] Successfully ${enabled ? 'enabled' : 'disabled'} Xdebug`);
2389
+ return {
2390
+ success: true,
2391
+ error: null,
2392
+ enabled,
2393
+ };
2394
+ }
2395
+ catch (error) {
2396
+ localLogger.error(`[${ADDON_NAME}] Failed to toggle Xdebug:`, error);
2397
+ return {
2398
+ success: false,
2399
+ error: error.message || 'Unknown error',
2400
+ enabled: null,
2401
+ };
2402
+ }
2403
+ },
2404
+ getSiteLogs: async (_parent, args) => {
2405
+ const { siteId, logType = 'php', lines = 100 } = args.input;
2406
+ const fs = require('fs');
2407
+ const fsPromises = fs.promises;
2408
+ const pathModule = require('path');
2409
+ // Helper for async file existence check
2410
+ const fileExists = async (filePath) => {
2411
+ try {
2412
+ await fsPromises.access(filePath);
2413
+ return true;
2414
+ }
2415
+ catch {
2416
+ return false;
2417
+ }
2418
+ };
2419
+ // Helper to read last N lines of a file
2420
+ const readLastLines = async (filePath, numLines) => {
2421
+ try {
2422
+ const content = await fsPromises.readFile(filePath, 'utf-8');
2423
+ const logLines = content.split('\n');
2424
+ return logLines.slice(-numLines).join('\n') || '(empty)';
2425
+ }
2426
+ catch {
2427
+ return '';
2428
+ }
2429
+ };
2430
+ try {
2431
+ const site = siteData.getSite(siteId);
2432
+ if (!site) {
2433
+ return {
2434
+ success: false,
2435
+ error: `Site not found: ${siteId}`,
2436
+ logs: [],
2437
+ };
2438
+ }
2439
+ localLogger.info(`[${ADDON_NAME}] Getting ${logType} logs for ${site.name}`);
2440
+ const logs = [];
2441
+ const logsDir = pathModule.join(site.path, 'logs');
2442
+ const logFiles = {
2443
+ php: ['php', 'php-fpm'],
2444
+ nginx: ['nginx'],
2445
+ mysql: ['mysql'],
2446
+ all: ['php', 'php-fpm', 'nginx', 'mysql'],
2447
+ };
2448
+ const targetLogs = logFiles[logType] || logFiles.php;
2449
+ for (const logName of targetLogs) {
2450
+ // Check for error and access logs
2451
+ for (const suffix of ['error.log', 'access.log', '.log']) {
2452
+ const logPath = pathModule.join(logsDir, `${logName}${suffix === '.log' ? '' : '/'}${suffix}`);
2453
+ const altLogPath = pathModule.join(logsDir, `${logName}${suffix}`);
2454
+ let finalPath = null;
2455
+ if (await fileExists(logPath)) {
2456
+ finalPath = logPath;
2457
+ }
2458
+ else if (await fileExists(altLogPath)) {
2459
+ finalPath = altLogPath;
2460
+ }
2461
+ if (finalPath) {
2462
+ const content = await readLastLines(finalPath, lines);
2463
+ if (content) {
2464
+ logs.push({
2465
+ type: logName,
2466
+ content,
2467
+ path: finalPath,
2468
+ });
2469
+ }
2470
+ }
2471
+ }
2472
+ }
2473
+ if (logs.length === 0) {
2474
+ // Try to find any log files
2475
+ if (await fileExists(logsDir)) {
2476
+ const entries = await fsPromises.readdir(logsDir, { withFileTypes: true });
2477
+ for (const entry of entries) {
2478
+ if (entry.isDirectory()) {
2479
+ const subDir = pathModule.join(logsDir, entry.name);
2480
+ const subEntries = await fsPromises.readdir(subDir);
2481
+ for (const subFile of subEntries) {
2482
+ if (subFile.endsWith('.log')) {
2483
+ const logPath = pathModule.join(subDir, subFile);
2484
+ const content = await readLastLines(logPath, lines);
2485
+ if (content) {
2486
+ logs.push({
2487
+ type: entry.name,
2488
+ content,
2489
+ path: logPath,
2490
+ });
2491
+ }
2492
+ }
2493
+ }
2494
+ }
2495
+ else if (entry.name.endsWith('.log')) {
2496
+ const logPath = pathModule.join(logsDir, entry.name);
2497
+ const content = await readLastLines(logPath, lines);
2498
+ if (content) {
2499
+ logs.push({
2500
+ type: entry.name.replace('.log', ''),
2501
+ content,
2502
+ path: logPath,
2503
+ });
2504
+ }
2505
+ }
2506
+ }
2507
+ }
2508
+ }
2509
+ return {
2510
+ success: true,
2511
+ error: null,
2512
+ logs,
2513
+ };
2514
+ }
2515
+ catch (error) {
2516
+ localLogger.error(`[${ADDON_NAME}] Failed to get logs:`, error);
2517
+ return {
2518
+ success: false,
2519
+ error: error.message || 'Unknown error',
2520
+ logs: [],
2521
+ };
2522
+ }
2523
+ },
2524
+ // Phase 10: Cloud Backup Mutations
2525
+ createBackup: async (_parent, args) => {
2526
+ const { siteId, provider, note } = args;
2527
+ try {
2528
+ localLogger.info(`[${ADDON_NAME}] Creating backup for site ${siteId} to ${provider}`);
2529
+ // Get site
2530
+ const site = siteData.getSite(siteId);
2531
+ if (!site) {
2532
+ return {
2533
+ success: false,
2534
+ snapshotId: null,
2535
+ timestamp: null,
2536
+ message: null,
2537
+ error: `Site not found: ${siteId}`,
2538
+ };
2539
+ }
2540
+ // Get providers from Cloud Backups addon
2541
+ const providers = await getBackupProviders();
2542
+ if (providers.length === 0) {
2543
+ return {
2544
+ success: false,
2545
+ snapshotId: null,
2546
+ timestamp: null,
2547
+ message: null,
2548
+ error: 'No cloud storage providers configured. Connect Google Drive or Dropbox in Local Hub.',
2549
+ };
2550
+ }
2551
+ // Find the matching provider (map 'googleDrive' to 'google' for the addon)
2552
+ const providerMap = { googleDrive: 'google', dropbox: 'dropbox' };
2553
+ const providerId = providerMap[provider] || provider;
2554
+ const matchedProvider = providers.find((p) => p.id === providerId);
2555
+ if (!matchedProvider) {
2556
+ return {
2557
+ success: false,
2558
+ snapshotId: null,
2559
+ timestamp: null,
2560
+ message: null,
2561
+ error: `Provider '${provider}' not configured. Available: ${providers.map((p) => p.name).join(', ')}`,
2562
+ };
2563
+ }
2564
+ // Map the Hub provider ID to rclone backend name
2565
+ // The addon uses 'google' in enabled-providers but expects 'drive' for backup operations
2566
+ const backupProviderMap = { google: 'drive', dropbox: 'dropbox' };
2567
+ const backupProviderId = backupProviderMap[matchedProvider.id] || matchedProvider.id;
2568
+ localLogger.info(`[${ADDON_NAME}] Using backup provider ID: ${backupProviderId} (from ${matchedProvider.id})`);
2569
+ // Create backup via IPC (use long timeout for backup operations)
2570
+ const description = note || 'Backup created via MCP';
2571
+ const result = await invokeBackupIPC('backups:backup-site', BACKUP_IPC_TIMEOUT, siteId, backupProviderId, description);
2572
+ localLogger.info(`[${ADDON_NAME}] Backup IPC result: ${JSON.stringify(result)}`);
2573
+ // Check for top-level IPC error
2574
+ if (result.error) {
2575
+ return {
2576
+ success: false,
2577
+ snapshotId: null,
2578
+ timestamp: null,
2579
+ message: null,
2580
+ error: result.error.message || 'Backup creation failed',
2581
+ };
2582
+ }
2583
+ // Unwrap nested result structure - the actual result is at result.result
2584
+ const backupResult = result.result;
2585
+ // Check if the backup result contains an error (nested at result.result.error)
2586
+ if (backupResult?.error) {
2587
+ const errorMsg = backupResult.error.message || backupResult.error.original?.message || 'Backup failed';
2588
+ return {
2589
+ success: false,
2590
+ snapshotId: null,
2591
+ timestamp: null,
2592
+ message: null,
2593
+ error: errorMsg,
2594
+ };
2595
+ }
2596
+ // Try to extract snapshot ID (may be nested in result.result.result)
2597
+ let snapshotId = backupResult?.snapshotId || backupResult?.id;
2598
+ if (!snapshotId && backupResult?.result) {
2599
+ snapshotId = backupResult.result.snapshotId || backupResult.result.id;
2600
+ }
2601
+ // If no error was returned, the backup succeeded even if no snapshot ID is provided
2602
+ // The addon doesn't always return the snapshot ID in its IPC response
2603
+ return {
2604
+ success: true,
2605
+ snapshotId: snapshotId || null,
2606
+ timestamp: new Date().toISOString(),
2607
+ message: `Backup created successfully to ${matchedProvider.name}`,
2608
+ error: null,
2609
+ };
2610
+ }
2611
+ catch (error) {
2612
+ localLogger.error(`[${ADDON_NAME}] Failed to create backup:`, error);
2613
+ return {
2614
+ success: false,
2615
+ snapshotId: null,
2616
+ timestamp: null,
2617
+ message: null,
2618
+ error: error.message || 'Unknown error',
2619
+ };
2620
+ }
2621
+ },
2622
+ restoreBackup: async (_parent, args) => {
2623
+ const { siteId, provider, snapshotId, confirm = false } = args;
2624
+ try {
2625
+ localLogger.info(`[${ADDON_NAME}] Restoring backup ${snapshotId} for site ${siteId}`);
2626
+ // Check confirmation
2627
+ if (!confirm) {
2628
+ return {
2629
+ success: false,
2630
+ message: null,
2631
+ error: 'Restore requires confirm=true to prevent accidental data loss. Current site files and database will be overwritten.',
2632
+ };
2633
+ }
2634
+ // Get site
2635
+ const site = siteData.getSite(siteId);
2636
+ if (!site) {
2637
+ return {
2638
+ success: false,
2639
+ message: null,
2640
+ error: `Site not found: ${siteId}`,
2641
+ };
2642
+ }
2643
+ // Get providers from Cloud Backups addon
2644
+ const providers = await getBackupProviders();
2645
+ if (providers.length === 0) {
2646
+ return {
2647
+ success: false,
2648
+ message: null,
2649
+ error: 'No cloud storage providers configured. Connect Google Drive or Dropbox in Local Hub.',
2650
+ };
2651
+ }
2652
+ // Find the matching provider (map 'googleDrive' to 'google' for the addon)
2653
+ const providerMap = { googleDrive: 'google', dropbox: 'dropbox' };
2654
+ const providerId = providerMap[provider] || provider;
2655
+ const matchedProvider = providers.find((p) => p.id === providerId);
2656
+ if (!matchedProvider) {
2657
+ return {
2658
+ success: false,
2659
+ message: null,
2660
+ error: `Provider '${provider}' not configured. Available: ${providers.map((p) => p.name).join(', ')}`,
2661
+ };
2662
+ }
2663
+ // Map the Hub provider ID to rclone backend name
2664
+ const backupProviderMap = { google: 'drive', dropbox: 'dropbox' };
2665
+ const backupProviderId = backupProviderMap[matchedProvider.id] || matchedProvider.id;
2666
+ // Restore backup via IPC (use long timeout for restore operations)
2667
+ const result = await invokeBackupIPC('backups:restore-backup', BACKUP_IPC_TIMEOUT, siteId, backupProviderId, snapshotId);
2668
+ localLogger.info(`[${ADDON_NAME}] Restore result: ${JSON.stringify(result)}`);
2669
+ // Check for errors - can be at result.error or result.result.error (IPC async pattern)
2670
+ const ipcError = result.error || result.result?.error;
2671
+ if (ipcError) {
2672
+ const errorMessage = typeof ipcError === 'string' ? ipcError : ipcError.message || 'Restore failed';
2673
+ return {
2674
+ success: false,
2675
+ message: null,
2676
+ error: errorMessage,
2677
+ };
2678
+ }
2679
+ return {
2680
+ success: true,
2681
+ message: `Site restored from backup ${snapshotId}`,
2682
+ error: null,
2683
+ };
2684
+ }
2685
+ catch (error) {
2686
+ localLogger.error(`[${ADDON_NAME}] Failed to restore backup:`, error);
2687
+ return {
2688
+ success: false,
2689
+ message: null,
2690
+ error: error.message || 'Unknown error',
2691
+ };
2692
+ }
2693
+ },
2694
+ deleteBackup: async (_parent, args) => {
2695
+ const { siteId, provider, snapshotId, confirm = false } = args;
2696
+ try {
2697
+ localLogger.info(`[${ADDON_NAME}] Deleting backup ${snapshotId} for site ${siteId}`);
2698
+ // Check confirmation
2699
+ if (!confirm) {
2700
+ return {
2701
+ success: false,
2702
+ deletedSnapshotId: null,
2703
+ message: null,
2704
+ error: 'Delete requires confirm=true to prevent accidental deletion.',
2705
+ };
2706
+ }
2707
+ // Get site
2708
+ const site = siteData.getSite(siteId);
2709
+ if (!site) {
2710
+ return {
2711
+ success: false,
2712
+ deletedSnapshotId: null,
2713
+ message: null,
2714
+ error: `Site not found: ${siteId}`,
2715
+ };
2716
+ }
2717
+ // Get providers from Cloud Backups addon
2718
+ const providers = await getBackupProviders();
2719
+ if (providers.length === 0) {
2720
+ return {
2721
+ success: false,
2722
+ deletedSnapshotId: null,
2723
+ message: null,
2724
+ error: 'No cloud storage providers configured. Connect Google Drive or Dropbox in Local Hub.',
2725
+ };
2726
+ }
2727
+ // Find the matching provider (map 'googleDrive' to 'google' for the addon)
2728
+ const providerMap = { googleDrive: 'google', dropbox: 'dropbox' };
2729
+ const providerId = providerMap[provider] || provider;
2730
+ const matchedProvider = providers.find((p) => p.id === providerId);
2731
+ if (!matchedProvider) {
2732
+ return {
2733
+ success: false,
2734
+ deletedSnapshotId: null,
2735
+ message: null,
2736
+ error: `Provider '${provider}' not configured. Available: ${providers.map((p) => p.name).join(', ')}`,
2737
+ };
2738
+ }
2739
+ // Map the Hub provider ID to rclone backend name
2740
+ const backupProviderMap = { google: 'drive', dropbox: 'dropbox' };
2741
+ const backupProviderId = backupProviderMap[matchedProvider.id] || matchedProvider.id;
2742
+ // Try to delete backup via IPC (may not be supported by the addon)
2743
+ const result = await invokeBackupIPC('backups:delete-backup', DEFAULT_IPC_TIMEOUT, siteId, backupProviderId, snapshotId);
2744
+ if (result.error) {
2745
+ // If the IPC channel doesn't exist or isn't supported, provide helpful message
2746
+ if (result.error.message?.includes('timed out')) {
2747
+ return {
2748
+ success: false,
2749
+ deletedSnapshotId: null,
2750
+ message: null,
2751
+ error: 'Delete backup operation is not available via MCP. Please delete backups through the Local UI.',
2752
+ };
2753
+ }
2754
+ return {
2755
+ success: false,
2756
+ deletedSnapshotId: null,
2757
+ message: null,
2758
+ error: result.error.message || 'Delete failed',
2759
+ };
2760
+ }
2761
+ return {
2762
+ success: true,
2763
+ deletedSnapshotId: snapshotId,
2764
+ message: 'Backup deleted',
2765
+ error: null,
2766
+ };
2767
+ }
2768
+ catch (error) {
2769
+ localLogger.error(`[${ADDON_NAME}] Failed to delete backup:`, error);
2770
+ return {
2771
+ success: false,
2772
+ deletedSnapshotId: null,
2773
+ message: null,
2774
+ error: error.message || 'Unknown error',
2775
+ };
2776
+ }
2777
+ },
2778
+ downloadBackup: async (_parent, args) => {
2779
+ const { siteId, provider, snapshotId } = args;
2780
+ try {
2781
+ localLogger.info(`[${ADDON_NAME}] Downloading backup ${snapshotId} for site ${siteId}`);
2782
+ // Get site
2783
+ const site = siteData.getSite(siteId);
2784
+ if (!site) {
2785
+ return {
2786
+ success: false,
2787
+ filePath: null,
2788
+ message: null,
2789
+ error: `Site not found: ${siteId}`,
2790
+ };
2791
+ }
2792
+ // Get providers from Cloud Backups addon
2793
+ const providers = await getBackupProviders();
2794
+ if (providers.length === 0) {
2795
+ return {
2796
+ success: false,
2797
+ filePath: null,
2798
+ message: null,
2799
+ error: 'No cloud storage providers configured. Connect Google Drive or Dropbox in Local Hub.',
2800
+ };
2801
+ }
2802
+ // Find the matching provider (map 'googleDrive' to 'google' for the addon)
2803
+ const providerMap = { googleDrive: 'google', dropbox: 'dropbox' };
2804
+ const providerId = providerMap[provider] || provider;
2805
+ const matchedProvider = providers.find((p) => p.id === providerId);
2806
+ if (!matchedProvider) {
2807
+ return {
2808
+ success: false,
2809
+ filePath: null,
2810
+ message: null,
2811
+ error: `Provider '${provider}' not configured. Available: ${providers.map((p) => p.name).join(', ')}`,
2812
+ };
2813
+ }
2814
+ // Map the Hub provider ID to rclone backend name
2815
+ const backupProviderMap = { google: 'drive', dropbox: 'dropbox' };
2816
+ const backupProviderId = backupProviderMap[matchedProvider.id] || matchedProvider.id;
2817
+ // Try to download backup via IPC (use long timeout for downloads)
2818
+ const result = await invokeBackupIPC('backups:download-backup', BACKUP_IPC_TIMEOUT, siteId, backupProviderId, snapshotId);
2819
+ if (result.error) {
2820
+ // If the IPC channel doesn't exist or isn't supported, provide helpful message
2821
+ if (result.error.message?.includes('timed out')) {
2822
+ return {
2823
+ success: false,
2824
+ filePath: null,
2825
+ message: null,
2826
+ error: 'Download backup operation is not available via MCP. Please download backups through the Local UI.',
2827
+ };
2828
+ }
2829
+ return {
2830
+ success: false,
2831
+ filePath: null,
2832
+ message: null,
2833
+ error: result.error.message || 'Download failed',
2834
+ };
2835
+ }
2836
+ return {
2837
+ success: true,
2838
+ filePath: result.result?.filePath || null,
2839
+ message: 'Backup downloaded to Downloads folder',
2840
+ error: null,
2841
+ };
2842
+ }
2843
+ catch (error) {
2844
+ localLogger.error(`[${ADDON_NAME}] Failed to download backup:`, error);
2845
+ return {
2846
+ success: false,
2847
+ filePath: null,
2848
+ message: null,
2849
+ error: error.message || 'Unknown error',
2850
+ };
2851
+ }
2852
+ },
2853
+ editBackupNote: async (_parent, args) => {
2854
+ const { siteId, provider, snapshotId, note } = args;
2855
+ try {
2856
+ localLogger.info(`[${ADDON_NAME}] Editing backup note for ${snapshotId}`);
2857
+ // Get site
2858
+ const site = siteData.getSite(siteId);
2859
+ if (!site) {
2860
+ return {
2861
+ success: false,
2862
+ snapshotId: null,
2863
+ note: null,
2864
+ error: `Site not found: ${siteId}`,
2865
+ };
2866
+ }
2867
+ // Get providers from Cloud Backups addon
2868
+ const providers = await getBackupProviders();
2869
+ if (providers.length === 0) {
2870
+ return {
2871
+ success: false,
2872
+ snapshotId: null,
2873
+ note: null,
2874
+ error: 'No cloud storage providers configured. Connect Google Drive or Dropbox in Local Hub.',
2875
+ };
2876
+ }
2877
+ // Find the matching provider (map 'googleDrive' to 'google' for the addon)
2878
+ const providerMap = { googleDrive: 'google', dropbox: 'dropbox' };
2879
+ const providerId = providerMap[provider] || provider;
2880
+ const matchedProvider = providers.find((p) => p.id === providerId);
2881
+ if (!matchedProvider) {
2882
+ return {
2883
+ success: false,
2884
+ snapshotId: null,
2885
+ note: null,
2886
+ error: `Provider '${provider}' not configured. Available: ${providers.map((p) => p.name).join(', ')}`,
2887
+ };
2888
+ }
2889
+ // Map the Hub provider ID to rclone backend name
2890
+ const backupProviderMap = { google: 'drive', dropbox: 'dropbox' };
2891
+ const backupProviderId = backupProviderMap[matchedProvider.id] || matchedProvider.id;
2892
+ // Try to edit backup note via IPC (quick metadata operation)
2893
+ const result = await invokeBackupIPC('backups:edit-note', DEFAULT_IPC_TIMEOUT, siteId, backupProviderId, snapshotId, note);
2894
+ if (result.error) {
2895
+ // If the IPC channel doesn't exist or isn't supported, provide helpful message
2896
+ if (result.error.message?.includes('timed out')) {
2897
+ return {
2898
+ success: false,
2899
+ snapshotId: null,
2900
+ note: null,
2901
+ error: 'Edit backup note operation is not available via MCP. Please edit backup notes through the Local UI.',
2902
+ };
2903
+ }
2904
+ return {
2905
+ success: false,
2906
+ snapshotId: null,
2907
+ note: null,
2908
+ error: result.error.message || 'Edit note failed',
2909
+ };
2910
+ }
2911
+ return {
2912
+ success: true,
2913
+ snapshotId,
2914
+ note,
2915
+ error: null,
2916
+ };
2917
+ }
2918
+ catch (error) {
2919
+ localLogger.error(`[${ADDON_NAME}] Failed to edit backup note:`, error);
2920
+ return {
2921
+ success: false,
2922
+ snapshotId: null,
2923
+ note: null,
2924
+ error: error.message || 'Unknown error',
2925
+ };
2926
+ }
2927
+ },
2928
+ // Phase 11: WP Engine Connect
2929
+ wpeAuthenticate: async () => {
2930
+ try {
2931
+ localLogger.info(`[${ADDON_NAME}] Initiating WP Engine authentication`);
2932
+ if (!wpeOAuthService) {
2933
+ return {
2934
+ success: false,
2935
+ email: null,
2936
+ message: null,
2937
+ error: 'WP Engine OAuth service not available',
2938
+ };
2939
+ }
2940
+ // Trigger OAuth flow - this will open browser for user consent
2941
+ // authenticate() returns OAuthTokens on success
2942
+ const tokens = await wpeOAuthService.authenticate();
2943
+ if (tokens && tokens.accessToken) {
2944
+ // Try to get user email from CAPI
2945
+ let email = null;
2946
+ if (capiService) {
2947
+ try {
2948
+ const currentUser = await capiService.getCurrentUser();
2949
+ email = currentUser?.email || null;
2950
+ }
2951
+ catch {
2952
+ // User info not available
2953
+ }
2954
+ }
2955
+ localLogger.info(`[${ADDON_NAME}] Successfully authenticated with WPE${email ? ` as ${email}` : ''}`);
2956
+ return {
2957
+ success: true,
2958
+ email,
2959
+ message: 'Successfully authenticated with WP Engine',
2960
+ error: null,
2961
+ };
2962
+ }
2963
+ return {
2964
+ success: true,
2965
+ email: null,
2966
+ message: 'Authentication initiated. Please complete the login in your browser.',
2967
+ error: null,
2968
+ };
2969
+ }
2970
+ catch (error) {
2971
+ localLogger.error(`[${ADDON_NAME}] WPE authentication failed:`, error);
2972
+ return {
2973
+ success: false,
2974
+ email: null,
2975
+ message: null,
2976
+ error: error.message || 'Authentication failed',
2977
+ };
2978
+ }
2979
+ },
2980
+ wpeLogout: async () => {
2981
+ try {
2982
+ localLogger.info(`[${ADDON_NAME}] Logging out from WP Engine`);
2983
+ if (!wpeOAuthService) {
2984
+ return {
2985
+ success: false,
2986
+ message: null,
2987
+ error: 'WP Engine OAuth service not available',
2988
+ };
2989
+ }
2990
+ // clearTokens() is the logout method
2991
+ await wpeOAuthService.clearTokens();
2992
+ localLogger.info(`[${ADDON_NAME}] Successfully logged out from WPE`);
2993
+ return {
2994
+ success: true,
2995
+ message: 'Logged out from WP Engine',
2996
+ error: null,
2997
+ };
2998
+ }
2999
+ catch (error) {
3000
+ localLogger.error(`[${ADDON_NAME}] WPE logout failed:`, error);
3001
+ return {
3002
+ success: false,
3003
+ message: null,
3004
+ error: error.message || 'Logout failed',
3005
+ };
3006
+ }
3007
+ },
3008
+ // Phase 11c: Push to WP Engine
3009
+ pushToWpe: async (_parent, args) => {
3010
+ const { localSiteId, remoteInstallId, includeSql = false, confirm = false } = args;
3011
+ try {
3012
+ localLogger.info(`[${ADDON_NAME}] Push to WPE: site=${localSiteId}, remote=${remoteInstallId}, includeSql=${includeSql}`);
3013
+ // Require confirmation for push operations
3014
+ if (!confirm) {
3015
+ return {
3016
+ success: false,
3017
+ message: null,
3018
+ error: 'Push requires confirm=true to prevent accidental overwrites. Set confirm=true to proceed.',
3019
+ };
3020
+ }
3021
+ // Verify site exists
3022
+ const site = siteData.getSite(localSiteId);
3023
+ if (!site) {
3024
+ return {
3025
+ success: false,
3026
+ message: null,
3027
+ error: `Site not found: ${localSiteId}`,
3028
+ };
3029
+ }
3030
+ // Check WPE connection exists
3031
+ const wpeConnection = site.hostConnections?.find((c) => c.hostId === 'wpe');
3032
+ if (!wpeConnection) {
3033
+ return {
3034
+ success: false,
3035
+ message: null,
3036
+ error: 'Site is not linked to WP Engine. Use Connect in Local to link the site first.',
3037
+ };
3038
+ }
3039
+ // Check push service availability
3040
+ if (!wpePushService || typeof wpePushService.push !== 'function') {
3041
+ return {
3042
+ success: false,
3043
+ message: null,
3044
+ error: 'WPE Push service not available',
3045
+ };
3046
+ }
3047
+ // Get install details from CAPI to get required parameters
3048
+ let installName = remoteInstallId;
3049
+ let primaryDomain = '';
3050
+ let installId = '';
3051
+ if (capiService && typeof capiService.getInstallList === 'function') {
3052
+ const installs = await capiService.getInstallList();
3053
+ const matchingInstall = installs?.find((i) => i.site?.id === wpeConnection.remoteSiteId &&
3054
+ (!wpeConnection.remoteSiteEnv || i.environment === wpeConnection.remoteSiteEnv));
3055
+ if (matchingInstall) {
3056
+ installName = matchingInstall.name;
3057
+ primaryDomain =
3058
+ matchingInstall.primary_domain ||
3059
+ matchingInstall.cname ||
3060
+ `${matchingInstall.name}.wpengine.com`;
3061
+ installId = matchingInstall.id;
3062
+ }
3063
+ }
3064
+ if (!primaryDomain) {
3065
+ return {
3066
+ success: false,
3067
+ message: null,
3068
+ error: 'Could not determine WP Engine install details. Please ensure you are authenticated.',
3069
+ };
3070
+ }
3071
+ // Start the push operation (async - returns immediately)
3072
+ wpePushService
3073
+ .push({
3074
+ includeSql,
3075
+ wpengineInstallName: installName,
3076
+ wpengineInstallId: installId,
3077
+ wpengineSiteId: wpeConnection.remoteSiteId,
3078
+ wpenginePrimaryDomain: primaryDomain,
3079
+ localSiteId: site.id,
3080
+ environment: wpeConnection.remoteSiteEnv,
3081
+ isMagicSync: false,
3082
+ })
3083
+ .catch((err) => {
3084
+ localLogger.error(`[${ADDON_NAME}] Push failed:`, err);
3085
+ });
3086
+ return {
3087
+ success: true,
3088
+ message: `Push started to ${installName}. Check Local UI for progress.`,
3089
+ error: null,
3090
+ };
3091
+ }
3092
+ catch (error) {
3093
+ localLogger.error(`[${ADDON_NAME}] Failed to start push:`, error);
3094
+ return {
3095
+ success: false,
3096
+ message: null,
3097
+ error: error.message || 'Failed to start push',
3098
+ };
3099
+ }
3100
+ },
3101
+ // Phase 11c: Pull from WP Engine
3102
+ pullFromWpe: async (_parent, args) => {
3103
+ const { localSiteId, remoteInstallId, includeSql = false } = args;
3104
+ try {
3105
+ localLogger.info(`[${ADDON_NAME}] Pull from WPE: site=${localSiteId}, remote=${remoteInstallId}, includeSql=${includeSql}`);
3106
+ // Verify site exists
3107
+ const site = siteData.getSite(localSiteId);
3108
+ if (!site) {
3109
+ return {
3110
+ success: false,
3111
+ message: null,
3112
+ error: `Site not found: ${localSiteId}`,
3113
+ };
3114
+ }
3115
+ // Check WPE connection exists
3116
+ const wpeConnection = site.hostConnections?.find((c) => c.hostId === 'wpe');
3117
+ if (!wpeConnection) {
3118
+ return {
3119
+ success: false,
3120
+ message: null,
3121
+ error: 'Site is not linked to WP Engine. Use Connect in Local to link the site first.',
3122
+ };
3123
+ }
3124
+ // Check pull service availability
3125
+ if (!wpePullService || typeof wpePullService.pull !== 'function') {
3126
+ return {
3127
+ success: false,
3128
+ message: null,
3129
+ error: 'WPE Pull service not available',
3130
+ };
3131
+ }
3132
+ // Get install details from CAPI
3133
+ let installName = remoteInstallId;
3134
+ let primaryDomain = '';
3135
+ let installId = '';
3136
+ if (capiService && typeof capiService.getInstallList === 'function') {
3137
+ const installs = await capiService.getInstallList();
3138
+ const matchingInstall = installs?.find((i) => i.site?.id === wpeConnection.remoteSiteId &&
3139
+ (!wpeConnection.remoteSiteEnv || i.environment === wpeConnection.remoteSiteEnv));
3140
+ if (matchingInstall) {
3141
+ installName = matchingInstall.name;
3142
+ primaryDomain =
3143
+ matchingInstall.primary_domain ||
3144
+ matchingInstall.cname ||
3145
+ `${matchingInstall.name}.wpengine.com`;
3146
+ installId = matchingInstall.id;
3147
+ }
3148
+ }
3149
+ if (!primaryDomain) {
3150
+ return {
3151
+ success: false,
3152
+ message: null,
3153
+ error: 'Could not determine WP Engine install details. Please ensure you are authenticated.',
3154
+ };
3155
+ }
3156
+ // Start the pull operation (async - returns immediately)
3157
+ wpePullService
3158
+ .pull({
3159
+ includeSql,
3160
+ wpengineInstallName: installName,
3161
+ wpengineInstallId: installId,
3162
+ wpengineSiteId: wpeConnection.remoteSiteId,
3163
+ wpenginePrimaryDomain: primaryDomain,
3164
+ localSiteId: site.id,
3165
+ environment: wpeConnection.remoteSiteEnv,
3166
+ isMagicSync: false,
3167
+ })
3168
+ .catch((err) => {
3169
+ localLogger.error(`[${ADDON_NAME}] Pull failed:`, err);
3170
+ });
3171
+ return {
3172
+ success: true,
3173
+ message: `Pull started from ${installName}. Check Local UI for progress.`,
3174
+ error: null,
3175
+ };
3176
+ }
3177
+ catch (error) {
3178
+ localLogger.error(`[${ADDON_NAME}] Failed to start pull:`, error);
3179
+ return {
3180
+ success: false,
3181
+ message: null,
3182
+ error: error.message || 'Failed to start pull',
3183
+ };
3184
+ }
3185
+ },
3186
+ },
3187
+ };
3188
+ }
3189
+ /**
3190
+ * Start the MCP server
3191
+ */
3192
+ async function startMcpServer(services, logger) {
3193
+ if (mcpServer) {
3194
+ logger.warn(`[${ADDON_NAME}] MCP server already running`);
3195
+ return;
3196
+ }
3197
+ try {
3198
+ mcpServer = new McpServer_1.McpServer({ port: constants_1.MCP_SERVER.DEFAULT_PORT }, services, logger);
3199
+ await mcpServer.start();
3200
+ const info = mcpServer.getConnectionInfo();
3201
+ logger.info(`[${ADDON_NAME}] MCP server started on port ${info.port}`);
3202
+ logger.info(`[${ADDON_NAME}] MCP connection info saved to: ~/Library/Application Support/Local/mcp-connection-info.json`);
3203
+ logger.info(`[${ADDON_NAME}] Available tools: ${info.tools.join(', ')}`);
3204
+ }
3205
+ catch (error) {
3206
+ logger.error(`[${ADDON_NAME}] Failed to start MCP server:`, error);
3207
+ }
3208
+ }
3209
+ /**
3210
+ * Stop the MCP server
3211
+ */
3212
+ async function stopMcpServer(logger) {
3213
+ if (mcpServer) {
3214
+ await mcpServer.stop();
3215
+ mcpServer = null;
3216
+ logger.info(`[${ADDON_NAME}] MCP server stopped`);
3217
+ }
3218
+ }
3219
+ /**
3220
+ * Register IPC handlers for renderer communication
3221
+ */
3222
+ function registerIpcHandlers(services, logger) {
3223
+ // Get MCP server status
3224
+ electron_1.ipcMain.handle('mcp:getStatus', async () => {
3225
+ if (!mcpServer) {
3226
+ return { running: false, port: 0, uptime: 0 };
3227
+ }
3228
+ return mcpServer.getStatus();
3229
+ });
3230
+ // Get connection info
3231
+ electron_1.ipcMain.handle('mcp:getConnectionInfo', async () => {
3232
+ if (!mcpServer) {
3233
+ return null;
3234
+ }
3235
+ return mcpServer.getConnectionInfo();
3236
+ });
3237
+ // Start MCP server
3238
+ electron_1.ipcMain.handle('mcp:start', async () => {
3239
+ try {
3240
+ await startMcpServer(services, logger);
3241
+ return { success: true };
3242
+ }
3243
+ catch (error) {
3244
+ return { success: false, error: error.message };
3245
+ }
3246
+ });
3247
+ // Stop MCP server
3248
+ electron_1.ipcMain.handle('mcp:stop', async () => {
3249
+ try {
3250
+ await stopMcpServer(logger);
3251
+ return { success: true };
3252
+ }
3253
+ catch (error) {
3254
+ return { success: false, error: error.message };
3255
+ }
3256
+ });
3257
+ // Restart MCP server
3258
+ electron_1.ipcMain.handle('mcp:restart', async () => {
3259
+ try {
3260
+ await stopMcpServer(logger);
3261
+ await startMcpServer(services, logger);
3262
+ return { success: true };
3263
+ }
3264
+ catch (error) {
3265
+ return { success: false, error: error.message };
3266
+ }
3267
+ });
3268
+ // Regenerate auth token
3269
+ electron_1.ipcMain.handle('mcp:regenerateToken', async () => {
3270
+ if (!mcpServer) {
3271
+ return { success: false, error: 'MCP server not running' };
3272
+ }
3273
+ try {
3274
+ const newToken = await mcpServer.regenerateToken();
3275
+ return { success: true, token: newToken };
3276
+ }
3277
+ catch (error) {
3278
+ return { success: false, error: error.message };
3279
+ }
3280
+ });
3281
+ logger.info(`[${ADDON_NAME}] Registered IPC handlers: mcp:getStatus, mcp:getConnectionInfo, mcp:start, mcp:stop, mcp:restart, mcp:regenerateToken`);
3282
+ }
3283
+ /**
3284
+ * Main addon initialization function
3285
+ */
3286
+ function default_1(_context) {
3287
+ const services = LocalMain.getServiceContainer().cradle;
3288
+ const { localLogger, graphql } = services;
3289
+ try {
3290
+ localLogger.info(`[${ADDON_NAME}] Initializing...`);
3291
+ // Register GraphQL extensions (for local-cli and MCP)
3292
+ const resolvers = createResolvers(services);
3293
+ graphql.registerGraphQLService('mcp-server', typeDefs, resolvers);
3294
+ localLogger.info(`[${ADDON_NAME}] Registered GraphQL: 29 tools (Phase 1-11b)`);
3295
+ // Start MCP server (for AI tools)
3296
+ const localServices = {
3297
+ siteData: services.siteData,
3298
+ siteProcessManager: services.siteProcessManager,
3299
+ wpCli: services.wpCli,
3300
+ deleteSite: services.deleteSite,
3301
+ addSite: services.addSite,
3302
+ localLogger: services.localLogger,
3303
+ adminer: services.adminer,
3304
+ x509Cert: services.x509Cert,
3305
+ siteProvisioner: services.siteProvisioner,
3306
+ importSite: services.importSite,
3307
+ lightningServices: services.lightningServices,
3308
+ // Phase 11: WP Engine Connect
3309
+ wpeOAuth: services.wpeOAuth,
3310
+ capi: services.capi,
3311
+ };
3312
+ // MCP server disabled - CLI-only mode
3313
+ // To enable MCP server for AI tool integration, uncomment the following:
3314
+ // startMcpServer(localServices, localLogger);
3315
+ // registerIpcHandlers(localServices, localLogger);
3316
+ localLogger.info(`[${ADDON_NAME}] Successfully initialized (CLI-only mode)`);
3317
+ }
3318
+ catch (error) {
3319
+ localLogger.error(`[${ADDON_NAME}] Failed to initialize:`, error);
3320
+ }
3321
+ }
3322
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbWFpbi9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7OztHQU1HOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQXdzSEgsNEJBdUNDO0FBN3VIRCxtRUFBcUQ7QUFDckQsdUNBQW1DO0FBQ25DLDhEQUE4QjtBQUM5QiwrQ0FBNEM7QUFDNUMsbURBQWlEO0FBR2pELE1BQU0sVUFBVSxHQUFHLFlBQVksQ0FBQztBQUVoQyxJQUFJLFNBQVMsR0FBcUIsSUFBSSxDQUFDO0FBRXZDOztHQUVHO0FBQ0gsTUFBTSxRQUFRLEdBQUcsSUFBQSxxQkFBRyxFQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7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QVEsQ0FBQyxXQUFXO1lBQ2pDLE9BQU8sRUFBRSxRQUFRLENBQUMsT0FBTztZQUN6QixRQUFRLEVBQUUsUUFBUSxDQUFDLFFBQVE7WUFDM0IsZUFBZSxFQUFFLFFBQVEsQ0FBQyxlQUFlO1lBQ3pDLFVBQVUsRUFBRSxRQUFRLENBQUMsVUFBVTtZQUMvQixpQkFBaUIsRUFBRSxRQUFRLENBQUMsaUJBQWlCO1lBQzdDLDhCQUE4QjtZQUM5QixRQUFRLEVBQUUsUUFBUSxDQUFDLFFBQVE7WUFDM0IsSUFBSSxFQUFFLFFBQVEsQ0FBQyxJQUFJO1NBQ3BCLENBQUM7UUFFRixzQ0FBc0M7UUFDdEMseUVBQXlFO1FBQ3pFLDhDQUE4QztRQUM5QyxtREFBbUQ7UUFFbkQsV0FBVyxDQUFDLElBQUksQ0FBQyxJQUFJLFVBQVUsNENBQTRDLENBQUMsQ0FBQztJQUMvRSxDQUFDO0lBQUMsT0FBTyxLQUFVLEVBQUUsQ0FBQztRQUNwQixXQUFXLENBQUMsS0FBSyxDQUFDLElBQUksVUFBVSx5QkFBeUIsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUNwRSxDQUFDO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQ0xJIEJyaWRnZSBBZGRvbiAtIE1haW4gUHJvY2VzcyBFbnRyeSBQb2ludFxuICpcbiAqIFRoaXMgYWRkb24gZXh0ZW5kcyBMb2NhbCdzIGNhcGFiaWxpdGllczpcbiAqIC0gR3JhcGhRTCBtdXRhdGlvbnMgZm9yIGRlbGV0ZVNpdGUsIHdwQ2xpIChmb3IgbG9jYWwtY2xpKVxuICogLSBNQ1AgU2VydmVyIGZvciBBSSB0b29sIGludGVncmF0aW9uIChDbGF1ZGUgQ29kZSwgQ2hhdEdQVCwgZXRjLilcbiAqL1xuXG5pbXBvcnQgKiBhcyBMb2NhbE1haW4gZnJvbSAnQGdldGZseXdoZWVsL2xvY2FsL21haW4nO1xuaW1wb3J0IHsgaXBjTWFpbiB9IGZyb20gJ2VsZWN0cm9uJztcbmltcG9ydCBncWwgZnJvbSAnZ3JhcGhxbC10YWcnO1xuaW1wb3J0IHsgTWNwU2VydmVyIH0gZnJvbSAnLi9tY3AvTWNwU2VydmVyJztcbmltcG9ydCB7IE1DUF9TRVJWRVIgfSBmcm9tICcuLi9jb21tb24vY29uc3RhbnRzJztcbmltcG9ydCB7IExvY2FsU2VydmljZXMgfSBmcm9tICcuLi9jb21tb24vdHlwZXMnO1xuXG5jb25zdCBBRERPTl9OQU1FID0gJ01DUCBTZXJ2ZXInO1xuXG5sZXQgbWNwU2VydmVyOiBNY3BTZXJ2ZXIgfCBudWxsID0gbnVsbDtcblxuLyoqXG4gKiBHcmFwaFFMIHR5cGUgZGVmaW5pdGlvbnMgZm9yIENMSSBCcmlkZ2VcbiAqL1xuY29uc3QgdHlwZURlZnMgPSBncWxgXG4gIGlucHV0IERlbGV0ZVNpdGVJbnB1dCB7XG4gICAgXCJUaGUgc2l0ZSBJRCB0byBkZWxldGVcIlxuICAgIGlkOiBJRCFcbiAgICBcIldoZXRoZXIgdG8gbW92ZSBzaXRlIGZpbGVzIHRvIHRyYXNoICh0cnVlKSBvciBqdXN0IHJlbW92ZSBmcm9tIExvY2FsIChmYWxzZSlcIlxuICAgIHRyYXNoRmlsZXM6IEJvb2xlYW4gPSB0cnVlXG4gICAgXCJXaGV0aGVyIHRvIHVwZGF0ZSB0aGUgaG9zdHMgZmlsZVwiXG4gICAgdXBkYXRlSG9zdHM6IEJvb2xlYW4gPSB0cnVlXG4gIH1cblxuICB0eXBlIERlbGV0ZVNpdGVSZXN1bHQge1xuICAgIFwiV2hldGhlciB0aGUgZGVsZXRpb24gd2FzIHN1Y2Nlc3NmdWxcIlxuICAgIHN1Y2Nlc3M6IEJvb2xlYW4hXG4gICAgXCJFcnJvciBtZXNzYWdlIGlmIGRlbGV0aW9uIGZhaWxlZFwiXG4gICAgZXJyb3I6IFN0cmluZ1xuICAgIFwiVGhlIElEIG9mIHRoZSBkZWxldGVkIHNpdGVcIlxuICAgIHNpdGVJZDogSURcbiAgfVxuXG4gIGlucHV0IFdwQ2xpSW5wdXQge1xuICAgIFwiVGhlIHNpdGUgSUQgdG8gcnVuIFdQLUNMSSBhZ2FpbnN0XCJcbiAgICBzaXRlSWQ6IElEIVxuICAgIFwiV1AtQ0xJIGNvbW1hbmQgYW5kIGFyZ3VtZW50cyAoZS5nLiwgWydwbHVnaW4nLCAnbGlzdCcsICctLWZvcm1hdD1qc29uJ10pXCJcbiAgICBhcmdzOiBbU3RyaW5nIV0hXG4gICAgXCJTa2lwIGxvYWRpbmcgcGx1Z2lucyAoZGVmYXVsdDogdHJ1ZSlcIlxuICAgIHNraXBQbHVnaW5zOiBCb29sZWFuID0gdHJ1ZVxuICAgIFwiU2tpcCBsb2FkaW5nIHRoZW1lcyAoZGVmYXVsdDogdHJ1ZSlcIlxuICAgIHNraXBUaGVtZXM6IEJvb2xlYW4gPSB0cnVlXG4gIH1cblxuICB0eXBlIFdwQ2xpUmVzdWx0IHtcbiAgICBcIldoZXRoZXIgdGhlIGNvbW1hbmQgZXhlY3V0ZWQgc3VjY2Vzc2Z1bGx5XCJcbiAgICBzdWNjZXNzOiBCb29sZWFuIVxuICAgIFwiQ29tbWFuZCBvdXRwdXQgKHN0ZG91dClcIlxuICAgIG91dHB1dDogU3RyaW5nXG4gICAgXCJFcnJvciBtZXNzYWdlIGlmIGNvbW1hbmQgZmFpbGVkXCJcbiAgICBlcnJvcjogU3RyaW5nXG4gIH1cblxuICBpbnB1dCBDcmVhdGVTaXRlSW5wdXQge1xuICAgIFwiU2l0ZSBuYW1lIChyZXF1aXJlZClcIlxuICAgIG5hbWU6IFN0cmluZyFcbiAgICBcIlBIUCB2ZXJzaW9uIChlLmcuLCAnOC4yLjEwJykuIFVzZXMgTG9jYWwgZGVmYXVsdCBpZiBub3Qgc3BlY2lmaWVkLlwiXG4gICAgcGhwVmVyc2lvbjogU3RyaW5nXG4gICAgXCJXZWIgc2VydmVyIHR5cGVcIlxuICAgIHdlYlNlcnZlcjogU3RyaW5nXG4gICAgXCJEYXRhYmFzZSB0eXBlXCJcbiAgICBkYXRhYmFzZTogU3RyaW5nXG4gICAgXCJXb3JkUHJlc3MgYWRtaW4gdXNlcm5hbWUgKGRlZmF1bHQ6IGFkbWluKVwiXG4gICAgd3BBZG1pblVzZXJuYW1lOiBTdHJpbmdcbiAgICBcIldvcmRQcmVzcyBhZG1pbiBwYXNzd29yZCAoZGVmYXVsdDogcGFzc3dvcmQpXCJcbiAgICB3cEFkbWluUGFzc3dvcmQ6IFN0cmluZ1xuICAgIFwiV29yZFByZXNzIGFkbWluIGVtYWlsIChkZWZhdWx0OiBhZG1pbkBsb2NhbC50ZXN0KVwiXG4gICAgd3BBZG1pbkVtYWlsOiBTdHJpbmdcbiAgICBcIkJsdWVwcmludCBuYW1lIHRvIGNyZWF0ZSBzaXRlIGZyb20uIFVzZSBsaXN0X2JsdWVwcmludHMgdG8gc2VlIGF2YWlsYWJsZSBibHVlcHJpbnRzLlwiXG4gICAgYmx1ZXByaW50OiBTdHJpbmdcbiAgfVxuXG4gIHR5cGUgQ3JlYXRlU2l0ZVJlc3VsdCB7XG4gICAgXCJXaGV0aGVyIHNpdGUgY3JlYXRpb24gd2FzIGluaXRpYXRlZCBzdWNjZXNzZnVsbHlcIlxuICAgIHN1Y2Nlc3M6IEJvb2xlYW4hXG4gICAgXCJFcnJvciBtZXNzYWdlIGlmIGNyZWF0aW9uIGZhaWxlZFwiXG4gICAgZXJyb3I6IFN0cmluZ1xuICAgIFwiVGhlIGNyZWF0ZWQgc2l0ZSBJRFwiXG4gICAgc2l0ZUlkOiBJRFxuICAgIFwiVGhlIHNpdGUgbmFtZVwiXG4gICAgc2l0ZU5hbWU6IFN0cmluZ1xuICAgIFwiVGhlIHNpdGUgZG9tYWluXCJcbiAgICBzaXRlRG9tYWluOiBTdHJpbmdcbiAgfVxuXG4gIGlucHV0IE9wZW5TaXRlSW5wdXQge1xuICAgIFwiVGhlIHNpdGUgSUQgdG8gb3BlblwiXG4gICAgc2l0ZUlkOiBJRCFcbiAgICBcIlBhdGggdG8gb3BlbiAoZGVmYXVsdDogLywgdXNlIC93cC1hZG1pbiBmb3IgYWRtaW4pXCJcbiAgICBwYXRoOiBTdHJpbmcgPSBcIi9cIlxuICB9XG5cbiAgdHlwZSBPcGVuU2l0ZVJlc3VsdCB7XG4gICAgXCJXaGV0aGVyIHRoZSBzaXRlIHdhcyBvcGVuZWQgc3VjY2Vzc2Z1bGx5XCJcbiAgICBzdWNjZXNzOiBCb29sZWFuIVxuICAgIFwiRXJyb3IgbWVzc2FnZSBpZiBmYWlsZWRcIlxuICAgIGVycm9yOiBTdHJpbmdcbiAgICBcIlRoZSBVUkwgdGhhdCB3YXMgb3BlbmVkXCJcbiAgICB1cmw6IFN0cmluZ1xuICB9XG5cbiAgaW5wdXQgQ2xvbmVTaXRlSW5wdXQge1xuICAgIFwiVGhlIHNpdGUgSUQgdG8gY2xvbmVcIlxuICAgIHNpdGVJZDogSUQhXG4gICAgXCJOYW1lIGZvciB0aGUgY2xvbmVkIHNpdGVcIlxuICAgIG5ld05hbWU6IFN0cmluZyFcbiAgfVxuXG4gIHR5cGUgQ2xvbmVTaXRlUmVzdWx0IHtcbiAgICBcIldoZXRoZXIgY2xvbmluZyB3YXMgc3VjY2Vzc2Z1bFwiXG4gICAgc3VjY2VzczogQm9vbGVhbiFcbiAgICBcIkVycm9yIG1lc3NhZ2UgaWYgZmFpbGVkXCJcbiAgICBlcnJvcjogU3RyaW5nXG4gICAgXCJUaGUgbmV3IHNpdGUgSURcIlxuICAgIG5ld1NpdGVJZDogSURcbiAgICBcIlRoZSBuZXcgc2l0ZSBuYW1lXCJcbiAgICBuZXdTaXRlTmFtZTogU3RyaW5nXG4gICAgXCJUaGUgbmV3IHNpdGUgZG9tYWluXCJcbiAgICBuZXdTaXRlRG9tYWluOiBTdHJpbmdcbiAgfVxuXG4gIGlucHV0IEV4cG9ydFNpdGVJbnB1dCB7XG4gICAgXCJUaGUgc2l0ZSBJRCB0byBleHBvcnRcIlxuICAgIHNpdGVJZDogSUQhXG4gICAgXCJPdXRwdXQgZGlyZWN0b3J5IHBhdGggKGRlZmF1bHQ6IH4vRG93bmxvYWRzKVwiXG4gICAgb3V0cHV0UGF0aDogU3RyaW5nXG4gIH1cblxuICB0eXBlIEV4cG9ydFNpdGVSZXN1bHQge1xuICAgIFwiV2hldGhlciBleHBvcnQgd2FzIHN1Y2Nlc3NmdWxcIlxuICAgIHN1Y2Nlc3M6IEJvb2xlYW4hXG4gICAgXCJFcnJvciBtZXNzYWdlIGlmIGZhaWxlZFwiXG4gICAgZXJyb3I6IFN0cmluZ1xuICAgIFwiUGF0aCB0byB0aGUgZXhwb3J0ZWQgemlwIGZpbGVcIlxuICAgIGV4cG9ydFBhdGg6IFN0cmluZ1xuICB9XG5cbiAgdHlwZSBCbHVlcHJpbnQge1xuICAgIFwiQmx1ZXByaW50IG5hbWVcIlxuICAgIG5hbWU6IFN0cmluZyFcbiAgICBcIkxhc3QgbW9kaWZpZWQgZGF0ZVwiXG4gICAgbGFzdE1vZGlmaWVkOiBTdHJpbmdcbiAgICBcIlBIUCB2ZXJzaW9uXCJcbiAgICBwaHBWZXJzaW9uOiBTdHJpbmdcbiAgICBcIldlYiBzZXJ2ZXIgdHlwZVwiXG4gICAgd2ViU2VydmVyOiBTdHJpbmdcbiAgICBcIkRhdGFiYXNlIHR5cGVcIlxuICAgIGRhdGFiYXNlOiBTdHJpbmdcbiAgfVxuXG4gIHR5cGUgQmx1ZXByaW50c1Jlc3VsdCB7XG4gICAgXCJXaGV0aGVyIHF1ZXJ5IHdhcyBzdWNjZXNzZnVsXCJcbiAgICBzdWNjZXNzOiBCb29sZWFuIVxuICAgIFwiRXJyb3IgbWVzc2FnZSBpZiBmYWlsZWRcIlxuICAgIGVycm9yOiBTdHJpbmdcbiAgICBcIkxpc3Qgb2YgYmx1ZXByaW50c1wiXG4gICAgYmx1ZXByaW50czogW0JsdWVwcmludCFdXG4gIH1cblxuICBpbnB1dCBTYXZlQmx1ZXByaW50SW5wdXQge1xuICAgIFwiVGhlIHNpdGUgSUQgdG8gc2F2ZSBhcyBibHVlcHJpbnRcIlxuICAgIHNpdGVJZDogSUQhXG4gICAgXCJOYW1lIGZvciB0aGUgYmx1ZXByaW50XCJcbiAgICBuYW1lOiBTdHJpbmchXG4gIH1cblxuICB0eXBlIFNhdmVCbHVlcHJpbnRSZXN1bHQge1xuICAgIFwiV2hldGhlciBzYXZlIHdhcyBzdWNjZXNzZnVsXCJcbiAgICBzdWNjZXNzOiBCb29sZWFuIVxuICAgIFwiRXJyb3IgbWVzc2FnZSBpZiBmYWlsZWRcIlxuICAgIGVycm9yOiBTdHJpbmdcbiAgICBcIlRoZSBibHVlcHJpbnQgbmFtZVwiXG4gICAgYmx1ZXByaW50TmFtZTogU3RyaW5nXG4gIH1cblxuICAjIFBoYXNlIDg6IFdvcmRQcmVzcyBEZXZlbG9wbWVudCBUb29sc1xuICBpbnB1dCBFeHBvcnREYXRhYmFzZUlucHV0IHtcbiAgICBcIlRoZSBzaXRlIElEXCJcbiAgICBzaXRlSWQ6IElEIVxuICAgIFwiT3V0cHV0IGZpbGUgcGF0aCAob3B0aW9uYWwsIGRlZmF1bHRzIHRvIH4vRG93bmxvYWRzLzxzaXRlLW5hbWU+LnNxbClcIlxuICAgIG91dHB1dFBhdGg6IFN0cmluZ1xuICB9XG5cbiAgdHlwZSBFeHBvcnREYXRhYmFzZVJlc3VsdCB7XG4gICAgXCJXaGV0aGVyIGV4cG9ydCB3YXMgc3VjY2Vzc2Z1bFwiXG4gICAgc3VjY2VzczogQm9vbGVhbiFcbiAgICBcIkVycm9yIG1lc3NhZ2UgaWYgZmFpbGVkXCJcbiAgICBlcnJvcjogU3RyaW5nXG4gICAgXCJQYXRoIHRvIHRoZSBleHBvcnRlZCBTUUwgZmlsZVwiXG4gICAgb3V0cHV0UGF0aDogU3RyaW5nXG4gIH1cblxuICBpbnB1dCBJbXBvcnREYXRhYmFzZUlucHV0IHtcbiAgICBcIlRoZSBzaXRlIElEXCJcbiAgICBzaXRlSWQ6IElEIVxuICAgIFwiUGF0aCB0byB0aGUgU1FMIGZpbGUgdG8gaW1wb3J0XCJcbiAgICBzcWxQYXRoOiBTdHJpbmchXG4gIH1cblxuICB0eXBlIEltcG9ydERhdGFiYXNlUmVzdWx0IHtcbiAgICBcIldoZXRoZXIgaW1wb3J0IHdhcyBzdWNjZXNzZnVsXCJcbiAgICBzdWNjZXNzOiBCb29sZWFuIVxuICAgIFwiRXJyb3IgbWVzc2FnZSBpZiBmYWlsZWRcIlxuICAgIGVycm9yOiBTdHJpbmdcbiAgfVxuXG4gIGlucHV0IE9wZW5BZG1pbmVySW5wdXQge1xuICAgIFwiVGhlIHNpdGUgSURcIlxuICAgIHNpdGVJZDogSUQhXG4gIH1cblxuICB0eXBlIE9wZW5BZG1pbmVyUmVzdWx0IHtcbiAgICBcIldoZXRoZXIgb3BlbmluZyB3YXMgc3VjY2Vzc2Z1bFwiXG4gICAgc3VjY2VzczogQm9vbGVhbiFcbiAgICBcIkVycm9yIG1lc3NhZ2UgaWYgZmFpbGVkXCJcbiAgICBlcnJvcjogU3RyaW5nXG4gIH1cblxuICBpbnB1dCBUcnVzdFNzbElucHV0IHtcbiAgICBcIlRoZSBzaXRlIElEXCJcbiAgICBzaXRlSWQ6IElEIVxuICB9XG5cbiAgdHlwZSBUcnVzdFNzbFJlc3VsdCB7XG4gICAgXCJXaGV0aGVyIHRydXN0IHdhcyBzdWNjZXNzZnVsXCJcbiAgICBzdWNjZXNzOiBCb29sZWFuIVxuICAgIFwiRXJyb3IgbWVzc2FnZSBpZiBmYWlsZWRcIlxuICAgIGVycm9yOiBTdHJpbmdcbiAgfVxuXG4gIGlucHV0IE1jcFJlbmFtZVNpdGVJbnB1dCB7XG4gICAgXCJUaGUgc2l0ZSBJRFwiXG4gICAgc2l0ZUlkOiBJRCFcbiAgICBcIk5ldyBuYW1lIGZvciB0aGUgc2l0ZVwiXG4gICAgbmV3TmFtZTogU3RyaW5nIVxuICB9XG5cbiAgdHlwZSBNY3BSZW5hbWVTaXRlUmVzdWx0IHtcbiAgICBcIldoZXRoZXIgcmVuYW1lIHdhcyBzdWNjZXNzZnVsXCJcbiAgICBzdWNjZXNzOiBCb29sZWFuIVxuICAgIFwiRXJyb3IgbWVzc2FnZSBpZiBmYWlsZWRcIlxuICAgIGVycm9yOiBTdHJpbmdcbiAgICBcIlRoZSBuZXcgbmFtZVwiXG4gICAgbmV3TmFtZTogU3RyaW5nXG4gIH1cblxuICBpbnB1dCBDaGFuZ2VQaHBWZXJzaW9uSW5wdXQge1xuICAgIFwiVGhlIHNpdGUgSURcIlxuICAgIHNpdGVJZDogSUQhXG4gICAgXCJUYXJnZXQgUEhQIHZlcnNpb25cIlxuICAgIHBocFZlcnNpb246IFN0cmluZyFcbiAgfVxuXG4gIHR5cGUgQ2hhbmdlUGhwVmVyc2lvblJlc3VsdCB7XG4gICAgXCJXaGV0aGVyIGNoYW5nZSB3YXMgc3VjY2Vzc2Z1bFwiXG4gICAgc3VjY2VzczogQm9vbGVhbiFcbiAgICBcIkVycm9yIG1lc3NhZ2UgaWYgZmFpbGVkXCJcbiAgICBlcnJvcjogU3RyaW5nXG4gICAgXCJUaGUgbmV3IFBIUCB2ZXJzaW9uXCJcbiAgICBwaHBWZXJzaW9uOiBTdHJpbmdcbiAgfVxuXG4gIGlucHV0IEltcG9ydFNpdGVJbnB1dCB7XG4gICAgXCJQYXRoIHRvIHRoZSB6aXAgZmlsZSB0byBpbXBvcnRcIlxuICAgIHppcFBhdGg6IFN0cmluZyFcbiAgICBcIk5hbWUgZm9yIHRoZSBpbXBvcnRlZCBzaXRlIChvcHRpb25hbClcIlxuICAgIHNpdGVOYW1lOiBTdHJpbmdcbiAgfVxuXG4gIHR5cGUgSW1wb3J0U2l0ZVJlc3VsdCB7XG4gICAgXCJXaGV0aGVyIGltcG9ydCB3YXMgc3VjY2Vzc2Z1bFwiXG4gICAgc3VjY2VzczogQm9vbGVhbiFcbiAgICBcIkVycm9yIG1lc3NhZ2UgaWYgZmFpbGVkXCJcbiAgICBlcnJvcjogU3RyaW5nXG4gICAgXCJUaGUgaW1wb3J0ZWQgc2l0ZSBJRFwiXG4gICAgc2l0ZUlkOiBJRFxuICAgIFwiVGhlIGltcG9ydGVkIHNpdGUgbmFtZVwiXG4gICAgc2l0ZU5hbWU6IFN0cmluZ1xuICB9XG5cbiAgIyBQaGFzZSA5OiBTaXRlIENvbmZpZ3VyYXRpb24gJiBEZXYgVG9vbHNcbiAgaW5wdXQgVG9nZ2xlWGRlYnVnSW5wdXQge1xuICAgIFwiVGhlIHNpdGUgSURcIlxuICAgIHNpdGVJZDogSUQhXG4gICAgXCJXaGV0aGVyIHRvIGVuYWJsZSBvciBkaXNhYmxlIFhkZWJ1Z1wiXG4gICAgZW5hYmxlZDogQm9vbGVhbiFcbiAgfVxuXG4gIHR5cGUgVG9nZ2xlWGRlYnVnUmVzdWx0IHtcbiAgICBcIldoZXRoZXIgdG9nZ2xlIHdhcyBzdWNjZXNzZnVsXCJcbiAgICBzdWNjZXNzOiBCb29sZWFuIVxuICAgIFwiRXJyb3IgbWVzc2FnZSBpZiBmYWlsZWRcIlxuICAgIGVycm9yOiBTdHJpbmdcbiAgICBcIkN1cnJlbnQgWGRlYnVnIHN0YXRlXCJcbiAgICBlbmFibGVkOiBCb29sZWFuXG4gIH1cblxuICBpbnB1dCBHZXRTaXRlTG9nc0lucHV0IHtcbiAgICBcIlRoZSBzaXRlIElEXCJcbiAgICBzaXRlSWQ6IElEIVxuICAgIFwiVHlwZSBvZiBsb2dzIHRvIHJldHJpZXZlIChwaHAsIG5naW54LCBteXNxbCwgYWxsKVwiXG4gICAgbG9nVHlwZTogU3RyaW5nID0gXCJwaHBcIlxuICAgIFwiTnVtYmVyIG9mIGxpbmVzIHRvIHJldHVyblwiXG4gICAgbGluZXM6IEludCA9IDEwMFxuICB9XG5cbiAgdHlwZSBMb2dFbnRyeSB7XG4gICAgXCJMb2cgdHlwZVwiXG4gICAgdHlwZTogU3RyaW5nIVxuICAgIFwiTG9nIGNvbnRlbnRcIlxuICAgIGNvbnRlbnQ6IFN0cmluZyFcbiAgICBcIkxvZyBmaWxlIHBhdGhcIlxuICAgIHBhdGg6IFN0cmluZyFcbiAgfVxuXG4gIHR5cGUgR2V0U2l0ZUxvZ3NSZXN1bHQge1xuICAgIFwiV2hldGhlciByZXRyaWV2YWwgd2FzIHN1Y2Nlc3NmdWxcIlxuICAgIHN1Y2Nlc3M6IEJvb2xlYW4hXG4gICAgXCJFcnJvciBtZXNzYWdlIGlmIGZhaWxlZFwiXG4gICAgZXJyb3I6IFN0cmluZ1xuICAgIFwiTG9nIGVudHJpZXNcIlxuICAgIGxvZ3M6IFtMb2dFbnRyeSFdXG4gIH1cblxuICB0eXBlIFNlcnZpY2VJbmZvIHtcbiAgICBcIlNlcnZpY2Ugcm9sZSAocGhwLCBkYXRhYmFzZSwgd2Vic2VydmVyKVwiXG4gICAgcm9sZTogU3RyaW5nIVxuICAgIFwiU2VydmljZSBuYW1lXCJcbiAgICBuYW1lOiBTdHJpbmchXG4gICAgXCJTZXJ2aWNlIHZlcnNpb25cIlxuICAgIHZlcnNpb246IFN0cmluZyFcbiAgfVxuXG4gIHR5cGUgTGlzdFNlcnZpY2VzUmVzdWx0IHtcbiAgICBcIldoZXRoZXIgbGlzdGluZyB3YXMgc3VjY2Vzc2Z1bFwiXG4gICAgc3VjY2VzczogQm9vbGVhbiFcbiAgICBcIkVycm9yIG1lc3NhZ2UgaWYgZmFpbGVkXCJcbiAgICBlcnJvcjogU3RyaW5nXG4gICAgXCJBdmFpbGFibGUgc2VydmljZXNcIlxuICAgIHNlcnZpY2VzOiBbU2VydmljZUluZm8hXVxuICB9XG5cbiAgZXh0ZW5kIHR5cGUgTXV0YXRpb24ge1xuICAgIFwiQ3JlYXRlIGEgbmV3IFdvcmRQcmVzcyBzaXRlIHdpdGggZnVsbCBXb3JkUHJlc3MgaW5zdGFsbGF0aW9uXCJcbiAgICBjcmVhdGVTaXRlKGlucHV0OiBDcmVhdGVTaXRlSW5wdXQhKTogQ3JlYXRlU2l0ZVJlc3VsdCFcblxuICAgIFwiRGVsZXRlIGEgc2l0ZSBmcm9tIExvY2FsXCJcbiAgICBkZWxldGVTaXRlKGlucHV0OiBEZWxldGVTaXRlSW5wdXQhKTogRGVsZXRlU2l0ZVJlc3VsdCFcblxuICAgIFwiRGVsZXRlIG11bHRpcGxlIHNpdGVzIGZyb20gTG9jYWxcIlxuICAgIGRlbGV0ZVNpdGVzKGlkczogW0lEIV0hLCB0cmFzaEZpbGVzOiBCb29sZWFuID0gdHJ1ZSk6IERlbGV0ZVNpdGVSZXN1bHQhXG5cbiAgICBcIlJ1biBhIFdQLUNMSSBjb21tYW5kIGFnYWluc3QgYSBzaXRlXCJcbiAgICB3cENsaShpbnB1dDogV3BDbGlJbnB1dCEpOiBXcENsaVJlc3VsdCFcblxuICAgIFwiT3BlbiBhIHNpdGUgaW4gdGhlIGRlZmF1bHQgYnJvd3NlclwiXG4gICAgb3BlblNpdGUoaW5wdXQ6IE9wZW5TaXRlSW5wdXQhKTogT3BlblNpdGVSZXN1bHQhXG5cbiAgICBcIkNsb25lIGFuIGV4aXN0aW5nIHNpdGVcIlxuICAgIGNsb25lU2l0ZShpbnB1dDogQ2xvbmVTaXRlSW5wdXQhKTogQ2xvbmVTaXRlUmVzdWx0IVxuXG4gICAgXCJFeHBvcnQgYSBzaXRlIHRvIGEgemlwIGZpbGVcIlxuICAgIGV4cG9ydFNpdGUoaW5wdXQ6IEV4cG9ydFNpdGVJbnB1dCEpOiBFeHBvcnRTaXRlUmVzdWx0IVxuXG4gICAgXCJTYXZlIGEgc2l0ZSBhcyBhIGJsdWVwcmludFwiXG4gICAgc2F2ZUJsdWVwcmludChpbnB1dDogU2F2ZUJsdWVwcmludElucHV0ISk6IFNhdmVCbHVlcHJpbnRSZXN1bHQhXG5cbiAgICAjIFBoYXNlIDg6IFdvcmRQcmVzcyBEZXZlbG9wbWVudCBUb29sc1xuICAgIFwiRXhwb3J0IHNpdGUgZGF0YWJhc2UgdG8gU1FMIGZpbGVcIlxuICAgIGV4cG9ydERhdGFiYXNlKGlucHV0OiBFeHBvcnREYXRhYmFzZUlucHV0ISk6IEV4cG9ydERhdGFiYXNlUmVzdWx0IVxuXG4gICAgXCJJbXBvcnQgU1FMIGZpbGUgaW50byBzaXRlIGRhdGFiYXNlXCJcbiAgICBpbXBvcnREYXRhYmFzZShpbnB1dDogSW1wb3J0RGF0YWJhc2VJbnB1dCEpOiBJbXBvcnREYXRhYmFzZVJlc3VsdCFcblxuICAgIFwiT3BlbiBBZG1pbmVyIGRhdGFiYXNlIG1hbmFnZW1lbnQgVUlcIlxuICAgIG9wZW5BZG1pbmVyKGlucHV0OiBPcGVuQWRtaW5lcklucHV0ISk6IE9wZW5BZG1pbmVyUmVzdWx0IVxuXG4gICAgXCJUcnVzdCBzaXRlIFNTTCBjZXJ0aWZpY2F0ZVwiXG4gICAgdHJ1c3RTc2woaW5wdXQ6IFRydXN0U3NsSW5wdXQhKTogVHJ1c3RTc2xSZXN1bHQhXG5cbiAgICBcIlJlbmFtZSBhIHNpdGUgKE1DUCB2ZXJzaW9uKVwiXG4gICAgbWNwUmVuYW1lU2l0ZShpbnB1dDogTWNwUmVuYW1lU2l0ZUlucHV0ISk6IE1jcFJlbmFtZVNpdGVSZXN1bHQhXG5cbiAgICBcIkNoYW5nZSBzaXRlIFBIUCB2ZXJzaW9uXCJcbiAgICBjaGFuZ2VQaHBWZXJzaW9uKGlucHV0OiBDaGFuZ2VQaHBWZXJzaW9uSW5wdXQhKTogQ2hhbmdlUGhwVmVyc2lvblJlc3VsdCFcblxuICAgIFwiSW1wb3J0IHNpdGUgZnJvbSB6aXAgZmlsZVwiXG4gICAgaW1wb3J0U2l0ZShpbnB1dDogSW1wb3J0U2l0ZUlucHV0ISk6IEltcG9ydFNpdGVSZXN1bHQhXG5cbiAgICAjIFBoYXNlIDk6IFNpdGUgQ29uZmlndXJhdGlvbiAmIERldiBUb29sc1xuICAgIFwiVG9nZ2xlIFhkZWJ1ZyBmb3IgYSBzaXRlXCJcbiAgICB0b2dnbGVYZGVidWcoaW5wdXQ6IFRvZ2dsZVhkZWJ1Z0lucHV0ISk6IFRvZ2dsZVhkZWJ1Z1Jlc3VsdCFcblxuICAgIFwiR2V0IHNpdGUgbG9nIGZpbGVzXCJcbiAgICBnZXRTaXRlTG9ncyhpbnB1dDogR2V0U2l0ZUxvZ3NJbnB1dCEpOiBHZXRTaXRlTG9nc1Jlc3VsdCFcbiAgfVxuXG4gIGV4dGVuZCB0eXBlIFF1ZXJ5IHtcbiAgICBcIlJ1biBhIFdQLUNMSSBjb21tYW5kIGFnYWluc3QgYSBzaXRlIChyZWFkLW9ubHkgb3BlcmF0aW9ucylcIlxuICAgIHdwQ2xpUXVlcnkoaW5wdXQ6IFdwQ2xpSW5wdXQhKTogV3BDbGlSZXN1bHQhXG5cbiAgICBcIkxpc3QgYWxsIGF2YWlsYWJsZSBibHVlcHJpbnRzXCJcbiAgICBibHVlcHJpbnRzOiBCbHVlcHJpbnRzUmVzdWx0IVxuXG4gICAgXCJMaXN0IGF2YWlsYWJsZSBzZXJ2aWNlIHZlcnNpb25zXCJcbiAgICBsaXN0U2VydmljZXModHlwZTogU3RyaW5nKTogTGlzdFNlcnZpY2VzUmVzdWx0IVxuXG4gICAgIyBQaGFzZSAxMTogV1AgRW5naW5lIENvbm5lY3RcbiAgICBcIkNoZWNrIFdQIEVuZ2luZSBhdXRoZW50aWNhdGlvbiBzdGF0dXNcIlxuICAgIHdwZVN0YXR1czogV3BlQXV0aFN0YXR1cyFcblxuICAgIFwiTGlzdCBhbGwgc2l0ZXMgZnJvbSBXUCBFbmdpbmUgYWNjb3VudFwiXG4gICAgbGlzdFdwZVNpdGVzKGFjY291bnRJZDogU3RyaW5nKTogTGlzdFdwZVNpdGVzUmVzdWx0IVxuXG4gICAgIyBQaGFzZSAxMWI6IFNpdGUgTGlua2luZ1xuICAgIFwiR2V0IFdQIEVuZ2luZSBjb25uZWN0aW9uIGRldGFpbHMgZm9yIGEgbG9jYWwgc2l0ZVwiXG4gICAgZ2V0V3BlTGluayhzaXRlSWQ6IElEISk6IEdldFdwZUxpbmtSZXN1bHQhXG4gIH1cblxuICAjIFBoYXNlIDExOiBXUCBFbmdpbmUgQ29ubmVjdCBUeXBlc1xuICB0eXBlIFdwZUF1dGhTdGF0dXMge1xuICAgIFwiV2hldGhlciBhdXRoZW50aWNhdGVkIHdpdGggV1AgRW5naW5lXCJcbiAgICBhdXRoZW50aWNhdGVkOiBCb29sZWFuIVxuICAgIFwiVXNlciBlbWFpbCBpZiBhdXRoZW50aWNhdGVkXCJcbiAgICBlbWFpbDogU3RyaW5nXG4gICAgXCJBY2NvdW50IElEIGlmIGF1dGhlbnRpY2F0ZWRcIlxuICAgIGFjY291bnRJZDogU3RyaW5nXG4gICAgXCJBY2NvdW50IG5hbWUgaWYgYXV0aGVudGljYXRlZFwiXG4gICAgYWNjb3VudE5hbWU6IFN0cmluZ1xuICAgIFwiVG9rZW4gZXhwaXJ5IHRpbWVcIlxuICAgIHRva2VuRXhwaXJ5OiBTdHJpbmdcbiAgICBcIkVycm9yIG1lc3NhZ2UgaWYgc3RhdHVzIGNoZWNrIGZhaWxlZFwiXG4gICAgZXJyb3I6IFN0cmluZ1xuICB9XG5cbiAgdHlwZSBXcGVBdXRoUmVzdWx0IHtcbiAgICBcIldoZXRoZXIgYXV0aGVudGljYXRpb24gd2FzIHN1Y2Nlc3NmdWxcIlxuICAgIHN1Y2Nlc3M6IEJvb2xlYW4hXG4gICAgXCJVc2VyIGVtYWlsIGlmIHN1Y2Nlc3NmdWxcIlxuICAgIGVtYWlsOiBTdHJpbmdcbiAgICBcIk1lc3NhZ2UgYWJvdXQgdGhlIGF1dGhlbnRpY2F0aW9uIHJlc3VsdFwiXG4gICAgbWVzc2FnZTogU3RyaW5nXG4gICAgXCJFcnJvciBtZXNzYWdlIGlmIGZhaWxlZFwiXG4gICAgZXJyb3I6IFN0cmluZ1xuICB9XG5cbiAgdHlwZSBXcGVMb2dvdXRSZXN1bHQge1xuICAgIFwiV2hldGhlciBsb2dvdXQgd2FzIHN1Y2Nlc3NmdWxcIlxuICAgIHN1Y2Nlc3M6IEJvb2xlYW4hXG4gICAgXCJNZXNzYWdlIGFib3V0IHRoZSBsb2dvdXQgcmVzdWx0XCJcbiAgICBtZXNzYWdlOiBTdHJpbmdcbiAgICBcIkVycm9yIG1lc3NhZ2UgaWYgZmFpbGVkXCJcbiAgICBlcnJvcjogU3RyaW5nXG4gIH1cblxuICB0eXBlIFdwZVNpdGUge1xuICAgIFwiSW5zdGFsbCBJRFwiXG4gICAgaWQ6IFN0cmluZyFcbiAgICBcIkluc3RhbGwgbmFtZVwiXG4gICAgbmFtZTogU3RyaW5nIVxuICAgIFwiRW52aXJvbm1lbnQgKHByb2R1Y3Rpb24sIHN0YWdpbmcsIGRldmVsb3BtZW50KVwiXG4gICAgZW52aXJvbm1lbnQ6IFN0cmluZyFcbiAgICBcIlBIUCB2ZXJzaW9uXCJcbiAgICBwaHBWZXJzaW9uOiBTdHJpbmdcbiAgICBcIlByaW1hcnkgZG9tYWluXCJcbiAgICBwcmltYXJ5RG9tYWluOiBTdHJpbmdcbiAgICBcIkFjY291bnQgSURcIlxuICAgIGFjY291bnRJZDogU3RyaW5nXG4gICAgXCJBY2NvdW50IG5hbWVcIlxuICAgIGFjY291bnROYW1lOiBTdHJpbmdcbiAgICBcIlNGVFAgaG9zdFwiXG4gICAgc2Z0cEhvc3Q6IFN0cmluZ1xuICAgIFwiU0ZUUCB1c2VyXCJcbiAgICBzZnRwVXNlcjogU3RyaW5nXG4gIH1cblxuICB0eXBlIExpc3RXcGVTaXRlc1Jlc3VsdCB7XG4gICAgXCJXaGV0aGVyIHF1ZXJ5IHdhcyBzdWNjZXNzZnVsXCJcbiAgICBzdWNjZXNzOiBCb29sZWFuIVxuICAgIFwiRXJyb3IgbWVzc2FnZSBpZiBmYWlsZWRcIlxuICAgIGVycm9yOiBTdHJpbmdcbiAgICBcIkxpc3Qgb2YgV1AgRW5naW5lIHNpdGVzXCJcbiAgICBzaXRlczogW1dwZVNpdGUhXVxuICAgIFwiVG90YWwgY291bnQgb2Ygc2l0ZXNcIlxuICAgIGNvdW50OiBJbnRcbiAgfVxuXG4gICMgUGhhc2UgMTFiOiBTaXRlIExpbmtpbmcgVHlwZXNcbiAgdHlwZSBXcGVDb25uZWN0aW9uIHtcbiAgICBcIlJlbW90ZSBpbnN0YWxsIElEIChVVUlEIGZyb20gV1AgRW5naW5lKVwiXG4gICAgcmVtb3RlSW5zdGFsbElkOiBTdHJpbmchXG4gICAgXCJJbnN0YWxsIG5hbWUgKGh1bWFuLXJlYWRhYmxlLCB1c2VkIGluIHBvcnRhbCBVUkxzKVwiXG4gICAgaW5zdGFsbE5hbWU6IFN0cmluZ1xuICAgIFwiRW52aXJvbm1lbnQgKHByb2R1Y3Rpb24sIHN0YWdpbmcsIGRldmVsb3BtZW50KVwiXG4gICAgZW52aXJvbm1lbnQ6IFN0cmluZ1xuICAgIFwiQWNjb3VudCBJRFwiXG4gICAgYWNjb3VudElkOiBTdHJpbmdcbiAgICBcIldQIEVuZ2luZSBwb3J0YWwgVVJMXCJcbiAgICBwb3J0YWxVcmw6IFN0cmluZ1xuICAgIFwiUHJpbWFyeSBkb21haW4vQ05BTUVcIlxuICAgIHByaW1hcnlEb21haW46IFN0cmluZ1xuICB9XG5cbiAgXCJTeW5jIGNhcGFiaWxpdGllcyBhdmFpbGFibGUgZm9yIFdQRS1jb25uZWN0ZWQgc2l0ZXNcIlxuICB0eXBlIFdwZVN5bmNDYXBhYmlsaXRpZXMge1xuICAgIFwiV2hldGhlciB1c2VyIGNhbiBwdXNoIHRvIFdQIEVuZ2luZVwiXG4gICAgY2FuUHVzaDogQm9vbGVhbiFcbiAgICBcIldoZXRoZXIgdXNlciBjYW4gcHVsbCBmcm9tIFdQIEVuZ2luZVwiXG4gICAgY2FuUHVsbDogQm9vbGVhbiFcbiAgICBcIkF2YWlsYWJsZSBzeW5jIG1vZGVzXCJcbiAgICBzeW5jTW9kZXM6IFtTdHJpbmchXSFcbiAgICBcIldoZXRoZXIgTWFnaWMgU3luYyAoc2VsZWN0IGZpbGVzKSBpcyBhdmFpbGFibGVcIlxuICAgIG1hZ2ljU3luY0F2YWlsYWJsZTogQm9vbGVhbiFcbiAgICBcIldoZXRoZXIgZGF0YWJhc2Ugc3luYyBpcyBhdmFpbGFibGVcIlxuICAgIGRhdGFiYXNlU3luY0F2YWlsYWJsZTogQm9vbGVhbiFcbiAgfVxuXG4gIHR5cGUgR2V0V3BlTGlua1Jlc3VsdCB7XG4gICAgXCJXaGV0aGVyIHNpdGUgaXMgbGlua2VkIHRvIFdQIEVuZ2luZVwiXG4gICAgbGlua2VkOiBCb29sZWFuIVxuICAgIFwiU2l0ZSBuYW1lXCJcbiAgICBzaXRlTmFtZTogU3RyaW5nXG4gICAgXCJXUCBFbmdpbmUgY29ubmVjdGlvbnNcIlxuICAgIGNvbm5lY3Rpb25zOiBbV3BlQ29ubmVjdGlvbiFdXG4gICAgXCJOdW1iZXIgb2YgY29ubmVjdGlvbnNcIlxuICAgIGNvbm5lY3Rpb25Db3VudDogSW50XG4gICAgXCJTeW5jIGNhcGFiaWxpdGllcyAob25seSBwcmVzZW50IGlmIGxpbmtlZClcIlxuICAgIGNhcGFiaWxpdGllczogV3BlU3luY0NhcGFiaWxpdGllc1xuICAgIFwiTWVzc2FnZSAoZm9yIHVubGlua2VkIHNpdGVzKVwiXG4gICAgbWVzc2FnZTogU3RyaW5nXG4gICAgXCJFcnJvciBtZXNzYWdlIGlmIGZhaWxlZFwiXG4gICAgZXJyb3I6IFN0cmluZ1xuICB9XG5cbiAgIyBQaGFzZSAxMWM6IFN5bmMgT3BlcmF0aW9ucyBUeXBlc1xuICB0eXBlIFN5bmNIaXN0b3J5RXZlbnQge1xuICAgIFwiUmVtb3RlIGluc3RhbGwgbmFtZVwiXG4gICAgcmVtb3RlSW5zdGFsbE5hbWU6IFN0cmluZ1xuICAgIFwiVW5peCB0aW1lc3RhbXBcIlxuICAgIHRpbWVzdGFtcDogRmxvYXQhXG4gICAgXCJFbnZpcm9ubWVudCAocHJvZHVjdGlvbiwgc3RhZ2luZywgZGV2ZWxvcG1lbnQpXCJcbiAgICBlbnZpcm9ubWVudDogU3RyaW5nIVxuICAgIFwiU3luYyBkaXJlY3Rpb25cIlxuICAgIGRpcmVjdGlvbjogU3RyaW5nIVxuICAgIFwiU3luYyBzdGF0dXNcIlxuICAgIHN0YXR1czogU3RyaW5nXG4gIH1cblxuICB0eXBlIEdldFN5bmNIaXN0b3J5UmVzdWx0IHtcbiAgICBcIldoZXRoZXIgdGhlIHF1ZXJ5IHdhcyBzdWNjZXNzZnVsXCJcbiAgICBzdWNjZXNzOiBCb29sZWFuIVxuICAgIFwiU2l0ZSBuYW1lXCJcbiAgICBzaXRlTmFtZTogU3RyaW5nXG4gICAgXCJTeW5jIGhpc3RvcnkgZXZlbnRzXCJcbiAgICBldmVudHM6IFtTeW5jSGlzdG9yeUV2ZW50IV1cbiAgICBcIk51bWJlciBvZiBldmVudHNcIlxuICAgIGNvdW50OiBJbnRcbiAgICBcIkVycm9yIG1lc3NhZ2UgaWYgZmFpbGVkXCJcbiAgICBlcnJvcjogU3RyaW5nXG4gIH1cblxuICB0eXBlIFN5bmNSZXN1bHQge1xuICAgIFwiV2hldGhlciB0aGUgc3luYyB3YXMgaW5pdGlhdGVkIHN1Y2Nlc3NmdWxseVwiXG4gICAgc3VjY2VzczogQm9vbGVhbiFcbiAgICBcIlN0YXR1cyBtZXNzYWdlXCJcbiAgICBtZXNzYWdlOiBTdHJpbmdcbiAgICBcIkVycm9yIG1lc3NhZ2UgaWYgZmFpbGVkXCJcbiAgICBlcnJvcjogU3RyaW5nXG4gIH1cblxuICAjIEZpbGUgY2hhbmdlIGRldGVjdGlvblxuICB0eXBlIEZpbGVDaGFuZ2Uge1xuICAgIFwiRmlsZSBwYXRoIHJlbGF0aXZlIHRvIHNpdGUgcm9vdFwiXG4gICAgcGF0aDogU3RyaW5nIVxuICAgIFwiQ2hhbmdlIHR5cGU6IGNyZWF0ZSwgdXBsb2FkLCBkb3dubG9hZCwgZGVsZXRlLCBtb2RpZnlcIlxuICAgIGluc3RydWN0aW9uOiBTdHJpbmchXG4gICAgXCJGaWxlIHNpemUgaW4gYnl0ZXNcIlxuICAgIHNpemU6IEludFxuICAgIFwiRmlsZSB0eXBlOiAtIChmaWxlKSBvciBkIChkaXJlY3RvcnkpXCJcbiAgICB0eXBlOiBTdHJpbmdcbiAgfVxuXG4gIHR5cGUgR2V0U2l0ZUNoYW5nZXNSZXN1bHQge1xuICAgIFwiV2hldGhlciB0aGUgcXVlcnkgd2FzIHN1Y2Nlc3NmdWxcIlxuICAgIHN1Y2Nlc3M6IEJvb2xlYW4hXG4gICAgXCJTaXRlIG5hbWVcIlxuICAgIHNpdGVOYW1lOiBTdHJpbmdcbiAgICBcIkRpcmVjdGlvbiBvZiBjb21wYXJpc29uXCJcbiAgICBkaXJlY3Rpb246IFN0cmluZ1xuICAgIFwiRmlsZXMgdGhhdCB3b3VsZCBiZSBhZGRlZC91cGxvYWRlZFwiXG4gICAgYWRkZWQ6IFtGaWxlQ2hhbmdlIV1cbiAgICBcIkZpbGVzIHRoYXQgd291bGQgYmUgbW9kaWZpZWRcIlxuICAgIG1vZGlmaWVkOiBbRmlsZUNoYW5nZSFdXG4gICAgXCJGaWxlcyB0aGF0IHdvdWxkIGJlIGRlbGV0ZWRcIlxuICAgIGRlbGV0ZWQ6IFtGaWxlQ2hhbmdlIV1cbiAgICBcIlRvdGFsIG51bWJlciBvZiBjaGFuZ2VzXCJcbiAgICB0b3RhbENoYW5nZXM6IEludFxuICAgIFwiU3VtbWFyeSBtZXNzYWdlXCJcbiAgICBtZXNzYWdlOiBTdHJpbmdcbiAgICBcIkVycm9yIG1lc3NhZ2UgaWYgZmFpbGVkXCJcbiAgICBlcnJvcjogU3RyaW5nXG4gIH1cblxuICAjIFBoYXNlIDEwOiBDbG91ZCBCYWNrdXAgVHlwZXNcbiAgdHlwZSBCYWNrdXBQcm92aWRlclN0YXR1cyB7XG4gICAgXCJXaGV0aGVyIGF1dGhlbnRpY2F0ZWQgd2l0aCBwcm92aWRlclwiXG4gICAgYXV0aGVudGljYXRlZDogQm9vbGVhbiFcbiAgICBcIkFjY291bnQgSURcIlxuICAgIGFjY291bnRJZDogU3RyaW5nXG4gICAgXCJBY2NvdW50IGVtYWlsXCJcbiAgICBlbWFpbDogU3RyaW5nXG4gIH1cblxuICB0eXBlIEJhY2t1cFN0YXR1c1Jlc3VsdCB7XG4gICAgXCJXaGV0aGVyIGJhY2t1cHMgYXJlIGF2YWlsYWJsZVwiXG4gICAgYXZhaWxhYmxlOiBCb29sZWFuIVxuICAgIFwiV2hldGhlciB0aGUgZmVhdHVyZSBpcyBlbmFibGVkXCJcbiAgICBmZWF0dXJlRW5hYmxlZDogQm9vbGVhbiFcbiAgICBcIkRyb3Bib3ggYXV0aGVudGljYXRpb24gc3RhdHVzXCJcbiAgICBkcm9wYm94OiBCYWNrdXBQcm92aWRlclN0YXR1c1xuICAgIFwiR29vZ2xlIERyaXZlIGF1dGhlbnRpY2F0aW9uIHN0YXR1c1wiXG4gICAgZ29vZ2xlRHJpdmU6IEJhY2t1cFByb3ZpZGVyU3RhdHVzXG4gICAgXCJNZXNzYWdlIGlmIGJhY2t1cHMgdW5hdmFpbGFibGVcIlxuICAgIG1lc3NhZ2U6IFN0cmluZ1xuICAgIFwiRXJyb3IgbWVzc2FnZSBpZiBmYWlsZWRcIlxuICAgIGVycm9yOiBTdHJpbmdcbiAgfVxuXG4gIHR5cGUgQmFja3VwTWV0YWRhdGEge1xuICAgIFwiU25hcHNob3QgSURcIlxuICAgIHNuYXBzaG90SWQ6IFN0cmluZyFcbiAgICBcIkJhY2t1cCB0aW1lc3RhbXAgKElTTyBmb3JtYXQpXCJcbiAgICB0aW1lc3RhbXA6IFN0cmluZ1xuICAgIFwiQmFja3VwIG5vdGUvZGVzY3JpcHRpb25cIlxuICAgIG5vdGU6IFN0cmluZ1xuICAgIFwiU2l0ZSBkb21haW5cIlxuICAgIHNpdGVEb21haW46IFN0cmluZ1xuICAgIFwiU2VydmljZXMgaW5mbyAoSlNPTilcIlxuICAgIHNlcnZpY2VzOiBTdHJpbmdcbiAgfVxuXG4gIHR5cGUgTGlzdEJhY2t1cHNSZXN1bHQge1xuICAgIFwiV2hldGhlciBxdWVyeSB3YXMgc3VjY2Vzc2Z1bFwiXG4gICAgc3VjY2VzczogQm9vbGVhbiFcbiAgICBcIlNpdGUgbmFtZVwiXG4gICAgc2l0ZU5hbWU6IFN0cmluZ1xuICAgIFwiQmFja3VwIHByb3ZpZGVyXCJcbiAgICBwcm92aWRlcjogU3RyaW5nXG4gICAgXCJMaXN0IG9mIGJhY2t1cHNcIlxuICAgIGJhY2t1cHM6IFtCYWNrdXBNZXRhZGF0YSFdXG4gICAgXCJOdW1iZXIgb2YgYmFja3Vwc1wiXG4gICAgY291bnQ6IEludFxuICAgIFwiRXJyb3IgbWVzc2FnZSBpZiBmYWlsZWRcIlxuICAgIGVycm9yOiBTdHJpbmdcbiAgfVxuXG4gIHR5cGUgQ3JlYXRlQmFja3VwUmVzdWx0IHtcbiAgICBcIldoZXRoZXIgYmFja3VwIHdhcyBjcmVhdGVkIHN1Y2Nlc3NmdWxseVwiXG4gICAgc3VjY2VzczogQm9vbGVhbiFcbiAgICBcIlNuYXBzaG90IElEXCJcbiAgICBzbmFwc2hvdElkOiBTdHJpbmdcbiAgICBcIkJhY2t1cCB0aW1lc3RhbXBcIlxuICAgIHRpbWVzdGFtcDogU3RyaW5nXG4gICAgXCJTdGF0dXMgbWVzc2FnZVwiXG4gICAgbWVzc2FnZTogU3RyaW5nXG4gICAgXCJFcnJvciBtZXNzYWdlIGlmIGZhaWxlZFwiXG4gICAgZXJyb3I6IFN0cmluZ1xuICB9XG5cbiAgdHlwZSBSZXN0b3JlQmFja3VwUmVzdWx0IHtcbiAgICBcIldoZXRoZXIgcmVzdG9yZSB3YXMgc3VjY2Vzc2Z1bFwiXG4gICAgc3VjY2VzczogQm9vbGVhbiFcbiAgICBcIlN0YXR1cyBtZXNzYWdlXCJcbiAgICBtZXNzYWdlOiBTdHJpbmdcbiAgICBcIkVycm9yIG1lc3NhZ2UgaWYgZmFpbGVkXCJcbiAgICBlcnJvcjogU3RyaW5nXG4gIH1cblxuICB0eXBlIERlbGV0ZUJhY2t1cFJlc3VsdCB7XG4gICAgXCJXaGV0aGVyIGRlbGV0aW9uIHdhcyBzdWNjZXNzZnVsXCJcbiAgICBzdWNjZXNzOiBCb29sZWFuIVxuICAgIFwiRGVsZXRlZCBzbmFwc2hvdCBJRFwiXG4gICAgZGVsZXRlZFNuYXBzaG90SWQ6IFN0cmluZ1xuICAgIFwiU3RhdHVzIG1lc3NhZ2VcIlxuICAgIG1lc3NhZ2U6IFN0cmluZ1xuICAgIFwiRXJyb3IgbWVzc2FnZSBpZiBmYWlsZWRcIlxuICAgIGVycm9yOiBTdHJpbmdcbiAgfVxuXG4gIHR5cGUgRG93bmxvYWRCYWNrdXBSZXN1bHQge1xuICAgIFwiV2hldGhlciBkb3dubG9hZCB3YXMgc3VjY2Vzc2Z1bFwiXG4gICAgc3VjY2VzczogQm9vbGVhbiFcbiAgICBcIlBhdGggdG8gZG93bmxvYWRlZCBmaWxlXCJcbiAgICBmaWxlUGF0aDogU3RyaW5nXG4gICAgXCJTdGF0dXMgbWVzc2FnZVwiXG4gICAgbWVzc2FnZTogU3RyaW5nXG4gICAgXCJFcnJvciBtZXNzYWdlIGlmIGZhaWxlZFwiXG4gICAgZXJyb3I6IFN0cmluZ1xuICB9XG5cbiAgdHlwZSBFZGl0QmFja3VwTm90ZVJlc3VsdCB7XG4gICAgXCJXaGV0aGVyIGVkaXQgd2FzIHN1Y2Nlc3NmdWxcIlxuICAgIHN1Y2Nlc3M6IEJvb2xlYW4hXG4gICAgXCJVcGRhdGVkIHNuYXBzaG90IElEXCJcbiAgICBzbmFwc2hvdElkOiBTdHJpbmdcbiAgICBcIlVwZGF0ZWQgbm90ZVwiXG4gICAgbm90ZTogU3RyaW5nXG4gICAgXCJFcnJvciBtZXNzYWdlIGlmIGZhaWxlZFwiXG4gICAgZXJyb3I6IFN0cmluZ1xuICB9XG5cbiAgZXh0ZW5kIHR5cGUgUXVlcnkge1xuICAgICMgUGhhc2UgMTA6IENsb3VkIEJhY2t1cHNcbiAgICBcIkNoZWNrIGlmIGNsb3VkIGJhY2t1cHMgYXJlIGF2YWlsYWJsZSBhbmQgYXV0aGVudGljYXRlZFwiXG4gICAgYmFja3VwU3RhdHVzOiBCYWNrdXBTdGF0dXNSZXN1bHQhXG5cbiAgICBcIkxpc3QgYWxsIGJhY2t1cHMgZm9yIGEgc2l0ZVwiXG4gICAgbGlzdEJhY2t1cHMoc2l0ZUlkOiBJRCEsIHByb3ZpZGVyOiBTdHJpbmchKTogTGlzdEJhY2t1cHNSZXN1bHQhXG5cbiAgICAjIFBoYXNlIDExYzogU3luYyBPcGVyYXRpb25zXG4gICAgXCJHZXQgc3luYyBoaXN0b3J5IGZvciBhIGxvY2FsIHNpdGVcIlxuICAgIGdldFN5bmNIaXN0b3J5KHNpdGVJZDogSUQhLCBsaW1pdDogSW50KTogR2V0U3luY0hpc3RvcnlSZXN1bHQhXG5cbiAgICBcIkdldCBmaWxlIGNoYW5nZXMgYmV0d2VlbiBsb2NhbCBzaXRlIGFuZCBXUCBFbmdpbmUgKGRyeS1ydW4gY29tcGFyaXNvbilcIlxuICAgIGdldFNpdGVDaGFuZ2VzKHNpdGVJZDogSUQhLCBkaXJlY3Rpb246IFN0cmluZyA9IFwicHVzaFwiKTogR2V0U2l0ZUNoYW5nZXNSZXN1bHQhXG4gIH1cblxuICBleHRlbmQgdHlwZSBNdXRhdGlvbiB7XG4gICAgIyBQaGFzZSAxMDogQ2xvdWQgQmFja3Vwc1xuICAgIFwiQ3JlYXRlIGEgYmFja3VwIG9mIGEgc2l0ZSB0byBjbG91ZCBzdG9yYWdlXCJcbiAgICBjcmVhdGVCYWNrdXAoc2l0ZUlkOiBJRCEsIHByb3ZpZGVyOiBTdHJpbmchLCBub3RlOiBTdHJpbmcpOiBDcmVhdGVCYWNrdXBSZXN1bHQhXG5cbiAgICBcIlJlc3RvcmUgYSBzaXRlIGZyb20gYSBjbG91ZCBiYWNrdXBcIlxuICAgIHJlc3RvcmVCYWNrdXAoXG4gICAgICBzaXRlSWQ6IElEIVxuICAgICAgcHJvdmlkZXI6IFN0cmluZyFcbiAgICAgIHNuYXBzaG90SWQ6IFN0cmluZyFcbiAgICAgIGNvbmZpcm06IEJvb2xlYW4gPSBmYWxzZVxuICAgICk6IFJlc3RvcmVCYWNrdXBSZXN1bHQhXG5cbiAgICBcIkRlbGV0ZSBhIGJhY2t1cCBmcm9tIGNsb3VkIHN0b3JhZ2VcIlxuICAgIGRlbGV0ZUJhY2t1cChcbiAgICAgIHNpdGVJZDogSUQhXG4gICAgICBwcm92aWRlcjogU3RyaW5nIVxuICAgICAgc25hcHNob3RJZDogU3RyaW5nIVxuICAgICAgY29uZmlybTogQm9vbGVhbiA9IGZhbHNlXG4gICAgKTogRGVsZXRlQmFja3VwUmVzdWx0IVxuXG4gICAgXCJEb3dubG9hZCBhIGJhY2t1cCBhcyBhIFpJUCBmaWxlXCJcbiAgICBkb3dubG9hZEJhY2t1cChzaXRlSWQ6IElEISwgcHJvdmlkZXI6IFN0cmluZyEsIHNuYXBzaG90SWQ6IFN0cmluZyEpOiBEb3dubG9hZEJhY2t1cFJlc3VsdCFcblxuICAgIFwiVXBkYXRlIHRoZSBub3RlL2Rlc2NyaXB0aW9uIGZvciBhIGJhY2t1cFwiXG4gICAgZWRpdEJhY2t1cE5vdGUoXG4gICAgICBzaXRlSWQ6IElEIVxuICAgICAgcHJvdmlkZXI6IFN0cmluZyFcbiAgICAgIHNuYXBzaG90SWQ6IFN0cmluZyFcbiAgICAgIG5vdGU6IFN0cmluZyFcbiAgICApOiBFZGl0QmFja3VwTm90ZVJlc3VsdCFcblxuICAgICMgUGhhc2UgMTE6IFdQIEVuZ2luZSBDb25uZWN0XG4gICAgXCJBdXRoZW50aWNhdGUgd2l0aCBXUCBFbmdpbmUgKG9wZW5zIGJyb3dzZXIgZm9yIE9BdXRoKVwiXG4gICAgd3BlQXV0aGVudGljYXRlOiBXcGVBdXRoUmVzdWx0IVxuXG4gICAgXCJMb2dvdXQgZnJvbSBXUCBFbmdpbmVcIlxuICAgIHdwZUxvZ291dDogV3BlTG9nb3V0UmVzdWx0IVxuXG4gICAgIyBQaGFzZSAxMWM6IFN5bmMgT3BlcmF0aW9uc1xuICAgIFwiUHVzaCBsb2NhbCBzaXRlIHRvIFdQIEVuZ2luZVwiXG4gICAgcHVzaFRvV3BlKFxuICAgICAgbG9jYWxTaXRlSWQ6IElEIVxuICAgICAgcmVtb3RlSW5zdGFsbElkOiBJRCFcbiAgICAgIGluY2x1ZGVTcWw6IEJvb2xlYW4gPSBmYWxzZVxuICAgICAgY29uZmlybTogQm9vbGVhbiA9IGZhbHNlXG4gICAgKTogU3luY1Jlc3VsdCFcblxuICAgIFwiUHVsbCBmcm9tIFdQIEVuZ2luZSB0byBsb2NhbCBzaXRlXCJcbiAgICBwdWxsRnJvbVdwZShsb2NhbFNpdGVJZDogSUQhLCByZW1vdGVJbnN0YWxsSWQ6IElEISwgaW5jbHVkZVNxbDogQm9vbGVhbiA9IGZhbHNlKTogU3luY1Jlc3VsdCFcbiAgfVxuYDtcblxuLyoqXG4gKiBDcmVhdGUgR3JhcGhRTCByZXNvbHZlcnMgdGhhdCB1c2UgTG9jYWwncyBpbnRlcm5hbCBzZXJ2aWNlc1xuICovXG5mdW5jdGlvbiBjcmVhdGVSZXNvbHZlcnMoc2VydmljZXM6IGFueSkge1xuICBjb25zdCB7XG4gICAgZGVsZXRlU2l0ZTogZGVsZXRlU2l0ZVNlcnZpY2UsXG4gICAgc2l0ZURhdGEsXG4gICAgbG9jYWxMb2dnZXIsXG4gICAgd3BDbGksXG4gICAgc2l0ZVByb2Nlc3NNYW5hZ2VyLFxuICAgIGFkZFNpdGU6IGFkZFNpdGVTZXJ2aWNlLFxuICAgIGNsb25lU2l0ZTogY2xvbmVTaXRlU2VydmljZSxcbiAgICBleHBvcnRTaXRlOiBleHBvcnRTaXRlU2VydmljZSxcbiAgICBibHVlcHJpbnRzOiBibHVlcHJpbnRzU2VydmljZSxcbiAgICBicm93c2VyTWFuYWdlcixcbiAgICBhZG1pbmVyLFxuICAgIHg1MDlDZXJ0LFxuICAgIHNpdGVQcm92aXNpb25lcixcbiAgICBpbXBvcnRTaXRlOiBpbXBvcnRTaXRlU2VydmljZSxcbiAgICBsaWdodG5pbmdTZXJ2aWNlcyxcbiAgICBzaXRlRGF0YWJhc2UsXG4gICAgaW1wb3J0U1FMRmlsZTogaW1wb3J0U1FMRmlsZVNlcnZpY2UsXG4gICAgLy8gUGhhc2UgMTE6IFdQIEVuZ2luZSBDb25uZWN0XG4gICAgd3BlT0F1dGg6IHdwZU9BdXRoU2VydmljZSxcbiAgICBjYXBpOiBjYXBpU2VydmljZSxcbiAgICAvLyBQaGFzZSAxMWM6IFN5bmMgc2VydmljZXNcbiAgICB3cGVQdXNoOiB3cGVQdXNoU2VydmljZSxcbiAgICB3cGVQdWxsOiB3cGVQdWxsU2VydmljZSxcbiAgICBjb25uZWN0SGlzdG9yeTogY29ubmVjdEhpc3RvcnlTZXJ2aWNlLFxuICAgIHdwZUNvbm5lY3RCYXNlOiB3cGVDb25uZWN0QmFzZVNlcnZpY2UsXG4gICAgLy8gTm90ZTogUGhhc2UgMTAgQ2xvdWQgQmFja3VwIHNlcnZpY2VzIGFyZSBhY2Nlc3NlZCB2aWEgSVBDIHRvIHRoZSBDbG91ZCBCYWNrdXBzIGFkZG9uXG4gICAgLy8gKGJhY2t1cFNlcnZpY2UsIGRyb3Bib3gsIGdvb2dsZURyaXZlLCBmZWF0dXJlRmxhZ3MsIHVzZXJEYXRhKVxuICB9ID0gc2VydmljZXM7XG5cbiAgLy8gSGVscGVyIHRvIGludm9rZSBJUEMgY2FsbHMgdG8gdGhlIENsb3VkIEJhY2t1cHMgYWRkb25cbiAgLy8gVGhpcyB1c2VzIHRoZSBzYW1lIHBhdHRlcm4gYXMgdGhlIEJhY2t1cEFJQnJpZGdlXG4gIC8vIFRpbWVvdXQgY29uc3RhbnRzIGZvciBiYWNrdXAgb3BlcmF0aW9ucyAoaW4gbWlsbGlzZWNvbmRzKVxuICBjb25zdCBCQUNLVVBfSVBDX1RJTUVPVVQgPSA2MDAwMDA7IC8vIDEwIG1pbnV0ZXMgZm9yIGJhY2t1cCBvcGVyYXRpb25zXG4gIGNvbnN0IERFRkFVTFRfSVBDX1RJTUVPVVQgPSAzMDAwMDsgLy8gMzAgc2Vjb25kcyBmb3IgcXVpY2sgb3BlcmF0aW9uc1xuXG4gIGNvbnN0IGludm9rZUJhY2t1cElQQyA9IGFzeW5jIChcbiAgICBjaGFubmVsOiBzdHJpbmcsXG4gICAgdGltZW91dE1zOiBudW1iZXIgPSBCQUNLVVBfSVBDX1RJTUVPVVQsXG4gICAgLi4uYXJnczogYW55W11cbiAgKTogUHJvbWlzZTxhbnk+ID0+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgY29uc3QgdGltZXN0YW1wID0gRGF0ZS5ub3coKTtcbiAgICAgIGNvbnN0IHJhbmRvbSA9IE1hdGgucmFuZG9tKCkudG9TdHJpbmcoMzYpLnN1YnN0cigyLCA5KTtcbiAgICAgIGNvbnN0IHN1Y2Nlc3NSZXBseUNoYW5uZWwgPSBgJHtjaGFubmVsfS1zdWNjZXNzLSR7dGltZXN0YW1wfS0ke3JhbmRvbX1gO1xuICAgICAgY29uc3QgZXJyb3JSZXBseUNoYW5uZWwgPSBgJHtjaGFubmVsfS1lcnJvci0ke3RpbWVzdGFtcH0tJHtyYW5kb219YDtcblxuICAgICAgY29uc3QgdGltZW91dFNlY29uZHMgPSBNYXRoLnJvdW5kKHRpbWVvdXRNcyAvIDEwMDApO1xuICAgICAgY29uc3QgdGltZW91dCA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICBpcGNNYWluLnJlbW92ZUFsbExpc3RlbmVycyhzdWNjZXNzUmVwbHlDaGFubmVsKTtcbiAgICAgICAgaXBjTWFpbi5yZW1vdmVBbGxMaXN0ZW5lcnMoZXJyb3JSZXBseUNoYW5uZWwpO1xuICAgICAgICByZWplY3QobmV3IEVycm9yKGBJUEMgY2FsbCB0byAke2NoYW5uZWx9IHRpbWVkIG91dCBhZnRlciAke3RpbWVvdXRTZWNvbmRzfSBzZWNvbmRzYCkpO1xuICAgICAgfSwgdGltZW91dE1zKTtcblxuICAgICAgaXBjTWFpbi5vbmNlKHN1Y2Nlc3NSZXBseUNoYW5uZWwsIChfZXZlbnQ6IGFueSwgcmVzdWx0OiBhbnkpID0+IHtcbiAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVvdXQpO1xuICAgICAgICBpcGNNYWluLnJlbW92ZUFsbExpc3RlbmVycyhlcnJvclJlcGx5Q2hhbm5lbCk7XG4gICAgICAgIGxvY2FsTG9nZ2VyLmluZm8oYFske0FERE9OX05BTUV9XSBJUEMgc3VjY2VzcyBmcm9tICR7Y2hhbm5lbH1gKTtcbiAgICAgICAgcmVzb2x2ZSh7IHJlc3VsdCB9KTtcbiAgICAgIH0pO1xuXG4gICAgICBpcGNNYWluLm9uY2UoZXJyb3JSZXBseUNoYW5uZWwsIChfZXZlbnQ6IGFueSwgZXJyb3I6IGFueSkgPT4ge1xuICAgICAgICBjbGVhclRpbWVvdXQodGltZW91dCk7XG4gICAgICAgIGlwY01haW4ucmVtb3ZlQWxsTGlzdGVuZXJzKHN1Y2Nlc3NSZXBseUNoYW5uZWwpO1xuICAgICAgICBsb2NhbExvZ2dlci5lcnJvcihgWyR7QURET05fTkFNRX1dIElQQyBlcnJvciBmcm9tICR7Y2hhbm5lbH06ICR7ZXJyb3I/Lm1lc3NhZ2V9YCk7XG4gICAgICAgIHJlc29sdmUoeyBlcnJvciB9KTtcbiAgICAgIH0pO1xuXG4gICAgICBjb25zdCBtb2NrRXZlbnQgPSB7XG4gICAgICAgIHJlcGx5OiAocmVwbHlDaGFubmVsOiBzdHJpbmcsIGRhdGE6IGFueSkgPT4ge1xuICAgICAgICAgIGlwY01haW4uZW1pdChyZXBseUNoYW5uZWwsIG51bGwsIGRhdGEpO1xuICAgICAgICB9LFxuICAgICAgICBzZW5kZXI6IHtcbiAgICAgICAgICBzZW5kOiAocmVwbHlDaGFubmVsOiBzdHJpbmcsIGRhdGE6IGFueSkgPT4ge1xuICAgICAgICAgICAgaXBjTWFpbi5lbWl0KHJlcGx5Q2hhbm5lbCwgbnVsbCwgZGF0YSk7XG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IHJlcGx5Q2hhbm5lbHMgPSB7IHN1Y2Nlc3NSZXBseUNoYW5uZWwsIGVycm9yUmVwbHlDaGFubmVsIH07XG4gICAgICBsb2NhbExvZ2dlci5pbmZvKGBbJHtBRERPTl9OQU1FfV0gSW52b2tpbmcgYmFja3VwIElQQzogJHtjaGFubmVsfWApO1xuICAgICAgaXBjTWFpbi5lbWl0KGNoYW5uZWwsIG1vY2tFdmVudCwgcmVwbHlDaGFubmVscywgLi4uYXJncyk7XG4gICAgfSk7XG4gIH07XG5cbiAgLy8gSGVscGVyIHRvIGdldCBiYWNrdXAgcHJvdmlkZXJzIGZyb20gdGhlIENsb3VkIEJhY2t1cHMgYWRkb25cbiAgY29uc3QgZ2V0QmFja3VwUHJvdmlkZXJzID0gYXN5bmMgKCk6IFByb21pc2U8QXJyYXk8eyBpZDogc3RyaW5nOyBuYW1lOiBzdHJpbmcgfT4+ID0+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgaW52b2tlQmFja3VwSVBDKCdiYWNrdXBzOmVuYWJsZWQtcHJvdmlkZXJzJywgREVGQVVMVF9JUENfVElNRU9VVCk7XG4gICAgICBsb2NhbExvZ2dlci5pbmZvKGBbJHtBRERPTl9OQU1FfV0gUmF3IElQQyByZXN1bHQ6ICR7SlNPTi5zdHJpbmdpZnkocmVzdWx0KX1gKTtcblxuICAgICAgaWYgKHJlc3VsdC5lcnJvcikge1xuICAgICAgICBsb2NhbExvZ2dlci5lcnJvcihcbiAgICAgICAgICBgWyR7QURET05fTkFNRX1dIEZhaWxlZCB0byBnZXQgYmFja3VwIHByb3ZpZGVyczogJHtyZXN1bHQuZXJyb3IubWVzc2FnZX1gXG4gICAgICAgICk7XG4gICAgICAgIHJldHVybiBbXTtcbiAgICAgIH1cblxuICAgICAgLy8gVGhlIHJlc3BvbnNlIGlzIGRvdWJsZS1uZXN0ZWQ6IHJlc3VsdC5yZXN1bHQucmVzdWx0IGNvbnRhaW5zIHRoZSBhcnJheVxuICAgICAgLy8gU3RydWN0dXJlOiB7IHJlc3VsdDogeyByZXN1bHQ6IFtwcm92aWRlcnMuLi5dIH0gfVxuICAgICAgbGV0IHByb3ZpZGVyczogYW55ID0gcmVzdWx0LnJlc3VsdDtcblxuICAgICAgLy8gVW53cmFwIG5lc3RlZCByZXN1bHQgaWYgcHJlc2VudFxuICAgICAgaWYgKHByb3ZpZGVycyAmJiB0eXBlb2YgcHJvdmlkZXJzID09PSAnb2JqZWN0JyAmJiAhQXJyYXkuaXNBcnJheShwcm92aWRlcnMpKSB7XG4gICAgICAgIGlmIChBcnJheS5pc0FycmF5KHByb3ZpZGVycy5yZXN1bHQpKSB7XG4gICAgICAgICAgcHJvdmlkZXJzID0gcHJvdmlkZXJzLnJlc3VsdDtcbiAgICAgICAgfSBlbHNlIGlmIChwcm92aWRlcnMucmVzdWx0ICYmIHR5cGVvZiBwcm92aWRlcnMucmVzdWx0ID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgIC8vIEV2ZW4gZGVlcGVyIG5lc3RpbmdcbiAgICAgICAgICBwcm92aWRlcnMgPSBwcm92aWRlcnMucmVzdWx0O1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGxvY2FsTG9nZ2VyLmluZm8oYFske0FERE9OX05BTUV9XSBFeHRyYWN0ZWQgcHJvdmlkZXJzOiAke0pTT04uc3RyaW5naWZ5KHByb3ZpZGVycyl9YCk7XG5cbiAgICAgIGlmIChBcnJheS5pc0FycmF5KHByb3ZpZGVycykpIHtcbiAgICAgICAgbG9jYWxMb2dnZXIuaW5mbyhgWyR7QURET05fTkFNRX1dIEdvdCAke3Byb3ZpZGVycy5sZW5ndGh9IGJhY2t1cCBwcm92aWRlcnNgKTtcbiAgICAgICAgcmV0dXJuIHByb3ZpZGVycztcbiAgICAgIH1cblxuICAgICAgbG9jYWxMb2dnZXIud2FybihcbiAgICAgICAgYFske0FERE9OX05BTUV9XSBVbmV4cGVjdGVkIHByb3ZpZGVycyBmb3JtYXQgYWZ0ZXIgdW53cmFwcGluZzogJHt0eXBlb2YgcHJvdmlkZXJzfWBcbiAgICAgICk7XG4gICAgICByZXR1cm4gW107XG4gICAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgICAgbG9jYWxMb2dnZXIuZXJyb3IoYFske0FERE9OX05BTUV9XSBFcnJvciBnZXR0aW5nIGJhY2t1cCBwcm92aWRlcnM6ICR7ZXJyb3IubWVzc2FnZX1gKTtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9XG4gIH07XG5cbiAgLy8gU2hhcmVkIFdQLUNMSSBleGVjdXRpb24gbG9naWNcbiAgY29uc3QgZXhlY3V0ZVdwQ2xpID0gYXN5bmMgKFxuICAgIF9wYXJlbnQ6IGFueSxcbiAgICBhcmdzOiB7IGlucHV0OiB7IHNpdGVJZDogc3RyaW5nOyBhcmdzOiBzdHJpbmdbXTsgc2tpcFBsdWdpbnM/OiBib29sZWFuOyBza2lwVGhlbWVzPzogYm9vbGVhbiB9IH1cbiAgKSA9PiB7XG4gICAgY29uc3QgeyBzaXRlSWQsIGFyZ3M6IHdwQXJncywgc2tpcFBsdWdpbnMgPSB0cnVlLCBza2lwVGhlbWVzID0gdHJ1ZSB9ID0gYXJncy5pbnB1dDtcblxuICAgIHRyeSB7XG4gICAgICBsb2NhbExvZ2dlci5pbmZvKGBbJHtBRERPTl9OQU1FfV0gUnVubmluZyBXUC1DTEk6IHdwICR7d3BBcmdzLmpvaW4oJyAnKX1gKTtcblxuICAgICAgY29uc3Qgc2l0ZSA9IHNpdGVEYXRhLmdldFNpdGUoc2l0ZUlkKTtcbiAgICAgIGlmICghc2l0ZSkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgIG91dHB1dDogbnVsbCxcbiAgICAgICAgICBlcnJvcjogYFNpdGUgbm90IGZvdW5kOiAke3NpdGVJZH1gLFxuICAgICAgICB9O1xuICAgICAgfVxuXG4gICAgICBjb25zdCBzdGF0dXMgPSBhd2FpdCBzaXRlUHJvY2Vzc01hbmFnZXIuZ2V0U2l0ZVN0YXR1cyhzaXRlKTtcbiAgICAgIGlmIChzdGF0dXMgIT09ICdydW5uaW5nJykge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgIG91dHB1dDogbnVsbCxcbiAgICAgICAgICBlcnJvcjogYFNpdGUgXCIke3NpdGUubmFtZX1cIiBpcyBub3QgcnVubmluZy4gU3RhcnQgaXQgZmlyc3Qgd2l0aDogbG9jYWwtY2xpIHN0YXJ0ICR7c2l0ZS5uYW1lfWAsXG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IG91dHB1dCA9IGF3YWl0IHdwQ2xpLnJ1bihzaXRlLCB3cEFyZ3MsIHtcbiAgICAgICAgc2tpcFBsdWdpbnMsXG4gICAgICAgIHNraXBUaGVtZXMsXG4gICAgICAgIGlnbm9yZUVycm9yczogZmFsc2UsXG4gICAgICB9KTtcblxuICAgICAgbG9jYWxMb2dnZXIuaW5mbyhgWyR7QURET05fTkFNRX1dIFdQLUNMSSBjb21wbGV0ZWQgc3VjY2Vzc2Z1bGx5YCk7XG5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgIG91dHB1dDogb3V0cHV0Py50cmltKCkgfHwgJycsXG4gICAgICAgIGVycm9yOiBudWxsLFxuICAgICAgfTtcbiAgICB9IGNhdGNoIChlcnJvcjogYW55KSB7XG4gICAgICBsb2NhbExvZ2dlci5lcnJvcihgWyR7QURET05fTkFNRX1dIFdQLUNMSSBmYWlsZWQ6YCwgZXJyb3IpO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgIG91dHB1dDogbnVsbCxcbiAgICAgICAgZXJyb3I6IGVycm9yLm1lc3NhZ2UgfHwgJ1Vua25vd24gZXJyb3InLFxuICAgICAgfTtcbiAgICB9XG4gIH07XG5cbiAgcmV0dXJuIHtcbiAgICBRdWVyeToge1xuICAgICAgd3BDbGlRdWVyeTogZXhlY3V0ZVdwQ2xpLFxuXG4gICAgICBibHVlcHJpbnRzOiBhc3luYyAoKSA9PiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgbG9jYWxMb2dnZXIuaW5mbyhgWyR7QURET05fTkFNRX1dIEZldGNoaW5nIGJsdWVwcmludHNgKTtcblxuICAgICAgICAgIGNvbnN0IGJsdWVwcmludHNMaXN0ID0gYXdhaXQgYmx1ZXByaW50c1NlcnZpY2UuZ2V0Qmx1ZXByaW50cygpO1xuXG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgICBlcnJvcjogbnVsbCxcbiAgICAgICAgICAgIGJsdWVwcmludHM6IGJsdWVwcmludHNMaXN0Lm1hcCgoYnA6IGFueSkgPT4gKHtcbiAgICAgICAgICAgICAgbmFtZTogYnAubmFtZSxcbiAgICAgICAgICAgICAgbGFzdE1vZGlmaWVkOiBicC5sYXN0TW9kaWZpZWQsXG4gICAgICAgICAgICAgIC8vIEhhbmRsZSBuZXN0ZWQgb2JqZWN0cyAtIGV4dHJhY3QganVzdCB0aGUgbmFtZS90eXBlIHN0cmluZ1xuICAgICAgICAgICAgICBwaHBWZXJzaW9uOlxuICAgICAgICAgICAgICAgIHR5cGVvZiBicC5waHBWZXJzaW9uID09PSAnb2JqZWN0J1xuICAgICAgICAgICAgICAgICAgPyBicC5waHBWZXJzaW9uPy5uYW1lIHx8IGJwLnBocFZlcnNpb24/LnZlcnNpb25cbiAgICAgICAgICAgICAgICAgIDogYnAucGhwVmVyc2lvbixcbiAgICAgICAgICAgICAgd2ViU2VydmVyOlxuICAgICAgICAgICAgICAgIHR5cGVvZiBicC53ZWJTZXJ2ZXIgPT09ICdvYmplY3QnXG4gICAgICAgICAgICAgICAgICA/IGJwLndlYlNlcnZlcj8ubmFtZSB8fCBicC53ZWJTZXJ2ZXI/LnR5cGVcbiAgICAgICAgICAgICAgICAgIDogYnAud2ViU2VydmVyLFxuICAgICAgICAgICAgICBkYXRhYmFzZTpcbiAgICAgICAgICAgICAgICB0eXBlb2YgYnAuZGF0YWJhc2UgPT09ICdvYmplY3QnXG4gICAgICAgICAgICAgICAgICA/IGJwLmRhdGFiYXNlPy5uYW1lIHx8IGJwLmRhdGFiYXNlPy50eXBlXG4gICAgICAgICAgICAgICAgICA6IGJwLmRhdGFiYXNlLFxuICAgICAgICAgICAgfSkpLFxuICAgICAgICAgIH07XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yOiBhbnkpIHtcbiAgICAgICAgICBsb2NhbExvZ2dlci5lcnJvcihgWyR7QURET05fTkFNRX1dIEZhaWxlZCB0byBmZXRjaCBibHVlcHJpbnRzOmAsIGVycm9yKTtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICBlcnJvcjogZXJyb3IubWVzc2FnZSB8fCAnVW5rbm93biBlcnJvcicsXG4gICAgICAgICAgICBibHVlcHJpbnRzOiBbXSxcbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICB9LFxuXG4gICAgICBsaXN0U2VydmljZXM6IGFzeW5jIChfcGFyZW50OiBhbnksIGFyZ3M6IHsgdHlwZT86IHN0cmluZyB9KSA9PiB7XG4gICAgICAgIGNvbnN0IHsgdHlwZSA9ICdhbGwnIH0gPSBhcmdzO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgbG9jYWxMb2dnZXIuaW5mbyhgWyR7QURET05fTkFNRX1dIExpc3Rpbmcgc2VydmljZXMgKHR5cGU6ICR7dHlwZX0pYCk7XG5cbiAgICAgICAgICBpZiAoIWxpZ2h0bmluZ1NlcnZpY2VzKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgZXJyb3I6ICdMaWdodG5pbmcgc2VydmljZXMgbm90IGF2YWlsYWJsZScsXG4gICAgICAgICAgICAgIHNlcnZpY2VzOiBbXSxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgY29uc3Qgcm9sZU1hcDogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHtcbiAgICAgICAgICAgIHBocDogJ3BocCcsXG4gICAgICAgICAgICBkYXRhYmFzZTogJ215c3FsJyxcbiAgICAgICAgICAgIHdlYnNlcnZlcjogJ25naW54JyxcbiAgICAgICAgICB9O1xuXG4gICAgICAgICAgY29uc3Qgcm9sZUZpbHRlciA9IHR5cGUgIT09ICdhbGwnID8gcm9sZU1hcFt0eXBlXSA6IHVuZGVmaW5lZDtcbiAgICAgICAgICBjb25zdCByZWdpc3RlcmVkU2VydmljZXMgPSBsaWdodG5pbmdTZXJ2aWNlcy5nZXRSZWdpc3RlcmVkU2VydmljZXMocm9sZUZpbHRlcik7XG5cbiAgICAgICAgICBjb25zdCBzZXJ2aWNlTGlzdDogQXJyYXk8eyByb2xlOiBzdHJpbmc7IG5hbWU6IHN0cmluZzsgdmVyc2lvbjogc3RyaW5nIH0+ID0gW107XG5cbiAgICAgICAgICBmb3IgKGNvbnN0IFtyb2xlLCB2ZXJzaW9uc10gb2YgT2JqZWN0LmVudHJpZXMocmVnaXN0ZXJlZFNlcnZpY2VzKSkge1xuICAgICAgICAgICAgZm9yIChjb25zdCBbdmVyc2lvbiwgaW5mb10gb2YgT2JqZWN0LmVudHJpZXModmVyc2lvbnMgYXMgUmVjb3JkPHN0cmluZywgYW55PikpIHtcbiAgICAgICAgICAgICAgc2VydmljZUxpc3QucHVzaCh7XG4gICAgICAgICAgICAgICAgcm9sZSxcbiAgICAgICAgICAgICAgICBuYW1lOiBpbmZvPy5uYW1lIHx8IHJvbGUsXG4gICAgICAgICAgICAgICAgdmVyc2lvbixcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgICBlcnJvcjogbnVsbCxcbiAgICAgICAgICAgIHNlcnZpY2VzOiBzZXJ2aWNlTGlzdCxcbiAgICAgICAgICB9O1xuICAgICAgICB9IGNhdGNoIChlcnJvcjogYW55KSB7XG4gICAgICAgICAgbG9jYWxMb2dnZXIuZXJyb3IoYFske0FERE9OX05BTUV9XSBGYWlsZWQgdG8gbGlzdCBzZXJ2aWNlczpgLCBlcnJvcik7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgZXJyb3I6IGVycm9yLm1lc3NhZ2UgfHwgJ1Vua25vd24gZXJyb3InLFxuICAgICAgICAgICAgc2VydmljZXM6IFtdLFxuICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgIH0sXG5cbiAgICAgIC8vIFBoYXNlIDExOiBXUCBFbmdpbmUgQ29ubmVjdFxuICAgICAgd3BlU3RhdHVzOiBhc3luYyAoKSA9PiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgbG9jYWxMb2dnZXIuaW5mbyhgWyR7QURET05fTkFNRX1dIENoZWNraW5nIFdQIEVuZ2luZSBhdXRoZW50aWNhdGlvbiBzdGF0dXNgKTtcblxuICAgICAgICAgIGlmICghd3BlT0F1dGhTZXJ2aWNlKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBhdXRoZW50aWNhdGVkOiBmYWxzZSxcbiAgICAgICAgICAgICAgZW1haWw6IG51bGwsXG4gICAgICAgICAgICAgIGFjY291bnRJZDogbnVsbCxcbiAgICAgICAgICAgICAgYWNjb3VudE5hbWU6IG51bGwsXG4gICAgICAgICAgICAgIHRva2VuRXhwaXJ5OiBudWxsLFxuICAgICAgICAgICAgICBlcnJvcjogJ1dQIEVuZ2luZSBPQXV0aCBzZXJ2aWNlIG5vdCBhdmFpbGFibGUnLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBDaGVjayBpZiB3ZSBoYXZlIHZhbGlkIGNyZWRlbnRpYWxzIGJ5IHRyeWluZyB0byBnZXQgYWNjZXNzIHRva2VuXG4gICAgICAgICAgY29uc3QgYWNjZXNzVG9rZW4gPSBhd2FpdCB3cGVPQXV0aFNlcnZpY2UuZ2V0QWNjZXNzVG9rZW4oKTtcblxuICAgICAgICAgIGlmICghYWNjZXNzVG9rZW4pIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIGF1dGhlbnRpY2F0ZWQ6IGZhbHNlLFxuICAgICAgICAgICAgICBlbWFpbDogbnVsbCxcbiAgICAgICAgICAgICAgYWNjb3VudElkOiBudWxsLFxuICAgICAgICAgICAgICBhY2NvdW50TmFtZTogbnVsbCxcbiAgICAgICAgICAgICAgdG9rZW5FeHBpcnk6IG51bGwsXG4gICAgICAgICAgICAgIGVycm9yOiBudWxsLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBUcnkgdG8gZ2V0IHVzZXIgaW5mbyBmcm9tIENBUEkgaWYgYXZhaWxhYmxlXG4gICAgICAgICAgbGV0IGVtYWlsID0gbnVsbDtcbiAgICAgICAgICBpZiAoY2FwaVNlcnZpY2UpIHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgIGNvbnN0IGN1cnJlbnRVc2VyID0gYXdhaXQgY2FwaVNlcnZpY2UuZ2V0Q3VycmVudFVzZXIoKTtcbiAgICAgICAgICAgICAgZW1haWwgPSBjdXJyZW50VXNlcj8uZW1haWwgfHwgbnVsbDtcbiAgICAgICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgICAgICAvLyBVc2VyIGluZm8gbm90IGF2YWlsYWJsZSwgYnV0IHN0aWxsIGF1dGhlbnRpY2F0ZWRcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgYXV0aGVudGljYXRlZDogdHJ1ZSxcbiAgICAgICAgICAgIGVtYWlsLFxuICAgICAgICAgICAgYWNjb3VudElkOiBudWxsLFxuICAgICAgICAgICAgYWNjb3VudE5hbWU6IG51bGwsXG4gICAgICAgICAgICB0b2tlbkV4cGlyeTogbnVsbCxcbiAgICAgICAgICAgIGVycm9yOiBudWxsLFxuICAgICAgICAgIH07XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yOiBhbnkpIHtcbiAgICAgICAgICBsb2NhbExvZ2dlci5lcnJvcihgWyR7QURET05fTkFNRX1dIEZhaWxlZCB0byBjaGVjayBXUEUgc3RhdHVzOmAsIGVycm9yKTtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgYXV0aGVudGljYXRlZDogZmFsc2UsXG4gICAgICAgICAgICBlbWFpbDogbnVsbCxcbiAgICAgICAgICAgIGFjY291bnRJZDogbnVsbCxcbiAgICAgICAgICAgIGFjY291bnROYW1lOiBudWxsLFxuICAgICAgICAgICAgdG9rZW5FeHBpcnk6IG51bGwsXG4gICAgICAgICAgICBlcnJvcjogZXJyb3IubWVzc2FnZSB8fCAnVW5rbm93biBlcnJvcicsXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgfSxcblxuICAgICAgbGlzdFdwZVNpdGVzOiBhc3luYyAoX3BhcmVudDogYW55LCBhcmdzOiB7IGFjY291bnRJZD86IHN0cmluZyB9KSA9PiB7XG4gICAgICAgIGNvbnN0IHsgYWNjb3VudElkIH0gPSBhcmdzO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgbG9jYWxMb2dnZXIuaW5mbyhcbiAgICAgICAgICAgIGBbJHtBRERPTl9OQU1FfV0gTGlzdGluZyBXUCBFbmdpbmUgc2l0ZXMke2FjY291bnRJZCA/IGAgZm9yIGFjY291bnQgJHthY2NvdW50SWR9YCA6ICcnfWBcbiAgICAgICAgICApO1xuXG4gICAgICAgICAgaWYgKCF3cGVPQXV0aFNlcnZpY2UpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICBlcnJvcjogJ1dQIEVuZ2luZSBPQXV0aCBzZXJ2aWNlIG5vdCBhdmFpbGFibGUnLFxuICAgICAgICAgICAgICBzaXRlczogW10sXG4gICAgICAgICAgICAgIGNvdW50OiAwLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBDaGVjayBpZiBhdXRoZW50aWNhdGVkIGJ5IHRyeWluZyB0byBnZXQgYWNjZXNzIHRva2VuXG4gICAgICAgICAgY29uc3QgYWNjZXNzVG9rZW4gPSBhd2FpdCB3cGVPQXV0aFNlcnZpY2UuZ2V0QWNjZXNzVG9rZW4oKTtcbiAgICAgICAgICBpZiAoIWFjY2Vzc1Rva2VuKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgZXJyb3I6ICdOb3QgYXV0aGVudGljYXRlZCB3aXRoIFdQIEVuZ2luZS4gVXNlIHdwZV9hdXRoZW50aWNhdGUgZmlyc3QuJyxcbiAgICAgICAgICAgICAgc2l0ZXM6IFtdLFxuICAgICAgICAgICAgICBjb3VudDogMCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKCFjYXBpU2VydmljZSkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICAgIGVycm9yOiAnV1AgRW5naW5lIENBUEkgc2VydmljZSBub3QgYXZhaWxhYmxlJyxcbiAgICAgICAgICAgICAgc2l0ZXM6IFtdLFxuICAgICAgICAgICAgICBjb3VudDogMCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gR2V0IGluc3RhbGxzIGZyb20gQ0FQSSB1c2luZyBnZXRJbnN0YWxsTGlzdFxuICAgICAgICAgIGNvbnN0IGluc3RhbGxzID0gYXdhaXQgY2FwaVNlcnZpY2UuZ2V0SW5zdGFsbExpc3QoKTtcblxuICAgICAgICAgIGlmICghaW5zdGFsbHMpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgICAgIGVycm9yOiBudWxsLFxuICAgICAgICAgICAgICBzaXRlczogW10sXG4gICAgICAgICAgICAgIGNvdW50OiAwLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjb25zdCBzaXRlcyA9IGluc3RhbGxzLm1hcCgoaW5zdGFsbDogYW55KSA9PiAoe1xuICAgICAgICAgICAgaWQ6IGluc3RhbGwuaWQsXG4gICAgICAgICAgICBuYW1lOiBpbnN0YWxsLm5hbWUsXG4gICAgICAgICAgICBlbnZpcm9ubWVudDogaW5zdGFsbC5lbnZpcm9ubWVudCB8fCAncHJvZHVjdGlvbicsXG4gICAgICAgICAgICBwaHBWZXJzaW9uOiBpbnN0YWxsLnBocFZlcnNpb24gfHwgbnVsbCxcbiAgICAgICAgICAgIHByaW1hcnlEb21haW46IGluc3RhbGwucHJpbWFyeURvbWFpbiB8fCBpbnN0YWxsLmNuYW1lIHx8IG51bGwsXG4gICAgICAgICAgICBhY2NvdW50SWQ6IGluc3RhbGwuYWNjb3VudElkIHx8IGFjY291bnRJZCB8fCBudWxsLFxuICAgICAgICAgICAgYWNjb3VudE5hbWU6IGluc3RhbGwuYWNjb3VudE5hbWUgfHwgbnVsbCxcbiAgICAgICAgICAgIHNmdHBIb3N0OiBgJHtpbnN0YWxsLm5hbWV9LnNzaC53cGVuZ2luZS5uZXRgLFxuICAgICAgICAgICAgc2Z0cFVzZXI6IGluc3RhbGwubmFtZSxcbiAgICAgICAgICB9KSk7XG5cbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgICAgICAgIGVycm9yOiBudWxsLFxuICAgICAgICAgICAgc2l0ZXMsXG4gICAgICAgICAgICBjb3VudDogc2l0ZXMubGVuZ3RoLFxuICAgICAgICAgIH07XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yOiBhbnkpIHtcbiAgICAgICAgICBsb2NhbExvZ2dlci5lcnJvcihgWyR7QURET05fTkFNRX1dIEZhaWxlZCB0byBsaXN0IFdQRSBzaXRlczpgLCBlcnJvcik7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgZXJyb3I6IGVycm9yLm1lc3NhZ2UgfHwgJ1Vua25vd24gZXJyb3InLFxuICAgICAgICAgICAgc2l0ZXM6IFtdLFxuICAgICAgICAgICAgY291bnQ6IDAsXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgfSxcblxuICAgICAgLy8gUGhhc2UgMTFiOiBTaXRlIExpbmtpbmdcbiAgICAgIGdldFdwZUxpbms6IGFzeW5jIChfcGFyZW50OiBhbnksIGFyZ3M6IHsgc2l0ZUlkOiBzdHJpbmcgfSkgPT4ge1xuICAgICAgICBjb25zdCB7IHNpdGVJZCB9ID0gYXJncztcblxuICAgICAgICB0cnkge1xuICAgICAgICAgIGxvY2FsTG9nZ2VyLmluZm8oYFske0FERE9OX05BTUV9XSBHZXR0aW5nIFdQIEVuZ2luZSBsaW5rIGZvciBzaXRlICR7c2l0ZUlkfWApO1xuXG4gICAgICAgICAgLy8gR2V0IHNpdGUgZnJvbSBzaXRlRGF0YVxuICAgICAgICAgIGNvbnN0IHNpdGUgPSBzaXRlRGF0YS5nZXRTaXRlKHNpdGVJZCk7XG4gICAgICAgICAgaWYgKCFzaXRlKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBsaW5rZWQ6IGZhbHNlLFxuICAgICAgICAgICAgICBzaXRlTmFtZTogbnVsbCxcbiAgICAgICAgICAgICAgY29ubmVjdGlvbnM6IFtdLFxuICAgICAgICAgICAgICBjb25uZWN0aW9uQ291bnQ6IDAsXG4gICAgICAgICAgICAgIG1lc3NhZ2U6IG51bGwsXG4gICAgICAgICAgICAgIGVycm9yOiBgU2l0ZSBub3QgZm91bmQ6ICR7c2l0ZUlkfWAsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIEdldCBob3N0Q29ubmVjdGlvbnMgZnJvbSBzaXRlXG4gICAgICAgICAgY29uc3QgaG9zdENvbm5lY3Rpb25zID0gc2l0ZS5ob3N0Q29ubmVjdGlvbnMgfHwgW107XG4gICAgICAgICAgY29uc3Qgd3BlQ29ubmVjdGlvbnMgPSBob3N0Q29ubmVjdGlvbnMuZmlsdGVyKChjOiBhbnkpID0+IGMuaG9zdElkID09PSAnd3BlJyk7XG5cbiAgICAgICAgICBpZiAod3BlQ29ubmVjdGlvbnMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBsaW5rZWQ6IGZhbHNlLFxuICAgICAgICAgICAgICBzaXRlTmFtZTogc2l0ZS5uYW1lLFxuICAgICAgICAgICAgICBjb25uZWN0aW9uczogW10sXG4gICAgICAgICAgICAgIGNvbm5lY3Rpb25Db3VudDogMCxcbiAgICAgICAgICAgICAgbWVzc2FnZTpcbiAgICAgICAgICAgICAgICAnU2l0ZSBpcyBub3QgbGlua2VkIHRvIGFueSBXUCBFbmdpbmUgZW52aXJvbm1lbnQuIFVzZSBDb25uZWN0IGluIExvY2FsIHRvIHB1bGwgYSBzaXRlIGZyb20gV1BFLicsXG4gICAgICAgICAgICAgIGVycm9yOiBudWxsLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBUcmFuc2Zvcm0gY29ubmVjdGlvbnMgZm9yIG91dHB1dCwgZW5yaWNoaW5nIHdpdGggQ0FQSSBkYXRhIGlmIGF2YWlsYWJsZVxuICAgICAgICAgIGNvbnN0IGNvbm5lY3Rpb25zID0gYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgICAgICB3cGVDb25uZWN0aW9ucy5tYXAoYXN5bmMgKGM6IGFueSkgPT4ge1xuICAgICAgICAgICAgICBsZXQgaW5zdGFsbE5hbWUgPSBjLnJlbW90ZVNpdGVJZDsgLy8gRGVmYXVsdCB0byBVVUlEXG4gICAgICAgICAgICAgIGxldCBwb3J0YWxVcmwgPSBudWxsO1xuICAgICAgICAgICAgICBsZXQgcHJpbWFyeURvbWFpbiA9IG51bGw7XG5cbiAgICAgICAgICAgICAgLy8gVHJ5IHRvIGdldCBpbnN0YWxsIGRldGFpbHMgZnJvbSBDQVBJIHRvIGdldCB0aGUgYWN0dWFsIG5hbWVcbiAgICAgICAgICAgICAgLy8gcmVtb3RlU2l0ZUlkIG1hdGNoZXMgaW5zdGFsbC5zaXRlLmlkIChXUEUgU2l0ZSBJRCksIG5vdCBpbnN0YWxsLmlkXG4gICAgICAgICAgICAgIGlmIChjYXBpU2VydmljZSAmJiB0eXBlb2YgY2FwaVNlcnZpY2UuZ2V0SW5zdGFsbExpc3QgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgbG9jYWxMb2dnZXIuaW5mbyhcbiAgICAgICAgICAgICAgICAgICAgYFske0FERE9OX05BTUV9XSBMb29raW5nIGZvciBpbnN0YWxsIHdpdGggc2l0ZS5pZD0ke2MucmVtb3RlU2l0ZUlkfSwgZW52PSR7Yy5yZW1vdGVTaXRlRW52fWBcbiAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICBjb25zdCBpbnN0YWxscyA9IGF3YWl0IGNhcGlTZXJ2aWNlLmdldEluc3RhbGxMaXN0KCk7XG4gICAgICAgICAgICAgICAgICBsb2NhbExvZ2dlci5pbmZvKFxuICAgICAgICAgICAgICAgICAgICBgWyR7QURET05fTkFNRX1dIEdvdCAke2luc3RhbGxzPy5sZW5ndGggfHwgMH0gaW5zdGFsbHMgZnJvbSBDQVBJYFxuICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgIGlmIChpbnN0YWxscyAmJiBpbnN0YWxscy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIExvZyBmaXJzdCBpbnN0YWxsIHN0cnVjdHVyZSBmb3IgZGVidWdnaW5nXG4gICAgICAgICAgICAgICAgICAgIGxvY2FsTG9nZ2VyLmluZm8oXG4gICAgICAgICAgICAgICAgICAgICAgYFske0FERE9OX05BTUV9XSBTYW1wbGUgaW5zdGFsbCBzdHJ1Y3R1cmU6ICR7SlNPTi5zdHJpbmdpZnkoaW5zdGFsbHNbMF0sIG51bGwsIDIpfWBcbiAgICAgICAgICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgICAgICAgICAvLyBNYXRjaCBieSBzaXRlLmlkIChyZW1vdGVTaXRlSWQgaXMgdGhlIFdQRSBTaXRlIElELCBub3QgSW5zdGFsbCBJRClcbiAgICAgICAgICAgICAgICAgICAgLy8gQWxzbyBmaWx0ZXIgYnkgZW52aXJvbm1lbnQgaWYgYXZhaWxhYmxlXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IG1hdGNoaW5nSW5zdGFsbCA9IGluc3RhbGxzLmZpbmQoXG4gICAgICAgICAgICAgICAgICAgICAgKGk6IGFueSkgPT5cbiAgICAgICAgICAgICAgICAgICAgICAgIGkuc2l0ZT8uaWQgPT09IGMucmVtb3RlU2l0ZUlkICYmXG4gICAgICAgICAgICAgICAgICAgICAgICAoIWMucmVtb3RlU2l0ZUVudiB8fCBpLmVudmlyb25tZW50ID09PSBjLnJlbW90ZVNpdGVFbnYpXG4gICAgICAgICAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKG1hdGNoaW5nSW5zdGFsbCkge1xuICAgICAgICAgICAgICAgICAgICAgIGxvY2FsTG9nZ2VyLmluZm8oYFske0FERE9OX05BTUV9XSBGb3VuZCBtYXRjaDogJHttYXRjaGluZ0luc3RhbGwubmFtZX1gKTtcbiAgICAgICAgICAgICAgICAgICAgICBpbnN0YWxsTmFtZSA9IG1hdGNoaW5nSW5zdGFsbC5uYW1lO1xuICAgICAgICAgICAgICAgICAgICAgIHBvcnRhbFVybCA9IGBodHRwczovL215LndwZW5naW5lLmNvbS9pbnN0YWxscy8ke21hdGNoaW5nSW5zdGFsbC5uYW1lfWA7XG4gICAgICAgICAgICAgICAgICAgICAgcHJpbWFyeURvbWFpbiA9XG4gICAgICAgICAgICAgICAgICAgICAgICBtYXRjaGluZ0luc3RhbGwucHJpbWFyeV9kb21haW4gfHwgbWF0Y2hpbmdJbnN0YWxsLmNuYW1lIHx8IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgbG9jYWxMb2dnZXIud2FybihcbiAgICAgICAgICAgICAgICAgICAgICAgIGBbJHtBRERPTl9OQU1FfV0gTm8gbWF0Y2hpbmcgaW5zdGFsbCBmb3VuZCBmb3Igc2l0ZS5pZD0ke2MucmVtb3RlU2l0ZUlkfWBcbiAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICAgICAgICAgICAgICBsb2NhbExvZ2dlci53YXJuKFxuICAgICAgICAgICAgICAgICAgICBgWyR7QURET05fTkFNRX1dIENvdWxkIG5vdCBsb29rIHVwIGluc3RhbGwgZnJvbSBDQVBJOiAke2UubWVzc2FnZX1gXG4gICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBsb2NhbExvZ2dlci53YXJuKGBbJHtBRERPTl9OQU1FfV0gY2FwaVNlcnZpY2Ugb3IgZ2V0SW5zdGFsbExpc3Qgbm90IGF2YWlsYWJsZWApO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICByZW1vdGVJbnN0YWxsSWQ6IGMucmVtb3RlU2l0ZUlkLFxuICAgICAgICAgICAgICAgIGluc3RhbGxOYW1lLFxuICAgICAgICAgICAgICAgIGVudmlyb25tZW50OiBjLnJlbW90ZVNpdGVFbnYgfHwgbnVsbCxcbiAgICAgICAgICAgICAgICBhY2NvdW50SWQ6IGMuYWNjb3VudElkIHx8IG51bGwsXG4gICAgICAgICAgICAgICAgcG9ydGFsVXJsLFxuICAgICAgICAgICAgICAgIHByaW1hcnlEb21haW4sXG4gICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICk7XG5cbiAgICAgICAgICAvLyBDYXBhYmlsaXRpZXMgYXJlIGFsd2F5cyB0aGUgc2FtZSBmb3IgV1BFLWNvbm5lY3RlZCBzaXRlc1xuICAgICAgICAgIGNvbnN0IGNhcGFiaWxpdGllcyA9IHtcbiAgICAgICAgICAgIGNhblB1c2g6IHRydWUsXG4gICAgICAgICAgICBjYW5QdWxsOiB0cnVlLFxuICAgICAgICAgICAgc3luY01vZGVzOiBbJ2FsbF9maWxlcycsICdzZWxlY3RfZmlsZXMnLCAnZGF0YWJhc2Vfb25seSddLFxuICAgICAgICAgICAgbWFnaWNTeW5jQXZhaWxhYmxlOiB0cnVlLFxuICAgICAgICAgICAgZGF0YWJhc2VTeW5jQXZhaWxhYmxlOiB0cnVlLFxuICAgICAgICAgIH07XG5cbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgbGlua2VkOiB0cnVlLFxuICAgICAgICAgICAgc2l0ZU5hbWU6IHNpdGUubmFtZSxcbiAgICAgICAgICAgIGNvbm5lY3Rpb25zLFxuICAgICAgICAgICAgY29ubmVjdGlvbkNvdW50OiBjb25uZWN0aW9ucy5sZW5ndGgsXG4gICAgICAgICAgICBjYXBhYmlsaXRpZXMsXG4gICAgICAgICAgICBtZXNzYWdlOiBudWxsLFxuICAgICAgICAgICAgZXJyb3I6IG51bGwsXG4gICAgICAgICAgfTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgICAgICAgIGxvY2FsTG9nZ2VyLmVycm9yKGBbJHtBRERPTl9OQU1FfV0gRmFpbGVkIHRvIGdldCBXUEUgbGluazpgLCBlcnJvcik7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGxpbmtlZDogZmFsc2UsXG4gICAgICAgICAgICBzaXRlTmFtZTogbnVsbCxcbiAgICAgICAgICAgIGNvbm5lY3Rpb25zOiBbXSxcbiAgICAgICAgICAgIGNvbm5lY3Rpb25Db3VudDogMCxcbiAgICAgICAgICAgIG1lc3NhZ2U6IG51bGwsXG4gICAgICAgICAgICBlcnJvcjogZXJyb3IubWVzc2FnZSB8fCAnVW5rbm93biBlcnJvcicsXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgfSxcblxuICAgICAgLy8gUGhhc2UgMTA6IENsb3VkIEJhY2t1cHNcbiAgICAgIGJhY2t1cFN0YXR1czogYXN5bmMgKCkgPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGxvY2FsTG9nZ2VyLmluZm8oYFske0FERE9OX05BTUV9XSBDaGVja2luZyBiYWNrdXAgc3RhdHVzYCk7XG5cbiAgICAgICAgICAvLyBHZXQgcHJvdmlkZXJzIGZyb20gQ2xvdWQgQmFja3VwcyBhZGRvbiB2aWEgSVBDXG4gICAgICAgICAgY29uc3QgcHJvdmlkZXJzID0gYXdhaXQgZ2V0QmFja3VwUHJvdmlkZXJzKCk7XG4gICAgICAgICAgbG9jYWxMb2dnZXIuaW5mbyhgWyR7QURET05fTkFNRX1dIEdvdCAke3Byb3ZpZGVycy5sZW5ndGh9IGJhY2t1cCBwcm92aWRlcnNgKTtcblxuICAgICAgICAgIGlmIChwcm92aWRlcnMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBhdmFpbGFibGU6IGZhbHNlLFxuICAgICAgICAgICAgICBmZWF0dXJlRW5hYmxlZDogZmFsc2UsXG4gICAgICAgICAgICAgIGRyb3Bib3g6IG51bGwsXG4gICAgICAgICAgICAgIGdvb2dsZURyaXZlOiBudWxsLFxuICAgICAgICAgICAgICBtZXNzYWdlOlxuICAgICAgICAgICAgICAgICdObyBjbG91ZCBzdG9yYWdlIHByb3ZpZGVycyBjb25maWd1cmVkLiBDb25uZWN0IEdvb2dsZSBEcml2ZSBvciBEcm9wYm94IGluIExvY2FsIEh1YiAoaHViLmxvY2Fsd3AuY29tL2FkZG9ucy9jbG91ZC1iYWNrdXBzKS4nLFxuICAgICAgICAgICAgICBlcnJvcjogbnVsbCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gTWFwIHByb3ZpZGVyIGluZm8gdG8gb3VyIHJlc3BvbnNlIGZvcm1hdFxuICAgICAgICAgIGNvbnN0IGRyb3Bib3hQcm92aWRlciA9IHByb3ZpZGVycy5maW5kKFxuICAgICAgICAgICAgKHA6IGFueSkgPT4gcC5pZCA9PT0gJ2Ryb3Bib3gnIHx8IHAubmFtZT8udG9Mb3dlckNhc2UoKS5pbmNsdWRlcygnZHJvcGJveCcpXG4gICAgICAgICAgKSBhcyBhbnk7XG4gICAgICAgICAgY29uc3QgZ29vZ2xlUHJvdmlkZXIgPSBwcm92aWRlcnMuZmluZChcbiAgICAgICAgICAgIChwOiBhbnkpID0+IHAuaWQgPT09ICdnb29nbGUnIHx8IHAubmFtZT8udG9Mb3dlckNhc2UoKS5pbmNsdWRlcygnZ29vZ2xlJylcbiAgICAgICAgICApIGFzIGFueTtcblxuICAgICAgICAgIGNvbnN0IGRyb3Bib3hTdGF0dXMgPSBkcm9wYm94UHJvdmlkZXJcbiAgICAgICAgICAgID8ge1xuICAgICAgICAgICAgICAgIGF1dGhlbnRpY2F0ZWQ6IHRydWUsXG4gICAgICAgICAgICAgICAgYWNjb3VudElkOiBkcm9wYm94UHJvdmlkZXIuaWQsXG4gICAgICAgICAgICAgICAgZW1haWw6IGRyb3Bib3hQcm92aWRlci5lbWFpbCB8fCBudWxsLFxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICA6IHtcbiAgICAgICAgICAgICAgICBhdXRoZW50aWNhdGVkOiBmYWxzZSxcbiAgICAgICAgICAgICAgICBhY2NvdW50SWQ6IG51bGwgYXMgc3RyaW5nIHwgbnVsbCxcbiAgICAgICAgICAgICAgICBlbWFpbDogbnVsbCBhcyBzdHJpbmcgfCBudWxsLFxuICAgICAgICAgICAgICB9O1xuXG4gICAgICAgICAgY29uc3QgZ29vZ2xlRHJpdmVTdGF0dXMgPSBnb29nbGVQcm92aWRlclxuICAgICAgICAgICAgPyB7XG4gICAgICAgICAgICAgICAgYXV0aGVudGljYXRlZDogdHJ1ZSxcbiAgICAgICAgICAgICAgICBhY2NvdW50SWQ6IGdvb2dsZVByb3ZpZGVyLmlkLFxuICAgICAgICAgICAgICAgIGVtYWlsOiBnb29nbGVQcm92aWRlci5lbWFpbCB8fCBudWxsLFxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICA6IHtcbiAgICAgICAgICAgICAgICBhdXRoZW50aWNhdGVkOiBmYWxzZSxcbiAgICAgICAgICAgICAgICBhY2NvdW50SWQ6IG51bGwgYXMgc3RyaW5nIHwgbnVsbCxcbiAgICAgICAgICAgICAgICBlbWFpbDogbnVsbCBhcyBzdHJpbmcgfCBudWxsLFxuICAgICAgICAgICAgICB9O1xuXG4gICAgICAgICAgY29uc3QgaGFzUHJvdmlkZXIgPSBwcm92aWRlcnMubGVuZ3RoID4gMDtcblxuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBhdmFpbGFibGU6IGhhc1Byb3ZpZGVyLFxuICAgICAgICAgICAgZmVhdHVyZUVuYWJsZWQ6IHRydWUsXG4gICAgICAgICAgICBkcm9wYm94OiBkcm9wYm94U3RhdHVzLFxuICAgICAgICAgICAgZ29vZ2xlRHJpdmU6IGdvb2dsZURyaXZlU3RhdHVzLFxuICAgICAgICAgICAgbWVzc2FnZTogaGFzUHJvdmlkZXJcbiAgICAgICAgICAgICAgPyBudWxsXG4gICAgICAgICAgICAgIDogJ05vIGNsb3VkIHN0b3JhZ2UgcHJvdmlkZXIgYXV0aGVudGljYXRlZC4gQ29ubmVjdCBEcm9wYm94IG9yIEdvb2dsZSBEcml2ZSBpbiBMb2NhbCBzZXR0aW5ncy4nLFxuICAgICAgICAgICAgZXJyb3I6IG51bGwsXG4gICAgICAgICAgfTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgICAgICAgIGxvY2FsTG9nZ2VyLmVycm9yKGBbJHtBRERPTl9OQU1FfV0gRmFpbGVkIHRvIGNoZWNrIGJhY2t1cCBzdGF0dXM6YCwgZXJyb3IpO1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBhdmFpbGFibGU6IGZhbHNlLFxuICAgICAgICAgICAgZmVhdHVyZUVuYWJsZWQ6IGZhbHNlLFxuICAgICAgICAgICAgZHJvcGJveDogbnVsbCxcbiAgICAgICAgICAgIGdvb2dsZURyaXZlOiBudWxsLFxuICAgICAgICAgICAgbWVzc2FnZTogbnVsbCxcbiAgICAgICAgICAgIGVycm9yOiBlcnJvci5tZXNzYWdlIHx8ICdVbmtub3duIGVycm9yJyxcbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICB9LFxuXG4gICAgICBsaXN0QmFja3VwczogYXN5bmMgKF9wYXJlbnQ6IGFueSwgYXJnczogeyBzaXRlSWQ6IHN0cmluZzsgcHJvdmlkZXI6IHN0cmluZyB9KSA9PiB7XG4gICAgICAgIGNvbnN0IHsgc2l0ZUlkLCBwcm92aWRlciB9ID0gYXJncztcblxuICAgICAgICB0cnkge1xuICAgICAgICAgIGxvY2FsTG9nZ2VyLmluZm8oYFske0FERE9OX05BTUV9XSBMaXN0aW5nIGJhY2t1cHMgZm9yIHNpdGUgJHtzaXRlSWR9IGZyb20gJHtwcm92aWRlcn1gKTtcblxuICAgICAgICAgIC8vIEdldCBzaXRlXG4gICAgICAgICAgY29uc3Qgc2l0ZSA9IHNpdGVEYXRhLmdldFNpdGUoc2l0ZUlkKTtcbiAgICAgICAgICBpZiAoIXNpdGUpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICBzaXRlTmFtZTogbnVsbCxcbiAgICAgICAgICAgICAgcHJvdmlkZXIsXG4gICAgICAgICAgICAgIGJhY2t1cHM6IFtdLFxuICAgICAgICAgICAgICBjb3VudDogMCxcbiAgICAgICAgICAgICAgZXJyb3I6IGBTaXRlIG5vdCBmb3VuZDogJHtzaXRlSWR9YCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gR2V0IHByb3ZpZGVycyBmcm9tIENsb3VkIEJhY2t1cHMgYWRkb25cbiAgICAgICAgICBjb25zdCBwcm92aWRlcnMgPSBhd2FpdCBnZXRCYWNrdXBQcm92aWRlcnMoKTtcbiAgICAgICAgICBpZiAocHJvdmlkZXJzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICAgIHNpdGVOYW1lOiBzaXRlLm5hbWUsXG4gICAgICAgICAgICAgIHByb3ZpZGVyLFxuICAgICAgICAgICAgICBiYWNrdXBzOiBbXSxcbiAgICAgICAgICAgICAgY291bnQ6IDAsXG4gICAgICAgICAgICAgIGVycm9yOlxuICAgICAgICAgICAgICAgICdObyBjbG91ZCBzdG9yYWdlIHByb3ZpZGVycyBjb25maWd1cmVkLiBDb25uZWN0IEdvb2dsZSBEcml2ZSBvciBEcm9wYm94IGluIExvY2FsIEh1Yi4nLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBGaW5kIHRoZSBtYXRjaGluZyBwcm92aWRlciAobWFwICdnb29nbGVEcml2ZScgdG8gJ2dvb2dsZScgZm9yIHRoZSBhZGRvbilcbiAgICAgICAgICBjb25zdCBwcm92aWRlck1hcDogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHsgZ29vZ2xlRHJpdmU6ICdnb29nbGUnLCBkcm9wYm94OiAnZHJvcGJveCcgfTtcbiAgICAgICAgICBjb25zdCBwcm92aWRlcklkID0gcHJvdmlkZXJNYXBbcHJvdmlkZXJdIHx8IHByb3ZpZGVyO1xuICAgICAgICAgIGNvbnN0IG1hdGNoZWRQcm92aWRlciA9IHByb3ZpZGVycy5maW5kKChwOiBhbnkpID0+IHAuaWQgPT09IHByb3ZpZGVySWQpO1xuXG4gICAgICAgICAgaWYgKCFtYXRjaGVkUHJvdmlkZXIpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICBzaXRlTmFtZTogc2l0ZS5uYW1lLFxuICAgICAgICAgICAgICBwcm92aWRlcixcbiAgICAgICAgICAgICAgYmFja3VwczogW10sXG4gICAgICAgICAgICAgIGNvdW50OiAwLFxuICAgICAgICAgICAgICBlcnJvcjogYFByb3ZpZGVyICcke3Byb3ZpZGVyfScgbm90IGNvbmZpZ3VyZWQuIEF2YWlsYWJsZTogJHtwcm92aWRlcnMubWFwKChwOiBhbnkpID0+IHAubmFtZSkuam9pbignLCAnKX1gLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBGb3IgbGlzdGluZyBzbmFwc2hvdHMsIHVzZSB0aGUgSHViIHByb3ZpZGVyIElEIGRpcmVjdGx5IChlLmcuLCAnZ29vZ2xlJylcbiAgICAgICAgICAvLyBOT1QgdGhlIHJjbG9uZSBiYWNrZW5kIG5hbWUgKCdkcml2ZScpIC0gdGhlIEh1YiBxdWVyaWVzIGV4cGVjdCB0aGUgT0F1dGggcHJvdmlkZXIgbmFtZVxuICAgICAgICAgIC8vIEFsc28gcGFzcyBwYWdlT2Zmc2V0IHBhcmFtZXRlciAoMCBmb3IgZmlyc3QgcGFnZSlcbiAgICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBpbnZva2VCYWNrdXBJUEMoXG4gICAgICAgICAgICAnYmFja3Vwczpwcm92aWRlci1zbmFwc2hvdHMnLFxuICAgICAgICAgICAgREVGQVVMVF9JUENfVElNRU9VVCxcbiAgICAgICAgICAgIHNpdGVJZCxcbiAgICAgICAgICAgIG1hdGNoZWRQcm92aWRlci5pZCxcbiAgICAgICAgICAgIDBcbiAgICAgICAgICApO1xuICAgICAgICAgIGxvY2FsTG9nZ2VyLmluZm8oXG4gICAgICAgICAgICBgWyR7QURET05fTkFNRX1dIFByb3ZpZGVyIHNuYXBzaG90cyByYXcgcmVzdWx0OiAke0pTT04uc3RyaW5naWZ5KHJlc3VsdCl9YFxuICAgICAgICAgICk7XG5cbiAgICAgICAgICBpZiAocmVzdWx0LmVycm9yKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgc2l0ZU5hbWU6IHNpdGUubmFtZSxcbiAgICAgICAgICAgICAgcHJvdmlkZXIsXG4gICAgICAgICAgICAgIGJhY2t1cHM6IFtdLFxuICAgICAgICAgICAgICBjb3VudDogMCxcbiAgICAgICAgICAgICAgZXJyb3I6IHJlc3VsdC5lcnJvci5tZXNzYWdlIHx8ICdGYWlsZWQgdG8gbGlzdCBiYWNrdXBzJyxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gVW53cmFwIG5lc3RlZCByZXN1bHQgc3RydWN0dXJlIChzaW1pbGFyIHRvIHByb3ZpZGVycylcbiAgICAgICAgICBsZXQgYmFja3Vwc0RhdGEgPSByZXN1bHQucmVzdWx0O1xuICAgICAgICAgIGlmIChiYWNrdXBzRGF0YSAmJiB0eXBlb2YgYmFja3Vwc0RhdGEgPT09ICdvYmplY3QnICYmICFBcnJheS5pc0FycmF5KGJhY2t1cHNEYXRhKSkge1xuICAgICAgICAgICAgLy8gQ2hlY2sgZm9yIG5lc3RlZCByZXN1bHQgb3Igc25hcHNob3RzIGFycmF5XG4gICAgICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShiYWNrdXBzRGF0YS5yZXN1bHQpKSB7XG4gICAgICAgICAgICAgIGJhY2t1cHNEYXRhID0gYmFja3Vwc0RhdGEucmVzdWx0O1xuICAgICAgICAgICAgfSBlbHNlIGlmIChBcnJheS5pc0FycmF5KGJhY2t1cHNEYXRhLnNuYXBzaG90cykpIHtcbiAgICAgICAgICAgICAgYmFja3Vwc0RhdGEgPSBiYWNrdXBzRGF0YS5zbmFwc2hvdHM7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGJhY2t1cHNEYXRhLnJlc3VsdCAmJiBBcnJheS5pc0FycmF5KGJhY2t1cHNEYXRhLnJlc3VsdC5zbmFwc2hvdHMpKSB7XG4gICAgICAgICAgICAgIGJhY2t1cHNEYXRhID0gYmFja3Vwc0RhdGEucmVzdWx0LnNuYXBzaG90cztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjb25zdCBiYWNrdXBzID0gQXJyYXkuaXNBcnJheShiYWNrdXBzRGF0YSkgPyBiYWNrdXBzRGF0YSA6IFtdO1xuICAgICAgICAgIGxvY2FsTG9nZ2VyLmluZm8oYFske0FERE9OX05BTUV9XSBFeHRyYWN0ZWQgJHtiYWNrdXBzLmxlbmd0aH0gYmFja3Vwc2ApO1xuXG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgICBzaXRlTmFtZTogc2l0ZS5uYW1lLFxuICAgICAgICAgICAgcHJvdmlkZXIsXG4gICAgICAgICAgICBiYWNrdXBzOiBiYWNrdXBzLm1hcCgoYjogYW55KSA9PiAoe1xuICAgICAgICAgICAgICAvLyBVc2UgaGFzaCBmb3Igc25hcHNob3RJZCBhcyB0aGF0J3Mgd2hhdCByZXN0aWMgdXNlcyBmb3IgcmVzdG9yZS9kZWxldGUgb3BlcmF0aW9uc1xuICAgICAgICAgICAgICAvLyBUaGUgSHViIElEIChiLmlkKSBpcyBqdXN0IGEgZGF0YWJhc2UgaWRlbnRpZmllclxuICAgICAgICAgICAgICBzbmFwc2hvdElkOiBiLmhhc2ggfHwgYi5zbmFwc2hvdElkIHx8IGIuc2hvcnRfaWQsXG4gICAgICAgICAgICAgIHRpbWVzdGFtcDogYi51cGRhdGVkQXQgfHwgYi5jcmVhdGVkQXQgfHwgYi50aW1lc3RhbXAgfHwgYi50aW1lIHx8IGIuY3JlYXRlZCxcbiAgICAgICAgICAgICAgbm90ZTpcbiAgICAgICAgICAgICAgICBiLmNvbmZpZ09iamVjdD8uZGVzY3JpcHRpb24gfHwgYi5ub3RlIHx8IGIuZGVzY3JpcHRpb24gfHwgYi50YWdzPy5kZXNjcmlwdGlvbiB8fCAnJyxcbiAgICAgICAgICAgICAgc2l0ZURvbWFpbjogYi5jb25maWdPYmplY3Q/Lm5hbWVcbiAgICAgICAgICAgICAgICA/IGAke2IuY29uZmlnT2JqZWN0Lm5hbWV9LmxvY2FsYFxuICAgICAgICAgICAgICAgIDogYi5zaXRlRG9tYWluIHx8IHNpdGUuZG9tYWluLFxuICAgICAgICAgICAgICBzZXJ2aWNlczogSlNPTi5zdHJpbmdpZnkoYi5jb25maWdPYmplY3Q/LnNlcnZpY2VzIHx8IGIuc2VydmljZXMgfHwge30pLFxuICAgICAgICAgICAgfSkpLFxuICAgICAgICAgICAgY291bnQ6IGJhY2t1cHMubGVuZ3RoLFxuICAgICAgICAgICAgZXJyb3I6IG51bGwsXG4gICAgICAgICAgfTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgICAgICAgIGxvY2FsTG9nZ2VyLmVycm9yKGBbJHtBRERPTl9OQU1FfV0gRmFpbGVkIHRvIGxpc3QgYmFja3VwczpgLCBlcnJvcik7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgc2l0ZU5hbWU6IG51bGwsXG4gICAgICAgICAgICBwcm92aWRlcixcbiAgICAgICAgICAgIGJhY2t1cHM6IFtdLFxuICAgICAgICAgICAgY291bnQ6IDAsXG4gICAgICAgICAgICBlcnJvcjogZXJyb3IubWVzc2FnZSB8fCAnVW5rbm93biBlcnJvcicsXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgfSxcblxuICAgICAgLy8gUGhhc2UgMTFjOiBTeW5jIEhpc3RvcnlcbiAgICAgIGdldFN5bmNIaXN0b3J5OiBhc3luYyAoX3BhcmVudDogYW55LCBhcmdzOiB7IHNpdGVJZDogc3RyaW5nOyBsaW1pdD86IG51bWJlciB9KSA9PiB7XG4gICAgICAgIGNvbnN0IHsgc2l0ZUlkLCBsaW1pdCA9IDMwIH0gPSBhcmdzO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgbG9jYWxMb2dnZXIuaW5mbyhgWyR7QURET05fTkFNRX1dIEdldHRpbmcgc3luYyBoaXN0b3J5IGZvciBzaXRlICR7c2l0ZUlkfWApO1xuXG4gICAgICAgICAgLy8gR2V0IHNpdGUgdG8gdmVyaWZ5IGl0IGV4aXN0c1xuICAgICAgICAgIGNvbnN0IHNpdGUgPSBzaXRlRGF0YS5nZXRTaXRlKHNpdGVJZCk7XG4gICAgICAgICAgaWYgKCFzaXRlKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgc2l0ZU5hbWU6IG51bGwsXG4gICAgICAgICAgICAgIGV2ZW50czogW10sXG4gICAgICAgICAgICAgIGNvdW50OiAwLFxuICAgICAgICAgICAgICBlcnJvcjogYFNpdGUgbm90IGZvdW5kOiAke3NpdGVJZH1gLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBDaGVjayBpZiBjb25uZWN0SGlzdG9yeSBzZXJ2aWNlIGlzIGF2YWlsYWJsZVxuICAgICAgICAgIGlmICghY29ubmVjdEhpc3RvcnlTZXJ2aWNlIHx8IHR5cGVvZiBjb25uZWN0SGlzdG9yeVNlcnZpY2UuZ2V0RXZlbnRzICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgc2l0ZU5hbWU6IHNpdGUubmFtZSxcbiAgICAgICAgICAgICAgZXZlbnRzOiBbXSxcbiAgICAgICAgICAgICAgY291bnQ6IDAsXG4gICAgICAgICAgICAgIGVycm9yOiAnU3luYyBoaXN0b3J5IHNlcnZpY2Ugbm90IGF2YWlsYWJsZScsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGNvbnN0IGV2ZW50cyA9IGNvbm5lY3RIaXN0b3J5U2VydmljZS5nZXRFdmVudHMoc2l0ZUlkKTtcbiAgICAgICAgICBjb25zdCBsaW1pdGVkRXZlbnRzID0gZXZlbnRzLnNsaWNlKDAsIGxpbWl0KTtcblxuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICAgICAgc2l0ZU5hbWU6IHNpdGUubmFtZSxcbiAgICAgICAgICAgIGV2ZW50czogbGltaXRlZEV2ZW50cy5tYXAoKGU6IGFueSkgPT4gKHtcbiAgICAgICAgICAgICAgcmVtb3RlSW5zdGFsbE5hbWU6IGUucmVtb3RlSW5zdGFsbE5hbWUgfHwgbnVsbCxcbiAgICAgICAgICAgICAgdGltZXN0YW1wOiBlLnRpbWVzdGFtcCxcbiAgICAgICAgICAgICAgZW52aXJvbm1lbnQ6IGUuZW52aXJvbm1lbnQsXG4gICAgICAgICAgICAgIGRpcmVjdGlvbjogZS5kaXJlY3Rpb24sXG4gICAgICAgICAgICAgIHN0YXR1czogZS5zdGF0dXMgfHwgbnVsbCxcbiAgICAgICAgICAgIH0pKSxcbiAgICAgICAgICAgIGNvdW50OiBsaW1pdGVkRXZlbnRzLmxlbmd0aCxcbiAgICAgICAgICAgIGVycm9yOiBudWxsLFxuICAgICAgICAgIH07XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yOiBhbnkpIHtcbiAgICAgICAgICBsb2NhbExvZ2dlci5lcnJvcihgWyR7QURET05fTkFNRX1dIEZhaWxlZCB0byBnZXQgc3luYyBoaXN0b3J5OmAsIGVycm9yKTtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICBzaXRlTmFtZTogbnVsbCxcbiAgICAgICAgICAgIGV2ZW50czogW10sXG4gICAgICAgICAgICBjb3VudDogMCxcbiAgICAgICAgICAgIGVycm9yOiBlcnJvci5tZXNzYWdlIHx8ICdVbmtub3duIGVycm9yJyxcbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICB9LFxuXG4gICAgICAvLyBHZXQgZmlsZSBjaGFuZ2VzIGJldHdlZW4gbG9jYWwgYW5kIFdQRSAoZHJ5LXJ1biBjb21wYXJpc29uKVxuICAgICAgZ2V0U2l0ZUNoYW5nZXM6IGFzeW5jIChfcGFyZW50OiBhbnksIGFyZ3M6IHsgc2l0ZUlkOiBzdHJpbmc7IGRpcmVjdGlvbj86IHN0cmluZyB9KSA9PiB7XG4gICAgICAgIGNvbnN0IHsgc2l0ZUlkLCBkaXJlY3Rpb24gPSAncHVzaCcgfSA9IGFyZ3M7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBsb2NhbExvZ2dlci5pbmZvKFxuICAgICAgICAgICAgYFske0FERE9OX05BTUV9XSBHZXR0aW5nIHNpdGUgY2hhbmdlcyBmb3IgJHtzaXRlSWR9LCBkaXJlY3Rpb249JHtkaXJlY3Rpb259YFxuICAgICAgICAgICk7XG5cbiAgICAgICAgICAvLyBWYWxpZGF0ZSBkaXJlY3Rpb25cbiAgICAgICAgICBpZiAoZGlyZWN0aW9uICE9PSAncHVzaCcgJiYgZGlyZWN0aW9uICE9PSAncHVsbCcpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICBzaXRlTmFtZTogbnVsbCxcbiAgICAgICAgICAgICAgZGlyZWN0aW9uLFxuICAgICAgICAgICAgICBhZGRlZDogW10sXG4gICAgICAgICAgICAgIG1vZGlmaWVkOiBbXSxcbiAgICAgICAgICAgICAgZGVsZXRlZDogW10sXG4gICAgICAgICAgICAgIHRvdGFsQ2hhbmdlczogMCxcbiAgICAgICAgICAgICAgbWVzc2FnZTogbnVsbCxcbiAgICAgICAgICAgICAgZXJyb3I6ICdJbnZhbGlkIGRpcmVjdGlvbi4gTXVzdCBiZSBcInB1c2hcIiBvciBcInB1bGxcIi4nLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBHZXQgc2l0ZVxuICAgICAgICAgIGNvbnN0IHNpdGUgPSBzaXRlRGF0YS5nZXRTaXRlKHNpdGVJZCk7XG4gICAgICAgICAgaWYgKCFzaXRlKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgc2l0ZU5hbWU6IG51bGwsXG4gICAgICAgICAgICAgIGRpcmVjdGlvbixcbiAgICAgICAgICAgICAgYWRkZWQ6IFtdLFxuICAgICAgICAgICAgICBtb2RpZmllZDogW10sXG4gICAgICAgICAgICAgIGRlbGV0ZWQ6IFtdLFxuICAgICAgICAgICAgICB0b3RhbENoYW5nZXM6IDAsXG4gICAgICAgICAgICAgIG1lc3NhZ2U6IG51bGwsXG4gICAgICAgICAgICAgIGVycm9yOiBgU2l0ZSBub3QgZm91bmQ6ICR7c2l0ZUlkfWAsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIENoZWNrIFdQRSBjb25uZWN0aW9uXG4gICAgICAgICAgY29uc3Qgd3BlQ29ubmVjdGlvbiA9IHNpdGUuaG9zdENvbm5lY3Rpb25zPy5maW5kKChjOiBhbnkpID0+IGMuaG9zdElkID09PSAnd3BlJyk7XG4gICAgICAgICAgaWYgKCF3cGVDb25uZWN0aW9uKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgc2l0ZU5hbWU6IHNpdGUubmFtZSxcbiAgICAgICAgICAgICAgZGlyZWN0aW9uLFxuICAgICAgICAgICAgICBhZGRlZDogW10sXG4gICAgICAgICAgICAgIG1vZGlmaWVkOiBbXSxcbiAgICAgICAgICAgICAgZGVsZXRlZDogW10sXG4gICAgICAgICAgICAgIHRvdGFsQ2hhbmdlczogMCxcbiAgICAgICAgICAgICAgbWVzc2FnZTogbnVsbCxcbiAgICAgICAgICAgICAgZXJyb3I6XG4gICAgICAgICAgICAgICAgJ1NpdGUgaXMgbm90IGxpbmtlZCB0byBXUCBFbmdpbmUuIFVzZSBDb25uZWN0IGluIExvY2FsIHRvIGxpbmsgdGhlIHNpdGUgZmlyc3QuJyxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gQ2hlY2sgc2VydmljZSBhdmFpbGFiaWxpdHlcbiAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAhd3BlQ29ubmVjdEJhc2VTZXJ2aWNlIHx8XG4gICAgICAgICAgICB0eXBlb2Ygd3BlQ29ubmVjdEJhc2VTZXJ2aWNlLmxpc3RNb2RpZmljYXRpb25zICE9PSAnZnVuY3Rpb24nXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgc2l0ZU5hbWU6IHNpdGUubmFtZSxcbiAgICAgICAgICAgICAgZGlyZWN0aW9uLFxuICAgICAgICAgICAgICBhZGRlZDogW10sXG4gICAgICAgICAgICAgIG1vZGlmaWVkOiBbXSxcbiAgICAgICAgICAgICAgZGVsZXRlZDogW10sXG4gICAgICAgICAgICAgIHRvdGFsQ2hhbmdlczogMCxcbiAgICAgICAgICAgICAgbWVzc2FnZTogbnVsbCxcbiAgICAgICAgICAgICAgZXJyb3I6ICdXUEUgQ29ubmVjdCBzZXJ2aWNlIG5vdCBhdmFpbGFibGUnLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBHZXQgaW5zdGFsbCBkZXRhaWxzIGZyb20gQ0FQSVxuICAgICAgICAgIGxldCBpbnN0YWxsTmFtZSA9IHdwZUNvbm5lY3Rpb24ucmVtb3RlU2l0ZUlkO1xuICAgICAgICAgIGxldCBwcmltYXJ5RG9tYWluID0gJyc7XG4gICAgICAgICAgbGV0IGluc3RhbGxJZCA9ICcnO1xuXG4gICAgICAgICAgaWYgKGNhcGlTZXJ2aWNlICYmIHR5cGVvZiBjYXBpU2VydmljZS5nZXRJbnN0YWxsTGlzdCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgY29uc3QgaW5zdGFsbHMgPSBhd2FpdCBjYXBpU2VydmljZS5nZXRJbnN0YWxsTGlzdCgpO1xuICAgICAgICAgICAgY29uc3QgbWF0Y2hpbmdJbnN0YWxsID0gaW5zdGFsbHM/LmZpbmQoXG4gICAgICAgICAgICAgIChpOiBhbnkpID0+XG4gICAgICAgICAgICAgICAgaS5zaXRlPy5pZCA9PT0gd3BlQ29ubmVjdGlvbi5yZW1vdGVTaXRlSWQgJiZcbiAgICAgICAgICAgICAgICAoIXdwZUNvbm5lY3Rpb24ucmVtb3RlU2l0ZUVudiB8fCBpLmVudmlyb25tZW50ID09PSB3cGVDb25uZWN0aW9uLnJlbW90ZVNpdGVFbnYpXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgaWYgKG1hdGNoaW5nSW5zdGFsbCkge1xuICAgICAgICAgICAgICBpbnN0YWxsTmFtZSA9IG1hdGNoaW5nSW5zdGFsbC5uYW1lO1xuICAgICAgICAgICAgICBwcmltYXJ5RG9tYWluID1cbiAgICAgICAgICAgICAgICBtYXRjaGluZ0luc3RhbGwucHJpbWFyeV9kb21haW4gfHxcbiAgICAgICAgICAgICAgICBtYXRjaGluZ0luc3RhbGwuY25hbWUgfHxcbiAgICAgICAgICAgICAgICBgJHttYXRjaGluZ0luc3RhbGwubmFtZX0ud3BlbmdpbmUuY29tYDtcbiAgICAgICAgICAgICAgaW5zdGFsbElkID0gbWF0Y2hpbmdJbnN0YWxsLmlkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmICghcHJpbWFyeURvbWFpbikge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICAgIHNpdGVOYW1lOiBzaXRlLm5hbWUsXG4gICAgICAgICAgICAgIGRpcmVjdGlvbixcbiAgICAgICAgICAgICAgYWRkZWQ6IFtdLFxuICAgICAgICAgICAgICBtb2RpZmllZDogW10sXG4gICAgICAgICAgICAgIGRlbGV0ZWQ6IFtdLFxuICAgICAgICAgICAgICB0b3RhbENoYW5nZXM6IDAsXG4gICAgICAgICAgICAgIG1lc3NhZ2U6IG51bGwsXG4gICAgICAgICAgICAgIGVycm9yOlxuICAgICAgICAgICAgICAgICdDb3VsZCBub3QgZGV0ZXJtaW5lIFdQIEVuZ2luZSBpbnN0YWxsIGRldGFpbHMuIFBsZWFzZSBlbnN1cmUgeW91IGFyZSBhdXRoZW50aWNhdGVkLicsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIENhbGwgbGlzdE1vZGlmaWNhdGlvbnMgKGRyeS1ydW4gcnN5bmMgY29tcGFyaXNvbilcbiAgICAgICAgICBsb2NhbExvZ2dlci5pbmZvKGBbJHtBRERPTl9OQU1FfV0gQ2FsbGluZyBsaXN0TW9kaWZpY2F0aW9ucyBmb3IgJHtpbnN0YWxsTmFtZX1gKTtcbiAgICAgICAgICBjb25zdCBtb2RpZmljYXRpb25zID0gYXdhaXQgd3BlQ29ubmVjdEJhc2VTZXJ2aWNlLmxpc3RNb2RpZmljYXRpb25zKHtcbiAgICAgICAgICAgIGNvbm5lY3RBcmdzOiB7XG4gICAgICAgICAgICAgIHdwZW5naW5lSW5zdGFsbE5hbWU6IGluc3RhbGxOYW1lLFxuICAgICAgICAgICAgICB3cGVuZ2luZUluc3RhbGxJZDogaW5zdGFsbElkLFxuICAgICAgICAgICAgICB3cGVuZ2luZVNpdGVJZDogd3BlQ29ubmVjdGlvbi5yZW1vdGVTaXRlSWQsXG4gICAgICAgICAgICAgIHdwZW5naW5lUHJpbWFyeURvbWFpbjogcHJpbWFyeURvbWFpbixcbiAgICAgICAgICAgICAgbG9jYWxTaXRlSWQ6IHNpdGUuaWQsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgZGlyZWN0aW9uOiBkaXJlY3Rpb24gYXMgJ3B1c2gnIHwgJ3B1bGwnLFxuICAgICAgICAgICAgaW5jbHVkZUlnbm9yZWQ6IGZhbHNlLFxuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgLy8gQ2F0ZWdvcml6ZSBjaGFuZ2VzXG4gICAgICAgICAgY29uc3QgYWRkZWQgPSBtb2RpZmljYXRpb25zXG4gICAgICAgICAgICAuZmlsdGVyKFxuICAgICAgICAgICAgICAoZjogYW55KSA9PlxuICAgICAgICAgICAgICAgIGYuaW5zdHJ1Y3Rpb24gPT09ICdjcmVhdGUnIHx8XG4gICAgICAgICAgICAgICAgZi5pbnN0cnVjdGlvbiA9PT0gJ3VwbG9hZCcgfHxcbiAgICAgICAgICAgICAgICBmLmluc3RydWN0aW9uID09PSAnZG93bmxvYWQnXG4gICAgICAgICAgICApXG4gICAgICAgICAgICAubWFwKChmOiBhbnkpID0+ICh7XG4gICAgICAgICAgICAgIHBhdGg6IGYucGF0aCxcbiAgICAgICAgICAgICAgaW5zdHJ1Y3Rpb246IGYuaW5zdHJ1Y3Rpb24sXG4gICAgICAgICAgICAgIHNpemU6IGYuc2l6ZSxcbiAgICAgICAgICAgICAgdHlwZTogZi50eXBlLFxuICAgICAgICAgICAgfSkpO1xuXG4gICAgICAgICAgY29uc3QgbW9kaWZpZWQgPSBtb2RpZmljYXRpb25zXG4gICAgICAgICAgICAuZmlsdGVyKChmOiBhbnkpID0+IGYuaW5zdHJ1Y3Rpb24gPT09ICdtb2RpZnknKVxuICAgICAgICAgICAgLm1hcCgoZjogYW55KSA9PiAoe1xuICAgICAgICAgICAgICBwYXRoOiBmLnBhdGgsXG4gICAgICAgICAgICAgIGluc3RydWN0aW9uOiBmLmluc3RydWN0aW9uLFxuICAgICAgICAgICAgICBzaXplOiBmLnNpemUsXG4gICAgICAgICAgICAgIHR5cGU6IGYudHlwZSxcbiAgICAgICAgICAgIH0pKTtcblxuICAgICAgICAgIGNvbnN0IGRlbGV0ZWQgPSBtb2RpZmljYXRpb25zXG4gICAgICAgICAgICAuZmlsdGVyKChmOiBhbnkpID0+IGYuaW5zdHJ1Y3Rpb24gPT09ICdkZWxldGUnKVxuICAgICAgICAgICAgLm1hcCgoZjogYW55KSA9PiAoe1xuICAgICAgICAgICAgICBwYXRoOiBmLnBhdGgsXG4gICAgICAgICAgICAgIGluc3RydWN0aW9uOiBmLmluc3RydWN0aW9uLFxuICAgICAgICAgICAgICBzaXplOiBmLnNpemUsXG4gICAgICAgICAgICAgIHR5cGU6IGYudHlwZSxcbiAgICAgICAgICAgIH0pKTtcblxuICAgICAgICAgIGNvbnN0IHRvdGFsQ2hhbmdlcyA9IGFkZGVkLmxlbmd0aCArIG1vZGlmaWVkLmxlbmd0aCArIGRlbGV0ZWQubGVuZ3RoO1xuICAgICAgICAgIGNvbnN0IGRpcmVjdGlvbkxhYmVsID0gZGlyZWN0aW9uID09PSAncHVzaCcgPyAnbG9jYWwg4oaSIFdQRScgOiAnV1BFIOKGkiBsb2NhbCc7XG5cbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgICAgICAgIHNpdGVOYW1lOiBzaXRlLm5hbWUsXG4gICAgICAgICAgICBkaXJlY3Rpb24sXG4gICAgICAgICAgICBhZGRlZCxcbiAgICAgICAgICAgIG1vZGlmaWVkLFxuICAgICAgICAgICAgZGVsZXRlZCxcbiAgICAgICAgICAgIHRvdGFsQ2hhbmdlcyxcbiAgICAgICAgICAgIG1lc3NhZ2U6XG4gICAgICAgICAgICAgIHRvdGFsQ2hhbmdlcyA+IDBcbiAgICAgICAgICAgICAgICA/IGAke3RvdGFsQ2hhbmdlc30gZmlsZShzKSBjaGFuZ2VkICgke2RpcmVjdGlvbkxhYmVsfSk6ICR7YWRkZWQubGVuZ3RofSBhZGRlZCwgJHttb2RpZmllZC5sZW5ndGh9IG1vZGlmaWVkLCAke2RlbGV0ZWQubGVuZ3RofSBkZWxldGVkYFxuICAgICAgICAgICAgICAgIDogYE5vIGNoYW5nZXMgZGV0ZWN0ZWQgKCR7ZGlyZWN0aW9uTGFiZWx9KWAsXG4gICAgICAgICAgICBlcnJvcjogbnVsbCxcbiAgICAgICAgICB9O1xuICAgICAgICB9IGNhdGNoIChlcnJvcjogYW55KSB7XG4gICAgICAgICAgbG9jYWxMb2dnZXIuZXJyb3IoYFske0FERE9OX05BTUV9XSBGYWlsZWQgdG8gZ2V0IHNpdGUgY2hhbmdlczpgLCBlcnJvcik7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgc2l0ZU5hbWU6IG51bGwsXG4gICAgICAgICAgICBkaXJlY3Rpb24sXG4gICAgICAgICAgICBhZGRlZDogW10sXG4gICAgICAgICAgICBtb2RpZmllZDogW10sXG4gICAgICAgICAgICBkZWxldGVkOiBbXSxcbiAgICAgICAgICAgIHRvdGFsQ2hhbmdlczogMCxcbiAgICAgICAgICAgIG1lc3NhZ2U6IG51bGwsXG4gICAgICAgICAgICBlcnJvcjogZXJyb3IubWVzc2FnZSB8fCAnVW5rbm93biBlcnJvcicsXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICB9LFxuICAgIE11dGF0aW9uOiB7XG4gICAgICB3cENsaTogZXhlY3V0ZVdwQ2xpLFxuXG4gICAgICBjcmVhdGVTaXRlOiBhc3luYyAoXG4gICAgICAgIF9wYXJlbnQ6IGFueSxcbiAgICAgICAgYXJnczoge1xuICAgICAgICAgIGlucHV0OiB7XG4gICAgICAgICAgICBuYW1lOiBzdHJpbmc7XG4gICAgICAgICAgICBwaHBWZXJzaW9uPzogc3RyaW5nO1xuICAgICAgICAgICAgd2ViU2VydmVyPzogc3RyaW5nO1xuICAgICAgICAgICAgZGF0YWJhc2U/OiBzdHJpbmc7XG4gICAgICAgICAgICB3cEFkbWluVXNlcm5hbWU/OiBzdHJpbmc7XG4gICAgICAgICAgICB3cEFkbWluUGFzc3dvcmQ/OiBzdHJpbmc7XG4gICAgICAgICAgICB3cEFkbWluRW1haWw/OiBzdHJpbmc7XG4gICAgICAgICAgICBibHVlcHJpbnQ/OiBzdHJpbmc7XG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgKSA9PiB7XG4gICAgICAgIC8vIERFQlVHOiBMb2cgcmF3IGFyZ3MgcmVjZWl2ZWRcbiAgICAgICAgbG9jYWxMb2dnZXIuaW5mbyhgWyR7QURET05fTkFNRX1dIGNyZWF0ZVNpdGUgY2FsbGVkIHdpdGggYXJnczogJHtKU09OLnN0cmluZ2lmeShhcmdzKX1gKTtcblxuICAgICAgICBjb25zdCB7XG4gICAgICAgICAgbmFtZSxcbiAgICAgICAgICBwaHBWZXJzaW9uLFxuICAgICAgICAgIHdlYlNlcnZlciA9ICduZ2lueCcsXG4gICAgICAgICAgZGF0YWJhc2UgPSAnbXlzcWwnLFxuICAgICAgICAgIHdwQWRtaW5Vc2VybmFtZSA9ICdhZG1pbicsXG4gICAgICAgICAgd3BBZG1pblBhc3N3b3JkID0gJ3Bhc3N3b3JkJyxcbiAgICAgICAgICB3cEFkbWluRW1haWwgPSAnYWRtaW5AbG9jYWwudGVzdCcsXG4gICAgICAgICAgYmx1ZXByaW50LFxuICAgICAgICB9ID0gYXJncy5pbnB1dDtcblxuICAgICAgICAvLyBERUJVRzogTG9nIGRlc3RydWN0dXJlZCB2YWx1ZXNcbiAgICAgICAgbG9jYWxMb2dnZXIuaW5mbyhcbiAgICAgICAgICBgWyR7QURET05fTkFNRX1dIERlc3RydWN0dXJlZCAtIG5hbWU6ICR7bmFtZX0sIGJsdWVwcmludDogJHtibHVlcHJpbnR9LCB0eXBlb2YgYmx1ZXByaW50OiAke3R5cGVvZiBibHVlcHJpbnR9YFxuICAgICAgICApO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgbG9jYWxMb2dnZXIuaW5mbyhcbiAgICAgICAgICAgIGBbJHtBRERPTl9OQU1FfV0gQ3JlYXRpbmcgc2l0ZTogJHtuYW1lfSR7Ymx1ZXByaW50ID8gYCBmcm9tIGJsdWVwcmludDogJHtibHVlcHJpbnR9YCA6ICcnfWBcbiAgICAgICAgICApO1xuXG4gICAgICAgICAgLy8gR2VuZXJhdGUgc2x1ZyBhbmQgZG9tYWluIGZyb20gbmFtZVxuICAgICAgICAgIGNvbnN0IHNpdGVTbHVnID0gbmFtZVxuICAgICAgICAgICAgLnRvTG93ZXJDYXNlKClcbiAgICAgICAgICAgIC5yZXBsYWNlKC9bXmEtejAtOV0rL2csICctJylcbiAgICAgICAgICAgIC5yZXBsYWNlKC9eLXwtJC9nLCAnJyk7XG4gICAgICAgICAgY29uc3Qgc2l0ZURvbWFpbiA9IGAke3NpdGVTbHVnfS5sb2NhbGA7XG5cbiAgICAgICAgICBjb25zdCBvcyA9IHJlcXVpcmUoJ29zJyk7XG4gICAgICAgICAgY29uc3QgcGF0aCA9IHJlcXVpcmUoJ3BhdGgnKTtcbiAgICAgICAgICBjb25zdCBmcyA9IHJlcXVpcmUoJ2ZzJyk7XG4gICAgICAgICAgY29uc3Qgc2l0ZVBhdGggPSBwYXRoLmpvaW4ob3MuaG9tZWRpcigpLCAnTG9jYWwgU2l0ZXMnLCBzaXRlU2x1Zyk7XG5cbiAgICAgICAgICAvLyBJZiBibHVlcHJpbnQgaXMgcHJvdmlkZWQsIHVzZSBpbXBvcnRTaXRlU2VydmljZSBpbnN0ZWFkIG9mIGFkZFNpdGVTZXJ2aWNlXG4gICAgICAgICAgaWYgKGJsdWVwcmludCkge1xuICAgICAgICAgICAgbG9jYWxMb2dnZXIuaW5mbyhgWyR7QURET05fTkFNRX1dIEJsdWVwcmludCBwYXJhbWV0ZXIgcmVjZWl2ZWQ6ICR7Ymx1ZXByaW50fWApO1xuXG4gICAgICAgICAgICAvLyBHZXQgdGhlIHVzZXJEYXRhUGF0aCBmcm9tIGVsZWN0cm9uIGFwcFxuICAgICAgICAgICAgY29uc3QgeyBhcHAgfSA9IHJlcXVpcmUoJ2VsZWN0cm9uJyk7XG4gICAgICAgICAgICBjb25zdCB1c2VyRGF0YVBhdGggPSBhcHAuZ2V0UGF0aCgndXNlckRhdGEnKTtcbiAgICAgICAgICAgIGNvbnN0IGJsdWVwcmludFppcFBhdGggPSBwYXRoLmpvaW4odXNlckRhdGFQYXRoLCAnYmx1ZXByaW50cycsIGAke2JsdWVwcmludH0uemlwYCk7XG5cbiAgICAgICAgICAgIGxvY2FsTG9nZ2VyLmluZm8oYFske0FERE9OX05BTUV9XSBMb29raW5nIGZvciBibHVlcHJpbnQgYXQ6ICR7Ymx1ZXByaW50WmlwUGF0aH1gKTtcblxuICAgICAgICAgICAgLy8gVmVyaWZ5IGJsdWVwcmludCBleGlzdHNcbiAgICAgICAgICAgIGlmICghZnMuZXhpc3RzU3luYyhibHVlcHJpbnRaaXBQYXRoKSkge1xuICAgICAgICAgICAgICBsb2NhbExvZ2dlci5lcnJvcihgWyR7QURET05fTkFNRX1dIEJsdWVwcmludCBub3QgZm91bmQgYXQ6ICR7Ymx1ZXByaW50WmlwUGF0aH1gKTtcbiAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgICBlcnJvcjogYEJsdWVwcmludCBub3QgZm91bmQ6ICR7Ymx1ZXByaW50fS4gVXNlIGxpc3RfYmx1ZXByaW50cyB0byBzZWUgYXZhaWxhYmxlIGJsdWVwcmludHMuYCxcbiAgICAgICAgICAgICAgICBzaXRlSWQ6IG51bGwsXG4gICAgICAgICAgICAgICAgc2l0ZU5hbWU6IG5hbWUsXG4gICAgICAgICAgICAgICAgc2l0ZURvbWFpbjogbnVsbCxcbiAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgbG9jYWxMb2dnZXIuaW5mbyhgWyR7QURET05fTkFNRX1dIEZvdW5kIGJsdWVwcmludCBhdDogJHtibHVlcHJpbnRaaXBQYXRofWApO1xuXG4gICAgICAgICAgICAvLyBSZWFkIHRoZSBsb2NhbC1zaXRlLmpzb24gZnJvbSB0aGUgYmx1ZXByaW50IHppcCB0byBnZXQgbWFuaWZlc3RcbiAgICAgICAgICAgIGxldCBsb2NhbFNpdGVKU09OOiBhbnk7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICBjb25zdCBTdHJlYW1aaXAgPSByZXF1aXJlKCdub2RlLXN0cmVhbS16aXAnKTtcbiAgICAgICAgICAgICAgbG9jYWxMb2dnZXIuaW5mbyhgWyR7QURET05fTkFNRX1dIG5vZGUtc3RyZWFtLXppcCBsb2FkZWQgc3VjY2Vzc2Z1bGx5YCk7XG5cbiAgICAgICAgICAgICAgY29uc3QgemlwID0gbmV3IFN0cmVhbVppcC5hc3luYyh7IGZpbGU6IGJsdWVwcmludFppcFBhdGggfSk7XG4gICAgICAgICAgICAgIGNvbnN0IGVudHJpZXMgPSBhd2FpdCB6aXAuZW50cmllcygpO1xuICAgICAgICAgICAgICBsb2NhbExvZ2dlci5pbmZvKFxuICAgICAgICAgICAgICAgIGBbJHtBRERPTl9OQU1FfV0gWmlwIGVudHJpZXMgbG9hZGVkLCBjb3VudDogJHtPYmplY3Qua2V5cyhlbnRyaWVzKS5sZW5ndGh9YFxuICAgICAgICAgICAgICApO1xuXG4gICAgICAgICAgICAgIGNvbnN0IGZpbGVuYW1lID0gZW50cmllc1snbG9jYWwtc2l0ZS5qc29uJ11cbiAgICAgICAgICAgICAgICA/ICdsb2NhbC1zaXRlLmpzb24nXG4gICAgICAgICAgICAgICAgOiAncHJlc3NtYXRpYy1zaXRlLmpzb24nO1xuICAgICAgICAgICAgICBsb2NhbExvZ2dlci5pbmZvKGBbJHtBRERPTl9OQU1FfV0gUmVhZGluZyBtYW5pZmVzdCBmaWxlOiAke2ZpbGVuYW1lfWApO1xuXG4gICAgICAgICAgICAgIGNvbnN0IGRhdGEgPSBhd2FpdCB6aXAuZW50cnlEYXRhKGZpbGVuYW1lKTtcbiAgICAgICAgICAgICAgbG9jYWxTaXRlSlNPTiA9IEpTT04ucGFyc2UoZGF0YS50b1N0cmluZygndXRmOCcpKTtcbiAgICAgICAgICAgICAgYXdhaXQgemlwLmNsb3NlKCk7XG4gICAgICAgICAgICAgIGxvY2FsTG9nZ2VyLmluZm8oXG4gICAgICAgICAgICAgICAgYFske0FERE9OX05BTUV9XSBTdWNjZXNzZnVsbHkgcmVhZCBtYW5pZmVzdDpgLFxuICAgICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KGxvY2FsU2l0ZUpTT04pLnN1YnN0cmluZygwLCAyMDApXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9IGNhdGNoICh6aXBFcnJvcjogYW55KSB7XG4gICAgICAgICAgICAgIGxvY2FsTG9nZ2VyLmVycm9yKFxuICAgICAgICAgICAgICAgIGBbJHtBRERPTl9OQU1FfV0gRmFpbGVkIHRvIHJlYWQgYmx1ZXByaW50IHppcDogJHt6aXBFcnJvci5tZXNzYWdlfWAsXG4gICAgICAgICAgICAgICAgemlwRXJyb3JcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgICBlcnJvcjogYEZhaWxlZCB0byByZWFkIGJsdWVwcmludCBtYW5pZmVzdDogJHt6aXBFcnJvci5tZXNzYWdlfWAsXG4gICAgICAgICAgICAgICAgc2l0ZUlkOiBudWxsLFxuICAgICAgICAgICAgICAgIHNpdGVOYW1lOiBuYW1lLFxuICAgICAgICAgICAgICAgIHNpdGVEb21haW46IG51bGwsXG4gICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIEJ1aWxkIGltcG9ydCBzZXR0aW5nc1xuICAgICAgICAgICAgY29uc3QgaW1wb3J0U2V0dGluZ3M6IGFueSA9IHtcbiAgICAgICAgICAgICAgc2l0ZU5hbWU6IG5hbWUsXG4gICAgICAgICAgICAgIHNpdGVEb21haW46IHNpdGVEb21haW4sXG4gICAgICAgICAgICAgIHNpdGVQYXRoOiBzaXRlUGF0aCxcbiAgICAgICAgICAgICAgemlwOiBibHVlcHJpbnRaaXBQYXRoLFxuICAgICAgICAgICAgICBpbXBvcnREYXRhOiB7XG4gICAgICAgICAgICAgICAgdHlwZTogJ2xvY2FsLWJsdWVwcmludCcsXG4gICAgICAgICAgICAgICAgb2xkU2l0ZTogbG9jYWxTaXRlSlNPTixcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgZW52aXJvbm1lbnQ6IGxvY2FsU2l0ZUpTT04uZW52aXJvbm1lbnQgfHwgJ2ZseXdoZWVsJyxcbiAgICAgICAgICAgICAgYmx1ZXByaW50OiBibHVlcHJpbnQsXG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICAvLyBDb3B5IHNlcnZpY2UgdmVyc2lvbnMgZnJvbSBibHVlcHJpbnQgaWYgYXZhaWxhYmxlXG4gICAgICAgICAgICBpZiAobG9jYWxTaXRlSlNPTi5zZXJ2aWNlcykge1xuICAgICAgICAgICAgICAvLyBFeHRyYWN0IFBIUCB2ZXJzaW9uXG4gICAgICAgICAgICAgIGNvbnN0IHBocFNlcnZpY2UgPSBPYmplY3QudmFsdWVzKGxvY2FsU2l0ZUpTT04uc2VydmljZXMpLmZpbmQoXG4gICAgICAgICAgICAgICAgKHM6IGFueSkgPT4gcy5yb2xlID09PSAncGhwJ1xuICAgICAgICAgICAgICApIGFzIGFueTtcbiAgICAgICAgICAgICAgaWYgKHBocFNlcnZpY2UpIHtcbiAgICAgICAgICAgICAgICBpbXBvcnRTZXR0aW5ncy5waHBWZXJzaW9uID0gcGhwU2VydmljZS52ZXJzaW9uO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgLy8gRXh0cmFjdCBkYXRhYmFzZVxuICAgICAgICAgICAgICBjb25zdCBkYlNlcnZpY2UgPSBPYmplY3QudmFsdWVzKGxvY2FsU2l0ZUpTT04uc2VydmljZXMpLmZpbmQoXG4gICAgICAgICAgICAgICAgKHM6IGFueSkgPT4gcy5yb2xlID09PSAnZGF0YWJhc2UnIHx8IHMucm9sZSA9PT0gJ2RiJ1xuICAgICAgICAgICAgICApIGFzIGFueTtcbiAgICAgICAgICAgICAgaWYgKGRiU2VydmljZSkge1xuICAgICAgICAgICAgICAgIGltcG9ydFNldHRpbmdzLmRhdGFiYXNlID0gYCR7ZGJTZXJ2aWNlLm5hbWV9LSR7ZGJTZXJ2aWNlLnZlcnNpb259YDtcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIC8vIEV4dHJhY3Qgd2ViIHNlcnZlclxuICAgICAgICAgICAgICBjb25zdCB3ZWJTZXJ2aWNlID0gT2JqZWN0LnZhbHVlcyhsb2NhbFNpdGVKU09OLnNlcnZpY2VzKS5maW5kKFxuICAgICAgICAgICAgICAgIChzOiBhbnkpID0+IHMucm9sZSA9PT0gJ2h0dHAnIHx8IHMucm9sZSA9PT0gJ3dlYidcbiAgICAgICAgICAgICAgKSBhcyBhbnk7XG4gICAgICAgICAgICAgIGlmICh3ZWJTZXJ2aWNlKSB7XG4gICAgICAgICAgICAgICAgaW1wb3J0U2V0dGluZ3Mud2ViU2VydmVyID0gYCR7d2ViU2VydmljZS5uYW1lfS0ke3dlYlNlcnZpY2UudmVyc2lvbn1gO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGxvY2FsU2l0ZUpTT04ucGhwVmVyc2lvbikge1xuICAgICAgICAgICAgICBpbXBvcnRTZXR0aW5ncy5waHBWZXJzaW9uID0gbG9jYWxTaXRlSlNPTi5waHBWZXJzaW9uO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBsb2NhbExvZ2dlci5pbmZvKFxuICAgICAgICAgICAgICBgWyR7QURET05fTkFNRX1dIEltcG9ydCBzZXR0aW5ncyBwcmVwYXJlZDpgLFxuICAgICAgICAgICAgICBKU09OLnN0cmluZ2lmeShpbXBvcnRTZXR0aW5ncykuc3Vic3RyaW5nKDAsIDUwMClcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIGlmICghaW1wb3J0U2l0ZVNlcnZpY2UpIHtcbiAgICAgICAgICAgICAgbG9jYWxMb2dnZXIuZXJyb3IoYFske0FERE9OX05BTUV9XSBpbXBvcnRTaXRlU2VydmljZSBpcyBub3QgYXZhaWxhYmxlIWApO1xuICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICAgIGVycm9yOiAnSW1wb3J0IHNlcnZpY2Ugbm90IGF2YWlsYWJsZScsXG4gICAgICAgICAgICAgICAgc2l0ZUlkOiBudWxsLFxuICAgICAgICAgICAgICAgIHNpdGVOYW1lOiBuYW1lLFxuICAgICAgICAgICAgICAgIHNpdGVEb21haW46IG51bGwsXG4gICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGxvY2FsTG9nZ2VyLmluZm8oYFske0FERE9OX05BTUV9XSBDYWxsaW5nIGltcG9ydFNpdGVTZXJ2aWNlLnJ1bigpLi4uYCk7XG5cbiAgICAgICAgICAgIC8vIFVzZSB0aGUgaW1wb3J0U2l0ZVNlcnZpY2UgdG8gY3JlYXRlIGZyb20gYmx1ZXByaW50XG4gICAgICAgICAgICBjb25zdCBpbXBvcnRSZXN1bHQgPSBhd2FpdCBpbXBvcnRTaXRlU2VydmljZS5ydW4oaW1wb3J0U2V0dGluZ3MpO1xuXG4gICAgICAgICAgICBsb2NhbExvZ2dlci5pbmZvKFxuICAgICAgICAgICAgICBgWyR7QURET05fTkFNRX1dIEltcG9ydCByZXN1bHQ6YCxcbiAgICAgICAgICAgICAgSlNPTi5zdHJpbmdpZnkoaW1wb3J0UmVzdWx0IHx8ICdudWxsJykuc3Vic3RyaW5nKDAsIDUwMClcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIGlmIChpbXBvcnRSZXN1bHQgJiYgaW1wb3J0UmVzdWx0LmlkKSB7XG4gICAgICAgICAgICAgIGxvY2FsTG9nZ2VyLmluZm8oXG4gICAgICAgICAgICAgICAgYFske0FERE9OX05BTUV9XSBTdWNjZXNzZnVsbHkgY3JlYXRlZCBzaXRlIGZyb20gYmx1ZXByaW50OiAke25hbWV9ICgke2ltcG9ydFJlc3VsdC5pZH0pYFxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgICAgICAgZXJyb3I6IG51bGwsXG4gICAgICAgICAgICAgICAgc2l0ZUlkOiBpbXBvcnRSZXN1bHQuaWQsXG4gICAgICAgICAgICAgICAgc2l0ZU5hbWU6IG5hbWUsXG4gICAgICAgICAgICAgICAgc2l0ZURvbWFpbjogc2l0ZURvbWFpbixcbiAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIGxvY2FsTG9nZ2VyLndhcm4oYFske0FERE9OX05BTUV9XSBJbXBvcnQgcmV0dXJuZWQgYnV0IG5vIHNpdGUgSUQgZm91bmRgKTtcbiAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICAgICAgICAgIGVycm9yOiBudWxsLFxuICAgICAgICAgICAgICAgIHNpdGVJZDogbnVsbCxcbiAgICAgICAgICAgICAgICBzaXRlTmFtZTogbmFtZSxcbiAgICAgICAgICAgICAgICBzaXRlRG9tYWluOiBzaXRlRG9tYWluLFxuICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIE5vIGJsdWVwcmludCAtIGNyZWF0ZSBhIGZyZXNoIHNpdGVcbiAgICAgICAgICBjb25zdCBuZXdTaXRlSW5mbzogYW55ID0ge1xuICAgICAgICAgICAgc2l0ZU5hbWU6IG5hbWUsXG4gICAgICAgICAgICBzaXRlRG9tYWluOiBzaXRlRG9tYWluLFxuICAgICAgICAgICAgc2l0ZVBhdGg6IHNpdGVQYXRoLFxuICAgICAgICAgICAgd2ViU2VydmVyOiB3ZWJTZXJ2ZXIsXG4gICAgICAgICAgICBkYXRhYmFzZTogZGF0YWJhc2UsXG4gICAgICAgICAgfTtcblxuICAgICAgICAgIGlmIChwaHBWZXJzaW9uKSB7XG4gICAgICAgICAgICBuZXdTaXRlSW5mby5waHBWZXJzaW9uID0gcGhwVmVyc2lvbjtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjb25zdCB3cENyZWRlbnRpYWxzID0ge1xuICAgICAgICAgICAgYWRtaW5Vc2VybmFtZTogd3BBZG1pblVzZXJuYW1lLFxuICAgICAgICAgICAgYWRtaW5QYXNzd29yZDogd3BBZG1pblBhc3N3b3JkLFxuICAgICAgICAgICAgYWRtaW5FbWFpbDogd3BBZG1pbkVtYWlsLFxuICAgICAgICAgIH07XG5cbiAgICAgICAgICBjb25zdCBzaXRlID0gYXdhaXQgYWRkU2l0ZVNlcnZpY2UuYWRkU2l0ZSh7XG4gICAgICAgICAgICBuZXdTaXRlSW5mbyxcbiAgICAgICAgICAgIHdwQ3JlZGVudGlhbHMsXG4gICAgICAgICAgICBnb1RvU2l0ZTogZmFsc2UsXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICBsb2NhbExvZ2dlci5pbmZvKGBbJHtBRERPTl9OQU1FfV0gU3VjY2Vzc2Z1bGx5IGNyZWF0ZWQgc2l0ZTogJHtuYW1lfSAoJHtzaXRlLmlkfSlgKTtcblxuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICAgICAgZXJyb3I6IG51bGwsXG4gICAgICAgICAgICBzaXRlSWQ6IHNpdGUuaWQsXG4gICAgICAgICAgICBzaXRlTmFtZTogbmFtZSxcbiAgICAgICAgICAgIHNpdGVEb21haW46IHNpdGVEb21haW4sXG4gICAgICAgICAgfTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgICAgICAgIGxvY2FsTG9nZ2VyLmVycm9yKGBbJHtBRERPTl9OQU1FfV0gRmFpbGVkIHRvIGNyZWF0ZSBzaXRlOmAsIGVycm9yKTtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICBlcnJvcjogZXJyb3IubWVzc2FnZSB8fCAnVW5rbm93biBlcnJvcicsXG4gICAgICAgICAgICBzaXRlSWQ6IG51bGwsXG4gICAgICAgICAgICBzaXRlTmFtZTogbmFtZSxcbiAgICAgICAgICAgIHNpdGVEb21haW46IG51bGwsXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgfSxcblxuICAgICAgZGVsZXRlU2l0ZTogYXN5bmMgKFxuICAgICAgICBfcGFyZW50OiBhbnksXG4gICAgICAgIGFyZ3M6IHsgaW5wdXQ6IHsgaWQ6IHN0cmluZzsgdHJhc2hGaWxlcz86IGJvb2xlYW47IHVwZGF0ZUhvc3RzPzogYm9vbGVhbiB9IH1cbiAgICAgICkgPT4ge1xuICAgICAgICBjb25zdCB7IGlkLCB0cmFzaEZpbGVzID0gdHJ1ZSwgdXBkYXRlSG9zdHMgPSB0cnVlIH0gPSBhcmdzLmlucHV0O1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgbG9jYWxMb2dnZXIuaW5mbyhgWyR7QURET05fTkFNRX1dIERlbGV0aW5nIHNpdGU6ICR7aWR9YCk7XG5cbiAgICAgICAgICBjb25zdCBzaXRlID0gc2l0ZURhdGEuZ2V0U2l0ZShpZCk7XG4gICAgICAgICAgaWYgKCFzaXRlKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgZXJyb3I6IGBTaXRlIG5vdCBmb3VuZDogJHtpZH1gLFxuICAgICAgICAgICAgICBzaXRlSWQ6IGlkLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBhd2FpdCBkZWxldGVTaXRlU2VydmljZS5kZWxldGVTaXRlKHtcbiAgICAgICAgICAgIHNpdGUsXG4gICAgICAgICAgICB0cmFzaEZpbGVzLFxuICAgICAgICAgICAgdXBkYXRlSG9zdHMsXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICBsb2NhbExvZ2dlci5pbmZvKGBbJHtBRERPTl9OQU1FfV0gU3VjY2Vzc2Z1bGx5IGRlbGV0ZWQgc2l0ZTogJHtzaXRlLm5hbWV9YCk7XG5cbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgICAgICAgIGVycm9yOiBudWxsLFxuICAgICAgICAgICAgc2l0ZUlkOiBpZCxcbiAgICAgICAgICB9O1xuICAgICAgICB9IGNhdGNoIChlcnJvcjogYW55KSB7XG4gICAgICAgICAgbG9jYWxMb2dnZXIuZXJyb3IoYFske0FERE9OX05BTUV9XSBGYWlsZWQgdG8gZGVsZXRlIHNpdGU6YCwgZXJyb3IpO1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgIGVycm9yOiBlcnJvci5tZXNzYWdlIHx8ICdVbmtub3duIGVycm9yJyxcbiAgICAgICAgICAgIHNpdGVJZDogaWQsXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgfSxcblxuICAgICAgZGVsZXRlU2l0ZXM6IGFzeW5jIChfcGFyZW50OiBhbnksIGFyZ3M6IHsgaWRzOiBzdHJpbmdbXTsgdHJhc2hGaWxlcz86IGJvb2xlYW4gfSkgPT4ge1xuICAgICAgICBjb25zdCB7IGlkcywgdHJhc2hGaWxlcyA9IHRydWUgfSA9IGFyZ3M7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBsb2NhbExvZ2dlci5pbmZvKGBbJHtBRERPTl9OQU1FfV0gRGVsZXRpbmcgJHtpZHMubGVuZ3RofSBzaXRlc2ApO1xuXG4gICAgICAgICAgYXdhaXQgZGVsZXRlU2l0ZVNlcnZpY2UuZGVsZXRlU2l0ZXMoe1xuICAgICAgICAgICAgc2l0ZUlkczogaWRzLFxuICAgICAgICAgICAgdHJhc2hGaWxlcyxcbiAgICAgICAgICAgIHVwZGF0ZUhvc3RzOiB0cnVlLFxuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgbG9jYWxMb2dnZXIuaW5mbyhgWyR7QURET05fTkFNRX1dIFN1Y2Nlc3NmdWxseSBkZWxldGVkICR7aWRzLmxlbmd0aH0gc2l0ZXNgKTtcblxuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICAgICAgZXJyb3I6IG51bGwsXG4gICAgICAgICAgICBzaXRlSWQ6IGlkcy5qb2luKCcsJyksXG4gICAgICAgICAgfTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgICAgICAgIGxvY2FsTG9nZ2VyLmVycm9yKGBbJHtBRERPTl9OQU1FfV0gRmFpbGVkIHRvIGRlbGV0ZSBzaXRlczpgLCBlcnJvcik7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgZXJyb3I6IGVycm9yLm1lc3NhZ2UgfHwgJ1Vua25vd24gZXJyb3InLFxuICAgICAgICAgICAgc2l0ZUlkOiBpZHMuam9pbignLCcpLFxuICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgIH0sXG5cbiAgICAgIG9wZW5TaXRlOiBhc3luYyAoX3BhcmVudDogYW55LCBhcmdzOiB7IGlucHV0OiB7IHNpdGVJZDogc3RyaW5nOyBwYXRoPzogc3RyaW5nIH0gfSkgPT4ge1xuICAgICAgICBjb25zdCB7IHNpdGVJZCwgcGF0aCA9ICcvJyB9ID0gYXJncy5pbnB1dDtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IHNpdGUgPSBzaXRlRGF0YS5nZXRTaXRlKHNpdGVJZCk7XG4gICAgICAgICAgaWYgKCFzaXRlKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgZXJyb3I6IGBTaXRlIG5vdCBmb3VuZDogJHtzaXRlSWR9YCxcbiAgICAgICAgICAgICAgdXJsOiBudWxsLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBDaGVjayBpZiBzaXRlIGlzIHJ1bm5pbmdcbiAgICAgICAgICBjb25zdCBzdGF0dXMgPSBhd2FpdCBzaXRlUHJvY2Vzc01hbmFnZXIuZ2V0U2l0ZVN0YXR1cyhzaXRlKTtcbiAgICAgICAgICBpZiAoc3RhdHVzICE9PSAncnVubmluZycpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICBlcnJvcjogYFNpdGUgXCIke3NpdGUubmFtZX1cIiBtdXN0IGJlIHJ1bm5pbmcgdG8gb3BlbiBpbiBicm93c2VyLiBTdGFydCBpdCBmaXJzdC5gLFxuICAgICAgICAgICAgICB1cmw6IG51bGwsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGNvbnN0IHByb3RvY29sID0gc2l0ZS5pc1N0YXJyZWQgPyAnaHR0cHMnIDogJ2h0dHAnO1xuICAgICAgICAgIGNvbnN0IHVybCA9IGAke3Byb3RvY29sfTovLyR7c2l0ZS5kb21haW59JHtwYXRofWA7XG5cbiAgICAgICAgICBsb2NhbExvZ2dlci5pbmZvKGBbJHtBRERPTl9OQU1FfV0gT3BlbmluZyBzaXRlIGluIGJyb3dzZXI6ICR7dXJsfWApO1xuXG4gICAgICAgICAgaWYgKGJyb3dzZXJNYW5hZ2VyKSB7XG4gICAgICAgICAgICBhd2FpdCBicm93c2VyTWFuYWdlci5vcGVuSW5Ccm93c2VyKHVybCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIEZhbGxiYWNrIHRvIHNoZWxsLm9wZW5FeHRlcm5hbFxuICAgICAgICAgICAgY29uc3QgeyBzaGVsbCB9ID0gcmVxdWlyZSgnZWxlY3Ryb24nKTtcbiAgICAgICAgICAgIGF3YWl0IHNoZWxsLm9wZW5FeHRlcm5hbCh1cmwpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICAgICAgZXJyb3I6IG51bGwsXG4gICAgICAgICAgICB1cmwsXG4gICAgICAgICAgfTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgICAgICAgIGxvY2FsTG9nZ2VyLmVycm9yKGBbJHtBRERPTl9OQU1FfV0gRmFpbGVkIHRvIG9wZW4gc2l0ZTpgLCBlcnJvcik7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgZXJyb3I6IGVycm9yLm1lc3NhZ2UgfHwgJ1Vua25vd24gZXJyb3InLFxuICAgICAgICAgICAgdXJsOiBudWxsLFxuICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgIH0sXG5cbiAgICAgIGNsb25lU2l0ZTogYXN5bmMgKF9wYXJlbnQ6IGFueSwgYXJnczogeyBpbnB1dDogeyBzaXRlSWQ6IHN0cmluZzsgbmV3TmFtZTogc3RyaW5nIH0gfSkgPT4ge1xuICAgICAgICBjb25zdCB7IHNpdGVJZCwgbmV3TmFtZSB9ID0gYXJncy5pbnB1dDtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IHNpdGUgPSBzaXRlRGF0YS5nZXRTaXRlKHNpdGVJZCk7XG4gICAgICAgICAgaWYgKCFzaXRlKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgZXJyb3I6IGBTaXRlIG5vdCBmb3VuZDogJHtzaXRlSWR9YCxcbiAgICAgICAgICAgICAgbmV3U2l0ZUlkOiBudWxsLFxuICAgICAgICAgICAgICBuZXdTaXRlTmFtZTogbnVsbCxcbiAgICAgICAgICAgICAgbmV3U2l0ZURvbWFpbjogbnVsbCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gQ2hlY2sgaWYgc2l0ZSBpcyBydW5uaW5nIC0gbmVlZGVkIGZvciBkYXRhYmFzZSBjbG9uaW5nXG4gICAgICAgICAgY29uc3Qgc3RhdHVzID0gYXdhaXQgc2l0ZVByb2Nlc3NNYW5hZ2VyLmdldFNpdGVTdGF0dXMoc2l0ZSk7XG4gICAgICAgICAgaWYgKHN0YXR1cyAhPT0gJ3J1bm5pbmcnKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgZXJyb3I6IGBTaXRlIFwiJHtzaXRlLm5hbWV9XCIgbXVzdCBiZSBydW5uaW5nIHRvIGNsb25lLiBTdGFydCBpdCBmaXJzdC5gLFxuICAgICAgICAgICAgICBuZXdTaXRlSWQ6IG51bGwsXG4gICAgICAgICAgICAgIG5ld1NpdGVOYW1lOiBudWxsLFxuICAgICAgICAgICAgICBuZXdTaXRlRG9tYWluOiBudWxsLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBsb2NhbExvZ2dlci5pbmZvKGBbJHtBRERPTl9OQU1FfV0gQ2xvbmluZyBzaXRlICR7c2l0ZS5uYW1lfSB0byAke25ld05hbWV9YCk7XG5cbiAgICAgICAgICBjb25zdCBuZXdTaXRlID0gYXdhaXQgY2xvbmVTaXRlU2VydmljZS5jbG9uZVNpdGUoe1xuICAgICAgICAgICAgc2l0ZSxcbiAgICAgICAgICAgIG5ld1NpdGVOYW1lOiBuZXdOYW1lLFxuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgbG9jYWxMb2dnZXIuaW5mbyhcbiAgICAgICAgICAgIGBbJHtBRERPTl9OQU1FfV0gU3VjY2Vzc2Z1bGx5IGNsb25lZCBzaXRlOiAke25ld1NpdGUubmFtZX0gKCR7bmV3U2l0ZS5pZH0pYFxuICAgICAgICAgICk7XG5cbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgICAgICAgIGVycm9yOiBudWxsLFxuICAgICAgICAgICAgbmV3U2l0ZUlkOiBuZXdTaXRlLmlkLFxuICAgICAgICAgICAgbmV3U2l0ZU5hbWU6IG5ld1NpdGUubmFtZSxcbiAgICAgICAgICAgIG5ld1NpdGVEb21haW46IG5ld1NpdGUuZG9tYWluLFxuICAgICAgICAgIH07XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yOiBhbnkpIHtcbiAgICAgICAgICBsb2NhbExvZ2dlci5lcnJvcihgWyR7QURET05fTkFNRX1dIEZhaWxlZCB0byBjbG9uZSBzaXRlOmAsIGVycm9yKTtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICBlcnJvcjogZXJyb3IubWVzc2FnZSB8fCAnVW5rbm93biBlcnJvcicsXG4gICAgICAgICAgICBuZXdTaXRlSWQ6IG51bGwsXG4gICAgICAgICAgICBuZXdTaXRlTmFtZTogbnVsbCxcbiAgICAgICAgICAgIG5ld1NpdGVEb21haW46IG51bGwsXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgfSxcblxuICAgICAgZXhwb3J0U2l0ZTogYXN5bmMgKFxuICAgICAgICBfcGFyZW50OiBhbnksXG4gICAgICAgIGFyZ3M6IHsgaW5wdXQ6IHsgc2l0ZUlkOiBzdHJpbmc7IG91dHB1dFBhdGg/OiBzdHJpbmcgfSB9XG4gICAgICApID0+IHtcbiAgICAgICAgY29uc3QgeyBzaXRlSWQsIG91dHB1dFBhdGggfSA9IGFyZ3MuaW5wdXQ7XG4gICAgICAgIGNvbnN0IG9zID0gcmVxdWlyZSgnb3MnKTtcbiAgICAgICAgY29uc3QgcGF0aCA9IHJlcXVpcmUoJ3BhdGgnKTtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IHNpdGUgPSBzaXRlRGF0YS5nZXRTaXRlKHNpdGVJZCk7XG4gICAgICAgICAgaWYgKCFzaXRlKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgZXJyb3I6IGBTaXRlIG5vdCBmb3VuZDogJHtzaXRlSWR9YCxcbiAgICAgICAgICAgICAgZXhwb3J0UGF0aDogbnVsbCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gQ2hlY2sgaWYgc2l0ZSBpcyBydW5uaW5nIC0gbmVlZGVkIGZvciBkYXRhYmFzZSBleHBvcnRcbiAgICAgICAgICBjb25zdCBzdGF0dXMgPSBhd2FpdCBzaXRlUHJvY2Vzc01hbmFnZXIuZ2V0U2l0ZVN0YXR1cyhzaXRlKTtcbiAgICAgICAgICBpZiAoc3RhdHVzICE9PSAncnVubmluZycpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICBlcnJvcjogYFNpdGUgXCIke3NpdGUubmFtZX1cIiBtdXN0IGJlIHJ1bm5pbmcgdG8gZXhwb3J0LiBTdGFydCBpdCBmaXJzdC5gLFxuICAgICAgICAgICAgICBleHBvcnRQYXRoOiBudWxsLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBEZWZhdWx0IHRvIERvd25sb2FkcyBmb2xkZXJcbiAgICAgICAgICBjb25zdCBvdXRwdXREaXIgPSBvdXRwdXRQYXRoIHx8IHBhdGguam9pbihvcy5ob21lZGlyKCksICdEb3dubG9hZHMnKTtcbiAgICAgICAgICBjb25zdCB0aW1lc3RhbXAgPSBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCkucmVwbGFjZSgvWzouXS9nLCAnLScpLnNsaWNlKDAsIDE5KTtcbiAgICAgICAgICBjb25zdCBmaWxlTmFtZSA9IGAke3NpdGUubmFtZX0tJHt0aW1lc3RhbXB9LnppcGA7XG4gICAgICAgICAgY29uc3QgZnVsbFBhdGggPSBwYXRoLmpvaW4ob3V0cHV0RGlyLCBmaWxlTmFtZSk7XG5cbiAgICAgICAgICBsb2NhbExvZ2dlci5pbmZvKGBbJHtBRERPTl9OQU1FfV0gRXhwb3J0aW5nIHNpdGUgJHtzaXRlLm5hbWV9IHRvICR7ZnVsbFBhdGh9YCk7XG5cbiAgICAgICAgICAvLyBVc2UgZGVmYXVsdCBleHBvcnQgZmlsdGVyIChleGNsdWRlcyBhcmNoaXZlIGZpbGVzKVxuICAgICAgICAgIGNvbnN0IGRlZmF1bHRFeHBvcnRGaWx0ZXIgPSAnKi56aXAsICoudGFyLmd6LCAqLmJ6MiwgKi50Z3onO1xuXG4gICAgICAgICAgYXdhaXQgZXhwb3J0U2l0ZVNlcnZpY2UuZXhwb3J0U2l0ZSh7XG4gICAgICAgICAgICBzaXRlLFxuICAgICAgICAgICAgb3V0cHV0UGF0aDogZnVsbFBhdGgsXG4gICAgICAgICAgICBmaWx0ZXI6IGRlZmF1bHRFeHBvcnRGaWx0ZXIsXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICBsb2NhbExvZ2dlci5pbmZvKGBbJHtBRERPTl9OQU1FfV0gU3VjY2Vzc2Z1bGx5IGV4cG9ydGVkIHNpdGUgdG86ICR7ZnVsbFBhdGh9YCk7XG5cbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgICAgICAgIGVycm9yOiBudWxsLFxuICAgICAgICAgICAgZXhwb3J0UGF0aDogZnVsbFBhdGgsXG4gICAgICAgICAgfTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgICAgICAgIGxvY2FsTG9nZ2VyLmVycm9yKGBbJHtBRERPTl9OQU1FfV0gRmFpbGVkIHRvIGV4cG9ydCBzaXRlOmAsIGVycm9yKTtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICBlcnJvcjogZXJyb3IubWVzc2FnZSB8fCAnVW5rbm93biBlcnJvcicsXG4gICAgICAgICAgICBleHBvcnRQYXRoOiBudWxsLFxuICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgIH0sXG5cbiAgICAgIHNhdmVCbHVlcHJpbnQ6IGFzeW5jIChfcGFyZW50OiBhbnksIGFyZ3M6IHsgaW5wdXQ6IHsgc2l0ZUlkOiBzdHJpbmc7IG5hbWU6IHN0cmluZyB9IH0pID0+IHtcbiAgICAgICAgY29uc3QgeyBzaXRlSWQsIG5hbWUgfSA9IGFyZ3MuaW5wdXQ7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBjb25zdCBzaXRlID0gc2l0ZURhdGEuZ2V0U2l0ZShzaXRlSWQpO1xuICAgICAgICAgIGlmICghc2l0ZSkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICAgIGVycm9yOiBgU2l0ZSBub3QgZm91bmQ6ICR7c2l0ZUlkfWAsXG4gICAgICAgICAgICAgIGJsdWVwcmludE5hbWU6IG51bGwsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIENoZWNrIGlmIHNpdGUgaXMgcnVubmluZyAtIG5lZWRlZCBmb3IgZGF0YWJhc2UgZXhwb3J0XG4gICAgICAgICAgY29uc3Qgc3RhdHVzID0gYXdhaXQgc2l0ZVByb2Nlc3NNYW5hZ2VyLmdldFNpdGVTdGF0dXMoc2l0ZSk7XG4gICAgICAgICAgaWYgKHN0YXR1cyAhPT0gJ3J1bm5pbmcnKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgZXJyb3I6IGBTaXRlIFwiJHtzaXRlLm5hbWV9XCIgbXVzdCBiZSBydW5uaW5nIHRvIHNhdmUgYXMgYmx1ZXByaW50LiBTdGFydCBpdCBmaXJzdC5gLFxuICAgICAgICAgICAgICBibHVlcHJpbnROYW1lOiBudWxsLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBsb2NhbExvZ2dlci5pbmZvKGBbJHtBRERPTl9OQU1FfV0gU2F2aW5nIHNpdGUgJHtzaXRlLm5hbWV9IGFzIGJsdWVwcmludDogJHtuYW1lfWApO1xuXG4gICAgICAgICAgLy8gVXNlIGRlZmF1bHQgZXhwb3J0IGZpbHRlciAoZXhjbHVkZXMgYXJjaGl2ZSBmaWxlcylcbiAgICAgICAgICBjb25zdCBkZWZhdWx0RmlsdGVyID0gJyouemlwLCAqLnRhci5neiwgKi5iejIsICoudGd6JztcblxuICAgICAgICAgIGF3YWl0IGJsdWVwcmludHNTZXJ2aWNlLnNhdmVCbHVlcHJpbnQoe1xuICAgICAgICAgICAgbmFtZSxcbiAgICAgICAgICAgIHNpdGVJZCxcbiAgICAgICAgICAgIGZpbHRlcjogZGVmYXVsdEZpbHRlcixcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIGxvY2FsTG9nZ2VyLmluZm8oYFske0FERE9OX05BTUV9XSBTdWNjZXNzZnVsbHkgc2F2ZWQgYmx1ZXByaW50OiAke25hbWV9YCk7XG5cbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgICAgICAgIGVycm9yOiBudWxsLFxuICAgICAgICAgICAgYmx1ZXByaW50TmFtZTogbmFtZSxcbiAgICAgICAgICB9O1xuICAgICAgICB9IGNhdGNoIChlcnJvcjogYW55KSB7XG4gICAgICAgICAgbG9jYWxMb2dnZXIuZXJyb3IoYFske0FERE9OX05BTUV9XSBGYWlsZWQgdG8gc2F2ZSBibHVlcHJpbnQ6YCwgZXJyb3IpO1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgIGVycm9yOiBlcnJvci5tZXNzYWdlIHx8ICdVbmtub3duIGVycm9yJyxcbiAgICAgICAgICAgIGJsdWVwcmludE5hbWU6IG51bGwsXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgfSxcblxuICAgICAgLy8gUGhhc2UgODogV29yZFByZXNzIERldmVsb3BtZW50IFRvb2xzXG4gICAgICBleHBvcnREYXRhYmFzZTogYXN5bmMgKFxuICAgICAgICBfcGFyZW50OiBhbnksXG4gICAgICAgIGFyZ3M6IHsgaW5wdXQ6IHsgc2l0ZUlkOiBzdHJpbmc7IG91dHB1dFBhdGg/OiBzdHJpbmcgfSB9XG4gICAgICApID0+IHtcbiAgICAgICAgY29uc3QgeyBzaXRlSWQsIG91dHB1dFBhdGggfSA9IGFyZ3MuaW5wdXQ7XG4gICAgICAgIGNvbnN0IG9zID0gcmVxdWlyZSgnb3MnKTtcbiAgICAgICAgY29uc3QgcGF0aE1vZHVsZSA9IHJlcXVpcmUoJ3BhdGgnKTtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IHNpdGUgPSBzaXRlRGF0YS5nZXRTaXRlKHNpdGVJZCk7XG4gICAgICAgICAgaWYgKCFzaXRlKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgZXJyb3I6IGBTaXRlIG5vdCBmb3VuZDogJHtzaXRlSWR9YCxcbiAgICAgICAgICAgICAgb3V0cHV0UGF0aDogbnVsbCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gQ2hlY2sgaWYgc2l0ZSBpcyBydW5uaW5nIC0gZGF0YWJhc2UgbXVzdCBiZSBhY2Nlc3NpYmxlXG4gICAgICAgICAgY29uc3Qgc3RhdHVzID0gYXdhaXQgc2l0ZVByb2Nlc3NNYW5hZ2VyLmdldFNpdGVTdGF0dXMoc2l0ZSk7XG4gICAgICAgICAgaWYgKHN0YXR1cyAhPT0gJ3J1bm5pbmcnKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgZXJyb3I6IGBTaXRlIFwiJHtzaXRlLm5hbWV9XCIgbXVzdCBiZSBydW5uaW5nIHRvIGV4cG9ydCBkYXRhYmFzZS4gU3RhcnQgaXQgZmlyc3QuYCxcbiAgICAgICAgICAgICAgb3V0cHV0UGF0aDogbnVsbCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gRGVmYXVsdCB0byBEb3dubG9hZHMgZm9sZGVyIHdpdGggc2l0ZSBuYW1lXG4gICAgICAgICAgY29uc3QgZGVmYXVsdFBhdGggPSBwYXRoTW9kdWxlLmpvaW4oXG4gICAgICAgICAgICBvcy5ob21lZGlyKCksXG4gICAgICAgICAgICAnRG93bmxvYWRzJyxcbiAgICAgICAgICAgIGAke3NpdGUubmFtZS5yZXBsYWNlKC9bXmEtejAtOV0vZ2ksICctJyl9LnNxbGBcbiAgICAgICAgICApO1xuICAgICAgICAgIGNvbnN0IGZpbmFsUGF0aCA9IG91dHB1dFBhdGggfHwgZGVmYXVsdFBhdGg7XG5cbiAgICAgICAgICBsb2NhbExvZ2dlci5pbmZvKGBbJHtBRERPTl9OQU1FfV0gRXhwb3J0aW5nIGRhdGFiYXNlIGZvciAke3NpdGUubmFtZX0gdG8gJHtmaW5hbFBhdGh9YCk7XG5cbiAgICAgICAgICAvLyBVc2Ugc2l0ZURhdGFiYXNlLmR1bXAoKSB3aGljaCBwcm9wZXJseSBzZXRzIHVwIE15U1FMIGVudmlyb25tZW50XG4gICAgICAgICAgaWYgKCFzaXRlRGF0YWJhc2UpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICBlcnJvcjogJ0RhdGFiYXNlIHNlcnZpY2Ugbm90IGF2YWlsYWJsZScsXG4gICAgICAgICAgICAgIG91dHB1dFBhdGg6IG51bGwsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGF3YWl0IHNpdGVEYXRhYmFzZS5kdW1wKHNpdGUsIGZpbmFsUGF0aCk7XG5cbiAgICAgICAgICBsb2NhbExvZ2dlci5pbmZvKGBbJHtBRERPTl9OQU1FfV0gU3VjY2Vzc2Z1bGx5IGV4cG9ydGVkIGRhdGFiYXNlIHRvOiAke2ZpbmFsUGF0aH1gKTtcblxuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICAgICAgZXJyb3I6IG51bGwsXG4gICAgICAgICAgICBvdXRwdXRQYXRoOiBmaW5hbFBhdGgsXG4gICAgICAgICAgfTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgICAgICAgIGxvY2FsTG9nZ2VyLmVycm9yKGBbJHtBRERPTl9OQU1FfV0gRmFpbGVkIHRvIGV4cG9ydCBkYXRhYmFzZTpgLCBlcnJvcik7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgZXJyb3I6IGVycm9yLm1lc3NhZ2UgfHwgJ1Vua25vd24gZXJyb3InLFxuICAgICAgICAgICAgb3V0cHV0UGF0aDogbnVsbCxcbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICB9LFxuXG4gICAgICBpbXBvcnREYXRhYmFzZTogYXN5bmMgKFxuICAgICAgICBfcGFyZW50OiBhbnksXG4gICAgICAgIGFyZ3M6IHsgaW5wdXQ6IHsgc2l0ZUlkOiBzdHJpbmc7IHNxbFBhdGg6IHN0cmluZyB9IH1cbiAgICAgICkgPT4ge1xuICAgICAgICBjb25zdCB7IHNpdGVJZCwgc3FsUGF0aCB9ID0gYXJncy5pbnB1dDtcbiAgICAgICAgY29uc3QgZnMgPSByZXF1aXJlKCdmcycpO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3Qgc2l0ZSA9IHNpdGVEYXRhLmdldFNpdGUoc2l0ZUlkKTtcbiAgICAgICAgICBpZiAoIXNpdGUpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICBlcnJvcjogYFNpdGUgbm90IGZvdW5kOiAke3NpdGVJZH1gLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoIWZzLmV4aXN0c1N5bmMoc3FsUGF0aCkpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICBlcnJvcjogYFNRTCBmaWxlIG5vdCBmb3VuZDogJHtzcWxQYXRofWAsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIENoZWNrIGlmIHNpdGUgaXMgcnVubmluZyAtIGRhdGFiYXNlIG11c3QgYmUgYWNjZXNzaWJsZVxuICAgICAgICAgIGNvbnN0IHN0YXR1cyA9IGF3YWl0IHNpdGVQcm9jZXNzTWFuYWdlci5nZXRTaXRlU3RhdHVzKHNpdGUpO1xuICAgICAgICAgIGlmIChzdGF0dXMgIT09ICdydW5uaW5nJykge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICAgIGVycm9yOiBgU2l0ZSBcIiR7c2l0ZS5uYW1lfVwiIG11c3QgYmUgcnVubmluZyB0byBpbXBvcnQgZGF0YWJhc2UuIFN0YXJ0IGl0IGZpcnN0LmAsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGxvY2FsTG9nZ2VyLmluZm8oYFske0FERE9OX05BTUV9XSBJbXBvcnRpbmcgZGF0YWJhc2UgZm9yICR7c2l0ZS5uYW1lfSBmcm9tICR7c3FsUGF0aH1gKTtcblxuICAgICAgICAgIC8vIFVzZSBpbXBvcnRTUUxGaWxlIHNlcnZpY2Ugd2hpY2ggcHJvcGVybHkgc2V0cyB1cCBNeVNRTCBlbnZpcm9ubWVudFxuICAgICAgICAgIGlmICghaW1wb3J0U1FMRmlsZVNlcnZpY2UpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICBlcnJvcjogJ0ltcG9ydCBTUUwgZmlsZSBzZXJ2aWNlIG5vdCBhdmFpbGFibGUnLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBhd2FpdCBpbXBvcnRTUUxGaWxlU2VydmljZShzaXRlLCBzcWxQYXRoKTtcblxuICAgICAgICAgIGxvY2FsTG9nZ2VyLmluZm8oYFske0FERE9OX05BTUV9XSBTdWNjZXNzZnVsbHkgaW1wb3J0ZWQgZGF0YWJhc2UgZnJvbTogJHtzcWxQYXRofWApO1xuXG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgICBlcnJvcjogbnVsbCxcbiAgICAgICAgICB9O1xuICAgICAgICB9IGNhdGNoIChlcnJvcjogYW55KSB7XG4gICAgICAgICAgbG9jYWxMb2dnZXIuZXJyb3IoYFske0FERE9OX05BTUV9XSBGYWlsZWQgdG8gaW1wb3J0IGRhdGFiYXNlOmAsIGVycm9yKTtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICBlcnJvcjogZXJyb3IubWVzc2FnZSB8fCAnVW5rbm93biBlcnJvcicsXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgfSxcblxuICAgICAgb3BlbkFkbWluZXI6IGFzeW5jIChfcGFyZW50OiBhbnksIGFyZ3M6IHsgaW5wdXQ6IHsgc2l0ZUlkOiBzdHJpbmcgfSB9KSA9PiB7XG4gICAgICAgIGNvbnN0IHsgc2l0ZUlkIH0gPSBhcmdzLmlucHV0O1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3Qgc2l0ZSA9IHNpdGVEYXRhLmdldFNpdGUoc2l0ZUlkKTtcbiAgICAgICAgICBpZiAoIXNpdGUpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICBlcnJvcjogYFNpdGUgbm90IGZvdW5kOiAke3NpdGVJZH1gLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBDaGVjayBpZiBzaXRlIGlzIHJ1bm5pbmcgLSBkYXRhYmFzZSBtdXN0IGJlIGFjY2Vzc2libGVcbiAgICAgICAgICBjb25zdCBzdGF0dXMgPSBhd2FpdCBzaXRlUHJvY2Vzc01hbmFnZXIuZ2V0U2l0ZVN0YXR1cyhzaXRlKTtcbiAgICAgICAgICBpZiAoc3RhdHVzICE9PSAncnVubmluZycpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICBlcnJvcjogYFNpdGUgXCIke3NpdGUubmFtZX1cIiBtdXN0IGJlIHJ1bm5pbmcgdG8gb3BlbiBBZG1pbmVyLiBTdGFydCBpdCBmaXJzdC5gLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBsb2NhbExvZ2dlci5pbmZvKGBbJHtBRERPTl9OQU1FfV0gT3BlbmluZyBBZG1pbmVyIGZvciAke3NpdGUubmFtZX1gKTtcblxuICAgICAgICAgIGlmIChhZG1pbmVyKSB7XG4gICAgICAgICAgICBhd2FpdCBhZG1pbmVyLm9wZW4oc2l0ZSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICBlcnJvcjogJ0FkbWluZXIgc2VydmljZSBub3QgYXZhaWxhYmxlJyxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgICBlcnJvcjogbnVsbCxcbiAgICAgICAgICB9O1xuICAgICAgICB9IGNhdGNoIChlcnJvcjogYW55KSB7XG4gICAgICAgICAgbG9jYWxMb2dnZXIuZXJyb3IoYFske0FERE9OX05BTUV9XSBGYWlsZWQgdG8gb3BlbiBBZG1pbmVyOmAsIGVycm9yKTtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICBlcnJvcjogZXJyb3IubWVzc2FnZSB8fCAnVW5rbm93biBlcnJvcicsXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgfSxcblxuICAgICAgdHJ1c3RTc2w6IGFzeW5jIChfcGFyZW50OiBhbnksIGFyZ3M6IHsgaW5wdXQ6IHsgc2l0ZUlkOiBzdHJpbmcgfSB9KSA9PiB7XG4gICAgICAgIGNvbnN0IHsgc2l0ZUlkIH0gPSBhcmdzLmlucHV0O1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3Qgc2l0ZSA9IHNpdGVEYXRhLmdldFNpdGUoc2l0ZUlkKTtcbiAgICAgICAgICBpZiAoIXNpdGUpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICBlcnJvcjogYFNpdGUgbm90IGZvdW5kOiAke3NpdGVJZH1gLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBsb2NhbExvZ2dlci5pbmZvKGBbJHtBRERPTl9OQU1FfV0gVHJ1c3RpbmcgU1NMIGZvciAke3NpdGUubmFtZX1gKTtcblxuICAgICAgICAgIGlmICh4NTA5Q2VydCkge1xuICAgICAgICAgICAgYXdhaXQgeDUwOUNlcnQudHJ1c3RDZXJ0KHNpdGUpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgZXJyb3I6ICdYNTA5IGNlcnRpZmljYXRlIHNlcnZpY2Ugbm90IGF2YWlsYWJsZScsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICAgICAgZXJyb3I6IG51bGwsXG4gICAgICAgICAgfTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgICAgICAgIGxvY2FsTG9nZ2VyLmVycm9yKGBbJHtBRERPTl9OQU1FfV0gRmFpbGVkIHRvIHRydXN0IFNTTDpgLCBlcnJvcik7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgZXJyb3I6IGVycm9yLm1lc3NhZ2UgfHwgJ1Vua25vd24gZXJyb3InLFxuICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgIH0sXG5cbiAgICAgIG1jcFJlbmFtZVNpdGU6IGFzeW5jIChfcGFyZW50OiBhbnksIGFyZ3M6IHsgaW5wdXQ6IHsgc2l0ZUlkOiBzdHJpbmc7IG5ld05hbWU6IHN0cmluZyB9IH0pID0+IHtcbiAgICAgICAgY29uc3QgeyBzaXRlSWQsIG5ld05hbWUgfSA9IGFyZ3MuaW5wdXQ7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBjb25zdCBzaXRlID0gc2l0ZURhdGEuZ2V0U2l0ZShzaXRlSWQpO1xuICAgICAgICAgIGlmICghc2l0ZSkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICAgIGVycm9yOiBgU2l0ZSBub3QgZm91bmQ6ICR7c2l0ZUlkfWAsXG4gICAgICAgICAgICAgIG5ld05hbWU6IG51bGwsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGxvY2FsTG9nZ2VyLmluZm8oYFske0FERE9OX05BTUV9XSBSZW5hbWluZyAke3NpdGUubmFtZX0gdG8gJHtuZXdOYW1lfWApO1xuXG4gICAgICAgICAgLy8gVXBkYXRlIHNpdGUgbmFtZSB2aWEgc2l0ZURhdGFcbiAgICAgICAgICBzaXRlLm5hbWUgPSBuZXdOYW1lO1xuICAgICAgICAgIGF3YWl0IHNpdGVEYXRhLnVwZGF0ZVNpdGUoc2l0ZUlkLCB7IG5hbWU6IG5ld05hbWUgfSk7XG5cbiAgICAgICAgICBsb2NhbExvZ2dlci5pbmZvKGBbJHtBRERPTl9OQU1FfV0gU3VjY2Vzc2Z1bGx5IHJlbmFtZWQgc2l0ZSB0bzogJHtuZXdOYW1lfWApO1xuXG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgICBlcnJvcjogbnVsbCxcbiAgICAgICAgICAgIG5ld05hbWUsXG4gICAgICAgICAgfTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgICAgICAgIGxvY2FsTG9nZ2VyLmVycm9yKGBbJHtBRERPTl9OQU1FfV0gRmFpbGVkIHRvIHJlbmFtZSBzaXRlOmAsIGVycm9yKTtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICBlcnJvcjogZXJyb3IubWVzc2FnZSB8fCAnVW5rbm93biBlcnJvcicsXG4gICAgICAgICAgICBuZXdOYW1lOiBudWxsLFxuICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgIH0sXG5cbiAgICAgIGNoYW5nZVBocFZlcnNpb246IGFzeW5jIChcbiAgICAgICAgX3BhcmVudDogYW55LFxuICAgICAgICBhcmdzOiB7IGlucHV0OiB7IHNpdGVJZDogc3RyaW5nOyBwaHBWZXJzaW9uOiBzdHJpbmcgfSB9XG4gICAgICApID0+IHtcbiAgICAgICAgY29uc3QgeyBzaXRlSWQsIHBocFZlcnNpb24gfSA9IGFyZ3MuaW5wdXQ7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBjb25zdCBzaXRlID0gc2l0ZURhdGEuZ2V0U2l0ZShzaXRlSWQpO1xuICAgICAgICAgIGlmICghc2l0ZSkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICAgIGVycm9yOiBgU2l0ZSBub3QgZm91bmQ6ICR7c2l0ZUlkfWAsXG4gICAgICAgICAgICAgIHBocFZlcnNpb246IG51bGwsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGxvY2FsTG9nZ2VyLmluZm8oXG4gICAgICAgICAgICBgWyR7QURET05fTkFNRX1dIENoYW5naW5nIFBIUCB2ZXJzaW9uIGZvciAke3NpdGUubmFtZX0gdG8gJHtwaHBWZXJzaW9ufWBcbiAgICAgICAgICApO1xuXG4gICAgICAgICAgaWYgKHNpdGVQcm92aXNpb25lcikge1xuICAgICAgICAgICAgYXdhaXQgc2l0ZVByb3Zpc2lvbmVyLnN3YXBTZXJ2aWNlKHNpdGUsICdwaHAnLCBwaHBWZXJzaW9uKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICAgIGVycm9yOiAnU2l0ZSBwcm92aXNpb25lciBzZXJ2aWNlIG5vdCBhdmFpbGFibGUnLFxuICAgICAgICAgICAgICBwaHBWZXJzaW9uOiBudWxsLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBsb2NhbExvZ2dlci5pbmZvKGBbJHtBRERPTl9OQU1FfV0gU3VjY2Vzc2Z1bGx5IGNoYW5nZWQgUEhQIHZlcnNpb24gdG86ICR7cGhwVmVyc2lvbn1gKTtcblxuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICAgICAgZXJyb3I6IG51bGwsXG4gICAgICAgICAgICBwaHBWZXJzaW9uLFxuICAgICAgICAgIH07XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yOiBhbnkpIHtcbiAgICAgICAgICBsb2NhbExvZ2dlci5lcnJvcihgWyR7QURET05fTkFNRX1dIEZhaWxlZCB0byBjaGFuZ2UgUEhQIHZlcnNpb246YCwgZXJyb3IpO1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgIGVycm9yOiBlcnJvci5tZXNzYWdlIHx8ICdVbmtub3duIGVycm9yJyxcbiAgICAgICAgICAgIHBocFZlcnNpb246IG51bGwsXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgfSxcblxuICAgICAgaW1wb3J0U2l0ZTogYXN5bmMgKF9wYXJlbnQ6IGFueSwgYXJnczogeyBpbnB1dDogeyB6aXBQYXRoOiBzdHJpbmc7IHNpdGVOYW1lPzogc3RyaW5nIH0gfSkgPT4ge1xuICAgICAgICBjb25zdCB7IHppcFBhdGgsIHNpdGVOYW1lIH0gPSBhcmdzLmlucHV0O1xuICAgICAgICBjb25zdCBmcyA9IHJlcXVpcmUoJ2ZzJyk7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBpZiAoIWZzLmV4aXN0c1N5bmMoemlwUGF0aCkpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICBlcnJvcjogYFppcCBmaWxlIG5vdCBmb3VuZDogJHt6aXBQYXRofWAsXG4gICAgICAgICAgICAgIHNpdGVJZDogbnVsbCxcbiAgICAgICAgICAgICAgc2l0ZU5hbWU6IG51bGwsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGxvY2FsTG9nZ2VyLmluZm8oYFske0FERE9OX05BTUV9XSBJbXBvcnRpbmcgc2l0ZSBmcm9tICR7emlwUGF0aH1gKTtcblxuICAgICAgICAgIGlmICghaW1wb3J0U2l0ZVNlcnZpY2UpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICBlcnJvcjogJ0ltcG9ydCBzaXRlIHNlcnZpY2Ugbm90IGF2YWlsYWJsZScsXG4gICAgICAgICAgICAgIHNpdGVJZDogbnVsbCxcbiAgICAgICAgICAgICAgc2l0ZU5hbWU6IG51bGwsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGltcG9ydFNpdGVTZXJ2aWNlLnJ1bih7XG4gICAgICAgICAgICB6aXBQYXRoLFxuICAgICAgICAgICAgc2l0ZU5hbWU6IHNpdGVOYW1lIHx8IHVuZGVmaW5lZCxcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIGxvY2FsTG9nZ2VyLmluZm8oYFske0FERE9OX05BTUV9XSBTdWNjZXNzZnVsbHkgaW1wb3J0ZWQgc2l0ZTogJHtyZXN1bHQubmFtZX1gKTtcblxuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICAgICAgZXJyb3I6IG51bGwsXG4gICAgICAgICAgICBzaXRlSWQ6IHJlc3VsdC5pZCxcbiAgICAgICAgICAgIHNpdGVOYW1lOiByZXN1bHQubmFtZSxcbiAgICAgICAgICB9O1xuICAgICAgICB9IGNhdGNoIChlcnJvcjogYW55KSB7XG4gICAgICAgICAgbG9jYWxMb2dnZXIuZXJyb3IoYFske0FERE9OX05BTUV9XSBGYWlsZWQgdG8gaW1wb3J0IHNpdGU6YCwgZXJyb3IpO1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgIGVycm9yOiBlcnJvci5tZXNzYWdlIHx8ICdVbmtub3duIGVycm9yJyxcbiAgICAgICAgICAgIHNpdGVJZDogbnVsbCxcbiAgICAgICAgICAgIHNpdGVOYW1lOiBudWxsLFxuICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgIH0sXG5cbiAgICAgIC8vIFBoYXNlIDk6IFNpdGUgQ29uZmlndXJhdGlvbiAmIERldiBUb29sc1xuICAgICAgdG9nZ2xlWGRlYnVnOiBhc3luYyAoX3BhcmVudDogYW55LCBhcmdzOiB7IGlucHV0OiB7IHNpdGVJZDogc3RyaW5nOyBlbmFibGVkOiBib29sZWFuIH0gfSkgPT4ge1xuICAgICAgICBjb25zdCB7IHNpdGVJZCwgZW5hYmxlZCB9ID0gYXJncy5pbnB1dDtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IHNpdGUgPSBzaXRlRGF0YS5nZXRTaXRlKHNpdGVJZCk7XG4gICAgICAgICAgaWYgKCFzaXRlKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgZXJyb3I6IGBTaXRlIG5vdCBmb3VuZDogJHtzaXRlSWR9YCxcbiAgICAgICAgICAgICAgZW5hYmxlZDogbnVsbCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgbG9jYWxMb2dnZXIuaW5mbyhcbiAgICAgICAgICAgIGBbJHtBRERPTl9OQU1FfV0gJHtlbmFibGVkID8gJ0VuYWJsaW5nJyA6ICdEaXNhYmxpbmcnfSBYZGVidWcgZm9yICR7c2l0ZS5uYW1lfWBcbiAgICAgICAgICApO1xuXG4gICAgICAgICAgLy8gVXBkYXRlIHRoZSBzaXRlJ3MgeGRlYnVnRW5hYmxlZCBwcm9wZXJ0eVxuICAgICAgICAgIGF3YWl0IHNpdGVEYXRhLnVwZGF0ZVNpdGUoc2l0ZUlkLCB7IHhkZWJ1Z0VuYWJsZWQ6IGVuYWJsZWQgfSk7XG5cbiAgICAgICAgICAvLyBSZXN0YXJ0IHRoZSBzaXRlIGlmIGl0J3MgcnVubmluZyB0byBhcHBseSB0aGUgY2hhbmdlXG4gICAgICAgICAgY29uc3Qgc3RhdHVzID0gYXdhaXQgc2l0ZVByb2Nlc3NNYW5hZ2VyLmdldFNpdGVTdGF0dXMoc2l0ZSk7XG4gICAgICAgICAgaWYgKHN0YXR1cyA9PT0gJ3J1bm5pbmcnKSB7XG4gICAgICAgICAgICBsb2NhbExvZ2dlci5pbmZvKGBbJHtBRERPTl9OQU1FfV0gUmVzdGFydGluZyBzaXRlIHRvIGFwcGx5IFhkZWJ1ZyBjaGFuZ2VgKTtcbiAgICAgICAgICAgIGF3YWl0IHNpdGVQcm9jZXNzTWFuYWdlci5yZXN0YXJ0KHNpdGUpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGxvY2FsTG9nZ2VyLmluZm8oXG4gICAgICAgICAgICBgWyR7QURET05fTkFNRX1dIFN1Y2Nlc3NmdWxseSAke2VuYWJsZWQgPyAnZW5hYmxlZCcgOiAnZGlzYWJsZWQnfSBYZGVidWdgXG4gICAgICAgICAgKTtcblxuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICAgICAgZXJyb3I6IG51bGwsXG4gICAgICAgICAgICBlbmFibGVkLFxuICAgICAgICAgIH07XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yOiBhbnkpIHtcbiAgICAgICAgICBsb2NhbExvZ2dlci5lcnJvcihgWyR7QURET05fTkFNRX1dIEZhaWxlZCB0byB0b2dnbGUgWGRlYnVnOmAsIGVycm9yKTtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICBlcnJvcjogZXJyb3IubWVzc2FnZSB8fCAnVW5rbm93biBlcnJvcicsXG4gICAgICAgICAgICBlbmFibGVkOiBudWxsLFxuICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgIH0sXG5cbiAgICAgIGdldFNpdGVMb2dzOiBhc3luYyAoXG4gICAgICAgIF9wYXJlbnQ6IGFueSxcbiAgICAgICAgYXJnczogeyBpbnB1dDogeyBzaXRlSWQ6IHN0cmluZzsgbG9nVHlwZT86IHN0cmluZzsgbGluZXM/OiBudW1iZXIgfSB9XG4gICAgICApID0+IHtcbiAgICAgICAgY29uc3QgeyBzaXRlSWQsIGxvZ1R5cGUgPSAncGhwJywgbGluZXMgPSAxMDAgfSA9IGFyZ3MuaW5wdXQ7XG4gICAgICAgIGNvbnN0IGZzID0gcmVxdWlyZSgnZnMnKTtcbiAgICAgICAgY29uc3QgZnNQcm9taXNlcyA9IGZzLnByb21pc2VzO1xuICAgICAgICBjb25zdCBwYXRoTW9kdWxlID0gcmVxdWlyZSgncGF0aCcpO1xuXG4gICAgICAgIC8vIEhlbHBlciBmb3IgYXN5bmMgZmlsZSBleGlzdGVuY2UgY2hlY2tcbiAgICAgICAgY29uc3QgZmlsZUV4aXN0cyA9IGFzeW5jIChmaWxlUGF0aDogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiA9PiB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGF3YWl0IGZzUHJvbWlzZXMuYWNjZXNzKGZpbGVQYXRoKTtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICAvLyBIZWxwZXIgdG8gcmVhZCBsYXN0IE4gbGluZXMgb2YgYSBmaWxlXG4gICAgICAgIGNvbnN0IHJlYWRMYXN0TGluZXMgPSBhc3luYyAoZmlsZVBhdGg6IHN0cmluZywgbnVtTGluZXM6IG51bWJlcik6IFByb21pc2U8c3RyaW5nPiA9PiB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IGNvbnRlbnQgPSBhd2FpdCBmc1Byb21pc2VzLnJlYWRGaWxlKGZpbGVQYXRoLCAndXRmLTgnKTtcbiAgICAgICAgICAgIGNvbnN0IGxvZ0xpbmVzID0gY29udGVudC5zcGxpdCgnXFxuJyk7XG4gICAgICAgICAgICByZXR1cm4gbG9nTGluZXMuc2xpY2UoLW51bUxpbmVzKS5qb2luKCdcXG4nKSB8fCAnKGVtcHR5KSc7XG4gICAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgICByZXR1cm4gJyc7XG4gICAgICAgICAgfVxuICAgICAgICB9O1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3Qgc2l0ZSA9IHNpdGVEYXRhLmdldFNpdGUoc2l0ZUlkKTtcbiAgICAgICAgICBpZiAoIXNpdGUpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICBlcnJvcjogYFNpdGUgbm90IGZvdW5kOiAke3NpdGVJZH1gLFxuICAgICAgICAgICAgICBsb2dzOiBbXSxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgbG9jYWxMb2dnZXIuaW5mbyhgWyR7QURET05fTkFNRX1dIEdldHRpbmcgJHtsb2dUeXBlfSBsb2dzIGZvciAke3NpdGUubmFtZX1gKTtcblxuICAgICAgICAgIGNvbnN0IGxvZ3M6IEFycmF5PHsgdHlwZTogc3RyaW5nOyBjb250ZW50OiBzdHJpbmc7IHBhdGg6IHN0cmluZyB9PiA9IFtdO1xuICAgICAgICAgIGNvbnN0IGxvZ3NEaXIgPSBwYXRoTW9kdWxlLmpvaW4oc2l0ZS5wYXRoLCAnbG9ncycpO1xuXG4gICAgICAgICAgY29uc3QgbG9nRmlsZXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZ1tdPiA9IHtcbiAgICAgICAgICAgIHBocDogWydwaHAnLCAncGhwLWZwbSddLFxuICAgICAgICAgICAgbmdpbng6IFsnbmdpbngnXSxcbiAgICAgICAgICAgIG15c3FsOiBbJ215c3FsJ10sXG4gICAgICAgICAgICBhbGw6IFsncGhwJywgJ3BocC1mcG0nLCAnbmdpbngnLCAnbXlzcWwnXSxcbiAgICAgICAgICB9O1xuXG4gICAgICAgICAgY29uc3QgdGFyZ2V0TG9ncyA9IGxvZ0ZpbGVzW2xvZ1R5cGVdIHx8IGxvZ0ZpbGVzLnBocDtcblxuICAgICAgICAgIGZvciAoY29uc3QgbG9nTmFtZSBvZiB0YXJnZXRMb2dzKSB7XG4gICAgICAgICAgICAvLyBDaGVjayBmb3IgZXJyb3IgYW5kIGFjY2VzcyBsb2dzXG4gICAgICAgICAgICBmb3IgKGNvbnN0IHN1ZmZpeCBvZiBbJ2Vycm9yLmxvZycsICdhY2Nlc3MubG9nJywgJy5sb2cnXSkge1xuICAgICAgICAgICAgICBjb25zdCBsb2dQYXRoID0gcGF0aE1vZHVsZS5qb2luKFxuICAgICAgICAgICAgICAgIGxvZ3NEaXIsXG4gICAgICAgICAgICAgICAgYCR7bG9nTmFtZX0ke3N1ZmZpeCA9PT0gJy5sb2cnID8gJycgOiAnLyd9JHtzdWZmaXh9YFxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICBjb25zdCBhbHRMb2dQYXRoID0gcGF0aE1vZHVsZS5qb2luKGxvZ3NEaXIsIGAke2xvZ05hbWV9JHtzdWZmaXh9YCk7XG5cbiAgICAgICAgICAgICAgbGV0IGZpbmFsUGF0aDogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG4gICAgICAgICAgICAgIGlmIChhd2FpdCBmaWxlRXhpc3RzKGxvZ1BhdGgpKSB7XG4gICAgICAgICAgICAgICAgZmluYWxQYXRoID0gbG9nUGF0aDtcbiAgICAgICAgICAgICAgfSBlbHNlIGlmIChhd2FpdCBmaWxlRXhpc3RzKGFsdExvZ1BhdGgpKSB7XG4gICAgICAgICAgICAgICAgZmluYWxQYXRoID0gYWx0TG9nUGF0aDtcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIGlmIChmaW5hbFBhdGgpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBjb250ZW50ID0gYXdhaXQgcmVhZExhc3RMaW5lcyhmaW5hbFBhdGgsIGxpbmVzKTtcbiAgICAgICAgICAgICAgICBpZiAoY29udGVudCkge1xuICAgICAgICAgICAgICAgICAgbG9ncy5wdXNoKHtcbiAgICAgICAgICAgICAgICAgICAgdHlwZTogbG9nTmFtZSxcbiAgICAgICAgICAgICAgICAgICAgY29udGVudCxcbiAgICAgICAgICAgICAgICAgICAgcGF0aDogZmluYWxQYXRoLFxuICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKGxvZ3MubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICAvLyBUcnkgdG8gZmluZCBhbnkgbG9nIGZpbGVzXG4gICAgICAgICAgICBpZiAoYXdhaXQgZmlsZUV4aXN0cyhsb2dzRGlyKSkge1xuICAgICAgICAgICAgICBjb25zdCBlbnRyaWVzID0gYXdhaXQgZnNQcm9taXNlcy5yZWFkZGlyKGxvZ3NEaXIsIHsgd2l0aEZpbGVUeXBlczogdHJ1ZSB9KTtcbiAgICAgICAgICAgICAgZm9yIChjb25zdCBlbnRyeSBvZiBlbnRyaWVzKSB7XG4gICAgICAgICAgICAgICAgaWYgKGVudHJ5LmlzRGlyZWN0b3J5KCkpIHtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IHN1YkRpciA9IHBhdGhNb2R1bGUuam9pbihsb2dzRGlyLCBlbnRyeS5uYW1lKTtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IHN1YkVudHJpZXMgPSBhd2FpdCBmc1Byb21pc2VzLnJlYWRkaXIoc3ViRGlyKTtcbiAgICAgICAgICAgICAgICAgIGZvciAoY29uc3Qgc3ViRmlsZSBvZiBzdWJFbnRyaWVzKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChzdWJGaWxlLmVuZHNXaXRoKCcubG9nJykpIHtcbiAgICAgICAgICAgICAgICAgICAgICBjb25zdCBsb2dQYXRoID0gcGF0aE1vZHVsZS5qb2luKHN1YkRpciwgc3ViRmlsZSk7XG4gICAgICAgICAgICAgICAgICAgICAgY29uc3QgY29udGVudCA9IGF3YWl0IHJlYWRMYXN0TGluZXMobG9nUGF0aCwgbGluZXMpO1xuICAgICAgICAgICAgICAgICAgICAgIGlmIChjb250ZW50KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBsb2dzLnB1c2goe1xuICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiBlbnRyeS5uYW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgICBjb250ZW50LFxuICAgICAgICAgICAgICAgICAgICAgICAgICBwYXRoOiBsb2dQYXRoLFxuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChlbnRyeS5uYW1lLmVuZHNXaXRoKCcubG9nJykpIHtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IGxvZ1BhdGggPSBwYXRoTW9kdWxlLmpvaW4obG9nc0RpciwgZW50cnkubmFtZSk7XG4gICAgICAgICAgICAgICAgICBjb25zdCBjb250ZW50ID0gYXdhaXQgcmVhZExhc3RMaW5lcyhsb2dQYXRoLCBsaW5lcyk7XG4gICAgICAgICAgICAgICAgICBpZiAoY29udGVudCkge1xuICAgICAgICAgICAgICAgICAgICBsb2dzLnB1c2goe1xuICAgICAgICAgICAgICAgICAgICAgIHR5cGU6IGVudHJ5Lm5hbWUucmVwbGFjZSgnLmxvZycsICcnKSxcbiAgICAgICAgICAgICAgICAgICAgICBjb250ZW50LFxuICAgICAgICAgICAgICAgICAgICAgIHBhdGg6IGxvZ1BhdGgsXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICAgICAgZXJyb3I6IG51bGwsXG4gICAgICAgICAgICBsb2dzLFxuICAgICAgICAgIH07XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yOiBhbnkpIHtcbiAgICAgICAgICBsb2NhbExvZ2dlci5lcnJvcihgWyR7QURET05fTkFNRX1dIEZhaWxlZCB0byBnZXQgbG9nczpgLCBlcnJvcik7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgZXJyb3I6IGVycm9yLm1lc3NhZ2UgfHwgJ1Vua25vd24gZXJyb3InLFxuICAgICAgICAgICAgbG9nczogW10sXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgfSxcblxuICAgICAgLy8gUGhhc2UgMTA6IENsb3VkIEJhY2t1cCBNdXRhdGlvbnNcbiAgICAgIGNyZWF0ZUJhY2t1cDogYXN5bmMgKFxuICAgICAgICBfcGFyZW50OiBhbnksXG4gICAgICAgIGFyZ3M6IHsgc2l0ZUlkOiBzdHJpbmc7IHByb3ZpZGVyOiBzdHJpbmc7IG5vdGU/OiBzdHJpbmcgfVxuICAgICAgKSA9PiB7XG4gICAgICAgIGNvbnN0IHsgc2l0ZUlkLCBwcm92aWRlciwgbm90ZSB9ID0gYXJncztcblxuICAgICAgICB0cnkge1xuICAgICAgICAgIGxvY2FsTG9nZ2VyLmluZm8oYFske0FERE9OX05BTUV9XSBDcmVhdGluZyBiYWNrdXAgZm9yIHNpdGUgJHtzaXRlSWR9IHRvICR7cHJvdmlkZXJ9YCk7XG5cbiAgICAgICAgICAvLyBHZXQgc2l0ZVxuICAgICAgICAgIGNvbnN0IHNpdGUgPSBzaXRlRGF0YS5nZXRTaXRlKHNpdGVJZCk7XG4gICAgICAgICAgaWYgKCFzaXRlKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgc25hcHNob3RJZDogbnVsbCxcbiAgICAgICAgICAgICAgdGltZXN0YW1wOiBudWxsLFxuICAgICAgICAgICAgICBtZXNzYWdlOiBudWxsLFxuICAgICAgICAgICAgICBlcnJvcjogYFNpdGUgbm90IGZvdW5kOiAke3NpdGVJZH1gLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBHZXQgcHJvdmlkZXJzIGZyb20gQ2xvdWQgQmFja3VwcyBhZGRvblxuICAgICAgICAgIGNvbnN0IHByb3ZpZGVycyA9IGF3YWl0IGdldEJhY2t1cFByb3ZpZGVycygpO1xuICAgICAgICAgIGlmIChwcm92aWRlcnMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgc25hcHNob3RJZDogbnVsbCxcbiAgICAgICAgICAgICAgdGltZXN0YW1wOiBudWxsLFxuICAgICAgICAgICAgICBtZXNzYWdlOiBudWxsLFxuICAgICAgICAgICAgICBlcnJvcjpcbiAgICAgICAgICAgICAgICAnTm8gY2xvdWQgc3RvcmFnZSBwcm92aWRlcnMgY29uZmlndXJlZC4gQ29ubmVjdCBHb29nbGUgRHJpdmUgb3IgRHJvcGJveCBpbiBMb2NhbCBIdWIuJyxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gRmluZCB0aGUgbWF0Y2hpbmcgcHJvdmlkZXIgKG1hcCAnZ29vZ2xlRHJpdmUnIHRvICdnb29nbGUnIGZvciB0aGUgYWRkb24pXG4gICAgICAgICAgY29uc3QgcHJvdmlkZXJNYXA6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7IGdvb2dsZURyaXZlOiAnZ29vZ2xlJywgZHJvcGJveDogJ2Ryb3Bib3gnIH07XG4gICAgICAgICAgY29uc3QgcHJvdmlkZXJJZCA9IHByb3ZpZGVyTWFwW3Byb3ZpZGVyXSB8fCBwcm92aWRlcjtcbiAgICAgICAgICBjb25zdCBtYXRjaGVkUHJvdmlkZXIgPSBwcm92aWRlcnMuZmluZCgocDogYW55KSA9PiBwLmlkID09PSBwcm92aWRlcklkKTtcblxuICAgICAgICAgIGlmICghbWF0Y2hlZFByb3ZpZGVyKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgc25hcHNob3RJZDogbnVsbCxcbiAgICAgICAgICAgICAgdGltZXN0YW1wOiBudWxsLFxuICAgICAgICAgICAgICBtZXNzYWdlOiBudWxsLFxuICAgICAgICAgICAgICBlcnJvcjogYFByb3ZpZGVyICcke3Byb3ZpZGVyfScgbm90IGNvbmZpZ3VyZWQuIEF2YWlsYWJsZTogJHtwcm92aWRlcnMubWFwKChwOiBhbnkpID0+IHAubmFtZSkuam9pbignLCAnKX1gLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBNYXAgdGhlIEh1YiBwcm92aWRlciBJRCB0byByY2xvbmUgYmFja2VuZCBuYW1lXG4gICAgICAgICAgLy8gVGhlIGFkZG9uIHVzZXMgJ2dvb2dsZScgaW4gZW5hYmxlZC1wcm92aWRlcnMgYnV0IGV4cGVjdHMgJ2RyaXZlJyBmb3IgYmFja3VwIG9wZXJhdGlvbnNcbiAgICAgICAgICBjb25zdCBiYWNrdXBQcm92aWRlck1hcDogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHsgZ29vZ2xlOiAnZHJpdmUnLCBkcm9wYm94OiAnZHJvcGJveCcgfTtcbiAgICAgICAgICBjb25zdCBiYWNrdXBQcm92aWRlcklkID0gYmFja3VwUHJvdmlkZXJNYXBbbWF0Y2hlZFByb3ZpZGVyLmlkXSB8fCBtYXRjaGVkUHJvdmlkZXIuaWQ7XG4gICAgICAgICAgbG9jYWxMb2dnZXIuaW5mbyhcbiAgICAgICAgICAgIGBbJHtBRERPTl9OQU1FfV0gVXNpbmcgYmFja3VwIHByb3ZpZGVyIElEOiAke2JhY2t1cFByb3ZpZGVySWR9IChmcm9tICR7bWF0Y2hlZFByb3ZpZGVyLmlkfSlgXG4gICAgICAgICAgKTtcblxuICAgICAgICAgIC8vIENyZWF0ZSBiYWNrdXAgdmlhIElQQyAodXNlIGxvbmcgdGltZW91dCBmb3IgYmFja3VwIG9wZXJhdGlvbnMpXG4gICAgICAgICAgY29uc3QgZGVzY3JpcHRpb24gPSBub3RlIHx8ICdCYWNrdXAgY3JlYXRlZCB2aWEgTUNQJztcbiAgICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBpbnZva2VCYWNrdXBJUEMoXG4gICAgICAgICAgICAnYmFja3VwczpiYWNrdXAtc2l0ZScsXG4gICAgICAgICAgICBCQUNLVVBfSVBDX1RJTUVPVVQsXG4gICAgICAgICAgICBzaXRlSWQsXG4gICAgICAgICAgICBiYWNrdXBQcm92aWRlcklkLFxuICAgICAgICAgICAgZGVzY3JpcHRpb25cbiAgICAgICAgICApO1xuICAgICAgICAgIGxvY2FsTG9nZ2VyLmluZm8oYFske0FERE9OX05BTUV9XSBCYWNrdXAgSVBDIHJlc3VsdDogJHtKU09OLnN0cmluZ2lmeShyZXN1bHQpfWApO1xuXG4gICAgICAgICAgLy8gQ2hlY2sgZm9yIHRvcC1sZXZlbCBJUEMgZXJyb3JcbiAgICAgICAgICBpZiAocmVzdWx0LmVycm9yKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgc25hcHNob3RJZDogbnVsbCxcbiAgICAgICAgICAgICAgdGltZXN0YW1wOiBudWxsLFxuICAgICAgICAgICAgICBtZXNzYWdlOiBudWxsLFxuICAgICAgICAgICAgICBlcnJvcjogcmVzdWx0LmVycm9yLm1lc3NhZ2UgfHwgJ0JhY2t1cCBjcmVhdGlvbiBmYWlsZWQnLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBVbndyYXAgbmVzdGVkIHJlc3VsdCBzdHJ1Y3R1cmUgLSB0aGUgYWN0dWFsIHJlc3VsdCBpcyBhdCByZXN1bHQucmVzdWx0XG4gICAgICAgICAgY29uc3QgYmFja3VwUmVzdWx0ID0gcmVzdWx0LnJlc3VsdDtcblxuICAgICAgICAgIC8vIENoZWNrIGlmIHRoZSBiYWNrdXAgcmVzdWx0IGNvbnRhaW5zIGFuIGVycm9yIChuZXN0ZWQgYXQgcmVzdWx0LnJlc3VsdC5lcnJvcilcbiAgICAgICAgICBpZiAoYmFja3VwUmVzdWx0Py5lcnJvcikge1xuICAgICAgICAgICAgY29uc3QgZXJyb3JNc2cgPVxuICAgICAgICAgICAgICBiYWNrdXBSZXN1bHQuZXJyb3IubWVzc2FnZSB8fCBiYWNrdXBSZXN1bHQuZXJyb3Iub3JpZ2luYWw/Lm1lc3NhZ2UgfHwgJ0JhY2t1cCBmYWlsZWQnO1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICAgIHNuYXBzaG90SWQ6IG51bGwsXG4gICAgICAgICAgICAgIHRpbWVzdGFtcDogbnVsbCxcbiAgICAgICAgICAgICAgbWVzc2FnZTogbnVsbCxcbiAgICAgICAgICAgICAgZXJyb3I6IGVycm9yTXNnLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBUcnkgdG8gZXh0cmFjdCBzbmFwc2hvdCBJRCAobWF5IGJlIG5lc3RlZCBpbiByZXN1bHQucmVzdWx0LnJlc3VsdClcbiAgICAgICAgICBsZXQgc25hcHNob3RJZCA9IGJhY2t1cFJlc3VsdD8uc25hcHNob3RJZCB8fCBiYWNrdXBSZXN1bHQ/LmlkO1xuICAgICAgICAgIGlmICghc25hcHNob3RJZCAmJiBiYWNrdXBSZXN1bHQ/LnJlc3VsdCkge1xuICAgICAgICAgICAgc25hcHNob3RJZCA9IGJhY2t1cFJlc3VsdC5yZXN1bHQuc25hcHNob3RJZCB8fCBiYWNrdXBSZXN1bHQucmVzdWx0LmlkO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIElmIG5vIGVycm9yIHdhcyByZXR1cm5lZCwgdGhlIGJhY2t1cCBzdWNjZWVkZWQgZXZlbiBpZiBubyBzbmFwc2hvdCBJRCBpcyBwcm92aWRlZFxuICAgICAgICAgIC8vIFRoZSBhZGRvbiBkb2Vzbid0IGFsd2F5cyByZXR1cm4gdGhlIHNuYXBzaG90IElEIGluIGl0cyBJUEMgcmVzcG9uc2VcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgICAgICAgIHNuYXBzaG90SWQ6IHNuYXBzaG90SWQgfHwgbnVsbCxcbiAgICAgICAgICAgIHRpbWVzdGFtcDogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgICAgICAgICAgbWVzc2FnZTogYEJhY2t1cCBjcmVhdGVkIHN1Y2Nlc3NmdWxseSB0byAke21hdGNoZWRQcm92aWRlci5uYW1lfWAsXG4gICAgICAgICAgICBlcnJvcjogbnVsbCxcbiAgICAgICAgICB9O1xuICAgICAgICB9IGNhdGNoIChlcnJvcjogYW55KSB7XG4gICAgICAgICAgbG9jYWxMb2dnZXIuZXJyb3IoYFske0FERE9OX05BTUV9XSBGYWlsZWQgdG8gY3JlYXRlIGJhY2t1cDpgLCBlcnJvcik7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgc25hcHNob3RJZDogbnVsbCxcbiAgICAgICAgICAgIHRpbWVzdGFtcDogbnVsbCxcbiAgICAgICAgICAgIG1lc3NhZ2U6IG51bGwsXG4gICAgICAgICAgICBlcnJvcjogZXJyb3IubWVzc2FnZSB8fCAnVW5rbm93biBlcnJvcicsXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgfSxcblxuICAgICAgcmVzdG9yZUJhY2t1cDogYXN5bmMgKFxuICAgICAgICBfcGFyZW50OiBhbnksXG4gICAgICAgIGFyZ3M6IHsgc2l0ZUlkOiBzdHJpbmc7IHByb3ZpZGVyOiBzdHJpbmc7IHNuYXBzaG90SWQ6IHN0cmluZzsgY29uZmlybT86IGJvb2xlYW4gfVxuICAgICAgKSA9PiB7XG4gICAgICAgIGNvbnN0IHsgc2l0ZUlkLCBwcm92aWRlciwgc25hcHNob3RJZCwgY29uZmlybSA9IGZhbHNlIH0gPSBhcmdzO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgbG9jYWxMb2dnZXIuaW5mbyhgWyR7QURET05fTkFNRX1dIFJlc3RvcmluZyBiYWNrdXAgJHtzbmFwc2hvdElkfSBmb3Igc2l0ZSAke3NpdGVJZH1gKTtcblxuICAgICAgICAgIC8vIENoZWNrIGNvbmZpcm1hdGlvblxuICAgICAgICAgIGlmICghY29uZmlybSkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICAgIG1lc3NhZ2U6IG51bGwsXG4gICAgICAgICAgICAgIGVycm9yOlxuICAgICAgICAgICAgICAgICdSZXN0b3JlIHJlcXVpcmVzIGNvbmZpcm09dHJ1ZSB0byBwcmV2ZW50IGFjY2lkZW50YWwgZGF0YSBsb3NzLiBDdXJyZW50IHNpdGUgZmlsZXMgYW5kIGRhdGFiYXNlIHdpbGwgYmUgb3ZlcndyaXR0ZW4uJyxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gR2V0IHNpdGVcbiAgICAgICAgICBjb25zdCBzaXRlID0gc2l0ZURhdGEuZ2V0U2l0ZShzaXRlSWQpO1xuICAgICAgICAgIGlmICghc2l0ZSkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICAgIG1lc3NhZ2U6IG51bGwsXG4gICAgICAgICAgICAgIGVycm9yOiBgU2l0ZSBub3QgZm91bmQ6ICR7c2l0ZUlkfWAsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIEdldCBwcm92aWRlcnMgZnJvbSBDbG91ZCBCYWNrdXBzIGFkZG9uXG4gICAgICAgICAgY29uc3QgcHJvdmlkZXJzID0gYXdhaXQgZ2V0QmFja3VwUHJvdmlkZXJzKCk7XG4gICAgICAgICAgaWYgKHByb3ZpZGVycy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICBtZXNzYWdlOiBudWxsLFxuICAgICAgICAgICAgICBlcnJvcjpcbiAgICAgICAgICAgICAgICAnTm8gY2xvdWQgc3RvcmFnZSBwcm92aWRlcnMgY29uZmlndXJlZC4gQ29ubmVjdCBHb29nbGUgRHJpdmUgb3IgRHJvcGJveCBpbiBMb2NhbCBIdWIuJyxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gRmluZCB0aGUgbWF0Y2hpbmcgcHJvdmlkZXIgKG1hcCAnZ29vZ2xlRHJpdmUnIHRvICdnb29nbGUnIGZvciB0aGUgYWRkb24pXG4gICAgICAgICAgY29uc3QgcHJvdmlkZXJNYXA6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7IGdvb2dsZURyaXZlOiAnZ29vZ2xlJywgZHJvcGJveDogJ2Ryb3Bib3gnIH07XG4gICAgICAgICAgY29uc3QgcHJvdmlkZXJJZCA9IHByb3ZpZGVyTWFwW3Byb3ZpZGVyXSB8fCBwcm92aWRlcjtcbiAgICAgICAgICBjb25zdCBtYXRjaGVkUHJvdmlkZXIgPSBwcm92aWRlcnMuZmluZCgocDogYW55KSA9PiBwLmlkID09PSBwcm92aWRlcklkKTtcblxuICAgICAgICAgIGlmICghbWF0Y2hlZFByb3ZpZGVyKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgbWVzc2FnZTogbnVsbCxcbiAgICAgICAgICAgICAgZXJyb3I6IGBQcm92aWRlciAnJHtwcm92aWRlcn0nIG5vdCBjb25maWd1cmVkLiBBdmFpbGFibGU6ICR7cHJvdmlkZXJzLm1hcCgocDogYW55KSA9PiBwLm5hbWUpLmpvaW4oJywgJyl9YCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gTWFwIHRoZSBIdWIgcHJvdmlkZXIgSUQgdG8gcmNsb25lIGJhY2tlbmQgbmFtZVxuICAgICAgICAgIGNvbnN0IGJhY2t1cFByb3ZpZGVyTWFwOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0geyBnb29nbGU6ICdkcml2ZScsIGRyb3Bib3g6ICdkcm9wYm94JyB9O1xuICAgICAgICAgIGNvbnN0IGJhY2t1cFByb3ZpZGVySWQgPSBiYWNrdXBQcm92aWRlck1hcFttYXRjaGVkUHJvdmlkZXIuaWRdIHx8IG1hdGNoZWRQcm92aWRlci5pZDtcblxuICAgICAgICAgIC8vIFJlc3RvcmUgYmFja3VwIHZpYSBJUEMgKHVzZSBsb25nIHRpbWVvdXQgZm9yIHJlc3RvcmUgb3BlcmF0aW9ucylcbiAgICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBpbnZva2VCYWNrdXBJUEMoXG4gICAgICAgICAgICAnYmFja3VwczpyZXN0b3JlLWJhY2t1cCcsXG4gICAgICAgICAgICBCQUNLVVBfSVBDX1RJTUVPVVQsXG4gICAgICAgICAgICBzaXRlSWQsXG4gICAgICAgICAgICBiYWNrdXBQcm92aWRlcklkLFxuICAgICAgICAgICAgc25hcHNob3RJZFxuICAgICAgICAgICk7XG4gICAgICAgICAgbG9jYWxMb2dnZXIuaW5mbyhgWyR7QURET05fTkFNRX1dIFJlc3RvcmUgcmVzdWx0OiAke0pTT04uc3RyaW5naWZ5KHJlc3VsdCl9YCk7XG5cbiAgICAgICAgICAvLyBDaGVjayBmb3IgZXJyb3JzIC0gY2FuIGJlIGF0IHJlc3VsdC5lcnJvciBvciByZXN1bHQucmVzdWx0LmVycm9yIChJUEMgYXN5bmMgcGF0dGVybilcbiAgICAgICAgICBjb25zdCBpcGNFcnJvciA9IHJlc3VsdC5lcnJvciB8fCByZXN1bHQucmVzdWx0Py5lcnJvcjtcbiAgICAgICAgICBpZiAoaXBjRXJyb3IpIHtcbiAgICAgICAgICAgIGNvbnN0IGVycm9yTWVzc2FnZSA9XG4gICAgICAgICAgICAgIHR5cGVvZiBpcGNFcnJvciA9PT0gJ3N0cmluZycgPyBpcGNFcnJvciA6IGlwY0Vycm9yLm1lc3NhZ2UgfHwgJ1Jlc3RvcmUgZmFpbGVkJztcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICBtZXNzYWdlOiBudWxsLFxuICAgICAgICAgICAgICBlcnJvcjogZXJyb3JNZXNzYWdlLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgICAgICAgIG1lc3NhZ2U6IGBTaXRlIHJlc3RvcmVkIGZyb20gYmFja3VwICR7c25hcHNob3RJZH1gLFxuICAgICAgICAgICAgZXJyb3I6IG51bGwsXG4gICAgICAgICAgfTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgICAgICAgIGxvY2FsTG9nZ2VyLmVycm9yKGBbJHtBRERPTl9OQU1FfV0gRmFpbGVkIHRvIHJlc3RvcmUgYmFja3VwOmAsIGVycm9yKTtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICBtZXNzYWdlOiBudWxsLFxuICAgICAgICAgICAgZXJyb3I6IGVycm9yLm1lc3NhZ2UgfHwgJ1Vua25vd24gZXJyb3InLFxuICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgIH0sXG5cbiAgICAgIGRlbGV0ZUJhY2t1cDogYXN5bmMgKFxuICAgICAgICBfcGFyZW50OiBhbnksXG4gICAgICAgIGFyZ3M6IHsgc2l0ZUlkOiBzdHJpbmc7IHByb3ZpZGVyOiBzdHJpbmc7IHNuYXBzaG90SWQ6IHN0cmluZzsgY29uZmlybT86IGJvb2xlYW4gfVxuICAgICAgKSA9PiB7XG4gICAgICAgIGNvbnN0IHsgc2l0ZUlkLCBwcm92aWRlciwgc25hcHNob3RJZCwgY29uZmlybSA9IGZhbHNlIH0gPSBhcmdzO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgbG9jYWxMb2dnZXIuaW5mbyhgWyR7QURET05fTkFNRX1dIERlbGV0aW5nIGJhY2t1cCAke3NuYXBzaG90SWR9IGZvciBzaXRlICR7c2l0ZUlkfWApO1xuXG4gICAgICAgICAgLy8gQ2hlY2sgY29uZmlybWF0aW9uXG4gICAgICAgICAgaWYgKCFjb25maXJtKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgZGVsZXRlZFNuYXBzaG90SWQ6IG51bGwsXG4gICAgICAgICAgICAgIG1lc3NhZ2U6IG51bGwsXG4gICAgICAgICAgICAgIGVycm9yOiAnRGVsZXRlIHJlcXVpcmVzIGNvbmZpcm09dHJ1ZSB0byBwcmV2ZW50IGFjY2lkZW50YWwgZGVsZXRpb24uJyxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gR2V0IHNpdGVcbiAgICAgICAgICBjb25zdCBzaXRlID0gc2l0ZURhdGEuZ2V0U2l0ZShzaXRlSWQpO1xuICAgICAgICAgIGlmICghc2l0ZSkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICAgIGRlbGV0ZWRTbmFwc2hvdElkOiBudWxsLFxuICAgICAgICAgICAgICBtZXNzYWdlOiBudWxsLFxuICAgICAgICAgICAgICBlcnJvcjogYFNpdGUgbm90IGZvdW5kOiAke3NpdGVJZH1gLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBHZXQgcHJvdmlkZXJzIGZyb20gQ2xvdWQgQmFja3VwcyBhZGRvblxuICAgICAgICAgIGNvbnN0IHByb3ZpZGVycyA9IGF3YWl0IGdldEJhY2t1cFByb3ZpZGVycygpO1xuICAgICAgICAgIGlmIChwcm92aWRlcnMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgZGVsZXRlZFNuYXBzaG90SWQ6IG51bGwsXG4gICAgICAgICAgICAgIG1lc3NhZ2U6IG51bGwsXG4gICAgICAgICAgICAgIGVycm9yOlxuICAgICAgICAgICAgICAgICdObyBjbG91ZCBzdG9yYWdlIHByb3ZpZGVycyBjb25maWd1cmVkLiBDb25uZWN0IEdvb2dsZSBEcml2ZSBvciBEcm9wYm94IGluIExvY2FsIEh1Yi4nLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBGaW5kIHRoZSBtYXRjaGluZyBwcm92aWRlciAobWFwICdnb29nbGVEcml2ZScgdG8gJ2dvb2dsZScgZm9yIHRoZSBhZGRvbilcbiAgICAgICAgICBjb25zdCBwcm92aWRlck1hcDogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHsgZ29vZ2xlRHJpdmU6ICdnb29nbGUnLCBkcm9wYm94OiAnZHJvcGJveCcgfTtcbiAgICAgICAgICBjb25zdCBwcm92aWRlcklkID0gcHJvdmlkZXJNYXBbcHJvdmlkZXJdIHx8IHByb3ZpZGVyO1xuICAgICAgICAgIGNvbnN0IG1hdGNoZWRQcm92aWRlciA9IHByb3ZpZGVycy5maW5kKChwOiBhbnkpID0+IHAuaWQgPT09IHByb3ZpZGVySWQpO1xuXG4gICAgICAgICAgaWYgKCFtYXRjaGVkUHJvdmlkZXIpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICBkZWxldGVkU25hcHNob3RJZDogbnVsbCxcbiAgICAgICAgICAgICAgbWVzc2FnZTogbnVsbCxcbiAgICAgICAgICAgICAgZXJyb3I6IGBQcm92aWRlciAnJHtwcm92aWRlcn0nIG5vdCBjb25maWd1cmVkLiBBdmFpbGFibGU6ICR7cHJvdmlkZXJzLm1hcCgocDogYW55KSA9PiBwLm5hbWUpLmpvaW4oJywgJyl9YCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gTWFwIHRoZSBIdWIgcHJvdmlkZXIgSUQgdG8gcmNsb25lIGJhY2tlbmQgbmFtZVxuICAgICAgICAgIGNvbnN0IGJhY2t1cFByb3ZpZGVyTWFwOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0geyBnb29nbGU6ICdkcml2ZScsIGRyb3Bib3g6ICdkcm9wYm94JyB9O1xuICAgICAgICAgIGNvbnN0IGJhY2t1cFByb3ZpZGVySWQgPSBiYWNrdXBQcm92aWRlck1hcFttYXRjaGVkUHJvdmlkZXIuaWRdIHx8IG1hdGNoZWRQcm92aWRlci5pZDtcblxuICAgICAgICAgIC8vIFRyeSB0byBkZWxldGUgYmFja3VwIHZpYSBJUEMgKG1heSBub3QgYmUgc3VwcG9ydGVkIGJ5IHRoZSBhZGRvbilcbiAgICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBpbnZva2VCYWNrdXBJUEMoXG4gICAgICAgICAgICAnYmFja3VwczpkZWxldGUtYmFja3VwJyxcbiAgICAgICAgICAgIERFRkFVTFRfSVBDX1RJTUVPVVQsXG4gICAgICAgICAgICBzaXRlSWQsXG4gICAgICAgICAgICBiYWNrdXBQcm92aWRlcklkLFxuICAgICAgICAgICAgc25hcHNob3RJZFxuICAgICAgICAgICk7XG5cbiAgICAgICAgICBpZiAocmVzdWx0LmVycm9yKSB7XG4gICAgICAgICAgICAvLyBJZiB0aGUgSVBDIGNoYW5uZWwgZG9lc24ndCBleGlzdCBvciBpc24ndCBzdXBwb3J0ZWQsIHByb3ZpZGUgaGVscGZ1bCBtZXNzYWdlXG4gICAgICAgICAgICBpZiAocmVzdWx0LmVycm9yLm1lc3NhZ2U/LmluY2x1ZGVzKCd0aW1lZCBvdXQnKSkge1xuICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICAgIGRlbGV0ZWRTbmFwc2hvdElkOiBudWxsLFxuICAgICAgICAgICAgICAgIG1lc3NhZ2U6IG51bGwsXG4gICAgICAgICAgICAgICAgZXJyb3I6XG4gICAgICAgICAgICAgICAgICAnRGVsZXRlIGJhY2t1cCBvcGVyYXRpb24gaXMgbm90IGF2YWlsYWJsZSB2aWEgTUNQLiBQbGVhc2UgZGVsZXRlIGJhY2t1cHMgdGhyb3VnaCB0aGUgTG9jYWwgVUkuJyxcbiAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICBkZWxldGVkU25hcHNob3RJZDogbnVsbCxcbiAgICAgICAgICAgICAgbWVzc2FnZTogbnVsbCxcbiAgICAgICAgICAgICAgZXJyb3I6IHJlc3VsdC5lcnJvci5tZXNzYWdlIHx8ICdEZWxldGUgZmFpbGVkJyxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgICBkZWxldGVkU25hcHNob3RJZDogc25hcHNob3RJZCxcbiAgICAgICAgICAgIG1lc3NhZ2U6ICdCYWNrdXAgZGVsZXRlZCcsXG4gICAgICAgICAgICBlcnJvcjogbnVsbCxcbiAgICAgICAgICB9O1xuICAgICAgICB9IGNhdGNoIChlcnJvcjogYW55KSB7XG4gICAgICAgICAgbG9jYWxMb2dnZXIuZXJyb3IoYFske0FERE9OX05BTUV9XSBGYWlsZWQgdG8gZGVsZXRlIGJhY2t1cDpgLCBlcnJvcik7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgZGVsZXRlZFNuYXBzaG90SWQ6IG51bGwsXG4gICAgICAgICAgICBtZXNzYWdlOiBudWxsLFxuICAgICAgICAgICAgZXJyb3I6IGVycm9yLm1lc3NhZ2UgfHwgJ1Vua25vd24gZXJyb3InLFxuICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgIH0sXG5cbiAgICAgIGRvd25sb2FkQmFja3VwOiBhc3luYyAoXG4gICAgICAgIF9wYXJlbnQ6IGFueSxcbiAgICAgICAgYXJnczogeyBzaXRlSWQ6IHN0cmluZzsgcHJvdmlkZXI6IHN0cmluZzsgc25hcHNob3RJZDogc3RyaW5nIH1cbiAgICAgICkgPT4ge1xuICAgICAgICBjb25zdCB7IHNpdGVJZCwgcHJvdmlkZXIsIHNuYXBzaG90SWQgfSA9IGFyZ3M7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBsb2NhbExvZ2dlci5pbmZvKGBbJHtBRERPTl9OQU1FfV0gRG93bmxvYWRpbmcgYmFja3VwICR7c25hcHNob3RJZH0gZm9yIHNpdGUgJHtzaXRlSWR9YCk7XG5cbiAgICAgICAgICAvLyBHZXQgc2l0ZVxuICAgICAgICAgIGNvbnN0IHNpdGUgPSBzaXRlRGF0YS5nZXRTaXRlKHNpdGVJZCk7XG4gICAgICAgICAgaWYgKCFzaXRlKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgZmlsZVBhdGg6IG51bGwsXG4gICAgICAgICAgICAgIG1lc3NhZ2U6IG51bGwsXG4gICAgICAgICAgICAgIGVycm9yOiBgU2l0ZSBub3QgZm91bmQ6ICR7c2l0ZUlkfWAsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIEdldCBwcm92aWRlcnMgZnJvbSBDbG91ZCBCYWNrdXBzIGFkZG9uXG4gICAgICAgICAgY29uc3QgcHJvdmlkZXJzID0gYXdhaXQgZ2V0QmFja3VwUHJvdmlkZXJzKCk7XG4gICAgICAgICAgaWYgKHByb3ZpZGVycy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICBmaWxlUGF0aDogbnVsbCxcbiAgICAgICAgICAgICAgbWVzc2FnZTogbnVsbCxcbiAgICAgICAgICAgICAgZXJyb3I6XG4gICAgICAgICAgICAgICAgJ05vIGNsb3VkIHN0b3JhZ2UgcHJvdmlkZXJzIGNvbmZpZ3VyZWQuIENvbm5lY3QgR29vZ2xlIERyaXZlIG9yIERyb3Bib3ggaW4gTG9jYWwgSHViLicsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIEZpbmQgdGhlIG1hdGNoaW5nIHByb3ZpZGVyIChtYXAgJ2dvb2dsZURyaXZlJyB0byAnZ29vZ2xlJyBmb3IgdGhlIGFkZG9uKVxuICAgICAgICAgIGNvbnN0IHByb3ZpZGVyTWFwOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0geyBnb29nbGVEcml2ZTogJ2dvb2dsZScsIGRyb3Bib3g6ICdkcm9wYm94JyB9O1xuICAgICAgICAgIGNvbnN0IHByb3ZpZGVySWQgPSBwcm92aWRlck1hcFtwcm92aWRlcl0gfHwgcHJvdmlkZXI7XG4gICAgICAgICAgY29uc3QgbWF0Y2hlZFByb3ZpZGVyID0gcHJvdmlkZXJzLmZpbmQoKHA6IGFueSkgPT4gcC5pZCA9PT0gcHJvdmlkZXJJZCk7XG5cbiAgICAgICAgICBpZiAoIW1hdGNoZWRQcm92aWRlcikge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICAgIGZpbGVQYXRoOiBudWxsLFxuICAgICAgICAgICAgICBtZXNzYWdlOiBudWxsLFxuICAgICAgICAgICAgICBlcnJvcjogYFByb3ZpZGVyICcke3Byb3ZpZGVyfScgbm90IGNvbmZpZ3VyZWQuIEF2YWlsYWJsZTogJHtwcm92aWRlcnMubWFwKChwOiBhbnkpID0+IHAubmFtZSkuam9pbignLCAnKX1gLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBNYXAgdGhlIEh1YiBwcm92aWRlciBJRCB0byByY2xvbmUgYmFja2VuZCBuYW1lXG4gICAgICAgICAgY29uc3QgYmFja3VwUHJvdmlkZXJNYXA6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7IGdvb2dsZTogJ2RyaXZlJywgZHJvcGJveDogJ2Ryb3Bib3gnIH07XG4gICAgICAgICAgY29uc3QgYmFja3VwUHJvdmlkZXJJZCA9IGJhY2t1cFByb3ZpZGVyTWFwW21hdGNoZWRQcm92aWRlci5pZF0gfHwgbWF0Y2hlZFByb3ZpZGVyLmlkO1xuXG4gICAgICAgICAgLy8gVHJ5IHRvIGRvd25sb2FkIGJhY2t1cCB2aWEgSVBDICh1c2UgbG9uZyB0aW1lb3V0IGZvciBkb3dubG9hZHMpXG4gICAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgaW52b2tlQmFja3VwSVBDKFxuICAgICAgICAgICAgJ2JhY2t1cHM6ZG93bmxvYWQtYmFja3VwJyxcbiAgICAgICAgICAgIEJBQ0tVUF9JUENfVElNRU9VVCxcbiAgICAgICAgICAgIHNpdGVJZCxcbiAgICAgICAgICAgIGJhY2t1cFByb3ZpZGVySWQsXG4gICAgICAgICAgICBzbmFwc2hvdElkXG4gICAgICAgICAgKTtcblxuICAgICAgICAgIGlmIChyZXN1bHQuZXJyb3IpIHtcbiAgICAgICAgICAgIC8vIElmIHRoZSBJUEMgY2hhbm5lbCBkb2Vzbid0IGV4aXN0IG9yIGlzbid0IHN1cHBvcnRlZCwgcHJvdmlkZSBoZWxwZnVsIG1lc3NhZ2VcbiAgICAgICAgICAgIGlmIChyZXN1bHQuZXJyb3IubWVzc2FnZT8uaW5jbHVkZXMoJ3RpbWVkIG91dCcpKSB7XG4gICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICAgICAgZmlsZVBhdGg6IG51bGwsXG4gICAgICAgICAgICAgICAgbWVzc2FnZTogbnVsbCxcbiAgICAgICAgICAgICAgICBlcnJvcjpcbiAgICAgICAgICAgICAgICAgICdEb3dubG9hZCBiYWNrdXAgb3BlcmF0aW9uIGlzIG5vdCBhdmFpbGFibGUgdmlhIE1DUC4gUGxlYXNlIGRvd25sb2FkIGJhY2t1cHMgdGhyb3VnaCB0aGUgTG9jYWwgVUkuJyxcbiAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICBmaWxlUGF0aDogbnVsbCxcbiAgICAgICAgICAgICAgbWVzc2FnZTogbnVsbCxcbiAgICAgICAgICAgICAgZXJyb3I6IHJlc3VsdC5lcnJvci5tZXNzYWdlIHx8ICdEb3dubG9hZCBmYWlsZWQnLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgICAgICAgIGZpbGVQYXRoOiByZXN1bHQucmVzdWx0Py5maWxlUGF0aCB8fCBudWxsLFxuICAgICAgICAgICAgbWVzc2FnZTogJ0JhY2t1cCBkb3dubG9hZGVkIHRvIERvd25sb2FkcyBmb2xkZXInLFxuICAgICAgICAgICAgZXJyb3I6IG51bGwsXG4gICAgICAgICAgfTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgICAgICAgIGxvY2FsTG9nZ2VyLmVycm9yKGBbJHtBRERPTl9OQU1FfV0gRmFpbGVkIHRvIGRvd25sb2FkIGJhY2t1cDpgLCBlcnJvcik7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgZmlsZVBhdGg6IG51bGwsXG4gICAgICAgICAgICBtZXNzYWdlOiBudWxsLFxuICAgICAgICAgICAgZXJyb3I6IGVycm9yLm1lc3NhZ2UgfHwgJ1Vua25vd24gZXJyb3InLFxuICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgIH0sXG5cbiAgICAgIGVkaXRCYWNrdXBOb3RlOiBhc3luYyAoXG4gICAgICAgIF9wYXJlbnQ6IGFueSxcbiAgICAgICAgYXJnczogeyBzaXRlSWQ6IHN0cmluZzsgcHJvdmlkZXI6IHN0cmluZzsgc25hcHNob3RJZDogc3RyaW5nOyBub3RlOiBzdHJpbmcgfVxuICAgICAgKSA9PiB7XG4gICAgICAgIGNvbnN0IHsgc2l0ZUlkLCBwcm92aWRlciwgc25hcHNob3RJZCwgbm90ZSB9ID0gYXJncztcblxuICAgICAgICB0cnkge1xuICAgICAgICAgIGxvY2FsTG9nZ2VyLmluZm8oYFske0FERE9OX05BTUV9XSBFZGl0aW5nIGJhY2t1cCBub3RlIGZvciAke3NuYXBzaG90SWR9YCk7XG5cbiAgICAgICAgICAvLyBHZXQgc2l0ZVxuICAgICAgICAgIGNvbnN0IHNpdGUgPSBzaXRlRGF0YS5nZXRTaXRlKHNpdGVJZCk7XG4gICAgICAgICAgaWYgKCFzaXRlKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgc25hcHNob3RJZDogbnVsbCxcbiAgICAgICAgICAgICAgbm90ZTogbnVsbCxcbiAgICAgICAgICAgICAgZXJyb3I6IGBTaXRlIG5vdCBmb3VuZDogJHtzaXRlSWR9YCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gR2V0IHByb3ZpZGVycyBmcm9tIENsb3VkIEJhY2t1cHMgYWRkb25cbiAgICAgICAgICBjb25zdCBwcm92aWRlcnMgPSBhd2FpdCBnZXRCYWNrdXBQcm92aWRlcnMoKTtcbiAgICAgICAgICBpZiAocHJvdmlkZXJzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICAgIHNuYXBzaG90SWQ6IG51bGwsXG4gICAgICAgICAgICAgIG5vdGU6IG51bGwsXG4gICAgICAgICAgICAgIGVycm9yOlxuICAgICAgICAgICAgICAgICdObyBjbG91ZCBzdG9yYWdlIHByb3ZpZGVycyBjb25maWd1cmVkLiBDb25uZWN0IEdvb2dsZSBEcml2ZSBvciBEcm9wYm94IGluIExvY2FsIEh1Yi4nLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBGaW5kIHRoZSBtYXRjaGluZyBwcm92aWRlciAobWFwICdnb29nbGVEcml2ZScgdG8gJ2dvb2dsZScgZm9yIHRoZSBhZGRvbilcbiAgICAgICAgICBjb25zdCBwcm92aWRlck1hcDogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHsgZ29vZ2xlRHJpdmU6ICdnb29nbGUnLCBkcm9wYm94OiAnZHJvcGJveCcgfTtcbiAgICAgICAgICBjb25zdCBwcm92aWRlcklkID0gcHJvdmlkZXJNYXBbcHJvdmlkZXJdIHx8IHByb3ZpZGVyO1xuICAgICAgICAgIGNvbnN0IG1hdGNoZWRQcm92aWRlciA9IHByb3ZpZGVycy5maW5kKChwOiBhbnkpID0+IHAuaWQgPT09IHByb3ZpZGVySWQpO1xuXG4gICAgICAgICAgaWYgKCFtYXRjaGVkUHJvdmlkZXIpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICBzbmFwc2hvdElkOiBudWxsLFxuICAgICAgICAgICAgICBub3RlOiBudWxsLFxuICAgICAgICAgICAgICBlcnJvcjogYFByb3ZpZGVyICcke3Byb3ZpZGVyfScgbm90IGNvbmZpZ3VyZWQuIEF2YWlsYWJsZTogJHtwcm92aWRlcnMubWFwKChwOiBhbnkpID0+IHAubmFtZSkuam9pbignLCAnKX1gLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBNYXAgdGhlIEh1YiBwcm92aWRlciBJRCB0byByY2xvbmUgYmFja2VuZCBuYW1lXG4gICAgICAgICAgY29uc3QgYmFja3VwUHJvdmlkZXJNYXA6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7IGdvb2dsZTogJ2RyaXZlJywgZHJvcGJveDogJ2Ryb3Bib3gnIH07XG4gICAgICAgICAgY29uc3QgYmFja3VwUHJvdmlkZXJJZCA9IGJhY2t1cFByb3ZpZGVyTWFwW21hdGNoZWRQcm92aWRlci5pZF0gfHwgbWF0Y2hlZFByb3ZpZGVyLmlkO1xuXG4gICAgICAgICAgLy8gVHJ5IHRvIGVkaXQgYmFja3VwIG5vdGUgdmlhIElQQyAocXVpY2sgbWV0YWRhdGEgb3BlcmF0aW9uKVxuICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGludm9rZUJhY2t1cElQQyhcbiAgICAgICAgICAgICdiYWNrdXBzOmVkaXQtbm90ZScsXG4gICAgICAgICAgICBERUZBVUxUX0lQQ19USU1FT1VULFxuICAgICAgICAgICAgc2l0ZUlkLFxuICAgICAgICAgICAgYmFja3VwUHJvdmlkZXJJZCxcbiAgICAgICAgICAgIHNuYXBzaG90SWQsXG4gICAgICAgICAgICBub3RlXG4gICAgICAgICAgKTtcblxuICAgICAgICAgIGlmIChyZXN1bHQuZXJyb3IpIHtcbiAgICAgICAgICAgIC8vIElmIHRoZSBJUEMgY2hhbm5lbCBkb2Vzbid0IGV4aXN0IG9yIGlzbid0IHN1cHBvcnRlZCwgcHJvdmlkZSBoZWxwZnVsIG1lc3NhZ2VcbiAgICAgICAgICAgIGlmIChyZXN1bHQuZXJyb3IubWVzc2FnZT8uaW5jbHVkZXMoJ3RpbWVkIG91dCcpKSB7XG4gICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICAgICAgc25hcHNob3RJZDogbnVsbCxcbiAgICAgICAgICAgICAgICBub3RlOiBudWxsLFxuICAgICAgICAgICAgICAgIGVycm9yOlxuICAgICAgICAgICAgICAgICAgJ0VkaXQgYmFja3VwIG5vdGUgb3BlcmF0aW9uIGlzIG5vdCBhdmFpbGFibGUgdmlhIE1DUC4gUGxlYXNlIGVkaXQgYmFja3VwIG5vdGVzIHRocm91Z2ggdGhlIExvY2FsIFVJLicsXG4gICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgc25hcHNob3RJZDogbnVsbCxcbiAgICAgICAgICAgICAgbm90ZTogbnVsbCxcbiAgICAgICAgICAgICAgZXJyb3I6IHJlc3VsdC5lcnJvci5tZXNzYWdlIHx8ICdFZGl0IG5vdGUgZmFpbGVkJyxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgICBzbmFwc2hvdElkLFxuICAgICAgICAgICAgbm90ZSxcbiAgICAgICAgICAgIGVycm9yOiBudWxsLFxuICAgICAgICAgIH07XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yOiBhbnkpIHtcbiAgICAgICAgICBsb2NhbExvZ2dlci5lcnJvcihgWyR7QURET05fTkFNRX1dIEZhaWxlZCB0byBlZGl0IGJhY2t1cCBub3RlOmAsIGVycm9yKTtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICBzbmFwc2hvdElkOiBudWxsLFxuICAgICAgICAgICAgbm90ZTogbnVsbCxcbiAgICAgICAgICAgIGVycm9yOiBlcnJvci5tZXNzYWdlIHx8ICdVbmtub3duIGVycm9yJyxcbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICB9LFxuXG4gICAgICAvLyBQaGFzZSAxMTogV1AgRW5naW5lIENvbm5lY3RcbiAgICAgIHdwZUF1dGhlbnRpY2F0ZTogYXN5bmMgKCkgPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGxvY2FsTG9nZ2VyLmluZm8oYFske0FERE9OX05BTUV9XSBJbml0aWF0aW5nIFdQIEVuZ2luZSBhdXRoZW50aWNhdGlvbmApO1xuXG4gICAgICAgICAgaWYgKCF3cGVPQXV0aFNlcnZpY2UpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICBlbWFpbDogbnVsbCxcbiAgICAgICAgICAgICAgbWVzc2FnZTogbnVsbCxcbiAgICAgICAgICAgICAgZXJyb3I6ICdXUCBFbmdpbmUgT0F1dGggc2VydmljZSBub3QgYXZhaWxhYmxlJyxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gVHJpZ2dlciBPQXV0aCBmbG93IC0gdGhpcyB3aWxsIG9wZW4gYnJvd3NlciBmb3IgdXNlciBjb25zZW50XG4gICAgICAgICAgLy8gYXV0aGVudGljYXRlKCkgcmV0dXJucyBPQXV0aFRva2VucyBvbiBzdWNjZXNzXG4gICAgICAgICAgY29uc3QgdG9rZW5zID0gYXdhaXQgd3BlT0F1dGhTZXJ2aWNlLmF1dGhlbnRpY2F0ZSgpO1xuXG4gICAgICAgICAgaWYgKHRva2VucyAmJiB0b2tlbnMuYWNjZXNzVG9rZW4pIHtcbiAgICAgICAgICAgIC8vIFRyeSB0byBnZXQgdXNlciBlbWFpbCBmcm9tIENBUElcbiAgICAgICAgICAgIGxldCBlbWFpbCA9IG51bGw7XG4gICAgICAgICAgICBpZiAoY2FwaVNlcnZpY2UpIHtcbiAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBjb25zdCBjdXJyZW50VXNlciA9IGF3YWl0IGNhcGlTZXJ2aWNlLmdldEN1cnJlbnRVc2VyKCk7XG4gICAgICAgICAgICAgICAgZW1haWwgPSBjdXJyZW50VXNlcj8uZW1haWwgfHwgbnVsbDtcbiAgICAgICAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgICAgICAgLy8gVXNlciBpbmZvIG5vdCBhdmFpbGFibGVcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBsb2NhbExvZ2dlci5pbmZvKFxuICAgICAgICAgICAgICBgWyR7QURET05fTkFNRX1dIFN1Y2Nlc3NmdWxseSBhdXRoZW50aWNhdGVkIHdpdGggV1BFJHtlbWFpbCA/IGAgYXMgJHtlbWFpbH1gIDogJyd9YFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgICAgIGVtYWlsLFxuICAgICAgICAgICAgICBtZXNzYWdlOiAnU3VjY2Vzc2Z1bGx5IGF1dGhlbnRpY2F0ZWQgd2l0aCBXUCBFbmdpbmUnLFxuICAgICAgICAgICAgICBlcnJvcjogbnVsbCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgICBlbWFpbDogbnVsbCxcbiAgICAgICAgICAgIG1lc3NhZ2U6ICdBdXRoZW50aWNhdGlvbiBpbml0aWF0ZWQuIFBsZWFzZSBjb21wbGV0ZSB0aGUgbG9naW4gaW4geW91ciBicm93c2VyLicsXG4gICAgICAgICAgICBlcnJvcjogbnVsbCxcbiAgICAgICAgICB9O1xuICAgICAgICB9IGNhdGNoIChlcnJvcjogYW55KSB7XG4gICAgICAgICAgbG9jYWxMb2dnZXIuZXJyb3IoYFske0FERE9OX05BTUV9XSBXUEUgYXV0aGVudGljYXRpb24gZmFpbGVkOmAsIGVycm9yKTtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICBlbWFpbDogbnVsbCxcbiAgICAgICAgICAgIG1lc3NhZ2U6IG51bGwsXG4gICAgICAgICAgICBlcnJvcjogZXJyb3IubWVzc2FnZSB8fCAnQXV0aGVudGljYXRpb24gZmFpbGVkJyxcbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICB9LFxuXG4gICAgICB3cGVMb2dvdXQ6IGFzeW5jICgpID0+IHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBsb2NhbExvZ2dlci5pbmZvKGBbJHtBRERPTl9OQU1FfV0gTG9nZ2luZyBvdXQgZnJvbSBXUCBFbmdpbmVgKTtcblxuICAgICAgICAgIGlmICghd3BlT0F1dGhTZXJ2aWNlKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgbWVzc2FnZTogbnVsbCxcbiAgICAgICAgICAgICAgZXJyb3I6ICdXUCBFbmdpbmUgT0F1dGggc2VydmljZSBub3QgYXZhaWxhYmxlJyxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gY2xlYXJUb2tlbnMoKSBpcyB0aGUgbG9nb3V0IG1ldGhvZFxuICAgICAgICAgIGF3YWl0IHdwZU9BdXRoU2VydmljZS5jbGVhclRva2VucygpO1xuXG4gICAgICAgICAgbG9jYWxMb2dnZXIuaW5mbyhgWyR7QURET05fTkFNRX1dIFN1Y2Nlc3NmdWxseSBsb2dnZWQgb3V0IGZyb20gV1BFYCk7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgICBtZXNzYWdlOiAnTG9nZ2VkIG91dCBmcm9tIFdQIEVuZ2luZScsXG4gICAgICAgICAgICBlcnJvcjogbnVsbCxcbiAgICAgICAgICB9O1xuICAgICAgICB9IGNhdGNoIChlcnJvcjogYW55KSB7XG4gICAgICAgICAgbG9jYWxMb2dnZXIuZXJyb3IoYFske0FERE9OX05BTUV9XSBXUEUgbG9nb3V0IGZhaWxlZDpgLCBlcnJvcik7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgbWVzc2FnZTogbnVsbCxcbiAgICAgICAgICAgIGVycm9yOiBlcnJvci5tZXNzYWdlIHx8ICdMb2dvdXQgZmFpbGVkJyxcbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICB9LFxuXG4gICAgICAvLyBQaGFzZSAxMWM6IFB1c2ggdG8gV1AgRW5naW5lXG4gICAgICBwdXNoVG9XcGU6IGFzeW5jIChcbiAgICAgICAgX3BhcmVudDogYW55LFxuICAgICAgICBhcmdzOiB7XG4gICAgICAgICAgbG9jYWxTaXRlSWQ6IHN0cmluZztcbiAgICAgICAgICByZW1vdGVJbnN0YWxsSWQ6IHN0cmluZztcbiAgICAgICAgICBpbmNsdWRlU3FsPzogYm9vbGVhbjtcbiAgICAgICAgICBjb25maXJtPzogYm9vbGVhbjtcbiAgICAgICAgfVxuICAgICAgKSA9PiB7XG4gICAgICAgIGNvbnN0IHsgbG9jYWxTaXRlSWQsIHJlbW90ZUluc3RhbGxJZCwgaW5jbHVkZVNxbCA9IGZhbHNlLCBjb25maXJtID0gZmFsc2UgfSA9IGFyZ3M7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBsb2NhbExvZ2dlci5pbmZvKFxuICAgICAgICAgICAgYFske0FERE9OX05BTUV9XSBQdXNoIHRvIFdQRTogc2l0ZT0ke2xvY2FsU2l0ZUlkfSwgcmVtb3RlPSR7cmVtb3RlSW5zdGFsbElkfSwgaW5jbHVkZVNxbD0ke2luY2x1ZGVTcWx9YFxuICAgICAgICAgICk7XG5cbiAgICAgICAgICAvLyBSZXF1aXJlIGNvbmZpcm1hdGlvbiBmb3IgcHVzaCBvcGVyYXRpb25zXG4gICAgICAgICAgaWYgKCFjb25maXJtKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgbWVzc2FnZTogbnVsbCxcbiAgICAgICAgICAgICAgZXJyb3I6XG4gICAgICAgICAgICAgICAgJ1B1c2ggcmVxdWlyZXMgY29uZmlybT10cnVlIHRvIHByZXZlbnQgYWNjaWRlbnRhbCBvdmVyd3JpdGVzLiBTZXQgY29uZmlybT10cnVlIHRvIHByb2NlZWQuJyxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gVmVyaWZ5IHNpdGUgZXhpc3RzXG4gICAgICAgICAgY29uc3Qgc2l0ZSA9IHNpdGVEYXRhLmdldFNpdGUobG9jYWxTaXRlSWQpO1xuICAgICAgICAgIGlmICghc2l0ZSkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICAgIG1lc3NhZ2U6IG51bGwsXG4gICAgICAgICAgICAgIGVycm9yOiBgU2l0ZSBub3QgZm91bmQ6ICR7bG9jYWxTaXRlSWR9YCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gQ2hlY2sgV1BFIGNvbm5lY3Rpb24gZXhpc3RzXG4gICAgICAgICAgY29uc3Qgd3BlQ29ubmVjdGlvbiA9IHNpdGUuaG9zdENvbm5lY3Rpb25zPy5maW5kKChjOiBhbnkpID0+IGMuaG9zdElkID09PSAnd3BlJyk7XG4gICAgICAgICAgaWYgKCF3cGVDb25uZWN0aW9uKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgbWVzc2FnZTogbnVsbCxcbiAgICAgICAgICAgICAgZXJyb3I6XG4gICAgICAgICAgICAgICAgJ1NpdGUgaXMgbm90IGxpbmtlZCB0byBXUCBFbmdpbmUuIFVzZSBDb25uZWN0IGluIExvY2FsIHRvIGxpbmsgdGhlIHNpdGUgZmlyc3QuJyxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gQ2hlY2sgcHVzaCBzZXJ2aWNlIGF2YWlsYWJpbGl0eVxuICAgICAgICAgIGlmICghd3BlUHVzaFNlcnZpY2UgfHwgdHlwZW9mIHdwZVB1c2hTZXJ2aWNlLnB1c2ggIT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICBtZXNzYWdlOiBudWxsLFxuICAgICAgICAgICAgICBlcnJvcjogJ1dQRSBQdXNoIHNlcnZpY2Ugbm90IGF2YWlsYWJsZScsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIEdldCBpbnN0YWxsIGRldGFpbHMgZnJvbSBDQVBJIHRvIGdldCByZXF1aXJlZCBwYXJhbWV0ZXJzXG4gICAgICAgICAgbGV0IGluc3RhbGxOYW1lID0gcmVtb3RlSW5zdGFsbElkO1xuICAgICAgICAgIGxldCBwcmltYXJ5RG9tYWluID0gJyc7XG4gICAgICAgICAgbGV0IGluc3RhbGxJZCA9ICcnO1xuXG4gICAgICAgICAgaWYgKGNhcGlTZXJ2aWNlICYmIHR5cGVvZiBjYXBpU2VydmljZS5nZXRJbnN0YWxsTGlzdCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgY29uc3QgaW5zdGFsbHMgPSBhd2FpdCBjYXBpU2VydmljZS5nZXRJbnN0YWxsTGlzdCgpO1xuICAgICAgICAgICAgY29uc3QgbWF0Y2hpbmdJbnN0YWxsID0gaW5zdGFsbHM/LmZpbmQoXG4gICAgICAgICAgICAgIChpOiBhbnkpID0+XG4gICAgICAgICAgICAgICAgaS5zaXRlPy5pZCA9PT0gd3BlQ29ubmVjdGlvbi5yZW1vdGVTaXRlSWQgJiZcbiAgICAgICAgICAgICAgICAoIXdwZUNvbm5lY3Rpb24ucmVtb3RlU2l0ZUVudiB8fCBpLmVudmlyb25tZW50ID09PSB3cGVDb25uZWN0aW9uLnJlbW90ZVNpdGVFbnYpXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgaWYgKG1hdGNoaW5nSW5zdGFsbCkge1xuICAgICAgICAgICAgICBpbnN0YWxsTmFtZSA9IG1hdGNoaW5nSW5zdGFsbC5uYW1lO1xuICAgICAgICAgICAgICBwcmltYXJ5RG9tYWluID1cbiAgICAgICAgICAgICAgICBtYXRjaGluZ0luc3RhbGwucHJpbWFyeV9kb21haW4gfHxcbiAgICAgICAgICAgICAgICBtYXRjaGluZ0luc3RhbGwuY25hbWUgfHxcbiAgICAgICAgICAgICAgICBgJHttYXRjaGluZ0luc3RhbGwubmFtZX0ud3BlbmdpbmUuY29tYDtcbiAgICAgICAgICAgICAgaW5zdGFsbElkID0gbWF0Y2hpbmdJbnN0YWxsLmlkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmICghcHJpbWFyeURvbWFpbikge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICAgIG1lc3NhZ2U6IG51bGwsXG4gICAgICAgICAgICAgIGVycm9yOlxuICAgICAgICAgICAgICAgICdDb3VsZCBub3QgZGV0ZXJtaW5lIFdQIEVuZ2luZSBpbnN0YWxsIGRldGFpbHMuIFBsZWFzZSBlbnN1cmUgeW91IGFyZSBhdXRoZW50aWNhdGVkLicsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIFN0YXJ0IHRoZSBwdXNoIG9wZXJhdGlvbiAoYXN5bmMgLSByZXR1cm5zIGltbWVkaWF0ZWx5KVxuICAgICAgICAgIHdwZVB1c2hTZXJ2aWNlXG4gICAgICAgICAgICAucHVzaCh7XG4gICAgICAgICAgICAgIGluY2x1ZGVTcWwsXG4gICAgICAgICAgICAgIHdwZW5naW5lSW5zdGFsbE5hbWU6IGluc3RhbGxOYW1lLFxuICAgICAgICAgICAgICB3cGVuZ2luZUluc3RhbGxJZDogaW5zdGFsbElkLFxuICAgICAgICAgICAgICB3cGVuZ2luZVNpdGVJZDogd3BlQ29ubmVjdGlvbi5yZW1vdGVTaXRlSWQsXG4gICAgICAgICAgICAgIHdwZW5naW5lUHJpbWFyeURvbWFpbjogcHJpbWFyeURvbWFpbixcbiAgICAgICAgICAgICAgbG9jYWxTaXRlSWQ6IHNpdGUuaWQsXG4gICAgICAgICAgICAgIGVudmlyb25tZW50OiB3cGVDb25uZWN0aW9uLnJlbW90ZVNpdGVFbnYsXG4gICAgICAgICAgICAgIGlzTWFnaWNTeW5jOiBmYWxzZSxcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAuY2F0Y2goKGVycjogYW55KSA9PiB7XG4gICAgICAgICAgICAgIGxvY2FsTG9nZ2VyLmVycm9yKGBbJHtBRERPTl9OQU1FfV0gUHVzaCBmYWlsZWQ6YCwgZXJyKTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgICBtZXNzYWdlOiBgUHVzaCBzdGFydGVkIHRvICR7aW5zdGFsbE5hbWV9LiBDaGVjayBMb2NhbCBVSSBmb3IgcHJvZ3Jlc3MuYCxcbiAgICAgICAgICAgIGVycm9yOiBudWxsLFxuICAgICAgICAgIH07XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yOiBhbnkpIHtcbiAgICAgICAgICBsb2NhbExvZ2dlci5lcnJvcihgWyR7QURET05fTkFNRX1dIEZhaWxlZCB0byBzdGFydCBwdXNoOmAsIGVycm9yKTtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICBtZXNzYWdlOiBudWxsLFxuICAgICAgICAgICAgZXJyb3I6IGVycm9yLm1lc3NhZ2UgfHwgJ0ZhaWxlZCB0byBzdGFydCBwdXNoJyxcbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICB9LFxuXG4gICAgICAvLyBQaGFzZSAxMWM6IFB1bGwgZnJvbSBXUCBFbmdpbmVcbiAgICAgIHB1bGxGcm9tV3BlOiBhc3luYyAoXG4gICAgICAgIF9wYXJlbnQ6IGFueSxcbiAgICAgICAgYXJnczoge1xuICAgICAgICAgIGxvY2FsU2l0ZUlkOiBzdHJpbmc7XG4gICAgICAgICAgcmVtb3RlSW5zdGFsbElkOiBzdHJpbmc7XG4gICAgICAgICAgaW5jbHVkZVNxbD86IGJvb2xlYW47XG4gICAgICAgIH1cbiAgICAgICkgPT4ge1xuICAgICAgICBjb25zdCB7IGxvY2FsU2l0ZUlkLCByZW1vdGVJbnN0YWxsSWQsIGluY2x1ZGVTcWwgPSBmYWxzZSB9ID0gYXJncztcblxuICAgICAgICB0cnkge1xuICAgICAgICAgIGxvY2FsTG9nZ2VyLmluZm8oXG4gICAgICAgICAgICBgWyR7QURET05fTkFNRX1dIFB1bGwgZnJvbSBXUEU6IHNpdGU9JHtsb2NhbFNpdGVJZH0sIHJlbW90ZT0ke3JlbW90ZUluc3RhbGxJZH0sIGluY2x1ZGVTcWw9JHtpbmNsdWRlU3FsfWBcbiAgICAgICAgICApO1xuXG4gICAgICAgICAgLy8gVmVyaWZ5IHNpdGUgZXhpc3RzXG4gICAgICAgICAgY29uc3Qgc2l0ZSA9IHNpdGVEYXRhLmdldFNpdGUobG9jYWxTaXRlSWQpO1xuICAgICAgICAgIGlmICghc2l0ZSkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICAgIG1lc3NhZ2U6IG51bGwsXG4gICAgICAgICAgICAgIGVycm9yOiBgU2l0ZSBub3QgZm91bmQ6ICR7bG9jYWxTaXRlSWR9YCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gQ2hlY2sgV1BFIGNvbm5lY3Rpb24gZXhpc3RzXG4gICAgICAgICAgY29uc3Qgd3BlQ29ubmVjdGlvbiA9IHNpdGUuaG9zdENvbm5lY3Rpb25zPy5maW5kKChjOiBhbnkpID0+IGMuaG9zdElkID09PSAnd3BlJyk7XG4gICAgICAgICAgaWYgKCF3cGVDb25uZWN0aW9uKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgICAgbWVzc2FnZTogbnVsbCxcbiAgICAgICAgICAgICAgZXJyb3I6XG4gICAgICAgICAgICAgICAgJ1NpdGUgaXMgbm90IGxpbmtlZCB0byBXUCBFbmdpbmUuIFVzZSBDb25uZWN0IGluIExvY2FsIHRvIGxpbmsgdGhlIHNpdGUgZmlyc3QuJyxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gQ2hlY2sgcHVsbCBzZXJ2aWNlIGF2YWlsYWJpbGl0eVxuICAgICAgICAgIGlmICghd3BlUHVsbFNlcnZpY2UgfHwgdHlwZW9mIHdwZVB1bGxTZXJ2aWNlLnB1bGwgIT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgICAgICBtZXNzYWdlOiBudWxsLFxuICAgICAgICAgICAgICBlcnJvcjogJ1dQRSBQdWxsIHNlcnZpY2Ugbm90IGF2YWlsYWJsZScsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIEdldCBpbnN0YWxsIGRldGFpbHMgZnJvbSBDQVBJXG4gICAgICAgICAgbGV0IGluc3RhbGxOYW1lID0gcmVtb3RlSW5zdGFsbElkO1xuICAgICAgICAgIGxldCBwcmltYXJ5RG9tYWluID0gJyc7XG4gICAgICAgICAgbGV0IGluc3RhbGxJZCA9ICcnO1xuXG4gICAgICAgICAgaWYgKGNhcGlTZXJ2aWNlICYmIHR5cGVvZiBjYXBpU2VydmljZS5nZXRJbnN0YWxsTGlzdCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgY29uc3QgaW5zdGFsbHMgPSBhd2FpdCBjYXBpU2VydmljZS5nZXRJbnN0YWxsTGlzdCgpO1xuICAgICAgICAgICAgY29uc3QgbWF0Y2hpbmdJbnN0YWxsID0gaW5zdGFsbHM/LmZpbmQoXG4gICAgICAgICAgICAgIChpOiBhbnkpID0+XG4gICAgICAgICAgICAgICAgaS5zaXRlPy5pZCA9PT0gd3BlQ29ubmVjdGlvbi5yZW1vdGVTaXRlSWQgJiZcbiAgICAgICAgICAgICAgICAoIXdwZUNvbm5lY3Rpb24ucmVtb3RlU2l0ZUVudiB8fCBpLmVudmlyb25tZW50ID09PSB3cGVDb25uZWN0aW9uLnJlbW90ZVNpdGVFbnYpXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgaWYgKG1hdGNoaW5nSW5zdGFsbCkge1xuICAgICAgICAgICAgICBpbnN0YWxsTmFtZSA9IG1hdGNoaW5nSW5zdGFsbC5uYW1lO1xuICAgICAgICAgICAgICBwcmltYXJ5RG9tYWluID1cbiAgICAgICAgICAgICAgICBtYXRjaGluZ0luc3RhbGwucHJpbWFyeV9kb21haW4gfHxcbiAgICAgICAgICAgICAgICBtYXRjaGluZ0luc3RhbGwuY25hbWUgfHxcbiAgICAgICAgICAgICAgICBgJHttYXRjaGluZ0luc3RhbGwubmFtZX0ud3BlbmdpbmUuY29tYDtcbiAgICAgICAgICAgICAgaW5zdGFsbElkID0gbWF0Y2hpbmdJbnN0YWxsLmlkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmICghcHJpbWFyeURvbWFpbikge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICAgIG1lc3NhZ2U6IG51bGwsXG4gICAgICAgICAgICAgIGVycm9yOlxuICAgICAgICAgICAgICAgICdDb3VsZCBub3QgZGV0ZXJtaW5lIFdQIEVuZ2luZSBpbnN0YWxsIGRldGFpbHMuIFBsZWFzZSBlbnN1cmUgeW91IGFyZSBhdXRoZW50aWNhdGVkLicsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIFN0YXJ0IHRoZSBwdWxsIG9wZXJhdGlvbiAoYXN5bmMgLSByZXR1cm5zIGltbWVkaWF0ZWx5KVxuICAgICAgICAgIHdwZVB1bGxTZXJ2aWNlXG4gICAgICAgICAgICAucHVsbCh7XG4gICAgICAgICAgICAgIGluY2x1ZGVTcWwsXG4gICAgICAgICAgICAgIHdwZW5naW5lSW5zdGFsbE5hbWU6IGluc3RhbGxOYW1lLFxuICAgICAgICAgICAgICB3cGVuZ2luZUluc3RhbGxJZDogaW5zdGFsbElkLFxuICAgICAgICAgICAgICB3cGVuZ2luZVNpdGVJZDogd3BlQ29ubmVjdGlvbi5yZW1vdGVTaXRlSWQsXG4gICAgICAgICAgICAgIHdwZW5naW5lUHJpbWFyeURvbWFpbjogcHJpbWFyeURvbWFpbixcbiAgICAgICAgICAgICAgbG9jYWxTaXRlSWQ6IHNpdGUuaWQsXG4gICAgICAgICAgICAgIGVudmlyb25tZW50OiB3cGVDb25uZWN0aW9uLnJlbW90ZVNpdGVFbnYsXG4gICAgICAgICAgICAgIGlzTWFnaWNTeW5jOiBmYWxzZSxcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAuY2F0Y2goKGVycjogYW55KSA9PiB7XG4gICAgICAgICAgICAgIGxvY2FsTG9nZ2VyLmVycm9yKGBbJHtBRERPTl9OQU1FfV0gUHVsbCBmYWlsZWQ6YCwgZXJyKTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgICBtZXNzYWdlOiBgUHVsbCBzdGFydGVkIGZyb20gJHtpbnN0YWxsTmFtZX0uIENoZWNrIExvY2FsIFVJIGZvciBwcm9ncmVzcy5gLFxuICAgICAgICAgICAgZXJyb3I6IG51bGwsXG4gICAgICAgICAgfTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgICAgICAgIGxvY2FsTG9nZ2VyLmVycm9yKGBbJHtBRERPTl9OQU1FfV0gRmFpbGVkIHRvIHN0YXJ0IHB1bGw6YCwgZXJyb3IpO1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgICAgIG1lc3NhZ2U6IG51bGwsXG4gICAgICAgICAgICBlcnJvcjogZXJyb3IubWVzc2FnZSB8fCAnRmFpbGVkIHRvIHN0YXJ0IHB1bGwnLFxuICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgfSxcbiAgfTtcbn1cblxuLyoqXG4gKiBTdGFydCB0aGUgTUNQIHNlcnZlclxuICovXG5hc3luYyBmdW5jdGlvbiBzdGFydE1jcFNlcnZlcihzZXJ2aWNlczogTG9jYWxTZXJ2aWNlcywgbG9nZ2VyOiBhbnkpOiBQcm9taXNlPHZvaWQ+IHtcbiAgaWYgKG1jcFNlcnZlcikge1xuICAgIGxvZ2dlci53YXJuKGBbJHtBRERPTl9OQU1FfV0gTUNQIHNlcnZlciBhbHJlYWR5IHJ1bm5pbmdgKTtcbiAgICByZXR1cm47XG4gIH1cblxuICB0cnkge1xuICAgIG1jcFNlcnZlciA9IG5ldyBNY3BTZXJ2ZXIoeyBwb3J0OiBNQ1BfU0VSVkVSLkRFRkFVTFRfUE9SVCB9LCBzZXJ2aWNlcywgbG9nZ2VyKTtcblxuICAgIGF3YWl0IG1jcFNlcnZlci5zdGFydCgpO1xuXG4gICAgY29uc3QgaW5mbyA9IG1jcFNlcnZlci5nZXRDb25uZWN0aW9uSW5mbygpO1xuICAgIGxvZ2dlci5pbmZvKGBbJHtBRERPTl9OQU1FfV0gTUNQIHNlcnZlciBzdGFydGVkIG9uIHBvcnQgJHtpbmZvLnBvcnR9YCk7XG4gICAgbG9nZ2VyLmluZm8oXG4gICAgICBgWyR7QURET05fTkFNRX1dIE1DUCBjb25uZWN0aW9uIGluZm8gc2F2ZWQgdG86IH4vTGlicmFyeS9BcHBsaWNhdGlvbiBTdXBwb3J0L0xvY2FsL21jcC1jb25uZWN0aW9uLWluZm8uanNvbmBcbiAgICApO1xuICAgIGxvZ2dlci5pbmZvKGBbJHtBRERPTl9OQU1FfV0gQXZhaWxhYmxlIHRvb2xzOiAke2luZm8udG9vbHMuam9pbignLCAnKX1gKTtcbiAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgIGxvZ2dlci5lcnJvcihgWyR7QURET05fTkFNRX1dIEZhaWxlZCB0byBzdGFydCBNQ1Agc2VydmVyOmAsIGVycm9yKTtcbiAgfVxufVxuXG4vKipcbiAqIFN0b3AgdGhlIE1DUCBzZXJ2ZXJcbiAqL1xuYXN5bmMgZnVuY3Rpb24gc3RvcE1jcFNlcnZlcihsb2dnZXI6IGFueSk6IFByb21pc2U8dm9pZD4ge1xuICBpZiAobWNwU2VydmVyKSB7XG4gICAgYXdhaXQgbWNwU2VydmVyLnN0b3AoKTtcbiAgICBtY3BTZXJ2ZXIgPSBudWxsO1xuICAgIGxvZ2dlci5pbmZvKGBbJHtBRERPTl9OQU1FfV0gTUNQIHNlcnZlciBzdG9wcGVkYCk7XG4gIH1cbn1cblxuLyoqXG4gKiBSZWdpc3RlciBJUEMgaGFuZGxlcnMgZm9yIHJlbmRlcmVyIGNvbW11bmljYXRpb25cbiAqL1xuZnVuY3Rpb24gcmVnaXN0ZXJJcGNIYW5kbGVycyhzZXJ2aWNlczogTG9jYWxTZXJ2aWNlcywgbG9nZ2VyOiBhbnkpOiB2b2lkIHtcbiAgLy8gR2V0IE1DUCBzZXJ2ZXIgc3RhdHVzXG4gIGlwY01haW4uaGFuZGxlKCdtY3A6Z2V0U3RhdHVzJywgYXN5bmMgKCkgPT4ge1xuICAgIGlmICghbWNwU2VydmVyKSB7XG4gICAgICByZXR1cm4geyBydW5uaW5nOiBmYWxzZSwgcG9ydDogMCwgdXB0aW1lOiAwIH07XG4gICAgfVxuICAgIHJldHVybiBtY3BTZXJ2ZXIuZ2V0U3RhdHVzKCk7XG4gIH0pO1xuXG4gIC8vIEdldCBjb25uZWN0aW9uIGluZm9cbiAgaXBjTWFpbi5oYW5kbGUoJ21jcDpnZXRDb25uZWN0aW9uSW5mbycsIGFzeW5jICgpID0+IHtcbiAgICBpZiAoIW1jcFNlcnZlcikge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICAgIHJldHVybiBtY3BTZXJ2ZXIuZ2V0Q29ubmVjdGlvbkluZm8oKTtcbiAgfSk7XG5cbiAgLy8gU3RhcnQgTUNQIHNlcnZlclxuICBpcGNNYWluLmhhbmRsZSgnbWNwOnN0YXJ0JywgYXN5bmMgKCkgPT4ge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCBzdGFydE1jcFNlcnZlcihzZXJ2aWNlcywgbG9nZ2VyKTtcbiAgICAgIHJldHVybiB7IHN1Y2Nlc3M6IHRydWUgfTtcbiAgICB9IGNhdGNoIChlcnJvcjogYW55KSB7XG4gICAgICByZXR1cm4geyBzdWNjZXNzOiBmYWxzZSwgZXJyb3I6IGVycm9yLm1lc3NhZ2UgfTtcbiAgICB9XG4gIH0pO1xuXG4gIC8vIFN0b3AgTUNQIHNlcnZlclxuICBpcGNNYWluLmhhbmRsZSgnbWNwOnN0b3AnLCBhc3luYyAoKSA9PiB7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHN0b3BNY3BTZXJ2ZXIobG9nZ2VyKTtcbiAgICAgIHJldHVybiB7IHN1Y2Nlc3M6IHRydWUgfTtcbiAgICB9IGNhdGNoIChlcnJvcjogYW55KSB7XG4gICAgICByZXR1cm4geyBzdWNjZXNzOiBmYWxzZSwgZXJyb3I6IGVycm9yLm1lc3NhZ2UgfTtcbiAgICB9XG4gIH0pO1xuXG4gIC8vIFJlc3RhcnQgTUNQIHNlcnZlclxuICBpcGNNYWluLmhhbmRsZSgnbWNwOnJlc3RhcnQnLCBhc3luYyAoKSA9PiB7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHN0b3BNY3BTZXJ2ZXIobG9nZ2VyKTtcbiAgICAgIGF3YWl0IHN0YXJ0TWNwU2VydmVyKHNlcnZpY2VzLCBsb2dnZXIpO1xuICAgICAgcmV0dXJuIHsgc3VjY2VzczogdHJ1ZSB9O1xuICAgIH0gY2F0Y2ggKGVycm9yOiBhbnkpIHtcbiAgICAgIHJldHVybiB7IHN1Y2Nlc3M6IGZhbHNlLCBlcnJvcjogZXJyb3IubWVzc2FnZSB9O1xuICAgIH1cbiAgfSk7XG5cbiAgLy8gUmVnZW5lcmF0ZSBhdXRoIHRva2VuXG4gIGlwY01haW4uaGFuZGxlKCdtY3A6cmVnZW5lcmF0ZVRva2VuJywgYXN5bmMgKCkgPT4ge1xuICAgIGlmICghbWNwU2VydmVyKSB7XG4gICAgICByZXR1cm4geyBzdWNjZXNzOiBmYWxzZSwgZXJyb3I6ICdNQ1Agc2VydmVyIG5vdCBydW5uaW5nJyB9O1xuICAgIH1cbiAgICB0cnkge1xuICAgICAgY29uc3QgbmV3VG9rZW4gPSBhd2FpdCBtY3BTZXJ2ZXIucmVnZW5lcmF0ZVRva2VuKCk7XG4gICAgICByZXR1cm4geyBzdWNjZXNzOiB0cnVlLCB0b2tlbjogbmV3VG9rZW4gfTtcbiAgICB9IGNhdGNoIChlcnJvcjogYW55KSB7XG4gICAgICByZXR1cm4geyBzdWNjZXNzOiBmYWxzZSwgZXJyb3I6IGVycm9yLm1lc3NhZ2UgfTtcbiAgICB9XG4gIH0pO1xuXG4gIGxvZ2dlci5pbmZvKFxuICAgIGBbJHtBRERPTl9OQU1FfV0gUmVnaXN0ZXJlZCBJUEMgaGFuZGxlcnM6IG1jcDpnZXRTdGF0dXMsIG1jcDpnZXRDb25uZWN0aW9uSW5mbywgbWNwOnN0YXJ0LCBtY3A6c3RvcCwgbWNwOnJlc3RhcnQsIG1jcDpyZWdlbmVyYXRlVG9rZW5gXG4gICk7XG59XG5cbi8qKlxuICogTWFpbiBhZGRvbiBpbml0aWFsaXphdGlvbiBmdW5jdGlvblxuICovXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiAoX2NvbnRleHQ6IExvY2FsTWFpbi5BZGRvbk1haW5Db250ZXh0KTogdm9pZCB7XG4gIGNvbnN0IHNlcnZpY2VzID0gTG9jYWxNYWluLmdldFNlcnZpY2VDb250YWluZXIoKS5jcmFkbGUgYXMgYW55O1xuICBjb25zdCB7IGxvY2FsTG9nZ2VyLCBncmFwaHFsIH0gPSBzZXJ2aWNlcztcblxuICB0cnkge1xuICAgIGxvY2FsTG9nZ2VyLmluZm8oYFske0FERE9OX05BTUV9XSBJbml0aWFsaXppbmcuLi5gKTtcblxuICAgIC8vIFJlZ2lzdGVyIEdyYXBoUUwgZXh0ZW5zaW9ucyAoZm9yIGxvY2FsLWNsaSBhbmQgTUNQKVxuICAgIGNvbnN0IHJlc29sdmVycyA9IGNyZWF0ZVJlc29sdmVycyhzZXJ2aWNlcyk7XG4gICAgZ3JhcGhxbC5yZWdpc3RlckdyYXBoUUxTZXJ2aWNlKCdtY3Atc2VydmVyJywgdHlwZURlZnMsIHJlc29sdmVycyk7XG4gICAgbG9jYWxMb2dnZXIuaW5mbyhgWyR7QURET05fTkFNRX1dIFJlZ2lzdGVyZWQgR3JhcGhRTDogMjkgdG9vbHMgKFBoYXNlIDEtMTFiKWApO1xuXG4gICAgLy8gU3RhcnQgTUNQIHNlcnZlciAoZm9yIEFJIHRvb2xzKVxuICAgIGNvbnN0IGxvY2FsU2VydmljZXM6IExvY2FsU2VydmljZXMgPSB7XG4gICAgICBzaXRlRGF0YTogc2VydmljZXMuc2l0ZURhdGEsXG4gICAgICBzaXRlUHJvY2Vzc01hbmFnZXI6IHNlcnZpY2VzLnNpdGVQcm9jZXNzTWFuYWdlcixcbiAgICAgIHdwQ2xpOiBzZXJ2aWNlcy53cENsaSxcbiAgICAgIGRlbGV0ZVNpdGU6IHNlcnZpY2VzLmRlbGV0ZVNpdGUsXG4gICAgICBhZGRTaXRlOiBzZXJ2aWNlcy5hZGRTaXRlLFxuICAgICAgbG9jYWxMb2dnZXI6IHNlcnZpY2VzLmxvY2FsTG9nZ2VyLFxuICAgICAgYWRtaW5lcjogc2VydmljZXMuYWRtaW5lcixcbiAgICAgIHg1MDlDZXJ0OiBzZXJ2aWNlcy54NTA5Q2VydCxcbiAgICAgIHNpdGVQcm92aXNpb25lcjogc2VydmljZXMuc2l0ZVByb3Zpc2lvbmVyLFxuICAgICAgaW1wb3J0U2l0ZTogc2VydmljZXMuaW1wb3J0U2l0ZSxcbiAgICAgIGxpZ2h0bmluZ1NlcnZpY2VzOiBzZXJ2aWNlcy5saWdodG5pbmdTZXJ2aWNlcyxcbiAgICAgIC8vIFBoYXNlIDExOiBXUCBFbmdpbmUgQ29ubmVjdFxuICAgICAgd3BlT0F1dGg6IHNlcnZpY2VzLndwZU9BdXRoLFxuICAgICAgY2FwaTogc2VydmljZXMuY2FwaSxcbiAgICB9O1xuXG4gICAgLy8gTUNQIHNlcnZlciBkaXNhYmxlZCAtIENMSS1vbmx5IG1vZGVcbiAgICAvLyBUbyBlbmFibGUgTUNQIHNlcnZlciBmb3IgQUkgdG9vbCBpbnRlZ3JhdGlvbiwgdW5jb21tZW50IHRoZSBmb2xsb3dpbmc6XG4gICAgLy8gc3RhcnRNY3BTZXJ2ZXIobG9jYWxTZXJ2aWNlcywgbG9jYWxMb2dnZXIpO1xuICAgIC8vIHJlZ2lzdGVySXBjSGFuZGxlcnMobG9jYWxTZXJ2aWNlcywgbG9jYWxMb2dnZXIpO1xuXG4gICAgbG9jYWxMb2dnZXIuaW5mbyhgWyR7QURET05fTkFNRX1dIFN1Y2Nlc3NmdWxseSBpbml0aWFsaXplZCAoQ0xJLW9ubHkgbW9kZSlgKTtcbiAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgIGxvY2FsTG9nZ2VyLmVycm9yKGBbJHtBRERPTl9OQU1FfV0gRmFpbGVkIHRvIGluaXRpYWxpemU6YCwgZXJyb3IpO1xuICB9XG59XG4iXX0=