@fjall/components-infrastructure 0.77.3 → 0.78.3

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 +747 -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 -468
  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,593 @@ 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
+ // For multi-service deployments, use service-prefixed tags
413
+ const isMultiService = this.props.services.length > 1;
414
+ const imageTag = isMultiService ? `${serviceName}-latest` : "latest";
415
+ if (typeof imageSource === "string") {
416
+ // Check if it's an ECR repository name or a public image
417
+ if (imageSource.includes("/") && !imageSource.includes(".")) {
418
+ return aws_ecs_1.ContainerImage.fromRegistry(imageSource);
419
+ }
420
+ return aws_ecs_1.ContainerImage.fromEcrRepository(aws_ecr_1.Repository.fromRepositoryName(this, `${serviceName}${containerConfig.name}EcrRepo`, imageSource), imageTag);
421
+ }
422
+ if (imageSource instanceof aws_ecr_1.Repository) {
423
+ return aws_ecs_1.ContainerImage.fromEcrRepository(imageSource, imageTag);
424
+ }
425
+ // RepositoryImage extends ContainerImage, so this is a safe upcast
426
+ return imageSource;
427
+ }
428
+ createService(serviceName, serviceProps, taskDefinition) {
429
+ const desiredCount = serviceProps.desiredCount ?? 2;
430
+ if (this.isFargate()) {
431
+ const service = new aws_ecs_1.FargateService(this, `${serviceName}Service`, {
432
+ cluster: this.cluster,
433
+ taskDefinition: taskDefinition,
434
+ desiredCount,
435
+ serviceName,
436
+ capacityProviderStrategies: [
437
+ {
438
+ capacityProvider: this.capacityProvider,
439
+ weight: 1
440
+ }
441
+ ],
442
+ propagateTags: aws_ecs_1.PropagatedTagSource.SERVICE,
443
+ circuitBreaker: { enable: true, rollback: true },
444
+ enableECSManagedTags: true,
445
+ enableExecuteCommand: true,
446
+ healthCheckGracePeriod: aws_cdk_lib_1.Duration.seconds(120),
447
+ minHealthyPercent: 100,
448
+ maxHealthyPercent: 200
449
+ });
450
+ new cfnOutput_1.CfnOutput(this, `${serviceName}ServiceArn`, {
451
+ key: `${serviceName}ServiceArn`,
452
+ exportName: `${this.props.clusterName}${serviceName}ServiceArn`,
453
+ value: service.serviceArn,
454
+ description: `ECS Service ARN for ${serviceName}`
455
+ });
456
+ // Fargate service depends on capacity provider associations:
457
+ // - CREATE: Associations created first, then Service (correct - providers ready before service)
458
+ // - DELETE: Service deleted first, then Associations (correct - services gone before disassociation)
459
+ // This ensures CloudFormation deletes all services BEFORE attempting to remove
460
+ // the FARGATE/FARGATE_SPOT capacity provider associations from the cluster.
461
+ // See: https://github.com/aws/aws-cdk/issues/15366
462
+ if (this.fargateCapacityProviderAssociations) {
463
+ service.node.addDependency(this.fargateCapacityProviderAssociations);
464
+ }
465
+ return service;
466
+ }
467
+ else {
468
+ const service = new aws_ecs_1.Ec2Service(this, `${serviceName}Service`, {
469
+ cluster: this.cluster,
470
+ taskDefinition: taskDefinition,
471
+ desiredCount,
472
+ serviceName,
473
+ capacityProviderStrategies: [
474
+ {
475
+ capacityProvider: this.asgCapacityProvider.capacityProviderName,
476
+ weight: 1
477
+ }
478
+ ],
479
+ propagateTags: aws_ecs_1.PropagatedTagSource.SERVICE,
480
+ circuitBreaker: { enable: true, rollback: true },
481
+ placementStrategies: [aws_ecs_1.PlacementStrategy.spreadAcrossInstances()],
482
+ enableECSManagedTags: true,
483
+ enableExecuteCommand: true,
484
+ healthCheckGracePeriod: aws_cdk_lib_1.Duration.seconds(120),
485
+ minHealthyPercent: 100,
486
+ maxHealthyPercent: 200
487
+ });
488
+ new cfnOutput_1.CfnOutput(this, `${serviceName}ServiceArn`, {
489
+ key: `${serviceName}ServiceArn`,
490
+ exportName: `${this.props.clusterName}${serviceName}ServiceArn`,
491
+ value: service.serviceArn,
492
+ description: `ECS Service ARN for ${serviceName}`
493
+ });
494
+ // Service depends on DrainWaiter:
495
+ // - CREATE: DrainWaiter created first, then Service (correct - infra ready before service)
496
+ // - DELETE: Service deleted first, then DrainWaiter runs (correct - services gone before drain)
497
+ // This ensures CloudFormation deletes all services BEFORE the DrainWaiter Lambda runs,
498
+ // which then disassociates the capacity provider before it's deleted.
499
+ if (this.drainWaiter) {
500
+ service.node.addDependency(this.drainWaiter);
501
+ }
502
+ return service;
503
+ }
504
+ }
505
+ registerServiceWithALB(serviceName, serviceProps, service, primaryContainer) {
506
+ const containerPort = primaryContainer.containerPort;
507
+ const healthCheckPath = serviceProps.routing?.healthCheckPath || "/";
508
+ // Determine routing conditions
509
+ const servicesWithPorts = this.props.services.filter((s) => s.containers.some((c) => c.port !== undefined));
510
+ const isSingleService = servicesWithPorts.length === 1;
511
+ const healthCheckConfig = this.isEc2()
512
+ ? {
513
+ interval: aws_cdk_lib_1.Duration.seconds(30),
514
+ healthyThresholdCount: 3,
515
+ unhealthyThresholdCount: 3,
516
+ path: healthCheckPath,
517
+ port: "traffic-port",
518
+ timeout: aws_cdk_lib_1.Duration.seconds(15)
519
+ }
520
+ : {
521
+ interval: aws_cdk_lib_1.Duration.seconds(120),
522
+ path: healthCheckPath,
523
+ port: `${containerPort}`,
524
+ timeout: aws_cdk_lib_1.Duration.seconds(10)
525
+ };
526
+ if (isSingleService) {
527
+ // Single service - create target group with service as default target
528
+ return this.loadBalancerListener.addTargets(`${serviceName}TargetGroup`, {
529
+ targets: [
530
+ service.loadBalancerTarget({
531
+ containerName: primaryContainer.containerName,
532
+ containerPort
533
+ })
534
+ ],
535
+ port: containerPort,
536
+ protocol: aws_elasticloadbalancingv2_1.ApplicationProtocol.HTTP,
537
+ healthCheck: healthCheckConfig
538
+ });
539
+ }
540
+ else {
541
+ // Multi-service - create target group with routing rules
542
+ const priority = serviceProps.routing?.priority || this.nextPriority++;
543
+ const targetGroup = this.loadBalancerListener.addTargets(`${serviceName}Targets`, {
544
+ targets: [
545
+ service.loadBalancerTarget({
546
+ containerName: primaryContainer.containerName,
547
+ containerPort
548
+ })
549
+ ],
550
+ port: containerPort,
551
+ protocol: aws_elasticloadbalancingv2_1.ApplicationProtocol.HTTP,
552
+ healthCheck: healthCheckConfig,
553
+ conditions: this.buildRoutingConditions(serviceProps),
554
+ priority
555
+ });
556
+ return targetGroup;
557
+ }
558
+ }
559
+ buildRoutingConditions(serviceProps) {
560
+ const conditions = [];
561
+ if (serviceProps.routing?.path) {
562
+ conditions.push(aws_elasticloadbalancingv2_1.ListenerCondition.pathPatterns([serviceProps.routing.path]));
563
+ }
564
+ if (serviceProps.routing?.host) {
565
+ conditions.push(aws_elasticloadbalancingv2_1.ListenerCondition.hostHeaders([serviceProps.routing.host]));
566
+ }
567
+ return conditions;
568
+ }
569
+ addServiceScaling(serviceName, serviceProps, service) {
570
+ const scalableTarget = new aws_applicationautoscaling_1.ScalableTarget(this, `${serviceName}ScalableTarget`, {
571
+ serviceNamespace: aws_applicationautoscaling_1.ServiceNamespace.ECS,
572
+ resourceId: `service/${this.cluster.clusterName}/${service.serviceName}`,
573
+ scalableDimension: "ecs:service:DesiredCount",
574
+ minCapacity: serviceProps.minCapacity ?? 2,
575
+ maxCapacity: serviceProps.maxCapacity ?? 10
50
576
  });
577
+ return new aws_applicationautoscaling_1.TargetTrackingScalingPolicy(this, `${serviceName}ScalingPolicy`, {
578
+ scalingTarget: scalableTarget,
579
+ predefinedMetric: serviceProps.scalingType === ScalingType.MEMORY
580
+ ? aws_applicationautoscaling_1.PredefinedMetric.ECS_SERVICE_AVERAGE_MEMORY_UTILIZATION
581
+ : aws_applicationautoscaling_1.PredefinedMetric.ECS_SERVICE_AVERAGE_CPU_UTILIZATION,
582
+ targetValue: 50,
583
+ scaleInCooldown: aws_cdk_lib_1.Duration.seconds(60),
584
+ scaleOutCooldown: aws_cdk_lib_1.Duration.seconds(60)
585
+ });
586
+ }
587
+ isEc2() {
588
+ return this.capacityProvider === "EC2";
589
+ }
590
+ isFargate() {
591
+ return (this.capacityProvider === "FARGATE" ||
592
+ this.capacityProvider === "FARGATE_SPOT");
51
593
  }
52
594
  addCluster(props) {
53
595
  this.cluster = new aws_ecs_1.Cluster(this, `${props.clusterName}`, {
54
596
  vpc: props.vpc,
55
597
  clusterName: props.clusterName,
56
598
  containerInsightsV2: aws_ecs_1.ContainerInsights.ENABLED,
57
- enableFargateCapacityProviders: true
599
+ enableFargateCapacityProviders: this.isFargate()
58
600
  });
59
- // Output used to auto-detect deployable cluter
601
+ // For Fargate clusters, find the internal CfnClusterCapacityProviderAssociations
602
+ // that CDK creates when enableFargateCapacityProviders is true.
603
+ // We need this reference to establish proper deletion dependencies.
604
+ if (this.isFargate()) {
605
+ // CDK creates this as a child of the cluster with a specific naming pattern
606
+ const children = this.cluster.node.children;
607
+ for (const child of children) {
608
+ if (child instanceof aws_ecs_1.CfnClusterCapacityProviderAssociations) {
609
+ this.fargateCapacityProviderAssociations = child;
610
+ break;
611
+ }
612
+ }
613
+ }
60
614
  new cfnOutput_1.CfnOutput(this, `${props.clusterName}DeployableCluster`, {
61
615
  key: `${props.clusterName}DeployableCluster`,
62
616
  exportName: `${props.clusterName}DeployableCluster`,
63
617
  value: this.cluster.clusterArn
64
618
  });
65
- // Export cluster ARN for monitoring
66
619
  new cfnOutput_1.CfnOutput(this, `${props.clusterName}ClusterArn`, {
67
620
  key: "ClusterArn",
68
621
  exportName: `${props.clusterName}ClusterArn`,
@@ -70,207 +623,110 @@ class FargateCluster extends constructs_1.Construct {
70
623
  description: `ECS Cluster ARN for ${props.clusterName}`
71
624
  });
72
625
  }
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
626
+ addAutoScalingGroup(props) {
627
+ const ec2Config = props.ec2Config || {};
628
+ const instanceType = ec2Config.instanceType || "t3.micro";
629
+ const amiHardwareType = ec2Config.amiHardwareType === "STANDARD"
630
+ ? aws_ecs_1.AmiHardwareType.STANDARD
631
+ : aws_ecs_1.AmiHardwareType.ARM;
632
+ const minCapacity = ec2Config.minCapacity ?? 2;
633
+ const maxCapacity = ec2Config.maxCapacity ?? 3;
634
+ this.asgSecurityGroup = new securityGroup_1.SecurityGroup(this, `AsgSecurityGroup`, {
635
+ vpc: this.cluster.vpc,
636
+ description: `Security group for the ${props.clusterName} auto scaling group`
157
637
  });
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
- ]
638
+ // Open container ports for direct EC2 access
639
+ if (this.directAccessEnabled) {
640
+ for (const service of props.services) {
641
+ for (const container of service.containers) {
642
+ if (container.port) {
643
+ this.asgSecurityGroup.addIngressRule(aws_ec2_1.Peer.anyIpv4(), aws_ec2_1.Port.tcp(container.port), `Direct access to container port ${container.port}`);
644
+ }
645
+ }
646
+ }
647
+ }
648
+ this.autoScalingGroup = new aws_autoscaling_1.AutoScalingGroup(this, "AutoScalingGroup", {
649
+ autoScalingGroupName: `${props.clusterName}AutoScalingGroup`,
650
+ vpc: this.cluster.vpc,
651
+ vpcSubnets: {
652
+ subnetType: aws_ec2_1.SubnetType.PUBLIC
179
653
  },
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
654
+ securityGroup: this.asgSecurityGroup,
655
+ minCapacity,
656
+ maxCapacity,
657
+ instanceType: new aws_ec2_1.InstanceType(instanceType),
658
+ capacityRebalance: true,
659
+ instanceMonitoring: aws_autoscaling_1.Monitoring.BASIC,
660
+ machineImage: aws_ecs_1.EcsOptimizedImage.amazonLinux2(amiHardwareType)
201
661
  });
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
662
+ this.asgCapacityProvider = new aws_ecs_1.AsgCapacityProvider(this, "AsgCapacityProvider", {
663
+ autoScalingGroup: this.autoScalingGroup,
664
+ enableManagedDraining: true,
665
+ enableManagedTerminationProtection: false
232
666
  });
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
- })
667
+ this.cluster.addAsgCapacityProvider(this.asgCapacityProvider);
668
+ // Create drain waiter custom resource that handles capacity provider cleanup during deletion.
669
+ // This resource waits for ECS services to drain, then disassociates the capacity provider
670
+ // from the cluster before CloudFormation attempts to delete the AsgCapacityProvider.
671
+ //
672
+ // Dependency chain for DELETE order:
673
+ // Services deleted → DrainWaiter runs → AsgCapacityProvider deleted → Cluster deleted
674
+ //
675
+ // The drain waiter must depend on AsgCapacityProvider so it runs BEFORE the provider is deleted.
676
+ // Services must depend on the drain waiter so they're deleted BEFORE the drain waiter runs.
677
+ this.drainWaiter = new capacityProviderDrainWaiter_1.CapacityProviderDrainWaiter(this, "CapacityProviderDrainWaiter", {
678
+ clusterName: props.clusterName,
679
+ capacityProviderName: this.asgCapacityProvider.capacityProviderName
249
680
  });
681
+ // DrainWaiter depends on AsgCapacityProvider:
682
+ // - CREATE: AsgCapacityProvider created first, then DrainWaiter
683
+ // - DELETE: DrainWaiter deleted first (runs Lambda), then AsgCapacityProvider
684
+ this.drainWaiter.node.addDependency(this.asgCapacityProvider);
250
685
  }
