@fjall/components-infrastructure 0.77.4 → 0.78.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/lib/app.d.ts +8 -5
  2. package/dist/lib/app.js +19 -7
  3. package/dist/lib/patterns/aws/buildkite.js +4 -7
  4. package/dist/lib/patterns/aws/compute.d.ts +479 -48
  5. package/dist/lib/patterns/aws/compute.js +307 -94
  6. package/dist/lib/patterns/aws/database.d.ts +1 -0
  7. package/dist/lib/patterns/aws/database.js +4 -1
  8. package/dist/lib/patterns/aws/hostedZone.js +4 -7
  9. package/dist/lib/patterns/aws/loadBalancer.d.ts +163 -0
  10. package/dist/lib/patterns/aws/loadBalancer.js +278 -0
  11. package/dist/lib/patterns/aws/network.d.ts +1 -0
  12. package/dist/lib/patterns/aws/network.js +2 -1
  13. package/dist/lib/resources/aws/compute/capacityProviderDrainWaiter.d.ts +20 -0
  14. package/dist/lib/resources/aws/compute/capacityProviderDrainWaiter.js +180 -0
  15. package/dist/lib/resources/aws/compute/ecs.d.ts +294 -57
  16. package/dist/lib/resources/aws/compute/ecs.js +745 -261
  17. package/dist/lib/resources/aws/compute/ecsFreeTier.js +1 -1
  18. package/dist/lib/resources/aws/compute/ecsSpot.js +1 -1
  19. package/dist/lib/resources/aws/compute/utilities/capacityProviderDrainWaiter.d.ts +20 -0
  20. package/dist/lib/resources/aws/compute/utilities/capacityProviderDrainWaiter.js +180 -0
  21. package/dist/lib/resources/aws/database/rdsAurora.d.ts +1 -0
  22. package/dist/lib/resources/aws/database/rdsAurora.js +2 -2
  23. package/dist/lib/resources/aws/database/rdsAuroraGlobal.d.ts +1 -0
  24. package/dist/lib/resources/aws/database/rdsAuroraGlobal.js +2 -1
  25. package/dist/lib/resources/aws/database/rdsDeletionWaiter.d.ts +33 -0
  26. package/dist/lib/resources/aws/database/rdsDeletionWaiter.js +74 -0
  27. package/dist/lib/resources/aws/database/rdsInstance.d.ts +1 -0
  28. package/dist/lib/resources/aws/database/rdsInstance.js +3 -3
  29. package/dist/lib/resources/aws/networking/vpc.d.ts +1 -0
  30. package/dist/lib/resources/aws/networking/vpc.js +4 -3
  31. package/dist/lib/resources/aws/networking/vpcEndpoint.d.ts +2 -2
  32. package/dist/lib/resources/aws/networking/vpcEndpoint.js +1 -1
  33. package/dist/lib/resources/aws/networking/vpcEndpoints.d.ts +71 -0
  34. package/dist/lib/resources/aws/networking/vpcEndpoints.js +125 -0
  35. package/dist/lib/resources/aws/secrets/kms.d.ts +14 -0
  36. package/dist/lib/resources/aws/secrets/kms.js +5 -2
  37. package/dist/lib/resources/aws/secrets/secret.js +1 -1
  38. package/dist/lib/utils/standardTagsAspect.d.ts +26 -12
  39. package/dist/lib/utils/standardTagsAspect.js +67 -477
  40. package/dist/lib/utils/tagResource.d.ts +18 -3
  41. package/dist/lib/utils/tagResource.js +23 -6
  42. package/package.json +3 -3
  43. package/dist/lib/aspects/resourceInventory.d.ts +0 -41
  44. package/dist/lib/aspects/resourceInventory.js +0 -56
  45. package/dist/lib/config/audit.d.ts +0 -18
  46. package/dist/lib/config/audit.js +0 -22
  47. package/dist/lib/patterns/aws/auditRole.d.ts +0 -44
  48. package/dist/lib/patterns/aws/auditRole.js +0 -58
  49. package/dist/lib/patterns/aws/basicApp.d.ts +0 -0
  50. package/dist/lib/patterns/aws/basicApp.js +0 -150
  51. package/dist/lib/patterns/aws/ec2.d.ts +0 -43
  52. package/dist/lib/patterns/aws/ec2.js +0 -123
  53. package/dist/lib/patterns/aws/freeTierApp.d.ts +0 -44
  54. package/dist/lib/patterns/aws/freeTierApp.js +0 -83
  55. package/dist/lib/patterns/aws/spotInstanceApp.d.ts +0 -45
  56. package/dist/lib/patterns/aws/spotInstanceApp.js +0 -85
  57. package/dist/lib/resources/aws/audit/auditRole.d.ts +0 -32
  58. package/dist/lib/resources/aws/audit/auditRole.js +0 -46
  59. package/dist/lib/resources/aws/database/databaseFreeTier.d.ts +0 -15
  60. package/dist/lib/resources/aws/database/databaseFreeTier.js +0 -29
  61. package/dist/lib/resources/aws/database/rdsFreeTier.d.ts +0 -37
  62. package/dist/lib/resources/aws/database/rdsFreeTier.js +0 -84
  63. package/dist/lib/utils/getCidr.d.ts +0 -8
  64. package/dist/lib/utils/getCidr.js +0 -40
@@ -14,8 +14,11 @@ const aws_certificatemanager_1 = require("aws-cdk-lib/aws-certificatemanager");
14
14
  const aws_route53_1 = require("aws-cdk-lib/aws-route53");
15
15
  const aws_route53_targets_1 = require("aws-cdk-lib/aws-route53-targets");
16
16
  const aws_ecr_1 = require("aws-cdk-lib/aws-ecr");
17
+ const aws_autoscaling_1 = require("aws-cdk-lib/aws-autoscaling");
17
18
  const cfnOutput_1 = require("../utilities/cfnOutput");
18
19
  const hostedZone_1 = require("../../../patterns/aws/hostedZone");
20
+ const securityGroup_1 = require("../iam/securityGroup");
21
+ const capacityProviderDrainWaiter_1 = require("./utilities/capacityProviderDrainWaiter");
19
22
  var Protocol;
20
23
  (function (Protocol) {
21
24
  Protocol[Protocol["HTTP"] = 0] = "HTTP";
@@ -26,43 +29,591 @@ var ScalingType;
26
29
  ScalingType["CPU"] = "ECSServiceAverageCPUUtilization";
27
30
  ScalingType["MEMORY"] = "ECSServiceAverageMemoryUtilization";
28
31
  })(ScalingType || (exports.ScalingType = ScalingType = {}));
