@fjall/components-infrastructure 0.77.4 → 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.
- package/dist/lib/app.d.ts +8 -5
- package/dist/lib/app.js +19 -7
- package/dist/lib/patterns/aws/buildkite.js +4 -7
- package/dist/lib/patterns/aws/compute.d.ts +479 -48
- package/dist/lib/patterns/aws/compute.js +307 -94
- package/dist/lib/patterns/aws/database.d.ts +1 -0
- package/dist/lib/patterns/aws/database.js +4 -1
- package/dist/lib/patterns/aws/hostedZone.js +4 -7
- package/dist/lib/patterns/aws/loadBalancer.d.ts +163 -0
- package/dist/lib/patterns/aws/loadBalancer.js +278 -0
- package/dist/lib/patterns/aws/network.d.ts +1 -0
- package/dist/lib/patterns/aws/network.js +2 -1
- package/dist/lib/resources/aws/compute/capacityProviderDrainWaiter.d.ts +20 -0
- package/dist/lib/resources/aws/compute/capacityProviderDrainWaiter.js +180 -0
- package/dist/lib/resources/aws/compute/ecs.d.ts +294 -57
- package/dist/lib/resources/aws/compute/ecs.js +747 -261
- package/dist/lib/resources/aws/compute/ecsFreeTier.js +1 -1
- package/dist/lib/resources/aws/compute/ecsSpot.js +1 -1
- package/dist/lib/resources/aws/compute/utilities/capacityProviderDrainWaiter.d.ts +20 -0
- package/dist/lib/resources/aws/compute/utilities/capacityProviderDrainWaiter.js +180 -0
- package/dist/lib/resources/aws/database/rdsAurora.d.ts +1 -0
- package/dist/lib/resources/aws/database/rdsAurora.js +2 -2
- package/dist/lib/resources/aws/database/rdsAuroraGlobal.d.ts +1 -0
- package/dist/lib/resources/aws/database/rdsAuroraGlobal.js +2 -1
- package/dist/lib/resources/aws/database/rdsDeletionWaiter.d.ts +33 -0
- package/dist/lib/resources/aws/database/rdsDeletionWaiter.js +74 -0
- package/dist/lib/resources/aws/database/rdsInstance.d.ts +1 -0
- package/dist/lib/resources/aws/database/rdsInstance.js +3 -3
- package/dist/lib/resources/aws/networking/vpc.d.ts +1 -0
- package/dist/lib/resources/aws/networking/vpc.js +4 -3
- package/dist/lib/resources/aws/networking/vpcEndpoint.d.ts +2 -2
- package/dist/lib/resources/aws/networking/vpcEndpoint.js +1 -1
- package/dist/lib/resources/aws/networking/vpcEndpoints.d.ts +71 -0
- package/dist/lib/resources/aws/networking/vpcEndpoints.js +125 -0
- package/dist/lib/resources/aws/secrets/kms.d.ts +14 -0
- package/dist/lib/resources/aws/secrets/kms.js +5 -2
- package/dist/lib/resources/aws/secrets/secret.js +1 -1
- package/dist/lib/utils/standardTagsAspect.d.ts +26 -12
- package/dist/lib/utils/standardTagsAspect.js +67 -477
- package/dist/lib/utils/tagResource.d.ts +18 -3
- package/dist/lib/utils/tagResource.js +23 -6
- package/package.json +3 -3
- package/dist/lib/aspects/resourceInventory.d.ts +0 -41
- package/dist/lib/aspects/resourceInventory.js +0 -56
- package/dist/lib/config/audit.d.ts +0 -18
- package/dist/lib/config/audit.js +0 -22
- package/dist/lib/patterns/aws/auditRole.d.ts +0 -44
- package/dist/lib/patterns/aws/auditRole.js +0 -58
- package/dist/lib/patterns/aws/basicApp.d.ts +0 -0
- package/dist/lib/patterns/aws/basicApp.js +0 -150
- package/dist/lib/patterns/aws/ec2.d.ts +0 -43
- package/dist/lib/patterns/aws/ec2.js +0 -123
- package/dist/lib/patterns/aws/freeTierApp.d.ts +0 -44
- package/dist/lib/patterns/aws/freeTierApp.js +0 -83
- package/dist/lib/patterns/aws/spotInstanceApp.d.ts +0 -45
- package/dist/lib/patterns/aws/spotInstanceApp.js +0 -85
- package/dist/lib/resources/aws/audit/auditRole.d.ts +0 -32
- package/dist/lib/resources/aws/audit/auditRole.js +0 -46
- package/dist/lib/resources/aws/database/databaseFreeTier.d.ts +0 -15
- package/dist/lib/resources/aws/database/databaseFreeTier.js +0 -29
- package/dist/lib/resources/aws/database/rdsFreeTier.d.ts +0 -37
- package/dist/lib/resources/aws/database/rdsFreeTier.js +0 -84
- package/dist/lib/utils/getCidr.d.ts +0 -8
- 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
36
|
-
this.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
this.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
|
49
|
-
defaultPort: aws_ec2_1.Port.tcp(
|
|
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:
|
|
599
|
+
enableFargateCapacityProviders: this.isFargate()
|
|
58
600
|
});
|
|
59
|
-
//
|
|
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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
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
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
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
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
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
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
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
|
-
|
|
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
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
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.
|
|
284
|
-
port
|
|
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.
|
|
290
|
-
port
|
|
775
|
+
this.loadBalancerListener = this.loadBalancer.addListener(`${props.clusterName}Listener`, {
|
|
776
|
+
port,
|
|
777
|
+
defaultAction
|
|
291
778
|
});
|
|
292
779
|
}
|
|
293
780
|
}
|
|
294
781
|
addHostedZone(props) {
|
|
295
|
-
|
|
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
|
-
|
|
298
|
-
|
|
299
|
-
const hostedZone = new hostedZone_1.HostedZone(this, `${props.
|
|
300
|
-
zoneName:
|
|
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
|
-
|
|
306
|
-
this.hostedZone = props.domainConfig.hostedZone.getInternalHostedZone();
|
|
795
|
+
this.hostedZone = domainConfig.hostedZone.getInternalHostedZone();
|
|
307
796
|
}
|
|
308
|
-
if (!
|
|
309
|
-
|
|
310
|
-
|
|
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
|
-
//
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
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
|
-
|
|
333
|
-
|
|
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
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
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 =
|
|
373
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWNzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vbGliL3Jlc291cmNlcy9hd3MvY29tcHV0ZS9lY3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsaURBVzZCO0FBQzdCLGlEQU02QjtBQUM3QiwyQ0FBdUM7QUFFdkMsNkNBQWdFO0FBQ2hFLHVGQUlnRDtBQUNoRCxpREFRNkI7QUFDN0IsdUZBS2dEO0FBQ2hELGlEQUEwRDtBQUMxRCx1RUFBd0Q7QUFDeEQsK0VBRzRDO0FBQzVDLHlEQUtpQztBQUNqQyx5RUFBcUU7QUFDckUsaURBQWlEO0FBR2pELHNEQUFtRDtBQUNuRCxpRUFBaUY7QUFJakYsSUFBWSxRQUdYO0FBSEQsV0FBWSxRQUFRO0lBQ2xCLHVDQUFJLENBQUE7SUFDSix5Q0FBSyxDQUFBO0FBQ1AsQ0FBQyxFQUhXLFFBQVEsd0JBQVIsUUFBUSxRQUduQjtBQUVELElBQVksV0FHWDtBQUhELFdBQVksV0FBVztJQUNyQixzREFBMEQsQ0FBQTtJQUMxRCw0REFBZ0UsQ0FBQTtBQUNsRSxDQUFDLEVBSFcsV0FBVywyQkFBWCxXQUFXLFFBR3RCO0FBcUVELE1BQXFCLGNBQWUsU0FBUSxzQkFBUztJQXFCbkQsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxLQUEwQjtRQUNsRSxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBUFgsWUFBTyxHQUVYLEVBQUUsQ0FBQztRQU9MLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO1FBRW5CLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDdkIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN2QixJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzFCLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUM3QixJQUFJLENBQUMsaUJBQWlCLENBQUMsS0FBSyxD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Q0osQ0FBQztDQUNGO0FBdGRELGlDQXNkQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIEF3c0xvZ0RyaXZlcixcbiAgQ2x1c3RlciBhcyBDZGtDbHVzdGVyLFxuICBDb250YWluZXJJbWFnZSxcbiAgRmFyZ2F0ZVNlcnZpY2UsXG4gIEZhcmdhdGVUYXNrRGVmaW5pdGlvbixcbiAgTGlzdGVuZXJDb25maWcsXG4gIFByb3BhZ2F0ZWRUYWdTb3VyY2UsXG4gIHR5cGUgUmVwb3NpdG9yeUltYWdlLFxuICB0eXBlIENvbnRhaW5lckRlZmluaXRpb24sXG4gIENvbnRhaW5lckluc2lnaHRzXG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtZWNzXCI7XG5pbXBvcnQge1xuICBDb25uZWN0aW9ucyxcbiAgdHlwZSBJQ29ubmVjdGFibGUsXG4gIHR5cGUgSVZwYyxcbiAgUG9ydCxcbiAgU3VibmV0VHlwZVxufSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWVjMlwiO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSBcImNvbnN0cnVjdHNcIjtcbmltcG9ydCB7IHR5cGUgU3RhY2tCdWlsZGVyIH0gZnJvbSBcIi4uL2Jhc2UvYXdzU3RhY2tcIjtcbmltcG9ydCB7IER1cmF0aW9uLCB0eXBlIFNlY3JldFZhbHVlLCBTdGFjayB9IGZyb20gXCJhd3MtY2RrLWxpYlwiO1xuaW1wb3J0IHtcbiAgdHlwZSBBcHBsaWNhdGlvbkxpc3RlbmVyLFxuICBBcHBsaWNhdGlvbkxvYWRCYWxhbmNlcixcbiAgQXBwbGljYXRpb25Qcm90b2NvbFxufSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWVsYXN0aWNsb2FkYmFsYW5jaW5ndjJcIjtcbmltcG9ydCB7XG4gIENvbXBvc2l0ZVByaW5jaXBhbCxcbiAgRWZmZWN0LFxuICB0eXBlIElNYW5hZ2VkUG9saWN5LFxuICBQb2xpY3lEb2N1bWVudCxcbiAgUG9saWN5U3RhdGVtZW50LFxuICBSb2xlLFxuICBTZXJ2aWNlUHJpbmNpcGFsXG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtaWFtXCI7XG5pbXBvcnQge1xuICBQcmVkZWZpbmVkTWV0cmljLFxuICBTY2FsYWJsZVRhcmdldCxcbiAgU2VydmljZU5hbWVzcGFjZSxcbiAgVGFyZ2V0VHJhY2tpbmdTY2FsaW5nUG9saWN5XG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtYXBwbGljYXRpb25hdXRvc2NhbGluZ1wiO1xuaW1wb3J0IHsgU2VjcmV0IGFzIEVjc1NlY3JldCB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtZWNzXCI7XG5pbXBvcnQgeyBTZWNyZXQgfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLXNlY3JldHNtYW5hZ2VyXCI7XG5pbXBvcnQge1xuICBDZXJ0aWZpY2F0ZSxcbiAgQ2VydGlmaWNhdGVWYWxpZGF0aW9uXG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtY2VydGlmaWNhdGVtYW5hZ2VyXCI7XG5pbXBvcnQge1xuICBBUmVjb3JkLFxuICBSZWNvcmRUYXJnZXQsXG4gIHR5cGUgSUhvc3RlZFpvbmUsXG4gIHR5cGUgR2VvTG9jYXRpb25cbn0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1yb3V0ZTUzXCI7XG5pbXBvcnQgeyBMb2FkQmFsYW5jZXJUYXJnZXQgfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLXJvdXRlNTMtdGFyZ2V0c1wiO1xuaW1wb3J0IHsgUmVwb3NpdG9yeSB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtZWNyXCI7XG5cbmltcG9ydCB7IHR5cGUgS2V5VmFsdWUgfSBmcm9tIFwiLi4vLi4vLi4vdHlwZXNcIjtcbmltcG9ydCB7IENmbk91dHB1dCB9IGZyb20gXCIuLi91dGlsaXRpZXMvY2ZuT3V0cHV0XCI7XG5pbXBvcnQgeyBIb3N0ZWRab25lIGFzIEZqYWxsSG9zdGVkWm9uZSB9IGZyb20gXCIuLi8uLi8uLi9wYXR0ZXJucy9hd3MvaG9zdGVkWm9uZVwiO1xuXG5pbXBvcnQgeyB0eXBlIFNlY3JldEltcG9ydCB9IGZyb20gXCIuLi9zZWNyZXRzXCI7XG5cbmV4cG9ydCBlbnVtIFByb3RvY29sIHtcbiAgSFRUUCxcbiAgSFRUUFNcbn1cblxuZXhwb3J0IGVudW0gU2NhbGluZ1R5cGUge1xuICBDUFUgPSBQcmVkZWZpbmVkTWV0cmljLkVDU19TRVJWSUNFX0FWRVJBR0VfQ1BVX1VUSUxJWkFUSU9OLFxuICBNRU1PUlkgPSBQcmVkZWZpbmVkTWV0cmljLkVDU19TRVJWSUNFX0FWRVJBR0VfTUVNT1JZX1VUSUxJWkFUSU9OXG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ29udGFpbmVyU2VjcmV0IHtcbiAgW2tleTogc3RyaW5nXTogU2VjcmV0VmFsdWU7XG59XG5cbi8qKlxuICogRG9tYWluQ29uZmlndXJhdGlvblxuICogLSBXaGVuIHN1cHBsaWVkIGEgZG9tYWluIG5hbWUsIGEgaG9zdGVkIHpvbmUsIGNlcnRpZmljYXRlIGFuZCBBUmVjb3JkIHdpbGwgYmUgY3JlYXRlZFxuICogLSBXaGVuIHN1cHBsaWVkIGEgZG9tYWluIG5hbWUgYW5kIGhvc3RlZCB6b25lLCBhIGNlcnRpZmljYXRlIGFuZCBBUmVjb3JkIHdpbGwgYmUgY3JlYXRlZFxuICogLSBXaGVuIGFsbCBwcm9wZXJ0aWVzIGFyZSBzdXBwbGllZCBvbmx5IGEgdGFyZ2V0IHdpbGwgYmUgY3JlYXRlZFxuICovXG5cbmV4cG9ydCBpbnRlcmZhY2UgRG9tYWluQmFzZUNvbmZpZyB7XG4gIGRvbWFpbk5hbWU6IHN0cmluZztcbiAgaG9zdGVkWm9uZT86IEZqYWxsSG9zdGVkWm9uZTtcbiAgY2VydGlmaWNhdGU/OiBDZXJ0aWZpY2F0ZTtcbiAgLy8gT3B0aW9uYWw6IFNldCBpZGVudGlmaWVyIGZvciByb3V0aW5nIHBvbGljaWVzIChhdXRvLWdlbmVyYXRlZCBpZiBub3QgcHJvdmlkZWQpXG4gIHNldElkZW50aWZpZXI/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTGF0ZW5jeURvbWFpbkNvbmZpZyBleHRlbmRzIERvbWFpbkJhc2VDb25maWcge1xuICAvLyBTZXQgdG8gZW5hYmxlIGxhdGVuY3kgYmFzZWQgcm91dGluZ1xuICByZWdpb246IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBXZWlnaHRlZERvbWFpbkNvbmZpZyBleHRlbmRzIERvbWFpbkJhc2VDb25maWcge1xuICAvLyBTZXQgdG8gZW5hYmxlIHdlaWdodGVkIHJvdXRpbmdcbiAgd2VpZ2h0OiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgR2VvTG9jYXRpb25Eb21haW5Db25maWcgZXh0ZW5kcyBEb21haW5CYXNlQ29uZmlnIHtcbiAgLy8gU2V0IHRvIGVuYWJsZSBnZW9sb2NhdGlvbiBiYXNlZCByb3V0aW5nXG4gIGdlb0xvY2F0aW9uOiBHZW9Mb2NhdGlvbjtcbn1cblxuZXhwb3J0IHR5cGUgRG9tYWluQ29uZmlnID1cbiAgfCBEb21haW5CYXNlQ29uZmlnXG4gIHwgTGF0ZW5jeURvbWFpbkNvbmZpZ1xuICB8IFdlaWdodGVkRG9tYWluQ29uZmlnXG4gIHwgR2VvTG9jYXRpb25Eb21haW5Db25maWc7XG5cbmV4cG9ydCB0eXBlIEZhcmdhdGVDbHVzdGVyUHJvcHMgPSB7XG4gIGVjclJlcG9zaXRvcnk6IFJlcG9zaXRvcnkgfCBSZXBvc2l0b3J5SW1hZ2U7XG4gIGNsdXN0ZXJOYW1lOiBzdHJpbmc7XG4gIGNvbnRhaW5lckNvbW1hbmQ/OiBzdHJpbmdbXTtcbiAgY29udGFpbmVyRW52aXJvbm1lbnQ/OiBLZXlWYWx1ZTtcbiAgY29udGFpbmVyU2VjcmV0cz86IENvbnRhaW5lclNlY3JldDtcbiAgY29udGFpbmVyU2VjcmV0c0ltcG9ydD86IHtcbiAgICBba2V5OiBzdHJpbmddOiBTZWNyZXRJbXBvcnQ7XG4gIH07XG4gIGNvbnRhaW5lclBvcnQ/OiBudW1iZXI7XG4gIGNwdT86IG51bWJlcjtcbiAgZG9tYWluQ29uZmlnPzogRG9tYWluQ29uZmlnO1xuICBkZXNpcmVkQ291bnQ/OiBudW1iZXI7XG4gIGhlYWx0aENoZWNrUGF0aD86IHN0cmluZztcbiAgbGlzdGVuZXJQb3J0PzogbnVtYmVyO1xuICBtZW1vcnlMaW1pdE1pQj86IG51bWJlcjtcbiAgcHVibGljTG9hZEJhbGFuY2VyPzogYm9vbGVhbjtcbiAgcHJvdG9jb2w6IFByb3RvY29sO1xuICBzY2FsaW5nVHlwZT86IFNjYWxpbmdUeXBlO1xuICBzZXJ2aWNlTmFtZTogc3RyaW5nO1xuICB0YXNrUm9sZUlubGluZVBvbGljaWVzPzoge1xuICAgIFtuYW1lOiBzdHJpbmddOiBQb2xpY3lEb2N1bWVudDtcbiAgfTtcbiAgdGFza1JvbGVNYW5hZ2VkUG9saWNpZXM/OiBJTWFuYWdlZFBvbGljeVtdO1xuICB2cGM/OiBJVnBjO1xufTtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgRmFyZ2F0ZUNsdXN0ZXIgZXh0ZW5kcyBDb25zdHJ1Y3QgaW1wbGVtZW50cyBJQ29ubmVjdGFibGUge1xuICBwdWJsaWMgY29ubmVjdGlvbnM6IENvbm5lY3Rpb25zO1xuXG4gIHByaXZhdGUgY2x1c3RlcjogQ2RrQ2x1c3RlcjtcbiAgcHJpdmF0ZSBsb2FkQmFsYW5jZXI6IEFwcGxpY2F0aW9uTG9hZEJhbGFuY2VyO1xuICBwcml2YXRlIGV4ZWN1dGlvblJvbGU6IFJvbGU7XG4gIHByaXZhdGUgdGFza0RlZmluaXRpb246IEZhcmdhdGVUYXNrRGVmaW5pdGlvbjtcbiAgcHJpdmF0ZSBjb250YWluZXJEZWZpbml0aW9uOiBDb250YWluZXJEZWZpbml0aW9uO1xuICBwcml2YXRlIGZhcmdhdGVTZXJ2aWNlOiBGYXJnYXRlU2VydmljZTtcbiAgcHJpdmF0ZSBzY2FsaW5nUG9saWN5OiBUYXJnZXRUcmFja2luZ1NjYWxpbmdQb2xpY3k7XG4gIHByaXZhdGUgaG9zdGVkWm9uZTogSUhvc3RlZFpvbmU7XG4gIHByaXZhdGUgY2VydGlmaWNhdGU6IENlcnRpZmljYXRlO1xuICBwcml2YXRlIGFSZWNvcmQ6IEFSZWNvcmQ7XG4gIHByaXZhdGUgbG9hZEJhbGFuY2VyTGlzdGVuZXI6IEFwcGxpY2F0aW9uTGlzdGVuZXI7XG5cbiAgcHJpdmF0ZSBzZWNyZXRzOiB7XG4gICAgW2tleTogc3RyaW5nXTogRWNzU2VjcmV0O1xuICB9ID0ge307XG5cbiAgcHJpdmF0ZSBzY29wZTogQ29uc3RydWN0O1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBGYXJnYXRlQ2x1c3RlclByb3BzKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkKTtcblxuICAgIHRoaXMuc2NvcGUgPSBzY29wZTtcblxuICAgIHRoaXMuYWRkQ2x1c3Rlcihwcm9wcyk7XG4gICAgdGhpcy5hZGRTZWNyZXRzKHByb3BzKTtcbiAgICB0aGlzLmltcG9ydFNlY3JldHMocHJvcHMpO1xuICAgIHRoaXMuYWRkRXhlY3V0aW9uUm9sZShwcm9wcyk7XG4gICAgdGhpcy5hZGRUYXNrRGVmaW5pdGlvbihwcm9wcyk7XG4gICAgdGhpcy5hZGRDb250YWluZXJEZWZpbml0aW9uKHByb3BzKTtcbiAgICB0aGlzLmFkZEZhcmdhdGVTZXJ2aWNlKHByb3BzKTtcbiAgICB0aGlzLmFkZExvYWRCYWxhbmNlcihwcm9wcyk7XG5cbiAgICBpZiAocHJvcHMuZG9tYWluQ29uZmlnKSB0aGlzLmFkZEhvc3RlZFpvbmUocHJvcHMpO1xuXG4gICAgdGhpcy5hZGRMb2FkQmFsYW5jZXJMaXN0ZW5lcihwcm9wcyk7XG4gICAgdGhpcy5yZWdpc3RlckxvYWRCYWxhbmNlclRhcmdldHMocHJvcHMpO1xuXG4gICAgY29uc3QgY29udGFpbmVyUG9ydCA9IHByb3BzLmNvbnRhaW5lclBvcnQgfHwgODA7XG4gICAgdGhpcy5jb25uZWN0aW9ucyA9IG5ldyBDb25uZWN0aW9ucyh7XG4gICAgICBzZWN1cml0eUdyb3VwczogdGhpcy5mYXJnYXRlU2VydmljZS5jb25uZWN0aW9ucy5zZWN1cml0eUdyb3VwcyxcbiAgICAgIGRlZmF1bHRQb3J0OiBQb3J0LnRjcChjb250YWluZXJQb3J0KVxuICAgIH0pO1xuICB9XG5cbiAgYWRkQ2x1c3Rlcihwcm9wczogRmFyZ2F0ZUNsdXN0ZXJQcm9wcykge1xuICAgIHRoaXMuY2x1c3RlciA9IG5ldyBDZGtDbHVzdGVyKHRoaXMsIGAke3Byb3BzLmNsdXN0ZXJOYW1lfWAsIHtcbiAgICAgIHZwYzogcHJvcHMudnBjLFxuICAgICAgY2x1c3Rlck5hbWU6IHByb3BzLmNsdXN0ZXJOYW1lLFxuICAgICAgY29udGFpbmVySW5zaWdodHNWMjogQ29udGFpbmVySW5zaWdodHMuRU5BQkxFRCxcbiAgICAgIGVuYWJsZUZhcmdhdGVDYXBhY2l0eVByb3ZpZGVyczogdHJ1ZVxuICAgIH0pO1xuXG4gICAgLy8gT3V0cHV0IHVzZWQgdG8gYXV0by1kZXRlY3QgZGVwbG95YWJsZSBjbHV0ZXJcbiAgICBuZXcgQ2ZuT3V0cHV0KHRoaXMsIGAke3Byb3BzLmNsdXN0ZXJOYW1lfURlcGxveWFibGVDbHVzdGVyYCwge1xuICAgICAga2V5OiBgJHtwcm9wcy5jbHVzdGVyTmFtZX1EZXBsb3lhYmxlQ2x1c3RlcmAsXG4gICAgICBleHBvcnROYW1lOiBgJHtwcm9wcy5jbHVzdGVyTmFtZX1EZXBsb3lhYmxlQ2x1c3RlcmAsXG4gICAgICB2YWx1ZTogdGhpcy5jbHVzdGVyLmNsdXN0ZXJBcm5cbiAgICB9KTtcblxuICAgIC8vIEV4cG9ydCBjbHVzdGVyIEFSTiBmb3IgbW9uaXRvcmluZ1xuICAgIG5ldyBDZm5PdXRwdXQodGhpcywgYCR7cHJvcHMuY2x1c3Rlck5hbWV9Q2x1c3RlckFybmAsIHtcbiAgICAgIGtleTogXCJDbHVzdGVyQXJuXCIsXG4gICAgICBleHBvcnROYW1lOiBgJHtwcm9wcy5jbHVzdGVyTmFtZX1DbHVzdGVyQXJuYCxcbiAgICAgIHZhbHVlOiB0aGlzLmNsdXN0ZXIuY2x1c3RlckFybixcbiAgICAgIGRlc2NyaXB0aW9uOiBgRUNTIENsdXN0ZXIgQVJOIGZvciAke3Byb3BzLmNsdXN0ZXJOYW1lfWBcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiAjdG9kbzogY2hhbmdlIHRoaXMgdG8gY3JlYXRlIG5ldyBzZWNyZXRzIGluc3RlYWRcbiAgICogQGRlcHJlY2F0ZWQgdXNlIGltcG9ydFNlY3JldHMgaW5zdGVhZFxuICAgKi9cbiAgYWRkU2VjcmV0cyhwcm9wczogRmFyZ2F0ZUNsdXN0ZXJQcm9wcykge1xuICAgIC8vIENvbnRhaW5lciBTZWNyZXRzXG4gICAgY29uc3QgY29udGFpbmVyU2VjcmV0ID0gU2VjcmV0LmZyb21TZWNyZXROYW1lVjIoXG4gICAgICB0aGlzLFxuICAgICAgYCR7cHJvcHMuY2x1c3Rlck5hbWV9U2VjcmV0YCxcbiAgICAgIGAvJHtwcm9wcy5jbHVzdGVyTmFtZX0vJHtwcm9wcy5zZXJ2aWNlTmFtZX1gXG4gICAgKTtcblxuICAgIGZvciAoY29uc3Qgc2VjcmV0RmllbGQgaW4gcHJvcHMuY29udGFpbmVyU2VjcmV0cykge1xuICAgICAgdGhpcy5zZWNyZXRzW3NlY3JldEZpZWxkXSA9IEVjc1NlY3JldC5mcm9tU2VjcmV0c01hbmFnZXIoXG4gICAgICAgIGNvbnRhaW5lclNlY3JldCxcbiAgICAgICAgc2VjcmV0RmllbGRcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEF1dG9tYXRpY2FsbHkgaW1wb3J0IHNlY3JldHMgZnJvbSBhbm90aGVyIHJlc291cmNlIG9yIHN0YWNrXG4gICAqL1xuICBpbXBvcnRTZWNyZXRzKHByb3BzOiBGYXJnYXRlQ2x1c3RlclByb3BzKSB7XG4gICAgaWYgKCFwcm9wcy5jb250YWluZXJTZWNyZXRzSW1wb3J0KSByZXR1cm47XG5cbiAgICBmb3IgKGNvbnN0IGtleSBpbiBwcm9wcy5jb250YWluZXJTZWNyZXRzSW1wb3J0KSB7XG4gICAgICBjb25zdCBpbXBvcnRTZWNyZXQgPSBwcm9wcy5jb250YWluZXJTZWNyZXRzSW1wb3J0W2tleV07XG5cbiAgICAgIC8vIHRvZG86IEkgdGhpbmsgSUQgbmVlZHMgdG8gYmUgYSBuZXcgdmFsdWUgYXMgaXQgSUQncyB0aGUgSU1QT1JUIG5vdCB0aGUgc2VjcmV0IGl0c2VsZj9cblxuICAgICAgLy8gQ29uc3RydWN0IHRoZSBBV1MgSVNlY3JldCBvYmplY3RcbiAgICAgIGNvbnN0IGlTZWNyZXQgPSBTZWNyZXQuZnJvbVNlY3JldE5hbWVWMihcbiAgICAgICAgdGhpcyxcbiAgICAgICAgaW1wb3J0U2VjcmV0LmlkLFxuICAgICAgICBpbXBvcnRTZWNyZXQubmFtZVxuICAgICAgKTtcblxuICAgICAgdGhpcy5zZWNyZXRzW2tleV0gPSBFY3NTZWNyZXQuZnJvbVNlY3JldHNNYW5hZ2VyKFxuICAgICAgICBpU2VjcmV0LFxuICAgICAgICBpbXBvcnRTZWNyZXQuZmllbGRcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgYWRkRXhlY3V0aW9uUm9sZShwcm9wczogRmFyZ2F0ZUNsdXN0ZXJQcm9wcykge1xuICAgIHRoaXMuZXhlY3V0aW9uUm9sZSA9IG5ldyBSb2xlKFxuICAgICAgdGhpcyxcbiAgICAgIGAke3Byb3BzLnNlcnZpY2VOYW1lfUV4ZWN1dGlvblJvbGUke1N0YWNrLm9mKHRoaXMpLnJlZ2lvbn1gLFxuICAgICAge1xuICAgICAgICByb2xlTmFtZTogYCR7cHJvcHMuc2VydmljZU5hbWV9RXhlY3V0aW9uUm9sZSR7U3RhY2sub2YodGhpcykucmVnaW9ufWAsXG4gICAgICAgIGRlc2NyaXB0aW9uOiBgJHtwcm9wcy5zZXJ2aWNlTmFtZX0gRXhlY3V0aW9uIFJvbGVgLFxuICAgICAgICBtYW5hZ2VkUG9saWNpZXM6IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBtYW5hZ2VkUG9saWN5QXJuOlxuICAgICAgICAgICAgICBcImFybjphd3M6aWFtOjphd3M6cG9saWN5L3NlcnZpY2Utcm9sZS9BbWF6b25FQ1NUYXNrRXhlY3V0aW9uUm9sZVBvbGljeVwiXG4gICAgICAgICAgfVxuICAgICAgICBdLFxuICAgICAgICBpbmxpbmVQb2xpY2llczoge1xuICAgICAgICAgIFtcInJlYWRTZWNyZXRzXCJdOiBuZXcgUG9saWN5RG9jdW1lbnQoe1xuICAgICAgICAgICAgc3RhdGVtZW50czogW1xuICAgICAgICAgICAgICBuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgICAgICAgICBhY3Rpb25zOiBbXG4gICAgICAgICAgICAgICAgICBcInNlY3JldHNtYW5hZ2VyOkdldFNlY3JldFZhbHVlXCIsXG4gICAgICAgICAgICAgICAgICBcInNlY3JldHNtYW5hZ2VyOkRlc2NyaWJlU2VjcmV0XCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIHJlc291cmNlczogW1wiKlwiXSAvLyBUT0RPOiBTZXQgdGhpcyB0byB0aGUgc2VjcmV0IEFSTlxuICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgXVxuICAgICAgICAgIH0pLFxuICAgICAgICAgIFtcImRlY3J5cHRTZWNyZXRzXCJdOiBuZXcgUG9saWN5RG9jdW1lbnQoe1xuICAgICAgICAgICAgc3RhdGVtZW50czogW1xuICAgICAgICAgICAgICBuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgICAgICAgICBhY3Rpb25zOiBbXCJrbXM6RGVjcnlwdFwiXSxcbiAgICAgICAgICAgICAgICByZXNvdXJjZXM6IFtcIipcIl0gLy8gVE9ETzogU2V0IHRoaXMgdG8gdGhlIEtNUyBBcm5cbiAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIF1cbiAgICAgICAgICB9KSxcbiAgICAgICAgICBbXCJlY3NFeGVjdXRlQ29tbWFuZFwiXTogbmV3IFBvbGljeURvY3VtZW50KHtcbiAgICAgICAgICAgIHN0YXRlbWVudHM6IFtcbiAgICAgICAgICAgICAgbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgICAgICAgICAgYWN0aW9uczogW1xuICAgICAgICAgICAgICAgICAgXCJzc21tZXNzYWdlczpDcmVhdGVDb250cm9sQ2hhbm5lbFwiLFxuICAgICAgICAgICAgICAgICAgXCJzc21tZXNzYWdlczpDcmVhdGVEYXRhQ2hhbm5lbFwiLFxuICAgICAgICAgICAgICAgICAgXCJzc21tZXNzYWdlczpPcGVuQ29udHJvbENoYW5uZWxcIixcbiAgICAgICAgICAgICAgICAgIFwic3NtbWVzc2FnZXM6T3BlbkRhdGFDaGFubmVsXCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIGVmZmVjdDogRWZmZWN0LkFMTE9XLFxuICAgICAgICAgICAgICAgIHJlc291cmNlczogW1wiKlwiXVxuICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgXVxuICAgICAgICAgIH0pXG4gICAgICAgIH0sXG4gICAgICAgIGFzc3VtZWRCeTogbmV3IENvbXBvc2l0ZVByaW5jaXBhbChcbiAgICAgICAgICBuZXcgU2VydmljZVByaW5jaXBhbChcImVjcy10YXNrcy5hbWF6b25hd3MuY29tXCIpXG4gICAgICAgIClcbiAgICAgIH1cbiAgICApO1xuICB9XG5cbiAgYWRkVGFza0RlZmluaXRpb24ocHJvcHM6IEZhcmdhdGVDbHVzdGVyUHJvcHMpIHtcbiAgICB0aGlzLnRhc2tEZWZpbml0aW9uID0gbmV3IEZhcmdhdGVUYXNrRGVmaW5pdGlvbihcbiAgICAgIHRoaXMsXG4gICAgICBgJHtwcm9wcy5zZXJ2aWNlTmFtZX1UYXNrRGVmaW5pdGlvbmAsXG4gICAgICB7XG4gICAgICAgIGNwdTogcHJvcHMuY3B1IHx8IDI1NixcbiAgICAgICAgZXhlY3V0aW9uUm9sZTogdGhpcy5leGVjdXRpb25Sb2xlLFxuICAgICAgICB0YXNrUm9sZTogbmV3IFJvbGUoXG4gICAgICAgICAgdGhpcyxcbiAgICAgICAgICBgJHtwcm9wcy5zZXJ2aWNlTmFtZX1UYXNrUm9sZSR7U3RhY2sub2YodGhpcykucmVnaW9ufWAsXG4gICAgICAgICAge1xuICAgICAgICAgICAgcm9sZU5hbWU6IGAke3Byb3BzLnNlcnZpY2VOYW1lfVRhc2tSb2xlJHtTdGFjay5vZih0aGlzKS5yZWdpb259YCxcbiAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBgJHtwcm9wcy5zZXJ2aWNlTmFtZX0gVGFzayBSb2xlYCxcbiAgICAgICAgICAgIGlubGluZVBvbGljaWVzOiBwcm9wcy50YXNrUm9sZUlubGluZVBvbGljaWVzLFxuICAgICAgICAgICAgbWFuYWdlZFBvbGljaWVzOiBwcm9wcy50YXNrUm9sZU1hbmFnZWRQb2xpY2llcyxcbiAgICAgICAgICAgIGFzc3VtZWRCeTogbmV3IENvbXBvc2l0ZVByaW5jaXBhbChcbiAgICAgICAgICAgICAgbmV3IFNlcnZpY2VQcmluY2lwYWwoXCJlY3MtdGFza3MuYW1hem9uYXdzLmNvbVwiKVxuICAgICAgICAgICAgKVxuICAgICAgICAgIH1cbiAgICAgICAgKSxcbiAgICAgICAgbWVtb3J5TGltaXRNaUI6IHByb3BzLm1lbW9yeUxpbWl0TWlCIHx8IDUxMlxuICAgICAgfVxuICAgICk7XG4gIH1cblxuICBhZGRDb250YWluZXJEZWZpbml0aW9uKHByb3BzOiBGYXJnYXRlQ2x1c3RlclByb3BzKSB7XG4gICAgdGhpcy5jb250YWluZXJEZWZpbml0aW9uID0gdGhpcy50YXNrRGVmaW5pdGlvbi5hZGRDb250YWluZXIoXG4gICAgICBgJHtwcm9wcy5zZXJ2aWNlTmFtZX1Db250YWluZXJEZWZpbml0aW9uYCxcbiAgICAgIHtcbiAgICAgICAgaW1hZ2U6IHRoaXMuZ2V0SW1hZ2UocHJvcHMpLFxuICAgICAgICBjb250YWluZXJOYW1lOiBwcm9wcy5zZXJ2aWNlTmFtZSxcbiAgICAgICAgZW52aXJvbm1lbnQ6IHtcbiAgICAgICAgICAuLi5wcm9wcy5jb250YWluZXJFbnZpcm9ubWVudFxuICAgICAgICB9LFxuICAgICAgICBjb21tYW5kOiBwcm9wcy5jb250YWluZXJDb21tYW5kLFxuICAgICAgICBzZWNyZXRzOiB7XG4gICAgICAgICAgLi4udGhpcy5zZWNyZXRzXG4gICAgICAgIH0sXG4gICAgICAgIC8vdG9kbzogcHJvdmlkZSBoZWFsdGggY2hlY2sgb3B0aW9uc1xuICAgICAgICBoZWFsdGhDaGVjazoge1xuICAgICAgICAgIGNvbW1hbmQ6IFtcbiAgICAgICAgICAgIFwiQ01ELVNIRUxMXCIsXG4gICAgICAgICAgICAvLyBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQW1hem9uRUNTL2xhdGVzdC9kZXZlbG9wZXJndWlkZS92aWV3LWNvbnRhaW5lci1oZWFsdGguaHRtbFxuICAgICAgICAgICAgLy8gID4+IHByb2MvMS9mZC8xIDI+JjEgcmVkaXJlY3RzIHN0ZG91dCBhbmQgc3RkZXJyIG9mIHRoZSBoZWFsdGggY2hlY2sgdG8gQ2xvdWRXYXRjaCBsb2dzXG4gICAgICAgICAgICAvLyBgY3VybCAtZiBodHRwOi8vbG9jYWxob3N0OiR7cHJvcHMuY29udGFpbmVyUG9ydH0vID4+IC9wcm9jLzEvZmQvMSAyPiYxICB8fCBleGl0IDFgXG4gICAgICAgICAgICBgY3VybCAtZiBodHRwOi8vbG9jYWxob3N0OiR7cHJvcHMuY29udGFpbmVyUG9ydH0vIHx8IGV4aXQgMWBcbiAgICAgICAgICBdXG4gICAgICAgIH0sXG4gICAgICAgIGxvZ2dpbmc6IG5ldyBBd3NMb2dEcml2ZXIoe1xuICAgICAgICAgIHN0cmVhbVByZWZpeDogYC9lY3MvJHtwcm9wcy5jbHVzdGVyTmFtZX0vJHtwcm9wcy5zZXJ2aWNlTmFtZX1gLFxuICAgICAgICAgIGxvZ1JldGVudGlvbjogMTRcbiAgICAgICAgfSksXG4gICAgICAgIHBvcnRNYXBwaW5nczogcHJvcHMuY29udGFpbmVyUG9ydFxuICAgICAgICAgID8gW3sgY29udGFpbmVyUG9ydDogcHJvcHMuY29udGFpbmVyUG9ydCB9XVxuICAgICAgICAgIDogW3sgY29udGFpbmVyUG9ydDogODAgfV1cbiAgICAgIH1cbiAgICApO1xuICB9XG5cbiAgYWRkRmFyZ2F0ZVNlcnZpY2UocHJvcHM6IEZhcmdhdGVDbHVzdGVyUHJvcHMpIHtcbiAgICB0aGlzLmZhcmdhdGVTZXJ2aWNlID0gbmV3IEZhcmdhdGVTZXJ2aWNlKFxuICAgICAgdGhpcyxcbiAgICAgIGAke3Byb3BzLnNlcnZpY2VOYW1lfUZhcmdhdGVTZXJ2aWNlYCxcbiAgICAgIHtcbiAgICAgICAgY2lyY3VpdEJyZWFrZXI6IHsgcm9sbGJhY2s6IHRydWUgfSxcbiAgICAgICAgY2x1c3RlcjogdGhpcy5jbHVzdGVyLFxuICAgICAgICBkZXNpcmVkQ291bnQ6IDIsXG4gICAgICAgIGVuYWJsZUVDU01hbmFnZWRUYWdzOiB0cnVlLFxuICAgICAgICBlbmFibGVFeGVjdXRlQ29tbWFuZDogdHJ1ZSxcbiAgICAgICAgcHJvcGFnYXRlVGFnczogUHJvcGFnYXRlZFRhZ1NvdXJjZS5TRVJWSUNFLFxuICAgICAgICBzZXJ2aWNlTmFtZTogYCR7cHJvcHMuc2VydmljZU5hbWV9YCxcbiAgICAgICAgdGFza0RlZmluaXRpb246IHRoaXMudGFza0RlZmluaXRpb24sXG4gICAgICAgIG1pbkhlYWx0aHlQZXJjZW50OiAxMDAsXG4gICAgICAgIG1heEhlYWx0aHlQZXJjZW50OiAyMDBcbiAgICAgIH1cbiAgICApO1xuXG4gICAgLy8gT3V0cHV0IHVzZWQgdG8gZGV0ZWN0IGRlcGxveWFibGUgc2VydmljZVxuICAgIG5ldyBDZm5PdXRwdXQodGhpcywgYCR7cHJvcHMuY2x1c3Rlck5hbWV9RGVwbG95YWJsZVNlcnZpY2VgLCB7XG4gICAgICBrZXk6IGAke3Byb3BzLmNsdXN0ZXJOYW1lfURlcGxveWFibGVTZXJ2aWNlYCxcbiAgICAgIGV4cG9ydE5hbWU6IGAke3Byb3BzLmNsdXN0ZXJOYW1lfURlcGxveWFibGVTZXJ2aWNlYCxcbiAgICAgIHZhbHVlOiB0aGlzLmZhcmdhdGVTZXJ2aWNlLnNlcnZpY2VBcm5cbiAgICB9KTtcblxuICAgIC8vIEV4cG9ydCBzZXJ2aWNlIEFSTiBmb3IgbW9uaXRvcmluZ1xuICAgIG5ldyBDZm5PdXRwdXQodGhpcywgYCR7cHJvcHMuY2x1c3Rlck5hbWV9U2VydmljZUFybmAsIHtcbiAgICAgIGtleTogXCJTZXJ2aWNlQXJuXCIsXG4gICAgICBleHBvcnROYW1lOiBgJHtwcm9wcy5jbHVzdGVyTmFtZX1TZXJ2aWNlQXJuYCxcbiAgICAgIHZhbHVlOiB0aGlzLmZhcmdhdGVTZXJ2aWNlLnNlcnZpY2VBcm4sXG4gICAgICBkZXNjcmlwdGlvbjogYEVDUyBTZXJ2aWNlIEFSTiBmb3IgJHtwcm9wcy5zZXJ2aWNlTmFtZX1gXG4gICAgfSk7XG4gIH1cblxuICBhZGRTY2FsaW5nUG9saWN5KHByb3BzOiBGYXJnYXRlQ2x1c3RlclByb3BzKSB7XG4gICAgdGhpcy5zY2FsaW5nUG9saWN5ID0gbmV3IFRhcmdldFRyYWNraW5nU2NhbGluZ1BvbGljeShcbiAgICAgIHRoaXMsXG4gICAgICBgJHtwcm9wcy5zZXJ2aWNlTmFtZX1TY2FsaW5nUG9saWN5YCxcbiAgICAgIHtcbiAgICAgICAgcG9saWN5TmFtZTogYCR7cHJvcHMuc2VydmljZU5hbWV9U2NhbGluZ1BvbGljeWAsXG4gICAgICAgIHNjYWxpbmdUYXJnZXQ6IG5ldyBTY2FsYWJsZVRhcmdldChcbiAgICAgICAgICB0aGlzLFxuICAgICAgICAgIGAke3Byb3BzLnNlcnZpY2VOYW1lfXNjYWxhYmxlVGFyZ2V0YCxcbiAgICAgICAgICB7XG4gICAgICAgICAgICBtYXhDYXBhY2l0eTogMTAsXG4gICAgICAgICAgICBtaW5DYXBhY2l0eTogMixcbiAgICAgICAgICAgIHJlc291cmNlSWQ6IGBzZXJ2aWNlLyR7dGhpcy5jbHVzdGVyLmNsdXN0ZXJOYW1lfS8ke3RoaXMuZmFyZ2F0ZVNlcnZpY2Uuc2VydmljZU5hbWV9YCxcbiAgICAgICAgICAgIHNjYWxhYmxlRGltZW5zaW9uOiBcImVjczpzZXJ2aWNlOkRlc2lyZWRDb3VudFwiLFxuICAgICAgICAgICAgc2VydmljZU5hbWVzcGFjZTogU2VydmljZU5hbWVzcGFjZS5FQ1NcbiAgICAgICAgICB9XG4gICAgICAgICksXG4gICAgICAgIHRhcmdldFZhbHVlOiA1MCxcbiAgICAgICAgc2NhbGVPdXRDb29sZG93bjogRHVyYXRpb24uc2Vjb25kcyg2MCksXG4gICAgICAgIHNjYWxlSW5Db29sZG93bjogRHVyYXRpb24uc2Vjb25kcyg2MCksXG4gICAgICAgIHByZWRlZmluZWRNZXRyaWM6XG4gICAgICAgICAgcHJvcHMuc2NhbGluZ1R5cGUgPT0gU2NhbGluZ1R5cGUuTUVNT1JZXG4gICAgICAgICAgICA/IFByZWRlZmluZWRNZXRyaWMuRUNTX1NFUlZJQ0VfQVZFUkFHRV9NRU1PUllfVVRJTElaQVRJT05cbiAgICAgICAgICAgIDogUHJlZGVmaW5lZE1ldHJpYy5FQ1NfU0VSVklDRV9BVkVSQUdFX0NQVV9VVElMSVpBVElPTlxuICAgICAgfVxuICAgICk7XG4gIH1cblxuICByZWdpc3RlckxvYWRCYWxhbmNlclRhcmdldHMocHJvcHM6IEZhcmdhdGVDbHVzdGVyUHJvcHMpIHtcbiAgICB0aGlzLmZhcmdhdGVTZXJ2aWNlLnJlZ2lzdGVyTG9hZEJhbGFuY2VyVGFyZ2V0cyh7XG4gICAgICBjb250YWluZXJOYW1lOiB0aGlzLmNvbnRhaW5lckRlZmluaXRpb24uY29udGFpbmVyTmFtZSxcbiAgICAgIGNvbnRhaW5lclBvcnQ6IHRoaXMuY29udGFpbmVyRGVmaW5pdGlvbi5jb250YWluZXJQb3J0LFxuICAgICAgbmV3VGFyZ2V0R3JvdXBJZDogYCR7cHJvcHMuc2VydmljZU5hbWV9VGFyZ2V0R3JvdXBgLFxuICAgICAgbGlzdGVuZXI6IExpc3RlbmVyQ29uZmlnLmFwcGxpY2F0aW9uTGlzdGVuZXIodGhpcy5sb2FkQmFsYW5jZXJMaXN0ZW5lciwge1xuICAgICAgICBwb3J0OiBwcm9wcy5jb250YWluZXJQb3J0LFxuICAgICAgICBwcm90b2NvbDogQXBwbGljYXRpb25Qcm90b2NvbC5IVFRQLFxuICAgICAgICBoZWFsdGhDaGVjazoge1xuICAgICAgICAgIGludGVydmFsOiBEdXJhdGlvbi5zZWNvbmRzKDEyMCksXG4gICAgICAgICAgcGF0aDogcHJvcHMuaGVhbHRoQ2hlY2tQYXRoIHx8IFwiL1wiLFxuICAgICAgICAgIHBvcnQ6IHByb3BzLmNvbnRhaW5lclBvcnQgPyBgJHtwcm9wcy5jb250YWluZXJQb3J0fWAgOiBcInRyYWZmaWMtcG9ydFwiLFxuICAgICAgICAgIHRpbWVvdXQ6IER1cmF0aW9uLnNlY29uZHMoMTApXG4gICAgICAgIH1cbiAgICAgIH0pXG4gICAgfSk7XG4gIH1cblxuICBhZGRMb2FkQmFsYW5jZXIocHJvcHM6IEZhcmdhdGVDbHVzdGVyUHJvcHMpIHtcbiAgICAvLyBUcnVuY2F0ZSB0aGUgbG9hZCBiYWxhbmNlciBuYW1lIHRvIGVuc3VyZSBpdCBkb2VzIG5vdCBleGNlZWQgdGhlIDMyIGNoYXJhY3RlciBBV1MgbGltaXRcbiAgICBjb25zdCBkZWZhdWx0TG9hZEJhbGFuY2VyTmFtZSA9IGAke3Byb3BzLnNlcnZpY2VOYW1lfUxvYWRCYWxhbmNlcmA7XG4gICAgY29uc3Qgc3VwcG9ydGVkTmFtZUxlbmd0aCA9IDMyO1xuXG4gICAgbGV0IHRydW5jYXRlZExvYWRCYWxhbmNlck5hbWUgPVxuICAgICAgZGVmYXVsdExvYWRCYWxhbmNlck5hbWUubGVuZ3RoID4gc3VwcG9ydGVkTmFtZUxlbmd0aFxuICAgICAgICA/IGRlZmF1bHRMb2FkQmFsYW5jZXJOYW1lLnN1YnN0cmluZygwLCBzdXBwb3J0ZWROYW1lTGVuZ3RoKVxuICAgICAgICA6IGRlZmF1bHRMb2FkQmFsYW5jZXJOYW1lO1xuXG4gICAgLy8gUmVtb3ZlIGFueSB0cmFpbGluZyBoeXBoZW5zIHRoYXQgbWlnaHQgYmUgaW50cm9kdWNlZCBieSB0cnVuY2F0aW9uXG4gICAgdHJ1bmNhdGVkTG9hZEJhbGFuY2VyTmFtZSA9IHRydW5jYXRlZExvYWRCYWxhbmNlck5hbWUucmVwbGFjZSgvLSskLywgXCJcIik7XG5cbiAgICB0aGlzLmxvYWRCYWxhbmNlciA9IG5ldyBBcHBsaWNhdGlvbkxvYWRCYWxhbmNlcihcbiAgICAgIHRoaXMsXG4gICAgICBgJHtwcm9wcy5jbHVzdGVyTmFtZX1Mb2FkQmFsYW5jZXJgLFxuICAgICAge1xuICAgICAgICB2cGM6IHRoaXMuY2x1c3Rlci52cGMsXG4gICAgICAgIGludGVybmV0RmFjaW5nOiB0cnVlLFxuICAgICAgICBsb2FkQmFsYW5jZXJOYW1lOiB0cnVuY2F0ZWRMb2FkQmFsYW5jZXJOYW1lLFxuICAgICAgICB2cGNTdWJuZXRzOiB7XG4gICAgICAgICAgc3VibmV0VHlwZTogU3VibmV0VHlwZS5QVUJMSUNcbiAgICAgICAgfVxuICAgICAgfVxuICAgICk7XG5cbiAgICBuZXcgQ2ZuT3V0cHV0KHRoaXMsIGAke3Byb3BzLmNsdXN0ZXJOYW1lfUxvYWRCYWxhbmNlckRuc05hbWVgLCB7XG4gICAgICBrZXk6IGAke3Byb3BzLmNsdXN0ZXJOYW1lfUxvYWRCYWxhbmNlckRuc05hbWVgLFxuICAgICAgZXhwb3J0TmFtZTogYCR7cHJvcHMuY2x1c3Rlck5hbWV9TG9hZEJhbGFuY2VyRG5zTmFtZWAsXG4gICAgICB2YWx1ZTogdGhpcy5sb2FkQmFsYW5jZXIubG9hZEJhbGFuY2VyRG5zTmFtZVxuICAgIH0pO1xuXG4gICAgLy8gRXhwb3J0IGxvYWQgYmFsYW5jZXIgVVJMIGZvciBtb25pdG9yaW5nXG4gICAgbmV3IENmbk91dHB1dCh0aGlzLCBgJHtwcm9wcy5jbHVzdGVyTmFtZX1Mb2FkQmFsYW5jZXJVcmxgLCB7XG4gICAgICBrZXk6IFwiTG9hZEJhbGFuY2VyVXJsXCIsXG4gICAgICBleHBvcnROYW1lOiBgJHtwcm9wcy5jbHVzdGVyTmFtZX1Mb2FkQmFsYW5jZXJVcmxgLFxuICAgICAgdmFsdWU6IGBodHRwOi8vJHt0aGlzLmxvYWRCYWxhbmNlci5sb2FkQmFsYW5jZXJEbnNOYW1lfWAsXG4gICAgICBkZXNjcmlwdGlvbjogYExvYWQgQmFsYW5jZXIgVVJMIGZvciAke3Byb3BzLmNsdXN0ZXJOYW1lfWBcbiAgICB9KTtcbiAgfVxuXG4gIGFkZExvYWRCYWxhbmNlckxpc3RlbmVyKHByb3BzOiBGYXJnYXRlQ2x1c3RlclByb3BzKSB7XG4gICAgaWYgKHRoaXMuY2VydGlmaWNhdGUpIHtcbiAgICAgIHRoaXMubG9hZEJhbGFuY2VyTGlzdGVuZXIgPSB0aGlzLmxvYWRCYWxhbmNlci5hZGRMaXN0ZW5lcihcbiAgICAgICAgYCR7cHJvcHMuc2VydmljZU5hbWV9TGlzdGVuZXJgLFxuICAgICAgICB7XG4gICAgICAgICAgcG9ydDogcHJvcHMucHJvdG9jb2wgPT0gUHJvdG9jb2wuSFRUUCA/IDgwIDogNDQzLFxuICAgICAgICAgIGNlcnRpZmljYXRlczogW3RoaXMuY2VydGlmaWNhdGVdXG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMubG9hZEJhbGFuY2VyTGlzdGVuZXIgPSB0aGlzLmxvYWRCYWxhbmNlci5hZGRMaXN0ZW5lcihcbiAgICAgICAgYCR7cHJvcHMuc2VydmljZU5hbWV9TGlzdGVuZXJgLFxuICAgICAgICB7XG4gICAgICAgICAgcG9ydDogcHJvcHMucHJvdG9jb2wgPT0gUHJvdG9jb2wuSFRUUCA/IDgwIDogNDQzXG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgYWRkSG9zdGVkWm9uZShwcm9wczogRmFyZ2F0ZUNsdXN0ZXJQcm9wcykge1xuICAgIGlmICghcHJvcHMuZG9tYWluQ29uZmlnKSByZXR1cm47XG5cbiAgICBpZiAoIXByb3BzLmRvbWFpbkNvbmZpZy5ob3N0ZWRab25lKSB7XG4gICAgICAvLyBDcmVhdGUgYSBuZXcgaG9zdGVkIHpvbmUgaWYgb25lIGlzIG5vdCBwcm92aWRlZFxuICAgICAgY29uc3QgaG9zdGVkWm9uZSA9IG5ldyBGamFsbEhvc3RlZFpvbmUoXG4gICAgICAgIHRoaXMsXG4gICAgICAgIGAke3Byb3BzLnNlcnZpY2VOYW1lfUhvc3RlZFpvbmVgLFxuICAgICAgICB7XG4gICAgICAgICAgem9uZU5hbWU6IHByb3BzLmRvbWFpbkNvbmZpZy5kb21haW5OYW1lXG4gICAgICAgIH1cbiAgICAgICk7XG5cbiAgICAgIHRoaXMuaG9zdGVkWm9uZSA9IGhvc3RlZFpvbmUuZ2V0SW50ZXJuYWxIb3N0ZWRab25lKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIE90aGVyd2lzZSB1c2UgdGhlIHByb3ZpZGVkIGhvc3RlZCB6b25lXG4gICAgICB0aGlzLmhvc3RlZFpvbmUgPSBwcm9wcy5kb21haW5Db25maWcuaG9zdGVkWm9uZS5nZXRJbnRlcm5hbEhvc3RlZFpvbmUoKTtcbiAgICB9XG5cbiAgICBpZiAoIXByb3BzLmRvbWFpbkNvbmZpZy5jZXJ0aWZpY2F0ZSkge1xuICAgICAgLy8gSWYgbm8gY2VydGlmaWNhdGUgaXMgcHJvdmlkZWQgLSBjcmVhdGUgYSBuZXcgb25lXG4gICAgICB0aGlzLmNlcnRpZmljYXRlID0gbmV3IENlcnRpZmljYXRlKFxuICAgICAgICB0aGlzLFxuICAgICAgICBgJHtwcm9wcy5zZXJ2aWNlTmFtZX1DZXJ0aWZpY2F0ZWAsXG4gICAgICAgIHtcbiAgICAgICAgICBkb21haW5OYW1lOiBwcm9wcy5kb21haW5Db25maWcuZG9tYWluTmFtZSxcbiAgICAgICAgICB2YWxpZGF0aW9uOiBDZXJ0aWZpY2F0ZVZhbGlkYXRpb24uZnJvbURucyh0aGlzLmhvc3RlZFpvbmUpXG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gQ2hlY2sgaWYgdGhpcyBpcyBhIG11bHRpLXJlZ2lvbi93ZWlnaHRlZC9nZW8gcm91dGluZyBjb25maWd1cmF0aW9uXG4gICAgY29uc3QgbGF0ZW5jeUNvbmZpZyA9IHByb3BzLmRvbWFpbkNvbmZpZyBhcyBMYXRlbmN5RG9tYWluQ29uZmlnO1xuICAgIGNvbnN0IHdlaWdodGVkQ29uZmlnID0gcHJvcHMuZG9tYWluQ29uZmlnIGFzIFdlaWdodGVkRG9tYWluQ29uZmlnO1xuICAgIGNvbnN0IGdlb0NvbmZpZyA9IHByb3BzLmRvbWFpbkNvbmZpZyBhcyBHZW9Mb2NhdGlvbkRvbWFpbkNvbmZpZztcblxuICAgIGNvbnN0IGhhc1JvdXRpbmdQb2xpY3k6IGJvb2xlYW4gPVxuICAgICAgISFsYXRlbmN5Q29uZmlnPy5yZWdpb24gfHxcbiAgICAgIHdlaWdodGVkQ29uZmlnPy53ZWlnaHQgIT09IHVuZGVmaW5lZCB8fFxuICAgICAgISFnZW9Db25maWc/Lmdlb0xvY2F0aW9uO1xuXG4gICAgLy8gR2VuZXJhdGUgc2V0SWRlbnRpZmllciBpZiBub3QgcHJvdmlkZWQgYW5kIHVzaW5nIHJvdXRpbmcgcG9saWNpZXNcbiAgICAvLyBBV1MgcmVxdWlyZXMgc2V0SWRlbnRpZmllciBmb3IgYWxsIHJvdXRpbmcgcG9saWNpZXMgKGxhdGVuY3ksIHdlaWdodGVkLCBnZW8sIGZhaWxvdmVyLCBtdWx0aXZhbHVlKVxuICAgIGxldCBzZXRJZGVudGlmaWVyID0gcHJvcHMuZG9tYWluQ29uZmlnLnNldElkZW50aWZpZXI7XG4gICAgaWYgKGhhc1JvdXRpbmdQb2xpY3kgJiYgIXNldElkZW50aWZpZXIpIHtcbiAgICAgIGlmIChsYXRlbmN5Q29uZmlnPy5yZWdpb24pIHtcbiAgICAgICAgc2V0SWRlbnRpZmllciA9IGAke3Byb3BzLnNlcnZpY2VOYW1lfS0ke2xhdGVuY3lDb25maWcucmVnaW9ufWA7XG4gICAgICB9IGVsc2UgaWYgKHdlaWdodGVkQ29uZmlnPy53ZWlnaHQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBzZXRJZGVudGlmaWVyID0gYCR7cHJvcHMuc2VydmljZU5hbWV9LXdlaWdodC0ke3dlaWdodGVkQ29uZmlnLndlaWdodH1gO1xuICAgICAgfSBlbHNlIGlmIChnZW9Db25maWc/Lmdlb0xvY2F0aW9uKSB7XG4gICAgICAgIHNldElkZW50aWZpZXIgPSBgJHtwcm9wcy5zZXJ2aWNlTmFtZX0tZ2VvYDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBBbHdheXMgY3JlYXRlIGEgbmV3IEFSZWNvcmQgZm9yIHRoaXMgZG9tYWluIGFuZCBhdHRhY2ggaXQgdG8gdGhlIGxvYWQgYmFsYW5jZXJcbiAgICB0aGlzLmFSZWNvcmQgPSBuZXcgQVJlY29yZChcbiAgICAgIHRoaXMsXG4gICAgICBgJHtwcm9wcy5zZXJ2aWNlTmFtZX0uJHtwcm9wcy5jbHVzdGVyTmFtZX0uJHtwcm9wcy5kb21haW5Db25maWcuZG9tYWluTmFtZX1BUmVjb3JkYCxcbiAgICAgIHtcbiAgICAgICAgcmVjb3JkTmFtZTogcHJvcHMuZG9tYWluQ29uZmlnLmRvbWFpbk5hbWUsXG4gICAgICAgIHpvbmU6IHRoaXMuaG9zdGVkWm9uZSxcbiAgICAgICAgdGFyZ2V0OiBSZWNvcmRUYXJnZXQuZnJvbUFsaWFzKFxuICAgICAgICAgIG5ldyBMb2FkQmFsYW5jZXJUYXJnZXQodGhpcy5sb2FkQmFsYW5jZXIsIHtcbiAgICAgICAgICAgIGV2YWx1YXRlVGFyZ2V0SGVhbHRoOiBoYXNSb3V0aW5nUG9saWN5XG4gICAgICAgICAgfSlcbiAgICAgICAgKSxcbiAgICAgICAgcmVnaW9uOiBsYXRlbmN5Q29uZmlnPy5yZWdpb24sXG4gICAgICAgIHdlaWdodDogd2VpZ2h0ZWRDb25maWc/LndlaWdodCxcbiAgICAgICAgZ2VvTG9jYXRpb246IGdlb0NvbmZpZz8uZ2VvTG9jYXRpb24sXG4gICAgICAgIC8vIFNldCBpZGVudGlmaWVyIGlzIHJlcXVpcmVkIGZvciByb3V0aW5nIHBvbGljaWVzIChsYXRlbmN5LCB3ZWlnaHRlZCwgZ2VvLCBmYWlsb3ZlciwgbXVsdGl2YWx1ZSlcbiAgICAgICAgc2V0SWRlbnRpZmllcjogc2V0SWRlbnRpZmllclxuICAgICAgfVxuICAgICk7XG4gIH1cblxuICBnZXRJbWFnZShwcm9wczogRmFyZ2F0ZUNsdXN0ZXJQcm9wcyk6IENvbnRhaW5lckltYWdlIHtcbiAgICBpZiAoIXByb3BzLmVjclJlcG9zaXRvcnkpXG4gICAgICByZXR1cm4gQ29udGFpbmVySW1hZ2UuZnJvbVJlZ2lzdHJ5KFwiYW1hem9uL2FtYXpvbi1lY3Mtc2FtcGxlXCIpO1xuICAgIGlmIChwcm9wcy5lY3JSZXBvc2l0b3J5IGluc3RhbmNlb2YgQ29udGFpbmVySW1hZ2UpXG4gICAgICByZXR1cm4gcHJvcHMuZWNyUmVwb3NpdG9yeTtcbiAgICBpZiAocHJvcHMuZWNyUmVwb3NpdG9yeSBpbnN0YW5jZW9mIFJlcG9zaXRvcnkpIHtcbiAgICAgIHJldHVybiBDb250YWluZXJJbWFnZS5mcm9tRWNyUmVwb3NpdG9yeShwcm9wcy5lY3JSZXBvc2l0b3J5LCBcImxhdGVzdFwiKTtcbiAgICB9XG4gICAgcmV0dXJuIENvbnRhaW5lckltYWdlLmZyb21SZWdpc3RyeShcImFtYXpvbi9hbWF6b24tZWNzLXNhbXBsZVwiKTtcbiAgfVxuXG4gIHN0YXRpYyBidWlsZChcbiAgICBpZDogc3RyaW5nLFxuICAgIHByb3BzOiBGYXJnYXRlQ2x1c3RlclByb3BzXG4gICk6IChzYjogU3RhY2tCdWlsZGVyKSA9PiBDb25zdHJ1Y3Qge1xuICAgIHJldHVybiAoc2I6IFN0YWNrQnVpbGRlcikgPT4ge1xuICAgICAgY29uc3QgbmV3UHJvcHM6IEZhcmdhdGVDbHVzdGVyUHJvcHMgPSB7XG4gICAgICAgIC4uLnByb3BzLFxuICAgICAgICAuLi57XG4gICAgICAgICAgdnBjOiAoc2IuZ2V0TmV0d29yaygpIGFzIElWcGMpIHx8IHByb3BzLnZwY1xuICAgICAgICB9XG4gICAgICB9O1xuICAgICAgcmV0dXJuIG5ldyB0aGlzKHNiLmdldFN0YWNrKCksIGlkLCBuZXdQcm9wcyk7XG4gICAgfTtcbiAgfVxufVxuIl19
|
|
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=
|