251
686
  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`;
687
+ const defaultLoadBalancerName = `${props.clusterName}LoadBalancer`;
254
688
  const supportedNameLength = 32;
255
689
  let truncatedLoadBalancerName = defaultLoadBalancerName.length > supportedNameLength
256
690
  ? defaultLoadBalancerName.substring(0, supportedNameLength)
257
691
  : defaultLoadBalancerName;
258
- // Remove any trailing hyphens that might be introduced by truncation
259
692
  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
- });
693
+ const isInternal = props.cluster?.loadBalancer === "internal";
694
+ if (this.isEc2()) {
695
+ this.loadBalancerSecurityGroup = new securityGroup_1.SecurityGroup(this, `LoadBalancerSecurityGroup`, {
696
+ vpc: this.cluster.vpc,
697
+ description: `Security group for the ${props.clusterName} load balancer`
698
+ });
699
+ this.loadBalancerSecurityGroup.connections.allowTo(this.asgSecurityGroup, aws_ec2_1.Port.allTcp());
700
+ this.loadBalancer = new aws_elasticloadbalancingv2_1.ApplicationLoadBalancer(this, `${props.clusterName}LoadBalancer`, {
701
+ vpc: this.cluster.vpc,
702
+ internetFacing: !isInternal,
703
+ securityGroup: this.loadBalancerSecurityGroup,
704
+ loadBalancerName: truncatedLoadBalancerName,
705
+ vpcSubnets: {
706
+ subnetType: isInternal
707
+ ? aws_ec2_1.SubnetType.PRIVATE_WITH_EGRESS
708
+ : aws_ec2_1.SubnetType.PUBLIC
709
+ }
710
+ });
711
+ this.asgSecurityGroup.connections.allowFrom(this.loadBalancerSecurityGroup, aws_ec2_1.Port.tcpRange(49152, 65535));
712
+ }
713
+ else {
714
+ this.loadBalancer = new aws_elasticloadbalancingv2_1.ApplicationLoadBalancer(this, `${props.clusterName}LoadBalancer`, {
715
+ vpc: this.cluster.vpc,
716
+ internetFacing: !isInternal,
717
+ loadBalancerName: truncatedLoadBalancerName,
718
+ vpcSubnets: {
719
+ subnetType: isInternal
720
+ ? aws_ec2_1.SubnetType.PRIVATE_WITH_EGRESS
721
+ : aws_ec2_1.SubnetType.PUBLIC
722
+ }
723
+ });
724
+ }
268
725
  new cfnOutput_1.CfnOutput(this, `${props.clusterName}LoadBalancerDnsName`, {
269
726
  key: `${props.clusterName}LoadBalancerDnsName`,
270
727
  exportName: `${props.clusterName}LoadBalancerDnsName`,
271
728
  value: this.loadBalancer.loadBalancerDnsName
272
729
  });
273
- // Export load balancer URL for monitoring
274
730
  new cfnOutput_1.CfnOutput(this, `${props.clusterName}LoadBalancerUrl`, {
275
731
  key: "LoadBalancerUrl",
276
732
  exportName: `${props.clusterName}LoadBalancerUrl`,
@@ -278,84 +734,114 @@ class FargateCluster extends constructs_1.Construct {
278
734
  description: `Load Balancer URL for ${props.clusterName}`
279
735
  });
280
736
  }
737
+ addDirectAccessOutputs(props) {
738
+ if (!this.directAccessEnabled || !this.autoScalingGroup)
739
+ return;
740
+ // Get the first container port (for user instructions)
741
+ const containerPort = props.services.flatMap((s) => s.containers).find((c) => c.port)?.port ||
742
+ 3000;
743
+ new cfnOutput_1.CfnOutput(this, `${props.clusterName}AutoScalingGroupName`, {
744
+ key: "AutoScalingGroupName",
745
+ exportName: `${props.clusterName}AutoScalingGroupName`,
746
+ value: this.autoScalingGroup.autoScalingGroupName,
747
+ description: `Run: aws autoscaling describe-auto-scaling-groups --auto-scaling-group-names <name> to find instance IP`
748
+ });
749
+ new cfnOutput_1.CfnOutput(this, `${props.clusterName}DirectAccessPort`, {
750
+ key: "DirectAccessPort",
751
+ exportName: `${props.clusterName}DirectAccessPort`,
752
+ value: String(containerPort),
753
+ description: `Access your app at http://<EC2-PUBLIC-IP>:${containerPort}`
754
+ });
755
+ }
281
756
  addLoadBalancerListener(props) {
757
+ if (!this.loadBalancer)
758
+ return;
759
+ // Determine port based on whether HTTPS is configured (domain + cert)
760
+ const port = this.certificate ? 443 : 80;
761
+ // Default action for requests that don't match any routing rule
762
+ // Returns 404 for multi-service clusters with routing rules
763
+ const defaultAction = aws_elasticloadbalancingv2_1.ListenerAction.fixedResponse(404, {
764
+ contentType: "text/plain",
765
+ messageBody: "Not Found"
766
+ });
282
767
  if (this.certificate) {
283
- this.loadBalancerListener = this.loadBalancer.addListener(`${props.serviceName}Listener`, {
284
- port: props.protocol == Protocol.HTTP ? 80 : 443,
285
- certificates: [this.certificate]
768
+ this.loadBalancerListener = this.loadBalancer.addListener(`${props.clusterName}Listener`, {
769
+ port,
770
+ certificates: [this.certificate],
771
+ defaultAction
286
772
  });
287
773
  }
288
774
  else {
289
- this.loadBalancerListener = this.loadBalancer.addListener(`${props.serviceName}Listener`, {
290
- port: props.protocol == Protocol.HTTP ? 80 : 443
775
+ this.loadBalancerListener = this.loadBalancer.addListener(`${props.clusterName}Listener`, {
776
+ port,
777
+ defaultAction
291
778
  });
292
779
  }
293
780
  }
294
781
  addHostedZone(props) {
295
- if (!props.domainConfig)
782
+ // Support both new cluster.domain and advanced cluster.domainConfig
783
+ const domainConfig = props.cluster?.domainConfig;
784
+ const simpleDomain = props.cluster?.domain;
785
+ if (!domainConfig && !simpleDomain)
296
786
  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
787
+ const domainName = domainConfig?.domainName || simpleDomain;
788
+ if (!domainConfig?.hostedZone) {
789
+ const hostedZone = new hostedZone_1.HostedZone(this, `${props.clusterName}HostedZone`, {
790
+ zoneName: domainName
301
791
  });
302
792
  this.hostedZone = hostedZone.getInternalHostedZone();
303
793
  }
304
794
  else {
305
- // Otherwise use the provided hosted zone
306
- this.hostedZone = props.domainConfig.hostedZone.getInternalHostedZone();
795
+ this.hostedZone = domainConfig.hostedZone.getInternalHostedZone();
307
796
  }
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,
797
+ if (!domainConfig?.certificate) {
798
+ this.certificate = new aws_certificatemanager_1.Certificate(this, `${props.clusterName}Certificate`, {
799
+ domainName,
312
800
  validation: aws_certificatemanager_1.CertificateValidation.fromDns(this.hostedZone)
313
801
  });
314
802
  }
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}`;
803
+ // Handle advanced routing policies (latency, weighted, geo)
804
+ if (domainConfig) {
805
+ const latencyConfig = domainConfig;
806
+ const weightedConfig = domainConfig;
807
+ const geoConfig = domainConfig;
808
+ const hasRoutingPolicy = !!latencyConfig?.region ||
809
+ weightedConfig?.weight !== undefined ||
810
+ !!geoConfig?.geoLocation;
811
+ let setIdentifier = domainConfig.setIdentifier;
812
+ if (hasRoutingPolicy && !setIdentifier) {
813
+ if (latencyConfig?.region) {
814
+ setIdentifier = `${props.clusterName}${latencyConfig.region}`;
815
+ }
816
+ else if (weightedConfig?.weight !== undefined) {
817
+ setIdentifier = `${props.clusterName}Weight${weightedConfig.weight}`;
818
+ }
819
+ else if (geoConfig?.geoLocation) {
820
+ setIdentifier = `${props.clusterName}Geo`;
821
+ }
331
822
  }
332
- else if (geoConfig?.geoLocation) {
333
- setIdentifier = `${props.serviceName}-geo`;
823
+ if (this.loadBalancer) {
824
+ this.aRecord = new aws_route53_1.ARecord(this, `${props.clusterName}ARecord`, {
825
+ recordName: domainName,
826
+ zone: this.hostedZone,
827
+ target: aws_route53_1.RecordTarget.fromAlias(new aws_route53_targets_1.LoadBalancerTarget(this.loadBalancer, {
828
+ evaluateTargetHealth: hasRoutingPolicy
829
+ })),
830
+ region: latencyConfig?.region,
831
+ weight: weightedConfig?.weight,
832
+ geoLocation: geoConfig?.geoLocation,
833
+ setIdentifier: setIdentifier
834
+ });
334
835
  }
335
836
  }
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");
837
+ else if (simpleDomain && this.loadBalancer) {
838
+ // Simple domain - just create A record
839
+ this.aRecord = new aws_route53_1.ARecord(this, `${props.clusterName}ARecord`, {
840
+ recordName: domainName,
841
+ zone: this.hostedZone,
842
+ target: aws_route53_1.RecordTarget.fromAlias(new aws_route53_targets_1.LoadBalancerTarget(this.loadBalancer))
843
+ });
357
844
  }
358
- return aws_ecs_1.ContainerImage.fromRegistry("amazon/amazon-ecs-sample");
359
845
  }
360
846
  static build(id, props) {
361
847
  return (sb) => {
@@ -369,5 +855,5 @@ class FargateCluster extends constructs_1.Construct {
369
855
  };
370
856
  }
371
857
  }
372
- exports.default = FargateCluster;
373
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWNzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vbGliL3Jlc291cmNlcy9hd3MvY29tcHV0ZS9lY3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsaURBVzZCO0FBQzdCLGlEQU02QjtBQUM3QiwyQ0FBdUM7QUFFdkMsNkNBQWdFO0FBQ2hFLHVGQUlnRDtBQUNoRCxpREFRNkI7QUFDN0IsdUZBS2dEO0FBQ2hELGlEQUEwRDtBQUMxRCx1RUFBd0Q7QUFDeEQsK0VBRzRDO0FBQzVDLHlEQUtpQztBQUNqQyx5RUFBcUU7QUFDckUsaURBQWlEO0FBR2pELHNEQUFtRDtBQUNuRCxpRUFBaUY7QUFJakYsSUFBWSxRQUdYO0FBSEQsV0FBWSxRQUFRO0lBQ2xCLHVDQUFJLENBQUE7SUFDSix5Q0FBSyxDQUFBO0FBQ1AsQ0FBQyxFQUhXLFFBQVEsd0JBQVIsUUFBUSxRQUduQjtBQUVELElBQVksV0FHWDtBQUhELFdBQVksV0FBVztJQUNyQixzREFBMEQsQ0FBQTtJQUMxRCw0REFBZ0UsQ0FBQTtBQUNsRSxDQUFDLEVBSFcsV0FBVywyQkFBWCxXQUFXLFFBR3RCO0FBcUVELE1BQXFCLGNBQWUsU0FBUSxzQkFBUztJQXFCbkQsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxLQUEwQjtRQUNsRSxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBUFgsWUFBTyxHQUVYLEVBQUUsQ0FBQztRQU9MLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO1FBRW5CLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDdkIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN2QixJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzFCLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUM3QixJQUFJLENBQUMsaUJBQWlCLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDOUIsSUFBSSxDQUFDLHNCQUFzQixDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ25DLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUM5QixJQUFJLENBQUMsZUFBZSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRTVCLElBQUksS0FBSyxDQUFDLFlBQVk7WUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRWxELElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUNwQyxJQUFJLENBQUMsMkJBQTJCLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFeEMsTUFBTSxhQUFhLEdBQUcsS0FBSyxDQUFDLGFBQWEsSUFBSSxFQUFFLENBQUM7UUFDaEQsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLHFCQUFXLENBQUM7WUFDakMsY0FBYyxFQUFFLElBQUksQ0FBQyxjQUFjLENBQUMsV0FBVyxDQUFDLGNBQWM7WUFDOUQsV0FBVyxFQUFFLGNBQUksQ0FBQyxHQUFHLENBQUMsYUFBYSxDQUFDO1NBQ3JDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRCxVQUFVLENBQUMsS0FBMEI7UUFDbkMsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLGlCQUFVLENBQUMsSUFBSSxFQUFFLEdBQUcsS0FBSyxDQUFDLFdBQVcsRUFBRSxFQUFFO1lBQzFELEdBQUcsRUFBRSxLQUFLLENBQUMsR0FBRztZQUNkLFdBQVcsRUFBRSxLQUFLLENBQUMsV0FBVztZQUM5QixtQkFBbUIsRUFBRSwyQkFBaUIsQ0FBQyxPQUFPO1lBQzlDLDhCQUE4QixFQUFFLElBQUk7U0FDckMsQ0FBQyxDQUFDO1FBRUgsK0NBQStDO1FBQy9DLElBQUkscUJBQVMsQ0FBQyxJQUFJLEVBQUUsR0FBRyxLQUFLLENBQUMsV0FBVyxtQkFBbUIsRUFBRTtZQUMzRCxHQUFHLEVBQUUsR0FBRyxLQUFLLENBQUMsV0FBVyxtQkFBbUI7WUFDNUMsVUFBVSxFQUFFLEdBQUcsS0FBSyxDQUFDLFdBQVcsbUJBQW1CO1lBQ25ELEtBQUssRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVU7U0FDL0IsQ0FBQyxDQUFDO1FBRUgsb0NBQW9DO1FBQ3BDLElBQUkscUJBQVMsQ0FBQyxJQUFJLEVBQUUsR0FBRyxLQUFLLENBQUMsV0FBVyxZQUFZLEVBQUU7WUFDcEQsR0FBRyxFQUFFLFlBQVk7WUFDakIsVUFBVSxFQUFFLEdBQUcsS0FBSyxDQUFDLFdBQVcsWUFBWTtZQUM1QyxLQUFLLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxVQUFVO1lBQzlCLFdBQVcsRUFBRSx1QkFBdUIsS0FBSyxDQUFDLFdBQVcsRUFBRTtTQUN4RCxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsVUFBVSxDQUFDLEtBQTBCO1FBQ25DLG9CQUFvQjtRQUNwQixNQUFNLGVBQWUsR0FBRywyQkFBTSxDQUFDLGdCQUFnQixDQUM3QyxJQUFJLEVBQ0osR0FBRyxLQUFLLENBQUMsV0FBVyxRQUFRLEVBQzVCLElBQUksS0FBSyxDQUFDLFdBQVcsSUFBSSxLQUFLLENBQUMsV0FBVyxFQUFFLENBQzdDLENBQUM7UUFFRixLQUFLLE1BQU0sV0FBVyxJQUFJLEtBQUssQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1lBQ2pELElBQUksQ0FBQyxPQUFPLENBQUMsV0FBVyxDQUFDLEdBQUcsZ0JBQVMsQ0FBQyxrQkFBa0IsQ0FDdEQsZUFBZSxFQUNmLFdBQVcsQ0FDWixDQUFDO1FBQ0osQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNILGFBQWEsQ0FBQyxLQUEwQjtRQUN0QyxJQUFJLENBQUMsS0FBSyxDQUFDLHNCQUFzQjtZQUFFLE9BQU87UUFFMUMsS0FBSyxNQUFNLEdBQUcsSUFBSSxLQUFLLENBQUMsc0JBQXNCLEVBQUUsQ0FBQztZQUMvQyxNQUFNLFlBQVksR0FBRyxLQUFLLENBQUMsc0JBQXNCLENBQUMsR0FBRyxDQUFDLENBQUM7WUFFdkQsd0ZBQXdGO1lBRXhGLG1DQUFtQztZQUNuQyxNQUFNLE9BQU8sR0FBRywyQkFBTSxDQUFDLGdCQUFnQixDQUNyQyxJQUFJLEVBQ0osWUFBWSxDQUFDLEVBQUUsRUFDZixZQUFZLENBQUMsSUFBSSxDQUNsQixDQUFDO1lBRUYsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsR0FBRyxnQkFBUyxDQUFDLGtCQUFrQixDQUM5QyxPQUFPLEVBQ1AsWUFBWSxDQUFDLEtBQUssQ0FDbkIsQ0FBQztRQUNKLENBQUM7SUFDSCxDQUFDO0lBRUQsZ0JBQWdCLENBQUMsS0FBMEI7UUFDekMsSUFBSSxDQUFDLGFBQWEsR0FBRyxJQUFJLGNBQUksQ0FDM0IsSUFBSSxFQUNKLEdBQUcsS0FBSyxDQUFDLFdBQVcsZ0JBQWdCLG1CQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUMzRDtZQUNFLFFBQVEsRUFBRSxHQUFHLEtBQUssQ0FBQyxXQUFXLGdCQUFnQixtQkFBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLEVBQUU7WUFDckUsV0FBVyxFQUFFLEdBQUcsS0FBSyxDQUFDLFdBQVcsaUJBQWlCO1lBQ2xELGVBQWUsRUFBRTtnQkFDZjtvQkFDRSxnQkFBZ0IsRUFDZCx1RUFBdUU7aUJBQzFFO2FBQ0Y7WUFDRCxjQUFjLEVBQUU7Z0JBQ2QsQ0FBQyxhQUFhLENBQUMsRUFBRSxJQUFJLHdCQUFjLENBQUM7b0JBQ2xDLFVBQVUsRUFBRTt3QkFDVixJQUFJLHlCQUFlLENBQUM7NEJBQ2xCLE9BQU8sRUFBRTtnQ0FDUCwrQkFBK0I7Z0NBQy9CLCtCQUErQjs2QkFDaEM7NEJBQ0QsU0FBUyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsbUNBQW1DO3lCQUNyRCxDQUFDO3FCQUNIO2lCQUNGLENBQUM7Z0JBQ0YsQ0FBQyxnQkFBZ0IsQ0FBQyxFQUFFLElBQUksd0JBQWMsQ0FBQztvQkFDckMsVUFBVSxFQUFFO3dCQUNWLElBQUkseUJBQWUsQ0FBQzs0QkFDbEIsT0FBTyxFQUFFLENBQUMsYUFBYSxDQUFDOzRCQUN4QixTQUFTLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxnQ0FBZ0M7eUJBQ2xELENBQUM7cUJBQ0g7aUJBQ0YsQ0FBQztnQkFDRixDQUFDLG1CQUFtQixDQUFDLEVBQUUsSUFBSSx3QkFBYyxDQUFDO29CQUN4QyxVQUFVLEVBQUU7d0JBQ1YsSUFBSSx5QkFBZSxDQUFDOzRCQUNsQixPQUFPLEVBQUU7Z0NBQ1Asa0NBQWtDO2dDQUNsQywrQkFBK0I7Z0NBQy9CLGdDQUFnQztnQ0FDaEMsNkJBQTZCOzZCQUM5Qjs0QkFDRCxNQUFNLEVBQUUsZ0JBQU0sQ0FBQyxLQUFLOzRCQUNwQixTQUFTLEVBQUUsQ0FBQyxHQUFHLENBQUM7eUJBQ2pCLENBQUM7cUJBQ0g7aUJBQ0YsQ0FBQzthQUNIO1lBQ0QsU0FBUyxFQUFFLElBQUksNEJBQWtCLENBQy9CLElBQUksMEJBQWdCLENBQUMseUJBQXlCLENBQUMsQ0FDaEQ7U0FDRixDQUNGLENBQUM7SUFDSixDQUFDO0lBRUQsaUJBQWlCLENBQUMsS0FBMEI7UUFDMUMsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLCtCQUFxQixDQUM3QyxJQUFJLEVBQ0osR0FBRyxLQUFLLENBQUMsV0FBVyxnQkFBZ0IsRUFDcEM7WUFDRSxHQUFHLEVBQUUsS0FBSyxDQUFDLEdBQUcsSUFBSSxHQUFHO1lBQ3JCLGFBQWEsRUFBRSxJQUFJLENBQUMsYUFBYTtZQUNqQyxRQUFRLEVBQUUsSUFBSSxjQUFJLENBQ2hCLElBQUksRUFDSixHQUFHLEtBQUssQ0FBQyxXQUFXLFdBQVcsbUJBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQ3REO2dCQUNFLFFBQVEsRUFBRSxHQUFHLEtBQUssQ0FBQyxXQUFXLFdBQVcsbUJBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxFQUFFO2dCQUNoRSxXQUFXLEVBQUUsR0FBRyxLQUFLLENBQUMsV0FBVyxZQUFZO2dCQUM3QyxjQUFjLEVBQUUsS0FBSyxDQUFDLHNCQUFzQjtnQkFDNUMsZUFBZSxFQUFFLEtBQUssQ0FBQyx1QkFBdUI7Z0JBQzlDLFNBQVMsRUFBRSxJQUFJLDRCQUFrQixDQUMvQixJQUFJLDBCQUFnQixDQUFDLHlCQUF5QixDQUFDLENBQ2hEO2FBQ0YsQ0FDRjtZQUNELGNBQWMsRUFBRSxLQUFLLENBQUMsY0FBYyxJQUFJLEdBQUc7U0FDNUMsQ0FDRixDQUFDO0lBQ0osQ0FBQztJQUVELHNCQUFzQixDQUFDLEtBQTBCO1FBQy9DLElBQUksQ0FBQyxtQkFBbUIsR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLFlBQVksQ0FDekQsR0FBRyxLQUFLLENBQUMsV0FBVyxxQkFBcUIsRUFDekM7WUFDRSxLQUFLLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUM7WUFDM0IsYUFBYSxFQUFFLEtBQUssQ0FBQyxXQUFXO1lBQ2hDLFdBQVcsRUFBRTtnQkFDWCxHQUFHLEtBQUssQ0FBQyxvQkFBb0I7YUFDOUI7WUFDRCxPQUFPLEVBQUUsS0FBSyxDQUFDLGdCQUFnQjtZQUMvQixPQUFPLEVBQUU7Z0JBQ1AsR0FBRyxJQUFJLENBQUMsT0FBTzthQUNoQjtZQUNELG9DQUFvQztZQUNwQyxXQUFXLEVBQUU7Z0JBQ1gsT0FBTyxFQUFFO29CQUNQLFdBQVc7b0JBQ1gseUZBQXlGO29CQUN6RiwwRkFBMEY7b0JBQzFGLHFGQUFxRjtvQkFDckYsNEJBQTRCLEtBQUssQ0FBQyxhQUFhLGFBQWE7aUJBQzdEO2FBQ0Y7WUFDRCxPQUFPLEVBQUUsSUFBSSxzQkFBWSxDQUFDO2dCQUN4QixZQUFZLEVBQUUsUUFBUSxLQUFLLENBQUMsV0FBVyxJQUFJLEtBQUssQ0FBQyxXQUFXLEVBQUU7Z0JBQzlELFlBQVksRUFBRSxFQUFFO2FBQ2pCLENBQUM7WUFDRixZQUFZLEVBQUUsS0FBSyxDQUFDLGFBQWE7Z0JBQy9CLENBQUMsQ0FBQyxDQUFDLEVBQUUsYUFBYSxFQUFFLEtBQUssQ0FBQyxhQUFhLEVBQUUsQ0FBQztnQkFDMUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxhQUFhLEVBQUUsRUFBRSxFQUFFLENBQUM7U0FDNUIsQ0FDRixDQUFDO0lBQ0osQ0FBQztJQUVELGlCQUFpQixDQUFDLEtBQTBCO1FBQzFDLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSx3QkFBYyxDQUN0QyxJQUFJLEVBQ0osR0FBRyxLQUFLLENBQUMsV0FBVyxnQkFBZ0IsRUFDcEM7WUFDRSxjQUFjLEVBQUUsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFO1lBQ2xDLE9BQU8sRUFBRSxJQUFJLENBQUMsT0FBTztZQUNyQixZQUFZLEVBQUUsQ0FBQztZQUNmLG9CQUFvQixFQUFFLElBQUk7WUFDMUIsb0JBQW9CLEVBQUUsSUFBSTtZQUMxQixhQUFhLEVBQUUsNkJBQW1CLENBQUMsT0FBTztZQUMxQyxXQUFXLEVBQUUsR0FBRyxLQUFLLENBQUMsV0FBVyxFQUFFO1lBQ25DLGNBQWMsRUFBRSxJQUFJLENBQUMsY0FBYztZQUNuQyxpQkFBaUIsRUFBRSxHQUFHO1lBQ3RCLGlCQUFpQixFQUFFLEdBQUc7U0FDdkIsQ0FDRixDQUFDO1FBRUYsMkNBQTJDO1FBQzNDLElBQUkscUJBQVMsQ0FBQyxJQUFJLEVBQUUsR0FBRyxLQUFLLENBQUMsV0FBVyxtQkFBbUIsRUFBRTtZQUMzRCxHQUFHLEVBQUUsR0FBRyxLQUFLLENBQUMsV0FBVyxtQkFBbUI7WUFDNUMsVUFBVSxFQUFFLEdBQUcsS0FBSyxDQUFDLFdBQVcsbUJBQW1CO1lBQ25ELEtBQUssRUFBRSxJQUFJLENBQUMsY0FBYyxDQUFDLFVBQVU7U0FDdEMsQ0FBQyxDQUFDO1FBRUgsb0NBQW9DO1FBQ3BDLElBQUkscUJBQVMsQ0FBQyxJQUFJLEVBQUUsR0FBRyxLQUFLLENBQUMsV0FBVyxZQUFZLEVBQUU7WUFDcEQsR0FBRyxFQUFFLFlBQVk7WUFDakIsVUFBVSxFQUFFLEdBQUcsS0FBSyxDQUFDLFdBQVcsWUFBWTtZQUM1QyxLQUFLLEVBQUUsSUFBSSxDQUFDLGNBQWMsQ0FBQyxVQUFVO1lBQ3JDLFdBQVcsRUFBRSx1QkFBdUIsS0FBSyxDQUFDLFdBQVcsRUFBRTtTQUN4RCxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQsZ0JBQWdCLENBQUMsS0FBMEI7UUFDekMsSUFBSSxDQUFDLGFBQWEsR0FBRyxJQUFJLHdEQUEyQixDQUNsRCxJQUFJLEVBQ0osR0FBRyxLQUFLLENBQUMsV0FBVyxlQUFlLEVBQ25DO1lBQ0UsVUFBVSxFQUFFLEdBQUcsS0FBSyxDQUFDLFdBQVcsZUFBZTtZQUMvQyxhQUFhLEVBQUUsSUFBSSwyQ0FBYyxDQUMvQixJQUFJLEVBQ0osR0FBRyxLQUFLLENBQUMsV0FBVyxnQkFBZ0IsRUFDcEM7Z0JBQ0UsV0FBVyxFQUFFLEVBQUU7Z0JBQ2YsV0FBVyxFQUFFLENBQUM7Z0JBQ2QsVUFBVSxFQUFFLFdBQVcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxXQUFXLElBQUksSUFBSSxDQUFDLGNBQWMsQ0FBQyxXQUFXLEVBQUU7Z0JBQ3BGLGlCQUFpQixFQUFFLDBCQUEwQjtnQkFDN0MsZ0JBQWdCLEVBQUUsNkNBQWdCLENBQUMsR0FBRzthQUN2QyxDQUNGO1lBQ0QsV0FBVyxFQUFFLEVBQUU7WUFDZixnQkFBZ0IsRUFBRSxzQkFBUSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDdEMsZUFBZSxFQUFFLHNCQUFRLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUNyQyxnQkFBZ0IsRUFDZCxLQUFLLENBQUMsV0FBVyxJQUFJLFdBQVcsQ0FBQyxNQUFNO2dCQUNyQyxDQUFDLENBQUMsNkNBQWdCLENBQUMsc0NBQXNDO2dCQUN6RCxDQUFDLENBQUMsNkNBQWdCLENBQUMsbUNBQW1DO1NBQzNELENBQ0YsQ0FBQztJQUNKLENBQUM7SUFFRCwyQkFBMkIsQ0FBQyxLQUEwQjtRQUNwRCxJQUFJLENBQUMsY0FBYyxDQUFDLDJCQUEyQixDQUFDO1lBQzlDLGFBQWEsRUFBRSxJQUFJLENBQUMsbUJBQW1CLENBQUMsYUFBYTtZQUNyRCxhQUFhLEVBQUUsSUFBSSxDQUFDLG1CQUFtQixDQUFDLGFBQWE7WUFDckQsZ0JBQWdCLEVBQUUsR0FBRyxLQUFLLENBQUMsV0FBVyxhQUFhO1lBQ25ELFFBQVEsRUFBRSx3QkFBYyxDQUFDLG1CQUFtQixDQUFDLElBQUksQ0FBQyxvQkFBb0IsRUFBRTtnQkFDdEUsSUFBSSxFQUFFLEtBQUssQ0FBQyxhQUFhO2dCQUN6QixRQUFRLEVBQUUsZ0RBQW1CLENBQUMsSUFBSTtnQkFDbEMsV0FBVyxFQUFFO29CQUNYLFFBQVEsRUFBRSxzQkFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUM7b0JBQy9CLElBQUksRUFBRSxLQUFLLENBQUMsZUFBZSxJQUFJLEdBQUc7b0JBQ2xDLElBQUksRUFBRSxLQUFLLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxhQUFhLEVBQUUsQ0FBQyxDQUFDLENBQUMsY0FBYztvQkFDckUsT0FBTyxFQUFFLHNCQUFRLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztpQkFDOUI7YUFDRixDQUFDO1NBQ0gsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVELGVBQWUsQ0FBQyxLQUEwQjtRQUN4QywwRkFBMEY7UUFDMUYsTUFBTSx1QkFBdUIsR0FBRyxHQUFHLEtBQUssQ0FBQyxXQUFXLGNBQWMsQ0FBQztRQUNuRSxNQUFNLG1CQUFtQixHQUFHLEVBQUUsQ0FBQztRQUUvQixJQUFJLHlCQUF5QixHQUMzQix1QkFBdUIsQ0FBQyxNQUFNLEdBQUcsbUJBQW1CO1lBQ2xELENBQUMsQ0FBQyx1QkFBdUIsQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLG1CQUFtQixDQUFDO1lBQzNELENBQUMsQ0FBQyx1QkFBdUIsQ0FBQztRQUU5QixxRUFBcUU7UUFDckUseUJBQXlCLEdBQUcseUJBQXlCLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUV6RSxJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksb0RBQXVCLENBQzdDLElBQUksRUFDSixHQUFHLEtBQUssQ0FBQyxXQUFXLGNBQWMsRUFDbEM7WUFDRSxHQUFHLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHO1lBQ3JCLGNBQWMsRUFBRSxJQUFJO1lBQ3BCLGdCQUFnQixFQUFFLHlCQUF5QjtZQUMzQyxVQUFVLEVBQUU7Z0JBQ1YsVUFBVSxFQUFFLG9CQUFVLENBQUMsTUFBTTthQUM5QjtTQUNGLENBQ0YsQ0FBQztRQUVGLElBQUkscUJBQVMsQ0FBQyxJQUFJLEVBQUUsR0FBRyxLQUFLLENBQUMsV0FBVyxxQkFBcUIsRUFBRTtZQUM3RCxHQUFHLEVBQUUsR0FBRyxLQUFLLENBQUMsV0FBVyxxQkFBcUI7WUFDOUMsVUFBVSxFQUFFLEdBQUcsS0FBSyxDQUFDLFdBQVcscUJBQXFCO1lBQ3JELEtBQUssRUFBRSxJQUFJLENBQUMsWUFBWSxDQUFDLG1CQUFtQjtTQUM3QyxDQUFDLENBQUM7UUFFSCwwQ0FBMEM7UUFDMUMsSUFBSSxxQkFBUyxDQUFDLElBQUksRUFBRSxHQUFHLEtBQUssQ0FBQyxXQUFXLGlCQUFpQixFQUFFO1lBQ3pELEdBQUcsRUFBRSxpQkFBaUI7WUFDdEIsVUFBVSxFQUFFLEdBQUcsS0FBSyxDQUFDLFdBQVcsaUJBQWlCO1lBQ2pELEtBQUssRUFBRSxVQUFVLElBQUksQ0FBQyxZQUFZLENBQUMsbUJBQW1CLEVBQUU7WUFDeEQsV0FBVyxFQUFFLHlCQUF5QixLQUFLLENBQUMsV0FBVyxFQUFFO1NBQzFELENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRCx1QkFBdUIsQ0FBQyxLQUEwQjtRQUNoRCxJQUFJLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUNyQixJQUFJLENBQUMsb0JBQW9CLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQ3ZELEdBQUcsS0FBSyxDQUFDLFdBQVcsVUFBVSxFQUM5QjtnQkFDRSxJQUFJLEVBQUUsS0FBSyxDQUFDLFFBQVEsSUFBSSxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUc7Z0JBQ2hELFlBQVksRUFBRSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUM7YUFDakMsQ0FDRixDQUFDO1FBQ0osQ0FBQzthQUFNLENBQUM7WUFDTixJQUFJLENBQUMsb0JBQW9CLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQ3ZELEdBQUcsS0FBSyxDQUFDLFdBQVcsVUFBVSxFQUM5QjtnQkFDRSxJQUFJLEVBQUUsS0FBSyxDQUFDLFFBQVEsSUFBSSxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUc7YUFDakQsQ0FDRixDQUFDO1FBQ0osQ0FBQztJQUNILENBQUM7SUFFRCxhQUFhLENBQUMsS0FBMEI7UUFDdEMsSUFBSSxDQUFDLEtBQUssQ0FBQyxZQUFZO1lBQUUsT0FBTztRQUVoQyxJQUFJLENBQUMsS0FBSyxDQUFDLFlBQVksQ0FBQyxVQUFVLEVBQUUsQ0FBQztZQUNuQyxrREFBa0Q7WUFDbEQsTUFBTSxVQUFVLEdBQUcsSUFBSSx1QkFBZSxDQUNwQyxJQUFJLEVBQ0osR0FBRyxLQUFLLENBQUMsV0FBVyxZQUFZLEVBQ2hDO2dCQUNFLFFBQVEsRUFBRSxLQUFLLENBQUMsWUFBWSxDQUFDLFVBQVU7YUFDeEMsQ0FDRixDQUFDO1lBRUYsSUFBSSxDQUFDLFVBQVUsR0FBRyxVQUFVLENBQUMscUJBQXFCLEVBQUUsQ0FBQztRQUN2RCxDQUFDO2FBQU0sQ0FBQztZQUNOLHlDQUF5QztZQUN6QyxJQUFJLENBQUMsVUFBVSxHQUFHLEtBQUssQ0FBQyxZQUFZLENBQUMsVUFBVSxDQUFDLHFCQUFxQixFQUFFLENBQUM7UUFDMUUsQ0FBQztRQUVELElBQUksQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQ3BDLG1EQUFtRDtZQUNuRCxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksb0NBQVcsQ0FDaEMsSUFBSSxFQUNKLEdBQUcsS0FBSyxDQUFDLFdBQVcsYUFBYSxFQUNqQztnQkFDRSxVQUFVLEVBQUUsS0FBSyxDQUFDLFlBQVksQ0FBQyxVQUFVO2dCQUN6QyxVQUFVLEVBQUUsOENBQXFCLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUM7YUFDM0QsQ0FDRixDQUFDO1FBQ0osQ0FBQztRQUVELHFFQUFxRTtRQUNyRSxNQUFNLGFBQWEsR0FBRyxLQUFLLENBQUMsWUFBbUMsQ0FBQztRQUNoRSxNQUFNLGNBQWMsR0FBRyxLQUFLLENBQUMsWUFBb0MsQ0FBQztRQUNsRSxNQUFNLFNBQVMsR0FBRyxLQUFLLENBQUMsWUFBdUMsQ0FBQztRQUVoRSxNQUFNLGdCQUFnQixHQUNwQixDQUFDLENBQUMsYUFBYSxFQUFFLE1BQU07WUFDdkIsY0FBYyxFQUFFLE1BQU0sS0FBSyxTQUFTO1lBQ3BDLENBQUMsQ0FBQyxTQUFTLEVBQUUsV0FBVyxDQUFDO1FBRTNCLG9FQUFvRTtRQUNwRSxxR0FBcUc7UUFDckcsSUFBSSxhQUFhLEdBQUcsS0FBSyxDQUFDLFlBQVksQ0FBQyxhQUFhLENBQUM7UUFDckQsSUFBSSxnQkFBZ0IsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO1lBQ3ZDLElBQUksYUFBYSxFQUFFLE1BQU0sRUFBRSxDQUFDO2dCQUMxQixhQUFhLEdBQUcsR0FBRyxLQUFLLENBQUMsV0FBVyxJQUFJLGFBQWEsQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNqRSxDQUFDO2lCQUFNLElBQUksY0FBYyxFQUFFLE1BQU0sS0FBSyxTQUFTLEVBQUUsQ0FBQztnQkFDaEQsYUFBYSxHQUFHLEdBQUcsS0FBSyxDQUFDLFdBQVcsV0FBVyxjQUFjLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDekUsQ0FBQztpQkFBTSxJQUFJLFNBQVMsRUFBRSxXQUFXLEVBQUUsQ0FBQztnQkFDbEMsYUFBYSxHQUFHLEdBQUcsS0FBSyxDQUFDLFdBQVcsTUFBTSxDQUFDO1lBQzdDLENBQUM7UUFDSCxDQUFDO1FBRUQsaUZBQWlGO1FBQ2pGLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxxQkFBTyxDQUN4QixJQUFJLEVBQ0osR0FBRyxLQUFLLENBQUMsV0FBVyxJQUFJLEtBQUssQ0FBQyxXQUFXLElBQUksS0FBSyxDQUFDLFlBQVksQ0FBQyxVQUFVLFNBQVMsRUFDbkY7WUFDRSxVQUFVLEVBQUUsS0FBSyxDQUFDLFlBQVksQ0FBQyxVQUFVO1lBQ3pDLElBQUksRUFBRSxJQUFJLENBQUMsVUFBVTtZQUNyQixNQUFNLEVBQUUsMEJBQVksQ0FBQyxTQUFTLENBQzVCLElBQUksd0NBQWtCLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRTtnQkFDeEMsb0JBQW9CLEVBQUUsZ0JBQWdCO2FBQ3ZDLENBQUMsQ0FDSDtZQUNELE1BQU0sRUFBRSxhQUFhLEVBQUUsTUFBTTtZQUM3QixNQUFNLEVBQUUsY0FBYyxFQUFFLE1BQU07WUFDOUIsV0FBVyxFQUFFLFNBQVMsRUFBRSxXQUFXO1lBQ25DLGlHQUFpRztZQUNqRyxhQUFhLEVBQUUsYUFBYTtTQUM3QixDQUNGLENBQUM7SUFDSixDQUFDO0lBRUQsUUFBUSxDQUFDLEtBQTBCO1FBQ2pDLElBQUksQ0FBQyxLQUFLLENBQUMsYUFBYTtZQUN0QixPQUFPLHdCQUFjLENBQUMsWUFBWSxDQUFDLDBCQUEwQixDQUFDLENBQUM7UUFDakUsSUFBSSxLQUFLLENBQUMsYUFBYSxZQUFZLHdCQUFjO1lBQy9DLE9BQU8sS0FBSyxDQUFDLGFBQWEsQ0FBQztRQUM3QixJQUFJLEtBQUssQ0FBQyxhQUFhLFlBQVksb0JBQVUsRUFBRSxDQUFDO1lBQzlDLE9BQU8sd0JBQWMsQ0FBQyxpQkFBaUIsQ0FBQyxLQUFLLENBQUMsYUFBYSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBQ3pFLENBQUM7UUFDRCxPQUFPLHdCQUFjLENBQUMsWUFBWSxDQUFDLDBCQUEwQixDQUFDLENBQUM7SUFDakUsQ0FBQztJQUVELE1BQU0sQ0FBQyxLQUFLLENBQ1YsRUFBVSxFQUNWLEtBQTBCO1FBRTFCLE9BQU8sQ0FBQyxFQUFnQixFQUFFLEVBQUU7WUFDMUIsTUFBTSxRQUFRLEdBQXdCO2dCQUNwQyxHQUFHLEtBQUs7Z0JBQ1IsR0FBRztvQkFDRCxHQUFHLEVBQUcsRUFBRSxDQUFDLFVBQVUsRUFBVyxJQUFJLEtBQUssQ0FBQyxHQUFHO2lCQUM1QzthQUNGLENBQUM7WUFDRixPQUFPLElBQUksSUFBSSxDQUFDLEVBQUUsQ0FBQyxRQUFRLEVBQUUsRUFBRSxFQUFFLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFDL0MsQ0FBQyxDQUFDO0lBQ0osQ0FBQztDQUNGO0FBdGRELGlDQXNkQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIEF3c0xvZ0RyaXZlcixcbiAgQ2x1c3RlciBhcyBDZGtDbHVzdGVyLFxuICBDb250YWluZXJJbWFnZSxcbiAgRmFyZ2F0ZVNlcnZpY2UsXG4gIEZhcmdhdGVUYXNrRGVmaW5pdGlvbixcbiAgTGlzdGVuZXJDb25maWcsXG4gIFByb3BhZ2F0ZWRUYWdTb3VyY2UsXG4gIHR5cGUgUmVwb3NpdG9yeUltYWdlLFxuICB0eXBlIENvbnRhaW5lckRlZmluaXRpb24sXG4gIENvbnRhaW5lckluc2lnaHRzXG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtZWNzXCI7XG5pbXBvcnQge1xuICBDb25uZWN0aW9ucyxcbiAgdHlwZSBJQ29ubmVjdGFibGUsXG4gIHR5cGUgSVZwYyxcbiAgUG9ydCxcbiAgU3VibmV0VHlwZVxufSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWVjMlwiO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSBcImNvbnN0cnVjdHNcIjtcbmltcG9ydCB7IHR5cGUgU3RhY2tCdWlsZGVyIH0gZnJvbSBcIi4uL2Jhc2UvYXdzU3RhY2tcIjtcbmltcG9ydCB7IER1cmF0aW9uLCB0eXBlIFNlY3JldFZhbHVlLCBTdGFjayB9IGZyb20gXCJhd3MtY2RrLWxpYlwiO1xuaW1wb3J0IHtcbiAgdHlwZSBBcHBsaWNhdGlvbkxpc3RlbmVyLFxuICBBcHBsaWNhdGlvbkxvYWRCYWxhbmNlcixcbiAgQXBwbGljYXRpb25Qcm90b2NvbFxufSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWVsYXN0aWNsb2FkYmFsYW5jaW5ndjJcIjtcbmltcG9ydCB7XG4gIENvbXBvc2l0ZVByaW5jaXBhbCxcbiAgRWZmZWN0LFxuICB0eXBlIElNYW5hZ2VkUG9saWN5LFxuICBQb2xpY3lEb2N1bWVudCxcbiAgUG9saWN5U3RhdGVtZW50LFxuICBSb2xlLFxuICBTZXJ2aWNlUHJpbmNpcGFsXG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtaWFtXCI7XG5pbXBvcnQge1xuICBQcmVkZWZpbmVkTWV0cmljLFxuICBTY2FsYWJsZVRhcmdldCxcbiAgU2VydmljZU5hbWVzcGFjZSxcbiAgVGFyZ2V0VHJhY2tpbmdTY2FsaW5nUG9saWN5XG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtYXBwbGljYXRpb25hdXRvc2NhbGluZ1wiO1xuaW1wb3J0IHsgU2VjcmV0IGFzIEVjc1NlY3JldCB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtZWNzXCI7XG5pbXBvcnQgeyBTZWNyZXQgfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLXNlY3JldHNtYW5hZ2VyXCI7XG5pbXBvcnQge1xuICBDZXJ0aWZpY2F0ZSxcbiAgQ2VydGlmaWNhdGVWYWxpZGF0aW9uXG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtY2VydGlmaWNhdGVtYW5hZ2VyXCI7XG5pbXBvcnQge1xuICBBUmVjb3JkLFxuICBSZWNvcmRUYXJnZXQsXG4gIHR5cGUgSUhvc3RlZFpvbmUsXG4gIHR5cGUgR2VvTG9jYXRpb25cbn0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1yb3V0ZTUzXCI7XG5pbXBvcnQgeyBMb2FkQmFsYW5jZXJUYXJnZXQgfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLXJvdXRlNTMtdGFyZ2V0c1wiO1xuaW1wb3J0IHsgUmVwb3NpdG9yeSB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtZWNyXCI7XG5cbmltcG9ydCB7IHR5cGUgS2V5VmFsdWUgfSBmcm9tIFwiLi4vLi4vLi4vdHlwZXNcIjtcbmltcG9ydCB7IENmbk91dHB1dCB9IGZyb20gXCIuLi91dGlsaXRpZXMvY2ZuT3V0cHV0XCI7XG5pbXBvcnQgeyBIb3N0ZWRab25lIGFzIEZqYWxsSG9zdGVkWm9uZSB9IGZyb20gXCIuLi8uLi8uLi9wYXR0ZXJucy9hd3MvaG9zdGVkWm9uZVwiO1xuXG5pbXBvcnQgeyB0eXBlIFNlY3JldEltcG9ydCB9IGZyb20gXCIuLi9zZWNyZXRzXCI7XG5cbmV4cG9ydCBlbnVtIFByb3RvY29sIHtcbiAgSFRUUCxcbiAgSFRUUFNcbn1cblxuZXhwb3J0IGVudW0gU2NhbGluZ1R5cGUge1xuICBDUFUgPSBQcmVkZWZpbmVkTWV0cmljLkVDU19TRVJWSUNFX0FWRVJBR0VfQ1BVX1VUSUxJWkFUSU9OLFxuICBNRU1PUlkgPSBQcmVkZWZpbmVkTWV0cmljLkVDU19TRVJWSUNFX0FWRVJBR0VfTUVNT1JZX1VUSUxJWkFUSU9OXG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ29udGFpbmVyU2VjcmV0IHtcbiAgW2tleTogc3RyaW5nXTogU2VjcmV0VmFsdWU7XG59XG5cbi8qKlxuICogRG9tYWluQ29uZmlndXJhdGlvblxuICogLSBXaGVuIHN1cHBsaWVkIGEgZG9tYWluIG5hbWUsIGEgaG9zdGVkIHpvbmUsIGNlcnRpZmljYXRlIGFuZCBBUmVjb3JkIHdpbGwgYmUgY3JlYXRlZFxuICogLSBXaGVuIHN1cHBsaWVkIGEgZG9tYWluIG5hbWUgYW5kIGhvc3RlZCB6b25lLCBhIGNlcnRpZmljYXRlIGFuZCBBUmVjb3JkIHdpbGwgYmUgY3JlYXRlZFxuICogLSBXaGVuIGFsbCBwcm9wZXJ0aWVzIGFyZSBzdXBwbGllZCBvbmx5IGEgdGFyZ2V0IHdpbGwgYmUgY3JlYXRlZFxuICovXG5cbmV4cG9ydCBpbnRlcmZhY2UgRG9tYWluQmFzZUNvbmZpZyB7XG4gIGRvbWFpbk5hbWU6IHN0cmluZztcbiAgaG9zdGVkWm9uZT86IEZqYWxsSG9zdGVkWm9uZTtcbiAgY2VydGlmaWNhdGU/OiBDZXJ0aWZpY2F0ZTtcbiAgLy8gT3B0aW9uYWw6IFNldCBpZGVudGlmaWVyIGZvciByb3V0aW5nIHBvbGljaWVzIChhdXRvLWdlbmVyYXRlZCBpZiBub3QgcHJvdmlkZWQpXG4gIHNldElkZW50aWZpZXI/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTGF0ZW5jeURvbWFpbkNvbmZpZyBleHRlbmRzIERvbWFpbkJhc2VDb25maWcge1xuICAvLyBTZXQgdG8gZW5hYmxlIGxhdGVuY3kgYmFzZWQgcm91dGluZ1xuICByZWdpb246IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBXZWlnaHRlZERvbWFpbkNvbmZpZyBleHRlbmRzIERvbWFpbkJhc2VDb25maWcge1xuICAvLyBTZXQgdG8gZW5hYmxlIHdlaWdodGVkIHJvdXRpbmdcbiAgd2VpZ2h0OiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgR2VvTG9jYXRpb25Eb21haW5Db25maWcgZXh0ZW5kcyBEb21haW5CYXNlQ29uZmlnIHtcbiAgLy8gU2V0IHRvIGVuYWJsZSBnZW9sb2NhdGlvbiBiYXNlZCByb3V0aW5nXG4gIGdlb0xvY2F0aW9uOiBHZW9Mb2NhdGlvbjtcbn1cblxuZXhwb3J0IHR5cGUgRG9tYWluQ29uZmlnID1cbiAgfCBEb21haW5CYXNlQ29uZmlnXG4gIHwgTGF0ZW5jeURvbWFpbkNvbmZpZ1xuICB8IFdlaWdodGVkRG9tYWluQ29uZmlnXG4gIHwgR2VvTG9jYXRpb25Eb21haW5Db25maWc7XG5cbmV4cG9ydCB0eXBlIEZhcmdhdGVDbHVzdGVyUHJvcHMgPSB7XG4gIGVjclJlcG9zaXRvcnk6IFJlcG9zaXRvcnkgfCBSZXBvc2l0b3J5SW1hZ2U7XG4gIGNsdXN0ZXJOYW1lOiBzdHJpbmc7XG4gIGNvbnRhaW5lckNvbW1hbmQ/OiBzdHJpbmdbXTtcbiAgY29udGFpbmVyRW52aXJvbm1lbnQ/OiBLZXlWYWx1ZTtcbiAgY29udGFpbmVyU2VjcmV0cz86IENvbnRhaW5lclNlY3JldDtcbiAgY29udGFpbmVyU2VjcmV0c0ltcG9ydD86IHtcbiAgICBba2V5OiBzdHJpbmddOiBTZWNyZXRJbXBvcnQ7XG4gIH07XG4gIGNvbnRhaW5lclBvcnQ/OiBudW1iZXI7XG4gIGNwdT86IG51bWJlcjtcbiAgZG9tYWluQ29uZmlnPzogRG9tYWluQ29uZmlnO1xuICBkZXNpcmVkQ291bnQ/OiBudW1iZXI7XG4gIGhlYWx0aENoZWNrUGF0aD86IHN0cmluZztcbiAgbGlzdGVuZXJQb3J0PzogbnVtYmVyO1xuICBtZW1vcnlMaW1pdE1pQj86IG51bWJlcjtcbiAgcHVibGljTG9hZEJhbGFuY2VyPzogYm9vbGVhbjtcbiAgcHJvdG9jb2w6IFByb3RvY29sO1xuICBzY2FsaW5nVHlwZT86IFNjYWxpbmdUeXBlO1xuICBzZXJ2aWNlTmFtZTogc3RyaW5nO1xuICB0YXNrUm9sZUlubGluZVBvbGljaWVzPzoge1xuICAgIFtuYW1lOiBzdHJpbmddOiBQb2xpY3lEb2N1bWVudDtcbiAgfTtcbiAgdGFza1JvbGVNYW5hZ2VkUG9saWNpZXM/OiBJTWFuYWdlZFBvbGljeVtdO1xuICB2cGM/OiBJVnBjO1xufTtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgRmFyZ2F0ZUNsdXN0ZXIgZXh0ZW5kcyBDb25zdHJ1Y3QgaW1wbGVtZW50cyBJQ29ubmVjdGFibGUge1xuICBwdWJsaWMgY29ubmVjdGlvbnM6IENvbm5lY3Rpb25zO1xuXG4gIHByaXZhdGUgY2x1c3RlcjogQ2RrQ2x1c3RlcjtcbiAgcHJpdmF0ZSBsb2FkQmFsYW5jZXI6IEFwcGxpY2F0aW9uTG9hZEJhbGFuY2VyO1xuICBwcml2YXRlIGV4ZWN1dGlvblJvbGU6IFJvbGU7XG4gIHByaXZhdGUgdGFza0RlZmluaXRpb246IEZhcmdhdGVUYXNrRGVmaW5pdGlvbjtcbiAgcHJpdmF0ZSBjb250YWluZXJEZWZpbml0aW9uOiBDb250YWluZXJEZWZpbml0aW9uO1xuICBwcml2YXRlIGZhcmdhdGVTZXJ2aWNlOiBGYXJnYXRlU2VydmljZTtcbiAgcHJpdmF0ZSBzY2FsaW5nUG9saWN5OiBUYXJnZXRUcmFja2luZ1NjYWxpbmdQb2xpY3k7XG4gIHByaXZhdGUgaG9zdGVkWm9uZTogSUhvc3RlZFpvbmU7XG4gIHByaXZhdGUgY2VydGlmaWNhdGU6IENlcnRpZmljYXRlO1xuICBwcml2YXRlIGFSZWNvcmQ6IEFSZWNvcmQ7XG4gIHByaXZhdGUgbG9hZEJhbGFuY2VyTGlzdGVuZXI6IEFwcGxpY2F0aW9uTGlzdGVuZXI7XG5cbiAgcHJpdmF0ZSBzZWNyZXRzOiB7XG4gICAgW2tleTogc3RyaW5nXTogRWNzU2VjcmV0O1xuICB9ID0ge307XG5cbiAgcHJpdmF0ZSBzY29wZTogQ29uc3RydWN0O1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBGYXJnYXRlQ2x1c3RlclByb3BzKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkKTtcblxuICAgIHRoaXMuc2NvcGUgPSBzY29wZTtcblxuICAgIHRoaXMuYWRkQ2x1c3Rlcihwcm9wcyk7XG4gICAgdGhpcy5hZGRTZWNyZXRzKHByb3BzKTtcbiAgICB0aGlzLmltcG9ydFNlY3JldHMocHJvcHMpO1xuICAgIHRoaXMuYWRkRXhlY3V0aW9uUm9sZShwcm9wcyk7XG4gICAgdGhpcy5hZGRUYXNrRGVmaW5pdGlvbihwcm9wcyk7XG4gICAgdGhpcy5hZGRDb250YWluZXJEZWZpbml0aW9uKHByb3BzKTtcbiAgICB0aGlzLmFkZEZhcmdhdGVTZXJ2aWNlKHByb3BzKTtcbiAgICB0aGlzLmFkZExvYWRCYWxhbmNlcihwcm9wcyk7XG5cbiAgICBpZiAocHJvcHMuZG9tYWluQ29uZmlnKSB0aGlzLmFkZEhvc3RlZFpvbmUocHJvcHMpO1xuXG4gICAgdGhpcy5hZGRMb2FkQmFsYW5jZXJMaXN0ZW5lcihwcm9wcyk7XG4gICAgdGhpcy5yZWdpc3RlckxvYWRCYWxhbmNlclRhcmdldHMocHJvcHMpO1xuXG4gICAgY29uc3QgY29udGFpbmVyUG9ydCA9IHByb3BzLmNvbnRhaW5lclBvcnQgfHwgODA7XG4gICAgdGhpcy5jb25uZWN0aW9ucyA9IG5ldyBDb25uZWN0aW9ucyh7XG4gICAgICBzZWN1cml0eUdyb3VwczogdGhpcy5mYXJnYXRlU2VydmljZS5jb25uZWN0aW9ucy5zZWN1cml0eUdyb3VwcyxcbiAgICAgIGRlZmF1bHRQb3J0OiBQb3J0LnRjcChjb250YWluZXJQb3J0KVxuICAgIH0pO1xuICB9XG5cbiAgYWRkQ2x1c3Rlcihwcm9wczogRmFyZ2F0ZUNsdXN0ZXJQcm9wcykge1xuICAgIHRoaXMuY2x1c3RlciA9IG5ldyBDZGtDbHVzdGVyKHRoaXMsIGAke3Byb3BzLmNsdXN0ZXJOYW1lfWAsIHtcbiAgICAgIHZwYzogcHJvcHMudnBjLFxuICAgICAgY2x1c3Rlck5hbWU6IHByb3BzLmNsdXN0ZXJOYW1lLFxuICAgICAgY29udGFpbmVySW5zaWdodHNWMjogQ29udGFpbmVySW5zaWdodHMuRU5BQkxFRCxcbiAgICAgIGVuYWJsZUZhcmdhdGVDYXBhY2l0eVByb3ZpZGVyczogdHJ1ZVxuICAgIH0pO1xuXG4gICAgLy8gT3V0cHV0IHVzZWQgdG8gYXV0by1kZXRlY3QgZGVwbG95YWJsZSBjbHV0ZXJcbiAgICBuZXcgQ2ZuT3V0cHV0KHRoaXMsIGAke3Byb3BzLmNsdXN0ZXJOYW1lfURlcGxveWFibGVDbHVzdGVyYCwge1xuICAgICAga2V5OiBgJHtwcm9wcy5jbHVzdGVyTmFtZX1EZXBsb3lhYmxlQ2x1c3RlcmAsXG4gICAgICBleHBvcnROYW1lOiBgJHtwcm9wcy5jbHVzdGVyTmFtZX1EZXBsb3lhYmxlQ2x1c3RlcmAsXG4gICAgICB2YWx1ZTogdGhpcy5jbHVzdGVyLmNsdXN0ZXJBcm5cbiAgICB9KTtcblxuICAgIC8vIEV4cG9ydCBjbHVzdGVyIEFSTiBmb3IgbW9uaXRvcmluZ1xuICAgIG5ldyBDZm5PdXRwdXQodGhpcywgYCR7cHJvcHMuY2x1c3Rlck5hbWV9Q2x1c3RlckFybmAsIHtcbiAgICAgIGtleTogXCJDbHVzdGVyQXJuXCIsXG4gICAgICBleHBvcnROYW1lOiBgJHtwcm9wcy5jbHVzdGVyTmFtZX1DbHVzdGVyQXJuYCxcbiAgICAgIHZhbHVlOiB0aGlzLmNsdXN0ZXIuY2x1c3RlckFybixcbiAgICAgIGRlc2NyaXB0aW9uOiBgRUNTIENsdXN0ZXIgQVJOIGZvciAke3Byb3BzLmNsdXN0ZXJOYW1lfWBcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiAjdG9kbzogY2hhbmdlIHRoaXMgdG8gY3JlYXRlIG5ldyBzZWNyZXRzIGluc3RlYWRcbiAgICogQGRlcHJlY2F0ZWQgdXNlIGltcG9ydFNlY3JldHMgaW5zdGVhZFxuICAgKi9cbiAgYWRkU2VjcmV0cyhwcm9wczogRmFyZ2F0ZUNsdXN0ZXJQcm9wcykge1xuICAgIC8vIENvbnRhaW5lciBTZWNyZXRzXG4gICAgY29uc3QgY29udGFpbmVyU2VjcmV0ID0gU2VjcmV0LmZyb21TZWNyZXROYW1lVjIoXG4gICAgICB0aGlzLFxuICAgICAgYCR7cHJvcHMuY2x1c3Rlck5hbWV9U2VjcmV0YCxcbiAgICAgIGAvJHtwcm9wcy5jbHVzdGVyTmFtZX0vJHtwcm9wcy5zZXJ2aWNlTmFtZX1gXG4gICAgKTtcblxuICAgIGZvciAoY29uc3Qgc2VjcmV0RmllbGQgaW4gcHJvcHMuY29udGFpbmVyU2VjcmV0cykge1xuICAgICAgdGhpcy5zZWNyZXRzW3NlY3JldEZpZWxkXSA9IEVjc1NlY3JldC5mcm9tU2VjcmV0c01hbmFnZXIoXG4gICAgICAgIGNvbnRhaW5lclNlY3JldCxcbiAgICAgICAgc2VjcmV0RmllbGRcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEF1dG9tYXRpY2FsbHkgaW1wb3J0IHNlY3JldHMgZnJvbSBhbm90aGVyIHJlc291cmNlIG9yIHN0YWNrXG4gICAqL1xuICBpbXBvcnRTZWNyZXRzKHByb3BzOiBGYXJnYXRlQ2x1c3RlclByb3BzKSB7XG4gICAgaWYgKCFwcm9wcy5jb250YWluZXJTZWNyZXRzSW1wb3J0KSByZXR1cm47XG5cbiAgICBmb3IgKGNvbnN0IGtleSBpbiBwcm9wcy5jb250YWluZXJTZWNyZXRzSW1wb3J0KSB7XG4gICAgICBjb25zdCBpbXBvcnRTZWNyZXQgPSBwcm9wcy5jb250YWluZXJTZWNyZXRzSW1wb3J0W2tleV07XG5cbiAgICAgIC8vIHRvZG86IEkgdGhpbmsgSUQgbmVlZHMgdG8gYmUgYSBuZXcgdmFsdWUgYXMgaXQgSUQncyB0aGUgSU1QT1JUIG5vdCB0aGUgc2VjcmV0IGl0c2VsZj9cblxuICAgICAgLy8gQ29uc3RydWN0IHRoZSBBV1MgSVNlY3JldCBvYmplY3RcbiAgICAgIGNvbnN0IGlTZWNyZXQgPSBTZWNyZXQuZnJvbVNlY3JldE5hbWVWMihcbiAgICAgICAgdGhpcyxcbiAgICAgICAgaW1wb3J0U2VjcmV0LmlkLFxuICAgICAgICBpbXBvcnRTZWNyZXQubmFtZVxuICAgICAgKTtcblxuICAgICAgdGhpcy5zZWNyZXRzW2tleV0gPSBFY3NTZWNyZXQuZnJvbVNlY3JldHNNYW5hZ2VyKFxuICAgICAgICBpU2VjcmV0LFxuICAgICAgICBpbXBvcnRTZWNyZXQuZmllbGRcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgYWRkRXhlY3V0aW9uUm9sZShwcm9wczogRmFyZ2F0ZUNsdXN0ZXJQcm9wcykge1xuICAgIHRoaXMuZXhlY3V0aW9uUm9sZSA9IG5ldyBSb2xlKFxuICAgICAgdGhpcyxcbiAgICAgIGAke3Byb3BzLnNlcnZpY2VOYW1lfUV4ZWN1dGlvblJvbGUke1N0YWNrLm9mKHRoaXMpLnJlZ2lvbn1gLFxuICAgICAge1xuICAgICAgICByb2xlTmFtZTogYCR7cHJvcHMuc2VydmljZU5hbWV9RXhlY3V0aW9uUm9sZSR7U3RhY2sub2YodGhpcykucmVnaW9ufWAsXG4gICAgICAgIGRlc2NyaXB0aW9uOiBgJHtwcm9wcy5zZXJ2aWNlTmFtZX0gRXhlY3V0aW9uIFJvbGVgLFxuICAgICAgICBtYW5hZ2VkUG9saWNpZXM6IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBtYW5hZ2VkUG9saWN5QXJuOlxuICAgICAgICAgICAgICBcImFybjphd3M6aWFtOjphd3M6cG9saWN5L3NlcnZpY2Utcm9sZS9BbWF6b25FQ1NUYXNrRXhlY3V0aW9uUm9sZVBvbGljeVwiXG4gICAgICAgICAgfVxuICAgICAgICBdLFxuICAgICAgICBpbmxpbmVQb2xpY2llczoge1xuICAgICAgICAgIFtcInJlYWRTZWNyZXRzXCJdOiBuZXcgUG9saWN5RG9jdW1lbnQoe1xuICAgICAgICAgICAgc3RhdGVtZW50czogW1xuICAgICAgICAgICAgICBuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgICAgICAgICBhY3Rpb25zOiBbXG4gICAgICAgICAgICAgICAgICBcInNlY3JldHNtYW5hZ2VyOkdldFNlY3JldFZhbHVlXCIsXG4gICAgICAgICAgICAgICAgICBcInNlY3JldHNtYW5hZ2VyOkRlc2NyaWJlU2VjcmV0XCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIHJlc291cmNlczogW1wiKlwiXSAvLyBUT0RPOiBTZXQgdGhpcyB0byB0aGUgc2VjcmV0IEFSTlxuICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgXVxuICAgICAgICAgIH0pLFxuICAgICAgICAgIFtcImRlY3J5cHRTZWNyZXRzXCJdOiBuZXcgUG9saWN5RG9jdW1lbnQoe1xuICAgICAgICAgICAgc3RhdGVtZW50czogW1xuICAgICAgICAgICAgICBuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgICAgICAgICBhY3Rpb25zOiBbXCJrbXM6RGVjcnlwdFwiXSxcbiAgICAgICAgICAgICAgICByZXNvdXJjZXM6IFtcIipcIl0gLy8gVE9ETzogU2V0IHRoaXMgdG8gdGhlIEtNUyBBcm5cbiAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIF1cbiAgICAgICAgICB9KSxcbiAgICAgICAgICBbXCJlY3NFeGVjdXRlQ29tbWFuZFwiXTogbmV3IFBvbGljeURvY3VtZW50KHtcbiAgICAgICAgICAgIHN0YXRlbWVudHM6IFtcbiAgICAgICAgICAgICAgbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgICAgICAgICAgYWN0aW9uczogW1xuICAgICAgICAgICAgICAgICAgXCJzc21tZXNzYWdlczpDcmVhdGVDb250cm9sQ2hhbm5lbFwiLFxuICAgICAgICAgICAgICAgICAgXCJzc21tZXNzYWdlczpDcmVhdGVEYXRhQ2hhbm5lbFwiLFxuICAgICAgICAgICAgICAgICAgXCJzc21tZXNzYWdlczpPcGVuQ29udHJvbENoYW5uZWxcIixcbiAgICAgICAgICAgICAgICAgIFwic3NtbWVzc2FnZXM6T3BlbkRhdGFDaGFubmVsXCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIGVmZmVjdDogRWZmZWN0LkFMTE9XLFxuICAgICAgICAgICAgICAgIHJlc291cmNlczogW1wiKlwiXVxuICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgXVxuICAgICAgICAgIH0pXG4gICAgICAgIH0sXG4gICAgICAgIGFzc3VtZWRCeTogbmV3IENvbXBvc2l0ZVByaW5jaXBhbChcbiAgICAgICAgICBuZXcgU2VydmljZVByaW5jaXBhbChcImVjcy10YXNrcy5hbWF6b25hd3MuY29tXCIpXG4gICAgICAgIClcbiAgICAgIH1cbiAgICApO1xuICB9XG5cbiAgYWRkVGFza0RlZmluaXRpb24ocHJvcHM6IEZhcmdhdGVDbHVzdGVyUHJvcHMpIHtcbiAgICB0aGlzLnRhc2tEZWZpbml0aW9uID0gbmV3IEZhcmdhdGVUYXNrRGVmaW5pdGlvbihcbiAgICAgIHRoaXMsXG4gICAgICBgJHtwcm9wcy5zZXJ2aWNlTmFtZX1UYXNrRGVmaW5pdGlvbmAsXG4gICAgICB7XG4gICAgICAgIGNwdTogcHJvcHMuY3B1IHx8IDI1NixcbiAgICAgICAgZXhlY3V0aW9uUm9sZTogdGhpcy5leGVjdXRpb25Sb2xlLFxuICAgICAgICB0YXNrUm9sZTogbmV3IFJvbGUoXG4gICAgICAgICAgdGhpcyxcbiAgICAgICAgICBgJHtwcm9wcy5zZXJ2aWNlTmFtZX1UYXNrUm9sZSR7U3RhY2sub2YodGhpcykucmVnaW9ufWAsXG4gICAgICAgICAge1xuICAgICAgICAgICAgcm9sZU5hbWU6IGAke3Byb3BzLnNlcnZpY2VOYW1lfVRhc2tSb2xlJHtTdGFjay5vZih0aGlzKS5yZWdpb259YCxcbiAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBgJHtwcm9wcy5zZXJ2aWNlTmFtZX0gVGFzayBSb2xlYCxcbiAgICAgICAgICAgIGlubGluZVBvbGljaWVzOiBwcm9wcy50YXNrUm9sZUlubGluZVBvbGljaWVzLFxuICAgICAgICAgICAgbWFuYWdlZFBvbGljaWVzOiBwcm9wcy50YXNrUm9sZU1hbmFnZWRQb2xpY2llcyxcbiAgICAgICAgICAgIGFzc3VtZWRCeTogbmV3IENvbXBvc2l0ZVByaW5jaXBhbChcbiAgICAgICAgICAgICAgbmV3IFNlcnZpY2VQcmluY2lwYWwoXCJlY3MtdGFza3MuYW1hem9uYXdzLmNvbVwiKVxuICAgICAgICAgICAgKVxuICAgICAgICAgIH1cbiAgICAgICAgKSxcbiAgICAgICAgbWVtb3J5TGltaXRNaUI6IHByb3BzLm1lbW9yeUxpbWl0TWlCIHx8IDUxMlxuICAgICAgfVxuICAgICk7XG4gIH1cblxuICBhZGRDb250YWluZXJEZWZpbml0aW9uKHByb3BzOiBGYXJnYXRlQ2x1c3RlclByb3BzKSB7XG4gICAgdGhpcy5jb250YWluZXJEZWZpbml0aW9uID0gdGhpcy50YXNrRGVmaW5pdGlvbi5hZGRDb250YWluZXIoXG4gICAgICBgJHtwcm9wcy5zZXJ2aWNlTmFtZX1Db250YWluZXJEZWZpbml0aW9uYCxcbiAgICAgIHtcbiAgICAgICAgaW1hZ2U6IHRoaXMuZ2V0SW1hZ2UocHJvcHMpLFxuICAgICAgICBjb250YWluZXJOYW1lOiBwcm9wcy5zZXJ2aWNlTmFtZSxcbiAgICAgICAgZW52aXJvbm1lbnQ6IHtcbiAgICAgICAgICAuLi5wcm9wcy5jb250YWluZXJFbnZpcm9ubWVudFxuICAgICAgICB9LFxuICAgICAgICBjb21tYW5kOiBwcm9wcy5jb250YWluZXJDb21tYW5kLFxuICAgICAgICBzZWNyZXRzOiB7XG4gICAgICAgICAgLi4udGhpcy5zZWNyZXRzXG4gICAgICAgIH0sXG4gICAgICAgIC8vdG9kbzogcHJvdmlkZSBoZWFsdGggY2hlY2sgb3B0aW9uc1xuICAgICAgICBoZWFsdGhDaGVjazoge1xuICAgICAgICAgIGNvbW1hbmQ6IFtcbiAgICAgICAgICAgIFwiQ01ELVNIRUxMXCIsXG4gICAgICAgICAgICAvLyBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQW1hem9uRUNTL2xhdGVzdC9kZXZlbG9wZXJndWlkZS92aWV3LWNvbnRhaW5lci1oZWFsdGguaHRtbFxuICAgICAgICAgICAgLy8gID4+IHByb2MvMS9mZC8xIDI+JjEgcmVkaXJlY3RzIHN0ZG91dCBhbmQgc3RkZXJyIG9mIHRoZSBoZWFsdGggY2hlY2sgdG8gQ2xvdWRXYXRjaCBsb2dzXG4gICAgICAgICAgICAvLyBgY3VybCAtZiBodHRwOi8vbG9jYWxob3N0OiR7cHJvcHMuY29udGFpbmVyUG9ydH0vID4+IC9wcm9jLzEvZmQvMSAyPiYxICB8fCBleGl0IDFgXG4gICAgICAgICAgICBgY3VybCAtZiBodHRwOi8vbG9jYWxob3N0OiR7cHJvcHMuY29udGFpbmVyUG9ydH0vIHx8IGV4aXQgMWBcbiAgICAgICAgICBdXG4gICAgICAgIH0sXG4gICAgICAgIGxvZ2dpbmc6IG5ldyBBd3NMb2dEcml2ZXIoe1xuICAgICAgICAgIHN0cmVhbVByZWZpeDogYC9lY3MvJHtwcm9wcy5jbHVzdGVyTmFtZX0vJHtwcm9wcy5zZXJ2aWNlTmFtZX1gLFxuICAgICAgICAgIGxvZ1JldGVudGlvbjogMTRcbiAgICAgICAgfSksXG4gICAgICAgIHBvcnRNYXBwaW5nczogcHJvcHMuY29udGFpbmVyUG9ydFxuICAgICAgICAgID8gW3sgY29udGFpbmVyUG9ydDogcHJvcHMuY29udGFpbmVyUG9ydCB9XVxuICAgICAgICAgIDogW3sgY29udGFpbmVyUG9ydDogODAgfV1cbiAgICAgIH1cbiAgICApO1xuICB9XG5cbiAgYWRkRmFyZ2F0ZVNlcnZpY2UocHJvcHM6IEZhcmdhdGVDbHVzdGVyUHJvcHMpIHtcbiAgICB0aGlzLmZhcmdhdGVTZXJ2aWNlID0gbmV3IEZhcmdhdGVTZXJ2aWNlKFxuICAgICAgdGhpcyxcbiAgICAgIGAke3Byb3BzLnNlcnZpY2VOYW1lfUZhcmdhdGVTZXJ2aWNlYCxcbiAgICAgIHtcbiAgICAgICAgY2lyY3VpdEJyZWFrZXI6IHsgcm9sbGJhY2s6IHRydWUgfSxcbiAgICAgICAgY2x1c3RlcjogdGhpcy5jbHVzdGVyLFxuICAgICAgICBkZXNpcmVkQ291bnQ6IDIsXG4gICAgICAgIGVuYWJsZUVDU01hbmFnZWRUYWdzOiB0cnVlLFxuICAgICAgICBlbmFibGVFeGVjdXRlQ29tbWFuZDogdHJ1ZSxcbiAgICAgICAgcHJvcGFnYXRlVGFnczogUHJvcGFnYXRlZFRhZ1NvdXJjZS5TRVJWSUNFLFxuICAgICAgICBzZXJ2aWNlTmFtZTogYCR7cHJvcHMuc2VydmljZU5hbWV9YCxcbiAgICAgICAgdGFza0RlZmluaXRpb246IHRoaXMudGFza0RlZmluaXRpb24sXG4gICAgICAgIG1pbkhlYWx0aHlQZXJjZW50OiAxMDAsXG4gICAgICAgIG1heEhlYWx0aHlQZXJjZW50OiAyMDBcbiAgICAgIH1cbiAgICApO1xuXG4gICAgLy8gT3V0cHV0IHVzZWQgdG8gZGV0ZWN0IGRlcGxveWFibGUgc2VydmljZVxuICAgIG5ldyBDZm5PdXRwdXQodGhpcywgYCR7cHJvcHMuY2x1c3Rlck5hbWV9RGVwbG95YWJsZVNlcnZpY2VgLCB7XG4gICAgICBrZXk6IGAke3Byb3BzLmNsdXN0ZXJOYW1lfURlcGxveWFibGVTZXJ2aWNlYCxcbiAgICAgIGV4cG9ydE5hbWU6IGAke3Byb3BzLmNsdXN0ZXJOYW1lfURlcGxveWFibGVTZXJ2aWNlYCxcbiAgICAgIHZhbHVlOiB0aGlzLmZhcmdhdGVTZXJ2aWNlLnNlcnZpY2VBcm5cbiAgICB9KTtcblxuICAgIC8vIEV4cG9ydCBzZXJ2aWNlIEFSTiBmb3IgbW9uaXRvcmluZ1xuICAgIG5ldyBDZm5PdXRwdXQodGhpcywgYCR7cHJvcHMuY2x1c3Rlck5hbWV9U2VydmljZUFybmAsIHtcbiAgICAgIGtleTogXCJTZXJ2aWNlQXJuXCIsXG4gICAgICBleHBvcnROYW1lOiBgJHtwcm9wcy5jbHVzdGVyTmFtZX1TZXJ2aWNlQXJuYCxcbiAgICAgIHZhbHVlOiB0aGlzLmZhcmdhdGVTZXJ2aWNlLnNlcnZpY2VBcm4sXG4gICAgICBkZXNjcmlwdGlvbjogYEVDUyBTZXJ2aWNlIEFSTiBmb3IgJHtwcm9wcy5zZXJ2aWNlTmFtZX1gXG4gICAgfSk7XG4gIH1cblxuICBhZGRTY2FsaW5nUG9saWN5KHByb3BzOiBGYXJnYXRlQ2x1c3RlclByb3BzKSB7XG4gICAgdGhpcy5zY2FsaW5nUG9saWN5ID0gbmV3IFRhcmdldFRyYWNraW5nU2NhbGluZ1BvbGljeShcbiAgICAgIHRoaXMsXG4gICAgICBgJHtwcm9wcy5zZXJ2aWNlTmFtZX1TY2FsaW5nUG9saWN5YCxcbiAgICAgIHtcbiAgICAgICAgcG9saWN5TmFtZTogYCR7cHJvcHMuc2VydmljZU5hbWV9U2NhbGluZ1BvbGljeWAsXG4gICAgICAgIHNjYWxpbmdUYXJnZXQ6IG5ldyBTY2FsYWJsZVRhcmdldChcbiAgICAgICAgICB0aGlzLFxuICAgICAgICAgIGAke3Byb3BzLnNlcnZpY2VOYW1lfXNjYWxhYmxlVGFyZ2V0YCxcbiAgICAgICAgICB7XG4gICAgICAgICAgICBtYXhDYXBhY2l0eTogMTAsXG4gICAgICAgICAgICBtaW5DYXBhY2l0eTogMixcbiAgICAgICAgICAgIHJlc291cmNlSWQ6IGBzZXJ2aWNlLyR7dGhpcy5jbHVzdGVyLmNsdXN0ZXJOYW1lfS8ke3RoaXMuZmFyZ2F0ZVNlcnZpY2Uuc2VydmljZU5hbWV9YCxcbiAgICAgICAgICAgIHNjYWxhYmxlRGltZW5zaW9uOiBcImVjczpzZXJ2aWNlOkRlc2lyZWRDb3VudFwiLFxuICAgICAgICAgICAgc2VydmljZU5hbWVzcGFjZTogU2VydmljZU5hbWVzcGFjZS5FQ1NcbiAgICAgICAgICB9XG4gICAgICAgICksXG4gICAgICAgIHRhcmdldFZhbHVlOiA1MCxcbiAgICAgICAgc2NhbGVPdXRDb29sZG93bjogRHVyYXRpb24uc2Vjb25kcyg2MCksXG4gICAgICAgIHNjYWxlSW5Db29sZG93bjogRHVyYXRpb24uc2Vjb25kcyg2MCksXG4gICAgICAgIHByZWRlZmluZWRNZXRyaWM6XG4gICAgICAgICAgcHJvcHMuc2NhbGluZ1R5cGUgPT0gU2NhbGluZ1R5cGUuTUVNT1JZXG4gICAgICAgICAgICA/IFByZWRlZmluZWRNZXRyaWMuRUNTX1NFUlZJQ0VfQVZFUkFHRV9NRU1PUllfVVRJTElaQVRJT05cbiAgICAgICAgICAgIDogUHJlZGVmaW5lZE1ldHJpYy5FQ1NfU0VSVklDRV9BVkVSQUdFX0NQVV9VVElMSVpBVElPTlxuICAgICAgfVxuICAgICk7XG4gIH1cblxuICByZWdpc3RlckxvYWRCYWxhbmNlclRhcmdldHMocHJvcHM6IEZhcmdhdGVDbHVzdGVyUHJvcHMpIHtcbiAgICB0aGlzLmZhcmdhdGVTZXJ2aWNlLnJlZ2lzdGVyTG9hZEJhbGFuY2VyVGFyZ2V0cyh7XG4gICAgICBjb250YWluZXJOYW1lOiB0aGlzLmNvbnRhaW5lckRlZmluaXRpb24uY29udGFpbmVyTmFtZSxcbiAgICAgIGNvbnRhaW5lclBvcnQ6IHRoaXMuY29udGFpbmVyRGVmaW5pdGlvbi5jb250YWluZXJQb3J0LFxuICAgICAgbmV3VGFyZ2V0R3JvdXBJZDogYCR7cHJvcHMuc2VydmljZU5hbWV9VGFyZ2V0R3JvdXBgLFxuICAgICAgbGlzdGVuZXI6IExpc3RlbmVyQ29uZmlnLmFwcGxpY2F0aW9uTGlzdGVuZXIodGhpcy5sb2FkQmFsYW5jZXJMaXN0ZW5lciwge1xuICAgICAgICBwb3J0OiBwcm9wcy5jb250YWluZXJQb3J0LFxuICAgICAgICBwcm90b2NvbDogQXBwbGljYXRpb25Qcm90b2NvbC5IVFRQLFxuICAgICAgICBoZWFsdGhDaGVjazoge1xuICAgICAgICAgIGludGVydmFsOiBEdXJhdGlvbi5zZWNvbmRzKDEyMCksXG4gICAgICAgICAgcGF0aDogcHJvcHMuaGVhbHRoQ2hlY2tQYXRoIHx8IFwiL1wiLFxuICAgICAgICAgIHBvcnQ6IHByb3BzLmNvbnRhaW5lclBvcnQgPyBgJHtwcm9wcy5jb250YWluZXJQb3J0fWAgOiBcInRyYWZmaWMtcG9ydFwiLFxuICAgICAgICAgIHRpbWVvdXQ6IER1cmF0aW9uLnNlY29uZHMoMTApXG4gICAgICAgIH1cbiAgICAgIH0pXG4gICAgfSk7XG4gIH1cblxuICBhZGRMb2FkQmFsYW5jZXIocHJvcHM6IEZhcmdhdGVDbHVzdGVyUHJvcHMpIHtcbiAgICAvLyBUcnVuY2F0ZSB0aGUgbG9hZCBiYWxhbmNlciBuYW1lIHRvIGVuc3VyZSBpdCBkb2VzIG5vdCBleGNlZWQgdGhlIDMyIGNoYXJhY3RlciBBV1MgbGltaXRcbiAgICBjb25zdCBkZWZhdWx0TG9hZEJhbGFuY2VyTmFtZSA9IGAke3Byb3BzLnNlcnZpY2VOYW1lfUxvYWRCYWxhbmNlcmA7XG4gICAgY29uc3Qgc3VwcG9ydGVkTmFtZUxlbmd0aCA9IDMyO1xuXG4gICAgbGV0IHRydW5jYXRlZExvYWRCYWxhbmNlck5hbWUgPVxuICAgICAgZGVmYXVsdExvYWRCYWxhbmNlck5hbWUubGVuZ3RoID4gc3VwcG9ydGVkTmFtZUxlbmd0aFxuICAgICAgICA/IGRlZmF1bHRMb2FkQmFsYW5jZXJOYW1lLnN1YnN0cmluZygwLCBzdXBwb3J0ZWROYW1lTGVuZ3RoKVxuICAgICAgICA6IGRlZmF1bHRMb2FkQmFsYW5jZXJOYW1lO1xuXG4gICAgLy8gUmVtb3ZlIGFueSB0cmFpbGluZyBoeXBoZW5zIHRoYXQgbWlnaHQgYmUgaW50cm9kdWNlZCBieSB0cnVuY2F0aW9uXG4gICAgdHJ1bmNhdGVkTG9hZEJhbGFuY2VyTmFtZSA9IHRydW5jYXRlZExvYWRCYWxhbmNlck5hbWUucmVwbGFjZSgvLSskLywgXCJcIik7XG5cbiAgICB0aGlzLmxvYWRCYWxhbmNlciA9IG5ldyBBcHBsaWNhdGlvbkxvYWRCYWxhbmNlcihcbiAgICAgIHRoaXMsXG4gICAgICBgJHtwcm9wcy5jbHVzdGVyTmFtZX1Mb2FkQmFsYW5jZXJgLFxuICAgICAge1xuICAgICAgICB2cGM6IHRoaXMuY2x1c3Rlci52cGMsXG4gICAgICAgIGludGVybmV0RmFjaW5nOiB0cnVlLFxuICAgICAgICBsb2FkQmFsYW5jZXJOYW1lOiB0cnVuY2F0ZWRMb2FkQmFsYW5jZXJOYW1lLFxuICAgICAgICB2cGNTdWJuZXRzOiB7XG4gICAgICAgICAgc3VibmV0VHlwZTogU3VibmV0VHlwZS5QVUJMSUNcbiAgICAgICAgfVxuICAgICAgfVxuICAgICk7XG5cbiAgICBuZXcgQ2ZuT3V0cHV0KHRoaXMsIGAke3Byb3BzLmNsdXN0ZXJOYW1lfUxvYWRCYWxhbmNlckRuc05hbWVgLCB7XG4gICAgICBrZXk6IGAke3Byb3BzLmNsdXN0ZXJOYW1lfUxvYWRCYWxhbmNlckRuc05hbWVgLFxuICAgICAgZXhwb3J0TmFtZTogYCR7cHJvcHMuY2x1c3Rlck5hbWV9TG9hZEJhbGFuY2VyRG5zTmFtZWAsXG4gICAgICB2YWx1ZTogdGhpcy5sb2FkQmFsYW5jZXIubG9hZEJhbGFuY2VyRG5zTmFtZVxuICAgIH0pO1xuXG4gICAgLy8gRXhwb3J0IGxvYWQgYmFsYW5jZXIgVVJMIGZvciBtb25pdG9yaW5nXG4gICAgbmV3IENmbk91dHB1dCh0aGlzLCBgJHtwcm9wcy5jbHVzdGVyTmFtZX1Mb2FkQmFsYW5jZXJVcmxgLCB7XG4gICAgICBrZXk6IFwiTG9hZEJhbGFuY2VyVXJsXCIsXG4gICAgICBleHBvcnROYW1lOiBgJHtwcm9wcy5jbHVzdGVyTmFtZX1Mb2FkQmFsYW5jZXJVcmxgLFxuICAgICAgdmFsdWU6IGBodHRwOi8vJHt0aGlzLmxvYWRCYWxhbmNlci5sb2FkQmFsYW5jZXJEbnNOYW1lfWAsXG4gICAgICBkZXNjcmlwdGlvbjogYExvYWQgQmFsYW5jZXIgVVJMIGZvciAke3Byb3BzLmNsdXN0ZXJOYW1lfWBcbiAgICB9KTtcbiAgfVxuXG4gIGFkZExvYWRCYWxhbmNlckxpc3RlbmVyKHByb3BzOiBGYXJnYXRlQ2x1c3RlclByb3BzKSB7XG4gICAgaWYgKHRoaXMuY2VydGlmaWNhdGUpIHtcbiAgICAgIHRoaXMubG9hZEJhbGFuY2VyTGlzdGVuZXIgPSB0aGlzLmxvYWRCYWxhbmNlci5hZGRMaXN0ZW5lcihcbiAgICAgICAgYCR7cHJvcHMuc2VydmljZU5hbWV9TGlzdGVuZXJgLFxuICAgICAgICB7XG4gICAgICAgICAgcG9ydDogcHJvcHMucHJvdG9jb2wgPT0gUHJvdG9jb2wuSFRUUCA/IDgwIDogNDQzLFxuICAgICAgICAgIGNlcnRpZmljYXRlczogW3RoaXMuY2VydGlmaWNhdGVdXG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMubG9hZEJhbGFuY2VyTGlzdGVuZXIgPSB0aGlzLmxvYWRCYWxhbmNlci5hZGRMaXN0ZW5lcihcbiAgICAgICAgYCR7cHJvcHMuc2VydmljZU5hbWV9TGlzdGVuZXJgLFxuICAgICAgICB7XG4gICAgICAgICAgcG9ydDogcHJvcHMucHJvdG9jb2wgPT0gUHJvdG9jb2wuSFRUUCA/IDgwIDogNDQzXG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgYWRkSG9zdGVkWm9uZShwcm9wczogRmFyZ2F0ZUNsdXN0ZXJQcm9wcykge1xuICAgIGlmICghcHJvcHMuZG9tYWluQ29uZmlnKSByZXR1cm47XG5cbiAgICBpZiAoIXByb3BzLmRvbWFpbkNvbmZpZy5ob3N0ZWRab25lKSB7XG4gICAgICAvLyBDcmVhdGUgYSBuZXcgaG9zdGVkIHpvbmUgaWYgb25lIGlzIG5vdCBwcm92aWRlZFxuICAgICAgY29uc3QgaG9zdGVkWm9uZSA9IG5ldyBGamFsbEhvc3RlZFpvbmUoXG4gICAgICAgIHRoaXMsXG4gICAgICAgIGAke3Byb3BzLnNlcnZpY2VOYW1lfUhvc3RlZFpvbmVgLFxuICAgICAgICB7XG4gICAgICAgICAgem9uZU5hbWU6IHByb3BzLmRvbWFpbkNvbmZpZy5kb21haW5OYW1lXG4gICAgICAgIH1cbiAgICAgICk7XG5cbiAgICAgIHRoaXMuaG9zdGVkWm9uZSA9IGhvc3RlZFpvbmUuZ2V0SW50ZXJuYWxIb3N0ZWRab25lKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIE90aGVyd2lzZSB1c2UgdGhlIHByb3ZpZGVkIGhvc3RlZCB6b25lXG4gICAgICB0aGlzLmhvc3RlZFpvbmUgPSBwcm9wcy5kb21haW5Db25maWcuaG9zdGVkWm9uZS5nZXRJbnRlcm5hbEhvc3RlZFpvbmUoKTtcbiAgICB9XG5cbiAgICBpZiAoIXByb3BzLmRvbWFpbkNvbmZpZy5jZXJ0aWZpY2F0ZSkge1xuICAgICAgLy8gSWYgbm8gY2VydGlmaWNhdGUgaXMgcHJvdmlkZWQgLSBjcmVhdGUgYSBuZXcgb25lXG4gICAgICB0aGlzLmNlcnRpZmljYXRlID0gbmV3IENlcnRpZmljYXRlKFxuICAgICAgICB0aGlzLFxuICAgICAgICBgJHtwcm9wcy5zZXJ2aWNlTmFtZX1DZXJ0aWZpY2F0ZWAsXG4gICAgICAgIHtcbiAgICAgICAgICBkb21haW5OYW1lOiBwcm9wcy5kb21haW5Db25maWcuZG9tYWluTmFtZSxcbiAgICAgICAgICB2YWxpZGF0aW9uOiBDZXJ0aWZpY2F0ZVZhbGlkYXRpb24uZnJvbURucyh0aGlzLmhvc3RlZFpvbmUpXG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gQ2hlY2sgaWYgdGhpcyBpcyBhIG11bHRpLXJlZ2lvbi93ZWlnaHRlZC9nZW8gcm91dGluZyBjb25maWd1cmF0aW9uXG4gICAgY29uc3QgbGF0ZW5jeUNvbmZpZyA9IHByb3BzLmRvbWFpbkNvbmZpZyBhcyBMYXRlbmN5RG9tYWluQ29uZmlnO1xuICAgIGNvbnN0IHdlaWdodGVkQ29uZmlnID0gcHJvcHMuZG9tYWluQ29uZmlnIGFzIFdlaWdodGVkRG9tYWluQ29uZmlnO1xuICAgIGNvbnN0IGdlb0NvbmZpZyA9IHByb3BzLmRvbWFpbkNvbmZpZyBhcyBHZW9Mb2NhdGlvbkRvbWFpbkNvbmZpZztcblxuICAgIGNvbnN0IGhhc1JvdXRpbmdQb2xpY3k6IGJvb2xlYW4gPVxuICAgICAgISFsYXRlbmN5Q29uZmlnPy5yZWdpb24gfHxcbiAgICAgIHdlaWdodGVkQ29uZmlnPy53ZWlnaHQgIT09IHVuZGVmaW5lZCB8fFxuICAgICAgISFnZW9Db25maWc/Lmdlb0xvY2F0aW9uO1xuXG4gICAgLy8gR2VuZXJhdGUgc2V0SWRlbnRpZmllciBpZiBub3QgcHJvdmlkZWQgYW5kIHVzaW5nIHJvdXRpbmcgcG9saWNpZXNcbiAgICAvLyBBV1MgcmVxdWlyZXMgc2V0SWRlbnRpZmllciBmb3IgYWxsIHJvdXRpbmcgcG9saWNpZXMgKGxhdGVuY3ksIHdlaWdodGVkLCBnZW8sIGZhaWxvdmVyLCBtdWx0aXZhbHVlKVxuICAgIGxldCBzZXRJZGVudGlmaWVyID0gcHJvcHMuZG9tYWluQ29uZmlnLnNldElkZW50aWZpZXI7XG4gICAgaWYgKGhhc1JvdXRpbmdQb2xpY3kgJiYgIXNldElkZW50aWZpZXIpIHtcbiAgICAgIGlmIChsYXRlbmN5Q29uZmlnPy5yZWdpb24pIHtcbiAgICAgICAgc2V0SWRlbnRpZmllciA9IGAke3Byb3BzLnNlcnZpY2VOYW1lfS0ke2xhdGVuY3lDb25maWcucmVnaW9ufWA7XG4gICAgICB9IGVsc2UgaWYgKHdlaWdodGVkQ29uZmlnPy53ZWlnaHQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBzZXRJZGVudGlmaWVyID0gYCR7cHJvcHMuc2VydmljZU5hbWV9LXdlaWdodC0ke3dlaWdodGVkQ29uZmlnLndlaWdodH1gO1xuICAgICAgfSBlbHNlIGlmIChnZW9Db25maWc/Lmdlb0xvY2F0aW9uKSB7XG4gICAgICAgIHNldElkZW50aWZpZXIgPSBgJHtwcm9wcy5zZXJ2aWNlTmFtZX0tZ2VvYDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBBbHdheXMgY3JlYXRlIGEgbmV3IEFSZWNvcmQgZm9yIHRoaXMgZG9tYWluIGFuZCBhdHRhY2ggaXQgdG8gdGhlIGxvYWQgYmFsYW5jZXJcbiAgICB0aGlzLmFSZWNvcmQgPSBuZXcgQVJlY29yZChcbiAgICAgIHRoaXMsXG4gICAgICBgJHtwcm9wcy5zZXJ2aWNlTmFtZX0uJHtwcm9wcy5jbHVzdGVyTmFtZX0uJHtwcm9wcy5kb21haW5Db25maWcuZG9tYWluTmFtZX1BUmVjb3JkYCxcbiAgICAgIHtcbiAgICAgICAgcmVjb3JkTmFtZTogcHJvcHMuZG9tYWluQ29uZmlnLmRvbWFpbk5hbWUsXG4gICAgICAgIHpvbmU6IHRoaXMuaG9zdGVkWm9uZSxcbiAgICAgICAgdGFyZ2V0OiBSZWNvcmRUYXJnZXQuZnJvbUFsaWFzKFxuICAgICAgICAgIG5ldyBMb2FkQmFsYW5jZXJUYXJnZXQodGhpcy5sb2FkQmFsYW5jZXIsIHtcbiAgICAgICAgICAgIGV2YWx1YXRlVGFyZ2V0SGVhbHRoOiBoYXNSb3V0aW5nUG9saWN5XG4gICAgICAgICAgfSlcbiAgICAgICAgKSxcbiAgICAgICAgcmVnaW9uOiBsYXRlbmN5Q29uZmlnPy5yZWdpb24sXG4gICAgICAgIHdlaWdodDogd2VpZ2h0ZWRDb25maWc/LndlaWdodCxcbiAgICAgICAgZ2VvTG9jYXRpb246IGdlb0NvbmZpZz8uZ2VvTG9jYXRpb24sXG4gICAgICAgIC8vIFNldCBpZGVudGlmaWVyIGlzIHJlcXVpcmVkIGZvciByb3V0aW5nIHBvbGljaWVzIChsYXRlbmN5LCB3ZWlnaHRlZCwgZ2VvLCBmYWlsb3ZlciwgbXVsdGl2YWx1ZSlcbiAgICAgICAgc2V0SWRlbnRpZmllcjogc2V0SWRlbnRpZmllclxuICAgICAgfVxuICAgICk7XG4gIH1cblxuICBnZXRJbWFnZShwcm9wczogRmFyZ2F0ZUNsdXN0ZXJQcm9wcyk6IENvbnRhaW5lckltYWdlIHtcbiAgICBpZiAoIXByb3BzLmVjclJlcG9zaXRvcnkpXG4gICAgICByZXR1cm4gQ29udGFpbmVySW1hZ2UuZnJvbVJlZ2lzdHJ5KFwiYW1hem9uL2FtYXpvbi1lY3Mtc2FtcGxlXCIpO1xuICAgIGlmIChwcm9wcy5lY3JSZXBvc2l0b3J5IGluc3RhbmNlb2YgQ29udGFpbmVySW1hZ2UpXG4gICAgICByZXR1cm4gcHJvcHMuZWNyUmVwb3NpdG9yeTtcbiAgICBpZiAocHJvcHMuZWNyUmVwb3NpdG9yeSBpbnN0YW5jZW9mIFJlcG9zaXRvcnkpIHtcbiAgICAgIHJldHVybiBDb250YWluZXJJbWFnZS5mcm9tRWNyUmVwb3NpdG9yeShwcm9wcy5lY3JSZXBvc2l0b3J5LCBcImxhdGVzdFwiKTtcbiAgICB9XG4gICAgcmV0dXJuIENvbnRhaW5lckltYWdlLmZyb21SZWdpc3RyeShcImFtYXpvbi9hbWF6b24tZWNzLXNhbXBsZVwiKTtcbiAgfVxuXG4gIHN0YXRpYyBidWlsZChcbiAgICBpZDogc3RyaW5nLFxuICAgIHByb3BzOiBGYXJnYXRlQ2x1c3RlclByb3BzXG4gICk6IChzYjogU3RhY2tCdWlsZGVyKSA9PiBDb25zdHJ1Y3Qge1xuICAgIHJldHVybiAoc2I6IFN0YWNrQnVpbGRlcikgPT4ge1xuICAgICAgY29uc3QgbmV3UHJvcHM6IEZhcmdhdGVDbHVzdGVyUHJvcHMgPSB7XG4gICAgICAgIC4uLnByb3BzLFxuICAgICAgICAuLi57XG4gICAgICAgICAgdnBjOiAoc2IuZ2V0TmV0d29yaygpIGFzIElWcGMpIHx8IHByb3BzLnZwY1xuICAgICAgICB9XG4gICAgICB9O1xuICAgICAgcmV0dXJuIG5ldyB0aGlzKHNiLmdldFN0YWNrKCksIGlkLCBuZXdQcm9wcyk7XG4gICAgfTtcbiAgfVxufVxuIl19
858
+ exports.default = EcsCluster;
859
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWNzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vbGliL3Jlc291cmNlcy9hd3MvY29tcHV0ZS9lY3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsaURBb0I2QjtBQUM3QixpREFTNkI7QUFDN0IsMkNBQXVDO0FBRXZDLDZDQUE4QztBQUM5Qyx1RkFPZ0Q7QUFDaEQsaURBUTZCO0FBQzdCLHVGQUtnRDtBQUNoRCxpREFBMEQ7QUFDMUQsdUVBQXdEO0FBQ3hELCtFQUc0QztBQUM1Qyx5REFLaUM7QUFDakMseUVBQXFFO0FBQ3JFLGlEQUFpRDtBQUNqRCxpRUFBMkU7QUFFM0Usc0RBQW1EO0FBQ25ELGlFQUFpRjtBQUNqRix3REFBcUQ7QUFDckQseUZBQXNGO0FBSXRGLElBQVksUUFHWDtBQUhELFdBQVksUUFBUTtJQUNsQix1Q0FBSSxDQUFBO0lBQ0oseUNBQUssQ0FBQTtBQUNQLENBQUMsRUFIVyxRQUFRLHdCQUFSLFFBQVEsUUFHbkI7QUFFRCxJQUFZLFdBR1g7QUFIRCxXQUFZLFdBQVc7SUFDckIsc0RBQTBELENBQUE7SUFDMUQsNERBQWdFLENBQUE7QUFDbEUsQ0FBQyxFQUhXLFdBQVcsMkJBQVgsV0FBVyxRQUd0QjtBQWtSRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FtQ0c7QUFDSCxNQUFxQixVQUFXLFNBQVEsc0JBQVM7SUFnQy9DLFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBc0I7UUFDOUQsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQVpuQix1QkFBdUI7UUFDZixhQUFRLEdBQUcsSUFBSSxHQUFHLEVBQXVCLENBQUM7UUFRMUMsaUJBQVksR0FBVyxHQUFHLENBQUM7UUFLakMsSUFBSSxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUM7UUFDbkIsSUFBSSxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUM7UUFDbkIsSUFBSSxDQUFDLGdCQUFnQixHQUFH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cyBDZGtDbHVzdGVyLFxuICBDb250YWluZXJJbWFnZSxcbiAgRmFyZ2F0ZVNlcnZpY2UsXG4gIEZhcmdhdGVUYXNrRGVmaW5pdGlvbixcbiAgRWMyU2VydmljZSxcbiAgRWMyVGFza0RlZmluaXRpb24sXG4gIE5ldHdvcmtNb2RlLFxuICBQcm9wYWdhdGVkVGFnU291cmNlLFxuICB0eXBlIFJlcG9zaXRvcnlJbWFnZSxcbiAgdHlwZSBDb250YWluZXJEZWZpbml0aW9uLFxuICBDb250YWluZXJJbnNpZ2h0cyxcbiAgUGxhY2VtZW50U3RyYXRlZ3ksXG4gIEFzZ0NhcGFjaXR5UHJvdmlkZXIsXG4gIEVjc09wdGltaXplZEltYWdlLFxuICBBbWlIYXJkd2FyZVR5cGUsXG4gIENwdUFyY2hpdGVjdHVyZSxcbiAgT3BlcmF0aW5nU3lzdGVtRmFtaWx5LFxuICBDZm5DbHVzdGVyQ2FwYWNpdHlQcm92aWRlckFzc29jaWF0aW9uc1xufSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWVjc1wiO1xuaW1wb3J0IHtcbiAgQ29ubmVjdGlvbnMsXG4gIHR5cGUgSUNvbm5lY3RhYmxlLFxuICB0eXBlIElTZWN1cml0eUdyb3VwLFxuICB0eXBlIElWcGMsXG4gIEluc3RhbmNlVHlwZSxcbiAgUGVlcixcbiAgUG9ydCxcbiAgU3VibmV0VHlwZVxufSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWVjMlwiO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSBcImNvbnN0cnVjdHNcIjtcbmltcG9ydCB7IHR5cGUgU3RhY2tCdWlsZGVyIH0gZnJvbSBcIi4uL2Jhc2UvYXdzU3RhY2tcIjtcbmltcG9ydCB7IER1cmF0aW9uLCBTdGFjayB9IGZyb20gXCJhd3MtY2RrLWxpYlwiO1xuaW1wb3J0IHtcbiAgdHlwZSBBcHBsaWNhdGlvbkxpc3RlbmVyLFxuICBBcHBsaWNhdGlvbkxvYWRCYWxhbmNlcixcbiAgQXBwbGljYXRpb25Qcm90b2NvbCxcbiAgdHlwZSBJQXBwbGljYXRpb25UYXJnZXRHcm91cCxcbiAgTGlzdGVuZXJBY3Rpb24sXG4gIExpc3RlbmVyQ29uZGl0aW9uXG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtZWxhc3RpY2xvYWRiYWxhbmNpbmd2MlwiO1xuaW1wb3J0IHtcbiAgRWZmZWN0LFxuICB0eXBlIElNYW5hZ2VkUG9saWN5LFxuICBQb2xpY3ksXG4gIFBvbGljeURvY3VtZW50LFxuICBQb2xpY3lTdGF0ZW1lbnQsXG4gIFJvbGUsXG4gIFNlcnZpY2VQcmluY2lwYWxcbn0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1pYW1cIjtcbmltcG9ydCB7XG4gIFByZWRlZmluZWRNZXRyaWMsXG4gIFNjYWxhYmxlVGFyZ2V0LFxuICBTZXJ2aWNlTmFtZXNwYWNlLFxuICBUYXJnZXRUcmFja2luZ1NjYWxpbmdQb2xpY3lcbn0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1hcHBsaWNhdGlvbmF1dG9zY2FsaW5nXCI7XG5pbXBvcnQgeyBTZWNyZXQgYXMgRWNzU2VjcmV0IH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1lY3NcIjtcbmltcG9ydCB7IFNlY3JldCB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3Mtc2VjcmV0c21hbmFnZXJcIjtcbmltcG9ydCB7XG4gIENlcnRpZmljYXRlLFxuICBDZXJ0aWZpY2F0ZVZhbGlkYXRpb25cbn0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1jZXJ0aWZpY2F0ZW1hbmFnZXJcIjtcbmltcG9ydCB7XG4gIEFSZWNvcmQsXG4gIFJlY29yZFRhcmdldCxcbiAgdHlwZSBJSG9zdGVkWm9uZSxcbiAgdHlwZSBHZW9Mb2NhdGlvblxufSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLXJvdXRlNTNcIjtcbmltcG9ydCB7IExvYWRCYWxhbmNlclRhcmdldCB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3Mtcm91dGU1My10YXJnZXRzXCI7XG5pbXBvcnQgeyBSZXBvc2l0b3J5IH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1lY3JcIjtcbmltcG9ydCB7IEF1dG9TY2FsaW5nR3JvdXAsIE1vbml0b3JpbmcgfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWF1dG9zY2FsaW5nXCI7XG5cbmltcG9ydCB7IENmbk91dHB1dCB9IGZyb20gXCIuLi91dGlsaXRpZXMvY2ZuT3V0cHV0XCI7XG5pbXBvcnQgeyBIb3N0ZWRab25lIGFzIEZqYWxsSG9zdGVkWm9uZSB9IGZyb20gXCIuLi8uLi8uLi9wYXR0ZXJucy9hd3MvaG9zdGVkWm9uZVwiO1xuaW1wb3J0IHsgU2VjdXJpdHlHcm91cCB9IGZyb20gXCIuLi9pYW0vc2VjdXJpdHlHcm91cFwiO1xuaW1wb3J0IHsgQ2FwYWNpdHlQcm92aWRlckRyYWluV2FpdGVyIH0gZnJvbSBcIi4vdXRpbGl0aWVzL2NhcGFjaXR5UHJvdmlkZXJEcmFpbldhaXRlclwiO1xuXG5pbXBvcnQgeyB0eXBlIFNlY3JldEltcG9ydCB9IGZyb20gXCIuLi9zZWNyZXRzXCI7XG5cbmV4cG9ydCBlbnVtIFByb3RvY29sIHtcbiAgSFRUUCxcbiAgSFRUUFNcbn1cblxuZXhwb3J0IGVudW0gU2NhbGluZ1R5cGUge1xuICBDUFUgPSBQcmVkZWZpbmVkTWV0cmljLkVDU19TRVJWSUNFX0FWRVJBR0VfQ1BVX1VUSUxJWkFUSU9OLFxuICBNRU1PUlkgPSBQcmVkZWZpbmVkTWV0cmljLkVDU19TRVJWSUNFX0FWRVJBR0VfTUVNT1JZX1VUSUxJWkFUSU9OXG59XG5cbmV4cG9ydCB0eXBlIEVjc0NhcGFjaXR5UHJvdmlkZXIgPSBcIkZBUkdBVEVcIiB8IFwiRkFSR0FURV9TUE9UXCIgfCBcIkVDMlwiO1xuXG4vKipcbiAqIEVDMiBjYXBhY2l0eSBjb25maWd1cmF0aW9uIGZvciBFQ1MgRUMyLWJhY2tlZCBjbHVzdGVycy5cbiAqIE9ubHkgdXNlZCB3aGVuIGNhcGFjaXR5UHJvdmlkZXIgaXMgXCJFQzJcIi5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBFYzJDYXBhY2l0eUNvbmZpZyB7XG4gIC8qKiBFQzIgaW5zdGFuY2UgdHlwZS4gRGVmYXVsdDogXCJ0My5taWNyb1wiICovXG4gIGluc3RhbmNlVHlwZT86IHN0cmluZztcbiAgLyoqIEFNSSBoYXJkd2FyZSB0eXBlLiBEZWZhdWx0OiBcIkFSTVwiIChHcmF2aXRvbiAtIGJldHRlciBjb3N0L3BlcmZvcm1hbmNlKSAqL1xuICBhbWlIYXJkd2FyZVR5cGU/OiBcIkFSTVwiIHwgXCJTVEFOREFSRFwiO1xuICAvKiogTWluaW11bSBudW1iZXIgb2YgaW5zdGFuY2VzLiBEZWZhdWx0OiAyICovXG4gIG1pbkNhcGFjaXR5PzogbnVtYmVyO1xuICAvKiogTWF4aW11bSBudW1iZXIgb2YgaW5zdGFuY2VzLiBEZWZhdWx0OiAzICovXG4gIG1heENhcGFjaXR5PzogbnVtYmVyO1xuICAvKiogTWVtb3J5IGxpbWl0IGluIE1pQiBmb3IgdGhlIGNvbnRhaW5lci4gRGVmYXVsdDogMTAyNCAqL1xuICBtZW1vcnlMaW1pdE1pQj86IG51bWJlcjtcbn1cblxuLyoqXG4gKiBEb21haW4gY29uZmlndXJhdGlvbiBmb3IgSFRUUFMgYW5kIEROUy5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBEb21haW5CYXNlQ29uZmlnIHtcbiAgZG9tYWluTmFtZTogc3RyaW5nO1xuICBob3N0ZWRab25lPzogRmphbGxIb3N0ZWRab25lO1xuICBjZXJ0aWZpY2F0ZT86IENlcnRpZmljYXRlO1xuICBzZXRJZGVudGlmaWVyPzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIExhdGVuY3lEb21haW5Db25maWcgZXh0ZW5kcyBEb21haW5CYXNlQ29uZmlnIHtcbiAgcmVnaW9uOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgV2VpZ2h0ZWREb21haW5Db25maWcgZXh0ZW5kcyBEb21haW5CYXNlQ29uZmlnIHtcbiAgd2VpZ2h0OiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgR2VvTG9jYXRpb25Eb21haW5Db25maWcgZXh0ZW5kcyBEb21haW5CYXNlQ29uZmlnIHtcbiAgZ2VvTG9jYXRpb246IEdlb0xvY2F0aW9uO1xufVxuXG5leHBvcnQgdHlwZSBEb21haW5Db25maWcgPVxuICB8IERvbWFpbkJhc2VDb25maWdcbiAgfCBMYXRlbmN5RG9tYWluQ29uZmlnXG4gIHwgV2VpZ2h0ZWREb21haW5Db25maWdcbiAgfCBHZW9Mb2NhdGlvbkRvbWFpbkNvbmZpZztcblxuLyoqXG4gKiBJbnRlcm5hbCBjb25maWd1cmF0aW9uIGZvciBhIGNvbnRhaW5lciBpbiBhIG11bHRpLWNvbnRhaW5lciBFQ1MgdGFzay5cbiAqXG4gKiBJbiBtdWx0aS1jb250YWluZXIgdGFza3MsIHRoZSBmaXJzdCBjb250YWluZXIgd2l0aCBhIGBwb3J0YCBpcyB0aGUgKipwcmltYXJ5IGNvbnRhaW5lcioqXG4gKiB0aGF0IHJlY2VpdmVzIGxvYWQgYmFsYW5jZXIgdHJhZmZpYy4gQWxsIG90aGVyIGNvbnRhaW5lcnMgYXJlICoqc2lkZWNhcnMqKiB0aGF0IHByb3ZpZGVcbiAqIHN1cHBvcnRpbmcgZnVuY3Rpb25hbGl0eSAobG9nZ2luZywgbW9uaXRvcmluZywgcHJveGllcywgZXRjLikuXG4gKlxuICogQGV4YW1wbGVcbiAqIC8vIFByaW1hcnkgY29udGFpbmVyIChoYXMgcG9ydCkgKyBzaWRlY2FyIChubyBwb3J0KVxuICogY29udGFpbmVyczogW1xuICogICB7IG5hbWU6IFwiYXBwXCIsIHBvcnQ6IDMwMDAgfSwgICAgICAgICAgIC8vIFByaW1hcnkgLSByZWNlaXZlcyBBTEIgdHJhZmZpY1xuICogICB7IG5hbWU6IFwiZGF0YWRvZ1wiLCBpbWFnZTogXCJkYXRhZG9nL2FnZW50XCIgfSAgLy8gU2lkZWNhciAtIG1vbml0b3JpbmdcbiAqIF1cbiAqXG4gKiBAaW50ZXJuYWxcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBFY3NDbHVzdGVyQ29udGFpbmVyQ29uZmlnIHtcbiAgLyoqIFVuaXF1ZSBjb250YWluZXIgbmFtZSAqL1xuICBuYW1lOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBDb250YWluZXIgaW1hZ2UuIE9wdGlvbnM6XG4gICAqIC0gT21pdDogVXNlcyBkZWZhdWx0IEVDUiByZXBvc2l0b3J5IChwcmltYXJ5IGNvbnRhaW5lciBvbmx5KVxuICAgKiAtIHN0cmluZzogRUNSIHJlcG9zaXRvcnkgbmFtZSBvciBwdWJsaWMgaW1hZ2UgVVJMXG4gICAqIC0gUmVwb3NpdG9yeTogQ0RLIEVDUiBSZXBvc2l0b3J5IGNvbnN0cnVjdFxuICAgKi9cbiAgaW1hZ2U/OiBzdHJpbmcgfCBSZXBvc2l0b3J5O1xuICAvKipcbiAgICogUG9ydCB0aGUgY29udGFpbmVyIGxpc3RlbnMgb24uXG4gICAqIFRoZSBmaXJzdCBjb250YWluZXIgd2l0aCBhIHBvcnQgYmVjb21lcyB0aGUgKipwcmltYXJ5IGNvbnRhaW5lcioqXG4gICAqIGFuZCBpcyByZWdpc3RlcmVkIHdpdGggdGhlIGxvYWQgYmFsYW5jZXIuXG4gICAqL1xuICBwb3J0PzogbnVtYmVyO1xuICAvKiogRW52aXJvbm1lbnQgdmFyaWFibGVzICovXG4gIGVudmlyb25tZW50PzogUmVjb3JkPHN0cmluZywgc3RyaW5nPjtcbiAgLyoqIFNlY3JldHMgaW1wb3J0ZWQgZnJvbSBvdGhlciByZXNvdXJjZXMgKi9cbiAgc2VjcmV0c0ltcG9ydD86IHsgW2tleTogc3RyaW5nXTogU2VjcmV0SW1wb3J0IH07XG4gIC8qKiBDb21tYW5kIHRvIHJ1biBpbiB0aGUgY29udGFpbmVyICovXG4gIGNvbW1hbmQ/OiBzdHJpbmdbXTtcbiAgLyoqIEVudHJ5IHBvaW50IGZvciB0aGUgY29udGFpbmVyICovXG4gIGVudHJ5UG9pbnQ/OiBzdHJpbmdbXTtcbiAgLyoqXG4gICAqIFdoZXRoZXIgdGhpcyBjb250YWluZXIgaXMgZXNzZW50aWFsLlxuICAgKiBJZiBhbiBlc3NlbnRpYWwgY29udGFpbmVyIHN0b3BzLCBhbGwgY29udGFpbmVycyBpbiB0aGUgdGFzayBzdG9wLlxuICAgKiBEZWZhdWx0OiB0cnVlIGZvciBwcmltYXJ5IGNvbnRhaW5lciwgdHJ1ZSBmb3Igc2lkZWNhcnNcbiAgICovXG4gIGVzc2VudGlhbD86IGJvb2xlYW47XG4gIC8qKlxuICAgKiBIZWFsdGggY2hlY2sgY29uZmlndXJhdGlvbi5cbiAgICogRGVmYXVsdDogRm9yIHByaW1hcnkgY29udGFpbmVyIHdpdGggcG9ydCwgdXNlcyBjdXJsIGhlYWx0aCBjaGVjay5cbiAgICovXG4gIGhlYWx0aENoZWNrPzoge1xuICAgIGNvbW1hbmQ6IHN0cmluZ1tdO1xuICAgIGludGVydmFsPzogbnVtYmVyO1xuICAgIHRpbWVvdXQ/OiBudW1iZXI7XG4gICAgcmV0cmllcz86IG51bWJlcjtcbiAgICBzdGFydFBlcmlvZD86IG51bWJlcjtcbiAgfTtcbn1cblxuLyoqXG4gKiBDbHVzdGVyLWxldmVsIGNvbmZpZ3VyYXRpb24uXG4gKiBDb250cm9scyB0aGUgc2hhcmVkIEFMQiBmb3IgYWxsIHNlcnZpY2VzIGluIHRoaXMgY2x1c3Rlci5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBFY3NDbHVzdGVyQ2x1c3RlckNvbmZpZyB7XG4gIC8qKlxuICAgKiBEb21haW4gZm9yIEhUVFBTIGFjY2Vzcy5cbiAgICogLSBPbWl0OiBBTEIgY3JlYXRlZCB3aXRoIGRlZmF1bHQgRE5TICgqLmVsYi5hbWF6b25hd3MuY29tKVxuICAgKiAtIFNwZWNpZmllZDogQ3JlYXRlcyBBQ00gY2VydGlmaWNhdGUgKyBSb3V0ZTUzIEROUyBBIHJlY29yZFxuICAgKi9cbiAgZG9tYWluPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBMb2FkIGJhbGFuY2VyIGNvbmZpZ3VyYXRpb24uXG4gICAqIC0gZmFsc2U6IE5vIEFMQiAoZm9yIHdvcmtlcnMvaW50ZXJuYWwgc2VydmljZXMpXG4gICAqIC0gXCJwdWJsaWNcIjogSW50ZXJuZXQtZmFjaW5nIEFMQiAoZGVmYXVsdClcbiAgICogLSBcImludGVybmFsXCI6IFZQQy1vbmx5IEFMQlxuICAgKi9cbiAgbG9hZEJhbGFuY2VyPzogZmFsc2UgfCBcInB1YmxpY1wiIHwgXCJpbnRlcm5hbFwiO1xuXG4gIC8qKlxuICAgKiBFbmFibGUgZGlyZWN0IEVDMiBhY2Nlc3Mgd2l0aG91dCBBTEIuXG4gICAqIE9wZW5zIGNvbnRhaW5lciBwb3J0cyBvbiBzZWN1cml0eSBncm91cCBmb3IgZGlyZWN0IGFjY2VzcyB2aWEgRUMyIHB1YmxpYyBJUC5cbiAgICogVXNlcyBob3N0IG5ldHdvcmsgbW9kZSBmb3IgcHJlZGljdGFibGUgcG9ydCBtYXBwaW5nIChjb250YWluZXI6MzAwMCDihpIgaG9zdDozMDAwKS5cbiAgICogT25seSB2YWxpZCB3aXRoIEVDMiBjYXBhY2l0eSBwcm92aWRlci5cbiAgICovXG4gIGRpcmVjdEFjY2Vzcz86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIERvbWFpbiBjb25maWd1cmF0aW9uIGZvciBhZHZhbmNlZCByb3V0aW5nIHBvbGljaWVzIChsYXRlbmN5LCB3ZWlnaHRlZCwgZ2VvKS5cbiAgICogT25seSB1c2VkIHdoZW4gZG9tYWluIGlzIHNwZWNpZmllZC5cbiAgICovXG4gIGRvbWFpbkNvbmZpZz86IERvbWFpbkNvbmZpZztcbn1cblxuLyoqXG4gKiBSb3V0aW5nIGNvbmZpZ3VyYXRpb24gZm9yIHBhdGgvaG9zdC1iYXNlZCByb3V0aW5nIG9uIHRoZSBBTEIuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRWNzUm91dGluZ0NvbmZpZyB7XG4gIC8qKiBQYXRoIHBhdHRlcm4gZm9yIHJvdXRpbmcgKGUuZy4sIFwiL2FwaS8qXCIsIFwiL3VzZXJzLypcIikgKi9cbiAgcGF0aD86IHN0cmluZztcbiAgLyoqIEhvc3QgaGVhZGVyIGZvciByb3V0aW5nIChlLmcuLCBcImFwaS5leGFtcGxlLmNvbVwiKSAqL1xuICBob3N0Pzogc3RyaW5nO1xuICAvKiogUHJpb3JpdHkgZm9yIHRoaXMgcm91dGluZyBydWxlICgxLTUwMDAwKS4gTG93ZXIgPSBoaWdoZXIgcHJpb3JpdHkuICovXG4gIHByaW9yaXR5PzogbnVtYmVyO1xuICAvKiogSGVhbHRoIGNoZWNrIHBhdGggZm9yIHRoaXMgc2VydmljZSdzIHRhcmdldCBncm91cC4gRGVmYXVsdDogXCIvXCIgKi9cbiAgaGVhbHRoQ2hlY2tQYXRoPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIENvbmZpZ3VyYXRpb24gZm9yIGEgc2VydmljZSBpbiBhbiBFQ1MgY2x1c3Rlci5cbiAqIEVhY2ggc2VydmljZSBnZXRzIGl0cyBvd24gdGFzayBkZWZpbml0aW9uLCBzY2FsaW5nLCBhbmQgdGFyZ2V0IGdyb3VwLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEVjc1NlcnZpY2VQcm9wcyB7XG4gIC8qKiBTZXJ2aWNlIG5hbWUgKHVuaXF1ZSB3aXRoaW4gY2x1c3RlcikgKi9cbiAgbmFtZTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBDb250YWluZXIgaW1hZ2UgZm9yIHRoaXMgc2VydmljZS5cbiAgICogLSBPbWl0OiBVc2VzIGNsdXN0ZXIncyBkZWZhdWx0IEVDUiByZXBvc2l0b3J5XG4gICAqIC0gc3RyaW5nOiBFQ1IgcmVwb3NpdG9yeSBuYW1lIG9yIHB1YmxpYyBpbWFnZSBVUkxcbiAgICogLSBSZXBvc2l0b3J5OiBDREsgRUNSIFJlcG9zaXRvcnkgY29uc3RydWN0XG4gICAqL1xuICBpbWFnZT86IHN0cmluZyB8IFJlcG9zaXRvcnk7XG5cbiAgLyoqXG4gICAqIENvbnRhaW5lciBjb25maWd1cmF0aW9ucyBmb3IgdGhpcyBzZXJ2aWNlLlxuICAgKiBUaGUgZmlyc3QgY29udGFpbmVyIHdpdGggYSBwb3J0IGlzIHRoZSAqKnByaW1hcnkgY29udGFpbmVyKiogKHJlY2VpdmVzIEFMQiB0cmFmZmljKS5cbiAgICovXG4gIGNvbnRhaW5lcnM6IEVjc0NsdXN0ZXJDb250YWluZXJDb25maWdbXTtcblxuICAvKiogQ1BVIHVuaXRzIGZvciB0aGlzIHNlcnZpY2UncyB0YXNrcyAoMjU2LTQwOTYpICovXG4gIGNwdT86IG51bWJlcjtcblxuICAvKiogTWVtb3J5IGluIE1pQiBmb3IgdGhpcyBzZXJ2aWNlJ3MgdGFza3MgKDUxMi0zMDcyMCkgKi9cbiAgbWVtb3J5TGltaXRNaUI/OiBudW1iZXI7XG5cbiAgLyoqIERlc2lyZWQgbnVtYmVyIG9mIHRhc2tzLiBEZWZhdWx0OiAyICovXG4gIGRlc2lyZWRDb3VudD86IG51bWJlcjtcblxuICAvKiogU2NhbGluZyB0eXBlIChDUFUgb3IgTUVNT1JZKS4gT21pdCB0byBkaXNhYmxlIGF1dG8tc2NhbGluZy4gKi9cbiAgc2NhbGluZ1R5cGU/OiBTY2FsaW5nVHlwZTtcblxuICAvKiogTWluaW11bSBudW1iZXIgb2YgdGFza3MgZm9yIGF1dG8tc2NhbGluZy4gRGVmYXVsdDogMiAqL1xuICBtaW5DYXBhY2l0eT86IG51bWJlcjtcblxuICAvKiogTWF4aW11bSBudW1iZXIgb2YgdGFza3MgZm9yIGF1dG8tc2NhbGluZy4gRGVmYXVsdDogMTAgKi9cbiAgbWF4Q2FwYWNpdHk/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIFJvdXRpbmcgcnVsZXMgZm9yIHRoaXMgc2VydmljZSBvbiB0aGUgY2x1c3RlcidzIEFMQi5cbiAgICogUmVxdWlyZWQgd2hlbiBjbHVzdGVyIGhhcyBtdWx0aXBsZSBzZXJ2aWNlcyB3aXRoIHBvcnRzLlxuICAgKi9cbiAgcm91dGluZz86IEVjc1JvdXRpbmdDb25maWc7XG5cbiAgLyoqXG4gICAqIEFkZGl0aW9uYWwgaW5saW5lIHBvbGljaWVzIGZvciB0aGlzIHNlcnZpY2UncyB0YXNrIHJvbGUuXG4gICAqIEFkZGVkIG9uIHRvcCBvZiB0aGUgZGVmYXVsdCBFQ1MgRXhlYyBwZXJtaXNzaW9ucy5cbiAgICovXG4gIHRhc2tSb2xlSW5saW5lUG9saWNpZXM/OiB7XG4gICAgW25hbWU6IHN0cmluZ106IFBvbGljeURvY3VtZW50O1xuICB9O1xuXG4gIC8qKlxuICAgKiBBZGRpdGlvbmFsIG1hbmFnZWQgcG9saWNpZXMgZm9yIHRoaXMgc2VydmljZSdzIHRhc2sgcm9sZS5cbiAgICogQWRkZWQgb24gdG9wIG9mIHRoZSBkZWZhdWx0IEVDUyBFeGVjIHBlcm1pc3Npb25zLlxuICAgKi9cbiAgdGFza1JvbGVNYW5hZ2VkUG9saWNpZXM/OiBJTWFuYWdlZFBvbGljeVtdO1xuXG4gIC8qKlxuICAgKiBSZXNvdXJjZXMgdGhpcyBzZXJ2aWNlIG5lZWRzIHRvIGNvbm5lY3QgdG8gKGUuZy4sIGRhdGFiYXNlcykuXG4gICAqIENyZWF0ZXMgc2VjdXJpdHkgZ3JvdXAgcnVsZXMgdG8gYWxsb3cgdHJhZmZpYyBmcm9tIHRoaXMgc3BlY2lmaWMgc2VydmljZSBvbmx5LlxuICAgKi9cbiAgY29ubmVjdGlvbnM/OiBJQ29ubmVjdGFibGVbXTtcbn1cblxuLyoqXG4gKiBQcm9wcyBmb3IgY3JlYXRpbmcgYW4gRUNTIGNsdXN0ZXIgd2l0aCBtdWx0aXBsZSBzZXJ2aWNlcy5cbiAqL1xuZXhwb3J0IHR5cGUgRWNzQ2x1c3RlclByb3BzID0ge1xuICAvKiogQ2x1c3RlciBuYW1lICovXG4gIGNsdXN0ZXJOYW1lOiBzdHJpbmc7XG5cbiAgLyoqIFZQQyB0byBkZXBsb3kgaW50byAqL1xuICB2cGM/OiBJVnBjO1xuXG4gIC8qKiBEZWZhdWx0IEVDUiByZXBvc2l0b3J5IG9yIGNvbnRhaW5lciBpbWFnZSAqL1xuICBlY3JSZXBvc2l0b3J5OiBSZXBvc2l0b3J5IHwgUmVwb3NpdG9yeUltYWdlIHwgc3RyaW5nO1xuXG4gIC8qKiBDYXBhY2l0eSBwcm92aWRlciBkZXRlcm1pbmVzIEZhcmdhdGUgdnMgRUMyIGluZnJhc3RydWN0dXJlICovXG4gIGNhcGFjaXR5UHJvdmlkZXI/OiBFY3NDYXBhY2l0eVByb3ZpZGVyO1xuXG4gIC8qKiBFQzItc3BlY2lmaWMgY29uZmlndXJhdGlvbi4gT25seSB1c2VkIHdoZW4gY2FwYWNpdHlQcm92aWRlciBpcyBcIkVDMlwiICovXG4gIGVjMkNvbmZpZz86IEVjMkNhcGFjaXR5Q29uZmlnO1xuXG4gIC8qKlxuICAgKiBDbHVzdGVyIGNvbmZpZ3VyYXRpb24uXG4gICAqIENvbnRyb2xzIHRoZSBzaGFyZWQgQUxCIGZvciBhbGwgc2VydmljZXMuXG4gICAqL1xuICBjbHVzdGVyPzogRWNzQ2x1c3RlckNsdXN0ZXJDb25maWc7XG5cbiAgLyoqXG4gICAqIFNlcnZpY2VzIGluIHRoaXMgY2x1c3Rlci5cbiAgICogRWFjaCBzZXJ2aWNlIGdldHMgaXRzIG93biB0YXNrIGRlZmluaXRpb24sIHNjYWxpbmcsIGFuZCB0YXJnZXQgZ3JvdXAuXG4gICAqIEFsbCBzZXJ2aWNlcyBzaGFyZSB0aGUgY2x1c3RlcidzIEFMQiAodW5sZXNzIGRpc2FibGVkKS5cbiAgICogVGFzayByb2xlIHBvbGljaWVzIGFyZSBjb25maWd1cmVkIHBlci1zZXJ2aWNlIGZvciBsZWFzdC1wcml2aWxlZ2UuXG4gICAqL1xuICBzZXJ2aWNlczogRWNzU2VydmljZVByb3BzW107XG59O1xuXG4vKipcbiAqIERhdGEgdHJhY2tlZCBmb3IgZWFjaCBzZXJ2aWNlIGluIHRoZSBjbHVzdGVyLlxuICovXG5pbnRlcmZhY2UgU2VydmljZURhdGEge1xuICBzZXJ2aWNlOiBGYXJnYXRlU2VydmljZSB8IEVjMlNlcnZpY2U7XG4gIHRhc2tEZWZpbml0aW9uOiBGYXJnYXRlVGFza0RlZmluaXRpb24gfCBFYzJUYXNrRGVmaW5pdGlvbjtcbiAgLyoqIFJvbGUgZm9yIEVDUyBhZ2VudCAocHVsbCBpbWFnZXMsIHdyaXRlIGxvZ3MsIGluamVjdCBzZWNyZXRzKSAqL1xuICBleGVjdXRpb25Sb2xlOiBSb2xlO1xuICAvKiogUm9sZSBmb3IgYXBwbGljYXRpb24gY29kZSAodXNlciBwb2xpY2llcywgRUNTIEV4ZWMpICovXG4gIHRhc2tSb2xlOiBSb2xlO1xuICBjb250YWluZXJzOiBDb250YWluZXJEZWZpbml0aW9uW107XG4gIHByaW1hcnlDb250YWluZXI/OiBDb250YWluZXJEZWZpbml0aW9uO1xuICB0YXJnZXRHcm91cD86IElBcHBsaWNhdGlvblRhcmdldEdyb3VwO1xuICBzY2FsaW5nUG9saWN5PzogVGFyZ2V0VHJhY2tpbmdTY2FsaW5nUG9saWN5O1xufVxuXG4vKipcbiAqIEVDUyBDbHVzdGVyIHN1cHBvcnRpbmcgbXVsdGlwbGUgc2VydmljZXMgd2l0aCBhIHNoYXJlZCBBTEIuXG4gKlxuICogQGV4YW1wbGVcbiAqIC8vIFNpbmdsZSBzZXJ2aWNlIGNsdXN0ZXJcbiAqIG5ldyBFY3NDbHVzdGVyKHNjb3BlLCBcIldlYkNsdXN0ZXJcIiwge1xuICogICBjbHVzdGVyTmFtZTogXCJXZWJDbHVzdGVyXCIsXG4gKiAgIGVjclJlcG9zaXRvcnk6IGVjcixcbiAqICAgc2VydmljZXM6IFtcbiAqICAgICB7IG5hbWU6IFwid2ViXCIsIGNvbnRhaW5lcnM6IFt7IG5hbWU6IFwiYXBwXCIsIHBvcnQ6IDMwMDAgfV0gfVxuICogICBdXG4gKiB9KTtcbiAqXG4gKiBAZXhhbXBsZVxuICogLy8gTXVsdGktc2VydmljZSBjbHVzdGVyIHdpdGggcm91dGluZ1xuICogbmV3IEVjc0NsdXN0ZXIoc2NvcGUsIFwiQXBpQ2x1c3RlclwiLCB7XG4gKiAgIGNsdXN0ZXJOYW1lOiBcIkFwaUNsdXN0ZXJcIixcbiAqICAgY2x1c3RlcjogeyBkb21haW46IFwiYXBpLmV4YW1wbGUuY29tXCIgfSxcbiAqICAgZWNyUmVwb3NpdG9yeTogZWNyLFxuICogICBzZXJ2aWNlczogW1xuICogICAgIHsgbmFtZTogXCJ1c2Vyc1wiLCBjb250YWluZXJzOiBbeyBuYW1lOiBcImFwcFwiLCBwb3J0OiAzMDAwIH1dLCByb3V0aW5nOiB7IHBhdGg6IFwiL3VzZXJzLypcIiB9IH0sXG4gKiAgICAgeyBuYW1lOiBcIm9yZGVyc1wiLCBjb250YWluZXJzOiBbeyBuYW1lOiBcImFwcFwiLCBwb3J0OiAzMDAxIH1dLCByb3V0aW5nOiB7IHBhdGg6IFwiL29yZGVycy8qXCIgfSB9XG4gKiAgIF1cbiAqIH0pO1xuICpcbiAqIEBleGFtcGxlXG4gKiAvLyBXb3JrZXIgY2x1c3RlciAobm8gQUxCKVxuICogbmV3IEVjc0NsdXN0ZXIoc2NvcGUsIFwiV29ya2Vyc1wiLCB7XG4gKiAgIGNsdXN0ZXJOYW1lOiBcIldvcmtlcnNcIixcbiAqICAgY2x1c3RlcjogeyBsb2FkQmFsYW5jZXI6IGZhbHNlIH0sXG4gKiAgIGVjclJlcG9zaXRvcnk6IGVjcixcbiAqICAgc2VydmljZXM6IFtcbiAqICAgICB7IG5hbWU6IFwicHJvY2Vzc29yXCIsIGNvbnRhaW5lcnM6IFt7IG5hbWU6IFwid29ya2VyXCIgfV0gfVxuICogICBdXG4gKiB9KTtcbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgRWNzQ2x1c3RlciBleHRlbmRzIENvbnN0cnVjdCBpbXBsZW1lbnRzIElDb25uZWN0YWJsZSB7XG4gIHB1YmxpYyBjb25uZWN0aW9uczogQ29ubmVjdGlvbnM7XG5cbiAgLy8gQ2x1c3Rlci1sZXZlbCByZXNvdXJjZXNcbiAgcHJpdmF0ZSBjbHVzdGVyOiBDZGtDbHVzdGVyO1xuICBwcml2YXRlIGxvYWRCYWxhbmNlcj86IEFwcGxpY2F0aW9uTG9hZEJhbGFuY2VyO1xuICBwcml2YXRlIGxvYWRCYWxhbmNlckxpc3RlbmVyPzogQXBwbGljYXRpb25MaXN0ZW5lcjtcbiAgcHJpdmF0ZSBob3N0ZWRab25lPzogSUhvc3RlZFpvbmU7XG4gIHByaXZhdGUgY2VydGlmaWNhdGU/OiBDZXJ0aWZpY2F0ZTtcbiAgcHJpdmF0ZSBhUmVjb3JkPzogQVJlY29yZDtcblxuICAvLyBFQzItc3BlY2lmaWNcbiAgcHJpdmF0ZSBhdXRvU2NhbGluZ0dyb3VwPzogQXV0b1NjYWxpbmdHcm91cDtcbiAgcHJpdmF0ZSBhc2dTZWN1cml0eUdyb3VwPzogU2VjdXJpdHlHcm91cDtcbiAgcHJpdmF0ZSBhc2dDYXBhY2l0eVByb3ZpZGVyPzogQXNnQ2FwYWNpdHlQcm92aWRlcjtcbiAgcHJpdmF0ZSBsb2FkQmFsYW5jZXJTZWN1cml0eUdyb3VwPzogU2VjdXJpdHlHcm91cDtcbiAgcHJpdmF0ZSBkcmFpbldhaXRlcj86IENhcGFjaXR5UHJvdmlkZXJEcmFpbldhaXRlcjtcblxuICAvLyBGYXJnYXRlLXNwZWNpZmljIC0gcmVmZXJlbmNlIHRvIENESydzIGludGVybmFsIGNhcGFjaXR5IHByb3ZpZGVyIGFzc29jaWF0aW9uc1xuICBwcml2YXRlIGZhcmdhdGVDYXBhY2l0eVByb3ZpZGVyQXNzb2NpYXRpb25zPzogQ2ZuQ2x1c3RlckNhcGFjaXR5UHJvdmlkZXJBc3NvY2lhdGlvbnM7XG5cbiAgLy8gUGVyLXNlcnZpY2UgdHJhY2tpbmdcbiAgcHJpdmF0ZSBzZXJ2aWNlcyA9IG5ldyBNYXA8c3RyaW5nLCBTZXJ2aWNlRGF0YT4oKTtcblxuICAvLyBDb25maWd1cmF0aW9uXG4gIHByaXZhdGUgc2NvcGU6IENvbnN0cnVjdDtcbiAgcHJpdmF0ZSBwcm9wczogRWNzQ2x1c3RlclByb3BzO1xuICBwcml2YXRlIGNhcGFjaXR5UHJvdmlkZXI6IEVjc0NhcGFjaXR5UHJvdmlkZXI7XG4gIHByaXZhdGUgbG9hZEJhbGFuY2VyRGlzYWJsZWQ6IGJvb2xlYW47XG4gIHByaXZhdGUgZGlyZWN0QWNjZXNzRW5hYmxlZDogYm9vbGVhbjtcbiAgcHJpdmF0ZSBuZXh0UHJpb3JpdHk6IG51bWJlciA9IDEwMDtcblxuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogRWNzQ2x1c3RlclByb3BzKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkKTtcblxuICAgIHRoaXMuc2NvcGUgPSBzY29wZTtcbiAgICB0aGlzLnByb3BzID0gcHJvcHM7XG4gICAgdGhpcy5jYXBhY2l0eVByb3ZpZGVyID0gcHJvcHMuY2FwYWNpdHlQcm92aWRlciB8fCBcIkZBUkdBVEVcIjtcbiAgICB0aGlzLmRpcmVjdEFjY2Vzc0VuYWJsZWQgPSBwcm9wcy5jbHVzdGVyPy5kaXJlY3RBY2Nlc3MgPT09IHRydWU7XG4gICAgdGhpcy5sb2FkQmFsYW5jZXJEaXNhYmxlZCA9XG4gICAgICBwcm9wcy5jbHVzdGVyPy5sb2FkQmFsYW5jZXIgPT09IGZhbHNlIHx8IHRoaXMuZGlyZWN0QWNjZXNzRW5hYmxlZDtcblxuICAgIHRoaXMudmFsaWRhdGVQcm9wcyhwcm9wcyk7XG5cbiAgICAvLyAxLiBDcmVhdGUgdGhlIEVDUyBjbHVzdGVyXG4gICAgdGhpcy5hZGRDbHVzdGVyKHByb3BzKTtcblxuICAgIC8vIDIuIFNldCB1cCBFQzIgaW5mcmFzdHJ1Y3R1cmUgaWYgbmVlZGVkXG4gICAgaWYgKHRoaXMuaXNFYzIoKSkge1xuICAgICAgdGhpcy5hZGRBdXRvU2NhbGluZ0dyb3VwKHByb3BzKTtcbiAgICB9XG5cbiAgICAvLyAzLiBDcmVhdGUgQUxCIGlmIG5vdCBkaXNhYmxlZCAoc2hhcmVkIGJ5IGFsbCBzZXJ2aWNlcylcbiAgICBpZiAoIXRoaXMubG9hZEJhbGFuY2VyRGlzYWJsZWQpIHtcbiAgICAgIHRoaXMuYWRkTG9hZEJhbGFuY2VyKHByb3BzKTtcblxuICAgICAgLy8gU2V0IHVwIGRvbWFpbi9IVFRQUyBpZiBjb25maWd1cmVkXG4gICAgICBpZiAocHJvcHMuY2x1c3Rlcj8uZG9tYWluIHx8IHByb3BzLmNsdXN0ZXI/LmRvbWFpbkNvbmZpZykge1xuICAgICAgICB0aGlzLmFkZEhvc3RlZFpvbmUocHJvcHMpO1xuICAgICAgfVxuXG4gICAgICB0aGlzLmFkZExvYWRCYWxhbmNlckxpc3RlbmVyKHByb3BzKTtcbiAgICB9IGVsc2UgaWYgKHRoaXMuZGlyZWN0QWNjZXNzRW5hYmxlZCkge1xuICAgICAgdGhpcy5hZGREaXJlY3RBY2Nlc3NPdXRwdXRzKHByb3BzKTtcbiAgICB9XG5cbiAgICAvLyA0LiBDcmVhdGUgZWFjaCBzZXJ2aWNlXG4gICAgZm9yIChjb25zdCBzZXJ2aWNlUHJvcHMgb2YgcHJvcHMuc2VydmljZXMpIHtcbiAgICAgIHRoaXMuYWRkU2VydmljZVRvQ2x1c3RlcihzZXJ2aWNlUHJvcHMpO1xuICAgIH1cblxuICAgIC8vIDUuIFNldCB1cCBjb25uZWN0aW9uc1xuICAgIHRoaXMuc2V0dXBDb25uZWN0aW9ucyhwcm9wcyk7XG4gIH1cblxuICAvKiogR2V0IHRoZSBjbHVzdGVyJ3MgbG9hZCBiYWxhbmNlci4gVW5kZWZpbmVkIGlmIGRpc2FibGVkLiAqL1xuICBnZXRMb2FkQmFsYW5jZXIoKTogQXBwbGljYXRpb25Mb2FkQmFsYW5jZXIgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLmxvYWRCYWxhbmNlcjtcbiAgfVxuXG4gIC8qKiBHZXQgdGhlIGxvYWQgYmFsYW5jZXIncyBsaXN0ZW5lci4gVW5kZWZpbmVkIGlmIGRpc2FibGVkLiAqL1xuICBnZXRMaXN0ZW5lcigpOiBBcHBsaWNhdGlvbkxpc3RlbmVyIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5sb2FkQmFsYW5jZXJMaXN0ZW5lcjtcbiAgfVxuXG4gIC8qKiBHZXQgYSBzcGVjaWZpYyBzZXJ2aWNlIGJ5IG5hbWUuICovXG4gIGdldFNlcnZpY2UobmFtZTogc3RyaW5nKTogRmFyZ2F0ZVNlcnZpY2UgfCBFYzJTZXJ2aWNlIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5zZXJ2aWNlcy5nZXQobmFtZSk/LnNlcnZpY2U7XG4gIH1cblxuICAvKiogR2V0IGFsbCBzZXJ2aWNlcyBpbiB0aGlzIGNsdXN0ZXIuICovXG4gIGdldFNlcnZpY2VzKCk6IE1hcDxzdHJpbmcsIEZhcmdhdGVTZXJ2aWNlIHwgRWMyU2VydmljZT4ge1xuICAgIGNvbnN0IHJlc3VsdCA9IG5ldyBNYXA8c3RyaW5nLCBGYXJnYXRlU2VydmljZSB8IEVjMlNlcnZpY2U+KCk7XG4gICAgZm9yIChjb25zdCBbbmFtZSwgZGF0YV0gb2YgdGhpcy5zZXJ2aWNlcykge1xuICAgICAgcmVzdWx0LnNldChuYW1lLCBkYXRhLnNlcnZpY2UpO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgLyoqIEdldCB0aGUgRUNTIGNsdXN0ZXIgY29uc3RydWN0LiAqL1xuICBnZXRDbHVzdGVyKCk6IENka0NsdXN0ZXIge1xuICAgIHJldHVybiB0aGlzLmNsdXN0ZXI7XG4gIH1cblxuICAvKiogR2V0IHRoZSBBTEIgVVJMIChodHRwOi8vIG9yIGh0dHBzOi8vKS4gKi9cbiAgZ2V0VXJsKCk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gICAgaWYgKCF0aGlzLmxvYWRCYWxhbmNlcikgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICBjb25zdCBwcm90b2NvbCA9IHRoaXMuY2VydGlmaWNhdGUgPyBcImh0dHBzXCIgOiBcImh0dHBcIjtcbiAgICBjb25zdCBkb21haW4gPVxuICAgICAgdGhpcy5wcm9wcy5jbHVzdGVyPy5kb21haW4gfHwgdGhpcy5sb2FkQmFsYW5jZXIubG9hZEJhbGFuY2VyRG5zTmFtZTtcbiAgICByZXR1cm4gYCR7cHJvdG9jb2x9Oi8vJHtkb21haW59YDtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgYSBzZXJ2aWNlIHRvIHRoZSBjbHVzdGVyLlxuICAgKiBFYWNoIHNlcnZpY2UgZ2V0cyBpdHMgb3duIHRhc2sgZGVmaW5pdGlvbiwgY29udGFpbmVycywgYW5kIHRhcmdldCBncm91cC5cbiAgICovXG4gIHByaXZhdGUgYWRkU2VydmljZVRvQ2x1c3RlcihzZXJ2aWNlUHJvcHM6IEVjc1NlcnZpY2VQcm9wcyk6IHZvaWQge1xuICAgIGNvbnN0IHNlcnZpY2VOYW1lID0gc2VydmljZVByb3BzLm5hbWU7XG5cbiAgICAvLyBDcmVhdGUgc2VwYXJhdGUgcm9sZXMgZm9yIHNlY3VyaXR5IGJlc3QgcHJhY3RpY2VcbiAgICBjb25zdCBleGVjdXRpb25Sb2xlID0gdGhpcy5jcmVhdGVFeGVjdXRpb25Sb2xlKHNlcnZpY2VOYW1lKTtcbiAgICBjb25zdCB0YXNrUm9sZSA9IHRoaXMuY3JlYXRlVGFza1JvbGUoc2VydmljZU5hbWUsIHNlcnZpY2VQcm9wcyk7XG5cbiAgICAvLyBDcmVhdGUgdGFzayBkZWZpbml0aW9uIHdpdGggYm90aCByb2xlc1xuICAgIGNvbnN0IHRhc2tEZWZpbml0aW9uID0gdGhpcy5jcmVhdGVUYXNrRGVmaW5pdGlvbihcbiAgICAgIHNlcnZpY2VOYW1lLFxuICAgICAgc2VydmljZVByb3BzLFxuICAgICAgZXhlY3V0aW9uUm9sZSxcbiAgICAgIHRhc2tSb2xlXG4gICAgKTtcblxuICAgIC8vIEFkZCBjb250YWluZXJzIHRvIHRhc2sgZGVmaW5pdGlvblxuICAgIGNvbnN0IHsgY29udGFpbmVycywgcHJpbWFyeUNvbnRhaW5lciB9ID0gdGhpcy5hZGRDb250YWluZXJzVG9UYXNrKFxuICAgICAgc2VydmljZU5hbWUsXG4gICAgICBzZXJ2aWNlUHJvcHMsXG4gICAgICB0YXNrRGVmaW5pdGlvblxuICAgICk7XG5cbiAgICAvLyBDcmVhdGUgdGhlIEVDUyBzZXJ2aWNlXG4gICAgY29uc3Qgc2VydmljZSA9IHRoaXMuY3JlYXRlU2VydmljZShcbiAgICAgIHNlcnZpY2VOYW1lLFxuICAgICAgc2VydmljZVByb3BzLFxuICAgICAgdGFza0RlZmluaXRpb25cbiAgICApO1xuXG4gICAgLy8gUmVnaXN0ZXIgd2l0aCBBTEIgaWYgZW5hYmxlZCBhbmQgaGFzIHByaW1hcnkgY29udGFpbmVyIHdpdGggcG9ydFxuICAgIGxldCB0YXJnZXRHcm91cDogSUFwcGxpY2F0aW9uVGFyZ2V0R3JvdXAgfCB1bmRlZmluZWQ7XG4gICAgaWYgKFxuICAgICAgIXRoaXMubG9hZEJhbGFuY2VyRGlzYWJsZWQgJiZcbiAgICAgIHByaW1hcnlDb250YWluZXIgJiZcbiAgICAgIHRoaXMubG9hZEJhbGFuY2VyTGlzdGVuZXJcbiAgICApIHtcbiAgICAgIHRhcmdldEdyb3VwID0gdGhpcy5yZWdpc3RlclNlcnZpY2VXaXRoQUxCKFxuICAgICAgICBzZXJ2aWNlTmFtZSxcbiAgICAgICAgc2VydmljZVByb3BzLFxuICAgICAgICBzZXJ2aWNlLFxuICAgICAgICBwcmltYXJ5Q29udGFpbmVyXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIEFkZCBzY2FsaW5nIGlmIGNvbmZpZ3VyZWRcbiAgICBsZXQgc2NhbGluZ1BvbGljeTogVGFyZ2V0VHJhY2tpbmdTY2FsaW5nUG9saWN5IHwgdW5kZWZpbmVkO1xuICAgIGlmIChzZXJ2aWNlUHJvcHMuc2NhbGluZ1R5cGUpIHtcbiAgICAgIHNjYWxpbmdQb2xpY3kgPSB0aGlzLmFkZFNlcnZpY2VTY2FsaW5nKFxuICAgICAgICBzZXJ2aWNlTmFtZSxcbiAgICAgICAgc2VydmljZVByb3BzLFxuICAgICAgICBzZXJ2aWNlXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIFN0b3JlIHNlcnZpY2UgZGF0YVxuICAgIHRoaXMuc2VydmljZXMuc2V0KHNlcnZpY2VOYW1lLCB7XG4gICAgICBzZXJ2aWNlLFxuICAgICAgdGFza0RlZmluaXRpb24sXG4gICAgICBleGVjdXRpb25Sb2xlLFxuICAgICAgdGFza1JvbGUsXG4gICAgICBjb250YWluZXJzLFxuICAgICAgcHJpbWFyeUNvbnRhaW5lcixcbiAgICAgIHRhcmdldEdyb3VwLFxuICAgICAgc2NhbGluZ1BvbGljeVxuICAgIH0pO1xuXG4gICAgLy8gQWRkIHNlcnZpY2UgbGV2ZWwgY29ubmVjdGlvbnNcbiAgICBpZiAoc2VydmljZVByb3BzLmNvbm5lY3Rpb25zICYmIHNlcnZpY2VQcm9wcy5jb25uZWN0aW9ucy5sZW5ndGggPiAwKSB7XG4gICAgICBmb3IgKGNvbnN0IGNvbm5lY3RhYmxlIG9mIHNlcnZpY2VQcm9wcy5jb25uZWN0aW9ucykge1xuICAgICAgICBzZXJ2aWNlLmNvbm5lY3Rpb25zLmFsbG93VG9EZWZhdWx0UG9ydChjb25uZWN0YWJsZSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSB2YWxpZGF0ZVByb3BzKHByb3BzOiBFY3NDbHVzdGVyUHJvcHMpOiB2b2lkIHtcbiAgICAvLyBWYWxpZGF0ZSBzZXJ2aWNlcyBhcnJheVxuICAgIGlmICghcHJvcHMuc2VydmljZXMgfHwgcHJvcHMuc2VydmljZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJBdCBsZWFzdCBvbmUgc2VydmljZSBtdXN0IGJlIHNwZWNpZmllZC5cIik7XG4gICAgfVxuXG4gICAgLy8gQ2hlY2sgZm9yIGR1cGxpY2F0ZSBzZXJ2aWNlIG5hbWVzXG4gICAgY29uc3Qgc2VydmljZU5hbWVzID0gcHJvcHMuc2VydmljZXMubWFwKChzKSA9PiBzLm5hbWUpO1xuICAgIGNvbnN0IGR1cGxpY2F0ZVNlcnZpY2VzID0gc2VydmljZU5hbWVzLmZpbHRlcihcbiAgICAgIChuYW1lLCBpbmRleCkgPT4gc2VydmljZU5hbWVzLmluZGV4T2YobmFtZSkgIT09IGluZGV4XG4gICAgKTtcbiAgICBpZiAoZHVwbGljYXRlU2VydmljZXMubGVuZ3RoID4gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgRHVwbGljYXRlIHNlcnZpY2UgbmFtZXM6ICR7Wy4uLm5ldyBTZXQoZHVwbGljYXRlU2VydmljZXMpXS5qb2luKFwiLCBcIil9YFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBWYWxpZGF0ZSByb3V0aW5nIHdoZW4gbXVsdGlwbGUgc2VydmljZXMgaGF2ZSBwb3J0c1xuICAgIGNvbnN0IHNlcnZpY2VzV2l0aFBvcnRzID0gcHJvcHMuc2VydmljZXMuZmlsdGVyKChzKSA9PlxuICAgICAgcy5jb250YWluZXJzLnNvbWUoKGMpID0+IGMucG9ydCAhPT0gdW5kZWZpbmVkKVxuICAgICk7XG5cbiAgICBpZiAoc2VydmljZXNXaXRoUG9ydHMubGVuZ3RoID4gMSAmJiAhdGhpcy5sb2FkQmFsYW5jZXJEaXNhYmxlZCkge1xuICAgICAgY29uc3QgbWlzc2luZ1JvdXRpbmcgPSBzZXJ2aWNlc1dpdGhQb3J0cy5maWx0ZXIoXG4gICAgICAgIChzKSA9PiAhcy5yb3V0aW5nPy5wYXRoICYmICFzLnJvdXRpbmc/Lmhvc3RcbiAgICAgICk7XG4gICAgICBpZiAobWlzc2luZ1JvdXRpbmcubGVuZ3RoID4gMCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgYFNlcnZpY2VzIHdpdGggcG9ydHMgcmVxdWlyZSByb3V0aW5nIGNvbmZpZyB3aGVuIGNsdXN0ZXIgaGFzIG11bHRpcGxlIHNlcnZpY2VzOiBgICtcbiAgICAgICAgICAgIGAke21pc3NpbmdSb3V0aW5nLm1hcCgocykgPT4gcy5uYW1lKS5qb2luKFwiLCBcIil9LiBgICtcbiAgICAgICAgICAgIFwiQWRkIHJvdXRpbmc6IHsgcGF0aDogJy8uLi4nIH0gdG8gZWFjaCBzZXJ2aWNlLlwiXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gVmFsaWRhdGUgZWFjaCBzZXJ2aWNlJ3MgY29udGFpbmVyc1xuICAgIGZvciAoY29uc3Qgc2VydmljZSBvZiBwcm9wcy5zZXJ2aWNlcykge1xuICAgICAgaWYgKCFzZXJ2aWNlLmNvbnRhaW5lcnMgfHwgc2VydmljZS5jb250YWluZXJzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgYFNlcnZpY2UgJyR7c2VydmljZS5uYW1lfSc6IEF0IGxlYXN0IG9uZSBjb250YWluZXIgbXVzdCBiZSBzcGVjaWZpZWQuYFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICAvLyBDaGVjayBmb3IgZHVwbGljYXRlIGNvbnRhaW5lciBuYW1lcyB3aXRoaW4gc2VydmljZVxuICAgICAgY29uc3QgY29udGFpbmVyTmFtZXMgPSBzZXJ2aWNlLmNvbnRhaW5lcnMubWFwKChjKSA9PiBjLm5hbWUpO1xuICAgICAgY29uc3QgZHVwbGljYXRlQ29udGFpbmVycyA9IGNvbnRhaW5lck5hbWVzLmZpbHRlcihcbiAgICAgICAgKG5hbWUsIGluZGV4KSA9PiBjb250YWluZXJOYW1lcy5pbmRleE9mKG5hbWUpICE9PSBpbmRleFxuICAgICAgKTtcbiAgICAgIGlmIChkdXBsaWNhdGVDb250YWluZXJzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgIGBTZXJ2aWNlICcke3NlcnZpY2UubmFtZX0nOiBEdXBsaWNhdGUgY29udGFpbmVyIG5hbWVzOiBgICtcbiAgICAgICAgICAgIGAke1suLi5uZXcgU2V0KGR1cGxpY2F0ZUNvbnRhaW5lcnMpXS5qb2luKFwiLCBcIil9YFxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgc2V0dXBDb25uZWN0aW9ucyhwcm9wczogRWNzQ2x1c3RlclByb3BzKTogdm9pZCB7XG4gICAgLy8gRmluZCB0aGUgZmlyc3Qgc2VydmljZSB3aXRoIGEgcG9ydCBmb3IgZGVmYXVsdCBjb25uZWN0aW9uXG4gICAgbGV0IGRlZmF1bHRQb3J0ID0gODA7XG4gICAgZm9yIChjb25zdCBzZXJ2aWNlIG9mIHByb3BzLnNlcnZpY2VzKSB7XG4gICAgICBjb25zdCBwcmltYXJ5Q29udGFpbmVyID0gc2VydmljZS5jb250YWluZXJzLmZpbmQoXG4gICAgICAgIChjKSA9PiBjLnBvcnQgIT09IHVuZGVmaW5lZFxuICAgICAgKTtcbiAgICAgIGlmIChwcmltYXJ5Q29udGFpbmVyPy5wb3J0KSB7XG4gICAgICAgIGRlZmF1bHRQb3J0ID0gcHJpbWFyeUNvbnRhaW5lci5wb3J0O1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG5cbiAgICBsZXQgc2VjdXJpdHlHcm91cHM6IElTZWN1cml0eUdyb3VwW10gPSBbXTtcbiAgICBpZiAodGhpcy5pc0VjMigpKSB7XG4gICAgICBzZWN1cml0eUdyb3VwcyA9IFt0aGlzLmFzZ1NlY3VyaXR5R3JvdXAhXTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgZmlyc3RTZXJ2aWNlID0gdGhpcy5zZXJ2aWNlcy52YWx1ZXMoKS5uZXh0KCkudmFsdWU7XG4gICAgICBzZWN1cml0eUdyb3VwcyA9IGZpcnN0U2VydmljZT8uc2VydmljZT8uY29ubmVjdGlvbnM/LnNlY3VyaXR5R3JvdXBzIHx8IFtdO1xuICAgIH1cblxuICAgIHRoaXMuY29ubmVjdGlvbnMgPSBuZXcgQ29ubmVjdGlvbnMoe1xuICAgICAgc2VjdXJpdHlHcm91cHMsXG4gICAgICBkZWZhdWx0UG9ydDogUG9ydC50Y3AoZGVmYXVsdFBvcnQpXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyB0aGUgZXhlY3V0aW9uIHJvbGUgZm9yIEVDUyBpbmZyYXN0cnVjdHVyZSBvcGVyYXRpb25zLlxuICAgKiBVc2VkIGJ5IHRoZSBFQ1MgYWdlbnQgdG8gcHVsbCBpbWFnZXMsIHdyaXRlIGxvZ3MsIGFuZCBpbmplY3Qgc2VjcmV0cy5cbiAgICogTk9UIHVzZWQgYnkgYXBwbGljYXRpb24gY29kZSAtIHRoYXQncyB0aGUgdGFzayByb2xlLlxuICAgKi9cbiAgcHJpdmF0ZSBjcmVhdGVFeGVjdXRpb25Sb2xlKHNlcnZpY2VOYW1lOiBzdHJpbmcpOiBSb2xlIHtcbiAgICBjb25zdCBleGVjdXRpb25Sb2xlID0gbmV3IFJvbGUodGhpcywgYCR7c2VydmljZU5hbWV9RXhlY3V0aW9uUm9sZWAsIHtcbiAgICAgIGFzc3VtZWRCeTogbmV3IFNlcnZpY2VQcmluY2lwYWwoXCJlY3MtdGFza3MuYW1hem9uYXdzLmNvbVwiKVxuICAgIH0pO1xuXG4gICAgLy8gRUNSIHB1bGwgcGVybWlzc2lvbnNcbiAgICBleGVjdXRpb25Sb2xlLmFkZFRvUG9saWN5KFxuICAgICAgbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgIGVmZmVjdDogRWZmZWN0LkFMTE9XLFxuICAgICAgICBhY3Rpb25zOiBbXG4gICAgICAgICAgXCJlY3I6R2V0QXV0aG9yaXphdGlvblRva2VuXCIsXG4gICAgICAgICAgXCJlY3I6QmF0Y2hDaGVja0xheWVyQXZhaWxhYmlsaXR5XCIsXG4gICAgICAgICAgXCJlY3I6R2V0RG93bmxvYWRVcmxGb3JMYXllclwiLFxuICAgICAgICAgIFwiZWNyOkJhdGNoR2V0SW1hZ2VcIlxuICAgICAgICBdLFxuICAgICAgICByZXNvdXJjZXM6IFtcIipcIl1cbiAgICAgIH0pXG4gICAgKTtcblxuICAgIC8vIENsb3VkV2F0Y2ggTG9ncyBwZXJtaXNzaW9uc1xuICAgIGV4ZWN1dGlvblJvbGUuYWRkVG9Qb2xpY3koXG4gICAgICBuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgZWZmZWN0OiBFZmZlY3QuQUxMT1csXG4gICAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgICBcImxvZ3M6Q3JlYXRlTG9nU3RyZWFtXCIsXG4gICAgICAgICAgXCJsb2dzOlB1dExvZ0V2ZW50c1wiLFxuICAgICAgICAgIFwibG9nczpDcmVhdGVMb2dHcm91cFwiXG4gICAgICAgIF0sXG4gICAgICAgIHJlc291cmNlczogW1wiKlwiXVxuICAgICAgfSlcbiAgICApO1xuXG4gICAgLy8gU2VjcmV0cyBNYW5hZ2VyIGFjY2VzcyBmb3IgaW5qZWN0aW5nIHNlY3JldHMgaW50byBjb250YWluZXJzXG4gICAgZXhlY3V0aW9uUm9sZS5hZGRUb1BvbGljeShcbiAgICAgIG5ldyBQb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBlZmZlY3Q6IEVmZmVjdC5BTExPVyxcbiAgICAgICAgYWN0aW9uczogW1xuICAgICAgICAgIFwic2VjcmV0c21hbmFnZXI6R2V0U2VjcmV0VmFsdWVcIixcbiAgICAgICAgICBcInNlY3JldHNtYW5hZ2VyOkRlc2NyaWJlU2VjcmV0XCJcbiAgICAgICAgXSxcbiAgICAgICAgcmVzb3VyY2VzOiBbXCIqXCJdXG4gICAgICB9KVxuICAgICk7XG5cbiAgICAvLyBLTVMgZGVjcnlwdCBmb3Igc2VjcmV0cyBlbmNyeXB0ZWQgd2l0aCBjdXN0b21lci1tYW5hZ2VkIGtleXNcbiAgICBleGVjdXRpb25Sb2xlLmFkZFRvUG9saWN5KFxuICAgICAgbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgIGVmZmVjdDogRWZmZWN0LkFMTE9XLFxuICAgICAgICBhY3Rpb25zOiBbXCJrbXM6RGVjcnlwdFwiXSxcbiAgICAgICAgcmVzb3VyY2VzOiBbXCIqXCJdXG4gICAgICB9KVxuICAgICk7XG5cbiAgICByZXR1cm4gZXhlY3V0aW9uUm9sZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIHRoZSB0YXNrIHJvbGUgZm9yIGFwcGxpY2F0aW9uIGNvZGUgcnVubmluZyBpbiB0aGUgY29udGFpbmVyLlxuICAgKiBUaGlzIHJvbGUgaXMgYXNzdW1lZCBieSB0aGUgYXBwbGljYXRpb24sIG5vdCB0aGUgRUNTIGFnZW50LlxuICAgKiBJbmNsdWRlcyBkZWZhdWx0IEVDUyBFeGVjIHBlcm1pc3Npb25zIHBsdXMgYW55IHNlcnZpY2Utc3BlY2lmaWMgcG9saWNpZXMuXG4gICAqL1xuICBwcml2YXRlIGNyZWF0ZVRhc2tSb2xlKFxuICAgIHNlcnZpY2VOYW1lOiBzdHJpbmcsXG4gICAgc2VydmljZVByb3BzOiBFY3NTZXJ2aWNlUHJvcHNcbiAgKTogUm9sZSB7XG4gICAgY29uc3QgdGFza1JvbGUgPSBuZXcgUm9sZSh0aGlzLCBgJHtzZXJ2aWNlTmFtZX1UYXNrUm9sZWAsIHtcbiAgICAgIGFzc3VtZWRCeTogbmV3IFNlcnZpY2VQcmluY2lwYWwoXCJlY3MtdGFza3MuYW1hem9uYXdzLmNvbVwiKVxuICAgIH0pO1xuXG4gICAgLy8gRGVmYXVsdDogU1NNIHBlcm1pc3Npb25zIGZvciBFQ1MgRXhlYyAoZWNzIGV4ZWN1dGUtY29tbWFuZClcbiAgICB0YXNrUm9sZS5hZGRUb1BvbGljeShcbiAgICAgIG5ldyBQb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBlZmZlY3Q6IEVmZmVjdC5BTExPVyxcbiAgICAgICAgYWN0aW9uczogW1xuICAgICAgICAgIFwic3NtbWVzc2FnZXM6Q3JlYXRlQ29udHJvbENoYW5uZWxcIixcbiAgICAgICAgICBcInNzbW1lc3NhZ2VzOkNyZWF0ZURhdGFDaGFubmVsXCIsXG4gICAgICAgICAgXCJzc21tZXNzYWdlczpPcGVuQ29udHJvbENoYW5uZWxcIixcbiAgICAgICAgICBcInNzbW1lc3NhZ2VzOk9wZW5EYXRhQ2hhbm5lbFwiXG4gICAgICAgIF0sXG4gICAgICAgIHJlc291cmNlczogW1wiKlwiXVxuICAgICAgfSlcbiAgICApO1xuXG4gICAgLy8gQWRkIHNlcnZpY2Utc3BlY2lmaWMgaW5saW5lIHBvbGljaWVzXG4gICAgaWYgKHNlcnZpY2VQcm9wcy50YXNrUm9sZUlubGluZVBvbGljaWVzKSB7XG4gICAgICBmb3IgKGNvbnN0IFtwb2xpY3lOYW1lLCBwb2xpY3lEb2N1bWVudF0gb2YgT2JqZWN0LmVudHJpZXMoXG4gICAgICAgIHNlcnZpY2VQcm9wcy50YXNrUm9sZUlubGluZVBvbGljaWVzXG4gICAgICApKSB7XG4gICAgICAgIHRhc2tSb2xlLmF0dGFjaElubGluZVBvbGljeShcbiAgICAgICAgICBuZXcgUG9saWN5KHRoaXMsIGAke3NlcnZpY2VOYW1lfSR7cG9saWN5TmFtZX1gLCB7XG4gICAgICAgICAgICBkb2N1bWVudDogcG9saWN5RG9jdW1lbnRcbiAgICAgICAgICB9KVxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEFkZCBzZXJ2aWNlLXNwZWNpZmljIG1hbmFnZWQgcG9saWNpZXNcbiAgICBpZiAoc2VydmljZVByb3BzLnRhc2tSb2xlTWFuYWdlZFBvbGljaWVzKSB7XG4gICAgICBmb3IgKGNvbnN0IHBvbGljeSBvZiBzZXJ2aWNlUHJvcHMudGFza1JvbGVNYW5hZ2VkUG9saWNpZXMpIHtcbiAgICAgICAgdGFza1JvbGUuYWRkTWFuYWdlZFBvbGljeShwb2xpY3kpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0YXNrUm9sZTtcbiAgfVxuXG4gIHByaXZhdGUgY3JlYXRlVGFza0RlZmluaXRpb24oXG4gICAgc2VydmljZU5hbWU6IHN0cmluZyxcbiAgICBzZXJ2aWNlUHJvcHM6IEVjc1NlcnZpY2VQcm9wcyxcbiAgICBleGVjdXRpb25Sb2xlOiBSb2xlLFxuICAgIHRhc2tSb2xlOiBSb2xlXG4gICk6IEZhcmdhdGVUYXNrRGVmaW5pdGlvbiB8IEVjMlRhc2tEZWZpbml0aW9uIHtcbiAgICBjb25zdCBjcHUgPSBzZXJ2aWNlUHJvcHMuY3B1IHx8IDI1NjtcbiAgICBjb25zdCBtZW1vcnlMaW1pdE1pQiA9IHNlcnZpY2VQcm9wcy5tZW1vcnlMaW1pdE1pQiB8fCA1MTI7XG5cbiAgICBpZiAodGhpcy5pc0ZhcmdhdGUoKSkge1xuICAgICAgcmV0dXJuIG5ldyBGYXJnYXRlVGFza0RlZmluaXRpb24odGhpcywgYCR7c2VydmljZU5hbWV9VGFza0RlZmluaXRpb25gLCB7XG4gICAgICAgIGZhbWlseTogYCR7dGhpcy5wcm9wcy5jbHVzdGVyTmFtZX0tJHtzZXJ2aWNlTmFtZX1gLFxuICAgICAgICBjcHUsXG4gICAgICAgIG1lbW9yeUxpbWl0TWlCLFxuICAgICAgICBleGVjdXRpb25Sb2xlLFxuICAgICAgICB0YXNrUm9sZSxcbiAgICAgICAgcnVudGltZVBsYXRmb3JtOiB7XG4gICAgICAgICAgY3B1QXJjaGl0ZWN0dXJlOiBDcHVBcmNoaXRlY3R1cmUuQVJNNjQsXG4gICAgICAgICAgb3BlcmF0aW5nU3lzdGVtRmFtaWx5OiBPcGVyYXRpbmdTeXN0ZW1GYW1pbHkuTElOVVhcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBuZXcgRWMyVGFza0RlZmluaXRpb24odGhpcywgYCR7c2VydmljZU5hbWV9VGFza0RlZmluaXRpb25gLCB7XG4gICAgICAgIGZhbWlseTogYCR7dGhpcy5wcm9wcy5jbHVzdGVyTmFtZX0tJHtzZXJ2aWNlTmFtZX1gLFxuICAgICAgICBleGVjdXRpb25Sb2xlLFxuICAgICAgICB0YXNrUm9sZSxcbiAgICAgICAgLi4uKHRoaXMuZGlyZWN0QWNjZXNzRW5hYmxlZCAmJiB7IG5ldHdvcmtNb2RlOiBOZXR3b3JrTW9kZS5IT1NUIH0pXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFkZENvbnRhaW5lcnNUb1Rhc2soXG4gICAgc2VydmljZU5hbWU6IHN0cmluZyxcbiAgICBzZXJ2aWNlUHJvcHM6IEVjc1NlcnZpY2VQcm9wcyxcbiAgICB0YXNrRGVmaW5pdGlvbjogRmFyZ2F0ZVRhc2tEZWZpbml0aW9uIHwgRWMyVGFza0RlZmluaXRpb25cbiAgKToge1xuICAgIGNvbnRhaW5lcnM6IENvbnRhaW5lckRlZmluaXRpb25bXTtcbiAgICBwcmltYXJ5Q29udGFpbmVyPzogQ29udGFpbmVyRGVmaW5pdGlvbjtcbiAgfSB7XG4gICAgY29uc3QgY29udGFpbmVyczogQ29udGFpbmVyRGVmaW5pdGlvbltdID0gW107XG4gICAgbGV0IHByaW1hcnlDb250YWluZXI6IENvbnRhaW5lckRlZmluaXRpb24gfCB1bmRlZmluZWQ7XG5cbiAgICBmb3IgKGNvbnN0IGNvbnRhaW5lckNvbmZpZyBvZiBzZXJ2aWNlUHJvcHMuY29udGFpbmVycykge1xuICAgICAgY29uc3QgaW1hZ2UgPSB0aGlzLmdldENvbnRhaW5lckltYWdlKFxuICAgICAgICBzZXJ2aWNlTmFtZSxcbiAgICAgICAgY29udGFpbmVyQ29uZmlnLFxuICAgICAgICBzZXJ2aWNlUHJvcHNcbiAgICAgICk7XG4gICAgICBjb25zdCBpc0ZpcnN0V2l0aFBvcnQgPVxuICAgICAgICAhcHJpbWFyeUNvbnRhaW5lciAmJiBjb250YWluZXJDb25maWcucG9ydCAhPT0gdW5kZWZpbmVkO1xuXG4gICAgICAvLyBCdWlsZCBzZWNyZXRzXG4gICAgICBjb25zdCBzZWNyZXRzOiBSZWNvcmQ8c3RyaW5nLCBFY3NTZWNyZXQ+ID0ge307XG4gICAgICBpZiAoY29udGFpbmVyQ29uZmlnLnNlY3JldHNJbXBvcnQpIHtcbiAgICAgICAgZm9yIChjb25zdCBba2V5LCBzZWNyZXRJbXBvcnRdIG9mIE9iamVjdC5lbnRyaWVzKFxuICAgICAgICAgIGNvbnRhaW5lckNvbmZpZy5zZWNyZXRzSW1wb3J0XG4gICAgICAgICkpIHtcbiAgICAgICAgICBjb25zdCBzZWNyZXQgPSBTZWNyZXQuZnJvbVNlY3JldE5hbWVWMihcbiAgICAgICAgICAgIHRoaXMsXG4gICAgICAgICAgICBgJHtzZXJ2aWNlTmFtZX0ke2NvbnRhaW5lckNvbmZpZy5uYW1lfSR7a2V5fVNlY3JldGAsXG4gICAgICAgICAgICBzZWNyZXRJbXBvcnQubmFtZVxuICAgICAgICAgICk7XG4gICAgICAgICAgc2VjcmV0c1trZXldID0gRWNzU2VjcmV0LmZyb21TZWNyZXRzTWFuYWdlcihcbiAgICAgICAgICAgIHNlY3JldCxcbiAgICAgICAgICAgIHNlY3JldEltcG9ydC5maWVsZFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgY29uc3QgY29udGFpbmVyID0gdGFza0RlZmluaXRpb24uYWRkQ29udGFpbmVyKFxuICAgICAgICBgJHtzZXJ2aWNlTmFtZX0ke2NvbnRhaW5lckNvbmZpZy5uYW1lfWAsXG4gICAgICAgIHtcbiAgICAgICAgICBpbWFnZSxcbiAgICAgICAgICBjb250YWluZXJOYW1lOiBjb250YWluZXJDb25maWcubmFtZSxcbiAgICAgICAgICBsb2dnaW5nOiBuZXcgQXdzTG9nRHJpdmVyKHtcbiAgICAgICAgICAgIHN0cmVhbVByZWZpeDogYC9lY3MvJHt0aGlzLnByb3BzLmNsdXN0ZXJOYW1lfS8ke3NlcnZpY2VOYW1lfS8ke2NvbnRhaW5lckNvbmZpZy5uYW1lfWAsXG4gICAgICAgICAgICBsb2dSZXRlbnRpb246IDE0XG4gICAgICAgICAgfSksXG4gICAgICAgICAgZW52aXJvbm1lbnQ6IGNvbnRhaW5lckNvbmZpZy5lbnZpcm9ubWVudCxcbiAgICAgICAgICBzZWNyZXRzLFxuICAgICAgICAgIGNvbW1hbmQ6IGNvbnRhaW5lckNvbmZpZy5jb21tYW5kLFxuICAgICAgICAgIGVudHJ5UG9pbnQ6IGNvbnRhaW5lckNvbmZpZy5lbnRyeVBvaW50LFxuICAgICAgICAgIGVzc2VudGlhbDogY29udGFpbmVyQ29uZmlnLmVzc2VudGlhbCA/PyB0cnVlLFxuICAgICAgICAgIGhlYWx0aENoZWNrOiBjb250YWluZXJDb25maWcuaGVhbHRoQ2hlY2tcbiAgICAgICAgICAgID8ge1xuICAgICAgICAgICAgICAgIGNvbW1hbmQ6IGNvbnRhaW5lckNvbmZpZy5oZWFsdGhDaGVjay5jb21tYW5kLFxuICAgICAgICAgICAgICAgIGludGVydmFsOiBjb250YWluZXJDb25maWcuaGVhbHRoQ2hlY2suaW50ZXJ2YWxcbiAgICAgICAgICAgICAgICAgID8gRHVyYXRpb24uc2Vjb25kcyhjb250YWluZXJDb25maWcuaGVhbHRoQ2hlY2suaW50ZXJ2YWwpXG4gICAgICAgICAgICAgICAgICA6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgICB0aW1lb3V0OiBjb250YWluZXJDb25maWcuaGVhbHRoQ2hlY2sudGltZW91dFxuICAgICAgICAgICAgICAgICAgPyBEdXJhdGlvbi5zZWNvbmRzKGNvbnRhaW5lckNvbmZpZy5oZWFsdGhDaGVjay50aW1lb3V0KVxuICAgICAgICAgICAgICAgICAgOiB1bmRlZmluZWQsXG4gICAgICAgICAgICAgICAgcmV0cmllczogY29udGFpbmVyQ29uZmlnLmhlYWx0aENoZWNrLnJldHJpZXMsXG4gICAgICAgICAgICAgICAgc3RhcnRQZXJpb2Q6IGNvbnRhaW5lckNvbmZpZy5oZWFsdGhDaGVjay5zdGFydFBlcmlvZFxuICAgICAgICAgICAgICAgICAgPyBEdXJhdGlvbi5zZWNvbmRzKGNvbnRhaW5lckNvbmZpZy5oZWFsdGhDaGVjay5zdGFydFBlcmlvZClcbiAgICAgICAgICAgICAgICAgIDogdW5kZWZpbmVkXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIDogdW5kZWZpbmVkLFxuICAgICAgICAgIC4uLih0aGlzLmlzRWMyKCkgJiYge1xuICAgICAgICAgICAgbWVtb3J5TGltaXRNaUI6IHRoaXMucHJvcHMuZWMyQ29uZmlnPy5tZW1vcnlMaW1pdE1pQiB8fCAxMDI0XG4gICAgICAgICAgfSlcbiAgICAgICAgfVxuICAgICAgKTtcblxuICAgICAgaWYgKGNvbnRhaW5lckNvbmZpZy5wb3J0KSB7XG4gICAgICAgIGNvbnRhaW5lci5hZGRQb3J0TWFwcGluZ3Moe1xuICAgICAgICAgIGNvbnRhaW5lclBvcnQ6IGNvbnRhaW5lckNvbmZpZy5wb3J0XG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAoaXNGaXJzdFdpdGhQb3J0KSB7XG4gICAgICAgIHByaW1hcnlDb250YWluZXIgPSBjb250YWluZXI7XG4gICAgICB9XG5cbiAgICAgIGNvbnRhaW5lcnMucHVzaChjb250YWluZXIpO1xuICAgIH1cblxuICAgIHJldHVybiB7IGNvbnRhaW5lcnMsIHByaW1hcnlDb250YWluZXIgfTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0Q29udGFpbmVySW1hZ2UoXG4gICAgc2VydmljZU5hbWU6IHN0cmluZyxcbiAgICBjb250YWluZXJDb25maWc6IEVjc0NsdXN0ZXJDb250YWluZXJDb25maWcsXG4gICAgc2VydmljZVByb3BzOiBFY3NTZXJ2aWNlUHJvcHNcbiAgKTogQ29udGFpbmVySW1hZ2Uge1xuICAgIC8vIFByaW9yaXR5OiBjb250YWluZXIuaW1hZ2UgPiBzZXJ2aWNlLmltYWdlID4gY2x1c3RlciBkZWZhdWx0XG4gICAgY29uc3QgaW1hZ2VTb3VyY2UgPVxuICAgICAgY29udGFpbmVyQ29uZmlnLmltYWdlIHx8IHNlcnZpY2VQcm9wcy5pbWFnZSB8fCB0aGlzLnByb3BzLmVjclJlcG9zaXRvcnk7XG5cbiAgICBpZiAoIWltYWdlU291cmNlKSB7XG4gICAgICByZXR1cm4gQ29udGFpbmVySW1hZ2UuZnJvbVJlZ2lzdHJ5KFwiYW1hem9uL2FtYXpvbi1lY3Mtc2FtcGxlXCIpO1xuICAgIH1cblxuICAgIC8vIEZvciBtdWx0aS1zZXJ2aWNlIGRlcGxveW1lbnRzLCB1c2Ugc2VydmljZS1wcmVmaXhlZCB0YWdzXG4gICAgY29uc3QgaXNNdWx0aVNlcnZpY2UgPSB0aGlzLnByb3BzLnNlcnZpY2VzLmxlbmd0aCA+IDE7XG4gICAgY29uc3QgaW1hZ2VUYWcgPSBpc011bHRpU2VydmljZSA/IGAke3NlcnZpY2VOYW1lfS1sYXRlc3RgIDogXCJsYXRlc3RcIjtcblxuICAgIGlmICh0eXBlb2YgaW1hZ2VTb3VyY2UgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIC8vIENoZWNrIGlmIGl0J3MgYW4gRUNSIHJlcG9zaXRvcnkgbmFtZSBvciBhIHB1YmxpYyBpbWFnZVxuICAgICAgaWYgKGltYWdlU291cmNlLmluY2x1ZGVzKFwiL1wiKSAmJiAhaW1hZ2VTb3VyY2UuaW5jbHVkZXMoXCIuXCIpKSB7XG4gICAgICAgIHJldHVybiBDb250YWluZXJJbWFnZS5mcm9tUmVnaXN0cnkoaW1hZ2VTb3VyY2UpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIENvbnRhaW5lckltYWdlLmZyb21FY3JSZXBvc2l0b3J5KFxuICAgICAgICBSZXBvc2l0b3J5LmZyb21SZXBvc2l0b3J5TmFtZShcbiAgICAgICAgICB0aGlzLFxuICAgICAgICAgIGAke3NlcnZpY2VOYW1lfSR7Y29udGFpbmVyQ29uZmlnLm5hbWV9RWNyUmVwb2AsXG4gICAgICAgICAgaW1hZ2VTb3VyY2VcbiAgICAgICAgKSxcbiAgICAgICAgaW1hZ2VUYWdcbiAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKGltYWdlU291cmNlIGluc3RhbmNlb2YgUmVwb3NpdG9yeSkge1xuICAgICAgcmV0dXJuIENvbnRhaW5lckltYWdlLmZyb21FY3JSZXBvc2l0b3J5KGltYWdlU291cmNlLCBpbWFnZVRhZyk7XG4gICAgfVxuXG4gICAgLy8gUmVwb3NpdG9yeUltYWdlIGV4dGVuZHMgQ29udGFpbmVySW1hZ2UsIHNvIHRoaXMgaXMgYSBzYWZlIHVwY2FzdFxuICAgIHJldHVybiBpbWFnZVNvdXJjZSBhcyBDb250YWluZXJJbWFnZTtcbiAgfVxuXG4gIHByaXZhdGUgY3JlYXRlU2VydmljZShcbiAgICBzZXJ2aWNlTmFtZTogc3RyaW5nLFxuICAgIHNlcnZpY2VQcm9wczogRWNzU2VydmljZVByb3BzLFxuICAgIHRhc2tEZWZpbml0aW9uOiBGYXJnYXRlVGFza0RlZmluaXRpb24gfCBFYzJUYXNrRGVmaW5pdGlvblxuICApOiBGYXJnYXRlU2VydmljZSB8IEVjMlNlcnZpY2Uge1xuICAgIGNvbnN0IGRlc2lyZWRDb3VudCA9IHNlcnZpY2VQcm9wcy5kZXNpcmVkQ291bnQgPz8gMjtcblxuICAgIGlmICh0aGlzLmlzRmFyZ2F0ZSgpKSB7XG4gICAgICBjb25zdCBzZXJ2aWNlID0gbmV3IEZhcmdhdGVTZXJ2aWNlKHRoaXMsIGAke3NlcnZpY2VOYW1lfVNlcnZpY2VgLCB7XG4gICAgICAgIGNsdXN0ZXI6IHRoaXMuY2x1c3RlcixcbiAgICAgICAgdGFza0RlZmluaXRpb246IHRhc2tEZWZpbml0aW9uIGFzIEZhcmdhdGVUYXNrRGVmaW5pdGlvbixcbiAgICAgICAgZGVzaXJlZENvdW50LFxuICAgICAgICBzZXJ2aWNlTmFtZSxcbiAgICAgICAgY2FwYWNpdHlQcm92aWRlclN0cmF0ZWdpZXM6IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBjYXBhY2l0eVByb3ZpZGVyOiB0aGlzLmNhcGFjaXR5UHJvdmlkZXIsXG4gICAgICAgICAgICB3ZWlnaHQ6IDFcbiAgICAgICAgICB9XG4gICAgICAgIF0sXG4gICAgICAgIHByb3BhZ2F0ZVRhZ3M6IFByb3BhZ2F0ZWRUYWdTb3VyY2UuU0VSVklDRSxcbiAgICAgICAgY2lyY3VpdEJyZWFrZXI6IHsgZW5hYmxlOiB0cnVlLCByb2xsYmFjazogdHJ1ZSB9LFxuICAgICAgICBlbmFibGVFQ1NNYW5hZ2VkVGFnczogdHJ1ZSxcbiAgICAgICAgZW5hYmxlRXhlY3V0ZUNvbW1hbmQ6IHRydWUsXG4gICAgICAgIGhlYWx0aENoZWNrR3JhY2VQZXJpb2Q6IER1cmF0aW9uLnNlY29uZHMoMTIwKSxcbiAgICAgICAgbWluSGVhbHRoeVBlcmNlbnQ6IDEwMCxcbiAgICAgICAgbWF4SGVhbHRoeVBlcmNlbnQ6IDIwMFxuICAgICAgfSk7XG5cbiAgICAgIG5ldyBDZm5PdXRwdXQodGhpcywgYCR7c2VydmljZU5hbWV9U2VydmljZUFybmAsIHtcbiAgICAgICAga2V5OiBgJHtzZXJ2aWNlTmFtZX1TZXJ2aWNlQXJuYCxcbiAgICAgICAgZXhwb3J0TmFtZTogYCR7dGhpcy5wcm9wcy5jbHVzdGVyTmFtZX0ke3NlcnZpY2VOYW1lfVNlcnZpY2VBcm5gLFxuICAgICAgICB2YWx1ZTogc2VydmljZS5zZXJ2aWNlQXJuLFxuICAgICAgICBkZXNjcmlwdGlvbjogYEVDUyBTZXJ2aWNlIEFSTiBmb3IgJHtzZXJ2aWNlTmFtZX1gXG4gICAgICB9KTtcblxuICAgICAgLy8gRmFyZ2F0ZSBzZXJ2aWNlIGRlcGVuZHMgb24gY2FwYWNpdHkgcHJvdmlkZXIgYXNzb2NpYXRpb25zOlxuICAgICAgLy8gLSBDUkVBVEU6IEFzc29jaWF0aW9ucyBjcmVhdGVkIGZpcnN0LCB0aGVuIFNlcnZpY2UgKGNvcnJlY3QgLSBwcm92aWRlcnMgcmVhZHkgYmVmb3JlIHNlcnZpY2UpXG4gICAgICAvLyAtIERFTEVURTogU2VydmljZSBkZWxldGVkIGZpcnN0LCB0aGVuIEFzc29jaWF0aW9ucyAoY29ycmVjdCAtIHNlcnZpY2VzIGdvbmUgYmVmb3JlIGRpc2Fzc29jaWF0aW9uKVxuICAgICAgLy8gVGhpcyBlbnN1cmVzIENsb3VkRm9ybWF0aW9uIGRlbGV0ZXMgYWxsIHNlcnZpY2VzIEJFRk9SRSBhdHRlbXB0aW5nIHRvIHJlbW92ZVxuICAgICAgLy8gdGhlIEZBUkdBVEUvRkFSR0FURV9TUE9UIGNhcGFjaXR5IHByb3ZpZGVyIGFzc29jaWF0aW9ucyBmcm9tIHRoZSBjbHVzdGVyLlxuICAgICAgLy8gU2VlOiBodHRwczovL2dpdGh1Yi5jb20vYXdzL2F3cy1jZGsvaXNzdWVzLzE1MzY2XG4gICAgICBpZiAodGhpcy5mYXJnYXRlQ2FwYWNpdHlQcm92aWRlckFzc29jaWF0aW9ucykge1xuICAgICAgICBzZXJ2aWNlLm5vZGUuYWRkRGVwZW5kZW5jeSh0aGlzLmZhcmdhdGVDYXBhY2l0eVByb3ZpZGVyQXNzb2NpYXRpb25zKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHNlcnZpY2U7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IHNlcnZpY2UgPSBuZXcgRWMyU2VydmljZSh0aGlzLCBgJHtzZXJ2aWNlTmFtZX1TZXJ2aWNlYCwge1xuICAgICAgICBjbHVzdGVyOiB0aGlzLmNsdXN0ZXIsXG4gICAgICAgIHRhc2tEZWZpbml0aW9uOiB0YXNrRGVmaW5pdGlvbiBhcyBFYzJUYXNrRGVmaW5pdGlvbixcbiAgICAgICAgZGVzaXJlZENvdW50LFxuICAgICAgICBzZXJ2aWNlTmFtZSxcbiAgICAgICAgY2FwYWNpdHlQcm92aWRlclN0cmF0ZWdpZXM6IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBjYXBhY2l0eVByb3ZpZGVyOiB0aGlzLmFzZ0NhcGFjaXR5UHJvdmlkZXIhLmNhcGFjaXR5UHJvdmlkZXJOYW1lLFxuICAgICAgICAgICAgd2VpZ2h0OiAxXG4gICAgICAgICAgfVxuICAgICAgICBdLFxuICAgICAgICBwcm9wYWdhdGVUYWdzOiBQcm9wYWdhdGVkVGFnU291cmNlLlNFUlZJQ0UsXG4gICAgICAgIGNpcmN1aXRCcmVha2VyOiB7IGVuYWJsZTogdHJ1ZSwgcm9sbGJhY2s6IHRydWUgfSxcbiAgICAgICAgcGxhY2VtZW50U3RyYXRlZ2llczogW1BsYWNlbWVudFN0cmF0ZWd5LnNwcmVhZEFjcm9zc0luc3RhbmNlcygpXSxcbiAgICAgICAgZW5hYmxlRUNTTWFuYWdlZFRhZ3M6IHRydWUsXG4gICAgICAgIGVuYWJsZUV4ZWN1dGVDb21tYW5kOiB0cnVlLFxuICAgICAgICBoZWFsdGhDaGVja0dyYWNlUGVyaW9kOiBEdXJhdGlvbi5zZWNvbmRzKDEyMCksXG4gICAgICAgIG1pbkhlYWx0aHlQZXJjZW50OiAxMDAsXG4gICAgICAgIG1heEhlYWx0aHlQZXJjZW50OiAyMDBcbiAgICAgIH0pO1xuXG4gICAgICBuZXcgQ2ZuT3V0cHV0KHRoaXMsIGAke3NlcnZpY2VOYW1lfVNlcnZpY2VBcm5gLCB7XG4gICAgICAgIGtleTogYCR7c2VydmljZU5hbWV9U2VydmljZUFybmAsXG4gICAgICAgIGV4cG9ydE5hbWU6IGAke3RoaXMucHJvcHMuY2x1c3Rlck5hbWV9JHtzZXJ2aWNlTmFtZX1TZXJ2aWNlQXJuYCxcbiAgICAgICAgdmFsdWU6IHNlcnZpY2Uuc2VydmljZUFybixcbiAgICAgICAgZGVzY3JpcHRpb246IGBFQ1MgU2VydmljZSBBUk4gZm9yICR7c2VydmljZU5hbWV9YFxuICAgICAgfSk7XG5cbiAgICAgIC8vIFNlcnZpY2UgZGVwZW5kcyBvbiBEcmFpbldhaXRlcjpcbiAgICAgIC8vIC0gQ1JFQVRFOiBEcmFpbldhaXRlciBjcmVhdGVkIGZpcnN0LCB0aGVuIFNlcnZpY2UgKGNvcnJlY3QgLSBpbmZyYSByZWFkeSBiZWZvcmUgc2VydmljZSlcbiAgICAgIC8vIC0gREVMRVRFOiBTZXJ2aWNlIGRlbGV0ZWQgZmlyc3QsIHRoZW4gRHJhaW5XYWl0ZXIgcnVucyAoY29ycmVjdCAtIHNlcnZpY2VzIGdvbmUgYmVmb3JlIGRyYWluKVxuICAgICAgLy8gVGhpcyBlbnN1cmVzIENsb3VkRm9ybWF0aW9uIGRlbGV0ZXMgYWxsIHNlcnZpY2VzIEJFRk9SRSB0aGUgRHJhaW5XYWl0ZXIgTGFtYmRhIHJ1bnMsXG4gICAgICAvLyB3aGljaCB0aGVuIGRpc2Fzc29jaWF0ZXMgdGhlIGNhcGFjaXR5IHByb3ZpZGVyIGJlZm9yZSBpdCdzIGRlbGV0ZWQuXG4gICAgICBpZiAodGhpcy5kcmFpbldhaXRlcikge1xuICAgICAgICBzZXJ2aWNlLm5vZGUuYWRkRGVwZW5kZW5jeSh0aGlzLmRyYWluV2FpdGVyKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHNlcnZpY2U7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSByZWdpc3RlclNlcnZpY2VXaXRoQUxCKFxuICAgIHNlcnZpY2VOYW1lOiBzdHJpbmcsXG4gICAgc2VydmljZVByb3BzOiBFY3NTZXJ2aWNlUHJvcHMsXG4gICAgc2VydmljZTogRmFyZ2F0ZVNlcnZpY2UgfCBFYzJTZXJ2aWNlLFxuICAgIHByaW1hcnlDb250YWluZXI6IENvbnRhaW5lckRlZmluaXRpb25cbiAgKTogSUFwcGxpY2F0aW9uVGFyZ2V0R3JvdXAge1xuICAgIGNvbnN0IGNvbnRhaW5lclBvcnQgPSBwcmltYXJ5Q29udGFpbmVyLmNvbnRhaW5lclBvcnQ7XG4gICAgY29uc3QgaGVhbHRoQ2hlY2tQYXRoID0gc2VydmljZVByb3BzLnJvdXRpbmc/LmhlYWx0aENoZWNrUGF0aCB8fCBcIi9cIjtcblxuICAgIC8vIERldGVybWluZSByb3V0aW5nIGNvbmRpdGlvbnNcbiAgICBjb25zdCBzZXJ2aWNlc1dpdGhQb3J0cyA9IHRoaXMucHJvcHMuc2VydmljZXMuZmlsdGVyKChzKSA9PlxuICAgICAgcy5jb250YWluZXJzLnNvbWUoKGMpID0+IGMucG9ydCAhPT0gdW5kZWZpbmVkKVxuICAgICk7XG4gICAgY29uc3QgaXNTaW5nbGVTZXJ2aWNlID0gc2VydmljZXNXaXRoUG9ydHMubGVuZ3RoID09PSAxO1xuXG4gICAgY29uc3QgaGVhbHRoQ2hlY2tDb25maWcgPSB0aGlzLmlzRWMyKClcbiAgICAgID8ge1xuICAgICAgICAgIGludGVydmFsOiBEdXJhdGlvbi5zZWNvbmRzKDMwKSxcbiAgICAgICAgICBoZWFsdGh5VGhyZXNob2xkQ291bnQ6IDMsXG4gICAgICAgICAgdW5oZWFsdGh5VGhyZXNob2xkQ291bnQ6IDMsXG4gICAgICAgICAgcGF0aDogaGVhbHRoQ2hlY2tQYXRoLFxuICAgICAgICAgIHBvcnQ6IFwidHJhZmZpYy1wb3J0XCIgYXMgY29uc3QsXG4gICAgICAgICAgdGltZW91dDogRHVyYXRpb24uc2Vjb25kcygxNSlcbiAgICAgICAgfVxuICAgICAgOiB7XG4gICAgICAgICAgaW50ZXJ2YWw6IER1cmF0aW9uLnNlY29uZHMoMTIwKSxcbiAgICAgICAgICBwYXRoOiBoZWFsdGhDaGVja1BhdGgsXG4gICAgICAgICAgcG9ydDogYCR7Y29udGFpbmVyUG9ydH1gLFxuICAgICAgICAgIHRpbWVvdXQ6IER1cmF0aW9uLnNlY29uZHMoMTApXG4gICAgICAgIH07XG5cbiAgICBpZiAoaXNTaW5nbGVTZXJ2aWNlKSB7XG4gICAgICAvLyBTaW5nbGUgc2VydmljZSAtIGNyZWF0ZSB0YXJnZXQgZ3JvdXAgd2l0aCBzZXJ2aWNlIGFzIGRlZmF1bHQgdGFyZ2V0XG4gICAgICByZXR1cm4gdGhpcy5sb2FkQmFsYW5jZXJMaXN0ZW5lciEuYWRkVGFyZ2V0cyhcbiAgICAgICAgYCR7c2VydmljZU5hbWV9VGFyZ2V0R3JvdXBgLFxuICAgICAgICB7XG4gICAgICAgICAgdGFyZ2V0czogW1xuICAgICAgICAgICAgc2VydmljZS5sb2FkQmFsYW5jZXJUYXJnZXQoe1xuICAgICAgICAgICAgICBjb250YWluZXJOYW1lOiBwcmltYXJ5Q29udGFpbmVyLmNvbnRhaW5lck5hbWUsXG4gICAgICAgICAgICAgIGNvbnRhaW5lclBvcnRcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgXSxcbiAgICAgICAgICBwb3J0OiBjb250YWluZXJQb3J0LFxuICAgICAgICAgIHByb3RvY29sOiBBcHBsaWNhdGlvblByb3RvY29sLkhUVFAsXG4gICAgICAgICAgaGVhbHRoQ2hlY2s6IGhlYWx0aENoZWNrQ29uZmlnXG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIE11bHRpLXNlcnZpY2UgLSBjcmVhdGUgdGFyZ2V0IGdyb3VwIHdpdGggcm91dGluZyBydWxlc1xuICAgICAgY29uc3QgcHJpb3JpdHkgPSBzZXJ2aWNlUHJvcHMucm91dGluZz8ucHJpb3JpdHkgfHwgdGhpcy5uZXh0UHJpb3JpdHkrKztcblxuICAgICAgY29uc3QgdGFyZ2V0R3JvdXAgPSB0aGlzLmxvYWRCYWxhbmNlckxpc3RlbmVyIS5hZGRUYXJnZXRzKFxuICAgICAgICBgJHtzZXJ2aWNlTmFtZX1UYXJnZXRzYCxcbiAgICAgICAge1xuICAgICAgICAgIHRhcmdldHM6IFtcbiAgICAgICAgICAgIHNlcnZpY2UubG9hZEJhbGFuY2VyVGFyZ2V0KHtcbiAgICAgICAgICAgICAgY29udGFpbmVyTmFtZTogcHJpbWFyeUNvbnRhaW5lci5jb250YWluZXJOYW1lLFxuICAgICAgICAgICAgICBjb250YWluZXJQb3J0XG4gICAgICAgICAgICB9KVxuICAgICAgICAgIF0sXG4gICAgICAgICAgcG9ydDogY29udGFpbmVyUG9ydCxcbiAgICAgICAgICBwcm90b2NvbDogQXBwbGljYXRpb25Qcm90b2NvbC5IVFRQLFxuICAgICAgICAgIGhlYWx0aENoZWNrOiBoZWFsdGhDaGVja0NvbmZpZyxcbiAgICAgICAgICBjb25kaXRpb25zOiB0aGlzLmJ1aWxkUm91dGluZ0NvbmRpdGlvbnMoc2VydmljZVByb3BzKSxcbiAgICAgICAgICBwcmlvcml0eVxuICAgICAgICB9XG4gICAgICApO1xuXG4gICAgICByZXR1cm4gdGFyZ2V0R3JvdXA7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBidWlsZFJvdXRpbmdDb25kaXRpb25zKFxuICAgIHNlcnZpY2VQcm9wczogRWNzU2VydmljZVByb3BzXG4gICk6IExpc3RlbmVyQ29uZGl0aW9uW10ge1xuICAgIGNvbnN0IGNvbmRpdGlvbnM6IExpc3RlbmVyQ29uZGl0aW9uW10gPSBbXTtcblxuICAgIGlmIChzZXJ2aWNlUHJvcHMucm91dGluZz8ucGF0aCkge1xuICAgICAgY29uZGl0aW9ucy5wdXNoKFxuICAgICAgICBMaXN0ZW5lckNvbmRpdGlvbi5wYXRoUGF0dGVybnMoW3NlcnZpY2VQcm9wcy5yb3V0aW5nLnBhdGhdKVxuICAgICAgKTtcbiAgICB9XG4gICAgaWYgKHNlcnZpY2VQcm9wcy5yb3V0aW5nPy5ob3N0KSB7XG4gICAgICBjb25kaXRpb25zLnB1c2goXG4gICAgICAgIExpc3RlbmVyQ29uZGl0aW9uLmhvc3RIZWFkZXJzKFtzZXJ2aWNlUHJvcHMucm91dGluZy5ob3N0XSlcbiAgICAgICk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGNvbmRpdGlvbnM7XG4gIH1cblxuICBwcml2YXRlIGFkZFNlcnZpY2VTY2FsaW5nKFxuICAgIHNlcnZpY2VOYW1lOiBzdHJpbmcsXG4gICAgc2VydmljZVByb3BzOiBFY3NTZXJ2aWNlUHJvcHMsXG4gICAgc2VydmljZTogRmFyZ2F0ZVNlcnZpY2UgfCBFYzJTZXJ2aWNlXG4gICk6IFRhcmdldFRyYWNraW5nU2NhbGluZ1BvbGljeSB7XG4gICAgY29uc3Qgc2NhbGFibGVUYXJnZXQgPSBuZXcgU2NhbGFibGVUYXJnZXQoXG4gICAgICB0aGlzLFxuICAgICAgYCR7c2VydmljZU5hbWV9U2NhbGFibGVUYXJnZXRgLFxuICAgICAge1xuICAgICAgICBzZXJ2aWNlTmFtZXNwYWNlOiBTZXJ2aWNlTmFtZXNwYWNlLkVDUyxcbiAgICAgICAgcmVzb3VyY2VJZDogYHNlcnZpY2UvJHt0aGlzLmNsdXN0ZXIuY2x1c3Rlck5hbWV9LyR7c2VydmljZS5zZXJ2aWNlTmFtZX1gLFxuICAgICAgICBzY2FsYWJsZURpbWVuc2lvbjogXCJlY3M6c2VydmljZTpEZXNpcmVkQ291bnRcIixcbiAgICAgICAgbWluQ2FwYWNpdHk6IHNlcnZpY2VQcm9wcy5taW5DYXBhY2l0eSA/PyAyLFxuICAgICAgICBtYXhDYXBhY2l0eTogc2VydmljZVByb3BzLm1heENhcGFjaXR5ID8/IDEwXG4gICAgICB9XG4gICAgKTtcblxuICAgIHJldHVybiBuZXcgVGFyZ2V0VHJhY2tpbmdTY2FsaW5nUG9saWN5KFxuICAgICAgdGhpcyxcbiAgICAgIGAke3NlcnZpY2VOYW1lfVNjYWxpbmdQb2xpY3lgLFxuICAgICAge1xuICAgICAgICBzY2FsaW5nVGFyZ2V0OiBzY2FsYWJsZVRhcmdldCxcbiAgICAgICAgcHJlZGVmaW5lZE1ldHJpYzpcbiAgICAgICAgICBzZXJ2aWNlUHJvcHMuc2NhbGluZ1R5cGUgPT09IFNjYWxpbmdUeXBlLk1FTU9SWVxuICAgICAgICAgICAgPyBQcmVkZWZpbmVkTWV0cmljLkVDU19TRVJWSUNFX0FWRVJBR0VfTUVNT1JZX1VUSUxJWkFUSU9OXG4gICAgICAgICAgICA6IFByZWRlZmluZWRNZXRyaWMuRUNTX1NFUlZJQ0VfQVZFUkFHRV9DUFVfVVRJTElaQVRJT04sXG4gICAgICAgIHRhcmdldFZhbHVlOiA1MCxcbiAgICAgICAgc2NhbGVJbkNvb2xkb3duOiBEdXJhdGlvbi5zZWNvbmRzKDYwKSxcbiAgICAgICAgc2NhbGVPdXRDb29sZG93bjogRHVyYXRpb24uc2Vjb25kcyg2MClcbiAgICAgIH1cbiAgICApO1xuICB9XG5cbiAgcHJpdmF0ZSBpc0VjMigpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5jYXBhY2l0eVByb3ZpZGVyID09PSBcIkVDMlwiO1xuICB9XG5cbiAgcHJpdmF0ZSBpc0ZhcmdhdGUoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIChcbiAgICAgIHRoaXMuY2FwYWNpdHlQcm92aWRlciA9PT0gXCJGQVJHQVRFXCIgfHxcbiAgICAgIHRoaXMuY2FwYWNpdHlQcm92aWRlciA9PT0gXCJGQVJHQVRFX1NQT1RcIlxuICAgICk7XG4gIH1cblxuICBhZGRDbHVzdGVyKHByb3BzOiBFY3NDbHVzdGVyUHJvcHMpIHtcbiAgICB0aGlzLmNsdXN0ZXIgPSBuZXcgQ2RrQ2x1c3Rlcih0aGlzLCBgJHtwcm9wcy5jbHVzdGVyTmFtZX1gLCB7XG4gICAgICB2cGM6IHByb3BzLnZwYyxcbiAgICAgIGNsdXN0ZXJOYW1lOiBwcm9wcy5jbHVzdGVyTmFtZSxcbiAgICAgIGNvbnRhaW5lckluc2lnaHRzVjI6IENvbnRhaW5lckluc2lnaHRzLkVOQUJMRUQsXG4gICAgICBlbmFibGVGYXJnYXRlQ2FwYWNpdHlQcm92aWRlcnM6IHRoaXMuaXNGYXJnYXRlKClcbiAgICB9KTtcblxuICAgIC8vIEZvciBGYXJnYXRlIGNsdXN0ZXJzLCBmaW5kIHRoZSBpbnRlcm5hbCBDZm5DbHVzdGVyQ2FwYWNpdHlQcm92aWRlckFzc29jaWF0aW9uc1xuICAgIC8vIHRoYXQgQ0RLIGNyZWF0ZXMgd2hlbiBlbmFibGVGYXJnYXRlQ2FwYWNpdHlQcm92aWRlcnMgaXMgdHJ1ZS5cbiAgICAvLyBXZSBuZWVkIHRoaXMgcmVmZXJlbmNlIHRvIGVzdGFibGlzaCBwcm9wZXIgZGVsZXRpb24gZGVwZW5kZW5jaWVzLlxuICAgIGlmICh0aGlzLmlzRmFyZ2F0ZSgpKSB7XG4gICAgICAvLyBDREsgY3JlYXRlcyB0aGlzIGFzIGEgY2hpbGQgb2YgdGhlIGNsdXN0ZXIgd2l0aCBhIHNwZWNpZmljIG5hbWluZyBwYXR0ZXJuXG4gICAgICBjb25zdCBjaGlsZHJlbiA9IHRoaXMuY2x1c3Rlci5ub2RlLmNoaWxkcmVuO1xuICAgICAgZm9yIChjb25zdCBjaGlsZCBvZiBjaGlsZHJlbikge1xuICAgICAgICBpZiAoY2hpbGQgaW5zdGFuY2VvZiBDZm5DbHVzdGVyQ2FwYWNpdHlQcm92aWRlckFzc29jaWF0aW9ucykge1xuICAgICAgICAgIHRoaXMuZmFyZ2F0ZUNhcGFjaXR5UHJvdmlkZXJBc3NvY2lhdGlvbnMgPSBjaGlsZDtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIG5ldyBDZm5PdXRwdXQodGhpcywgYCR7cHJvcHMuY2x1c3Rlck5hbWV9RGVwbG95YWJsZUNsdXN0ZXJgLCB7XG4gICAgICBrZXk6IGAke3Byb3BzLmNsdXN0ZXJOYW1lfURlcGxveWFibGVDbHVzdGVyYCxcbiAgICAgIGV4cG9ydE5hbWU6IGAke3Byb3BzLmNsdXN0ZXJOYW1lfURlcGxveWFibGVDbHVzdGVyYCxcbiAgICAgIHZhbHVlOiB0aGlzLmNsdXN0ZXIuY2x1c3RlckFyblxuICAgIH0pO1xuXG4gICAgbmV3IENmbk91dHB1dCh0aGlzLCBgJHtwcm9wcy5jbHVzdGVyTmFtZX1DbHVzdGVyQXJuYCwge1xuICAgICAga2V5OiBcIkNsdXN0ZXJBcm5cIixcbiAgICAgIGV4cG9ydE5hbWU6IGAke3Byb3BzLmNsdXN0ZXJOYW1lfUNsdXN0ZXJBcm5gLFxuICAgICAgdmFsdWU6IHRoaXMuY2x1c3Rlci5jbHVzdGVyQXJuLFxuICAgICAgZGVzY3JpcHRpb246IGBFQ1MgQ2x1c3RlciBBUk4gZm9yICR7cHJvcHMuY2x1c3Rlck5hbWV9YFxuICAgIH0pO1xuICB9XG5cbiAgYWRkQXV0b1NjYWxpbmdHcm91cChwcm9wczogRWNzQ2x1c3RlclByb3BzKSB7XG4gICAgY29uc3QgZWMyQ29uZmlnID0gcHJvcHMuZWMyQ29uZmlnIHx8IHt9O1xuICAgIGNvbnN0IGluc3RhbmNlVHlwZSA9IGVjMkNvbmZpZy5pbnN0YW5jZVR5cGUgfHwgXCJ0My5taWNyb1wiO1xuICAgIGNvbnN0IGFtaUhhcmR3YXJlVHlwZSA9XG4gICAgICBlYzJDb25maWcuYW1pSGFyZHdhcmVUeXBlID09PSBcIlNUQU5EQVJEXCJcbiAgICAgICAgPyBBbWlIYXJkd2FyZVR5cGUuU1RBTkRBUkRcbiAgICAgICAgOiBBbWlIYXJkd2FyZVR5cGUuQVJNO1xuICAgIGNvbnN0IG1pbkNhcGFjaXR5ID0gZWMyQ29uZmlnLm1pbkNhcGFjaXR5ID8/IDI7XG4gICAgY29uc3QgbWF4Q2FwYWNpdHkgPSBlYzJDb25maWcubWF4Q2FwYWNpdHkgPz8gMztcblxuICAgIHRoaXMuYXNnU2VjdXJpdHlHcm91cCA9IG5ldyBTZWN1cml0eUdyb3VwKHRoaXMsIGBBc2dTZWN1cml0eUdyb3VwYCwge1xuICAgICAgdnBjOiB0aGlzLmNsdXN0ZXIudnBjLFxuICAgICAgZGVzY3JpcHRpb246IGBTZWN1cml0eSBncm91cCBmb3IgdGhlICR7cHJvcHMuY2x1c3Rlck5hbWV9IGF1dG8gc2NhbGluZyBncm91cGBcbiAgICB9KTtcblxuICAgIC8vIE9wZW4gY29udGFpbmVyIHBvcnRzIGZvciBkaXJlY3QgRUMyIGFjY2Vzc1xuICAgIGlmICh0aGlzLmRpcmVjdEFjY2Vzc0VuYWJsZWQpIHtcbiAgICAgIGZvciAoY29uc3Qgc2VydmljZSBvZiBwcm9wcy5zZXJ2aWNlcykge1xuICAgICAgICBmb3IgKGNvbnN0IGNvbnRhaW5lciBvZiBzZXJ2aWNlLmNvbnRhaW5lcnMpIHtcbiAgICAgICAgICBpZiAoY29udGFpbmVyLnBvcnQpIHtcbiAgICAgICAgICAgIHRoaXMuYXNnU2VjdXJpdHlHcm91cC5hZGRJbmdyZXNzUnVsZShcbiAgICAgICAgICAgICAgUGVlci5hbnlJcHY0KCksXG4gICAgICAgICAgICAgIFBvcnQudGNwKGNvbnRhaW5lci5wb3J0KSxcbiAgICAgICAgICAgICAgYERpcmVjdCBhY2Nlc3MgdG8gY29udGFpbmVyIHBvcnQgJHtjb250YWluZXIucG9ydH1gXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHRoaXMuYXV0b1NjYWxpbmdHcm91cCA9IG5ldyBBdXRvU2NhbGluZ0dyb3VwKHRoaXMsIFwiQXV0b1NjYWxpbmdHcm91cFwiLCB7XG4gICAgICBhdXRvU2NhbGluZ0dyb3VwTmFtZTogYCR7cHJvcHMuY2x1c3Rlck5hbWV9QXV0b1NjYWxpbmdHcm91cGAsXG4gICAgICB2cGM6IHRoaXMuY2x1c3Rlci52cGMsXG4gICAgICB2cGNTdWJuZXRzOiB7XG4gICAgICAgIHN1Ym5ldFR5cGU6IFN1Ym5ldFR5cGUuUFVCTElDXG4gICAgICB9LFxuICAgICAgc2VjdXJpdHlHcm91cDogdGhpcy5hc2dTZWN1cml0eUdyb3VwLFxuICAgICAgbWluQ2FwYWNpdHksXG4gICAgICBtYXhDYXBhY2l0eSxcbiAgICAgIGluc3RhbmNlVHlwZTogbmV3IEluc3RhbmNlVHlwZShpbnN0YW5jZVR5cGUpLFxuICAgICAgY2FwYWNpdHlSZWJhbGFuY2U6IHRydWUsXG4gICAgICBpbnN0YW5jZU1vbml0b3Jpbmc6IE1vbml0b3JpbmcuQkFTSUMsXG4gICAgICBtYWNoaW5lSW1hZ2U6IEVjc09wdGltaXplZEltYWdlLmFtYXpvbkxpbnV4MihhbWlIYXJkd2FyZVR5cGUpXG4gICAgfSk7XG5cbiAgICB0aGlzLmFzZ0NhcGFjaXR5UHJvdmlkZXIgPSBuZXcgQXNnQ2FwYWNpdHlQcm92aWRlcihcbiAgICAgIHRoaXMsXG4gICAgICBcIkFzZ0NhcGFjaXR5UHJvdmlkZXJcIixcbiAgICAgIHtcbiAgICAgICAgYXV0b1NjYWxpbmdHcm91cDogdGhpcy5hdXRvU2NhbGluZ0dyb3VwLFxuICAgICAgICBlbmFibGVNYW5hZ2VkRHJhaW5pbmc6IHRydWUsXG4gICAgICAgIGVuYWJsZU1hbmFnZWRUZXJtaW5hdGlvblByb3RlY3Rpb246IGZhbHNlXG4gICAgICB9XG4gICAgKTtcblxuICAgIHRoaXMuY2x1c3Rlci5hZGRBc2dDYXBhY2l0eVByb3ZpZGVyKHRoaXMuYXNnQ2FwYWNpdHlQcm92aWRlcik7XG5cbiAgICAvLyBDcmVhdGUgZHJhaW4gd2FpdGVyIGN1c3RvbSByZXNvdXJjZSB0aGF0IGhhbmRsZXMgY2FwYWNpdHkgcHJvdmlkZXIgY2xlYW51cCBkdXJpbmcgZGVsZXRpb24uXG4gICAgLy8gVGhpcyByZXNvdXJjZSB3YWl0cyBmb3IgRUNTIHNlcnZpY2VzIHRvIGRyYWluLCB0aGVuIGRpc2Fzc29jaWF0ZXMgdGhlIGNhcGFjaXR5IHByb3ZpZGVyXG4gICAgLy8gZnJvbSB0aGUgY2x1c3RlciBiZWZvcmUgQ2xvdWRGb3JtYXRpb24gYXR0ZW1wdHMgdG8gZGVsZXRlIHRoZSBBc2dDYXBhY2l0eVByb3ZpZGVyLlxuICAgIC8vXG4gICAgLy8gRGVwZW5kZW5jeSBjaGFpbiBmb3IgREVMRVRFIG9yZGVyOlxuICAgIC8vICAgU2VydmljZXMgZGVsZXRlZCDihpIgRHJhaW5XYWl0ZXIgcnVucyDihpIgQXNnQ2FwYWNpdHlQcm92aWRlciBkZWxldGVkIOKGkiBDbHVzdGVyIGRlbGV0ZWRcbiAgICAvL1xuICAgIC8vIFRoZSBkcmFpbiB3YWl0ZXIgbXVzdCBkZXBlbmQgb24gQXNnQ2FwYWNpdHlQcm92aWRlciBzbyBpdCBydW5zIEJFRk9SRSB0aGUgcHJvdmlkZXIgaXMgZGVsZXRlZC5cbiAgICAvLyBTZXJ2aWNlcyBtdXN0IGRlcGVuZCBvbiB0aGUgZHJhaW4gd2FpdGVyIHNvIHRoZXkncmUgZGVsZXRlZCBCRUZPUkUgdGhlIGRyYWluIHdhaXRlciBydW5zLlxuICAgIHRoaXMuZHJhaW5XYWl0ZXIgPSBuZXcgQ2FwYWNpdHlQcm92aWRlckRyYWluV2FpdGVyKFxuICAgICAgdGhpcyxcbiAgICAgIFwiQ2FwYWNpdHlQcm92aWRlckRyYWluV2FpdGVyXCIsXG4gICAgICB7XG4gICAgICAgIGNsdXN0ZXJOYW1lOiBwcm9wcy5jbHVzdGVyTmFtZSxcbiAgICAgICAgY2FwYWNpdHlQcm92aWRlck5hbWU6IHRoaXMuYXNnQ2FwYWNpdHlQcm92aWRlci5jYXBhY2l0eVByb3ZpZGVyTmFtZVxuICAgICAgfVxuICAgICk7XG5cbiAgICAvLyBEcmFpbldhaXRlciBkZXBlbmRzIG9uIEFzZ0NhcGFjaXR5UHJvdmlkZXI6XG4gICAgLy8gLSBDUkVBVEU6IEFzZ0NhcGFjaXR5UHJvdmlkZXIgY3JlYXRlZCBmaXJzdCwgdGhlbiBEcmFpbldhaXRlclxuICAgIC8vIC0gREVMRVRFOiBEcmFpbldhaXRlciBkZWxldGVkIGZpcnN0IChydW5zIExhbWJkYSksIHRoZW4gQXNnQ2FwYWNpdHlQcm92aWRlclxuICAgIHRoaXMuZHJhaW5XYWl0ZXIubm9kZS5hZGREZXBlbmRlbmN5KHRoaXMuYXNnQ2FwYWNpdHlQcm92aWRlcik7XG4gIH1cblxuICBhZGRMb2FkQmFsYW5jZXIocHJvcHM6IEVjc0NsdXN0ZXJQcm9wcykge1xuICAgIGNvbnN0IGRlZmF1bHRMb2FkQmFsYW5jZXJOYW1lID0gYCR7cHJvcHMuY2x1c3Rlck5hbWV9TG9hZEJhbGFuY2VyYDtcbiAgICBjb25zdCBzdXBwb3J0ZWROYW1lTGVuZ3RoID0gMzI7XG5cbiAgICBsZXQgdHJ1bmNhdGVkTG9hZEJhbGFuY2VyTmFtZSA9XG4gICAgICBkZWZhdWx0TG9hZEJhbGFuY2VyTmFtZS5sZW5ndGggPiBzdXBwb3J0ZWROYW1lTGVuZ3RoXG4gICAgICAgID8gZGVmYXVsdExvYWRCYWxhbmNlck5hbWUuc3Vic3RyaW5nKDAsIHN1cHBvcnRlZE5hbWVMZW5ndGgpXG4gICAgICAgIDogZGVmYXVsdExvYWRCYWxhbmNlck5hbWU7XG5cbiAgICB0cnVuY2F0ZWRMb2FkQmFsYW5jZXJOYW1lID0gdHJ1bmNhdGVkTG9hZEJhbGFuY2VyTmFtZS5yZXBsYWNlKC8tKyQvLCBcIlwiKTtcblxuICAgIGNvbnN0IGlzSW50ZXJuYWwgPSBwcm9wcy5jbHVzdGVyPy5sb2FkQmFsYW5jZXIgPT09IFwiaW50ZXJuYWxcIjtcblxuICAgIGlmICh0aGlzLmlzRWMyKCkpIHtcbiAgICAgIHRoaXMubG9hZEJhbGFuY2VyU2VjdXJpdHlHcm91cCA9IG5ldyBTZWN1cml0eUdyb3VwKFxuICAgICAgICB0aGlzLFxuICAgICAgICBgTG9hZEJhbGFuY2VyU2VjdXJpdHlHcm91cGAsXG4gICAgICAgIHtcbiAgICAgICAgICB2cGM6IHRoaXMuY2x1c3Rlci52cGMsXG4gICAgICAgICAgZGVzY3JpcHRpb246IGBTZWN1cml0eSBncm91cCBmb3IgdGhlICR7cHJvcHMuY2x1c3Rlck5hbWV9IGxvYWQgYmFsYW5jZXJgXG4gICAgICAgIH1cbiAgICAgICk7XG5cbiAgICAgIHRoaXMubG9hZEJhbGFuY2VyU2VjdXJpdHlHcm91cC5jb25uZWN0aW9ucy5hbGxvd1RvKFxuICAgICAgICB0aGlzLmFzZ1NlY3VyaXR5R3JvdXAhLFxuICAgICAgICBQb3J0LmFsbFRjcCgpXG4gICAgICApO1xuXG4gICAgICB0aGlzLmxvYWRCYWxhbmNlciA9IG5ldyBBcHBsaWNhdGlvbkxvYWRCYWxhbmNlcihcbiAgICAgICAgdGhpcyxcbiAgICAgICAgYCR7cHJvcHMuY2x1c3Rlck5hbWV9TG9hZEJhbGFuY2VyYCxcbiAgICAgICAge1xuICAgICAgICAgIHZwYzogdGhpcy5jbHVzdGVyLnZwYyxcbiAgICAgICAgICBpbnRlcm5ldEZhY2luZzogIWlzSW50ZXJuYWwsXG4gICAgICAgICAgc2VjdXJpdHlHcm91cDogdGhpcy5sb2FkQmFsYW5jZXJTZWN1cml0eUdyb3VwLFxuICAgICAgICAgIGxvYWRCYWxhbmNlck5hbWU6IHRydW5jYXRlZExvYWRCYWxhbmNlck5hbWUsXG4gICAgICAgICAgdnBjU3VibmV0czoge1xuICAgICAgICAgICAgc3VibmV0VHlwZTogaXNJbnRlcm5hbFxuICAgICAgICAgICAgICA/IFN1Ym5ldFR5cGUuUFJJVkFURV9XSVRIX0VHUkVTU1xuICAgICAgICAgICAgICA6IFN1Ym5ldFR5cGUuUFVCTElDXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICApO1xuXG4gICAgICB0aGlzLmFzZ1NlY3VyaXR5R3JvdXAhLmNvbm5lY3Rpb25zLmFsbG93RnJvbShcbiAgICAgICAgdGhpcy5sb2FkQmFsYW5jZXJTZWN1cml0eUdyb3VwLFxuICAgICAgICBQb3J0LnRjcFJhbmdlKDQ5MTUyLCA2NTUzNSlcbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMubG9hZEJhbGFuY2VyID0gbmV3IEFwcGxpY2F0aW9uTG9hZEJhbGFuY2VyKFxuICAgICAgICB0aGlzLFxuICAgICAgICBgJHtwcm9wcy5jbHVzdGVyTmFtZX1Mb2FkQmFsYW5jZXJgLFxuICAgICAgICB7XG4gICAgICAgICAgdnBjOiB0aGlzLmNsdXN0ZXIudnBjLFxuICAgICAgICAgIGludGVybmV0RmFjaW5nOiAhaXNJbnRlcm5hbCxcbiAgICAgICAgICBsb2FkQmFsYW5jZXJOYW1lOiB0cnVuY2F0ZWRMb2FkQmFsYW5jZXJOYW1lLFxuICAgICAgICAgIHZwY1N1Ym5ldHM6IHtcbiAgICAgICAgICAgIHN1Ym5ldFR5cGU6IGlzSW50ZXJuYWxcbiAgICAgICAgICAgICAgPyBTdWJuZXRUeXBlLlBSSVZBVEVfV0lUSF9FR1JFU1NcbiAgICAgICAgICAgICAgOiBTdWJuZXRUeXBlLlBVQkxJQ1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBuZXcgQ2ZuT3V0cHV0KHRoaXMsIGAke3Byb3BzLmNsdXN0ZXJOYW1lfUxvYWRCYWxhbmNlckRuc05hbWVgLCB7XG4gICAgICBrZXk6IGAke3Byb3BzLmNsdXN0ZXJOYW1lfUxvYWRCYWxhbmNlckRuc05hbWVgLFxuICAgICAgZXhwb3J0TmFtZTogYCR7cHJvcHMuY2x1c3Rlck5hbWV9TG9hZEJhbGFuY2VyRG5zTmFtZWAsXG4gICAgICB2YWx1ZTogdGhpcy5sb2FkQmFsYW5jZXIubG9hZEJhbGFuY2VyRG5zTmFtZVxuICAgIH0pO1xuXG4gICAgbmV3IENmbk91dHB1dCh0aGlzLCBgJHtwcm9wcy5jbHVzdGVyTmFtZX1Mb2FkQmFsYW5jZXJVcmxgLCB7XG4gICAgICBrZXk6IFwiTG9hZEJhbGFuY2VyVXJsXCIsXG4gICAgICBleHBvcnROYW1lOiBgJHtwcm9wcy5jbHVzdGVyTmFtZX1Mb2FkQmFsYW5jZXJVcmxgLFxuICAgICAgdmFsdWU6IGBodHRwOi8vJHt0aGlzLmxvYWRCYWxhbmNlci5sb2FkQmFsYW5jZXJEbnNOYW1lfWAsXG4gICAgICBkZXNjcmlwdGlvbjogYExvYWQgQmFsYW5jZXIgVVJMIGZvciAke3Byb3BzLmNsdXN0ZXJOYW1lfWBcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgYWRkRGlyZWN0QWNjZXNzT3V0cHV0cyhwcm9wczogRWNzQ2x1c3RlclByb3BzKSB7XG4gICAgaWYgKCF0aGlzLmRpcmVjdEFjY2Vzc0VuYWJsZWQgfHwgIXRoaXMuYXV0b1NjYWxpbmdHcm91cCkgcmV0dXJuO1xuXG4gICAgLy8gR2V0IHRoZSBmaXJzdCBjb250YWluZXIgcG9ydCAoZm9yIHVzZXIgaW5zdHJ1Y3Rpb25zKVxuICAgIGNvbnN0IGNvbnRhaW5lclBvcnQgPVxuICAgICAgcHJvcHMuc2VydmljZXMuZmxhdE1hcCgocykgPT4gcy5jb250YWluZXJzKS5maW5kKChjKSA9PiBjLnBvcnQpPy5wb3J0IHx8XG4gICAgICAzMDAwO1xuXG4gICAgbmV3IENmbk91dHB1dCh0aGlzLCBgJHtwcm9wcy5jbHVzdGVyTmFtZX1BdXRvU2NhbGluZ0dyb3VwTmFtZWAsIHtcbiAgICAgIGtleTogXCJBdXRvU2NhbGluZ0dyb3VwTmFtZVwiLFxuICAgICAgZXhwb3J0TmFtZTogYCR7cHJvcHMuY2x1c3Rlck5hbWV9QXV0b1NjYWxpbmdHcm91cE5hbWVgLFxuICAgICAgdmFsdWU6IHRoaXMuYXV0b1NjYWxpbmdHcm91cC5hdXRvU2NhbGluZ0dyb3VwTmFtZSxcbiAgICAgIGRlc2NyaXB0aW9uOiBgUnVuOiBhd3MgYXV0b3NjYWxpbmcgZGVzY3JpYmUtYXV0by1zY2FsaW5nLWdyb3VwcyAtLWF1dG8tc2NhbGluZy1ncm91cC1uYW1lcyA8bmFtZT4gdG8gZmluZCBpbnN0YW5jZSBJUGBcbiAgICB9KTtcblxuICAgIG5ldyBDZm5PdXRwdXQodGhpcywgYCR7cHJvcHMuY2x1c3Rlck5hbWV9RGlyZWN0QWNjZXNzUG9ydGAsIHtcbiAgICAgIGtleTogXCJEaXJlY3RBY2Nlc3NQb3J0XCIsXG4gICAgICBleHBvcnROYW1lOiBgJHtwcm9wcy5jbHVzdGVyTmFtZX1EaXJlY3RBY2Nlc3NQb3J0YCxcbiAgICAgIHZhbHVlOiBTdHJpbmcoY29udGFpbmVyUG9ydCksXG4gICAgICBkZXNjcmlwdGlvbjogYEFjY2VzcyB5b3VyIGFwcCBhdCBodHRwOi8vPEVDMi1QVUJMSUMtSVA+OiR7Y29udGFpbmVyUG9ydH1gXG4gICAgfSk7XG4gIH1cblxuICBhZGRMb2FkQmFsYW5jZXJMaXN0ZW5lcihwcm9wczogRWNzQ2x1c3RlclByb3BzKSB7XG4gICAgaWYgKCF0aGlzLmxvYWRCYWxhbmNlcikgcmV0dXJuO1xuXG4gICAgLy8gRGV0ZXJtaW5lIHBvcnQgYmFzZWQgb24gd2hldGhlciBIVFRQUyBpcyBjb25maWd1cmVkIChkb21haW4gKyBjZXJ0KVxuICAgIGNvbnN0IHBvcnQgPSB0aGlzLmNlcnRpZmljYXRlID8gNDQzIDogODA7XG5cbiAgICAvLyBEZWZhdWx0IGFjdGlvbiBmb3IgcmVxdWVzdHMgdGhhdCBkb24ndCBtYXRjaCBhbnkgcm91dGluZyBydWxlXG4gICAgLy8gUmV0dXJucyA0MDQgZm9yIG11bHRpLXNlcnZpY2UgY2x1c3RlcnMgd2l0aCByb3V0aW5nIHJ1bGVzXG4gICAgY29uc3QgZGVmYXVsdEFjdGlvbiA9IExpc3RlbmVyQWN0aW9uLmZpeGVkUmVzcG9uc2UoNDA0LCB7XG4gICAgICBjb250ZW50VHlwZTogXCJ0ZXh0L3BsYWluXCIsXG4gICAgICBtZXNzYWdlQm9keTogXCJOb3QgRm91bmRcIlxuICAgIH0pO1xuXG4gICAgaWYgKHRoaXMuY2VydGlmaWNhdGUpIHtcbiAgICAgIHRoaXMubG9hZEJhbGFuY2VyTGlzdGVuZXIgPSB0aGlzLmxvYWRCYWxhbmNlci5hZGRMaXN0ZW5lcihcbiAgICAgICAgYCR7cHJvcHMuY2x1c3Rlck5hbWV9TGlzdGVuZXJgLFxuICAgICAgICB7XG4gICAgICAgICAgcG9ydCxcbiAgICAgICAgICBjZXJ0aWZpY2F0ZXM6IFt0aGlzLmNlcnRpZmljYXRlXSxcbiAgICAgICAgICBkZWZhdWx0QWN0aW9uXG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMubG9hZEJhbGFuY2VyTGlzdGVuZXIgPSB0aGlzLmxvYWRCYWxhbmNlci5hZGRMaXN0ZW5lcihcbiAgICAgICAgYCR7cHJvcHMuY2x1c3Rlck5hbWV9TGlzdGVuZXJgLFxuICAgICAgICB7XG4gICAgICAgICAgcG9ydCxcbiAgICAgICAgICBkZWZhdWx0QWN0aW9uXG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgYWRkSG9zdGVkWm9uZShwcm9wczogRWNzQ2x1c3RlclByb3BzKSB7XG4gICAgLy8gU3VwcG9ydCBib3RoIG5ldyBjbHVzdGVyLmRvbWFpbiBhbmQgYWR2YW5jZWQgY2x1c3Rlci5kb21haW5Db25maWdcbiAgICBjb25zdCBkb21haW5Db25maWcgPSBwcm9wcy5jbHVzdGVyPy5kb21haW5Db25maWc7XG4gICAgY29uc3Qgc2ltcGxlRG9tYWluID0gcHJvcHMuY2x1c3Rlcj8uZG9tYWluO1xuXG4gICAgaWYgKCFkb21haW5Db25maWcgJiYgIXNpbXBsZURvbWFpbikgcmV0dXJuO1xuXG4gICAgY29uc3QgZG9tYWluTmFtZSA9IGRvbWFpbkNvbmZpZz8uZG9tYWluTmFtZSB8fCBzaW1wbGVEb21haW4hO1xuXG4gICAgaWYgKCFkb21haW5Db25maWc/Lmhvc3RlZFpvbmUpIHtcbiAgICAgIGNvbnN0IGhvc3RlZFpvbmUgPSBuZXcgRmphbGxIb3N0ZWRab25lKFxuICAgICAgICB0aGlzLFxuICAgICAgICBgJHtwcm9wcy5jbHVzdGVyTmFtZX1Ib3N0ZWRab25lYCxcbiAgICAgICAge1xuICAgICAgICAgIHpvbmVOYW1lOiBkb21haW5OYW1lXG4gICAgICAgIH1cbiAgICAgICk7XG5cbiAgICAgIHRoaXMuaG9zdGVkWm9uZSA9IGhvc3RlZFpvbmUuZ2V0SW50ZXJuYWxIb3N0ZWRab25lKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuaG9zdGVkWm9uZSA9IGRvbWFpbkNvbmZpZy5ob3N0ZWRab25lLmdldEludGVybmFsSG9zdGVkWm9uZSgpO1xuICAgIH1cblxuICAgIGlmICghZG9tYWluQ29uZmlnPy5jZXJ0aWZpY2F0ZSkge1xuICAgICAgdGhpcy5jZXJ0aWZpY2F0ZSA9IG5ldyBDZXJ0aWZpY2F0ZShcbiAgICAgICAgdGhpcyxcbiAgICAgICAgYCR7cHJvcHMuY2x1c3Rlck5hbWV9Q2VydGlmaWNhdGVgLFxuICAgICAgICB7XG4gICAgICAgICAgZG9tYWluTmFtZSxcbiAgICAgICAgICB2YWxpZGF0aW9uOiBDZXJ0aWZpY2F0ZVZhbGlkYXRpb24uZnJvbURucyh0aGlzLmhvc3RlZFpvbmUpXG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gSGFuZGxlIGFkdmFuY2VkIHJvdXRpbmcgcG9saWNpZXMgKGxhdGVuY3ksIHdlaWdodGVkLCBnZW8pXG4gICAgaWYgKGRvbWFpbkNvbmZpZykge1xuICAgICAgY29uc3QgbGF0ZW5jeUNvbmZpZyA9IGRvbWFpbkNvbmZpZyBhcyBMYXRlbmN5RG9tYWluQ29uZmlnO1xuICAgICAgY29uc3Qgd2VpZ2h0ZWRDb25maWcgPSBkb21haW5Db25maWcgYXMgV2VpZ2h0ZWREb21haW5Db25maWc7XG4gICAgICBjb25zdCBnZW9Db25maWcgPSBkb21haW5Db25maWcgYXMgR2VvTG9jYXRpb25Eb21haW5Db25maWc7XG5cbiAgICAgIGNvbnN0IGhhc1JvdXRpbmdQb2xpY3k6IGJvb2xlYW4gPVxuICAgICAgICAhIWxhdGVuY3lDb25maWc/LnJlZ2lvbiB8fFxuICAgICAgICB3ZWlnaHRlZENvbmZpZz8ud2VpZ2h0ICE9PSB1bmRlZmluZWQgfHxcbiAgICAgICAgISFnZW9Db25maWc/Lmdlb0xvY2F0aW9uO1xuXG4gICAgICBsZXQgc2V0SWRlbnRpZmllciA9IGRvbWFpbkNvbmZpZy5zZXRJZGVudGlmaWVyO1xuICAgICAgaWYgKGhhc1JvdXRpbmdQb2xpY3kgJiYgIXNldElkZW50aWZpZXIpIHtcbiAgICAgICAgaWYgKGxhdGVuY3lDb25maWc/LnJlZ2lvbikge1xuICAgICAgICAgIHNldElkZW50aWZpZXIgPSBgJHtwcm9wcy5jbHVzdGVyTmFtZX0ke2xhdGVuY3lDb25maWcucmVnaW9ufWA7XG4gICAgICAgIH0gZWxzZSBpZiAod2VpZ2h0ZWRDb25maWc/LndlaWdodCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgc2V0SWRlbnRpZmllciA9IGAke3Byb3BzLmNsdXN0ZXJOYW1lfVdlaWdodCR7d2VpZ2h0ZWRDb25maWcud2VpZ2h0fWA7XG4gICAgICAgIH0gZWxzZSBpZiAoZ2VvQ29uZmlnPy5nZW9Mb2NhdGlvbikge1xuICAgICAgICAgIHNldElkZW50aWZpZXIgPSBgJHtwcm9wcy5jbHVzdGVyTmFtZX1HZW9gO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLmxvYWRCYWxhbmNlcikge1xuICAgICAgICB0aGlzLmFSZWNvcmQgPSBuZXcgQVJlY29yZCh0aGlzLCBgJHtwcm9wcy5jbHVzdGVyTmFtZX1BUmVjb3JkYCwge1xuICAgICAgICAgIHJlY29yZE5hbWU6IGRvbWFpbk5hbWUsXG4gICAgICAgICAgem9uZTogdGhpcy5ob3N0ZWRab25lLFxuICAgICAgICAgIHRhcmdldDogUmVjb3JkVGFyZ2V0LmZyb21BbGlhcyhcbiAgICAgICAgICAgIG5ldyBMb2FkQmFsYW5jZXJUYXJnZXQodGhpcy5sb2FkQmFsYW5jZXIsIHtcbiAgICAgICAgICAgICAgZXZhbHVhdGVUYXJnZXRIZWFsdGg6IGhhc1JvdXRpbmdQb2xpY3lcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgKSxcbiAgICAgICAgICByZWdpb246IGxhdGVuY3lDb25maWc/LnJlZ2lvbixcbiAgICAgICAgICB3ZWlnaHQ6IHdlaWdodGVkQ29uZmlnPy53ZWlnaHQsXG4gICAgICAgICAgZ2VvTG9jYXRpb246IGdlb0NvbmZpZz8uZ2VvTG9jYXRpb24sXG4gICAgICAgICAgc2V0SWRlbnRpZmllcjogc2V0SWRlbnRpZmllclxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKHNpbXBsZURvbWFpbiAmJiB0aGlzLmxvYWRCYWxhbmNlcikge1xuICAgICAgLy8gU2ltcGxlIGRvbWFpbiAtIGp1c3QgY3JlYXRlIEEgcmVjb3JkXG4gICAgICB0aGlzLmFSZWNvcmQgPSBuZXcgQVJlY29yZCh0aGlzLCBgJHtwcm9wcy5jbHVzdGVyTmFtZX1BUmVjb3JkYCwge1xuICAgICAgICByZWNvcmROYW1lOiBkb21haW5OYW1lLFxuICAgICAgICB6b25lOiB0aGlzLmhvc3RlZFpvbmUsXG4gICAgICAgIHRhcmdldDogUmVjb3JkVGFyZ2V0LmZyb21BbGlhcyhcbiAgICAgICAgICBuZXcgTG9hZEJhbGFuY2VyVGFyZ2V0KHRoaXMubG9hZEJhbGFuY2VyKVxuICAgICAgICApXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBzdGF0aWMgYnVpbGQoXG4gICAgaWQ6IHN0cmluZyxcbiAgICBwcm9wczogRWNzQ2x1c3RlclByb3BzXG4gICk6IChzYjogU3RhY2tCdWlsZGVyKSA9PiBDb25zdHJ1Y3Qge1xuICAgIHJldHVybiAoc2I6IFN0YWNrQnVpbGRlcikgPT4ge1xuICAgICAgY29uc3QgbmV3UHJvcHM6IEVjc0NsdXN0ZXJQcm9wcyA9IHtcbiAgICAgICAgLi4ucHJvcHMsXG4gICAgICAgIC4uLntcbiAgICAgICAgICB2cGM6IChzYi5nZXROZXR3b3JrKCkgYXMgSVZwYykgfHwgcHJvcHMudnBjXG4gICAgICAgIH1cbiAgICAgIH07XG4gICAgICByZXR1cm4gbmV3IHRoaXMoc2IuZ2V0U3RhY2soKSwgaWQsIG5ld1Byb3BzKTtcbiAgICB9O1xuICB9XG59XG4iXX0=