29
- class FargateCluster extends constructs_1.Construct {
32
+ /**
33
+ * ECS Cluster supporting multiple services with a shared ALB.
34
+ *
35
+ * @example
36
+ * // Single service cluster
37
+ * new EcsCluster(scope, "WebCluster", {
38
+ * clusterName: "WebCluster",
39
+ * ecrRepository: ecr,
40
+ * services: [
41
+ * { name: "web", containers: [{ name: "app", port: 3000 }] }
42
+ * ]
43
+ * });
44
+ *
45
+ * @example
46
+ * // Multi-service cluster with routing
47
+ * new EcsCluster(scope, "ApiCluster", {
48
+ * clusterName: "ApiCluster",
49
+ * cluster: { domain: "api.example.com" },
50
+ * ecrRepository: ecr,
51
+ * services: [
52
+ * { name: "users", containers: [{ name: "app", port: 3000 }], routing: { path: "/users/*" } },
53
+ * { name: "orders", containers: [{ name: "app", port: 3001 }], routing: { path: "/orders/*" } }
54
+ * ]
55
+ * });
56
+ *
57
+ * @example
58
+ * // Worker cluster (no ALB)
59
+ * new EcsCluster(scope, "Workers", {
60
+ * clusterName: "Workers",
61
+ * cluster: { loadBalancer: false },
62
+ * ecrRepository: ecr,
63
+ * services: [
64
+ * { name: "processor", containers: [{ name: "worker" }] }
65
+ * ]
66
+ * });
67
+ */
68
+ class EcsCluster extends constructs_1.Construct {
30
69
  constructor(scope, id, props) {
31
70
  super(scope, id);
32
- this.secrets = {};
71
+ // Per-service tracking
72
+ this.services = new Map();
73
+ this.nextPriority = 100;
33
74
  this.scope = scope;
75
+ this.props = props;
76
+ this.capacityProvider = props.capacityProvider || "FARGATE";
77
+ this.directAccessEnabled = props.cluster?.directAccess === true;
78
+ this.loadBalancerDisabled =
79
+ props.cluster?.loadBalancer === false || this.directAccessEnabled;
80
+ this.validateProps(props);
81
+ // 1. Create the ECS cluster
34
82
  this.addCluster(props);
35
- this.addSecrets(props);
36
- this.importSecrets(props);
37
- this.addExecutionRole(props);
38
- this.addTaskDefinition(props);
39
- this.addContainerDefinition(props);
40
- this.addFargateService(props);
41
- this.addLoadBalancer(props);
42
- if (props.domainConfig)
43
- this.addHostedZone(props);
44
- this.addLoadBalancerListener(props);
45
- this.registerLoadBalancerTargets(props);
46
- const containerPort = props.containerPort || 80;
83
+ // 2. Set up EC2 infrastructure if needed
84
+ if (this.isEc2()) {
85
+ this.addAutoScalingGroup(props);
86
+ }
87
+ // 3. Create ALB if not disabled (shared by all services)
88
+ if (!this.loadBalancerDisabled) {
89
+ this.addLoadBalancer(props);
90
+ // Set up domain/HTTPS if configured
91
+ if (props.cluster?.domain || props.cluster?.domainConfig) {
92
+ this.addHostedZone(props);
93
+ }
94
+ this.addLoadBalancerListener(props);
95
+ }
96
+ else if (this.directAccessEnabled) {
97
+ this.addDirectAccessOutputs(props);
98
+ }
99
+ // 4. Create each service
100
+ for (const serviceProps of props.services) {
101
+ this.addServiceToCluster(serviceProps);
102
+ }
103
+ // 5. Set up connections
104
+ this.setupConnections(props);
105
+ }
106
+ /** Get the cluster's load balancer. Undefined if disabled. */
107
+ getLoadBalancer() {
108
+ return this.loadBalancer;
109
+ }
110
+ /** Get the load balancer's listener. Undefined if disabled. */
111
+ getListener() {
112
+ return this.loadBalancerListener;
113
+ }
114
+ /** Get a specific service by name. */
115
+ getService(name) {
116
+ return this.services.get(name)?.service;
117
+ }
118
+ /** Get all services in this cluster. */
119
+ getServices() {
120
+ const result = new Map();
121
+ for (const [name, data] of this.services) {
122
+ result.set(name, data.service);
123
+ }
124
+ return result;
125
+ }
126
+ /** Get the ECS cluster construct. */
127
+ getCluster() {
128
+ return this.cluster;
129
+ }
130
+ /** Get the ALB URL (http:// or https://). */
131
+ getUrl() {
132
+ if (!this.loadBalancer)
133
+ return undefined;
134
+ const protocol = this.certificate ? "https" : "http";
135
+ const domain = this.props.cluster?.domain || this.loadBalancer.loadBalancerDnsName;
136
+ return `${protocol}://${domain}`;
137
+ }
138
+ /**
139
+ * Add a service to the cluster.
140
+ * Each service gets its own task definition, containers, and target group.
141
+ */
142
+ addServiceToCluster(serviceProps) {
143
+ const serviceName = serviceProps.name;
144
+ // Create separate roles for security best practice
145
+ const executionRole = this.createExecutionRole(serviceName);
146
+ const taskRole = this.createTaskRole(serviceName, serviceProps);
147
+ // Create task definition with both roles
148
+ const taskDefinition = this.createTaskDefinition(serviceName, serviceProps, executionRole, taskRole);
149
+ // Add containers to task definition
150
+ const { containers, primaryContainer } = this.addContainersToTask(serviceName, serviceProps, taskDefinition);
151
+ // Create the ECS service
152
+ const service = this.createService(serviceName, serviceProps, taskDefinition);
153
+ // Register with ALB if enabled and has primary container with port
154
+ let targetGroup;
155
+ if (!this.loadBalancerDisabled &&
156
+ primaryContainer &&
157
+ this.loadBalancerListener) {
158
+ targetGroup = this.registerServiceWithALB(serviceName, serviceProps, service, primaryContainer);
159
+ }
160
+ // Add scaling if configured
161
+ let scalingPolicy;
162
+ if (serviceProps.scalingType) {
163
+ scalingPolicy = this.addServiceScaling(serviceName, serviceProps, service);
164
+ }
165
+ // Store service data
166
+ this.services.set(serviceName, {
167
+ service,
168
+ taskDefinition,
169
+ executionRole,
170
+ taskRole,
171
+ containers,
172
+ primaryContainer,
173
+ targetGroup,
174
+ scalingPolicy
175
+ });
176
+ // Add service level connections
177
+ if (serviceProps.connections && serviceProps.connections.length > 0) {
178
+ for (const connectable of serviceProps.connections) {
179
+ service.connections.allowToDefaultPort(connectable);
180
+ }
181
+ }
182
+ }
183
+ validateProps(props) {
184
+ // Validate services array
185
+ if (!props.services || props.services.length === 0) {
186
+ throw new Error("At least one service must be specified.");
187
+ }
188
+ // Check for duplicate service names
189
+ const serviceNames = props.services.map((s) => s.name);
190
+ const duplicateServices = serviceNames.filter((name, index) => serviceNames.indexOf(name) !== index);
191
+ if (duplicateServices.length > 0) {
192
+ throw new Error(`Duplicate service names: ${[...new Set(duplicateServices)].join(", ")}`);
193
+ }
194
+ // Validate routing when multiple services have ports
195
+ const servicesWithPorts = props.services.filter((s) => s.containers.some((c) => c.port !== undefined));
196
+ if (servicesWithPorts.length > 1 && !this.loadBalancerDisabled) {
197
+ const missingRouting = servicesWithPorts.filter((s) => !s.routing?.path && !s.routing?.host);
198
+ if (missingRouting.length > 0) {
199
+ throw new Error(`Services with ports require routing config when cluster has multiple services: ` +
200
+ `${missingRouting.map((s) => s.name).join(", ")}. ` +
201
+ "Add routing: { path: '/...' } to each service.");
202
+ }
203
+ }
204
+ // Validate each service's containers
205
+ for (const service of props.services) {
206
+ if (!service.containers || service.containers.length === 0) {
207
+ throw new Error(`Service '${service.name}': At least one container must be specified.`);
208
+ }
209
+ // Check for duplicate container names within service
210
+ const containerNames = service.containers.map((c) => c.name);
211
+ const duplicateContainers = containerNames.filter((name, index) => containerNames.indexOf(name) !== index);
212
+ if (duplicateContainers.length > 0) {
213
+ throw new Error(`Service '${service.name}': Duplicate container names: ` +
214
+ `${[...new Set(duplicateContainers)].join(", ")}`);
215
+ }
216
+ }
217
+ }
218
+ setupConnections(props) {
219
+ // Find the first service with a port for default connection
220
+ let defaultPort = 80;
221
+ for (const service of props.services) {
222
+ const primaryContainer = service.containers.find((c) => c.port !== undefined);
223
+ if (primaryContainer?.port) {
224
+ defaultPort = primaryContainer.port;
225
+ break;
226
+ }
227
+ }
228
+ let securityGroups = [];
229
+ if (this.isEc2()) {
230
+ securityGroups = [this.asgSecurityGroup];
231
+ }
232
+ else {
233
+ const firstService = this.services.values().next().value;
234
+ securityGroups = firstService?.service?.connections?.securityGroups || [];
235
+ }
47
236
  this.connections = new aws_ec2_1.Connections({
48
- securityGroups: this.fargateService.connections.securityGroups,
49
- defaultPort: aws_ec2_1.Port.tcp(containerPort)
237
+ securityGroups,
238
+ defaultPort: aws_ec2_1.Port.tcp(defaultPort)
239
+ });
240
+ }
241
+ /**
242
+ * Creates the execution role for ECS infrastructure operations.
243
+ * Used by the ECS agent to pull images, write logs, and inject secrets.
244
+ * NOT used by application code - that's the task role.
245
+ */
246
+ createExecutionRole(serviceName) {
247
+ const executionRole = new aws_iam_1.Role(this, `${serviceName}ExecutionRole`, {
248
+ assumedBy: new aws_iam_1.ServicePrincipal("ecs-tasks.amazonaws.com")
249
+ });
250
+ // ECR pull permissions
251
+ executionRole.addToPolicy(new aws_iam_1.PolicyStatement({
252
+ effect: aws_iam_1.Effect.ALLOW,
253
+ actions: [
254
+ "ecr:GetAuthorizationToken",
255
+ "ecr:BatchCheckLayerAvailability",
256
+ "ecr:GetDownloadUrlForLayer",
257
+ "ecr:BatchGetImage"
258
+ ],
259
+ resources: ["*"]
260
+ }));
261
+ // CloudWatch Logs permissions
262
+ executionRole.addToPolicy(new aws_iam_1.PolicyStatement({
263
+ effect: aws_iam_1.Effect.ALLOW,
264
+ actions: [
265
+ "logs:CreateLogStream",
266
+ "logs:PutLogEvents",
267
+ "logs:CreateLogGroup"
268
+ ],
269
+ resources: ["*"]
270
+ }));
271
+ // Secrets Manager access for injecting secrets into containers
272
+ executionRole.addToPolicy(new aws_iam_1.PolicyStatement({
273
+ effect: aws_iam_1.Effect.ALLOW,
274
+ actions: [
275
+ "secretsmanager:GetSecretValue",
276
+ "secretsmanager:DescribeSecret"
277
+ ],
278
+ resources: ["*"]
279
+ }));
280
+ // KMS decrypt for secrets encrypted with customer-managed keys
281
+ executionRole.addToPolicy(new aws_iam_1.PolicyStatement({
282
+ effect: aws_iam_1.Effect.ALLOW,
283
+ actions: ["kms:Decrypt"],
284
+ resources: ["*"]
285
+ }));
286
+ return executionRole;
287
+ }
288
+ /**
289
+ * Creates the task role for application code running in the container.
290
+ * This role is assumed by the application, not the ECS agent.
291
+ * Includes default ECS Exec permissions plus any service-specific policies.
292
+ */
293
+ createTaskRole(serviceName, serviceProps) {
294
+ const taskRole = new aws_iam_1.Role(this, `${serviceName}TaskRole`, {
295
+ assumedBy: new aws_iam_1.ServicePrincipal("ecs-tasks.amazonaws.com")
296
+ });
297
+ // Default: SSM permissions for ECS Exec (ecs execute-command)
298
+ taskRole.addToPolicy(new aws_iam_1.PolicyStatement({
299
+ effect: aws_iam_1.Effect.ALLOW,
300
+ actions: [
301
+ "ssmmessages:CreateControlChannel",
302
+ "ssmmessages:CreateDataChannel",
303
+ "ssmmessages:OpenControlChannel",
304
+ "ssmmessages:OpenDataChannel"
305
+ ],
306
+ resources: ["*"]
307
+ }));
308
+ // Add service-specific inline policies
309
+ if (serviceProps.taskRoleInlinePolicies) {
310
+ for (const [policyName, policyDocument] of Object.entries(serviceProps.taskRoleInlinePolicies)) {
311
+ taskRole.attachInlinePolicy(new aws_iam_1.Policy(this, `${serviceName}${policyName}`, {
312
+ document: policyDocument
313
+ }));
314
+ }
315
+ }
316
+ // Add service-specific managed policies
317
+ if (serviceProps.taskRoleManagedPolicies) {
318
+ for (const policy of serviceProps.taskRoleManagedPolicies) {
319
+ taskRole.addManagedPolicy(policy);
320
+ }
321
+ }
322
+ return taskRole;
323
+ }
324
+ createTaskDefinition(serviceName, serviceProps, executionRole, taskRole) {
325
+ const cpu = serviceProps.cpu || 256;
326
+ const memoryLimitMiB = serviceProps.memoryLimitMiB || 512;
327
+ if (this.isFargate()) {
328
+ return new aws_ecs_1.FargateTaskDefinition(this, `${serviceName}TaskDefinition`, {
329
+ family: `${this.props.clusterName}-${serviceName}`,
330
+ cpu,
331
+ memoryLimitMiB,
332
+ executionRole,
333
+ taskRole,
334
+ runtimePlatform: {
335
+ cpuArchitecture: aws_ecs_1.CpuArchitecture.ARM64,
336
+ operatingSystemFamily: aws_ecs_1.OperatingSystemFamily.LINUX
337
+ }
338
+ });
339
+ }
340
+ else {
341
+ return new aws_ecs_1.Ec2TaskDefinition(this, `${serviceName}TaskDefinition`, {
342
+ family: `${this.props.clusterName}-${serviceName}`,
343
+ executionRole,
344
+ taskRole,
345
+ ...(this.directAccessEnabled && { networkMode: aws_ecs_1.NetworkMode.HOST })
346
+ });
347
+ }
348
+ }
349
+ addContainersToTask(serviceName, serviceProps, taskDefinition) {
350
+ const containers = [];
351
+ let primaryContainer;
352
+ for (const containerConfig of serviceProps.containers) {
353
+ const image = this.getContainerImage(serviceName, containerConfig, serviceProps);
354
+ const isFirstWithPort = !primaryContainer && containerConfig.port !== undefined;
355
+ // Build secrets
356
+ const secrets = {};
357
+ if (containerConfig.secretsImport) {
358
+ for (const [key, secretImport] of Object.entries(containerConfig.secretsImport)) {
359
+ const secret = aws_secretsmanager_1.Secret.fromSecretNameV2(this, `${serviceName}${containerConfig.name}${key}Secret`, secretImport.name);
360
+ secrets[key] = aws_ecs_2.Secret.fromSecretsManager(secret, secretImport.field);
361
+ }
362
+ }
363
+ const container = taskDefinition.addContainer(`${serviceName}${containerConfig.name}`, {
364
+ image,
365
+ containerName: containerConfig.name,
366
+ logging: new aws_ecs_1.AwsLogDriver({
367
+ streamPrefix: `/ecs/${this.props.clusterName}/${serviceName}/${containerConfig.name}`,
368
+ logRetention: 14
369
+ }),
370
+ environment: containerConfig.environment,
371
+ secrets,
372
+ command: containerConfig.command,
373
+ entryPoint: containerConfig.entryPoint,
374
+ essential: containerConfig.essential ?? true,
375
+ healthCheck: containerConfig.healthCheck
376
+ ? {
377
+ command: containerConfig.healthCheck.command,
378
+ interval: containerConfig.healthCheck.interval
379
+ ? aws_cdk_lib_1.Duration.seconds(containerConfig.healthCheck.interval)
380
+ : undefined,
381
+ timeout: containerConfig.healthCheck.timeout
382
+ ? aws_cdk_lib_1.Duration.seconds(containerConfig.healthCheck.timeout)
383
+ : undefined,
384
+ retries: containerConfig.healthCheck.retries,
385
+ startPeriod: containerConfig.healthCheck.startPeriod
386
+ ? aws_cdk_lib_1.Duration.seconds(containerConfig.healthCheck.startPeriod)
387
+ : undefined
388
+ }
389
+ : undefined,
390
+ ...(this.isEc2() && {
391
+ memoryLimitMiB: this.props.ec2Config?.memoryLimitMiB || 1024
392
+ })
393
+ });
394
+ if (containerConfig.port) {
395
+ container.addPortMappings({
396
+ containerPort: containerConfig.port
397
+ });
398
+ }
399
+ if (isFirstWithPort) {
400
+ primaryContainer = container;
401
+ }
402
+ containers.push(container);
403
+ }
404
+ return { containers, primaryContainer };
405
+ }
406
+ getContainerImage(serviceName, containerConfig, serviceProps) {
407
+ // Priority: container.image > service.image > cluster default
408
+ const imageSource = containerConfig.image || serviceProps.image || this.props.ecrRepository;
409
+ if (!imageSource) {
410
+ return aws_ecs_1.ContainerImage.fromRegistry("amazon/amazon-ecs-sample");
411
+ }
412
+ const imageTag = `${serviceName}-latest`;
413
+ if (typeof imageSource === "string") {
414
+ // Check if it's an ECR repository name or a public image
415
+ if (imageSource.includes("/") && !imageSource.includes(".")) {
416
+ return aws_ecs_1.ContainerImage.fromRegistry(imageSource);
417
+ }
418
+ return aws_ecs_1.ContainerImage.fromEcrRepository(aws_ecr_1.Repository.fromRepositoryName(this, `${serviceName}${containerConfig.name}EcrRepo`, imageSource), imageTag);
419
+ }
420
+ if (imageSource instanceof aws_ecr_1.Repository) {
421
+ return aws_ecs_1.ContainerImage.fromEcrRepository(imageSource, imageTag);
422
+ }
423
+ // RepositoryImage extends ContainerImage, so this is a safe upcast
424
+ return imageSource;
425
+ }
426
+ createService(serviceName, serviceProps, taskDefinition) {
427
+ const desiredCount = serviceProps.desiredCount ?? 2;
428
+ if (this.isFargate()) {
429
+ const service = new aws_ecs_1.FargateService(this, `${serviceName}Service`, {
430
+ cluster: this.cluster,
431
+ taskDefinition: taskDefinition,
432
+ desiredCount,
433
+ serviceName,
434
+ capacityProviderStrategies: [
435
+ {
436
+ capacityProvider: this.capacityProvider,
437
+ weight: 1
438
+ }
439
+ ],
440
+ propagateTags: aws_ecs_1.PropagatedTagSource.SERVICE,
441
+ circuitBreaker: { enable: true, rollback: true },
442
+ enableECSManagedTags: true,
443
+ enableExecuteCommand: true,
444
+ healthCheckGracePeriod: aws_cdk_lib_1.Duration.seconds(120),
445
+ minHealthyPercent: 100,
446
+ maxHealthyPercent: 200
447
+ });
448
+ new cfnOutput_1.CfnOutput(this, `${serviceName}ServiceArn`, {
449
+ key: `${serviceName}ServiceArn`,
450
+ exportName: `${this.props.clusterName}${serviceName}ServiceArn`,
451
+ value: service.serviceArn,
452
+ description: `ECS Service ARN for ${serviceName}`
453
+ });
454
+ // Fargate service depends on capacity provider associations:
455
+ // - CREATE: Associations created first, then Service (correct - providers ready before service)
456
+ // - DELETE: Service deleted first, then Associations (correct - services gone before disassociation)
457
+ // This ensures CloudFormation deletes all services BEFORE attempting to remove
458
+ // the FARGATE/FARGATE_SPOT capacity provider associations from the cluster.
459
+ // See: https://github.com/aws/aws-cdk/issues/15366
460
+ if (this.fargateCapacityProviderAssociations) {
461
+ service.node.addDependency(this.fargateCapacityProviderAssociations);
462
+ }
463
+ return service;
464
+ }
465
+ else {
466
+ const service = new aws_ecs_1.Ec2Service(this, `${serviceName}Service`, {
467
+ cluster: this.cluster,
468
+ taskDefinition: taskDefinition,
469
+ desiredCount,
470
+ serviceName,
471
+ capacityProviderStrategies: [
472
+ {
473
+ capacityProvider: this.asgCapacityProvider.capacityProviderName,
474
+ weight: 1
475
+ }
476
+ ],
477
+ propagateTags: aws_ecs_1.PropagatedTagSource.SERVICE,
478
+ circuitBreaker: { enable: true, rollback: true },
479
+ placementStrategies: [aws_ecs_1.PlacementStrategy.spreadAcrossInstances()],
480
+ enableECSManagedTags: true,
481
+ enableExecuteCommand: true,
482
+ healthCheckGracePeriod: aws_cdk_lib_1.Duration.seconds(120),
483
+ minHealthyPercent: 100,
484
+ maxHealthyPercent: 200
485
+ });
486
+ new cfnOutput_1.CfnOutput(this, `${serviceName}ServiceArn`, {
487
+ key: `${serviceName}ServiceArn`,
488
+ exportName: `${this.props.clusterName}${serviceName}ServiceArn`,
489
+ value: service.serviceArn,
490
+ description: `ECS Service ARN for ${serviceName}`
491
+ });
492
+ // Service depends on DrainWaiter:
493
+ // - CREATE: DrainWaiter created first, then Service (correct - infra ready before service)
494
+ // - DELETE: Service deleted first, then DrainWaiter runs (correct - services gone before drain)
495
+ // This ensures CloudFormation deletes all services BEFORE the DrainWaiter Lambda runs,
496
+ // which then disassociates the capacity provider before it's deleted.
497
+ if (this.drainWaiter) {
498
+ service.node.addDependency(this.drainWaiter);
499
+ }
500
+ return service;
501
+ }
502
+ }
503
+ registerServiceWithALB(serviceName, serviceProps, service, primaryContainer) {
504
+ const containerPort = primaryContainer.containerPort;
505
+ const healthCheckPath = serviceProps.routing?.healthCheckPath || "/";
506
+ // Determine routing conditions
507
+ const servicesWithPorts = this.props.services.filter((s) => s.containers.some((c) => c.port !== undefined));
508
+ const isSingleService = servicesWithPorts.length === 1;
509
+ const healthCheckConfig = this.isEc2()
510
+ ? {
511
+ interval: aws_cdk_lib_1.Duration.seconds(30),
512
+ healthyThresholdCount: 3,
513
+ unhealthyThresholdCount: 3,
514
+ path: healthCheckPath,
515
+ port: "traffic-port",
516
+ timeout: aws_cdk_lib_1.Duration.seconds(15)
517
+ }
518
+ : {
519
+ interval: aws_cdk_lib_1.Duration.seconds(120),
520
+ path: healthCheckPath,
521
+ port: `${containerPort}`,
522
+ timeout: aws_cdk_lib_1.Duration.seconds(10)
523
+ };
524
+ if (isSingleService) {
525
+ // Single service - create target group with service as default target
526
+ return this.loadBalancerListener.addTargets(`${serviceName}TargetGroup`, {
527
+ targets: [
528
+ service.loadBalancerTarget({
529
+ containerName: primaryContainer.containerName,
530
+ containerPort
531
+ })
532
+ ],
533
+ port: containerPort,
534
+ protocol: aws_elasticloadbalancingv2_1.ApplicationProtocol.HTTP,
535
+ healthCheck: healthCheckConfig
536
+ });
537
+ }
538
+ else {
539
+ // Multi-service - create target group with routing rules
540
+ const priority = serviceProps.routing?.priority || this.nextPriority++;
541
+ const targetGroup = this.loadBalancerListener.addTargets(`${serviceName}Targets`, {
542
+ targets: [
543
+ service.loadBalancerTarget({
544
+ containerName: primaryContainer.containerName,
545
+ containerPort
546
+ })
547
+ ],
548
+ port: containerPort,
549
+ protocol: aws_elasticloadbalancingv2_1.ApplicationProtocol.HTTP,
550
+ healthCheck: healthCheckConfig,
551
+ conditions: this.buildRoutingConditions(serviceProps),
552
+ priority
553
+ });
554
+ return targetGroup;
555
+ }
556
+ }
557
+ buildRoutingConditions(serviceProps) {
558
+ const conditions = [];
559
+ if (serviceProps.routing?.path) {
560
+ conditions.push(aws_elasticloadbalancingv2_1.ListenerCondition.pathPatterns([serviceProps.routing.path]));
561
+ }
562
+ if (serviceProps.routing?.host) {
563
+ conditions.push(aws_elasticloadbalancingv2_1.ListenerCondition.hostHeaders([serviceProps.routing.host]));
564
+ }
565
+ return conditions;
566
+ }
567
+ addServiceScaling(serviceName, serviceProps, service) {
568
+ const scalableTarget = new aws_applicationautoscaling_1.ScalableTarget(this, `${serviceName}ScalableTarget`, {
569
+ serviceNamespace: aws_applicationautoscaling_1.ServiceNamespace.ECS,
570
+ resourceId: `service/${this.cluster.clusterName}/${service.serviceName}`,
571
+ scalableDimension: "ecs:service:DesiredCount",
572
+ minCapacity: serviceProps.minCapacity ?? 2,
573
+ maxCapacity: serviceProps.maxCapacity ?? 10
50
574
  });
575
+ return new aws_applicationautoscaling_1.TargetTrackingScalingPolicy(this, `${serviceName}ScalingPolicy`, {
576
+ scalingTarget: scalableTarget,
577
+ predefinedMetric: serviceProps.scalingType === ScalingType.MEMORY
578
+ ? aws_applicationautoscaling_1.PredefinedMetric.ECS_SERVICE_AVERAGE_MEMORY_UTILIZATION
579
+ : aws_applicationautoscaling_1.PredefinedMetric.ECS_SERVICE_AVERAGE_CPU_UTILIZATION,
580
+ targetValue: 50,
581
+ scaleInCooldown: aws_cdk_lib_1.Duration.seconds(60),
582
+ scaleOutCooldown: aws_cdk_lib_1.Duration.seconds(60)
583
+ });
584
+ }
585
+ isEc2() {
586
+ return this.capacityProvider === "EC2";
587
+ }
588
+ isFargate() {
589
+ return (this.capacityProvider === "FARGATE" ||
590
+ this.capacityProvider === "FARGATE_SPOT");
51
591
  }
52
592
  addCluster(props) {
53
593
  this.cluster = new aws_ecs_1.Cluster(this, `${props.clusterName}`, {
54
594
  vpc: props.vpc,
55
595
  clusterName: props.clusterName,
56
596
  containerInsightsV2: aws_ecs_1.ContainerInsights.ENABLED,
57
- enableFargateCapacityProviders: true
597
+ enableFargateCapacityProviders: this.isFargate()
58
598
  });
59
- // Output used to auto-detect deployable cluter
599
+ // For Fargate clusters, find the internal CfnClusterCapacityProviderAssociations
600
+ // that CDK creates when enableFargateCapacityProviders is true.
601
+ // We need this reference to establish proper deletion dependencies.
602
+ if (this.isFargate()) {
603
+ // CDK creates this as a child of the cluster with a specific naming pattern
604
+ const children = this.cluster.node.children;
605
+ for (const child of children) {
606
+ if (child instanceof aws_ecs_1.CfnClusterCapacityProviderAssociations) {
607
+ this.fargateCapacityProviderAssociations = child;
608
+ break;
609
+ }
610
+ }
611
+ }
60
612
  new cfnOutput_1.CfnOutput(this, `${props.clusterName}DeployableCluster`, {
61
613
  key: `${props.clusterName}DeployableCluster`,
62
614
  exportName: `${props.clusterName}DeployableCluster`,
63
615
  value: this.cluster.clusterArn
64
616
  });
65
- // Export cluster ARN for monitoring
66
617
  new cfnOutput_1.CfnOutput(this, `${props.clusterName}ClusterArn`, {
67
618
  key: "ClusterArn",
68
619
  exportName: `${props.clusterName}ClusterArn`,
@@ -70,207 +621,110 @@ class FargateCluster extends constructs_1.Construct {
70
621
  description: `ECS Cluster ARN for ${props.clusterName}`
71
622
  });
72
623
  }
73
- /**
74
- * #todo: change this to create new secrets instead
75
- * @deprecated use importSecrets instead
76
- */
77
- addSecrets(props) {
78
- // Container Secrets
79
- const containerSecret = aws_secretsmanager_1.Secret.fromSecretNameV2(this, `${props.clusterName}Secret`, `/${props.clusterName}/${props.serviceName}`);
80
- for (const secretField in props.containerSecrets) {
81
- this.secrets[secretField] = aws_ecs_2.Secret.fromSecretsManager(containerSecret, secretField);
82
- }
83
- }
84
- /**
85
- * Automatically import secrets from another resource or stack
86
- */
87
- importSecrets(props) {
88
- if (!props.containerSecretsImport)
89
- return;
90
- for (const key in props.containerSecretsImport) {
91
- const importSecret = props.containerSecretsImport[key];
92
- // todo: I think ID needs to be a new value as it ID's the IMPORT not the secret itself?
93
- // Construct the AWS ISecret object
94
- const iSecret = aws_secretsmanager_1.Secret.fromSecretNameV2(this, importSecret.id, importSecret.name);
95
- this.secrets[key] = aws_ecs_2.Secret.fromSecretsManager(iSecret, importSecret.field);
96
- }
97
- }
98
- addExecutionRole(props) {
99
- this.executionRole = new aws_iam_1.Role(this, `${props.serviceName}ExecutionRole${aws_cdk_lib_1.Stack.of(this).region}`, {
100
- roleName: `${props.serviceName}ExecutionRole${aws_cdk_lib_1.Stack.of(this).region}`,
101
- description: `${props.serviceName} Execution Role`,
102
- managedPolicies: [
103
- {
104
- managedPolicyArn: "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
105
- }
106
- ],
107
- inlinePolicies: {
108
- ["readSecrets"]: new aws_iam_1.PolicyDocument({
109
- statements: [
110
- new aws_iam_1.PolicyStatement({
111
- actions: [
112
- "secretsmanager:GetSecretValue",
113
- "secretsmanager:DescribeSecret"
114
- ],
115
- resources: ["*"] // TODO: Set this to the secret ARN
116
- })
117
- ]
118
- }),
119
- ["decryptSecrets"]: new aws_iam_1.PolicyDocument({
120
- statements: [
121
- new aws_iam_1.PolicyStatement({
122
- actions: ["kms:Decrypt"],
123
- resources: ["*"] // TODO: Set this to the KMS Arn
124
- })
125
- ]
126
- }),
127
- ["ecsExecuteCommand"]: new aws_iam_1.PolicyDocument({
128
- statements: [
129
- new aws_iam_1.PolicyStatement({
130
- actions: [
131
- "ssmmessages:CreateControlChannel",
132
- "ssmmessages:CreateDataChannel",
133
- "ssmmessages:OpenControlChannel",
134
- "ssmmessages:OpenDataChannel"
135
- ],
136
- effect: aws_iam_1.Effect.ALLOW,
137
- resources: ["*"]
138
- })
139
- ]
140
- })
141
- },
142
- assumedBy: new aws_iam_1.CompositePrincipal(new aws_iam_1.ServicePrincipal("ecs-tasks.amazonaws.com"))
143
- });
144
- }
145
- addTaskDefinition(props) {
146
- this.taskDefinition = new aws_ecs_1.FargateTaskDefinition(this, `${props.serviceName}TaskDefinition`, {
147
- cpu: props.cpu || 256,
148
- executionRole: this.executionRole,
149
- taskRole: new aws_iam_1.Role(this, `${props.serviceName}TaskRole${aws_cdk_lib_1.Stack.of(this).region}`, {
150
- roleName: `${props.serviceName}TaskRole${aws_cdk_lib_1.Stack.of(this).region}`,
151
- description: `${props.serviceName} Task Role`,
152
- inlinePolicies: props.taskRoleInlinePolicies,
153
- managedPolicies: props.taskRoleManagedPolicies,
154
- assumedBy: new aws_iam_1.CompositePrincipal(new aws_iam_1.ServicePrincipal("ecs-tasks.amazonaws.com"))
155
- }),
156
- memoryLimitMiB: props.memoryLimitMiB || 512
624
+ addAutoScalingGroup(props) {
625
+ const ec2Config = props.ec2Config || {};
626
+ const instanceType = ec2Config.instanceType || "t3.micro";
627
+ const amiHardwareType = ec2Config.amiHardwareType === "STANDARD"
628
+ ? aws_ecs_1.AmiHardwareType.STANDARD
629
+ : aws_ecs_1.AmiHardwareType.ARM;
630
+ const minCapacity = ec2Config.minCapacity ?? 2;
631
+ const maxCapacity = ec2Config.maxCapacity ?? 3;
632
+ this.asgSecurityGroup = new securityGroup_1.SecurityGroup(this, `AsgSecurityGroup`, {
633
+ vpc: this.cluster.vpc,
634
+ description: `Security group for the ${props.clusterName} auto scaling group`
157
635
  });
158
- }
159
- addContainerDefinition(props) {
160
- this.containerDefinition = this.taskDefinition.addContainer(`${props.serviceName}ContainerDefinition`, {
161
- image: this.getImage(props),
162
- containerName: props.serviceName,
163
- environment: {
164
- ...props.containerEnvironment
165
- },
166
- command: props.containerCommand,
167
- secrets: {
168
- ...this.secrets
169
- },
170
- //todo: provide health check options
171
- healthCheck: {
172
- command: [
173
- "CMD-SHELL",
174
- // https://docs.aws.amazon.com/AmazonECS/latest/developerguide/view-container-health.html
175
- // >> proc/1/fd/1 2>&1 redirects stdout and stderr of the health check to CloudWatch logs
176
- // `curl -f http://localhost:${props.containerPort}/ >> /proc/1/fd/1 2>&1 || exit 1`
177
- `curl -f http://localhost:${props.containerPort}/ || exit 1`
178
- ]
636
+ // Open container ports for direct EC2 access
637
+ if (this.directAccessEnabled) {
638
+ for (const service of props.services) {
639
+ for (const container of service.containers) {
640
+ if (container.port) {
641
+ this.asgSecurityGroup.addIngressRule(aws_ec2_1.Peer.anyIpv4(), aws_ec2_1.Port.tcp(container.port), `Direct access to container port ${container.port}`);
642
+ }
643
+ }
644
+ }
645
+ }
646
+ this.autoScalingGroup = new aws_autoscaling_1.AutoScalingGroup(this, "AutoScalingGroup", {
647
+ autoScalingGroupName: `${props.clusterName}AutoScalingGroup`,
648
+ vpc: this.cluster.vpc,
649
+ vpcSubnets: {
650
+ subnetType: aws_ec2_1.SubnetType.PUBLIC
179
651
  },
180
- logging: new aws_ecs_1.AwsLogDriver({
181
- streamPrefix: `/ecs/${props.clusterName}/${props.serviceName}`,
182
- logRetention: 14
183
- }),
184
- portMappings: props.containerPort
185
- ? [{ containerPort: props.containerPort }]
186
- : [{ containerPort: 80 }]
187
- });
188
- }
189
- addFargateService(props) {
190
- this.fargateService = new aws_ecs_1.FargateService(this, `${props.serviceName}FargateService`, {
191
- circuitBreaker: { rollback: true },
192
- cluster: this.cluster,
193
- desiredCount: 2,
194
- enableECSManagedTags: true,
195
- enableExecuteCommand: true,
196
- propagateTags: aws_ecs_1.PropagatedTagSource.SERVICE,
197
- serviceName: `${props.serviceName}`,
198
- taskDefinition: this.taskDefinition,
199
- minHealthyPercent: 100,
200
- maxHealthyPercent: 200
652
+ securityGroup: this.asgSecurityGroup,
653
+ minCapacity,
654
+ maxCapacity,
655
+ instanceType: new aws_ec2_1.InstanceType(instanceType),
656
+ capacityRebalance: true,
657
+ instanceMonitoring: aws_autoscaling_1.Monitoring.BASIC,
658
+ machineImage: aws_ecs_1.EcsOptimizedImage.amazonLinux2(amiHardwareType)
201
659
  });
202
- // Output used to detect deployable service
203
- new cfnOutput_1.CfnOutput(this, `${props.clusterName}DeployableService`, {
204
- key: `${props.clusterName}DeployableService`,
205
- exportName: `${props.clusterName}DeployableService`,
206
- value: this.fargateService.serviceArn
207
- });
208
- // Export service ARN for monitoring
209
- new cfnOutput_1.CfnOutput(this, `${props.clusterName}ServiceArn`, {
210
- key: "ServiceArn",
211
- exportName: `${props.clusterName}ServiceArn`,
212
- value: this.fargateService.serviceArn,
213
- description: `ECS Service ARN for ${props.serviceName}`
214
- });
215
- }
216
- addScalingPolicy(props) {
217
- this.scalingPolicy = new aws_applicationautoscaling_1.TargetTrackingScalingPolicy(this, `${props.serviceName}ScalingPolicy`, {
218
- policyName: `${props.serviceName}ScalingPolicy`,
219
- scalingTarget: new aws_applicationautoscaling_1.ScalableTarget(this, `${props.serviceName}scalableTarget`, {
220
- maxCapacity: 10,
221
- minCapacity: 2,
222
- resourceId: `service/${this.cluster.clusterName}/${this.fargateService.serviceName}`,
223
- scalableDimension: "ecs:service:DesiredCount",
224
- serviceNamespace: aws_applicationautoscaling_1.ServiceNamespace.ECS
225
- }),
226
- targetValue: 50,
227
- scaleOutCooldown: aws_cdk_lib_1.Duration.seconds(60),
228
- scaleInCooldown: aws_cdk_lib_1.Duration.seconds(60),
229
- predefinedMetric: props.scalingType == ScalingType.MEMORY
230
- ? aws_applicationautoscaling_1.PredefinedMetric.ECS_SERVICE_AVERAGE_MEMORY_UTILIZATION
231
- : aws_applicationautoscaling_1.PredefinedMetric.ECS_SERVICE_AVERAGE_CPU_UTILIZATION
660
+ this.asgCapacityProvider = new aws_ecs_1.AsgCapacityProvider(this, "AsgCapacityProvider", {
661
+ autoScalingGroup: this.autoScalingGroup,
662
+ enableManagedDraining: true,
663
+ enableManagedTerminationProtection: false
232
664
  });
233
- }
234
- registerLoadBalancerTargets(props) {
235
- this.fargateService.registerLoadBalancerTargets({
236
- containerName: this.containerDefinition.containerName,
237
- containerPort: this.containerDefinition.containerPort,
238
- newTargetGroupId: `${props.serviceName}TargetGroup`,
239
- listener: aws_ecs_1.ListenerConfig.applicationListener(this.loadBalancerListener, {
240
- port: props.containerPort,
241
- protocol: aws_elasticloadbalancingv2_1.ApplicationProtocol.HTTP,
242
- healthCheck: {
243
- interval: aws_cdk_lib_1.Duration.seconds(120),
244
- path: props.healthCheckPath || "/",
245
- port: props.containerPort ? `${props.containerPort}` : "traffic-port",
246
- timeout: aws_cdk_lib_1.Duration.seconds(10)
247
- }
248
- })
665
+ this.cluster.addAsgCapacityProvider(this.asgCapacityProvider);
666
+ // Create drain waiter custom resource that handles capacity provider cleanup during deletion.
667
+ // This resource waits for ECS services to drain, then disassociates the capacity provider
668
+ // from the cluster before CloudFormation attempts to delete the AsgCapacityProvider.
669
+ //
670
+ // Dependency chain for DELETE order:
671
+ // Services deleted → DrainWaiter runs → AsgCapacityProvider deleted → Cluster deleted
672
+ //
673
+ // The drain waiter must depend on AsgCapacityProvider so it runs BEFORE the provider is deleted.
674
+ // Services must depend on the drain waiter so they're deleted BEFORE the drain waiter runs.
675
+ this.drainWaiter = new capacityProviderDrainWaiter_1.CapacityProviderDrainWaiter(this, "CapacityProviderDrainWaiter", {
676
+ clusterName: props.clusterName,
677
+ capacityProviderName: this.asgCapacityProvider.capacityProviderName
249
678
  });
679
+ // DrainWaiter depends on AsgCapacityProvider:
680
+ // - CREATE: AsgCapacityProvider created first, then DrainWaiter
681
+ // - DELETE: DrainWaiter deleted first (runs Lambda), then AsgCapacityProvider
682
+ this.drainWaiter.node.addDependency(this.asgCapacityProvider);
250
683
  }
251
684
  addLoadBalancer(props) {
252
- // Truncate the load balancer name to ensure it does not exceed the 32 character AWS limit
253
- const defaultLoadBalancerName = `${props.serviceName}LoadBalancer`;
685
+ const defaultLoadBalancerName = `${props.clusterName}LoadBalancer`;
254
686
  const supportedNameLength = 32;
255
687
  let truncatedLoadBalancerName = defaultLoadBalancerName.length > supportedNameLength
256
688
  ? defaultLoadBalancerName.substring(0, supportedNameLength)
257
689
  : defaultLoadBalancerName;
258
- // Remove any trailing hyphens that might be introduced by truncation
259
690
  truncatedLoadBalancerName = truncatedLoadBalancerName.replace(/-+$/, "");
260
- this.loadBalancer = new aws_elasticloadbalancingv2_1.ApplicationLoadBalancer(this, `${props.clusterName}LoadBalancer`, {
261
- vpc: this.cluster.vpc,
262
- internetFacing: true,
263
- loadBalancerName: truncatedLoadBalancerName,
264
- vpcSubnets: {
265
- subnetType: aws_ec2_1.SubnetType.PUBLIC
266
- }
267
- });
691
+ const isInternal = props.cluster?.loadBalancer === "internal";
692
+ if (this.isEc2()) {
693
+ this.loadBalancerSecurityGroup = new securityGroup_1.SecurityGroup(this, `LoadBalancerSecurityGroup`, {
694
+ vpc: this.cluster.vpc,
695
+ description: `Security group for the ${props.clusterName} load balancer`
696
+ });
697
+ this.loadBalancerSecurityGroup.connections.allowTo(this.asgSecurityGroup, aws_ec2_1.Port.allTcp());
698
+ this.loadBalancer = new aws_elasticloadbalancingv2_1.ApplicationLoadBalancer(this, `${props.clusterName}LoadBalancer`, {
699
+ vpc: this.cluster.vpc,
700
+ internetFacing: !isInternal,
701
+ securityGroup: this.loadBalancerSecurityGroup,
702
+ loadBalancerName: truncatedLoadBalancerName,
703
+ vpcSubnets: {
704
+ subnetType: isInternal
705
+ ? aws_ec2_1.SubnetType.PRIVATE_WITH_EGRESS
706
+ : aws_ec2_1.SubnetType.PUBLIC
707
+ }
708
+ });
709
+ this.asgSecurityGroup.connections.allowFrom(this.loadBalancerSecurityGroup, aws_ec2_1.Port.tcpRange(49152, 65535));
710
+ }
711
+ else {
712
+ this.loadBalancer = new aws_elasticloadbalancingv2_1.ApplicationLoadBalancer(this, `${props.clusterName}LoadBalancer`, {
713
+ vpc: this.cluster.vpc,
714
+ internetFacing: !isInternal,
715
+ loadBalancerName: truncatedLoadBalancerName,
716
+ vpcSubnets: {
717
+ subnetType: isInternal
718
+ ? aws_ec2_1.SubnetType.PRIVATE_WITH_EGRESS
719
+ : aws_ec2_1.SubnetType.PUBLIC
720
+ }
721
+ });
722
+ }
268
723
  new cfnOutput_1.CfnOutput(this, `${props.clusterName}LoadBalancerDnsName`, {
269
724
  key: `${props.clusterName}LoadBalancerDnsName`,
270
725
  exportName: `${props.clusterName}LoadBalancerDnsName`,
271
726
  value: this.loadBalancer.loadBalancerDnsName
272
727
  });
273
- // Export load balancer URL for monitoring
274
728
  new cfnOutput_1.CfnOutput(this, `${props.clusterName}LoadBalancerUrl`, {
275
729
  key: "LoadBalancerUrl",
276
730
  exportName: `${props.clusterName}LoadBalancerUrl`,
@@ -278,84 +732,114 @@ class FargateCluster extends constructs_1.Construct {
278
732
  description: `Load Balancer URL for ${props.clusterName}`
279
733
  });
280
734
  }
735
+ addDirectAccessOutputs(props) {
736
+ if (!this.directAccessEnabled || !this.autoScalingGroup)
737
+ return;
738
+ // Get the first container port (for user instructions)
739
+ const containerPort = props.services.flatMap((s) => s.containers).find((c) => c.port)?.port ||
740
+ 3000;
741
+ new cfnOutput_1.CfnOutput(this, `${props.clusterName}AutoScalingGroupName`, {
742
+ key: "AutoScalingGroupName",
743
+ exportName: `${props.clusterName}AutoScalingGroupName`,
744
+ value: this.autoScalingGroup.autoScalingGroupName,
745
+ description: `Run: aws autoscaling describe-auto-scaling-groups --auto-scaling-group-names <name> to find instance IP`
746
+ });
747
+ new cfnOutput_1.CfnOutput(this, `${props.clusterName}DirectAccessPort`, {
748
+ key: "DirectAccessPort",
749
+ exportName: `${props.clusterName}DirectAccessPort`,
750
+ value: String(containerPort),
751
+ description: `Access your app at http://<EC2-PUBLIC-IP>:${containerPort}`
752
+ });
753
+ }
281
754
  addLoadBalancerListener(props) {
755
+ if (!this.loadBalancer)
756
+ return;
757
+ // Determine port based on whether HTTPS is configured (domain + cert)
758
+ const port = this.certificate ? 443 : 80;
759
+ // Default action for requests that don't match any routing rule
760
+ // Returns 404 for multi-service clusters with routing rules
761
+ const defaultAction = aws_elasticloadbalancingv2_1.ListenerAction.fixedResponse(404, {
762
+ contentType: "text/plain",
763
+ messageBody: "Not Found"
764
+ });
282
765
  if (this.certificate) {
283
- this.loadBalancerListener = this.loadBalancer.addListener(`${props.serviceName}Listener`, {
284
- port: props.protocol == Protocol.HTTP ? 80 : 443,
285
- certificates: [this.certificate]
766
+ this.loadBalancerListener = this.loadBalancer.addListener(`${props.clusterName}Listener`, {
767
+ port,
768
+ certificates: [this.certificate],
769
+ defaultAction
286
770
  });
287
771
  }
288
772
  else {
289
- this.loadBalancerListener = this.loadBalancer.addListener(`${props.serviceName}Listener`, {
290
- port: props.protocol == Protocol.HTTP ? 80 : 443
773
+ this.loadBalancerListener = this.loadBalancer.addListener(`${props.clusterName}Listener`, {
774
+ port,
775
+ defaultAction
291
776
  });
292
777
  }
293
778
  }
294
779
  addHostedZone(props) {
295
- if (!props.domainConfig)
780
+ // Support both new cluster.domain and advanced cluster.domainConfig
781
+ const domainConfig = props.cluster?.domainConfig;
782
+ const simpleDomain = props.cluster?.domain;
783
+ if (!domainConfig && !simpleDomain)
296
784
  return;
297
- if (!props.domainConfig.hostedZone) {
298
- // Create a new hosted zone if one is not provided
299
- const hostedZone = new hostedZone_1.HostedZone(this, `${props.serviceName}HostedZone`, {
300
- zoneName: props.domainConfig.domainName
785
+ const domainName = domainConfig?.domainName || simpleDomain;
786
+ if (!domainConfig?.hostedZone) {
787
+ const hostedZone = new hostedZone_1.HostedZone(this, `${props.clusterName}HostedZone`, {
788
+ zoneName: domainName
301
789
  });
302
790
  this.hostedZone = hostedZone.getInternalHostedZone();
303
791
  }
304
792
  else {
305
- // Otherwise use the provided hosted zone
306
- this.hostedZone = props.domainConfig.hostedZone.getInternalHostedZone();
793
+ this.hostedZone = domainConfig.hostedZone.getInternalHostedZone();
307
794
  }
308
- if (!props.domainConfig.certificate) {
309
- // If no certificate is provided - create a new one
310
- this.certificate = new aws_certificatemanager_1.Certificate(this, `${props.serviceName}Certificate`, {
311
- domainName: props.domainConfig.domainName,
795
+ if (!domainConfig?.certificate) {
796
+ this.certificate = new aws_certificatemanager_1.Certificate(this, `${props.clusterName}Certificate`, {
797
+ domainName,
312
798
  validation: aws_certificatemanager_1.CertificateValidation.fromDns(this.hostedZone)
313
799
  });
314
800
  }
315
- // Check if this is a multi-region/weighted/geo routing configuration
316
- const latencyConfig = props.domainConfig;
317
- const weightedConfig = props.domainConfig;
318
- const geoConfig = props.domainConfig;
319
- const hasRoutingPolicy = !!latencyConfig?.region ||
320
- weightedConfig?.weight !== undefined ||
321
- !!geoConfig?.geoLocation;
322
- // Generate setIdentifier if not provided and using routing policies
323
- // AWS requires setIdentifier for all routing policies (latency, weighted, geo, failover, multivalue)
324
- let setIdentifier = props.domainConfig.setIdentifier;
325
- if (hasRoutingPolicy && !setIdentifier) {
326
- if (latencyConfig?.region) {
327
- setIdentifier = `${props.serviceName}-${latencyConfig.region}`;
328
- }
329
- else if (weightedConfig?.weight !== undefined) {
330
- setIdentifier = `${props.serviceName}-weight-${weightedConfig.weight}`;
801
+ // Handle advanced routing policies (latency, weighted, geo)
802
+ if (domainConfig) {
803
+ const latencyConfig = domainConfig;
804
+ const weightedConfig = domainConfig;
805
+ const geoConfig = domainConfig;
806
+ const hasRoutingPolicy = !!latencyConfig?.region ||
807
+ weightedConfig?.weight !== undefined ||
808
+ !!geoConfig?.geoLocation;
809
+ let setIdentifier = domainConfig.setIdentifier;
810
+ if (hasRoutingPolicy && !setIdentifier) {
811
+ if (latencyConfig?.region) {
812
+ setIdentifier = `${props.clusterName}${latencyConfig.region}`;
813
+ }
814
+ else if (weightedConfig?.weight !== undefined) {
815
+ setIdentifier = `${props.clusterName}Weight${weightedConfig.weight}`;
816
+ }
817
+ else if (geoConfig?.geoLocation) {
818
+ setIdentifier = `${props.clusterName}Geo`;
819
+ }
331
820
  }
332
- else if (geoConfig?.geoLocation) {
333
- setIdentifier = `${props.serviceName}-geo`;
821
+ if (this.loadBalancer) {
822
+ this.aRecord = new aws_route53_1.ARecord(this, `${props.clusterName}ARecord`, {
823
+ recordName: domainName,
824
+ zone: this.hostedZone,
825
+ target: aws_route53_1.RecordTarget.fromAlias(new aws_route53_targets_1.LoadBalancerTarget(this.loadBalancer, {
826
+ evaluateTargetHealth: hasRoutingPolicy
827
+ })),
828
+ region: latencyConfig?.region,
829
+ weight: weightedConfig?.weight,
830
+ geoLocation: geoConfig?.geoLocation,
831
+ setIdentifier: setIdentifier
832
+ });
334
833
  }
335
834
  }
336
- // Always create a new ARecord for this domain and attach it to the load balancer
337
- this.aRecord = new aws_route53_1.ARecord(this, `${props.serviceName}.${props.clusterName}.${props.domainConfig.domainName}ARecord`, {
338
- recordName: props.domainConfig.domainName,
339
- zone: this.hostedZone,
340
- target: aws_route53_1.RecordTarget.fromAlias(new aws_route53_targets_1.LoadBalancerTarget(this.loadBalancer, {
341
- evaluateTargetHealth: hasRoutingPolicy
342
- })),
343
- region: latencyConfig?.region,
344
- weight: weightedConfig?.weight,
345
- geoLocation: geoConfig?.geoLocation,
346
- // Set identifier is required for routing policies (latency, weighted, geo, failover, multivalue)
347
- setIdentifier: setIdentifier
348
- });
349
- }
350
- getImage(props) {
351
- if (!props.ecrRepository)
352
- return aws_ecs_1.ContainerImage.fromRegistry("amazon/amazon-ecs-sample");
353
- if (props.ecrRepository instanceof aws_ecs_1.ContainerImage)
354
- return props.ecrRepository;
355
- if (props.ecrRepository instanceof aws_ecr_1.Repository) {
356
- return aws_ecs_1.ContainerImage.fromEcrRepository(props.ecrRepository, "latest");
835
+ else if (simpleDomain && this.loadBalancer) {
836
+ // Simple domain - just create A record
837
+ this.aRecord = new aws_route53_1.ARecord(this, `${props.clusterName}ARecord`, {
838
+ recordName: domainName,
839
+ zone: this.hostedZone,
840
+ target: aws_route53_1.RecordTarget.fromAlias(new aws_route53_targets_1.LoadBalancerTarget(this.loadBalancer))
841
+ });
357
842
  }
358
- return aws_ecs_1.ContainerImage.fromRegistry("amazon/amazon-ecs-sample");
359
843
  }
360
844
  static build(id, props) {
361
845
  return (sb) => {
@@ -369,5 +853,5 @@ class FargateCluster extends constructs_1.Construct {
369
853
  };
370
854
  }
371
855
  }
372
- exports.default = FargateCluster;
373
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWNzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vbGliL3Jlc291cmNlcy9hd3MvY29tcHV0ZS9lY3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsaURBVzZCO0FBQzdCLGlEQU02QjtBQUM3QiwyQ0FBdUM7QUFFdkMsNkNBQWdFO0FBQ2hFLHVGQUlnRDtBQUNoRCxpREFRNkI7QUFDN0IsdUZBS2dEO0FBQ2hELGlEQUEwRDtBQUMxRCx1RUFBd0Q7QUFDeEQsK0VBRzRDO0FBQzVDLHlEQUtpQztBQUNqQyx5RUFBcUU7QUFDckUsaURBQWlEO0FBR2pELHNEQUFtRDtBQUNuRCxpRUFBaUY7QUFJakYsSUFBWSxRQUdYO0FBSEQsV0FBWSxRQUFRO0lBQ2xCLHVDQUFJLENBQUE7SUFDSix5Q0FBSyxDQUFBO0FBQ1AsQ0FBQyxFQUhXLFFBQVEsd0JBQVIsUUFBUSxRQUduQjtBQUVELElBQVksV0FHWDtBQUhELFdBQVksV0FBVztJQUNyQixzREFBMEQsQ0FBQTtJQUMxRCw0REFBZ0UsQ0FBQTtBQUNsRSxDQUFDLEVBSFcsV0FBVywyQkFBWCxXQUFXLFFBR3RCO0FBcUVELE1BQXFCLGNBQWUsU0FBUSxzQkFBUztJQXFCbkQsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxLQUEwQjtRQUNsRSxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBUFgsWUFBTyxHQUVYLEVBQUUsQ0FBQztRQU9MLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO1FBRW5CLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDdkIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN2QixJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzFCLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUM3QixJQUFJLENBQUMsaUJBQWlCLENBQUMsS0FBSyxD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Q0osQ0FBQztDQUNGO0FBdGRELGlDQXNkQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIEF3c0xvZ0RyaXZlcixcbiAgQ2x1c3RlciBhcyBDZGtDbHVzdGVyLFxuICBDb250YWluZXJJbWFnZSxcbiAgRmFyZ2F0ZVNlcnZpY2UsXG4gIEZhcmdhdGVUYXNrRGVmaW5pdGlvbixcbiAgTGlzdGVuZXJDb25maWcsXG4gIFByb3BhZ2F0ZWRUYWdTb3VyY2UsXG4gIHR5cGUgUmVwb3NpdG9yeUltYWdlLFxuICB0eXBlIENvbnRhaW5lckRlZmluaXRpb24sXG4gIENvbnRhaW5lckluc2lnaHRzXG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtZWNzXCI7XG5pbXBvcnQge1xuICBDb25uZWN0aW9ucyxcbiAgdHlwZSBJQ29ubmVjdGFibGUsXG4gIHR5cGUgSVZwYyxcbiAgUG9ydCxcbiAgU3VibmV0VHlwZVxufSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWVjMlwiO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSBcImNvbnN0cnVjdHNcIjtcbmltcG9ydCB7IHR5cGUgU3RhY2tCdWlsZGVyIH0gZnJvbSBcIi4uL2Jhc2UvYXdzU3RhY2tcIjtcbmltcG9ydCB7IER1cmF0aW9uLCB0eXBlIFNlY3JldFZhbHVlLCBTdGFjayB9IGZyb20gXCJhd3MtY2RrLWxpYlwiO1xuaW1wb3J0IHtcbiAgdHlwZSBBcHBsaWNhdGlvbkxpc3RlbmVyLFxuICBBcHBsaWNhdGlvbkxvYWRCYWxhbmNlcixcbiAgQXBwbGljYXRpb25Qcm90b2NvbFxufSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWVsYXN0aWNsb2FkYmFsYW5jaW5ndjJcIjtcbmltcG9ydCB7XG4gIENvbXBvc2l0ZVByaW5jaXBhbCxcbiAgRWZmZWN0LFxuICB0eXBlIElNYW5hZ2VkUG9saWN5LFxuICBQb2xpY3lEb2N1bWVudCxcbiAgUG9saWN5U3RhdGVtZW50LFxuICBSb2xlLFxuICBTZXJ2aWNlUHJpbmNpcGFsXG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtaWFtXCI7XG5pbXBvcnQge1xuICBQcmVkZWZpbmVkTWV0cmljLFxuICBTY2FsYWJsZVRhcmdldCxcbiAgU2VydmljZU5hbWVzcGFjZSxcbiAgVGFyZ2V0VHJhY2tpbmdTY2FsaW5nUG9saWN5XG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtYXBwbGljYXRpb25hdXRvc2NhbGluZ1wiO1xuaW1wb3J0IHsgU2VjcmV0IGFzIEVjc1NlY3JldCB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtZWNzXCI7XG5pbXBvcnQgeyBTZWNyZXQgfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLXNlY3JldHNtYW5hZ2VyXCI7XG5pbXBvcnQge1xuICBDZXJ0aWZpY2F0ZSxcbiAgQ2VydGlmaWNhdGVWYWxpZGF0aW9uXG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtY2VydGlmaWNhdGVtYW5hZ2VyXCI7XG5pbXBvcnQge1xuICBBUmVjb3JkLFxuICBSZWNvcmRUYXJnZXQsXG4gIHR5cGUgSUhvc3RlZFpvbmUsXG4gIHR5cGUgR2VvTG9jYXRpb25cbn0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1yb3V0ZTUzXCI7XG5pbXBvcnQgeyBMb2FkQmFsYW5jZXJUYXJnZXQgfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLXJvdXRlNTMtdGFyZ2V0c1wiO1xuaW1wb3J0IHsgUmVwb3NpdG9yeSB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtZWNyXCI7XG5cbmltcG9ydCB7IHR5cGUgS2V5VmFsdWUgfSBmcm9tIFwiLi4vLi4vLi4vdHlwZXNcIjtcbmltcG9ydCB7IENmbk91dHB1dCB9IGZyb20gXCIuLi91dGlsaXRpZXMvY2ZuT3V0cHV0XCI7XG5pbXBvcnQgeyBIb3N0ZWRab25lIGFzIEZqYWxsSG9zdGVkWm9uZSB9IGZyb20gXCIuLi8uLi8uLi9wYXR0ZXJucy9hd3MvaG9zdGVkWm9uZVwiO1xuXG5pbXBvcnQgeyB0eXBlIFNlY3JldEltcG9ydCB9IGZyb20gXCIuLi9zZWNyZXRzXCI7XG5cbmV4cG9ydCBlbnVtIFByb3RvY29sIHtcbiAgSFRUUCxcbiAgSFRUUFNcbn1cblxuZXhwb3J0IGVudW0gU2NhbGluZ1R5cGUge1xuICBDUFUgPSBQcmVkZWZpbmVkTWV0cmljLkVDU19TRVJWSUNFX0FWRVJBR0VfQ1BVX1VUSUxJWkFUSU9OLFxuICBNRU1PUlkgPSBQcmVkZWZpbmVkTWV0cmljLkVDU19TRVJWSUNFX0FWRVJBR0VfTUVNT1JZX1VUSUxJWkFUSU9OXG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ29udGFpbmVyU2VjcmV0IHtcbiAgW2tleTogc3RyaW5nXTogU2VjcmV0VmFsdWU7XG59XG5cbi8qKlxuICogRG9tYWluQ29uZmlndXJhdGlvblxuICogLSBXaGVuIHN1cHBsaWVkIGEgZG9tYWluIG5hbWUsIGEgaG9zdGVkIHpvbmUsIGNlcnRpZmljYXRlIGFuZCBBUmVjb3JkIHdpbGwgYmUgY3JlYXRlZFxuICogLSBXaGVuIHN1cHBsaWVkIGEgZG9tYWluIG5hbWUgYW5kIGhvc3RlZCB6b25lLCBhIGNlcnRpZmljYXRlIGFuZCBBUmVjb3JkIHdpbGwgYmUgY3JlYXRlZFxuICogLSBXaGVuIGFsbCBwcm9wZXJ0aWVzIGFyZSBzdXBwbGllZCBvbmx5IGEgdGFyZ2V0IHdpbGwgYmUgY3JlYXRlZFxuICovXG5cbmV4cG9ydCBpbnRlcmZhY2UgRG9tYWluQmFzZUNvbmZpZyB7XG4gIGRvbWFpbk5hbWU6IHN0cmluZztcbiAgaG9zdGVkWm9uZT86IEZqYWxsSG9zdGVkWm9uZTtcbiAgY2VydGlmaWNhdGU/OiBDZXJ0aWZpY2F0ZTtcbiAgLy8gT3B0aW9uYWw6IFNldCBpZGVudGlmaWVyIGZvciByb3V0aW5nIHBvbGljaWVzIChhdXRvLWdlbmVyYXRlZCBpZiBub3QgcHJvdmlkZWQpXG4gIHNldElkZW50aWZpZXI/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTGF0ZW5jeURvbWFpbkNvbmZpZyBleHRlbmRzIERvbWFpbkJhc2VDb25maWcge1xuICAvLyBTZXQgdG8gZW5hYmxlIGxhdGVuY3kgYmFzZWQgcm91dGluZ1xuICByZWdpb246IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBXZWlnaHRlZERvbWFpbkNvbmZpZyBleHRlbmRzIERvbWFpbkJhc2VDb25maWcge1xuICAvLyBTZXQgdG8gZW5hYmxlIHdlaWdodGVkIHJvdXRpbmdcbiAgd2VpZ2h0OiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgR2VvTG9jYXRpb25Eb21haW5Db25maWcgZXh0ZW5kcyBEb21haW5CYXNlQ29uZmlnIHtcbiAgLy8gU2V0IHRvIGVuYWJsZSBnZW9sb2NhdGlvbiBiYXNlZCByb3V0aW5nXG4gIGdlb0xvY2F0aW9uOiBHZW9Mb2NhdGlvbjtcbn1cblxuZXhwb3J0IHR5cGUgRG9tYWluQ29uZmlnID1cbiAgfCBEb21haW5CYXNlQ29uZmlnXG4gIHwgTGF0ZW5jeURvbWFpbkNvbmZpZ1xuICB8IFdlaWdodGVkRG9tYWluQ29uZmlnXG4gIHwgR2VvTG9jYXRpb25Eb21haW5Db25maWc7XG5cbmV4cG9ydCB0eXBlIEZhcmdhdGVDbHVzdGVyUHJvcHMgPSB7XG4gIGVjclJlcG9zaXRvcnk6IFJlcG9zaXRvcnkgfCBSZXBvc2l0b3J5SW1hZ2U7XG4gIGNsdXN0ZXJOYW1lOiBzdHJpbmc7XG4gIGNvbnRhaW5lckNvbW1hbmQ/OiBzdHJpbmdbXTtcbiAgY29udGFpbmVyRW52aXJvbm1lbnQ/OiBLZXlWYWx1ZTtcbiAgY29udGFpbmVyU2VjcmV0cz86IENvbnRhaW5lclNlY3JldDtcbiAgY29udGFpbmVyU2VjcmV0c0ltcG9ydD86IHtcbiAgICBba2V5OiBzdHJpbmddOiBTZWNyZXRJbXBvcnQ7XG4gIH07XG4gIGNvbnRhaW5lclBvcnQ/OiBudW1iZXI7XG4gIGNwdT86IG51bWJlcjtcbiAgZG9tYWluQ29uZmlnPzogRG9tYWluQ29uZmlnO1xuICBkZXNpcmVkQ291bnQ/OiBudW1iZXI7XG4gIGhlYWx0aENoZWNrUGF0aD86IHN0cmluZztcbiAgbGlzdGVuZXJQb3J0PzogbnVtYmVyO1xuICBtZW1vcnlMaW1pdE1pQj86IG51bWJlcjtcbiAgcHVibGljTG9hZEJhbGFuY2VyPzogYm9vbGVhbjtcbiAgcHJvdG9jb2w6IFByb3RvY29sO1xuICBzY2FsaW5nVHlwZT86IFNjYWxpbmdUeXBlO1xuICBzZXJ2aWNlTmFtZTogc3RyaW5nO1xuICB0YXNrUm9sZUlubGluZVBvbGljaWVzPzoge1xuICAgIFtuYW1lOiBzdHJpbmddOiBQb2xpY3lEb2N1bWVudDtcbiAgfTtcbiAgdGFza1JvbGVNYW5hZ2VkUG9saWNpZXM/OiBJTWFuYWdlZFBvbGljeVtdO1xuICB2cGM/OiBJVnBjO1xufTtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgRmFyZ2F0ZUNsdXN0ZXIgZXh0ZW5kcyBDb25zdHJ1Y3QgaW1wbGVtZW50cyBJQ29ubmVjdGFibGUge1xuICBwdWJsaWMgY29ubmVjdGlvbnM6IENvbm5lY3Rpb25zO1xuXG4gIHByaXZhdGUgY2x1c3RlcjogQ2RrQ2x1c3RlcjtcbiAgcHJpdmF0ZSBsb2FkQmFsYW5jZXI6IEFwcGxpY2F0aW9uTG9hZEJhbGFuY2VyO1xuICBwcml2YXRlIGV4ZWN1dGlvblJvbGU6IFJvbGU7XG4gIHByaXZhdGUgdGFza0RlZmluaXRpb246IEZhcmdhdGVUYXNrRGVmaW5pdGlvbjtcbiAgcHJpdmF0ZSBjb250YWluZXJEZWZpbml0aW9uOiBDb250YWluZXJEZWZpbml0aW9uO1xuICBwcml2YXRlIGZhcmdhdGVTZXJ2aWNlOiBGYXJnYXRlU2VydmljZTtcbiAgcHJpdmF0ZSBzY2FsaW5nUG9saWN5OiBUYXJnZXRUcmFja2luZ1NjYWxpbmdQb2xpY3k7XG4gIHByaXZhdGUgaG9zdGVkWm9uZTogSUhvc3RlZFpvbmU7XG4gIHByaXZhdGUgY2VydGlmaWNhdGU6IENlcnRpZmljYXRlO1xuICBwcml2YXRlIGFSZWNvcmQ6IEFSZWNvcmQ7XG4gIHByaXZhdGUgbG9hZEJhbGFuY2VyTGlzdGVuZXI6IEFwcGxpY2F0aW9uTGlzdGVuZXI7XG5cbiAgcHJpdmF0ZSBzZWNyZXRzOiB7XG4gICAgW2tleTogc3RyaW5nXTogRWNzU2VjcmV0O1xuICB9ID0ge307XG5cbiAgcHJpdmF0ZSBzY29wZTogQ29uc3RydWN0O1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBGYXJnYXRlQ2x1c3RlclByb3BzKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkKTtcblxuICAgIHRoaXMuc2NvcGUgPSBzY29wZTtcblxuICAgIHRoaXMuYWRkQ2x1c3Rlcihwcm9wcyk7XG4gICAgdGhpcy5hZGRTZWNyZXRzKHByb3BzKTtcbiAgICB0aGlzLmltcG9ydFNlY3JldHMocHJvcHMpO1xuICAgIHRoaXMuYWRkRXhlY3V0aW9uUm9sZShwcm9wcyk7XG4gICAgdGhpcy5hZGRUYXNrRGVmaW5pdGlvbihwcm9wcyk7XG4gICAgdGhpcy5hZGRDb250YWluZXJEZWZpbml0aW9uKHByb3BzKTtcbiAgICB0aGlzLmFkZEZhcmdhdGVTZXJ2aWNlKHByb3BzKTtcbiAgICB0aGlzLmFkZExvYWRCYWxhbmNlcihwcm9wcyk7XG5cbiAgICBpZiAocHJvcHMuZG9tYWluQ29uZmlnKSB0aGlzLmFkZEhvc3RlZFpvbmUocHJvcHMpO1xuXG4gICAgdGhpcy5hZGRMb2FkQmFsYW5jZXJMaXN0ZW5lcihwcm9wcyk7XG4gICAgdGhpcy5yZWdpc3RlckxvYWRCYWxhbmNlclRhcmdldHMocHJvcHMpO1xuXG4gICAgY29uc3QgY29udGFpbmVyUG9ydCA9IHByb3BzLmNvbnRhaW5lclBvcnQgfHwgODA7XG4gICAgdGhpcy5jb25uZWN0aW9ucyA9IG5ldyBDb25uZWN0aW9ucyh7XG4gICAgICBzZWN1cml0eUdyb3VwczogdGhpcy5mYXJnYXRlU2VydmljZS5jb25uZWN0aW9ucy5zZWN1cml0eUdyb3VwcyxcbiAgICAgIGRlZmF1bHRQb3J0OiBQb3J0LnRjcChjb250YWluZXJQb3J0KVxuICAgIH0pO1xuICB9XG5cbiAgYWRkQ2x1c3Rlcihwcm9wczogRmFyZ2F0ZUNsdXN0ZXJQcm9wcykge1xuICAgIHRoaXMuY2x1c3RlciA9IG5ldyBDZGtDbHVzdGVyKHRoaXMsIGAke3Byb3BzLmNsdXN0ZXJOYW1lfWAsIHtcbiAgICAgIHZwYzogcHJvcHMudnBjLFxuICAgICAgY2x1c3Rlck5hbWU6IHByb3BzLmNsdXN0ZXJOYW1lLFxuICAgICAgY29udGFpbmVySW5zaWdodHNWMjogQ29udGFpbmVySW5zaWdodHMuRU5BQkxFRCxcbiAgICAgIGVuYWJsZUZhcmdhdGVDYXBhY2l0eVByb3ZpZGVyczogdHJ1ZVxuICAgIH0pO1xuXG4gICAgLy8gT3V0cHV0IHVzZWQgdG8gYXV0by1kZXRlY3QgZGVwbG95YWJsZSBjbHV0ZXJcbiAgICBuZXcgQ2ZuT3V0cHV0KHRoaXMsIGAke3Byb3BzLmNsdXN0ZXJOYW1lfURlcGxveWFibGVDbHVzdGVyYCwge1xuICAgICAga2V5OiBgJHtwcm9wcy5jbHVzdGVyTmFtZX1EZXBsb3lhYmxlQ2x1c3RlcmAsXG4gICAgICBleHBvcnROYW1lOiBgJHtwcm9wcy5jbHVzdGVyTmFtZX1EZXBsb3lhYmxlQ2x1c3RlcmAsXG4gICAgICB2YWx1ZTogdGhpcy5jbHVzdGVyLmNsdXN0ZXJBcm5cbiAgICB9KTtcblxuICAgIC8vIEV4cG9ydCBjbHVzdGVyIEFSTiBmb3IgbW9uaXRvcmluZ1xuICAgIG5ldyBDZm5PdXRwdXQodGhpcywgYCR7cHJvcHMuY2x1c3Rlck5hbWV9Q2x1c3RlckFybmAsIHtcbiAgICAgIGtleTogXCJDbHVzdGVyQXJuXCIsXG4gICAgICBleHBvcnROYW1lOiBgJHtwcm9wcy5jbHVzdGVyTmFtZX1DbHVzdGVyQXJuYCxcbiAgICAgIHZhbHVlOiB0aGlzLmNsdXN0ZXIuY2x1c3RlckFybixcbiAgICAgIGRlc2NyaXB0aW9uOiBgRUNTIENsdXN0ZXIgQVJOIGZvciAke3Byb3BzLmNsdXN0ZXJOYW1lfWBcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiAjdG9kbzogY2hhbmdlIHRoaXMgdG8gY3JlYXRlIG5ldyBzZWNyZXRzIGluc3RlYWRcbiAgICogQGRlcHJlY2F0ZWQgdXNlIGltcG9ydFNlY3JldHMgaW5zdGVhZFxuICAgKi9cbiAgYWRkU2VjcmV0cyhwcm9wczogRmFyZ2F0ZUNsdXN0ZXJQcm9wcykge1xuICAgIC8vIENvbnRhaW5lciBTZWNyZXRzXG4gICAgY29uc3QgY29udGFpbmVyU2VjcmV0ID0gU2VjcmV0LmZyb21TZWNyZXROYW1lVjIoXG4gICAgICB0aGlzLFxuICAgICAgYCR7cHJvcHMuY2x1c3Rlck5hbWV9U2VjcmV0YCxcbiAgICAgIGAvJHtwcm9wcy5jbHVzdGVyTmFtZX0vJHtwcm9wcy5zZXJ2aWNlTmFtZX1gXG4gICAgKTtcblxuICAgIGZvciAoY29uc3Qgc2VjcmV0RmllbGQgaW4gcHJvcHMuY29udGFpbmVyU2VjcmV0cykge1xuICAgICAgdGhpcy5zZWNyZXRzW3NlY3JldEZpZWxkXSA9IEVjc1NlY3JldC5mcm9tU2VjcmV0c01hbmFnZXIoXG4gICAgICAgIGNvbnRhaW5lclNlY3JldCxcbiAgICAgICAgc2VjcmV0RmllbGRcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEF1dG9tYXRpY2FsbHkgaW1wb3J0IHNlY3JldHMgZnJvbSBhbm90aGVyIHJlc291cmNlIG9yIHN0YWNrXG4gICAqL1xuICBpbXBvcnRTZWNyZXRzKHByb3BzOiBGYXJnYXRlQ2x1c3RlclByb3BzKSB7XG4gICAgaWYgKCFwcm9wcy5jb250YWluZXJTZWNyZXRzSW1wb3J0KSByZXR1cm47XG5cbiAgICBmb3IgKGNvbnN0IGtleSBpbiBwcm9wcy5jb250YWluZXJTZWNyZXRzSW1wb3J0KSB7XG4gICAgICBjb25zdCBpbXBvcnRTZWNyZXQgPSBwcm9wcy5jb250YWluZXJTZWNyZXRzSW1wb3J0W2tleV07XG5cbiAgICAgIC8vIHRvZG86IEkgdGhpbmsgSUQgbmVlZHMgdG8gYmUgYSBuZXcgdmFsdWUgYXMgaXQgSUQncyB0aGUgSU1QT1JUIG5vdCB0aGUgc2VjcmV0IGl0c2VsZj9cblxuICAgICAgLy8gQ29uc3RydWN0IHRoZSBBV1MgSVNlY3JldCBvYmplY3RcbiAgICAgIGNvbnN0IGlTZWNyZXQgPSBTZWNyZXQuZnJvbVNlY3JldE5hbWVWMihcbiAgICAgICAgdGhpcyxcbiAgICAgICAgaW1wb3J0U2VjcmV0LmlkLFxuICAgICAgICBpbXBvcnRTZWNyZXQubmFtZVxuICAgICAgKTtcblxuICAgICAgdGhpcy5zZWNyZXRzW2tleV0gPSBFY3NTZWNyZXQuZnJvbVNlY3JldHNNYW5hZ2VyKFxuICAgICAgICBpU2VjcmV0LFxuICAgICAgICBpbXBvcnRTZWNyZXQuZmllbGRcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgYWRkRXhlY3V0aW9uUm9sZShwcm9wczogRmFyZ2F0ZUNsdXN0ZXJQcm9wcykge1xuICAgIHRoaXMuZXhlY3V0aW9uUm9sZSA9IG5ldyBSb2xlKFxuICAgICAgdGhpcyxcbiAgICAgIGAke3Byb3BzLnNlcnZpY2VOYW1lfUV4ZWN1dGlvblJvbGUke1N0YWNrLm9mKHRoaXMpLnJlZ2lvbn1gLFxuICAgICAge1xuICAgICAgICByb2xlTmFtZTogYCR7cHJvcHMuc2VydmljZU5hbWV9RXhlY3V0aW9uUm9sZSR7U3RhY2sub2YodGhpcykucmVnaW9ufWAsXG4gICAgICAgIGRlc2NyaXB0aW9uOiBgJHtwcm9wcy5zZXJ2aWNlTmFtZX0gRXhlY3V0aW9uIFJvbGVgLFxuICAgICAgICBtYW5hZ2VkUG9saWNpZXM6IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBtYW5hZ2VkUG9saWN5QXJuOlxuICAgICAgICAgICAgICBcImFybjphd3M6aWFtOjphd3M6cG9saWN5L3NlcnZpY2Utcm9sZS9BbWF6b25FQ1NUYXNrRXhlY3V0aW9uUm9sZVBvbGljeVwiXG4gICAgICAgICAgfVxuICAgICAgICBdLFxuICAgICAgICBpbmxpbmVQb2xpY2llczoge1xuICAgICAgICAgIFtcInJlYWRTZWNyZXRzXCJdOiBuZXcgUG9saWN5RG9jdW1lbnQoe1xuICAgICAgICAgICAgc3RhdGVtZW50czogW1xuICAgICAgICAgICAgICBuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgICAgICAgICBhY3Rpb25zOiBbXG4gICAgICAgICAgICAgICAgICBcInNlY3JldHNtYW5hZ2VyOkdldFNlY3JldFZhbHVlXCIsXG4gICAgICAgICAgICAgICAgICBcInNlY3JldHNtYW5hZ2VyOkRlc2NyaWJlU2VjcmV0XCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIHJlc291cmNlczogW1wiKlwiXSAvLyBUT0RPOiBTZXQgdGhpcyB0byB0aGUgc2VjcmV0IEFSTlxuICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgXVxuICAgICAgICAgIH0pLFxuICAgICAgICAgIFtcImRlY3J5cHRTZWNyZXRzXCJdOiBuZXcgUG9saWN5RG9jdW1lbnQoe1xuICAgICAgICAgICAgc3RhdGVtZW50czogW1xuICAgICAgICAgICAgICBuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgICAgICAgICBhY3Rpb25zOiBbXCJrbXM6RGVjcnlwdFwiXSxcbiAgICAgICAgICAgICAgICByZXNvdXJjZXM6IFtcIipcIl0gLy8gVE9ETzogU2V0IHRoaXMgdG8gdGhlIEtNUyBBcm5cbiAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIF1cbiAgICAgICAgICB9KSxcbiAgICAgICAgICBbXCJlY3NFeGVjdXRlQ29tbWFuZFwiXTogbmV3IFBvbGljeURvY3VtZW50KHtcbiAgICAgICAgICAgIHN0YXRlbWVudHM6IFtcbiAgICAgICAgICAgICAgbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgICAgICAgICAgYWN0aW9uczogW1xuICAgICAgICAgICAgICAgICAgXCJzc21tZXNzYWdlczpDcmVhdGVDb250cm9sQ2hhbm5lbFwiLFxuICAgICAgICAgICAgICAgICAgXCJzc21tZXNzYWdlczpDcmVhdGVEYXRhQ2hhbm5lbFwiLFxuICAgICAgICAgICAgICAgICAgXCJzc21tZXNzYWdlczpPcGVuQ29udHJvbENoYW5uZWxcIixcbiAgICAgICAgICAgICAgICAgIFwic3NtbWVzc2FnZXM6T3BlbkRhdGFDaGFubmVsXCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIGVmZmVjdDogRWZmZWN0LkFMTE9XLFxuICAgICAgICAgICAgICAgIHJlc291cmNlczogW1wiKlwiXVxuICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgXVxuICAgICAgICAgIH0pXG4gICAgICAgIH0sXG4gICAgICAgIGFzc3VtZWRCeTogbmV3IENvbXBvc2l0ZVByaW5jaXBhbChcbiAgICAgICAgICBuZXcgU2VydmljZVByaW5jaXBhbChcImVjcy10YXNrcy5hbWF6b25hd3MuY29tXCIpXG4gICAgICAgIClcbiAgICAgIH1cbiAgICApO1xuICB9XG5cbiAgYWRkVGFza0RlZmluaXRpb24ocHJvcHM6IEZhcmdhdGVDbHVzdGVyUHJvcHMpIHtcbiAgICB0aGlzLnRhc2tEZWZpbml0aW9uID0gbmV3IEZhcmdhdGVUYXNrRGVmaW5pdGlvbihcbiAgICAgIHRoaXMsXG4gICAgICBgJHtwcm9wcy5zZXJ2aWNlTmFtZX1UYXNrRGVmaW5pdGlvbmAsXG4gICAgICB7XG4gICAgICAgIGNwdTogcHJvcHMuY3B1IHx8IDI1NixcbiAgICAgICAgZXhlY3V0aW9uUm9sZTogdGhpcy5leGVjdXRpb25Sb2xlLFxuICAgICAgICB0YXNrUm9sZTogbmV3IFJvbGUoXG4gICAgICAgICAgdGhpcyxcbiAgICAgICAgICBgJHtwcm9wcy5zZXJ2aWNlTmFtZX1UYXNrUm9sZSR7U3RhY2sub2YodGhpcykucmVnaW9ufWAsXG4gICAgICAgICAge1xuICAgICAgICAgICAgcm9sZU5hbWU6IGAke3Byb3BzLnNlcnZpY2VOYW1lfVRhc2tSb2xlJHtTdGFjay5vZih0aGlzKS5yZWdpb259YCxcbiAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBgJHtwcm9wcy5zZXJ2aWNlTmFtZX0gVGFzayBSb2xlYCxcbiAgICAgICAgICAgIGlubGluZVBvbGljaWVzOiBwcm9wcy50YXNrUm9sZUlubGluZVBvbGljaWVzLFxuICAgICAgICAgICAgbWFuYWdlZFBvbGljaWVzOiBwcm9wcy50YXNrUm9sZU1hbmFnZWRQb2xpY2llcyxcbiAgICAgICAgICAgIGFzc3VtZWRCeTogbmV3IENvbXBvc2l0ZVByaW5jaXBhbChcbiAgICAgICAgICAgICAgbmV3IFNlcnZpY2VQcmluY2lwYWwoXCJlY3MtdGFza3MuYW1hem9uYXdzLmNvbVwiKVxuICAgICAgICAgICAgKVxuICAgICAgICAgIH1cbiAgICAgICAgKSxcbiAgICAgICAgbWVtb3J5TGltaXRNaUI6IHByb3BzLm1lbW9yeUxpbWl0TWlCIHx8IDUxMlxuICAgICAgfVxuICAgICk7XG4gIH1cblxuICBhZGRDb250YWluZXJEZWZpbml0aW9uKHByb3BzOiBGYXJnYXRlQ2x1c3RlclByb3BzKSB7XG4gICAgdGhpcy5jb250YWluZXJEZWZpbml0aW9uID0gdGhpcy50YXNrRGVmaW5pdGlvbi5hZGRDb250YWluZXIoXG4gICAgICBgJHtwcm9wcy5zZXJ2aWNlTmFtZX1Db250YWluZXJEZWZpbml0aW9uYCxcbiAgICAgIHtcbiAgICAgICAgaW1hZ2U6IHRoaXMuZ2V0SW1hZ2UocHJvcHMpLFxuICAgICAgICBjb250YWluZXJOYW1lOiBwcm9wcy5zZXJ2aWNlTmFtZSxcbiAgICAgICAgZW52aXJvbm1lbnQ6IHtcbiAgICAgICAgICAuLi5wcm9wcy5jb250YWluZXJFbnZpcm9ubWVudFxuICAgICAgICB9LFxuICAgICAgICBjb21tYW5kOiBwcm9wcy5jb250YWluZXJDb21tYW5kLFxuICAgICAgICBzZWNyZXRzOiB7XG4gICAgICAgICAgLi4udGhpcy5zZWNyZXRzXG4gICAgICAgIH0sXG4gICAgICAgIC8vdG9kbzogcHJvdmlkZSBoZWFsdGggY2hlY2sgb3B0aW9uc1xuICAgICAgICBoZWFsdGhDaGVjazoge1xuICAgICAgICAgIGNvbW1hbmQ6IFtcbiAgICAgICAgICAgIFwiQ01ELVNIRUxMXCIsXG4gICAgICAgICAgICAvLyBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQW1hem9uRUNTL2xhdGVzdC9kZXZlbG9wZXJndWlkZS92aWV3LWNvbnRhaW5lci1oZWFsdGguaHRtbFxuICAgICAgICAgICAgLy8gID4+IHByb2MvMS9mZC8xIDI+JjEgcmVkaXJlY3RzIHN0ZG91dCBhbmQgc3RkZXJyIG9mIHRoZSBoZWFsdGggY2hlY2sgdG8gQ2xvdWRXYXRjaCBsb2dzXG4gICAgICAgICAgICAvLyBgY3VybCAtZiBodHRwOi8vbG9jYWxob3N0OiR7cHJvcHMuY29udGFpbmVyUG9ydH0vID4+IC9wcm9jLzEvZmQvMSAyPiYxICB8fCBleGl0IDFgXG4gICAgICAgICAgICBgY3VybCAtZiBodHRwOi8vbG9jYWxob3N0OiR7cHJvcHMuY29udGFpbmVyUG9ydH0vIHx8IGV4aXQgMWBcbiAgICAgICAgICBdXG4gICAgICAgIH0sXG4gICAgICAgIGxvZ2dpbmc6IG5ldyBBd3NMb2dEcml2ZXIoe1xuICAgICAgICAgIHN0cmVhbVByZWZpeDogYC9lY3MvJHtwcm9wcy5jbHVzdGVyTmFtZX0vJHtwcm9wcy5zZXJ2aWNlTmFtZX1gLFxuICAgICAgICAgIGxvZ1JldGVudGlvbjogMTRcbiAgICAgICAgfSksXG4gICAgICAgIHBvcnRNYXBwaW5nczogcHJvcHMuY29udGFpbmVyUG9ydFxuICAgICAgICAgID8gW3sgY29udGFpbmVyUG9ydDogcHJvcHMuY29udGFpbmVyUG9ydCB9XVxuICAgICAgICAgIDogW3sgY29udGFpbmVyUG9ydDogODAgfV1cbiAgICAgIH1cbiAgICApO1xuICB9XG5cbiAgYWRkRmFyZ2F0ZVNlcnZpY2UocHJvcHM6IEZhcmdhdGVDbHVzdGVyUHJvcHMpIHtcbiAgICB0aGlzLmZhcmdhdGVTZXJ2aWNlID0gbmV3IEZhcmdhdGVTZXJ2aWNlKFxuICAgICAgdGhpcyxcbiAgICAgIGAke3Byb3BzLnNlcnZpY2VOYW1lfUZhcmdhdGVTZXJ2aWNlYCxcbiAgICAgIHtcbiAgICAgICAgY2lyY3VpdEJyZWFrZXI6IHsgcm9sbGJhY2s6IHRydWUgfSxcbiAgICAgICAgY2x1c3RlcjogdGhpcy5jbHVzdGVyLFxuICAgICAgICBkZXNpcmVkQ291bnQ6IDIsXG4gICAgICAgIGVuYWJsZUVDU01hbmFnZWRUYWdzOiB0cnVlLFxuICAgICAgICBlbmFibGVFeGVjdXRlQ29tbWFuZDogdHJ1ZSxcbiAgICAgICAgcHJvcGFnYXRlVGFnczogUHJvcGFnYXRlZFRhZ1NvdXJjZS5TRVJWSUNFLFxuICAgICAgICBzZXJ2aWNlTmFtZTogYCR7cHJvcHMuc2VydmljZU5hbWV9YCxcbiAgICAgICAgdGFza0RlZmluaXRpb246IHRoaXMudGFza0RlZmluaXRpb24sXG4gICAgICAgIG1pbkhlYWx0aHlQZXJjZW50OiAxMDAsXG4gICAgICAgIG1heEhlYWx0aHlQZXJjZW50OiAyMDBcbiAgICAgIH1cbiAgICApO1xuXG4gICAgLy8gT3V0cHV0IHVzZWQgdG8gZGV0ZWN0IGRlcGxveWFibGUgc2VydmljZVxuICAgIG5ldyBDZm5PdXRwdXQodGhpcywgYCR7cHJvcHMuY2x1c3Rlck5hbWV9RGVwbG95YWJsZVNlcnZpY2VgLCB7XG4gICAgICBrZXk6IGAke3Byb3BzLmNsdXN0ZXJOYW1lfURlcGxveWFibGVTZXJ2aWNlYCxcbiAgICAgIGV4cG9ydE5hbWU6IGAke3Byb3BzLmNsdXN0ZXJOYW1lfURlcGxveWFibGVTZXJ2aWNlYCxcbiAgICAgIHZhbHVlOiB0aGlzLmZhcmdhdGVTZXJ2aWNlLnNlcnZpY2VBcm5cbiAgICB9KTtcblxuICAgIC8vIEV4cG9ydCBzZXJ2aWNlIEFSTiBmb3IgbW9uaXRvcmluZ1xuICAgIG5ldyBDZm5PdXRwdXQodGhpcywgYCR7cHJvcHMuY2x1c3Rlck5hbWV9U2VydmljZUFybmAsIHtcbiAgICAgIGtleTogXCJTZXJ2aWNlQXJuXCIsXG4gICAgICBleHBvcnROYW1lOiBgJHtwcm9wcy5jbHVzdGVyTmFtZX1TZXJ2aWNlQXJuYCxcbiAgICAgIHZhbHVlOiB0aGlzLmZhcmdhdGVTZXJ2aWNlLnNlcnZpY2VBcm4sXG4gICAgICBkZXNjcmlwdGlvbjogYEVDUyBTZXJ2aWNlIEFSTiBmb3IgJHtwcm9wcy5zZXJ2aWNlTmFtZX1gXG4gICAgfSk7XG4gIH1cblxuICBhZGRTY2FsaW5nUG9saWN5KHByb3BzOiBGYXJnYXRlQ2x1c3RlclByb3BzKSB7XG4gICAgdGhpcy5zY2FsaW5nUG9saWN5ID0gbmV3IFRhcmdldFRyYWNraW5nU2NhbGluZ1BvbGljeShcbiAgICAgIHRoaXMsXG4gICAgICBgJHtwcm9wcy5zZXJ2aWNlTmFtZX1TY2FsaW5nUG9saWN5YCxcbiAgICAgIHtcbiAgICAgICAgcG9saWN5TmFtZTogYCR7cHJvcHMuc2VydmljZU5hbWV9U2NhbGluZ1BvbGljeWAsXG4gICAgICAgIHNjYWxpbmdUYXJnZXQ6IG5ldyBTY2FsYWJsZVRhcmdldChcbiAgICAgICAgICB0aGlzLFxuICAgICAgICAgIGAke3Byb3BzLnNlcnZpY2VOYW1lfXNjYWxhYmxlVGFyZ2V0YCxcbiAgICAgICAgICB7XG4gICAgICAgICAgICBtYXhDYXBhY2l0eTogMTAsXG4gICAgICAgICAgICBtaW5DYXBhY2l0eTogMixcbiAgICAgICAgICAgIHJlc291cmNlSWQ6IGBzZXJ2aWNlLyR7dGhpcy5jbHVzdGVyLmNsdXN0ZXJOYW1lfS8ke3RoaXMuZmFyZ2F0ZVNlcnZpY2Uuc2VydmljZU5hbWV9YCxcbiAgICAgICAgICAgIHNjYWxhYmxlRGltZW5zaW9uOiBcImVjczpzZXJ2aWNlOkRlc2lyZWRDb3VudFwiLFxuICAgICAgICAgICAgc2VydmljZU5hbWVzcGFjZTogU2VydmljZU5hbWVzcGFjZS5FQ1NcbiAgICAgICAgICB9XG4gICAgICAgICksXG4gICAgICAgIHRhcmdldFZhbHVlOiA1MCxcbiAgICAgICAgc2NhbGVPdXRDb29sZG93bjogRHVyYXRpb24uc2Vjb25kcyg2MCksXG4gICAgICAgIHNjYWxlSW5Db29sZG93bjogRHVyYXRpb24uc2Vjb25kcyg2MCksXG4gICAgICAgIHByZWRlZmluZWRNZXRyaWM6XG4gICAgICAgICAgcHJvcHMuc2NhbGluZ1R5cGUgPT0gU2NhbGluZ1R5cGUuTUVNT1JZXG4gICAgICAgICAgICA/IFByZWRlZmluZWRNZXRyaWMuRUNTX1NFUlZJQ0VfQVZFUkFHRV9NRU1PUllfVVRJTElaQVRJT05cbiAgICAgICAgICAgIDogUHJlZGVmaW5lZE1ldHJpYy5FQ1NfU0VSVklDRV9BVkVSQUdFX0NQVV9VVElMSVpBVElPTlxuICAgICAgfVxuICAgICk7XG4gIH1cblxuICByZWdpc3RlckxvYWRCYWxhbmNlclRhcmdldHMocHJvcHM6IEZhcmdhdGVDbHVzdGVyUHJvcHMpIHtcbiAgICB0aGlzLmZhcmdhdGVTZXJ2aWNlLnJlZ2lzdGVyTG9hZEJhbGFuY2VyVGFyZ2V0cyh7XG4gICAgICBjb250YWluZXJOYW1lOiB0aGlzLmNvbnRhaW5lckRlZmluaXRpb24uY29udGFpbmVyTmFtZSxcbiAgICAgIGNvbnRhaW5lclBvcnQ6IHRoaXMuY29udGFpbmVyRGVmaW5pdGlvbi5jb250YWluZXJQb3J0LFxuICAgICAgbmV3VGFyZ2V0R3JvdXBJZDogYCR7cHJvcHMuc2VydmljZU5hbWV9VGFyZ2V0R3JvdXBgLFxuICAgICAgbGlzdGVuZXI6IExpc3RlbmVyQ29uZmlnLmFwcGxpY2F0aW9uTGlzdGVuZXIodGhpcy5sb2FkQmFsYW5jZXJMaXN0ZW5lciwge1xuICAgICAgICBwb3J0OiBwcm9wcy5jb250YWluZXJQb3J0LFxuICAgICAgICBwcm90b2NvbDogQXBwbGljYXRpb25Qcm90b2NvbC5IVFRQLFxuICAgICAgICBoZWFsdGhDaGVjazoge1xuICAgICAgICAgIGludGVydmFsOiBEdXJhdGlvbi5zZWNvbmRzKDEyMCksXG4gICAgICAgICAgcGF0aDogcHJvcHMuaGVhbHRoQ2hlY2tQYXRoIHx8IFwiL1wiLFxuICAgICAgICAgIHBvcnQ6IHByb3BzLmNvbnRhaW5lclBvcnQgPyBgJHtwcm9wcy5jb250YWluZXJQb3J0fWAgOiBcInRyYWZmaWMtcG9ydFwiLFxuICAgICAgICAgIHRpbWVvdXQ6IER1cmF0aW9uLnNlY29uZHMoMTApXG4gICAgICAgIH1cbiAgICAgIH0pXG4gICAgfSk7XG4gIH1cblxuICBhZGRMb2FkQmFsYW5jZXIocHJvcHM6IEZhcmdhdGVDbHVzdGVyUHJvcHMpIHtcbiAgICAvLyBUcnVuY2F0ZSB0aGUgbG9hZCBiYWxhbmNlciBuYW1lIHRvIGVuc3VyZSBpdCBkb2VzIG5vdCBleGNlZWQgdGhlIDMyIGNoYXJhY3RlciBBV1MgbGltaXRcbiAgICBjb25zdCBkZWZhdWx0TG9hZEJhbGFuY2VyTmFtZSA9IGAke3Byb3BzLnNlcnZpY2VOYW1lfUxvYWRCYWxhbmNlcmA7XG4gICAgY29uc3Qgc3VwcG9ydGVkTmFtZUxlbmd0aCA9IDMyO1xuXG4gICAgbGV0IHRydW5jYXRlZExvYWRCYWxhbmNlck5hbWUgPVxuICAgICAgZGVmYXVsdExvYWRCYWxhbmNlck5hbWUubGVuZ3RoID4gc3VwcG9ydGVkTmFtZUxlbmd0aFxuICAgICAgICA/IGRlZmF1bHRMb2FkQmFsYW5jZXJOYW1lLnN1YnN0cmluZygwLCBzdXBwb3J0ZWROYW1lTGVuZ3RoKVxuICAgICAgICA6IGRlZmF1bHRMb2FkQmFsYW5jZXJOYW1lO1xuXG4gICAgLy8gUmVtb3ZlIGFueSB0cmFpbGluZyBoeXBoZW5zIHRoYXQgbWlnaHQgYmUgaW50cm9kdWNlZCBieSB0cnVuY2F0aW9uXG4gICAgdHJ1bmNhdGVkTG9hZEJhbGFuY2VyTmFtZSA9IHRydW5jYXRlZExvYWRCYWxhbmNlck5hbWUucmVwbGFjZSgvLSskLywgXCJcIik7XG5cbiAgICB0aGlzLmxvYWRCYWxhbmNlciA9IG5ldyBBcHBsaWNhdGlvbkxvYWRCYWxhbmNlcihcbiAgICAgIHRoaXMsXG4gICAgICBgJHtwcm9wcy5jbHVzdGVyTmFtZX1Mb2FkQmFsYW5jZXJgLFxuICAgICAge1xuICAgICAgICB2cGM6IHRoaXMuY2x1c3Rlci52cGMsXG4gICAgICAgIGludGVybmV0RmFjaW5nOiB0cnVlLFxuICAgICAgICBsb2FkQmFsYW5jZXJOYW1lOiB0cnVuY2F0ZWRMb2FkQmFsYW5jZXJOYW1lLFxuICAgICAgICB2cGNTdWJuZXRzOiB7XG4gICAgICAgICAgc3VibmV0VHlwZTogU3VibmV0VHlwZS5QVUJMSUNcbiAgICAgICAgfVxuICAgICAgfVxuICAgICk7XG5cbiAgICBuZXcgQ2ZuT3V0cHV0KHRoaXMsIGAke3Byb3BzLmNsdXN0ZXJOYW1lfUxvYWRCYWxhbmNlckRuc05hbWVgLCB7XG4gICAgICBrZXk6IGAke3Byb3BzLmNsdXN0ZXJOYW1lfUxvYWRCYWxhbmNlckRuc05hbWVgLFxuICAgICAgZXhwb3J0TmFtZTogYCR7cHJvcHMuY2x1c3Rlck5hbWV9TG9hZEJhbGFuY2VyRG5zTmFtZWAsXG4gICAgICB2YWx1ZTogdGhpcy5sb2FkQmFsYW5jZXIubG9hZEJhbGFuY2VyRG5zTmFtZVxuICAgIH0pO1xuXG4gICAgLy8gRXhwb3J0IGxvYWQgYmFsYW5jZXIgVVJMIGZvciBtb25pdG9yaW5nXG4gICAgbmV3IENmbk91dHB1dCh0aGlzLCBgJHtwcm9wcy5jbHVzdGVyTmFtZX1Mb2FkQmFsYW5jZXJVcmxgLCB7XG4gICAgICBrZXk6IFwiTG9hZEJhbGFuY2VyVXJsXCIsXG4gICAgICBleHBvcnROYW1lOiBgJHtwcm9wcy5jbHVzdGVyTmFtZX1Mb2FkQmFsYW5jZXJVcmxgLFxuICAgICAgdmFsdWU6IGBodHRwOi8vJHt0aGlzLmxvYWRCYWxhbmNlci5sb2FkQmFsYW5jZXJEbnNOYW1lfWAsXG4gICAgICBkZXNjcmlwdGlvbjogYExvYWQgQmFsYW5jZXIgVVJMIGZvciAke3Byb3BzLmNsdXN0ZXJOYW1lfWBcbiAgICB9KTtcbiAgfVxuXG4gIGFkZExvYWRCYWxhbmNlckxpc3RlbmVyKHByb3BzOiBGYXJnYXRlQ2x1c3RlclByb3BzKSB7XG4gICAgaWYgKHRoaXMuY2VydGlmaWNhdGUpIHtcbiAgICAgIHRoaXMubG9hZEJhbGFuY2VyTGlzdGVuZXIgPSB0aGlzLmxvYWRCYWxhbmNlci5hZGRMaXN0ZW5lcihcbiAgICAgICAgYCR7cHJvcHMuc2VydmljZU5hbWV9TGlzdGVuZXJgLFxuICAgICAgICB7XG4gICAgICAgICAgcG9ydDogcHJvcHMucHJvdG9jb2wgPT0gUHJvdG9jb2wuSFRUUCA/IDgwIDogNDQzLFxuICAgICAgICAgIGNlcnRpZmljYXRlczogW3RoaXMuY2VydGlmaWNhdGVdXG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMubG9hZEJhbGFuY2VyTGlzdGVuZXIgPSB0aGlzLmxvYWRCYWxhbmNlci5hZGRMaXN0ZW5lcihcbiAgICAgICAgYCR7cHJvcHMuc2VydmljZU5hbWV9TGlzdGVuZXJgLFxuICAgICAgICB7XG4gICAgICAgICAgcG9ydDogcHJvcHMucHJvdG9jb2wgPT0gUHJvdG9jb2wuSFRUUCA/IDgwIDogNDQzXG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgYWRkSG9zdGVkWm9uZShwcm9wczogRmFyZ2F0ZUNsdXN0ZXJQcm9wcykge1xuICAgIGlmICghcHJvcHMuZG9tYWluQ29uZmlnKSByZXR1cm47XG5cbiAgICBpZiAoIXByb3BzLmRvbWFpbkNvbmZpZy5ob3N0ZWRab25lKSB7XG4gICAgICAvLyBDcmVhdGUgYSBuZXcgaG9zdGVkIHpvbmUgaWYgb25lIGlzIG5vdCBwcm92aWRlZFxuICAgICAgY29uc3QgaG9zdGVkWm9uZSA9IG5ldyBGamFsbEhvc3RlZFpvbmUoXG4gICAgICAgIHRoaXMsXG4gICAgICAgIGAke3Byb3BzLnNlcnZpY2VOYW1lfUhvc3RlZFpvbmVgLFxuICAgICAgICB7XG4gICAgICAgICAgem9uZU5hbWU6IHByb3BzLmRvbWFpbkNvbmZpZy5kb21haW5OYW1lXG4gICAgICAgIH1cbiAgICAgICk7XG5cbiAgICAgIHRoaXMuaG9zdGVkWm9uZSA9IGhvc3RlZFpvbmUuZ2V0SW50ZXJuYWxIb3N0ZWRab25lKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIE90aGVyd2lzZSB1c2UgdGhlIHByb3ZpZGVkIGhvc3RlZCB6b25lXG4gICAgICB0aGlzLmhvc3RlZFpvbmUgPSBwcm9wcy5kb21haW5Db25maWcuaG9zdGVkWm9uZS5nZXRJbnRlcm5hbEhvc3RlZFpvbmUoKTtcbiAgICB9XG5cbiAgICBpZiAoIXByb3BzLmRvbWFpbkNvbmZpZy5jZXJ0aWZpY2F0ZSkge1xuICAgICAgLy8gSWYgbm8gY2VydGlmaWNhdGUgaXMgcHJvdmlkZWQgLSBjcmVhdGUgYSBuZXcgb25lXG4gICAgICB0aGlzLmNlcnRpZmljYXRlID0gbmV3IENlcnRpZmljYXRlKFxuICAgICAgICB0aGlzLFxuICAgICAgICBgJHtwcm9wcy5zZXJ2aWNlTmFtZX1DZXJ0aWZpY2F0ZWAsXG4gICAgICAgIHtcbiAgICAgICAgICBkb21haW5OYW1lOiBwcm9wcy5kb21haW5Db25maWcuZG9tYWluTmFtZSxcbiAgICAgICAgICB2YWxpZGF0aW9uOiBDZXJ0aWZpY2F0ZVZhbGlkYXRpb24uZnJvbURucyh0aGlzLmhvc3RlZFpvbmUpXG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gQ2hlY2sgaWYgdGhpcyBpcyBhIG11bHRpLXJlZ2lvbi93ZWlnaHRlZC9nZW8gcm91dGluZyBjb25maWd1cmF0aW9uXG4gICAgY29uc3QgbGF0ZW5jeUNvbmZpZyA9IHByb3BzLmRvbWFpbkNvbmZpZyBhcyBMYXRlbmN5RG9tYWluQ29uZmlnO1xuICAgIGNvbnN0IHdlaWdodGVkQ29uZmlnID0gcHJvcHMuZG9tYWluQ29uZmlnIGFzIFdlaWdodGVkRG9tYWluQ29uZmlnO1xuICAgIGNvbnN0IGdlb0NvbmZpZyA9IHByb3BzLmRvbWFpbkNvbmZpZyBhcyBHZW9Mb2NhdGlvbkRvbWFpbkNvbmZpZztcblxuICAgIGNvbnN0IGhhc1JvdXRpbmdQb2xpY3k6IGJvb2xlYW4gPVxuICAgICAgISFsYXRlbmN5Q29uZmlnPy5yZWdpb24gfHxcbiAgICAgIHdlaWdodGVkQ29uZmlnPy53ZWlnaHQgIT09IHVuZGVmaW5lZCB8fFxuICAgICAgISFnZW9Db25maWc/Lmdlb0xvY2F0aW9uO1xuXG4gICAgLy8gR2VuZXJhdGUgc2V0SWRlbnRpZmllciBpZiBub3QgcHJvdmlkZWQgYW5kIHVzaW5nIHJvdXRpbmcgcG9saWNpZXNcbiAgICAvLyBBV1MgcmVxdWlyZXMgc2V0SWRlbnRpZmllciBmb3IgYWxsIHJvdXRpbmcgcG9saWNpZXMgKGxhdGVuY3ksIHdlaWdodGVkLCBnZW8sIGZhaWxvdmVyLCBtdWx0aXZhbHVlKVxuICAgIGxldCBzZXRJZGVudGlmaWVyID0gcHJvcHMuZG9tYWluQ29uZmlnLnNldElkZW50aWZpZXI7XG4gICAgaWYgKGhhc1JvdXRpbmdQb2xpY3kgJiYgIXNldElkZW50aWZpZXIpIHtcbiAgICAgIGlmIChsYXRlbmN5Q29uZmlnPy5yZWdpb24pIHtcbiAgICAgICAgc2V0SWRlbnRpZmllciA9IGAke3Byb3BzLnNlcnZpY2VOYW1lfS0ke2xhdGVuY3lDb25maWcucmVnaW9ufWA7XG4gICAgICB9IGVsc2UgaWYgKHdlaWdodGVkQ29uZmlnPy53ZWlnaHQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBzZXRJZGVudGlmaWVyID0gYCR7cHJvcHMuc2VydmljZU5hbWV9LXdlaWdodC0ke3dlaWdodGVkQ29uZmlnLndlaWdodH1gO1xuICAgICAgfSBlbHNlIGlmIChnZW9Db25maWc/Lmdlb0xvY2F0aW9uKSB7XG4gICAgICAgIHNldElkZW50aWZpZXIgPSBgJHtwcm9wcy5zZXJ2aWNlTmFtZX0tZ2VvYDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBBbHdheXMgY3JlYXRlIGEgbmV3IEFSZWNvcmQgZm9yIHRoaXMgZG9tYWluIGFuZCBhdHRhY2ggaXQgdG8gdGhlIGxvYWQgYmFsYW5jZXJcbiAgICB0aGlzLmFSZWNvcmQgPSBuZXcgQVJlY29yZChcbiAgICAgIHRoaXMsXG4gICAgICBgJHtwcm9wcy5zZXJ2aWNlTmFtZX0uJHtwcm9wcy5jbHVzdGVyTmFtZX0uJHtwcm9wcy5kb21haW5Db25maWcuZG9tYWluTmFtZX1BUmVjb3JkYCxcbiAgICAgIHtcbiAgICAgICAgcmVjb3JkTmFtZTogcHJvcHMuZG9tYWluQ29uZmlnLmRvbWFpbk5hbWUsXG4gICAgICAgIHpvbmU6IHRoaXMuaG9zdGVkWm9uZSxcbiAgICAgICAgdGFyZ2V0OiBSZWNvcmRUYXJnZXQuZnJvbUFsaWFzKFxuICAgICAgICAgIG5ldyBMb2FkQmFsYW5jZXJUYXJnZXQodGhpcy5sb2FkQmFsYW5jZXIsIHtcbiAgICAgICAgICAgIGV2YWx1YXRlVGFyZ2V0SGVhbHRoOiBoYXNSb3V0aW5nUG9saWN5XG4gICAgICAgICAgfSlcbiAgICAgICAgKSxcbiAgICAgICAgcmVnaW9uOiBsYXRlbmN5Q29uZmlnPy5yZWdpb24sXG4gICAgICAgIHdlaWdodDogd2VpZ2h0ZWRDb25maWc/LndlaWdodCxcbiAgICAgICAgZ2VvTG9jYXRpb246IGdlb0NvbmZpZz8uZ2VvTG9jYXRpb24sXG4gICAgICAgIC8vIFNldCBpZGVudGlmaWVyIGlzIHJlcXVpcmVkIGZvciByb3V0aW5nIHBvbGljaWVzIChsYXRlbmN5LCB3ZWlnaHRlZCwgZ2VvLCBmYWlsb3ZlciwgbXVsdGl2YWx1ZSlcbiAgICAgICAgc2V0SWRlbnRpZmllcjogc2V0SWRlbnRpZmllclxuICAgICAgfVxuICAgICk7XG4gIH1cblxuICBnZXRJbWFnZShwcm9wczogRmFyZ2F0ZUNsdXN0ZXJQcm9wcyk6IENvbnRhaW5lckltYWdlIHtcbiAgICBpZiAoIXByb3BzLmVjclJlcG9zaXRvcnkpXG4gICAgICByZXR1cm4gQ29udGFpbmVySW1hZ2UuZnJvbVJlZ2lzdHJ5KFwiYW1hem9uL2FtYXpvbi1lY3Mtc2FtcGxlXCIpO1xuICAgIGlmIChwcm9wcy5lY3JSZXBvc2l0b3J5IGluc3RhbmNlb2YgQ29udGFpbmVySW1hZ2UpXG4gICAgICByZXR1cm4gcHJvcHMuZWNyUmVwb3NpdG9yeTtcbiAgICBpZiAocHJvcHMuZWNyUmVwb3NpdG9yeSBpbnN0YW5jZW9mIFJlcG9zaXRvcnkpIHtcbiAgICAgIHJldHVybiBDb250YWluZXJJbWFnZS5mcm9tRWNyUmVwb3NpdG9yeShwcm9wcy5lY3JSZXBvc2l0b3J5LCBcImxhdGVzdFwiKTtcbiAgICB9XG4gICAgcmV0dXJuIENvbnRhaW5lckltYWdlLmZyb21SZWdpc3RyeShcImFtYXpvbi9hbWF6b24tZWNzLXNhbXBsZVwiKTtcbiAgfVxuXG4gIHN0YXRpYyBidWlsZChcbiAgICBpZDogc3RyaW5nLFxuICAgIHByb3BzOiBGYXJnYXRlQ2x1c3RlclByb3BzXG4gICk6IChzYjogU3RhY2tCdWlsZGVyKSA9PiBDb25zdHJ1Y3Qge1xuICAgIHJldHVybiAoc2I6IFN0YWNrQnVpbGRlcikgPT4ge1xuICAgICAgY29uc3QgbmV3UHJvcHM6IEZhcmdhdGVDbHVzdGVyUHJvcHMgPSB7XG4gICAgICAgIC4uLnByb3BzLFxuICAgICAgICAuLi57XG4gICAgICAgICAgdnBjOiAoc2IuZ2V0TmV0d29yaygpIGFzIElWcGMpIHx8IHByb3BzLnZwY1xuICAgICAgICB9XG4gICAgICB9O1xuICAgICAgcmV0dXJuIG5ldyB0aGlzKHNiLmdldFN0YWNrKCksIGlkLCBuZXdQcm9wcyk7XG4gICAgfTtcbiAgfVxufVxuIl19
856
+ exports.default = EcsCluster;
857
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWNzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vbGliL3Jlc291cmNlcy9hd3MvY29tcHV0ZS9lY3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsaURBb0I2QjtBQUM3QixpREFTNkI7QUFDN0IsMkNBQXVDO0FBRXZDLDZDQUE4QztBQUM5Qyx1RkFPZ0Q7QUFDaEQsaURBUTZCO0FBQzdCLHVGQUtnRDtBQUNoRCxpREFBMEQ7QUFDMUQsdUVBQXdEO0FBQ3hELCtFQUc0QztBQUM1Qyx5REFLaUM7QUFDakMseUVBQXFFO0FBQ3JFLGlEQUFpRDtBQUNqRCxpRUFBMkU7QUFFM0Usc0RBQW1EO0FBQ25ELGlFQUFpRjtBQUNqRix3REFBcUQ7QUFDckQseUZBQXNGO0FBSXRGLElBQVksUUFHWDtBQUhELFdBQVksUUFBUTtJQUNsQix1Q0FBSSxDQUFBO0lBQ0oseUNBQUssQ0FBQTtBQUNQLENBQUMsRUFIVyxRQUFRLHdCQUFSLFFBQVEsUUFHbkI7QUFFRCxJQUFZLFdBR1g7QUFIRCxXQUFZLFdBQVc7SUFDckIsc0RBQTBELENBQUE7SUFDMUQsNERBQWdFLENBQUE7QUFDbEUsQ0FBQyxFQUhXLFdBQVcsMkJBQVgsV0FBVyxRQUd0QjtBQWtSRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FtQ0c7QUFDSCxNQUFxQixVQUFXLFNBQVEsc0JBQVM7SUFnQy9DLFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBc0I7UUFDOUQsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQVpuQix1QkFBdUI7UUFDZixhQUFRLEdBQUcsSUFBSSxHQUFHLEVBQXVCLENBQUM7UUFRMUMsaUJBQVksR0FBVyxHQUFHLENBQUM7UUFLakMsSUFBSSxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUM7UUFDbkIsSUFBSSxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUM7UUFDbkIsSUFBSSxDQUFDLGdCQUFnQixHQUFH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QkFDOUIsV0FBVyxFQUFFLFNBQVMsRUFBRSxXQUFXO29CQUNuQyxhQUFhLEVBQUUsYUFBYTtpQkFDN0IsQ0FBQyxDQUFDO1lBQ0wsQ0FBQztRQUNILENBQUM7YUFBTSxJQUFJLFlBQVksSUFBSSxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7WUFDN0MsdUNBQXVDO1lBQ3ZDLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxxQkFBTyxDQUFDLElBQUksRUFBRSxHQUFHLEtBQUssQ0FBQyxXQUFXLFNBQVMsRUFBRTtnQkFDOUQsVUFBVSxFQUFFLFVBQVU7Z0JBQ3RCLElBQUksRUFBRSxJQUFJLENBQUMsVUFBVTtnQkFDckIsTUFBTSxFQUFFLDBCQUFZLENBQUMsU0FBUyxDQUM1QixJQUFJLHdDQUFrQixDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FDMUM7YUFDRixDQUFDLENBQUM7UUFDTCxDQUFDO0lBQ0gsQ0FBQztJQUVELE1BQU0sQ0FBQyxLQUFLLENBQ1YsRUFBVSxFQUNWLEtBQXNCO1FBRXRCLE9BQU8sQ0FBQyxFQUFnQixFQUFFLEVBQUU7WUFDMUIsTUFBTSxRQUFRLEdBQW9CO2dCQUNoQyxHQUFHLEtBQUs7Z0JBQ1IsR0FBRztvQkFDRCxHQUFHLEVBQUcsRUFBRSxDQUFDLFVBQVUsRUFBVyxJQUFJLEtBQUssQ0FBQyxHQUFHO2lCQUM1QzthQUNGLENBQUM7WUFDRixPQUFPLElBQUksSUFBSSxDQUFDLEVBQUUsQ0FBQyxRQUFRLEVBQUUsRUFBRSxFQUFFLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFDL0MsQ0FBQyxDQUFDO0lBQ0osQ0FBQztDQUNGO0FBNWxDRCw2QkE0bENDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQXdzTG9nRHJpdmVyLFxuICBDbHVzdGVyIGFzIENka0NsdXN0ZXIsXG4gIENvbnRhaW5lckltYWdlLFxuICBGYXJnYXRlU2VydmljZSxcbiAgRmFyZ2F0ZVRhc2tEZWZpbml0aW9uLFxuICBFYzJTZXJ2aWNlLFxuICBFYzJUYXNrRGVmaW5pdGlvbixcbiAgTmV0d29ya01vZGUsXG4gIFByb3BhZ2F0ZWRUYWdTb3VyY2UsXG4gIHR5cGUgUmVwb3NpdG9yeUltYWdlLFxuICB0eXBlIENvbnRhaW5lckRlZmluaXRpb24sXG4gIENvbnRhaW5lckluc2lnaHRzLFxuICBQbGFjZW1lbnRTdHJhdGVneSxcbiAgQXNnQ2FwYWNpdHlQcm92aWRlcixcbiAgRWNzT3B0aW1pemVkSW1hZ2UsXG4gIEFtaUhhcmR3YXJlVHlwZSxcbiAgQ3B1QXJjaGl0ZWN0dXJlLFxuICBPcGVyYXRpbmdTeXN0ZW1GYW1pbHksXG4gIENmbkNsdXN0ZXJDYXBhY2l0eVByb3ZpZGVyQXNzb2NpYXRpb25zXG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtZWNzXCI7XG5pbXBvcnQge1xuICBDb25uZWN0aW9ucyxcbiAgdHlwZSBJQ29ubmVjdGFibGUsXG4gIHR5cGUgSVNlY3VyaXR5R3JvdXAsXG4gIHR5cGUgSVZwYyxcbiAgSW5zdGFuY2VUeXBlLFxuICBQZWVyLFxuICBQb3J0LFxuICBTdWJuZXRUeXBlXG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtZWMyXCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tIFwiY29uc3RydWN0c1wiO1xuaW1wb3J0IHsgdHlwZSBTdGFja0J1aWxkZXIgfSBmcm9tIFwiLi4vYmFzZS9hd3NTdGFja1wiO1xuaW1wb3J0IHsgRHVyYXRpb24sIFN0YWNrIH0gZnJvbSBcImF3cy1jZGstbGliXCI7XG5pbXBvcnQge1xuICB0eXBlIEFwcGxpY2F0aW9uTGlzdGVuZXIsXG4gIEFwcGxpY2F0aW9uTG9hZEJhbGFuY2VyLFxuICBBcHBsaWNhdGlvblByb3RvY29sLFxuICB0eXBlIElBcHBsaWNhdGlvblRhcmdldEdyb3VwLFxuICBMaXN0ZW5lckFjdGlvbixcbiAgTGlzdGVuZXJDb25kaXRpb25cbn0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1lbGFzdGljbG9hZGJhbGFuY2luZ3YyXCI7XG5pbXBvcnQge1xuICBFZmZlY3QsXG4gIHR5cGUgSU1hbmFnZWRQb2xpY3ksXG4gIFBvbGljeSxcbiAgUG9saWN5RG9jdW1lbnQsXG4gIFBvbGljeVN0YXRlbWVudCxcbiAgUm9sZSxcbiAgU2VydmljZVByaW5jaXBhbFxufSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWlhbVwiO1xuaW1wb3J0IHtcbiAgUHJlZGVmaW5lZE1ldHJpYyxcbiAgU2NhbGFibGVUYXJnZXQsXG4gIFNlcnZpY2VOYW1lc3BhY2UsXG4gIFRhcmdldFRyYWNraW5nU2NhbGluZ1BvbGljeVxufSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWFwcGxpY2F0aW9uYXV0b3NjYWxpbmdcIjtcbmltcG9ydCB7IFNlY3JldCBhcyBFY3NTZWNyZXQgfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWVjc1wiO1xuaW1wb3J0IHsgU2VjcmV0IH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1zZWNyZXRzbWFuYWdlclwiO1xuaW1wb3J0IHtcbiAgQ2VydGlmaWNhdGUsXG4gIENlcnRpZmljYXRlVmFsaWRhdGlvblxufSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWNlcnRpZmljYXRlbWFuYWdlclwiO1xuaW1wb3J0IHtcbiAgQVJlY29yZCxcbiAgUmVjb3JkVGFyZ2V0LFxuICB0eXBlIElIb3N0ZWRab25lLFxuICB0eXBlIEdlb0xvY2F0aW9uXG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3Mtcm91dGU1M1wiO1xuaW1wb3J0IHsgTG9hZEJhbGFuY2VyVGFyZ2V0IH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1yb3V0ZTUzLXRhcmdldHNcIjtcbmltcG9ydCB7IFJlcG9zaXRvcnkgfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWVjclwiO1xuaW1wb3J0IHsgQXV0b1NjYWxpbmdHcm91cCwgTW9uaXRvcmluZyB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtYXV0b3NjYWxpbmdcIjtcblxuaW1wb3J0IHsgQ2ZuT3V0cHV0IH0gZnJvbSBcIi4uL3V0aWxpdGllcy9jZm5PdXRwdXRcIjtcbmltcG9ydCB7IEhvc3RlZFpvbmUgYXMgRmphbGxIb3N0ZWRab25lIH0gZnJvbSBcIi4uLy4uLy4uL3BhdHRlcm5zL2F3cy9ob3N0ZWRab25lXCI7XG5pbXBvcnQgeyBTZWN1cml0eUdyb3VwIH0gZnJvbSBcIi4uL2lhbS9zZWN1cml0eUdyb3VwXCI7XG5pbXBvcnQgeyBDYXBhY2l0eVByb3ZpZGVyRHJhaW5XYWl0ZXIgfSBmcm9tIFwiLi91dGlsaXRpZXMvY2FwYWNpdHlQcm92aWRlckRyYWluV2FpdGVyXCI7XG5cbmltcG9ydCB7IHR5cGUgU2VjcmV0SW1wb3J0IH0gZnJvbSBcIi4uL3NlY3JldHNcIjtcblxuZXhwb3J0IGVudW0gUHJvdG9jb2wge1xuICBIVFRQLFxuICBIVFRQU1xufVxuXG5leHBvcnQgZW51bSBTY2FsaW5nVHlwZSB7XG4gIENQVSA9IFByZWRlZmluZWRNZXRyaWMuRUNTX1NFUlZJQ0VfQVZFUkFHRV9DUFVfVVRJTElaQVRJT04sXG4gIE1FTU9SWSA9IFByZWRlZmluZWRNZXRyaWMuRUNTX1NFUlZJQ0VfQVZFUkFHRV9NRU1PUllfVVRJTElaQVRJT05cbn1cblxuZXhwb3J0IHR5cGUgRWNzQ2FwYWNpdHlQcm92aWRlciA9IFwiRkFSR0FURVwiIHwgXCJGQVJHQVRFX1NQT1RcIiB8IFwiRUMyXCI7XG5cbi8qKlxuICogRUMyIGNhcGFjaXR5IGNvbmZpZ3VyYXRpb24gZm9yIEVDUyBFQzItYmFja2VkIGNsdXN0ZXJzLlxuICogT25seSB1c2VkIHdoZW4gY2FwYWNpdHlQcm92aWRlciBpcyBcIkVDMlwiLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEVjMkNhcGFjaXR5Q29uZmlnIHtcbiAgLyoqIEVDMiBpbnN0YW5jZSB0eXBlLiBEZWZhdWx0OiBcInQzLm1pY3JvXCIgKi9cbiAgaW5zdGFuY2VUeXBlPzogc3RyaW5nO1xuICAvKiogQU1JIGhhcmR3YXJlIHR5cGUuIERlZmF1bHQ6IFwiQVJNXCIgKEdyYXZpdG9uIC0gYmV0dGVyIGNvc3QvcGVyZm9ybWFuY2UpICovXG4gIGFtaUhhcmR3YXJlVHlwZT86IFwiQVJNXCIgfCBcIlNUQU5EQVJEXCI7XG4gIC8qKiBNaW5pbXVtIG51bWJlciBvZiBpbnN0YW5jZXMuIERlZmF1bHQ6IDIgKi9cbiAgbWluQ2FwYWNpdHk/OiBudW1iZXI7XG4gIC8qKiBNYXhpbXVtIG51bWJlciBvZiBpbnN0YW5jZXMuIERlZmF1bHQ6IDMgKi9cbiAgbWF4Q2FwYWNpdHk/OiBudW1iZXI7XG4gIC8qKiBNZW1vcnkgbGltaXQgaW4gTWlCIGZvciB0aGUgY29udGFpbmVyLiBEZWZhdWx0OiAxMDI0ICovXG4gIG1lbW9yeUxpbWl0TWlCPzogbnVtYmVyO1xufVxuXG4vKipcbiAqIERvbWFpbiBjb25maWd1cmF0aW9uIGZvciBIVFRQUyBhbmQgRE5TLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIERvbWFpbkJhc2VDb25maWcge1xuICBkb21haW5OYW1lOiBzdHJpbmc7XG4gIGhvc3RlZFpvbmU/OiBGamFsbEhvc3RlZFpvbmU7XG4gIGNlcnRpZmljYXRlPzogQ2VydGlmaWNhdGU7XG4gIHNldElkZW50aWZpZXI/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTGF0ZW5jeURvbWFpbkNvbmZpZyBleHRlbmRzIERvbWFpbkJhc2VDb25maWcge1xuICByZWdpb246IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBXZWlnaHRlZERvbWFpbkNvbmZpZyBleHRlbmRzIERvbWFpbkJhc2VDb25maWcge1xuICB3ZWlnaHQ6IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBHZW9Mb2NhdGlvbkRvbWFpbkNvbmZpZyBleHRlbmRzIERvbWFpbkJhc2VDb25maWcge1xuICBnZW9Mb2NhdGlvbjogR2VvTG9jYXRpb247XG59XG5cbmV4cG9ydCB0eXBlIERvbWFpbkNvbmZpZyA9XG4gIHwgRG9tYWluQmFzZUNvbmZpZ1xuICB8IExhdGVuY3lEb21haW5Db25maWdcbiAgfCBXZWlnaHRlZERvbWFpbkNvbmZpZ1xuICB8IEdlb0xvY2F0aW9uRG9tYWluQ29uZmlnO1xuXG4vKipcbiAqIEludGVybmFsIGNvbmZpZ3VyYXRpb24gZm9yIGEgY29udGFpbmVyIGluIGEgbXVsdGktY29udGFpbmVyIEVDUyB0YXNrLlxuICpcbiAqIEluIG11bHRpLWNvbnRhaW5lciB0YXNrcywgdGhlIGZpcnN0IGNvbnRhaW5lciB3aXRoIGEgYHBvcnRgIGlzIHRoZSAqKnByaW1hcnkgY29udGFpbmVyKipcbiAqIHRoYXQgcmVjZWl2ZXMgbG9hZCBiYWxhbmNlciB0cmFmZmljLiBBbGwgb3RoZXIgY29udGFpbmVycyBhcmUgKipzaWRlY2FycyoqIHRoYXQgcHJvdmlkZVxuICogc3VwcG9ydGluZyBmdW5jdGlvbmFsaXR5IChsb2dnaW5nLCBtb25pdG9yaW5nLCBwcm94aWVzLCBldGMuKS5cbiAqXG4gKiBAZXhhbXBsZVxuICogLy8gUHJpbWFyeSBjb250YWluZXIgKGhhcyBwb3J0KSArIHNpZGVjYXIgKG5vIHBvcnQpXG4gKiBjb250YWluZXJzOiBbXG4gKiAgIHsgbmFtZTogXCJhcHBcIiwgcG9ydDogMzAwMCB9LCAgICAgICAgICAgLy8gUHJpbWFyeSAtIHJlY2VpdmVzIEFMQiB0cmFmZmljXG4gKiAgIHsgbmFtZTogXCJkYXRhZG9nXCIsIGltYWdlOiBcImRhdGFkb2cvYWdlbnRcIiB9ICAvLyBTaWRlY2FyIC0gbW9uaXRvcmluZ1xuICogXVxuICpcbiAqIEBpbnRlcm5hbFxuICovXG5leHBvcnQgaW50ZXJmYWNlIEVjc0NsdXN0ZXJDb250YWluZXJDb25maWcge1xuICAvKiogVW5pcXVlIGNvbnRhaW5lciBuYW1lICovXG4gIG5hbWU6IHN0cmluZztcbiAgLyoqXG4gICAqIENvbnRhaW5lciBpbWFnZS4gT3B0aW9uczpcbiAgICogLSBPbWl0OiBVc2VzIGRlZmF1bHQgRUNSIHJlcG9zaXRvcnkgKHByaW1hcnkgY29udGFpbmVyIG9ubHkpXG4gICAqIC0gc3RyaW5nOiBFQ1IgcmVwb3NpdG9yeSBuYW1lIG9yIHB1YmxpYyBpbWFnZSBVUkxcbiAgICogLSBSZXBvc2l0b3J5OiBDREsgRUNSIFJlcG9zaXRvcnkgY29uc3RydWN0XG4gICAqL1xuICBpbWFnZT86IHN0cmluZyB8IFJlcG9zaXRvcnk7XG4gIC8qKlxuICAgKiBQb3J0IHRoZSBjb250YWluZXIgbGlzdGVucyBvbi5cbiAgICogVGhlIGZpcnN0IGNvbnRhaW5lciB3aXRoIGEgcG9ydCBiZWNvbWVzIHRoZSAqKnByaW1hcnkgY29udGFpbmVyKipcbiAgICogYW5kIGlzIHJlZ2lzdGVyZWQgd2l0aCB0aGUgbG9hZCBiYWxhbmNlci5cbiAgICovXG4gIHBvcnQ/OiBudW1iZXI7XG4gIC8qKiBFbnZpcm9ubWVudCB2YXJpYWJsZXMgKi9cbiAgZW52aXJvbm1lbnQ/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xuICAvKiogU2VjcmV0cyBpbXBvcnRlZCBmcm9tIG90aGVyIHJlc291cmNlcyAqL1xuICBzZWNyZXRzSW1wb3J0PzogeyBba2V5OiBzdHJpbmddOiBTZWNyZXRJbXBvcnQgfTtcbiAgLyoqIENvbW1hbmQgdG8gcnVuIGluIHRoZSBjb250YWluZXIgKi9cbiAgY29tbWFuZD86IHN0cmluZ1tdO1xuICAvKiogRW50cnkgcG9pbnQgZm9yIHRoZSBjb250YWluZXIgKi9cbiAgZW50cnlQb2ludD86IHN0cmluZ1tdO1xuICAvKipcbiAgICogV2hldGhlciB0aGlzIGNvbnRhaW5lciBpcyBlc3NlbnRpYWwuXG4gICAqIElmIGFuIGVzc2VudGlhbCBjb250YWluZXIgc3RvcHMsIGFsbCBjb250YWluZXJzIGluIHRoZSB0YXNrIHN0b3AuXG4gICAqIERlZmF1bHQ6IHRydWUgZm9yIHByaW1hcnkgY29udGFpbmVyLCB0cnVlIGZvciBzaWRlY2Fyc1xuICAgKi9cbiAgZXNzZW50aWFsPzogYm9vbGVhbjtcbiAgLyoqXG4gICAqIEhlYWx0aCBjaGVjayBjb25maWd1cmF0aW9uLlxuICAgKiBEZWZhdWx0OiBGb3IgcHJpbWFyeSBjb250YWluZXIgd2l0aCBwb3J0LCB1c2VzIGN1cmwgaGVhbHRoIGNoZWNrLlxuICAgKi9cbiAgaGVhbHRoQ2hlY2s/OiB7XG4gICAgY29tbWFuZDogc3RyaW5nW107XG4gICAgaW50ZXJ2YWw/OiBudW1iZXI7XG4gICAgdGltZW91dD86IG51bWJlcjtcbiAgICByZXRyaWVzPzogbnVtYmVyO1xuICAgIHN0YXJ0UGVyaW9kPzogbnVtYmVyO1xuICB9O1xufVxuXG4vKipcbiAqIENsdXN0ZXItbGV2ZWwgY29uZmlndXJhdGlvbi5cbiAqIENvbnRyb2xzIHRoZSBzaGFyZWQgQUxCIGZvciBhbGwgc2VydmljZXMgaW4gdGhpcyBjbHVzdGVyLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEVjc0NsdXN0ZXJDbHVzdGVyQ29uZmlnIHtcbiAgLyoqXG4gICAqIERvbWFpbiBmb3IgSFRUUFMgYWNjZXNzLlxuICAgKiAtIE9taXQ6IEFMQiBjcmVhdGVkIHdpdGggZGVmYXVsdCBETlMgKCouZWxiLmFtYXpvbmF3cy5jb20pXG4gICAqIC0gU3BlY2lmaWVkOiBDcmVhdGVzIEFDTSBjZXJ0aWZpY2F0ZSArIFJvdXRlNTMgRE5TIEEgcmVjb3JkXG4gICAqL1xuICBkb21haW4/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIExvYWQgYmFsYW5jZXIgY29uZmlndXJhdGlvbi5cbiAgICogLSBmYWxzZTogTm8gQUxCIChmb3Igd29ya2Vycy9pbnRlcm5hbCBzZXJ2aWNlcylcbiAgICogLSBcInB1YmxpY1wiOiBJbnRlcm5ldC1mYWNpbmcgQUxCIChkZWZhdWx0KVxuICAgKiAtIFwiaW50ZXJuYWxcIjogVlBDLW9ubHkgQUxCXG4gICAqL1xuICBsb2FkQmFsYW5jZXI/OiBmYWxzZSB8IFwicHVibGljXCIgfCBcImludGVybmFsXCI7XG5cbiAgLyoqXG4gICAqIEVuYWJsZSBkaXJlY3QgRUMyIGFjY2VzcyB3aXRob3V0IEFMQi5cbiAgICogT3BlbnMgY29udGFpbmVyIHBvcnRzIG9uIHNlY3VyaXR5IGdyb3VwIGZvciBkaXJlY3QgYWNjZXNzIHZpYSBFQzIgcHVibGljIElQLlxuICAgKiBVc2VzIGhvc3QgbmV0d29yayBtb2RlIGZvciBwcmVkaWN0YWJsZSBwb3J0IG1hcHBpbmcgKGNvbnRhaW5lcjozMDAwIOKGkiBob3N0OjMwMDApLlxuICAgKiBPbmx5IHZhbGlkIHdpdGggRUMyIGNhcGFjaXR5IHByb3ZpZGVyLlxuICAgKi9cbiAgZGlyZWN0QWNjZXNzPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogRG9tYWluIGNvbmZpZ3VyYXRpb24gZm9yIGFkdmFuY2VkIHJvdXRpbmcgcG9saWNpZXMgKGxhdGVuY3ksIHdlaWdodGVkLCBnZW8pLlxuICAgKiBPbmx5IHVzZWQgd2hlbiBkb21haW4gaXMgc3BlY2lmaWVkLlxuICAgKi9cbiAgZG9tYWluQ29uZmlnPzogRG9tYWluQ29uZmlnO1xufVxuXG4vKipcbiAqIFJvdXRpbmcgY29uZmlndXJhdGlvbiBmb3IgcGF0aC9ob3N0LWJhc2VkIHJvdXRpbmcgb24gdGhlIEFMQi5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBFY3NSb3V0aW5nQ29uZmlnIHtcbiAgLyoqIFBhdGggcGF0dGVybiBmb3Igcm91dGluZyAoZS5nLiwgXCIvYXBpLypcIiwgXCIvdXNlcnMvKlwiKSAqL1xuICBwYXRoPzogc3RyaW5nO1xuICAvKiogSG9zdCBoZWFkZXIgZm9yIHJvdXRpbmcgKGUuZy4sIFwiYXBpLmV4YW1wbGUuY29tXCIpICovXG4gIGhvc3Q/OiBzdHJpbmc7XG4gIC8qKiBQcmlvcml0eSBmb3IgdGhpcyByb3V0aW5nIHJ1bGUgKDEtNTAwMDApLiBMb3dlciA9IGhpZ2hlciBwcmlvcml0eS4gKi9cbiAgcHJpb3JpdHk/OiBudW1iZXI7XG4gIC8qKiBIZWFsdGggY2hlY2sgcGF0aCBmb3IgdGhpcyBzZXJ2aWNlJ3MgdGFyZ2V0IGdyb3VwLiBEZWZhdWx0OiBcIi9cIiAqL1xuICBoZWFsdGhDaGVja1BhdGg/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogQ29uZmlndXJhdGlvbiBmb3IgYSBzZXJ2aWNlIGluIGFuIEVDUyBjbHVzdGVyLlxuICogRWFjaCBzZXJ2aWNlIGdldHMgaXRzIG93biB0YXNrIGRlZmluaXRpb24sIHNjYWxpbmcsIGFuZCB0YXJnZXQgZ3JvdXAuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRWNzU2VydmljZVByb3BzIHtcbiAgLyoqIFNlcnZpY2UgbmFtZSAodW5pcXVlIHdpdGhpbiBjbHVzdGVyKSAqL1xuICBuYW1lOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIENvbnRhaW5lciBpbWFnZSBmb3IgdGhpcyBzZXJ2aWNlLlxuICAgKiAtIE9taXQ6IFVzZXMgY2x1c3RlcidzIGRlZmF1bHQgRUNSIHJlcG9zaXRvcnlcbiAgICogLSBzdHJpbmc6IEVDUiByZXBvc2l0b3J5IG5hbWUgb3IgcHVibGljIGltYWdlIFVSTFxuICAgKiAtIFJlcG9zaXRvcnk6IENESyBFQ1IgUmVwb3NpdG9yeSBjb25zdHJ1Y3RcbiAgICovXG4gIGltYWdlPzogc3RyaW5nIHwgUmVwb3NpdG9yeTtcblxuICAvKipcbiAgICogQ29udGFpbmVyIGNvbmZpZ3VyYXRpb25zIGZvciB0aGlzIHNlcnZpY2UuXG4gICAqIFRoZSBmaXJzdCBjb250YWluZXIgd2l0aCBhIHBvcnQgaXMgdGhlICoqcHJpbWFyeSBjb250YWluZXIqKiAocmVjZWl2ZXMgQUxCIHRyYWZmaWMpLlxuICAgKi9cbiAgY29udGFpbmVyczogRWNzQ2x1c3RlckNvbnRhaW5lckNvbmZpZ1tdO1xuXG4gIC8qKiBDUFUgdW5pdHMgZm9yIHRoaXMgc2VydmljZSdzIHRhc2tzICgyNTYtNDA5NikgKi9cbiAgY3B1PzogbnVtYmVyO1xuXG4gIC8qKiBNZW1vcnkgaW4gTWlCIGZvciB0aGlzIHNlcnZpY2UncyB0YXNrcyAoNTEyLTMwNzIwKSAqL1xuICBtZW1vcnlMaW1pdE1pQj86IG51bWJlcjtcblxuICAvKiogRGVzaXJlZCBudW1iZXIgb2YgdGFza3MuIERlZmF1bHQ6IDIgKi9cbiAgZGVzaXJlZENvdW50PzogbnVtYmVyO1xuXG4gIC8qKiBTY2FsaW5nIHR5cGUgKENQVSBvciBNRU1PUlkpLiBPbWl0IHRvIGRpc2FibGUgYXV0by1zY2FsaW5nLiAqL1xuICBzY2FsaW5nVHlwZT86IFNjYWxpbmdUeXBlO1xuXG4gIC8qKiBNaW5pbXVtIG51bWJlciBvZiB0YXNrcyBmb3IgYXV0by1zY2FsaW5nLiBEZWZhdWx0OiAyICovXG4gIG1pbkNhcGFjaXR5PzogbnVtYmVyO1xuXG4gIC8qKiBNYXhpbXVtIG51bWJlciBvZiB0YXNrcyBmb3IgYXV0by1zY2FsaW5nLiBEZWZhdWx0OiAxMCAqL1xuICBtYXhDYXBhY2l0eT86IG51bWJlcjtcblxuICAvKipcbiAgICogUm91dGluZyBydWxlcyBmb3IgdGhpcyBzZXJ2aWNlIG9uIHRoZSBjbHVzdGVyJ3MgQUxCLlxuICAgKiBSZXF1aXJlZCB3aGVuIGNsdXN0ZXIgaGFzIG11bHRpcGxlIHNlcnZpY2VzIHdpdGggcG9ydHMuXG4gICAqL1xuICByb3V0aW5nPzogRWNzUm91dGluZ0NvbmZpZztcblxuICAvKipcbiAgICogQWRkaXRpb25hbCBpbmxpbmUgcG9saWNpZXMgZm9yIHRoaXMgc2VydmljZSdzIHRhc2sgcm9sZS5cbiAgICogQWRkZWQgb24gdG9wIG9mIHRoZSBkZWZhdWx0IEVDUyBFeGVjIHBlcm1pc3Npb25zLlxuICAgKi9cbiAgdGFza1JvbGVJbmxpbmVQb2xpY2llcz86IHtcbiAgICBbbmFtZTogc3RyaW5nXTogUG9saWN5RG9jdW1lbnQ7XG4gIH07XG5cbiAgLyoqXG4gICAqIEFkZGl0aW9uYWwgbWFuYWdlZCBwb2xpY2llcyBmb3IgdGhpcyBzZXJ2aWNlJ3MgdGFzayByb2xlLlxuICAgKiBBZGRlZCBvbiB0b3Agb2YgdGhlIGRlZmF1bHQgRUNTIEV4ZWMgcGVybWlzc2lvbnMuXG4gICAqL1xuICB0YXNrUm9sZU1hbmFnZWRQb2xpY2llcz86IElNYW5hZ2VkUG9saWN5W107XG5cbiAgLyoqXG4gICAqIFJlc291cmNlcyB0aGlzIHNlcnZpY2UgbmVlZHMgdG8gY29ubmVjdCB0byAoZS5nLiwgZGF0YWJhc2VzKS5cbiAgICogQ3JlYXRlcyBzZWN1cml0eSBncm91cCBydWxlcyB0byBhbGxvdyB0cmFmZmljIGZyb20gdGhpcyBzcGVjaWZpYyBzZXJ2aWNlIG9ubHkuXG4gICAqL1xuICBjb25uZWN0aW9ucz86IElDb25uZWN0YWJsZVtdO1xufVxuXG4vKipcbiAqIFByb3BzIGZvciBjcmVhdGluZyBhbiBFQ1MgY2x1c3RlciB3aXRoIG11bHRpcGxlIHNlcnZpY2VzLlxuICovXG5leHBvcnQgdHlwZSBFY3NDbHVzdGVyUHJvcHMgPSB7XG4gIC8qKiBDbHVzdGVyIG5hbWUgKi9cbiAgY2x1c3Rlck5hbWU6IHN0cmluZztcblxuICAvKiogVlBDIHRvIGRlcGxveSBpbnRvICovXG4gIHZwYz86IElWcGM7XG5cbiAgLyoqIERlZmF1bHQgRUNSIHJlcG9zaXRvcnkgb3IgY29udGFpbmVyIGltYWdlICovXG4gIGVjclJlcG9zaXRvcnk6IFJlcG9zaXRvcnkgfCBSZXBvc2l0b3J5SW1hZ2UgfCBzdHJpbmc7XG5cbiAgLyoqIENhcGFjaXR5IHByb3ZpZGVyIGRldGVybWluZXMgRmFyZ2F0ZSB2cyBFQzIgaW5mcmFzdHJ1Y3R1cmUgKi9cbiAgY2FwYWNpdHlQcm92aWRlcj86IEVjc0NhcGFjaXR5UHJvdmlkZXI7XG5cbiAgLyoqIEVDMi1zcGVjaWZpYyBjb25maWd1cmF0aW9uLiBPbmx5IHVzZWQgd2hlbiBjYXBhY2l0eVByb3ZpZGVyIGlzIFwiRUMyXCIgKi9cbiAgZWMyQ29uZmlnPzogRWMyQ2FwYWNpdHlDb25maWc7XG5cbiAgLyoqXG4gICAqIENsdXN0ZXIgY29uZmlndXJhdGlvbi5cbiAgICogQ29udHJvbHMgdGhlIHNoYXJlZCBBTEIgZm9yIGFsbCBzZXJ2aWNlcy5cbiAgICovXG4gIGNsdXN0ZXI/OiBFY3NDbHVzdGVyQ2x1c3RlckNvbmZpZztcblxuICAvKipcbiAgICogU2VydmljZXMgaW4gdGhpcyBjbHVzdGVyLlxuICAgKiBFYWNoIHNlcnZpY2UgZ2V0cyBpdHMgb3duIHRhc2sgZGVmaW5pdGlvbiwgc2NhbGluZywgYW5kIHRhcmdldCBncm91cC5cbiAgICogQWxsIHNlcnZpY2VzIHNoYXJlIHRoZSBjbHVzdGVyJ3MgQUxCICh1bmxlc3MgZGlzYWJsZWQpLlxuICAgKiBUYXNrIHJvbGUgcG9saWNpZXMgYXJlIGNvbmZpZ3VyZWQgcGVyLXNlcnZpY2UgZm9yIGxlYXN0LXByaXZpbGVnZS5cbiAgICovXG4gIHNlcnZpY2VzOiBFY3NTZXJ2aWNlUHJvcHNbXTtcbn07XG5cbi8qKlxuICogRGF0YSB0cmFja2VkIGZvciBlYWNoIHNlcnZpY2UgaW4gdGhlIGNsdXN0ZXIuXG4gKi9cbmludGVyZmFjZSBTZXJ2aWNlRGF0YSB7XG4gIHNlcnZpY2U6IEZhcmdhdGVTZXJ2aWNlIHwgRWMyU2VydmljZTtcbiAgdGFza0RlZmluaXRpb246IEZhcmdhdGVUYXNrRGVmaW5pdGlvbiB8IEVjMlRhc2tEZWZpbml0aW9uO1xuICAvKiogUm9sZSBmb3IgRUNTIGFnZW50IChwdWxsIGltYWdlcywgd3JpdGUgbG9ncywgaW5qZWN0IHNlY3JldHMpICovXG4gIGV4ZWN1dGlvblJvbGU6IFJvbGU7XG4gIC8qKiBSb2xlIGZvciBhcHBsaWNhdGlvbiBjb2RlICh1c2VyIHBvbGljaWVzLCBFQ1MgRXhlYykgKi9cbiAgdGFza1JvbGU6IFJvbGU7XG4gIGNvbnRhaW5lcnM6IENvbnRhaW5lckRlZmluaXRpb25bXTtcbiAgcHJpbWFyeUNvbnRhaW5lcj86IENvbnRhaW5lckRlZmluaXRpb247XG4gIHRhcmdldEdyb3VwPzogSUFwcGxpY2F0aW9uVGFyZ2V0R3JvdXA7XG4gIHNjYWxpbmdQb2xpY3k/OiBUYXJnZXRUcmFja2luZ1NjYWxpbmdQb2xpY3k7XG59XG5cbi8qKlxuICogRUNTIENsdXN0ZXIgc3VwcG9ydGluZyBtdWx0aXBsZSBzZXJ2aWNlcyB3aXRoIGEgc2hhcmVkIEFMQi5cbiAqXG4gKiBAZXhhbXBsZVxuICogLy8gU2luZ2xlIHNlcnZpY2UgY2x1c3RlclxuICogbmV3IEVjc0NsdXN0ZXIoc2NvcGUsIFwiV2ViQ2x1c3RlclwiLCB7XG4gKiAgIGNsdXN0ZXJOYW1lOiBcIldlYkNsdXN0ZXJcIixcbiAqICAgZWNyUmVwb3NpdG9yeTogZWNyLFxuICogICBzZXJ2aWNlczogW1xuICogICAgIHsgbmFtZTogXCJ3ZWJcIiwgY29udGFpbmVyczogW3sgbmFtZTogXCJhcHBcIiwgcG9ydDogMzAwMCB9XSB9XG4gKiAgIF1cbiAqIH0pO1xuICpcbiAqIEBleGFtcGxlXG4gKiAvLyBNdWx0aS1zZXJ2aWNlIGNsdXN0ZXIgd2l0aCByb3V0aW5nXG4gKiBuZXcgRWNzQ2x1c3RlcihzY29wZSwgXCJBcGlDbHVzdGVyXCIsIHtcbiAqICAgY2x1c3Rlck5hbWU6IFwiQXBpQ2x1c3RlclwiLFxuICogICBjbHVzdGVyOiB7IGRvbWFpbjogXCJhcGkuZXhhbXBsZS5jb21cIiB9LFxuICogICBlY3JSZXBvc2l0b3J5OiBlY3IsXG4gKiAgIHNlcnZpY2VzOiBbXG4gKiAgICAgeyBuYW1lOiBcInVzZXJzXCIsIGNvbnRhaW5lcnM6IFt7IG5hbWU6IFwiYXBwXCIsIHBvcnQ6IDMwMDAgfV0sIHJvdXRpbmc6IHsgcGF0aDogXCIvdXNlcnMvKlwiIH0gfSxcbiAqICAgICB7IG5hbWU6IFwib3JkZXJzXCIsIGNvbnRhaW5lcnM6IFt7IG5hbWU6IFwiYXBwXCIsIHBvcnQ6IDMwMDEgfV0sIHJvdXRpbmc6IHsgcGF0aDogXCIvb3JkZXJzLypcIiB9IH1cbiAqICAgXVxuICogfSk7XG4gKlxuICogQGV4YW1wbGVcbiAqIC8vIFdvcmtlciBjbHVzdGVyIChubyBBTEIpXG4gKiBuZXcgRWNzQ2x1c3RlcihzY29wZSwgXCJXb3JrZXJzXCIsIHtcbiAqICAgY2x1c3Rlck5hbWU6IFwiV29ya2Vyc1wiLFxuICogICBjbHVzdGVyOiB7IGxvYWRCYWxhbmNlcjogZmFsc2UgfSxcbiAqICAgZWNyUmVwb3NpdG9yeTogZWNyLFxuICogICBzZXJ2aWNlczogW1xuICogICAgIHsgbmFtZTogXCJwcm9jZXNzb3JcIiwgY29udGFpbmVyczogW3sgbmFtZTogXCJ3b3JrZXJcIiB9XSB9XG4gKiAgIF1cbiAqIH0pO1xuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBFY3NDbHVzdGVyIGV4dGVuZHMgQ29uc3RydWN0IGltcGxlbWVudHMgSUNvbm5lY3RhYmxlIHtcbiAgcHVibGljIGNvbm5lY3Rpb25zOiBDb25uZWN0aW9ucztcblxuICAvLyBDbHVzdGVyLWxldmVsIHJlc291cmNlc1xuICBwcml2YXRlIGNsdXN0ZXI6IENka0NsdXN0ZXI7XG4gIHByaXZhdGUgbG9hZEJhbGFuY2VyPzogQXBwbGljYXRpb25Mb2FkQmFsYW5jZXI7XG4gIHByaXZhdGUgbG9hZEJhbGFuY2VyTGlzdGVuZXI/OiBBcHBsaWNhdGlvbkxpc3RlbmVyO1xuICBwcml2YXRlIGhvc3RlZFpvbmU/OiBJSG9zdGVkWm9uZTtcbiAgcHJpdmF0ZSBjZXJ0aWZpY2F0ZT86IENlcnRpZmljYXRlO1xuICBwcml2YXRlIGFSZWNvcmQ/OiBBUmVjb3JkO1xuXG4gIC8vIEVDMi1zcGVjaWZpY1xuICBwcml2YXRlIGF1dG9TY2FsaW5nR3JvdXA/OiBBdXRvU2NhbGluZ0dyb3VwO1xuICBwcml2YXRlIGFzZ1NlY3VyaXR5R3JvdXA/OiBTZWN1cml0eUdyb3VwO1xuICBwcml2YXRlIGFzZ0NhcGFjaXR5UHJvdmlkZXI/OiBBc2dDYXBhY2l0eVByb3ZpZGVyO1xuICBwcml2YXRlIGxvYWRCYWxhbmNlclNlY3VyaXR5R3JvdXA/OiBTZWN1cml0eUdyb3VwO1xuICBwcml2YXRlIGRyYWluV2FpdGVyPzogQ2FwYWNpdHlQcm92aWRlckRyYWluV2FpdGVyO1xuXG4gIC8vIEZhcmdhdGUtc3BlY2lmaWMgLSByZWZlcmVuY2UgdG8gQ0RLJ3MgaW50ZXJuYWwgY2FwYWNpdHkgcHJvdmlkZXIgYXNzb2NpYXRpb25zXG4gIHByaXZhdGUgZmFyZ2F0ZUNhcGFjaXR5UHJvdmlkZXJBc3NvY2lhdGlvbnM/OiBDZm5DbHVzdGVyQ2FwYWNpdHlQcm92aWRlckFzc29jaWF0aW9ucztcblxuICAvLyBQZXItc2VydmljZSB0cmFja2luZ1xuICBwcml2YXRlIHNlcnZpY2VzID0gbmV3IE1hcDxzdHJpbmcsIFNlcnZpY2VEYXRhPigpO1xuXG4gIC8vIENvbmZpZ3VyYXRpb25cbiAgcHJpdmF0ZSBzY29wZTogQ29uc3RydWN0O1xuICBwcml2YXRlIHByb3BzOiBFY3NDbHVzdGVyUHJvcHM7XG4gIHByaXZhdGUgY2FwYWNpdHlQcm92aWRlcjogRWNzQ2FwYWNpdHlQcm92aWRlcjtcbiAgcHJpdmF0ZSBsb2FkQmFsYW5jZXJEaXNhYmxlZDogYm9vbGVhbjtcbiAgcHJpdmF0ZSBkaXJlY3RBY2Nlc3NFbmFibGVkOiBib29sZWFuO1xuICBwcml2YXRlIG5leHRQcmlvcml0eTogbnVtYmVyID0gMTAwO1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBFY3NDbHVzdGVyUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgdGhpcy5zY29wZSA9IHNjb3BlO1xuICAgIHRoaXMucHJvcHMgPSBwcm9wcztcbiAgICB0aGlzLmNhcGFjaXR5UHJvdmlkZXIgPSBwcm9wcy5jYXBhY2l0eVByb3ZpZGVyIHx8IFwiRkFSR0FURVwiO1xuICAgIHRoaXMuZGlyZWN0QWNjZXNzRW5hYmxlZCA9IHByb3BzLmNsdXN0ZXI/LmRpcmVjdEFjY2VzcyA9PT0gdHJ1ZTtcbiAgICB0aGlzLmxvYWRCYWxhbmNlckRpc2FibGVkID1cbiAgICAgIHByb3BzLmNsdXN0ZXI/LmxvYWRCYWxhbmNlciA9PT0gZmFsc2UgfHwgdGhpcy5kaXJlY3RBY2Nlc3NFbmFibGVkO1xuXG4gICAgdGhpcy52YWxpZGF0ZVByb3BzKHByb3BzKTtcblxuICAgIC8vIDEuIENyZWF0ZSB0aGUgRUNTIGNsdXN0ZXJcbiAgICB0aGlzLmFkZENsdXN0ZXIocHJvcHMpO1xuXG4gICAgLy8gMi4gU2V0IHVwIEVDMiBpbmZyYXN0cnVjdHVyZSBpZiBuZWVkZWRcbiAgICBpZiAodGhpcy5pc0VjMigpKSB7XG4gICAgICB0aGlzLmFkZEF1dG9TY2FsaW5nR3JvdXAocHJvcHMpO1xuICAgIH1cblxuICAgIC8vIDMuIENyZWF0ZSBBTEIgaWYgbm90IGRpc2FibGVkIChzaGFyZWQgYnkgYWxsIHNlcnZpY2VzKVxuICAgIGlmICghdGhpcy5sb2FkQmFsYW5jZXJEaXNhYmxlZCkge1xuICAgICAgdGhpcy5hZGRMb2FkQmFsYW5jZXIocHJvcHMpO1xuXG4gICAgICAvLyBTZXQgdXAgZG9tYWluL0hUVFBTIGlmIGNvbmZpZ3VyZWRcbiAgICAgIGlmIChwcm9wcy5jbHVzdGVyPy5kb21haW4gfHwgcHJvcHMuY2x1c3Rlcj8uZG9tYWluQ29uZmlnKSB7XG4gICAgICAgIHRoaXMuYWRkSG9zdGVkWm9uZShwcm9wcyk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuYWRkTG9hZEJhbGFuY2VyTGlzdGVuZXIocHJvcHMpO1xuICAgIH0gZWxzZSBpZiAodGhpcy5kaXJlY3RBY2Nlc3NFbmFibGVkKSB7XG4gICAgICB0aGlzLmFkZERpcmVjdEFjY2Vzc091dHB1dHMocHJvcHMpO1xuICAgIH1cblxuICAgIC8vIDQuIENyZWF0ZSBlYWNoIHNlcnZpY2VcbiAgICBmb3IgKGNvbnN0IHNlcnZpY2VQcm9wcyBvZiBwcm9wcy5zZXJ2aWNlcykge1xuICAgICAgdGhpcy5hZGRTZXJ2aWNlVG9DbHVzdGVyKHNlcnZpY2VQcm9wcyk7XG4gICAgfVxuXG4gICAgLy8gNS4gU2V0IHVwIGNvbm5lY3Rpb25zXG4gICAgdGhpcy5zZXR1cENvbm5lY3Rpb25zKHByb3BzKTtcbiAgfVxuXG4gIC8qKiBHZXQgdGhlIGNsdXN0ZXIncyBsb2FkIGJhbGFuY2VyLiBVbmRlZmluZWQgaWYgZGlzYWJsZWQuICovXG4gIGdldExvYWRCYWxhbmNlcigpOiBBcHBsaWNhdGlvbkxvYWRCYWxhbmNlciB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMubG9hZEJhbGFuY2VyO1xuICB9XG5cbiAgLyoqIEdldCB0aGUgbG9hZCBiYWxhbmNlcidzIGxpc3RlbmVyLiBVbmRlZmluZWQgaWYgZGlzYWJsZWQuICovXG4gIGdldExpc3RlbmVyKCk6IEFwcGxpY2F0aW9uTGlzdGVuZXIgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLmxvYWRCYWxhbmNlckxpc3RlbmVyO1xuICB9XG5cbiAgLyoqIEdldCBhIHNwZWNpZmljIHNlcnZpY2UgYnkgbmFtZS4gKi9cbiAgZ2V0U2VydmljZShuYW1lOiBzdHJpbmcpOiBGYXJnYXRlU2VydmljZSB8IEVjMlNlcnZpY2UgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLnNlcnZpY2VzLmdldChuYW1lKT8uc2VydmljZTtcbiAgfVxuXG4gIC8qKiBHZXQgYWxsIHNlcnZpY2VzIGluIHRoaXMgY2x1c3Rlci4gKi9cbiAgZ2V0U2VydmljZXMoKTogTWFwPHN0cmluZywgRmFyZ2F0ZVNlcnZpY2UgfCBFYzJTZXJ2aWNlPiB7XG4gICAgY29uc3QgcmVzdWx0ID0gbmV3IE1hcDxzdHJpbmcsIEZhcmdhdGVTZXJ2aWNlIHwgRWMyU2VydmljZT4oKTtcbiAgICBmb3IgKGNvbnN0IFtuYW1lLCBkYXRhXSBvZiB0aGlzLnNlcnZpY2VzKSB7XG4gICAgICByZXN1bHQuc2V0KG5hbWUsIGRhdGEuc2VydmljZSk7XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICAvKiogR2V0IHRoZSBFQ1MgY2x1c3RlciBjb25zdHJ1Y3QuICovXG4gIGdldENsdXN0ZXIoKTogQ2RrQ2x1c3RlciB7XG4gICAgcmV0dXJuIHRoaXMuY2x1c3RlcjtcbiAgfVxuXG4gIC8qKiBHZXQgdGhlIEFMQiBVUkwgKGh0dHA6Ly8gb3IgaHR0cHM6Ly8pLiAqL1xuICBnZXRVcmwoKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICBpZiAoIXRoaXMubG9hZEJhbGFuY2VyKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgIGNvbnN0IHByb3RvY29sID0gdGhpcy5jZXJ0aWZpY2F0ZSA/IFwiaHR0cHNcIiA6IFwiaHR0cFwiO1xuICAgIGNvbnN0IGRvbWFpbiA9XG4gICAgICB0aGlzLnByb3BzLmNsdXN0ZXI/LmRvbWFpbiB8fCB0aGlzLmxvYWRCYWxhbmNlci5sb2FkQmFsYW5jZXJEbnNOYW1lO1xuICAgIHJldHVybiBgJHtwcm90b2NvbH06Ly8ke2RvbWFpbn1gO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZCBhIHNlcnZpY2UgdG8gdGhlIGNsdXN0ZXIuXG4gICAqIEVhY2ggc2VydmljZSBnZXRzIGl0cyBvd24gdGFzayBkZWZpbml0aW9uLCBjb250YWluZXJzLCBhbmQgdGFyZ2V0IGdyb3VwLlxuICAgKi9cbiAgcHJpdmF0ZSBhZGRTZXJ2aWNlVG9DbHVzdGVyKHNlcnZpY2VQcm9wczogRWNzU2VydmljZVByb3BzKTogdm9pZCB7XG4gICAgY29uc3Qgc2VydmljZU5hbWUgPSBzZXJ2aWNlUHJvcHMubmFtZTtcblxuICAgIC8vIENyZWF0ZSBzZXBhcmF0ZSByb2xlcyBmb3Igc2VjdXJpdHkgYmVzdCBwcmFjdGljZVxuICAgIGNvbnN0IGV4ZWN1dGlvblJvbGUgPSB0aGlzLmNyZWF0ZUV4ZWN1dGlvblJvbGUoc2VydmljZU5hbWUpO1xuICAgIGNvbnN0IHRhc2tSb2xlID0gdGhpcy5jcmVhdGVUYXNrUm9sZShzZXJ2aWNlTmFtZSwgc2VydmljZVByb3BzKTtcblxuICAgIC8vIENyZWF0ZSB0YXNrIGRlZmluaXRpb24gd2l0aCBib3RoIHJvbGVzXG4gICAgY29uc3QgdGFza0RlZmluaXRpb24gPSB0aGlzLmNyZWF0ZVRhc2tEZWZpbml0aW9uKFxuICAgICAgc2VydmljZU5hbWUsXG4gICAgICBzZXJ2aWNlUHJvcHMsXG4gICAgICBleGVjdXRpb25Sb2xlLFxuICAgICAgdGFza1JvbGVcbiAgICApO1xuXG4gICAgLy8gQWRkIGNvbnRhaW5lcnMgdG8gdGFzayBkZWZpbml0aW9uXG4gICAgY29uc3QgeyBjb250YWluZXJzLCBwcmltYXJ5Q29udGFpbmVyIH0gPSB0aGlzLmFkZENvbnRhaW5lcnNUb1Rhc2soXG4gICAgICBzZXJ2aWNlTmFtZSxcbiAgICAgIHNlcnZpY2VQcm9wcyxcbiAgICAgIHRhc2tEZWZpbml0aW9uXG4gICAgKTtcblxuICAgIC8vIENyZWF0ZSB0aGUgRUNTIHNlcnZpY2VcbiAgICBjb25zdCBzZXJ2aWNlID0gdGhpcy5jcmVhdGVTZXJ2aWNlKFxuICAgICAgc2VydmljZU5hbWUsXG4gICAgICBzZXJ2aWNlUHJvcHMsXG4gICAgICB0YXNrRGVmaW5pdGlvblxuICAgICk7XG5cbiAgICAvLyBSZWdpc3RlciB3aXRoIEFMQiBpZiBlbmFibGVkIGFuZCBoYXMgcHJpbWFyeSBjb250YWluZXIgd2l0aCBwb3J0XG4gICAgbGV0IHRhcmdldEdyb3VwOiBJQXBwbGljYXRpb25UYXJnZXRHcm91cCB8IHVuZGVmaW5lZDtcbiAgICBpZiAoXG4gICAgICAhdGhpcy5sb2FkQmFsYW5jZXJEaXNhYmxlZCAmJlxuICAgICAgcHJpbWFyeUNvbnRhaW5lciAmJlxuICAgICAgdGhpcy5sb2FkQmFsYW5jZXJMaXN0ZW5lclxuICAgICkge1xuICAgICAgdGFyZ2V0R3JvdXAgPSB0aGlzLnJlZ2lzdGVyU2VydmljZVdpdGhBTEIoXG4gICAgICAgIHNlcnZpY2VOYW1lLFxuICAgICAgICBzZXJ2aWNlUHJvcHMsXG4gICAgICAgIHNlcnZpY2UsXG4gICAgICAgIHByaW1hcnlDb250YWluZXJcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gQWRkIHNjYWxpbmcgaWYgY29uZmlndXJlZFxuICAgIGxldCBzY2FsaW5nUG9saWN5OiBUYXJnZXRUcmFja2luZ1NjYWxpbmdQb2xpY3kgfCB1bmRlZmluZWQ7XG4gICAgaWYgKHNlcnZpY2VQcm9wcy5zY2FsaW5nVHlwZSkge1xuICAgICAgc2NhbGluZ1BvbGljeSA9IHRoaXMuYWRkU2VydmljZVNjYWxpbmcoXG4gICAgICAgIHNlcnZpY2VOYW1lLFxuICAgICAgICBzZXJ2aWNlUHJvcHMsXG4gICAgICAgIHNlcnZpY2VcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gU3RvcmUgc2VydmljZSBkYXRhXG4gICAgdGhpcy5zZXJ2aWNlcy5zZXQoc2VydmljZU5hbWUsIHtcbiAgICAgIHNlcnZpY2UsXG4gICAgICB0YXNrRGVmaW5pdGlvbixcbiAgICAgIGV4ZWN1dGlvblJvbGUsXG4gICAgICB0YXNrUm9sZSxcbiAgICAgIGNvbnRhaW5lcnMsXG4gICAgICBwcmltYXJ5Q29udGFpbmVyLFxuICAgICAgdGFyZ2V0R3JvdXAsXG4gICAgICBzY2FsaW5nUG9saWN5XG4gICAgfSk7XG5cbiAgICAvLyBBZGQgc2VydmljZSBsZXZlbCBjb25uZWN0aW9uc1xuICAgIGlmIChzZXJ2aWNlUHJvcHMuY29ubmVjdGlvbnMgJiYgc2VydmljZVByb3BzLmNvbm5lY3Rpb25zLmxlbmd0aCA+IDApIHtcbiAgICAgIGZvciAoY29uc3QgY29ubmVjdGFibGUgb2Ygc2VydmljZVByb3BzLmNvbm5lY3Rpb25zKSB7XG4gICAgICAgIHNlcnZpY2UuY29ubmVjdGlvbnMuYWxsb3dUb0RlZmF1bHRQb3J0KGNvbm5lY3RhYmxlKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHZhbGlkYXRlUHJvcHMocHJvcHM6IEVjc0NsdXN0ZXJQcm9wcyk6IHZvaWQge1xuICAgIC8vIFZhbGlkYXRlIHNlcnZpY2VzIGFycmF5XG4gICAgaWYgKCFwcm9wcy5zZXJ2aWNlcyB8fCBwcm9wcy5zZXJ2aWNlcy5sZW5ndGggPT09IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkF0IGxlYXN0IG9uZSBzZXJ2aWNlIG11c3QgYmUgc3BlY2lmaWVkLlwiKTtcbiAgICB9XG5cbiAgICAvLyBDaGVjayBmb3IgZHVwbGljYXRlIHNlcnZpY2UgbmFtZXNcbiAgICBjb25zdCBzZXJ2aWNlTmFtZXMgPSBwcm9wcy5zZXJ2aWNlcy5tYXAoKHMpID0+IHMubmFtZSk7XG4gICAgY29uc3QgZHVwbGljYXRlU2VydmljZXMgPSBzZXJ2aWNlTmFtZXMuZmlsdGVyKFxuICAgICAgKG5hbWUsIGluZGV4KSA9PiBzZXJ2aWNlTmFtZXMuaW5kZXhPZihuYW1lKSAhPT0gaW5kZXhcbiAgICApO1xuICAgIGlmIChkdXBsaWNhdGVTZXJ2aWNlcy5sZW5ndGggPiAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBEdXBsaWNhdGUgc2VydmljZSBuYW1lczogJHtbLi4ubmV3IFNldChkdXBsaWNhdGVTZXJ2aWNlcyldLmpvaW4oXCIsIFwiKX1gXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIFZhbGlkYXRlIHJvdXRpbmcgd2hlbiBtdWx0aXBsZSBzZXJ2aWNlcyBoYXZlIHBvcnRzXG4gICAgY29uc3Qgc2VydmljZXNXaXRoUG9ydHMgPSBwcm9wcy5zZXJ2aWNlcy5maWx0ZXIoKHMpID0+XG4gICAgICBzLmNvbnRhaW5lcnMuc29tZSgoYykgPT4gYy5wb3J0ICE9PSB1bmRlZmluZWQpXG4gICAgKTtcblxuICAgIGlmIChzZXJ2aWNlc1dpdGhQb3J0cy5sZW5ndGggPiAxICYmICF0aGlzLmxvYWRCYWxhbmNlckRpc2FibGVkKSB7XG4gICAgICBjb25zdCBtaXNzaW5nUm91dGluZyA9IHNlcnZpY2VzV2l0aFBvcnRzLmZpbHRlcihcbiAgICAgICAgKHMpID0+ICFzLnJvdXRpbmc/LnBhdGggJiYgIXMucm91dGluZz8uaG9zdFxuICAgICAgKTtcbiAgICAgIGlmIChtaXNzaW5nUm91dGluZy5sZW5ndGggPiAwKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICBgU2VydmljZXMgd2l0aCBwb3J0cyByZXF1aXJlIHJvdXRpbmcgY29uZmlnIHdoZW4gY2x1c3RlciBoYXMgbXVsdGlwbGUgc2VydmljZXM6IGAgK1xuICAgICAgICAgICAgYCR7bWlzc2luZ1JvdXRpbmcubWFwKChzKSA9PiBzLm5hbWUpLmpvaW4oXCIsIFwiKX0uIGAgK1xuICAgICAgICAgICAgXCJBZGQgcm91dGluZzogeyBwYXRoOiAnLy4uLicgfSB0byBlYWNoIHNlcnZpY2UuXCJcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBWYWxpZGF0ZSBlYWNoIHNlcnZpY2UncyBjb250YWluZXJzXG4gICAgZm9yIChjb25zdCBzZXJ2aWNlIG9mIHByb3BzLnNlcnZpY2VzKSB7XG4gICAgICBpZiAoIXNlcnZpY2UuY29udGFpbmVycyB8fCBzZXJ2aWNlLmNvbnRhaW5lcnMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICBgU2VydmljZSAnJHtzZXJ2aWNlLm5hbWV9JzogQXQgbGVhc3Qgb25lIGNvbnRhaW5lciBtdXN0IGJlIHNwZWNpZmllZC5gXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIC8vIENoZWNrIGZvciBkdXBsaWNhdGUgY29udGFpbmVyIG5hbWVzIHdpdGhpbiBzZXJ2aWNlXG4gICAgICBjb25zdCBjb250YWluZXJOYW1lcyA9IHNlcnZpY2UuY29udGFpbmVycy5tYXAoKGMpID0+IGMubmFtZSk7XG4gICAgICBjb25zdCBkdXBsaWNhdGVDb250YWluZXJzID0gY29udGFpbmVyTmFtZXMuZmlsdGVyKFxuICAgICAgICAobmFtZSwgaW5kZXgpID0+IGNvbnRhaW5lck5hbWVzLmluZGV4T2YobmFtZSkgIT09IGluZGV4XG4gICAgICApO1xuICAgICAgaWYgKGR1cGxpY2F0ZUNvbnRhaW5lcnMubGVuZ3RoID4gMCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgYFNlcnZpY2UgJyR7c2VydmljZS5uYW1lfSc6IER1cGxpY2F0ZSBjb250YWluZXIgbmFtZXM6IGAgK1xuICAgICAgICAgICAgYCR7Wy4uLm5ldyBTZXQoZHVwbGljYXRlQ29udGFpbmVycyldLmpvaW4oXCIsIFwiKX1gXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBzZXR1cENvbm5lY3Rpb25zKHByb3BzOiBFY3NDbHVzdGVyUHJvcHMpOiB2b2lkIHtcbiAgICAvLyBGaW5kIHRoZSBmaXJzdCBzZXJ2aWNlIHdpdGggYSBwb3J0IGZvciBkZWZhdWx0IGNvbm5lY3Rpb25cbiAgICBsZXQgZGVmYXVsdFBvcnQgPSA4MDtcbiAgICBmb3IgKGNvbnN0IHNlcnZpY2Ugb2YgcHJvcHMuc2VydmljZXMpIHtcbiAgICAgIGNvbnN0IHByaW1hcnlDb250YWluZXIgPSBzZXJ2aWNlLmNvbnRhaW5lcnMuZmluZChcbiAgICAgICAgKGMpID0+IGMucG9ydCAhPT0gdW5kZWZpbmVkXG4gICAgICApO1xuICAgICAgaWYgKHByaW1hcnlDb250YWluZXI/LnBvcnQpIHtcbiAgICAgICAgZGVmYXVsdFBvcnQgPSBwcmltYXJ5Q29udGFpbmVyLnBvcnQ7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cblxuICAgIGxldCBzZWN1cml0eUdyb3VwczogSVNlY3VyaXR5R3JvdXBbXSA9IFtdO1xuICAgIGlmICh0aGlzLmlzRWMyKCkpIHtcbiAgICAgIHNlY3VyaXR5R3JvdXBzID0gW3RoaXMuYXNnU2VjdXJpdHlHcm91cCFdO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBmaXJzdFNlcnZpY2UgPSB0aGlzLnNlcnZpY2VzLnZhbHVlcygpLm5leHQoKS52YWx1ZTtcbiAgICAgIHNlY3VyaXR5R3JvdXBzID0gZmlyc3RTZXJ2aWNlPy5zZXJ2aWNlPy5jb25uZWN0aW9ucz8uc2VjdXJpdHlHcm91cHMgfHwgW107XG4gICAgfVxuXG4gICAgdGhpcy5jb25uZWN0aW9ucyA9IG5ldyBDb25uZWN0aW9ucyh7XG4gICAgICBzZWN1cml0eUdyb3VwcyxcbiAgICAgIGRlZmF1bHRQb3J0OiBQb3J0LnRjcChkZWZhdWx0UG9ydClcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIHRoZSBleGVjdXRpb24gcm9sZSBmb3IgRUNTIGluZnJhc3RydWN0dXJlIG9wZXJhdGlvbnMuXG4gICAqIFVzZWQgYnkgdGhlIEVDUyBhZ2VudCB0byBwdWxsIGltYWdlcywgd3JpdGUgbG9ncywgYW5kIGluamVjdCBzZWNyZXRzLlxuICAgKiBOT1QgdXNlZCBieSBhcHBsaWNhdGlvbiBjb2RlIC0gdGhhdCdzIHRoZSB0YXNrIHJvbGUuXG4gICAqL1xuICBwcml2YXRlIGNyZWF0ZUV4ZWN1dGlvblJvbGUoc2VydmljZU5hbWU6IHN0cmluZyk6IFJvbGUge1xuICAgIGNvbnN0IGV4ZWN1dGlvblJvbGUgPSBuZXcgUm9sZSh0aGlzLCBgJHtzZXJ2aWNlTmFtZX1FeGVjdXRpb25Sb2xlYCwge1xuICAgICAgYXNzdW1lZEJ5OiBuZXcgU2VydmljZVByaW5jaXBhbChcImVjcy10YXNrcy5hbWF6b25hd3MuY29tXCIpXG4gICAgfSk7XG5cbiAgICAvLyBFQ1IgcHVsbCBwZXJtaXNzaW9uc1xuICAgIGV4ZWN1dGlvblJvbGUuYWRkVG9Qb2xpY3koXG4gICAgICBuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgZWZmZWN0OiBFZmZlY3QuQUxMT1csXG4gICAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgICBcImVjcjpHZXRBdXRob3JpemF0aW9uVG9rZW5cIixcbiAgICAgICAgICBcImVjcjpCYXRjaENoZWNrTGF5ZXJBdmFpbGFiaWxpdHlcIixcbiAgICAgICAgICBcImVjcjpHZXREb3dubG9hZFVybEZvckxheWVyXCIsXG4gICAgICAgICAgXCJlY3I6QmF0Y2hHZXRJbWFnZVwiXG4gICAgICAgIF0sXG4gICAgICAgIHJlc291cmNlczogW1wiKlwiXVxuICAgICAgfSlcbiAgICApO1xuXG4gICAgLy8gQ2xvdWRXYXRjaCBMb2dzIHBlcm1pc3Npb25zXG4gICAgZXhlY3V0aW9uUm9sZS5hZGRUb1BvbGljeShcbiAgICAgIG5ldyBQb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBlZmZlY3Q6IEVmZmVjdC5BTExPVyxcbiAgICAgICAgYWN0aW9uczogW1xuICAgICAgICAgIFwibG9nczpDcmVhdGVMb2dTdHJlYW1cIixcbiAgICAgICAgICBcImxvZ3M6UHV0TG9nRXZlbnRzXCIsXG4gICAgICAgICAgXCJsb2dzOkNyZWF0ZUxvZ0dyb3VwXCJcbiAgICAgICAgXSxcbiAgICAgICAgcmVzb3VyY2VzOiBbXCIqXCJdXG4gICAgICB9KVxuICAgICk7XG5cbiAgICAvLyBTZWNyZXRzIE1hbmFnZXIgYWNjZXNzIGZvciBpbmplY3Rpbmcgc2VjcmV0cyBpbnRvIGNvbnRhaW5lcnNcbiAgICBleGVjdXRpb25Sb2xlLmFkZFRvUG9saWN5KFxuICAgICAgbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgIGVmZmVjdDogRWZmZWN0LkFMTE9XLFxuICAgICAgICBhY3Rpb25zOiBbXG4gICAgICAgICAgXCJzZWNyZXRzbWFuYWdlcjpHZXRTZWNyZXRWYWx1ZVwiLFxuICAgICAgICAgIFwic2VjcmV0c21hbmFnZXI6RGVzY3JpYmVTZWNyZXRcIlxuICAgICAgICBdLFxuICAgICAgICByZXNvdXJjZXM6IFtcIipcIl1cbiAgICAgIH0pXG4gICAgKTtcblxuICAgIC8vIEtNUyBkZWNyeXB0IGZvciBzZWNyZXRzIGVuY3J5cHRlZCB3aXRoIGN1c3RvbWVyLW1hbmFnZWQga2V5c1xuICAgIGV4ZWN1dGlvblJvbGUuYWRkVG9Qb2xpY3koXG4gICAgICBuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgZWZmZWN0OiBFZmZlY3QuQUxMT1csXG4gICAgICAgIGFjdGlvbnM6IFtcImttczpEZWNyeXB0XCJdLFxuICAgICAgICByZXNvdXJjZXM6IFtcIipcIl1cbiAgICAgIH0pXG4gICAgKTtcblxuICAgIHJldHVybiBleGVjdXRpb25Sb2xlO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgdGhlIHRhc2sgcm9sZSBmb3IgYXBwbGljYXRpb24gY29kZSBydW5uaW5nIGluIHRoZSBjb250YWluZXIuXG4gICAqIFRoaXMgcm9sZSBpcyBhc3N1bWVkIGJ5IHRoZSBhcHBsaWNhdGlvbiwgbm90IHRoZSBFQ1MgYWdlbnQuXG4gICAqIEluY2x1ZGVzIGRlZmF1bHQgRUNTIEV4ZWMgcGVybWlzc2lvbnMgcGx1cyBhbnkgc2VydmljZS1zcGVjaWZpYyBwb2xpY2llcy5cbiAgICovXG4gIHByaXZhdGUgY3JlYXRlVGFza1JvbGUoXG4gICAgc2VydmljZU5hbWU6IHN0cmluZyxcbiAgICBzZXJ2aWNlUHJvcHM6IEVjc1NlcnZpY2VQcm9wc1xuICApOiBSb2xlIHtcbiAgICBjb25zdCB0YXNrUm9sZSA9IG5ldyBSb2xlKHRoaXMsIGAke3NlcnZpY2VOYW1lfVRhc2tSb2xlYCwge1xuICAgICAgYXNzdW1lZEJ5OiBuZXcgU2VydmljZVByaW5jaXBhbChcImVjcy10YXNrcy5hbWF6b25hd3MuY29tXCIpXG4gICAgfSk7XG5cbiAgICAvLyBEZWZhdWx0OiBTU00gcGVybWlzc2lvbnMgZm9yIEVDUyBFeGVjIChlY3MgZXhlY3V0ZS1jb21tYW5kKVxuICAgIHRhc2tSb2xlLmFkZFRvUG9saWN5KFxuICAgICAgbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgIGVmZmVjdDogRWZmZWN0LkFMTE9XLFxuICAgICAgICBhY3Rpb25zOiBbXG4gICAgICAgICAgXCJzc21tZXNzYWdlczpDcmVhdGVDb250cm9sQ2hhbm5lbFwiLFxuICAgICAgICAgIFwic3NtbWVzc2FnZXM6Q3JlYXRlRGF0YUNoYW5uZWxcIixcbiAgICAgICAgICBcInNzbW1lc3NhZ2VzOk9wZW5Db250cm9sQ2hhbm5lbFwiLFxuICAgICAgICAgIFwic3NtbWVzc2FnZXM6T3BlbkRhdGFDaGFubmVsXCJcbiAgICAgICAgXSxcbiAgICAgICAgcmVzb3VyY2VzOiBbXCIqXCJdXG4gICAgICB9KVxuICAgICk7XG5cbiAgICAvLyBBZGQgc2VydmljZS1zcGVjaWZpYyBpbmxpbmUgcG9saWNpZXNcbiAgICBpZiAoc2VydmljZVByb3BzLnRhc2tSb2xlSW5saW5lUG9saWNpZXMpIHtcbiAgICAgIGZvciAoY29uc3QgW3BvbGljeU5hbWUsIHBvbGljeURvY3VtZW50XSBvZiBPYmplY3QuZW50cmllcyhcbiAgICAgICAgc2VydmljZVByb3BzLnRhc2tSb2xlSW5saW5lUG9saWNpZXNcbiAgICAgICkpIHtcbiAgICAgICAgdGFza1JvbGUuYXR0YWNoSW5saW5lUG9saWN5KFxuICAgICAgICAgIG5ldyBQb2xpY3kodGhpcywgYCR7c2VydmljZU5hbWV9JHtwb2xpY3lOYW1lfWAsIHtcbiAgICAgICAgICAgIGRvY3VtZW50OiBwb2xpY3lEb2N1bWVudFxuICAgICAgICAgIH0pXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gQWRkIHNlcnZpY2Utc3BlY2lmaWMgbWFuYWdlZCBwb2xpY2llc1xuICAgIGlmIChzZXJ2aWNlUHJvcHMudGFza1JvbGVNYW5hZ2VkUG9saWNpZXMpIHtcbiAgICAgIGZvciAoY29uc3QgcG9saWN5IG9mIHNlcnZpY2VQcm9wcy50YXNrUm9sZU1hbmFnZWRQb2xpY2llcykge1xuICAgICAgICB0YXNrUm9sZS5hZGRNYW5hZ2VkUG9saWN5KHBvbGljeSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRhc2tSb2xlO1xuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVUYXNrRGVmaW5pdGlvbihcbiAgICBzZXJ2aWNlTmFtZTogc3RyaW5nLFxuICAgIHNlcnZpY2VQcm9wczogRWNzU2VydmljZVByb3BzLFxuICAgIGV4ZWN1dGlvblJvbGU6IFJvbGUsXG4gICAgdGFza1JvbGU6IFJvbGVcbiAgKTogRmFyZ2F0ZVRhc2tEZWZpbml0aW9uIHwgRWMyVGFza0RlZmluaXRpb24ge1xuICAgIGNvbnN0IGNwdSA9IHNlcnZpY2VQcm9wcy5jcHUgfHwgMjU2O1xuICAgIGNvbnN0IG1lbW9yeUxpbWl0TWlCID0gc2VydmljZVByb3BzLm1lbW9yeUxpbWl0TWlCIHx8IDUxMjtcblxuICAgIGlmICh0aGlzLmlzRmFyZ2F0ZSgpKSB7XG4gICAgICByZXR1cm4gbmV3IEZhcmdhdGVUYXNrRGVmaW5pdGlvbih0aGlzLCBgJHtzZXJ2aWNlTmFtZX1UYXNrRGVmaW5pdGlvbmAsIHtcbiAgICAgICAgZmFtaWx5OiBgJHt0aGlzLnByb3BzLmNsdXN0ZXJOYW1lfS0ke3NlcnZpY2VOYW1lfWAsXG4gICAgICAgIGNwdSxcbiAgICAgICAgbWVtb3J5TGltaXRNaUIsXG4gICAgICAgIGV4ZWN1dGlvblJvbGUsXG4gICAgICAgIHRhc2tSb2xlLFxuICAgICAgICBydW50aW1lUGxhdGZvcm06IHtcbiAgICAgICAgICBjcHVBcmNoaXRlY3R1cmU6IENwdUFyY2hpdGVjdHVyZS5BUk02NCxcbiAgICAgICAgICBvcGVyYXRpbmdTeXN0ZW1GYW1pbHk6IE9wZXJhdGluZ1N5c3RlbUZhbWlseS5MSU5VWFxuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIG5ldyBFYzJUYXNrRGVmaW5pdGlvbih0aGlzLCBgJHtzZXJ2aWNlTmFtZX1UYXNrRGVmaW5pdGlvbmAsIHtcbiAgICAgICAgZmFtaWx5OiBgJHt0aGlzLnByb3BzLmNsdXN0ZXJOYW1lfS0ke3NlcnZpY2VOYW1lfWAsXG4gICAgICAgIGV4ZWN1dGlvblJvbGUsXG4gICAgICAgIHRhc2tSb2xlLFxuICAgICAgICAuLi4odGhpcy5kaXJlY3RBY2Nlc3NFbmFibGVkICYmIHsgbmV0d29ya01vZGU6IE5ldHdvcmtNb2RlLkhPU1QgfSlcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYWRkQ29udGFpbmVyc1RvVGFzayhcbiAgICBzZXJ2aWNlTmFtZTogc3RyaW5nLFxuICAgIHNlcnZpY2VQcm9wczogRWNzU2VydmljZVByb3BzLFxuICAgIHRhc2tEZWZpbml0aW9uOiBGYXJnYXRlVGFza0RlZmluaXRpb24gfCBFYzJUYXNrRGVmaW5pdGlvblxuICApOiB7XG4gICAgY29udGFpbmVyczogQ29udGFpbmVyRGVmaW5pdGlvbltdO1xuICAgIHByaW1hcnlDb250YWluZXI/OiBDb250YWluZXJEZWZpbml0aW9uO1xuICB9IHtcbiAgICBjb25zdCBjb250YWluZXJzOiBDb250YWluZXJEZWZpbml0aW9uW10gPSBbXTtcbiAgICBsZXQgcHJpbWFyeUNvbnRhaW5lcjogQ29udGFpbmVyRGVmaW5pdGlvbiB8IHVuZGVmaW5lZDtcblxuICAgIGZvciAoY29uc3QgY29udGFpbmVyQ29uZmlnIG9mIHNlcnZpY2VQcm9wcy5jb250YWluZXJzKSB7XG4gICAgICBjb25zdCBpbWFnZSA9IHRoaXMuZ2V0Q29udGFpbmVySW1hZ2UoXG4gICAgICAgIHNlcnZpY2VOYW1lLFxuICAgICAgICBjb250YWluZXJDb25maWcsXG4gICAgICAgIHNlcnZpY2VQcm9wc1xuICAgICAgKTtcbiAgICAgIGNvbnN0IGlzRmlyc3RXaXRoUG9ydCA9XG4gICAgICAgICFwcmltYXJ5Q29udGFpbmVyICYmIGNvbnRhaW5lckNvbmZpZy5wb3J0ICE9PSB1bmRlZmluZWQ7XG5cbiAgICAgIC8vIEJ1aWxkIHNlY3JldHNcbiAgICAgIGNvbnN0IHNlY3JldHM6IFJlY29yZDxzdHJpbmcsIEVjc1NlY3JldD4gPSB7fTtcbiAgICAgIGlmIChjb250YWluZXJDb25maWcuc2VjcmV0c0ltcG9ydCkge1xuICAgICAgICBmb3IgKGNvbnN0IFtrZXksIHNlY3JldEltcG9ydF0gb2YgT2JqZWN0LmVudHJpZXMoXG4gICAgICAgICAgY29udGFpbmVyQ29uZmlnLnNlY3JldHNJbXBvcnRcbiAgICAgICAgKSkge1xuICAgICAgICAgIGNvbnN0IHNlY3JldCA9IFNlY3JldC5mcm9tU2VjcmV0TmFtZVYyKFxuICAgICAgICAgICAgdGhpcyxcbiAgICAgICAgICAgIGAke3NlcnZpY2VOYW1lfSR7Y29udGFpbmVyQ29uZmlnLm5hbWV9JHtrZXl9U2VjcmV0YCxcbiAgICAgICAgICAgIHNlY3JldEltcG9ydC5uYW1lXG4gICAgICAgICAgKTtcbiAgICAgICAgICBzZWNyZXRzW2tleV0gPSBFY3NTZWNyZXQuZnJvbVNlY3JldHNNYW5hZ2VyKFxuICAgICAgICAgICAgc2VjcmV0LFxuICAgICAgICAgICAgc2VjcmV0SW1wb3J0LmZpZWxkXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjb25zdCBjb250YWluZXIgPSB0YXNrRGVmaW5pdGlvbi5hZGRDb250YWluZXIoXG4gICAgICAgIGAke3NlcnZpY2VOYW1lfSR7Y29udGFpbmVyQ29uZmlnLm5hbWV9YCxcbiAgICAgICAge1xuICAgICAgICAgIGltYWdlLFxuICAgICAgICAgIGNvbnRhaW5lck5hbWU6IGNvbnRhaW5lckNvbmZpZy5uYW1lLFxuICAgICAgICAgIGxvZ2dpbmc6IG5ldyBBd3NMb2dEcml2ZXIoe1xuICAgICAgICAgICAgc3RyZWFtUHJlZml4OiBgL2Vjcy8ke3RoaXMucHJvcHMuY2x1c3Rlck5hbWV9LyR7c2VydmljZU5hbWV9LyR7Y29udGFpbmVyQ29uZmlnLm5hbWV9YCxcbiAgICAgICAgICAgIGxvZ1JldGVudGlvbjogMTRcbiAgICAgICAgICB9KSxcbiAgICAgICAgICBlbnZpcm9ubWVudDogY29udGFpbmVyQ29uZmlnLmVudmlyb25tZW50LFxuICAgICAgICAgIHNlY3JldHMsXG4gICAgICAgICAgY29tbWFuZDogY29udGFpbmVyQ29uZmlnLmNvbW1hbmQsXG4gICAgICAgICAgZW50cnlQb2ludDogY29udGFpbmVyQ29uZmlnLmVudHJ5UG9pbnQsXG4gICAgICAgICAgZXNzZW50aWFsOiBjb250YWluZXJDb25maWcuZXNzZW50aWFsID8/IHRydWUsXG4gICAgICAgICAgaGVhbHRoQ2hlY2s6IGNvbnRhaW5lckNvbmZpZy5oZWFsdGhDaGVja1xuICAgICAgICAgICAgPyB7XG4gICAgICAgICAgICAgICAgY29tbWFuZDogY29udGFpbmVyQ29uZmlnLmhlYWx0aENoZWNrLmNvbW1hbmQsXG4gICAgICAgICAgICAgICAgaW50ZXJ2YWw6IGNvbnRhaW5lckNvbmZpZy5oZWFsdGhDaGVjay5pbnRlcnZhbFxuICAgICAgICAgICAgICAgICAgPyBEdXJhdGlvbi5zZWNvbmRzKGNvbnRhaW5lckNvbmZpZy5oZWFsdGhDaGVjay5pbnRlcnZhbClcbiAgICAgICAgICAgICAgICAgIDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgIHRpbWVvdXQ6IGNvbnRhaW5lckNvbmZpZy5oZWFsdGhDaGVjay50aW1lb3V0XG4gICAgICAgICAgICAgICAgICA/IER1cmF0aW9uLnNlY29uZHMoY29udGFpbmVyQ29uZmlnLmhlYWx0aENoZWNrLnRpbWVvdXQpXG4gICAgICAgICAgICAgICAgICA6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgICByZXRyaWVzOiBjb250YWluZXJDb25maWcuaGVhbHRoQ2hlY2sucmV0cmllcyxcbiAgICAgICAgICAgICAgICBzdGFydFBlcmlvZDogY29udGFpbmVyQ29uZmlnLmhlYWx0aENoZWNrLnN0YXJ0UGVyaW9kXG4gICAgICAgICAgICAgICAgICA/IER1cmF0aW9uLnNlY29uZHMoY29udGFpbmVyQ29uZmlnLmhlYWx0aENoZWNrLnN0YXJ0UGVyaW9kKVxuICAgICAgICAgICAgICAgICAgOiB1bmRlZmluZWRcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgOiB1bmRlZmluZWQsXG4gICAgICAgICAgLi4uKHRoaXMuaXNFYzIoKSAmJiB7XG4gICAgICAgICAgICBtZW1vcnlMaW1pdE1pQjogdGhpcy5wcm9wcy5lYzJDb25maWc/Lm1lbW9yeUxpbWl0TWlCIHx8IDEwMjRcbiAgICAgICAgICB9KVxuICAgICAgICB9XG4gICAgICApO1xuXG4gICAgICBpZiAoY29udGFpbmVyQ29uZmlnLnBvcnQpIHtcbiAgICAgICAgY29udGFpbmVyLmFkZFBvcnRNYXBwaW5ncyh7XG4gICAgICAgICAgY29udGFpbmVyUG9ydDogY29udGFpbmVyQ29uZmlnLnBvcnRcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChpc0ZpcnN0V2l0aFBvcnQpIHtcbiAgICAgICAgcHJpbWFyeUNvbnRhaW5lciA9IGNvbnRhaW5lcjtcbiAgICAgIH1cblxuICAgICAgY29udGFpbmVycy5wdXNoKGNvbnRhaW5lcik7XG4gICAgfVxuXG4gICAgcmV0dXJuIHsgY29udGFpbmVycywgcHJpbWFyeUNvbnRhaW5lciB9O1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRDb250YWluZXJJbWFnZShcbiAgICBzZXJ2aWNlTmFtZTogc3RyaW5nLFxuICAgIGNvbnRhaW5lckNvbmZpZzogRWNzQ2x1c3RlckNvbnRhaW5lckNvbmZpZyxcbiAgICBzZXJ2aWNlUHJvcHM6IEVjc1NlcnZpY2VQcm9wc1xuICApOiBDb250YWluZXJJbWFnZSB7XG4gICAgLy8gUHJpb3JpdHk6IGNvbnRhaW5lci5pbWFnZSA+IHNlcnZpY2UuaW1hZ2UgPiBjbHVzdGVyIGRlZmF1bHRcbiAgICBjb25zdCBpbWFnZVNvdXJjZSA9XG4gICAgICBjb250YWluZXJDb25maWcuaW1hZ2UgfHwgc2VydmljZVByb3BzLmltYWdlIHx8IHRoaXMucHJvcHMuZWNyUmVwb3NpdG9yeTtcblxuICAgIGlmICghaW1hZ2VTb3VyY2UpIHtcbiAgICAgIHJldHVybiBDb250YWluZXJJbWFnZS5mcm9tUmVnaXN0cnkoXCJhbWF6b24vYW1hem9uLWVjcy1zYW1wbGVcIik7XG4gICAgfVxuXG4gICAgY29uc3QgaW1hZ2VUYWcgPSBgJHtzZXJ2aWNlTmFtZX0tbGF0ZXN0YDtcblxuICAgIGlmICh0eXBlb2YgaW1hZ2VTb3VyY2UgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIC8vIENoZWNrIGlmIGl0J3MgYW4gRUNSIHJlcG9zaXRvcnkgbmFtZSBvciBhIHB1YmxpYyBpbWFnZVxuICAgICAgaWYgKGltYWdlU291cmNlLmluY2x1ZGVzKFwiL1wiKSAmJiAhaW1hZ2VTb3VyY2UuaW5jbHVkZXMoXCIuXCIpKSB7XG4gICAgICAgIHJldHVybiBDb250YWluZXJJbWFnZS5mcm9tUmVnaXN0cnkoaW1hZ2VTb3VyY2UpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIENvbnRhaW5lckltYWdlLmZyb21FY3JSZXBvc2l0b3J5KFxuICAgICAgICBSZXBvc2l0b3J5LmZyb21SZXBvc2l0b3J5TmFtZShcbiAgICAgICAgICB0aGlzLFxuICAgICAgICAgIGAke3NlcnZpY2VOYW1lfSR7Y29udGFpbmVyQ29uZmlnLm5hbWV9RWNyUmVwb2AsXG4gICAgICAgICAgaW1hZ2VTb3VyY2VcbiAgICAgICAgKSxcbiAgICAgICAgaW1hZ2VUYWdcbiAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKGltYWdlU291cmNlIGluc3RhbmNlb2YgUmVwb3NpdG9yeSkge1xuICAgICAgcmV0dXJuIENvbnRhaW5lckltYWdlLmZyb21FY3JSZXBvc2l0b3J5KGltYWdlU291cmNlLCBpbWFnZVRhZyk7XG4gICAgfVxuXG4gICAgLy8gUmVwb3NpdG9yeUltYWdlIGV4dGVuZHMgQ29udGFpbmVySW1hZ2UsIHNvIHRoaXMgaXMgYSBzYWZlIHVwY2FzdFxuICAgIHJldHVybiBpbWFnZVNvdXJjZSBhcyBDb250YWluZXJJbWFnZTtcbiAgfVxuXG4gIHByaXZhdGUgY3JlYXRlU2VydmljZShcbiAgICBzZXJ2aWNlTmFtZTogc3RyaW5nLFxuICAgIHNlcnZpY2VQcm9wczogRWNzU2VydmljZVByb3BzLFxuICAgIHRhc2tEZWZpbml0aW9uOiBGYXJnYXRlVGFza0RlZmluaXRpb24gfCBFYzJUYXNrRGVmaW5pdGlvblxuICApOiBGYXJnYXRlU2VydmljZSB8IEVjMlNlcnZpY2Uge1xuICAgIGNvbnN0IGRlc2lyZWRDb3VudCA9IHNlcnZpY2VQcm9wcy5kZXNpcmVkQ291bnQgPz8gMjtcblxuICAgIGlmICh0aGlzLmlzRmFyZ2F0ZSgpKSB7XG4gICAgICBjb25zdCBzZXJ2aWNlID0gbmV3IEZhcmdhdGVTZXJ2aWNlKHRoaXMsIGAke3NlcnZpY2VOYW1lfVNlcnZpY2VgLCB7XG4gICAgICAgIGNsdXN0ZXI6IHRoaXMuY2x1c3RlcixcbiAgICAgICAgdGFza0RlZmluaXRpb246IHRhc2tEZWZpbml0aW9uIGFzIEZhcmdhdGVUYXNrRGVmaW5pdGlvbixcbiAgICAgICAgZGVzaXJlZENvdW50LFxuICAgICAgICBzZXJ2aWNlTmFtZSxcbiAgICAgICAgY2FwYWNpdHlQcm92aWRlclN0cmF0ZWdpZXM6IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBjYXBhY2l0eVByb3ZpZGVyOiB0aGlzLmNhcGFjaXR5UHJvdmlkZXIsXG4gICAgICAgICAgICB3ZWlnaHQ6IDFcbiAgICAgICAgICB9XG4gICAgICAgIF0sXG4gICAgICAgIHByb3BhZ2F0ZVRhZ3M6IFByb3BhZ2F0ZWRUYWdTb3VyY2UuU0VSVklDRSxcbiAgICAgICAgY2lyY3VpdEJyZWFrZXI6IHsgZW5hYmxlOiB0cnVlLCByb2xsYmFjazogdHJ1ZSB9LFxuICAgICAgICBlbmFibGVFQ1NNYW5hZ2VkVGFnczogdHJ1ZSxcbiAgICAgICAgZW5hYmxlRXhlY3V0ZUNvbW1hbmQ6IHRydWUsXG4gICAgICAgIGhlYWx0aENoZWNrR3JhY2VQZXJpb2Q6IER1cmF0aW9uLnNlY29uZHMoMTIwKSxcbiAgICAgICAgbWluSGVhbHRoeVBlcmNlbnQ6IDEwMCxcbiAgICAgICAgbWF4SGVhbHRoeVBlcmNlbnQ6IDIwMFxuICAgICAgfSk7XG5cbiAgICAgIG5ldyBDZm5PdXRwdXQodGhpcywgYCR7c2VydmljZU5hbWV9U2VydmljZUFybmAsIHtcbiAgICAgICAga2V5OiBgJHtzZXJ2aWNlTmFtZX1TZXJ2aWNlQXJuYCxcbiAgICAgICAgZXhwb3J0TmFtZTogYCR7dGhpcy5wcm9wcy5jbHVzdGVyTmFtZX0ke3NlcnZpY2VOYW1lfVNlcnZpY2VBcm5gLFxuICAgICAgICB2YWx1ZTogc2VydmljZS5zZXJ2aWNlQXJuLFxuICAgICAgICBkZXNjcmlwdGlvbjogYEVDUyBTZXJ2aWNlIEFSTiBmb3IgJHtzZXJ2aWNlTmFtZX1gXG4gICAgICB9KTtcblxuICAgICAgLy8gRmFyZ2F0ZSBzZXJ2aWNlIGRlcGVuZHMgb24gY2FwYWNpdHkgcHJvdmlkZXIgYXNzb2NpYXRpb25zOlxuICAgICAgLy8gLSBDUkVBVEU6IEFzc29jaWF0aW9ucyBjcmVhdGVkIGZpcnN0LCB0aGVuIFNlcnZpY2UgKGNvcnJlY3QgLSBwcm92aWRlcnMgcmVhZHkgYmVmb3JlIHNlcnZpY2UpXG4gICAgICAvLyAtIERFTEVURTogU2VydmljZSBkZWxldGVkIGZpcnN0LCB0aGVuIEFzc29jaWF0aW9ucyAoY29ycmVjdCAtIHNlcnZpY2VzIGdvbmUgYmVmb3JlIGRpc2Fzc29jaWF0aW9uKVxuICAgICAgLy8gVGhpcyBlbnN1cmVzIENsb3VkRm9ybWF0aW9uIGRlbGV0ZXMgYWxsIHNlcnZpY2VzIEJFRk9SRSBhdHRlbXB0aW5nIHRvIHJlbW92ZVxuICAgICAgLy8gdGhlIEZBUkdBVEUvRkFSR0FURV9TUE9UIGNhcGFjaXR5IHByb3ZpZGVyIGFzc29jaWF0aW9ucyBmcm9tIHRoZSBjbHVzdGVyLlxuICAgICAgLy8gU2VlOiBodHRwczovL2dpdGh1Yi5jb20vYXdzL2F3cy1jZGsvaXNzdWVzLzE1MzY2XG4gICAgICBpZiAodGhpcy5mYXJnYXRlQ2FwYWNpdHlQcm92aWRlckFzc29jaWF0aW9ucykge1xuICAgICAgICBzZXJ2aWNlLm5vZGUuYWRkRGVwZW5kZW5jeSh0aGlzLmZhcmdhdGVDYXBhY2l0eVByb3ZpZGVyQXNzb2NpYXRpb25zKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHNlcnZpY2U7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IHNlcnZpY2UgPSBuZXcgRWMyU2VydmljZSh0aGlzLCBgJHtzZXJ2aWNlTmFtZX1TZXJ2aWNlYCwge1xuICAgICAgICBjbHVzdGVyOiB0aGlzLmNsdXN0ZXIsXG4gICAgICAgIHRhc2tEZWZpbml0aW9uOiB0YXNrRGVmaW5pdGlvbiBhcyBFYzJUYXNrRGVmaW5pdGlvbixcbiAgICAgICAgZGVzaXJlZENvdW50LFxuICAgICAgICBzZXJ2aWNlTmFtZSxcbiAgICAgICAgY2FwYWNpdHlQcm92aWRlclN0cmF0ZWdpZXM6IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBjYXBhY2l0eVByb3ZpZGVyOiB0aGlzLmFzZ0NhcGFjaXR5UHJvdmlkZXIhLmNhcGFjaXR5UHJvdmlkZXJOYW1lLFxuICAgICAgICAgICAgd2VpZ2h0OiAxXG4gICAgICAgICAgfVxuICAgICAgICBdLFxuICAgICAgICBwcm9wYWdhdGVUYWdzOiBQcm9wYWdhdGVkVGFnU291cmNlLlNFUlZJQ0UsXG4gICAgICAgIGNpcmN1aXRCcmVha2VyOiB7IGVuYWJsZTogdHJ1ZSwgcm9sbGJhY2s6IHRydWUgfSxcbiAgICAgICAgcGxhY2VtZW50U3RyYXRlZ2llczogW1BsYWNlbWVudFN0cmF0ZWd5LnNwcmVhZEFjcm9zc0luc3RhbmNlcygpXSxcbiAgICAgICAgZW5hYmxlRUNTTWFuYWdlZFRhZ3M6IHRydWUsXG4gICAgICAgIGVuYWJsZUV4ZWN1dGVDb21tYW5kOiB0cnVlLFxuICAgICAgICBoZWFsdGhDaGVja0dyYWNlUGVyaW9kOiBEdXJhdGlvbi5zZWNvbmRzKDEyMCksXG4gICAgICAgIG1pbkhlYWx0aHlQZXJjZW50OiAxMDAsXG4gICAgICAgIG1heEhlYWx0aHlQZXJjZW50OiAyMDBcbiAgICAgIH0pO1xuXG4gICAgICBuZXcgQ2ZuT3V0cHV0KHRoaXMsIGAke3NlcnZpY2VOYW1lfVNlcnZpY2VBcm5gLCB7XG4gICAgICAgIGtleTogYCR7c2VydmljZU5hbWV9U2VydmljZUFybmAsXG4gICAgICAgIGV4cG9ydE5hbWU6IGAke3RoaXMucHJvcHMuY2x1c3Rlck5hbWV9JHtzZXJ2aWNlTmFtZX1TZXJ2aWNlQXJuYCxcbiAgICAgICAgdmFsdWU6IHNlcnZpY2Uuc2VydmljZUFybixcbiAgICAgICAgZGVzY3JpcHRpb246IGBFQ1MgU2VydmljZSBBUk4gZm9yICR7c2VydmljZU5hbWV9YFxuICAgICAgfSk7XG5cbiAgICAgIC8vIFNlcnZpY2UgZGVwZW5kcyBvbiBEcmFpbldhaXRlcjpcbiAgICAgIC8vIC0gQ1JFQVRFOiBEcmFpbldhaXRlciBjcmVhdGVkIGZpcnN0LCB0aGVuIFNlcnZpY2UgKGNvcnJlY3QgLSBpbmZyYSByZWFkeSBiZWZvcmUgc2VydmljZSlcbiAgICAgIC8vIC0gREVMRVRFOiBTZXJ2aWNlIGRlbGV0ZWQgZmlyc3QsIHRoZW4gRHJhaW5XYWl0ZXIgcnVucyAoY29ycmVjdCAtIHNlcnZpY2VzIGdvbmUgYmVmb3JlIGRyYWluKVxuICAgICAgLy8gVGhpcyBlbnN1cmVzIENsb3VkRm9ybWF0aW9uIGRlbGV0ZXMgYWxsIHNlcnZpY2VzIEJFRk9SRSB0aGUgRHJhaW5XYWl0ZXIgTGFtYmRhIHJ1bnMsXG4gICAgICAvLyB3aGljaCB0aGVuIGRpc2Fzc29jaWF0ZXMgdGhlIGNhcGFjaXR5IHByb3ZpZGVyIGJlZm9yZSBpdCdzIGRlbGV0ZWQuXG4gICAgICBpZiAodGhpcy5kcmFpbldhaXRlcikge1xuICAgICAgICBzZXJ2aWNlLm5vZGUuYWRkRGVwZW5kZW5jeSh0aGlzLmRyYWluV2FpdGVyKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHNlcnZpY2U7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSByZWdpc3RlclNlcnZpY2VXaXRoQUxCKFxuICAgIHNlcnZpY2VOYW1lOiBzdHJpbmcsXG4gICAgc2VydmljZVByb3BzOiBFY3NTZXJ2aWNlUHJvcHMsXG4gICAgc2VydmljZTogRmFyZ2F0ZVNlcnZpY2UgfCBFYzJTZXJ2aWNlLFxuICAgIHByaW1hcnlDb250YWluZXI6IENvbnRhaW5lckRlZmluaXRpb25cbiAgKTogSUFwcGxpY2F0aW9uVGFyZ2V0R3JvdXAge1xuICAgIGNvbnN0IGNvbnRhaW5lclBvcnQgPSBwcmltYXJ5Q29udGFpbmVyLmNvbnRhaW5lclBvcnQ7XG4gICAgY29uc3QgaGVhbHRoQ2hlY2tQYXRoID0gc2VydmljZVByb3BzLnJvdXRpbmc/LmhlYWx0aENoZWNrUGF0aCB8fCBcIi9cIjtcblxuICAgIC8vIERldGVybWluZSByb3V0aW5nIGNvbmRpdGlvbnNcbiAgICBjb25zdCBzZXJ2aWNlc1dpdGhQb3J0cyA9IHRoaXMucHJvcHMuc2VydmljZXMuZmlsdGVyKChzKSA9PlxuICAgICAgcy5jb250YWluZXJzLnNvbWUoKGMpID0+IGMucG9ydCAhPT0gdW5kZWZpbmVkKVxuICAgICk7XG4gICAgY29uc3QgaXNTaW5nbGVTZXJ2aWNlID0gc2VydmljZXNXaXRoUG9ydHMubGVuZ3RoID09PSAxO1xuXG4gICAgY29uc3QgaGVhbHRoQ2hlY2tDb25maWcgPSB0aGlzLmlzRWMyKClcbiAgICAgID8ge1xuICAgICAgICAgIGludGVydmFsOiBEdXJhdGlvbi5zZWNvbmRzKDMwKSxcbiAgICAgICAgICBoZWFsdGh5VGhyZXNob2xkQ291bnQ6IDMsXG4gICAgICAgICAgdW5oZWFsdGh5VGhyZXNob2xkQ291bnQ6IDMsXG4gICAgICAgICAgcGF0aDogaGVhbHRoQ2hlY2tQYXRoLFxuICAgICAgICAgIHBvcnQ6IFwidHJhZmZpYy1wb3J0XCIgYXMgY29uc3QsXG4gICAgICAgICAgdGltZW91dDogRHVyYXRpb24uc2Vjb25kcygxNSlcbiAgICAgICAgfVxuICAgICAgOiB7XG4gICAgICAgICAgaW50ZXJ2YWw6IER1cmF0aW9uLnNlY29uZHMoMTIwKSxcbiAgICAgICAgICBwYXRoOiBoZWFsdGhDaGVja1BhdGgsXG4gICAgICAgICAgcG9ydDogYCR7Y29udGFpbmVyUG9ydH1gLFxuICAgICAgICAgIHRpbWVvdXQ6IER1cmF0aW9uLnNlY29uZHMoMTApXG4gICAgICAgIH07XG5cbiAgICBpZiAoaXNTaW5nbGVTZXJ2aWNlKSB7XG4gICAgICAvLyBTaW5nbGUgc2VydmljZSAtIGNyZWF0ZSB0YXJnZXQgZ3JvdXAgd2l0aCBzZXJ2aWNlIGFzIGRlZmF1bHQgdGFyZ2V0XG4gICAgICByZXR1cm4gdGhpcy5sb2FkQmFsYW5jZXJMaXN0ZW5lciEuYWRkVGFyZ2V0cyhcbiAgICAgICAgYCR7c2VydmljZU5hbWV9VGFyZ2V0R3JvdXBgLFxuICAgICAgICB7XG4gICAgICAgICAgdGFyZ2V0czogW1xuICAgICAgICAgICAgc2VydmljZS5sb2FkQmFsYW5jZXJUYXJnZXQoe1xuICAgICAgICAgICAgICBjb250YWluZXJOYW1lOiBwcmltYXJ5Q29udGFpbmVyLmNvbnRhaW5lck5hbWUsXG4gICAgICAgICAgICAgIGNvbnRhaW5lclBvcnRcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgXSxcbiAgICAgICAgICBwb3J0OiBjb250YWluZXJQb3J0LFxuICAgICAgICAgIHByb3RvY29sOiBBcHBsaWNhdGlvblByb3RvY29sLkhUVFAsXG4gICAgICAgICAgaGVhbHRoQ2hlY2s6IGhlYWx0aENoZWNrQ29uZmlnXG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIE11bHRpLXNlcnZpY2UgLSBjcmVhdGUgdGFyZ2V0IGdyb3VwIHdpdGggcm91dGluZyBydWxlc1xuICAgICAgY29uc3QgcHJpb3JpdHkgPSBzZXJ2aWNlUHJvcHMucm91dGluZz8ucHJpb3JpdHkgfHwgdGhpcy5uZXh0UHJpb3JpdHkrKztcblxuICAgICAgY29uc3QgdGFyZ2V0R3JvdXAgPSB0aGlzLmxvYWRCYWxhbmNlckxpc3RlbmVyIS5hZGRUYXJnZXRzKFxuICAgICAgICBgJHtzZXJ2aWNlTmFtZX1UYXJnZXRzYCxcbiAgICAgICAge1xuICAgICAgICAgIHRhcmdldHM6IFtcbiAgICAgICAgICAgIHNlcnZpY2UubG9hZEJhbGFuY2VyVGFyZ2V0KHtcbiAgICAgICAgICAgICAgY29udGFpbmVyTmFtZTogcHJpbWFyeUNvbnRhaW5lci5jb250YWluZXJOYW1lLFxuICAgICAgICAgICAgICBjb250YWluZXJQb3J0XG4gICAgICAgICAgICB9KVxuICAgICAgICAgIF0sXG4gICAgICAgICAgcG9ydDogY29udGFpbmVyUG9ydCxcbiAgICAgICAgICBwcm90b2NvbDogQXBwbGljYXRpb25Qcm90b2NvbC5IVFRQLFxuICAgICAgICAgIGhlYWx0aENoZWNrOiBoZWFsdGhDaGVja0NvbmZpZyxcbiAgICAgICAgICBjb25kaXRpb25zOiB0aGlzLmJ1aWxkUm91dGluZ0NvbmRpdGlvbnMoc2VydmljZVByb3BzKSxcbiAgICAgICAgICBwcmlvcml0eVxuICAgICAgICB9XG4gICAgICApO1xuXG4gICAgICByZXR1cm4gdGFyZ2V0R3JvdXA7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBidWlsZFJvdXRpbmdDb25kaXRpb25zKFxuICAgIHNlcnZpY2VQcm9wczogRWNzU2VydmljZVByb3BzXG4gICk6IExpc3RlbmVyQ29uZGl0aW9uW10ge1xuICAgIGNvbnN0IGNvbmRpdGlvbnM6IExpc3RlbmVyQ29uZGl0aW9uW10gPSBbXTtcblxuICAgIGlmIChzZXJ2aWNlUHJvcHMucm91dGluZz8ucGF0aCkge1xuICAgICAgY29uZGl0aW9ucy5wdXNoKFxuICAgICAgICBMaXN0ZW5lckNvbmRpdGlvbi5wYXRoUGF0dGVybnMoW3NlcnZpY2VQcm9wcy5yb3V0aW5nLnBhdGhdKVxuICAgICAgKTtcbiAgICB9XG4gICAgaWYgKHNlcnZpY2VQcm9wcy5yb3V0aW5nPy5ob3N0KSB7XG4gICAgICBjb25kaXRpb25zLnB1c2goXG4gICAgICAgIExpc3RlbmVyQ29uZGl0aW9uLmhvc3RIZWFkZXJzKFtzZXJ2aWNlUHJvcHMucm91dGluZy5ob3N0XSlcbiAgICAgICk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGNvbmRpdGlvbnM7XG4gIH1cblxuICBwcml2YXRlIGFkZFNlcnZpY2VTY2FsaW5nKFxuICAgIHNlcnZpY2VOYW1lOiBzdHJpbmcsXG4gICAgc2VydmljZVByb3BzOiBFY3NTZXJ2aWNlUHJvcHMsXG4gICAgc2VydmljZTogRmFyZ2F0ZVNlcnZpY2UgfCBFYzJTZXJ2aWNlXG4gICk6IFRhcmdldFRyYWNraW5nU2NhbGluZ1BvbGljeSB7XG4gICAgY29uc3Qgc2NhbGFibGVUYXJnZXQgPSBuZXcgU2NhbGFibGVUYXJnZXQoXG4gICAgICB0aGlzLFxuICAgICAgYCR7c2VydmljZU5hbWV9U2NhbGFibGVUYXJnZXRgLFxuICAgICAge1xuICAgICAgICBzZXJ2aWNlTmFtZXNwYWNlOiBTZXJ2aWNlTmFtZXNwYWNlLkVDUyxcbiAgICAgICAgcmVzb3VyY2VJZDogYHNlcnZpY2UvJHt0aGlzLmNsdXN0ZXIuY2x1c3Rlck5hbWV9LyR7c2VydmljZS5zZXJ2aWNlTmFtZX1gLFxuICAgICAgICBzY2FsYWJsZURpbWVuc2lvbjogXCJlY3M6c2VydmljZTpEZXNpcmVkQ291bnRcIixcbiAgICAgICAgbWluQ2FwYWNpdHk6IHNlcnZpY2VQcm9wcy5taW5DYXBhY2l0eSA/PyAyLFxuICAgICAgICBtYXhDYXBhY2l0eTogc2VydmljZVByb3BzLm1heENhcGFjaXR5ID8/IDEwXG4gICAgICB9XG4gICAgKTtcblxuICAgIHJldHVybiBuZXcgVGFyZ2V0VHJhY2tpbmdTY2FsaW5nUG9saWN5KFxuICAgICAgdGhpcyxcbiAgICAgIGAke3NlcnZpY2VOYW1lfVNjYWxpbmdQb2xpY3lgLFxuICAgICAge1xuICAgICAgICBzY2FsaW5nVGFyZ2V0OiBzY2FsYWJsZVRhcmdldCxcbiAgICAgICAgcHJlZGVmaW5lZE1ldHJpYzpcbiAgICAgICAgICBzZXJ2aWNlUHJvcHMuc2NhbGluZ1R5cGUgPT09IFNjYWxpbmdUeXBlLk1FTU9SWVxuICAgICAgICAgICAgPyBQcmVkZWZpbmVkTWV0cmljLkVDU19TRVJWSUNFX0FWRVJBR0VfTUVNT1JZX1VUSUxJWkFUSU9OXG4gICAgICAgICAgICA6IFByZWRlZmluZWRNZXRyaWMuRUNTX1NFUlZJQ0VfQVZFUkFHRV9DUFVfVVRJTElaQVRJT04sXG4gICAgICAgIHRhcmdldFZhbHVlOiA1MCxcbiAgICAgICAgc2NhbGVJbkNvb2xkb3duOiBEdXJhdGlvbi5zZWNvbmRzKDYwKSxcbiAgICAgICAgc2NhbGVPdXRDb29sZG93bjogRHVyYXRpb24uc2Vjb25kcyg2MClcbiAgICAgIH1cbiAgICApO1xuICB9XG5cbiAgcHJpdmF0ZSBpc0VjMigpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5jYXBhY2l0eVByb3ZpZGVyID09PSBcIkVDMlwiO1xuICB9XG5cbiAgcHJpdmF0ZSBpc0ZhcmdhdGUoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIChcbiAgICAgIHRoaXMuY2FwYWNpdHlQcm92aWRlciA9PT0gXCJGQVJHQVRFXCIgfHxcbiAgICAgIHRoaXMuY2FwYWNpdHlQcm92aWRlciA9PT0gXCJGQVJHQVRFX1NQT1RcIlxuICAgICk7XG4gIH1cblxuICBhZGRDbHVzdGVyKHByb3BzOiBFY3NDbHVzdGVyUHJvcHMpIHtcbiAgICB0aGlzLmNsdXN0ZXIgPSBuZXcgQ2RrQ2x1c3Rlcih0aGlzLCBgJHtwcm9wcy5jbHVzdGVyTmFtZX1gLCB7XG4gICAgICB2cGM6IHByb3BzLnZwYyxcbiAgICAgIGNsdXN0ZXJOYW1lOiBwcm9wcy5jbHVzdGVyTmFtZSxcbiAgICAgIGNvbnRhaW5lckluc2lnaHRzVjI6IENvbnRhaW5lckluc2lnaHRzLkVOQUJMRUQsXG4gICAgICBlbmFibGVGYXJnYXRlQ2FwYWNpdHlQcm92aWRlcnM6IHRoaXMuaXNGYXJnYXRlKClcbiAgICB9KTtcblxuICAgIC8vIEZvciBGYXJnYXRlIGNsdXN0ZXJzLCBmaW5kIHRoZSBpbnRlcm5hbCBDZm5DbHVzdGVyQ2FwYWNpdHlQcm92aWRlckFzc29jaWF0aW9uc1xuICAgIC8vIHRoYXQgQ0RLIGNyZWF0ZXMgd2hlbiBlbmFibGVGYXJnYXRlQ2FwYWNpdHlQcm92aWRlcnMgaXMgdHJ1ZS5cbiAgICAvLyBXZSBuZWVkIHRoaXMgcmVmZXJlbmNlIHRvIGVzdGFibGlzaCBwcm9wZXIgZGVsZXRpb24gZGVwZW5kZW5jaWVzLlxuICAgIGlmICh0aGlzLmlzRmFyZ2F0ZSgpKSB7XG4gICAgICAvLyBDREsgY3JlYXRlcyB0aGlzIGFzIGEgY2hpbGQgb2YgdGhlIGNsdXN0ZXIgd2l0aCBhIHNwZWNpZmljIG5hbWluZyBwYXR0ZXJuXG4gICAgICBjb25zdCBjaGlsZHJlbiA9IHRoaXMuY2x1c3Rlci5ub2RlLmNoaWxkcmVuO1xuICAgICAgZm9yIChjb25zdCBjaGlsZCBvZiBjaGlsZHJlbikge1xuICAgICAgICBpZiAoY2hpbGQgaW5zdGFuY2VvZiBDZm5DbHVzdGVyQ2FwYWNpdHlQcm92aWRlckFzc29jaWF0aW9ucykge1xuICAgICAgICAgIHRoaXMuZmFyZ2F0ZUNhcGFjaXR5UHJvdmlkZXJBc3NvY2lhdGlvbnMgPSBjaGlsZDtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIG5ldyBDZm5PdXRwdXQodGhpcywgYCR7cHJvcHMuY2x1c3Rlck5hbWV9RGVwbG95YWJsZUNsdXN0ZXJgLCB7XG4gICAgICBrZXk6IGAke3Byb3BzLmNsdXN0ZXJOYW1lfURlcGxveWFibGVDbHVzdGVyYCxcbiAgICAgIGV4cG9ydE5hbWU6IGAke3Byb3BzLmNsdXN0ZXJOYW1lfURlcGxveWFibGVDbHVzdGVyYCxcbiAgICAgIHZhbHVlOiB0aGlzLmNsdXN0ZXIuY2x1c3RlckFyblxuICAgIH0pO1xuXG4gICAgbmV3IENmbk91dHB1dCh0aGlzLCBgJHtwcm9wcy5jbHVzdGVyTmFtZX1DbHVzdGVyQXJuYCwge1xuICAgICAga2V5OiBcIkNsdXN0ZXJBcm5cIixcbiAgICAgIGV4cG9ydE5hbWU6IGAke3Byb3BzLmNsdXN0ZXJOYW1lfUNsdXN0ZXJBcm5gLFxuICAgICAgdmFsdWU6IHRoaXMuY2x1c3Rlci5jbHVzdGVyQXJuLFxuICAgICAgZGVzY3JpcHRpb246IGBFQ1MgQ2x1c3RlciBBUk4gZm9yICR7cHJvcHMuY2x1c3Rlck5hbWV9YFxuICAgIH0pO1xuICB9XG5cbiAgYWRkQXV0b1NjYWxpbmdHcm91cChwcm9wczogRWNzQ2x1c3RlclByb3BzKSB7XG4gICAgY29uc3QgZWMyQ29uZmlnID0gcHJvcHMuZWMyQ29uZmlnIHx8IHt9O1xuICAgIGNvbnN0IGluc3RhbmNlVHlwZSA9IGVjMkNvbmZpZy5pbnN0YW5jZVR5cGUgfHwgXCJ0My5taWNyb1wiO1xuICAgIGNvbnN0IGFtaUhhcmR3YXJlVHlwZSA9XG4gICAgICBlYzJDb25maWcuYW1pSGFyZHdhcmVUeXBlID09PSBcIlNUQU5EQVJEXCJcbiAgICAgICAgPyBBbWlIYXJkd2FyZVR5cGUuU1RBTkRBUkRcbiAgICAgICAgOiBBbWlIYXJkd2FyZVR5cGUuQVJNO1xuICAgIGNvbnN0IG1pbkNhcGFjaXR5ID0gZWMyQ29uZmlnLm1pbkNhcGFjaXR5ID8/IDI7XG4gICAgY29uc3QgbWF4Q2FwYWNpdHkgPSBlYzJDb25maWcubWF4Q2FwYWNpdHkgPz8gMztcblxuICAgIHRoaXMuYXNnU2VjdXJpdHlHcm91cCA9IG5ldyBTZWN1cml0eUdyb3VwKHRoaXMsIGBBc2dTZWN1cml0eUdyb3VwYCwge1xuICAgICAgdnBjOiB0aGlzLmNsdXN0ZXIudnBjLFxuICAgICAgZGVzY3JpcHRpb246IGBTZWN1cml0eSBncm91cCBmb3IgdGhlICR7cHJvcHMuY2x1c3Rlck5hbWV9IGF1dG8gc2NhbGluZyBncm91cGBcbiAgICB9KTtcblxuICAgIC8vIE9wZW4gY29udGFpbmVyIHBvcnRzIGZvciBkaXJlY3QgRUMyIGFjY2Vzc1xuICAgIGlmICh0aGlzLmRpcmVjdEFjY2Vzc0VuYWJsZWQpIHtcbiAgICAgIGZvciAoY29uc3Qgc2VydmljZSBvZiBwcm9wcy5zZXJ2aWNlcykge1xuICAgICAgICBmb3IgKGNvbnN0IGNvbnRhaW5lciBvZiBzZXJ2aWNlLmNvbnRhaW5lcnMpIHtcbiAgICAgICAgICBpZiAoY29udGFpbmVyLnBvcnQpIHtcbiAgICAgICAgICAgIHRoaXMuYXNnU2VjdXJpdHlHcm91cC5hZGRJbmdyZXNzUnVsZShcbiAgICAgICAgICAgICAgUGVlci5hbnlJcHY0KCksXG4gICAgICAgICAgICAgIFBvcnQudGNwKGNvbnRhaW5lci5wb3J0KSxcbiAgICAgICAgICAgICAgYERpcmVjdCBhY2Nlc3MgdG8gY29udGFpbmVyIHBvcnQgJHtjb250YWluZXIucG9ydH1gXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHRoaXMuYXV0b1NjYWxpbmdHcm91cCA9IG5ldyBBdXRvU2NhbGluZ0dyb3VwKHRoaXMsIFwiQXV0b1NjYWxpbmdHcm91cFwiLCB7XG4gICAgICBhdXRvU2NhbGluZ0dyb3VwTmFtZTogYCR7cHJvcHMuY2x1c3Rlck5hbWV9QXV0b1NjYWxpbmdHcm91cGAsXG4gICAgICB2cGM6IHRoaXMuY2x1c3Rlci52cGMsXG4gICAgICB2cGNTdWJuZXRzOiB7XG4gICAgICAgIHN1Ym5ldFR5cGU6IFN1Ym5ldFR5cGUuUFVCTElDXG4gICAgICB9LFxuICAgICAgc2VjdXJpdHlHcm91cDogdGhpcy5hc2dTZWN1cml0eUdyb3VwLFxuICAgICAgbWluQ2FwYWNpdHksXG4gICAgICBtYXhDYXBhY2l0eSxcbiAgICAgIGluc3RhbmNlVHlwZTogbmV3IEluc3RhbmNlVHlwZShpbnN0YW5jZVR5cGUpLFxuICAgICAgY2FwYWNpdHlSZWJhbGFuY2U6IHRydWUsXG4gICAgICBpbnN0YW5jZU1vbml0b3Jpbmc6IE1vbml0b3JpbmcuQkFTSUMsXG4gICAgICBtYWNoaW5lSW1hZ2U6IEVjc09wdGltaXplZEltYWdlLmFtYXpvbkxpbnV4MihhbWlIYXJkd2FyZVR5cGUpXG4gICAgfSk7XG5cbiAgICB0aGlzLmFzZ0NhcGFjaXR5UHJvdmlkZXIgPSBuZXcgQXNnQ2FwYWNpdHlQcm92aWRlcihcbiAgICAgIHRoaXMsXG4gICAgICBcIkFzZ0NhcGFjaXR5UHJvdmlkZXJcIixcbiAgICAgIHtcbiAgICAgICAgYXV0b1NjYWxpbmdHcm91cDogdGhpcy5hdXRvU2NhbGluZ0dyb3VwLFxuICAgICAgICBlbmFibGVNYW5hZ2VkRHJhaW5pbmc6IHRydWUsXG4gICAgICAgIGVuYWJsZU1hbmFnZWRUZXJtaW5hdGlvblByb3RlY3Rpb246IGZhbHNlXG4gICAgICB9XG4gICAgKTtcblxuICAgIHRoaXMuY2x1c3Rlci5hZGRBc2dDYXBhY2l0eVByb3ZpZGVyKHRoaXMuYXNnQ2FwYWNpdHlQcm92aWRlcik7XG5cbiAgICAvLyBDcmVhdGUgZHJhaW4gd2FpdGVyIGN1c3RvbSByZXNvdXJjZSB0aGF0IGhhbmRsZXMgY2FwYWNpdHkgcHJvdmlkZXIgY2xlYW51cCBkdXJpbmcgZGVsZXRpb24uXG4gICAgLy8gVGhpcyByZXNvdXJjZSB3YWl0cyBmb3IgRUNTIHNlcnZpY2VzIHRvIGRyYWluLCB0aGVuIGRpc2Fzc29jaWF0ZXMgdGhlIGNhcGFjaXR5IHByb3ZpZGVyXG4gICAgLy8gZnJvbSB0aGUgY2x1c3RlciBiZWZvcmUgQ2xvdWRGb3JtYXRpb24gYXR0ZW1wdHMgdG8gZGVsZXRlIHRoZSBBc2dDYXBhY2l0eVByb3ZpZGVyLlxuICAgIC8vXG4gICAgLy8gRGVwZW5kZW5jeSBjaGFpbiBmb3IgREVMRVRFIG9yZGVyOlxuICAgIC8vICAgU2VydmljZXMgZGVsZXRlZCDihpIgRHJhaW5XYWl0ZXIgcnVucyDihpIgQXNnQ2FwYWNpdHlQcm92aWRlciBkZWxldGVkIOKGkiBDbHVzdGVyIGRlbGV0ZWRcbiAgICAvL1xuICAgIC8vIFRoZSBkcmFpbiB3YWl0ZXIgbXVzdCBkZXBlbmQgb24gQXNnQ2FwYWNpdHlQcm92aWRlciBzbyBpdCBydW5zIEJFRk9SRSB0aGUgcHJvdmlkZXIgaXMgZGVsZXRlZC5cbiAgICAvLyBTZXJ2aWNlcyBtdXN0IGRlcGVuZCBvbiB0aGUgZHJhaW4gd2FpdGVyIHNvIHRoZXkncmUgZGVsZXRlZCBCRUZPUkUgdGhlIGRyYWluIHdhaXRlciBydW5zLlxuICAgIHRoaXMuZHJhaW5XYWl0ZXIgPSBuZXcgQ2FwYWNpdHlQcm92aWRlckRyYWluV2FpdGVyKFxuICAgICAgdGhpcyxcbiAgICAgIFwiQ2FwYWNpdHlQcm92aWRlckRyYWluV2FpdGVyXCIsXG4gICAgICB7XG4gICAgICAgIGNsdXN0ZXJOYW1lOiBwcm9wcy5jbHVzdGVyTmFtZSxcbiAgICAgICAgY2FwYWNpdHlQcm92aWRlck5hbWU6IHRoaXMuYXNnQ2FwYWNpdHlQcm92aWRlci5jYXBhY2l0eVByb3ZpZGVyTmFtZVxuICAgICAgfVxuICAgICk7XG5cbiAgICAvLyBEcmFpbldhaXRlciBkZXBlbmRzIG9uIEFzZ0NhcGFjaXR5UHJvdmlkZXI6XG4gICAgLy8gLSBDUkVBVEU6IEFzZ0NhcGFjaXR5UHJvdmlkZXIgY3JlYXRlZCBmaXJzdCwgdGhlbiBEcmFpbldhaXRlclxuICAgIC8vIC0gREVMRVRFOiBEcmFpbldhaXRlciBkZWxldGVkIGZpcnN0IChydW5zIExhbWJkYSksIHRoZW4gQXNnQ2FwYWNpdHlQcm92aWRlclxuICAgIHRoaXMuZHJhaW5XYWl0ZXIubm9kZS5hZGREZXBlbmRlbmN5KHRoaXMuYXNnQ2FwYWNpdHlQcm92aWRlcik7XG4gIH1cblxuICBhZGRMb2FkQmFsYW5jZXIocHJvcHM6IEVjc0NsdXN0ZXJQcm9wcykge1xuICAgIGNvbnN0IGRlZmF1bHRMb2FkQmFsYW5jZXJOYW1lID0gYCR7cHJvcHMuY2x1c3Rlck5hbWV9TG9hZEJhbGFuY2VyYDtcbiAgICBjb25zdCBzdXBwb3J0ZWROYW1lTGVuZ3RoID0gMzI7XG5cbiAgICBsZXQgdHJ1bmNhdGVkTG9hZEJhbGFuY2VyTmFtZSA9XG4gICAgICBkZWZhdWx0TG9hZEJhbGFuY2VyTmFtZS5sZW5ndGggPiBzdXBwb3J0ZWROYW1lTGVuZ3RoXG4gICAgICAgID8gZGVmYXVsdExvYWRCYWxhbmNlck5hbWUuc3Vic3RyaW5nKDAsIHN1cHBvcnRlZE5hbWVMZW5ndGgpXG4gICAgICAgIDogZGVmYXVsdExvYWRCYWxhbmNlck5hbWU7XG5cbiAgICB0cnVuY2F0ZWRMb2FkQmFsYW5jZXJOYW1lID0gdHJ1bmNhdGVkTG9hZEJhbGFuY2VyTmFtZS5yZXBsYWNlKC8tKyQvLCBcIlwiKTtcblxuICAgIGNvbnN0IGlzSW50ZXJuYWwgPSBwcm9wcy5jbHVzdGVyPy5sb2FkQmFsYW5jZXIgPT09IFwiaW50ZXJuYWxcIjtcblxuICAgIGlmICh0aGlzLmlzRWMyKCkpIHtcbiAgICAgIHRoaXMubG9hZEJhbGFuY2VyU2VjdXJpdHlHcm91cCA9IG5ldyBTZWN1cml0eUdyb3VwKFxuICAgICAgICB0aGlzLFxuICAgICAgICBgTG9hZEJhbGFuY2VyU2VjdXJpdHlHcm91cGAsXG4gICAgICAgIHtcbiAgICAgICAgICB2cGM6IHRoaXMuY2x1c3Rlci52cGMsXG4gICAgICAgICAgZGVzY3JpcHRpb246IGBTZWN1cml0eSBncm91cCBmb3IgdGhlICR7cHJvcHMuY2x1c3Rlck5hbWV9IGxvYWQgYmFsYW5jZXJgXG4gICAgICAgIH1cbiAgICAgICk7XG5cbiAgICAgIHRoaXMubG9hZEJhbGFuY2VyU2VjdXJpdHlHcm91cC5jb25uZWN0aW9ucy5hbGxvd1RvKFxuICAgICAgICB0aGlzLmFzZ1NlY3VyaXR5R3JvdXAhLFxuICAgICAgICBQb3J0LmFsbFRjcCgpXG4gICAgICApO1xuXG4gICAgICB0aGlzLmxvYWRCYWxhbmNlciA9IG5ldyBBcHBsaWNhdGlvbkxvYWRCYWxhbmNlcihcbiAgICAgICAgdGhpcyxcbiAgICAgICAgYCR7cHJvcHMuY2x1c3Rlck5hbWV9TG9hZEJhbGFuY2VyYCxcbiAgICAgICAge1xuICAgICAgICAgIHZwYzogdGhpcy5jbHVzdGVyLnZwYyxcbiAgICAgICAgICBpbnRlcm5ldEZhY2luZzogIWlzSW50ZXJuYWwsXG4gICAgICAgICAgc2VjdXJpdHlHcm91cDogdGhpcy5sb2FkQmFsYW5jZXJTZWN1cml0eUdyb3VwLFxuICAgICAgICAgIGxvYWRCYWxhbmNlck5hbWU6IHRydW5jYXRlZExvYWRCYWxhbmNlck5hbWUsXG4gICAgICAgICAgdnBjU3VibmV0czoge1xuICAgICAgICAgICAgc3VibmV0VHlwZTogaXNJbnRlcm5hbFxuICAgICAgICAgICAgICA/IFN1Ym5ldFR5cGUuUFJJVkFURV9XSVRIX0VHUkVTU1xuICAgICAgICAgICAgICA6IFN1Ym5ldFR5cGUuUFVCTElDXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICApO1xuXG4gICAgICB0aGlzLmFzZ1NlY3VyaXR5R3JvdXAhLmNvbm5lY3Rpb25zLmFsbG93RnJvbShcbiAgICAgICAgdGhpcy5sb2FkQmFsYW5jZXJTZWN1cml0eUdyb3VwLFxuICAgICAgICBQb3J0LnRjcFJhbmdlKDQ5MTUyLCA2NTUzNSlcbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMubG9hZEJhbGFuY2VyID0gbmV3IEFwcGxpY2F0aW9uTG9hZEJhbGFuY2VyKFxuICAgICAgICB0aGlzLFxuICAgICAgICBgJHtwcm9wcy5jbHVzdGVyTmFtZX1Mb2FkQmFsYW5jZXJgLFxuICAgICAgICB7XG4gICAgICAgICAgdnBjOiB0aGlzLmNsdXN0ZXIudnBjLFxuICAgICAgICAgIGludGVybmV0RmFjaW5nOiAhaXNJbnRlcm5hbCxcbiAgICAgICAgICBsb2FkQmFsYW5jZXJOYW1lOiB0cnVuY2F0ZWRMb2FkQmFsYW5jZXJOYW1lLFxuICAgICAgICAgIHZwY1N1Ym5ldHM6IHtcbiAgICAgICAgICAgIHN1Ym5ldFR5cGU6IGlzSW50ZXJuYWxcbiAgICAgICAgICAgICAgPyBTdWJuZXRUeXBlLlBSSVZBVEVfV0lUSF9FR1JFU1NcbiAgICAgICAgICAgICAgOiBTdWJuZXRUeXBlLlBVQkxJQ1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBuZXcgQ2ZuT3V0cHV0KHRoaXMsIGAke3Byb3BzLmNsdXN0ZXJOYW1lfUxvYWRCYWxhbmNlckRuc05hbWVgLCB7XG4gICAgICBrZXk6IGAke3Byb3BzLmNsdXN0ZXJOYW1lfUxvYWRCYWxhbmNlckRuc05hbWVgLFxuICAgICAgZXhwb3J0TmFtZTogYCR7cHJvcHMuY2x1c3Rlck5hbWV9TG9hZEJhbGFuY2VyRG5zTmFtZWAsXG4gICAgICB2YWx1ZTogdGhpcy5sb2FkQmFsYW5jZXIubG9hZEJhbGFuY2VyRG5zTmFtZVxuICAgIH0pO1xuXG4gICAgbmV3IENmbk91dHB1dCh0aGlzLCBgJHtwcm9wcy5jbHVzdGVyTmFtZX1Mb2FkQmFsYW5jZXJVcmxgLCB7XG4gICAgICBrZXk6IFwiTG9hZEJhbGFuY2VyVXJsXCIsXG4gICAgICBleHBvcnROYW1lOiBgJHtwcm9wcy5jbHVzdGVyTmFtZX1Mb2FkQmFsYW5jZXJVcmxgLFxuICAgICAgdmFsdWU6IGBodHRwOi8vJHt0aGlzLmxvYWRCYWxhbmNlci5sb2FkQmFsYW5jZXJEbnNOYW1lfWAsXG4gICAgICBkZXNjcmlwdGlvbjogYExvYWQgQmFsYW5jZXIgVVJMIGZvciAke3Byb3BzLmNsdXN0ZXJOYW1lfWBcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgYWRkRGlyZWN0QWNjZXNzT3V0cHV0cyhwcm9wczogRWNzQ2x1c3RlclByb3BzKSB7XG4gICAgaWYgKCF0aGlzLmRpcmVjdEFjY2Vzc0VuYWJsZWQgfHwgIXRoaXMuYXV0b1NjYWxpbmdHcm91cCkgcmV0dXJuO1xuXG4gICAgLy8gR2V0IHRoZSBmaXJzdCBjb250YWluZXIgcG9ydCAoZm9yIHVzZXIgaW5zdHJ1Y3Rpb25zKVxuICAgIGNvbnN0IGNvbnRhaW5lclBvcnQgPVxuICAgICAgcHJvcHMuc2VydmljZXMuZmxhdE1hcCgocykgPT4gcy5jb250YWluZXJzKS5maW5kKChjKSA9PiBjLnBvcnQpPy5wb3J0IHx8XG4gICAgICAzMDAwO1xuXG4gICAgbmV3IENmbk91dHB1dCh0aGlzLCBgJHtwcm9wcy5jbHVzdGVyTmFtZX1BdXRvU2NhbGluZ0dyb3VwTmFtZWAsIHtcbiAgICAgIGtleTogXCJBdXRvU2NhbGluZ0dyb3VwTmFtZVwiLFxuICAgICAgZXhwb3J0TmFtZTogYCR7cHJvcHMuY2x1c3Rlck5hbWV9QXV0b1NjYWxpbmdHcm91cE5hbWVgLFxuICAgICAgdmFsdWU6IHRoaXMuYXV0b1NjYWxpbmdHcm91cC5hdXRvU2NhbGluZ0dyb3VwTmFtZSxcbiAgICAgIGRlc2NyaXB0aW9uOiBgUnVuOiBhd3MgYXV0b3NjYWxpbmcgZGVzY3JpYmUtYXV0by1zY2FsaW5nLWdyb3VwcyAtLWF1dG8tc2NhbGluZy1ncm91cC1uYW1lcyA8bmFtZT4gdG8gZmluZCBpbnN0YW5jZSBJUGBcbiAgICB9KTtcblxuICAgIG5ldyBDZm5PdXRwdXQodGhpcywgYCR7cHJvcHMuY2x1c3Rlck5hbWV9RGlyZWN0QWNjZXNzUG9ydGAsIHtcbiAgICAgIGtleTogXCJEaXJlY3RBY2Nlc3NQb3J0XCIsXG4gICAgICBleHBvcnROYW1lOiBgJHtwcm9wcy5jbHVzdGVyTmFtZX1EaXJlY3RBY2Nlc3NQb3J0YCxcbiAgICAgIHZhbHVlOiBTdHJpbmcoY29udGFpbmVyUG9ydCksXG4gICAgICBkZXNjcmlwdGlvbjogYEFjY2VzcyB5b3VyIGFwcCBhdCBodHRwOi8vPEVDMi1QVUJMSUMtSVA+OiR7Y29udGFpbmVyUG9ydH1gXG4gICAgfSk7XG4gIH1cblxuICBhZGRMb2FkQmFsYW5jZXJMaXN0ZW5lcihwcm9wczogRWNzQ2x1c3RlclByb3BzKSB7XG4gICAgaWYgKCF0aGlzLmxvYWRCYWxhbmNlcikgcmV0dXJuO1xuXG4gICAgLy8gRGV0ZXJtaW5lIHBvcnQgYmFzZWQgb24gd2hldGhlciBIVFRQUyBpcyBjb25maWd1cmVkIChkb21haW4gKyBjZXJ0KVxuICAgIGNvbnN0IHBvcnQgPSB0aGlzLmNlcnRpZmljYXRlID8gNDQzIDogODA7XG5cbiAgICAvLyBEZWZhdWx0IGFjdGlvbiBmb3IgcmVxdWVzdHMgdGhhdCBkb24ndCBtYXRjaCBhbnkgcm91dGluZyBydWxlXG4gICAgLy8gUmV0dXJucyA0MDQgZm9yIG11bHRpLXNlcnZpY2UgY2x1c3RlcnMgd2l0aCByb3V0aW5nIHJ1bGVzXG4gICAgY29uc3QgZGVmYXVsdEFjdGlvbiA9IExpc3RlbmVyQWN0aW9uLmZpeGVkUmVzcG9uc2UoNDA0LCB7XG4gICAgICBjb250ZW50VHlwZTogXCJ0ZXh0L3BsYWluXCIsXG4gICAgICBtZXNzYWdlQm9keTogXCJOb3QgRm91bmRcIlxuICAgIH0pO1xuXG4gICAgaWYgKHRoaXMuY2VydGlmaWNhdGUpIHtcbiAgICAgIHRoaXMubG9hZEJhbGFuY2VyTGlzdGVuZXIgPSB0aGlzLmxvYWRCYWxhbmNlci5hZGRMaXN0ZW5lcihcbiAgICAgICAgYCR7cHJvcHMuY2x1c3Rlck5hbWV9TGlzdGVuZXJgLFxuICAgICAgICB7XG4gICAgICAgICAgcG9ydCxcbiAgICAgICAgICBjZXJ0aWZpY2F0ZXM6IFt0aGlzLmNlcnRpZmljYXRlXSxcbiAgICAgICAgICBkZWZhdWx0QWN0aW9uXG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMubG9hZEJhbGFuY2VyTGlzdGVuZXIgPSB0aGlzLmxvYWRCYWxhbmNlci5hZGRMaXN0ZW5lcihcbiAgICAgICAgYCR7cHJvcHMuY2x1c3Rlck5hbWV9TGlzdGVuZXJgLFxuICAgICAgICB7XG4gICAgICAgICAgcG9ydCxcbiAgICAgICAgICBkZWZhdWx0QWN0aW9uXG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgYWRkSG9zdGVkWm9uZShwcm9wczogRWNzQ2x1c3RlclByb3BzKSB7XG4gICAgLy8gU3VwcG9ydCBib3RoIG5ldyBjbHVzdGVyLmRvbWFpbiBhbmQgYWR2YW5jZWQgY2x1c3Rlci5kb21haW5Db25maWdcbiAgICBjb25zdCBkb21haW5Db25maWcgPSBwcm9wcy5jbHVzdGVyPy5kb21haW5Db25maWc7XG4gICAgY29uc3Qgc2ltcGxlRG9tYWluID0gcHJvcHMuY2x1c3Rlcj8uZG9tYWluO1xuXG4gICAgaWYgKCFkb21haW5Db25maWcgJiYgIXNpbXBsZURvbWFpbikgcmV0dXJuO1xuXG4gICAgY29uc3QgZG9tYWluTmFtZSA9IGRvbWFpbkNvbmZpZz8uZG9tYWluTmFtZSB8fCBzaW1wbGVEb21haW4hO1xuXG4gICAgaWYgKCFkb21haW5Db25maWc/Lmhvc3RlZFpvbmUpIHtcbiAgICAgIGNvbnN0IGhvc3RlZFpvbmUgPSBuZXcgRmphbGxIb3N0ZWRab25lKFxuICAgICAgICB0aGlzLFxuICAgICAgICBgJHtwcm9wcy5jbHVzdGVyTmFtZX1Ib3N0ZWRab25lYCxcbiAgICAgICAge1xuICAgICAgICAgIHpvbmVOYW1lOiBkb21haW5OYW1lXG4gICAgICAgIH1cbiAgICAgICk7XG5cbiAgICAgIHRoaXMuaG9zdGVkWm9uZSA9IGhvc3RlZFpvbmUuZ2V0SW50ZXJuYWxIb3N0ZWRab25lKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuaG9zdGVkWm9uZSA9IGRvbWFpbkNvbmZpZy5ob3N0ZWRab25lLmdldEludGVybmFsSG9zdGVkWm9uZSgpO1xuICAgIH1cblxuICAgIGlmICghZG9tYWluQ29uZmlnPy5jZXJ0aWZpY2F0ZSkge1xuICAgICAgdGhpcy5jZXJ0aWZpY2F0ZSA9IG5ldyBDZXJ0aWZpY2F0ZShcbiAgICAgICAgdGhpcyxcbiAgICAgICAgYCR7cHJvcHMuY2x1c3Rlck5hbWV9Q2VydGlmaWNhdGVgLFxuICAgICAgICB7XG4gICAgICAgICAgZG9tYWluTmFtZSxcbiAgICAgICAgICB2YWxpZGF0aW9uOiBDZXJ0aWZpY2F0ZVZhbGlkYXRpb24uZnJvbURucyh0aGlzLmhvc3RlZFpvbmUpXG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gSGFuZGxlIGFkdmFuY2VkIHJvdXRpbmcgcG9saWNpZXMgKGxhdGVuY3ksIHdlaWdodGVkLCBnZW8pXG4gICAgaWYgKGRvbWFpbkNvbmZpZykge1xuICAgICAgY29uc3QgbGF0ZW5jeUNvbmZpZyA9IGRvbWFpbkNvbmZpZyBhcyBMYXRlbmN5RG9tYWluQ29uZmlnO1xuICAgICAgY29uc3Qgd2VpZ2h0ZWRDb25maWcgPSBkb21haW5Db25maWcgYXMgV2VpZ2h0ZWREb21haW5Db25maWc7XG4gICAgICBjb25zdCBnZW9Db25maWcgPSBkb21haW5Db25maWcgYXMgR2VvTG9jYXRpb25Eb21haW5Db25maWc7XG5cbiAgICAgIGNvbnN0IGhhc1JvdXRpbmdQb2xpY3k6IGJvb2xlYW4gPVxuICAgICAgICAhIWxhdGVuY3lDb25maWc/LnJlZ2lvbiB8fFxuICAgICAgICB3ZWlnaHRlZENvbmZpZz8ud2VpZ2h0ICE9PSB1bmRlZmluZWQgfHxcbiAgICAgICAgISFnZW9Db25maWc/Lmdlb0xvY2F0aW9uO1xuXG4gICAgICBsZXQgc2V0SWRlbnRpZmllciA9IGRvbWFpbkNvbmZpZy5zZXRJZGVudGlmaWVyO1xuICAgICAgaWYgKGhhc1JvdXRpbmdQb2xpY3kgJiYgIXNldElkZW50aWZpZXIpIHtcbiAgICAgICAgaWYgKGxhdGVuY3lDb25maWc/LnJlZ2lvbikge1xuICAgICAgICAgIHNldElkZW50aWZpZXIgPSBgJHtwcm9wcy5jbHVzdGVyTmFtZX0ke2xhdGVuY3lDb25maWcucmVnaW9ufWA7XG4gICAgICAgIH0gZWxzZSBpZiAod2VpZ2h0ZWRDb25maWc/LndlaWdodCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgc2V0SWRlbnRpZmllciA9IGAke3Byb3BzLmNsdXN0ZXJOYW1lfVdlaWdodCR7d2VpZ2h0ZWRDb25maWcud2VpZ2h0fWA7XG4gICAgICAgIH0gZWxzZSBpZiAoZ2VvQ29uZmlnPy5nZW9Mb2NhdGlvbikge1xuICAgICAgICAgIHNldElkZW50aWZpZXIgPSBgJHtwcm9wcy5jbHVzdGVyTmFtZX1HZW9gO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLmxvYWRCYWxhbmNlcikge1xuICAgICAgICB0aGlzLmFSZWNvcmQgPSBuZXcgQVJlY29yZCh0aGlzLCBgJHtwcm9wcy5jbHVzdGVyTmFtZX1BUmVjb3JkYCwge1xuICAgICAgICAgIHJlY29yZE5hbWU6IGRvbWFpbk5hbWUsXG4gICAgICAgICAgem9uZTogdGhpcy5ob3N0ZWRab25lLFxuICAgICAgICAgIHRhcmdldDogUmVjb3JkVGFyZ2V0LmZyb21BbGlhcyhcbiAgICAgICAgICAgIG5ldyBMb2FkQmFsYW5jZXJUYXJnZXQodGhpcy5sb2FkQmFsYW5jZXIsIHtcbiAgICAgICAgICAgICAgZXZhbHVhdGVUYXJnZXRIZWFsdGg6IGhhc1JvdXRpbmdQb2xpY3lcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgKSxcbiAgICAgICAgICByZWdpb246IGxhdGVuY3lDb25maWc/LnJlZ2lvbixcbiAgICAgICAgICB3ZWlnaHQ6IHdlaWdodGVkQ29uZmlnPy53ZWlnaHQsXG4gICAgICAgICAgZ2VvTG9jYXRpb246IGdlb0NvbmZpZz8uZ2VvTG9jYXRpb24sXG4gICAgICAgICAgc2V0SWRlbnRpZmllcjogc2V0SWRlbnRpZmllclxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKHNpbXBsZURvbWFpbiAmJiB0aGlzLmxvYWRCYWxhbmNlcikge1xuICAgICAgLy8gU2ltcGxlIGRvbWFpbiAtIGp1c3QgY3JlYXRlIEEgcmVjb3JkXG4gICAgICB0aGlzLmFSZWNvcmQgPSBuZXcgQVJlY29yZCh0aGlzLCBgJHtwcm9wcy5jbHVzdGVyTmFtZX1BUmVjb3JkYCwge1xuICAgICAgICByZWNvcmROYW1lOiBkb21haW5OYW1lLFxuICAgICAgICB6b25lOiB0aGlzLmhvc3RlZFpvbmUsXG4gICAgICAgIHRhcmdldDogUmVjb3JkVGFyZ2V0LmZyb21BbGlhcyhcbiAgICAgICAgICBuZXcgTG9hZEJhbGFuY2VyVGFyZ2V0KHRoaXMubG9hZEJhbGFuY2VyKVxuICAgICAgICApXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBzdGF0aWMgYnVpbGQoXG4gICAgaWQ6IHN0cmluZyxcbiAgICBwcm9wczogRWNzQ2x1c3RlclByb3BzXG4gICk6IChzYjogU3RhY2tCdWlsZGVyKSA9PiBDb25zdHJ1Y3Qge1xuICAgIHJldHVybiAoc2I6IFN0YWNrQnVpbGRlcikgPT4ge1xuICAgICAgY29uc3QgbmV3UHJvcHM6IEVjc0NsdXN0ZXJQcm9wcyA9IHtcbiAgICAgICAgLi4ucHJvcHMsXG4gICAgICAgIC4uLntcbiAgICAgICAgICB2cGM6IChzYi5nZXROZXR3b3JrKCkgYXMgSVZwYykgfHwgcHJvcHMudnBjXG4gICAgICAgIH1cbiAgICAgIH07XG4gICAgICByZXR1cm4gbmV3IHRoaXMoc2IuZ2V0U3RhY2soKSwgaWQsIG5ld1Byb3BzKTtcbiAgICB9O1xuICB9XG59XG4iXX0=