1 | ;
|
2 | var _a, _b;
|
3 | Object.defineProperty(exports, "__esModule", { value: true });
|
4 | exports.PropagatedTagSource = exports.DeploymentControllerType = exports.LaunchType = exports.BaseService = exports.ListenerConfig = void 0;
|
5 | const jsiiDeprecationWarnings = require("../../.warnings.jsii.js");
|
6 | const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
|
7 | const appscaling = require("@aws-cdk/aws-applicationautoscaling");
|
8 | const cloudwatch = require("@aws-cdk/aws-cloudwatch");
|
9 | const ec2 = require("@aws-cdk/aws-ec2");
|
10 | const elbv2 = require("@aws-cdk/aws-elasticloadbalancingv2");
|
11 | const iam = require("@aws-cdk/aws-iam");
|
12 | const cloudmap = require("@aws-cdk/aws-servicediscovery");
|
13 | const core_1 = require("@aws-cdk/core");
|
14 | const task_definition_1 = require("../base/task-definition");
|
15 | const cluster_1 = require("../cluster");
|
16 | const ecs_generated_1 = require("../ecs.generated");
|
17 | const scalable_task_count_1 = require("./scalable-task-count");
|
18 | /**
|
19 | * Base class for configuring listener when registering targets.
|
20 | */
|
21 | class ListenerConfig {
|
22 | /**
|
23 | * Create a config for adding target group to ALB listener.
|
24 | */
|
25 | static applicationListener(listener, props) {
|
26 | return new ApplicationListenerConfig(listener, props);
|
27 | }
|
28 | /**
|
29 | * Create a config for adding target group to NLB listener.
|
30 | */
|
31 | static networkListener(listener, props) {
|
32 | return new NetworkListenerConfig(listener, props);
|
33 | }
|
34 | }
|
35 | exports.ListenerConfig = ListenerConfig;
|
36 | _a = JSII_RTTI_SYMBOL_1;
|
37 | ListenerConfig[_a] = { fqn: "@aws-cdk/aws-ecs.ListenerConfig", version: "1.156.1" };
|
38 | /**
|
39 | * Class for configuring application load balancer listener when registering targets.
|
40 | */
|
41 | class ApplicationListenerConfig extends ListenerConfig {
|
42 | constructor(listener, props) {
|
43 | super();
|
44 | this.listener = listener;
|
45 | this.props = props;
|
46 | }
|
47 | /**
|
48 | * Create and attach a target group to listener.
|
49 | */
|
50 | addTargets(id, target, service) {
|
51 | var _c;
|
52 | const props = this.props || {};
|
53 | const protocol = props.protocol;
|
54 | const port = (_c = props.port) !== null && _c !== void 0 ? _c : (protocol === elbv2.ApplicationProtocol.HTTPS ? 443 : 80);
|
55 | this.listener.addTargets(id, {
|
56 | ...props,
|
57 | targets: [
|
58 | service.loadBalancerTarget({
|
59 | ...target,
|
60 | }),
|
61 | ],
|
62 | port,
|
63 | });
|
64 | }
|
65 | }
|
66 | /**
|
67 | * Class for configuring network load balancer listener when registering targets.
|
68 | */
|
69 | class NetworkListenerConfig extends ListenerConfig {
|
70 | constructor(listener, props) {
|
71 | super();
|
72 | this.listener = listener;
|
73 | this.props = props;
|
74 | }
|
75 | /**
|
76 | * Create and attach a target group to listener.
|
77 | */
|
78 | addTargets(id, target, service) {
|
79 | var _c, _d;
|
80 | const port = (_d = (_c = this.props) === null || _c === void 0 ? void 0 : _c.port) !== null && _d !== void 0 ? _d : 80;
|
81 | this.listener.addTargets(id, {
|
82 | ...this.props,
|
83 | targets: [
|
84 | service.loadBalancerTarget({
|
85 | ...target,
|
86 | }),
|
87 | ],
|
88 | port,
|
89 | });
|
90 | }
|
91 | }
|
92 | /**
|
93 | * The base class for Ec2Service and FargateService services.
|
94 | */
|
95 | class BaseService extends core_1.Resource {
|
96 | /**
|
97 | * Constructs a new instance of the BaseService class.
|
98 | */
|
99 | constructor(scope, id, props, additionalProps, taskDefinition) {
|
100 | var _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
101 | super(scope, id, {
|
102 | physicalName: props.serviceName,
|
103 | });
|
104 | /**
|
105 | * The security groups which manage the allowed network traffic for the service.
|
106 | */
|
107 | this.connections = new ec2.Connections();
|
108 | /**
|
109 | * A list of Elastic Load Balancing load balancer objects, containing the load balancer name, the container
|
110 | * name (as it appears in a container definition), and the container port to access from the load balancer.
|
111 | */
|
112 | this.loadBalancers = new Array();
|
113 | /**
|
114 | * The details of the service discovery registries to assign to this service.
|
115 | * For more information, see Service Discovery.
|
116 | */
|
117 | this.serviceRegistries = new Array();
|
118 | try {
|
119 | jsiiDeprecationWarnings._aws_cdk_aws_ecs_BaseServiceProps(props);
|
120 | jsiiDeprecationWarnings._aws_cdk_aws_ecs_TaskDefinition(taskDefinition);
|
121 | }
|
122 | catch (error) {
|
123 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
124 | Error.captureStackTrace(error, this.constructor);
|
125 | }
|
126 | throw error;
|
127 | }
|
128 | if (props.propagateTags && props.propagateTaskTagsFrom) {
|
129 | throw new Error('You can only specify either propagateTags or propagateTaskTagsFrom. Alternatively, you can leave both blank');
|
130 | }
|
131 | this.taskDefinition = taskDefinition;
|
132 | // launchType will set to undefined if using external DeploymentController or capacityProviderStrategies
|
133 | const launchType = ((_c = props.deploymentController) === null || _c === void 0 ? void 0 : _c.type) === DeploymentControllerType.EXTERNAL ||
|
134 | props.capacityProviderStrategies !== undefined ?
|
135 | undefined : props.launchType;
|
136 | const propagateTagsFromSource = (_e = (_d = props.propagateTaskTagsFrom) !== null && _d !== void 0 ? _d : props.propagateTags) !== null && _e !== void 0 ? _e : PropagatedTagSource.NONE;
|
137 | this.resource = new ecs_generated_1.CfnService(this, 'Service', {
|
138 | desiredCount: props.desiredCount,
|
139 | serviceName: this.physicalName,
|
140 | loadBalancers: core_1.Lazy.any({ produce: () => this.loadBalancers }, { omitEmptyArray: true }),
|
141 | deploymentConfiguration: {
|
142 | maximumPercent: props.maxHealthyPercent || 200,
|
143 | minimumHealthyPercent: props.minHealthyPercent === undefined ? 50 : props.minHealthyPercent,
|
144 | deploymentCircuitBreaker: props.circuitBreaker ? {
|
145 | enable: true,
|
146 | rollback: (_f = props.circuitBreaker.rollback) !== null && _f !== void 0 ? _f : false,
|
147 | } : undefined,
|
148 | },
|
149 | propagateTags: propagateTagsFromSource === PropagatedTagSource.NONE ? undefined : props.propagateTags,
|
150 | enableEcsManagedTags: (_g = props.enableECSManagedTags) !== null && _g !== void 0 ? _g : false,
|
151 | deploymentController: props.circuitBreaker ? {
|
152 | type: DeploymentControllerType.ECS,
|
153 | } : props.deploymentController,
|
154 | launchType: launchType,
|
155 | enableExecuteCommand: props.enableExecuteCommand,
|
156 | capacityProviderStrategy: props.capacityProviderStrategies,
|
157 | healthCheckGracePeriodSeconds: this.evaluateHealthGracePeriod(props.healthCheckGracePeriod),
|
158 | /* role: never specified, supplanted by Service Linked Role */
|
159 | networkConfiguration: core_1.Lazy.any({ produce: () => this.networkConfiguration }, { omitEmptyArray: true }),
|
160 | serviceRegistries: core_1.Lazy.any({ produce: () => this.serviceRegistries }, { omitEmptyArray: true }),
|
161 | ...additionalProps,
|
162 | });
|
163 | if (((_h = props.deploymentController) === null || _h === void 0 ? void 0 : _h.type) === DeploymentControllerType.EXTERNAL) {
|
164 | core_1.Annotations.of(this).addWarning('taskDefinition and launchType are blanked out when using external deployment controller.');
|
165 | }
|
166 | this.serviceArn = this.getResourceArnAttribute(this.resource.ref, {
|
167 | service: 'ecs',
|
168 | resource: 'service',
|
169 | resourceName: `${props.cluster.clusterName}/${this.physicalName}`,
|
170 | });
|
171 | this.serviceName = this.getResourceNameAttribute(this.resource.attrName);
|
172 | this.cluster = props.cluster;
|
173 | if (props.cloudMapOptions) {
|
174 | this.enableCloudMap(props.cloudMapOptions);
|
175 | }
|
176 | if (props.enableExecuteCommand) {
|
177 | this.enableExecuteCommand();
|
178 | const logging = (_k = (_j = this.cluster.executeCommandConfiguration) === null || _j === void 0 ? void 0 : _j.logging) !== null && _k !== void 0 ? _k : cluster_1.ExecuteCommandLogging.DEFAULT;
|
179 | if ((_l = this.cluster.executeCommandConfiguration) === null || _l === void 0 ? void 0 : _l.kmsKey) {
|
180 | this.enableExecuteCommandEncryption(logging);
|
181 | }
|
182 | if (logging !== cluster_1.ExecuteCommandLogging.NONE) {
|
183 | this.executeCommandLogConfiguration();
|
184 | }
|
185 | }
|
186 | this.node.defaultChild = this.resource;
|
187 | }
|
188 | /**
|
189 | * Import an existing ECS/Fargate Service using the service cluster format.
|
190 | * The format is the "new" format "arn:aws:ecs:region:aws_account_id:service/cluster-name/service-name".
|
191 | * @see https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-account-settings.html#ecs-resource-ids
|
192 | */
|
193 | static fromServiceArnWithCluster(scope, id, serviceArn) {
|
194 | const stack = core_1.Stack.of(scope);
|
195 | const arn = stack.splitArn(serviceArn, core_1.ArnFormat.SLASH_RESOURCE_NAME);
|
196 | const resourceName = arn.resourceName;
|
197 | if (!resourceName) {
|
198 | throw new Error('Missing resource Name from service ARN: ${serviceArn}');
|
199 | }
|
200 | const resourceNameParts = resourceName.split('/');
|
201 | if (resourceNameParts.length !== 2) {
|
202 | throw new Error(`resource name ${resourceName} from service ARN: ${serviceArn} is not using the ARN cluster format`);
|
203 | }
|
204 | const clusterName = resourceNameParts[0];
|
205 | const serviceName = resourceNameParts[1];
|
206 | const clusterArn = core_1.Stack.of(scope).formatArn({
|
207 | partition: arn.partition,
|
208 | region: arn.region,
|
209 | account: arn.account,
|
210 | service: 'ecs',
|
211 | resource: 'cluster',
|
212 | resourceName: clusterName,
|
213 | });
|
214 | const cluster = cluster_1.Cluster.fromClusterArn(scope, `${id}Cluster`, clusterArn);
|
215 | class Import extends core_1.Resource {
|
216 | constructor() {
|
217 | super(...arguments);
|
218 | this.serviceArn = serviceArn;
|
219 | this.serviceName = serviceName;
|
220 | this.cluster = cluster;
|
221 | }
|
222 | }
|
223 | return new Import(scope, id, {
|
224 | environmentFromArn: serviceArn,
|
225 | });
|
226 | }
|
227 | /**
|
228 | * The CloudMap service created for this service, if any.
|
229 | */
|
230 | get cloudMapService() {
|
231 | return this.cloudmapService;
|
232 | }
|
233 | executeCommandLogConfiguration() {
|
234 | var _c, _d;
|
235 | const logConfiguration = (_c = this.cluster.executeCommandConfiguration) === null || _c === void 0 ? void 0 : _c.logConfiguration;
|
236 | this.taskDefinition.addToTaskRolePolicy(new iam.PolicyStatement({
|
237 | actions: [
|
238 | 'logs:DescribeLogGroups',
|
239 | ],
|
240 | resources: ['*'],
|
241 | }));
|
242 | const logGroupArn = (logConfiguration === null || logConfiguration === void 0 ? void 0 : logConfiguration.cloudWatchLogGroup) ? `arn:${this.stack.partition}:logs:${this.env.region}:${this.env.account}:log-group:${logConfiguration.cloudWatchLogGroup.logGroupName}:*` : '*';
|
243 | this.taskDefinition.addToTaskRolePolicy(new iam.PolicyStatement({
|
244 | actions: [
|
245 | 'logs:CreateLogStream',
|
246 | 'logs:DescribeLogStreams',
|
247 | 'logs:PutLogEvents',
|
248 | ],
|
249 | resources: [logGroupArn],
|
250 | }));
|
251 | if ((_d = logConfiguration === null || logConfiguration === void 0 ? void 0 : logConfiguration.s3Bucket) === null || _d === void 0 ? void 0 : _d.bucketName) {
|
252 | this.taskDefinition.addToTaskRolePolicy(new iam.PolicyStatement({
|
253 | actions: [
|
254 | 's3:GetBucketLocation',
|
255 | ],
|
256 | resources: ['*'],
|
257 | }));
|
258 | this.taskDefinition.addToTaskRolePolicy(new iam.PolicyStatement({
|
259 | actions: [
|
260 | 's3:PutObject',
|
261 | ],
|
262 | resources: [`arn:${this.stack.partition}:s3:::${logConfiguration.s3Bucket.bucketName}/*`],
|
263 | }));
|
264 | if (logConfiguration.s3EncryptionEnabled) {
|
265 | this.taskDefinition.addToTaskRolePolicy(new iam.PolicyStatement({
|
266 | actions: [
|
267 | 's3:GetEncryptionConfiguration',
|
268 | ],
|
269 | resources: [`arn:${this.stack.partition}:s3:::${logConfiguration.s3Bucket.bucketName}`],
|
270 | }));
|
271 | }
|
272 | }
|
273 | }
|
274 | enableExecuteCommandEncryption(logging) {
|
275 | var _c, _d, _e, _f, _g, _h, _j, _k;
|
276 | this.taskDefinition.addToTaskRolePolicy(new iam.PolicyStatement({
|
277 | actions: [
|
278 | 'kms:Decrypt',
|
279 | 'kms:GenerateDataKey',
|
280 | ],
|
281 | resources: [`${(_d = (_c = this.cluster.executeCommandConfiguration) === null || _c === void 0 ? void 0 : _c.kmsKey) === null || _d === void 0 ? void 0 : _d.keyArn}`],
|
282 | }));
|
283 | (_f = (_e = this.cluster.executeCommandConfiguration) === null || _e === void 0 ? void 0 : _e.kmsKey) === null || _f === void 0 ? void 0 : _f.addToResourcePolicy(new iam.PolicyStatement({
|
284 | actions: [
|
285 | 'kms:*',
|
286 | ],
|
287 | resources: ['*'],
|
288 | principals: [new iam.ArnPrincipal(`arn:${this.stack.partition}:iam::${this.env.account}:root`)],
|
289 | }));
|
290 | if (logging === cluster_1.ExecuteCommandLogging.DEFAULT || ((_h = (_g = this.cluster.executeCommandConfiguration) === null || _g === void 0 ? void 0 : _g.logConfiguration) === null || _h === void 0 ? void 0 : _h.cloudWatchEncryptionEnabled)) {
|
291 | (_k = (_j = this.cluster.executeCommandConfiguration) === null || _j === void 0 ? void 0 : _j.kmsKey) === null || _k === void 0 ? void 0 : _k.addToResourcePolicy(new iam.PolicyStatement({
|
292 | actions: [
|
293 | 'kms:Encrypt*',
|
294 | 'kms:Decrypt*',
|
295 | 'kms:ReEncrypt*',
|
296 | 'kms:GenerateDataKey*',
|
297 | 'kms:Describe*',
|
298 | ],
|
299 | resources: ['*'],
|
300 | principals: [new iam.ServicePrincipal(`logs.${this.env.region}.amazonaws.com`)],
|
301 | conditions: {
|
302 | ArnLike: { 'kms:EncryptionContext:aws:logs:arn': `arn:${this.stack.partition}:logs:${this.env.region}:${this.env.account}:*` },
|
303 | },
|
304 | }));
|
305 | }
|
306 | }
|
307 | /**
|
308 | * This method is called to attach this service to an Application Load Balancer.
|
309 | *
|
310 | * Don't call this function directly. Instead, call `listener.addTargets()`
|
311 | * to add this service to a load balancer.
|
312 | */
|
313 | attachToApplicationTargetGroup(targetGroup) {
|
314 | return this.defaultLoadBalancerTarget.attachToApplicationTargetGroup(targetGroup);
|
315 | }
|
316 | /**
|
317 | * Registers the service as a target of a Classic Load Balancer (CLB).
|
318 | *
|
319 | * Don't call this. Call `loadBalancer.addTarget()` instead.
|
320 | */
|
321 | attachToClassicLB(loadBalancer) {
|
322 | return this.defaultLoadBalancerTarget.attachToClassicLB(loadBalancer);
|
323 | }
|
324 | /**
|
325 | * Return a load balancing target for a specific container and port.
|
326 | *
|
327 | * Use this function to create a load balancer target if you want to load balance to
|
328 | * another container than the first essential container or the first mapped port on
|
329 | * the container.
|
330 | *
|
331 | * Use the return value of this function where you would normally use a load balancer
|
332 | * target, instead of the `Service` object itself.
|
333 | *
|
334 | * @example
|
335 | *
|
336 | * declare const listener: elbv2.ApplicationListener;
|
337 | * declare const service: ecs.BaseService;
|
338 | * listener.addTargets('ECS', {
|
339 | * port: 80,
|
340 | * targets: [service.loadBalancerTarget({
|
341 | * containerName: 'MyContainer',
|
342 | * containerPort: 1234,
|
343 | * })],
|
344 | * });
|
345 | */
|
346 | loadBalancerTarget(options) {
|
347 | try {
|
348 | jsiiDeprecationWarnings._aws_cdk_aws_ecs_LoadBalancerTargetOptions(options);
|
349 | }
|
350 | catch (error) {
|
351 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
352 | Error.captureStackTrace(error, this.loadBalancerTarget);
|
353 | }
|
354 | throw error;
|
355 | }
|
356 | const self = this;
|
357 | const target = this.taskDefinition._validateTarget(options);
|
358 | const connections = self.connections;
|
359 | return {
|
360 | attachToApplicationTargetGroup(targetGroup) {
|
361 | targetGroup.registerConnectable(self, self.taskDefinition._portRangeFromPortMapping(target.portMapping));
|
362 | return self.attachToELBv2(targetGroup, target.containerName, target.portMapping.containerPort);
|
363 | },
|
364 | attachToNetworkTargetGroup(targetGroup) {
|
365 | return self.attachToELBv2(targetGroup, target.containerName, target.portMapping.containerPort);
|
366 | },
|
367 | connections,
|
368 | attachToClassicLB(loadBalancer) {
|
369 | return self.attachToELB(loadBalancer, target.containerName, target.portMapping.containerPort);
|
370 | },
|
371 | };
|
372 | }
|
373 | /**
|
374 | * Use this function to create all load balancer targets to be registered in this service, add them to
|
375 | * target groups, and attach target groups to listeners accordingly.
|
376 | *
|
377 | * Alternatively, you can use `listener.addTargets()` to create targets and add them to target groups.
|
378 | *
|
379 | * @example
|
380 | *
|
381 | * declare const listener: elbv2.ApplicationListener;
|
382 | * declare const service: ecs.BaseService;
|
383 | * service.registerLoadBalancerTargets(
|
384 | * {
|
385 | * containerName: 'web',
|
386 | * containerPort: 80,
|
387 | * newTargetGroupId: 'ECS',
|
388 | * listener: ecs.ListenerConfig.applicationListener(listener, {
|
389 | * protocol: elbv2.ApplicationProtocol.HTTPS
|
390 | * }),
|
391 | * },
|
392 | * )
|
393 | */
|
394 | registerLoadBalancerTargets(...targets) {
|
395 | try {
|
396 | jsiiDeprecationWarnings._aws_cdk_aws_ecs_EcsTarget(targets);
|
397 | }
|
398 | catch (error) {
|
399 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
400 | Error.captureStackTrace(error, this.registerLoadBalancerTargets);
|
401 | }
|
402 | throw error;
|
403 | }
|
404 | for (const target of targets) {
|
405 | target.listener.addTargets(target.newTargetGroupId, {
|
406 | containerName: target.containerName,
|
407 | containerPort: target.containerPort,
|
408 | protocol: target.protocol,
|
409 | }, this);
|
410 | }
|
411 | }
|
412 | /**
|
413 | * This method is called to attach this service to a Network Load Balancer.
|
414 | *
|
415 | * Don't call this function directly. Instead, call `listener.addTargets()`
|
416 | * to add this service to a load balancer.
|
417 | */
|
418 | attachToNetworkTargetGroup(targetGroup) {
|
419 | return this.defaultLoadBalancerTarget.attachToNetworkTargetGroup(targetGroup);
|
420 | }
|
421 | /**
|
422 | * An attribute representing the minimum and maximum task count for an AutoScalingGroup.
|
423 | */
|
424 | autoScaleTaskCount(props) {
|
425 | if (this.scalableTaskCount) {
|
426 | throw new Error('AutoScaling of task count already enabled for this service');
|
427 | }
|
428 | return this.scalableTaskCount = new scalable_task_count_1.ScalableTaskCount(this, 'TaskCount', {
|
429 | serviceNamespace: appscaling.ServiceNamespace.ECS,
|
430 | resourceId: `service/${this.cluster.clusterName}/${this.serviceName}`,
|
431 | dimension: 'ecs:service:DesiredCount',
|
432 | role: this.makeAutoScalingRole(),
|
433 | ...props,
|
434 | });
|
435 | }
|
436 | /**
|
437 | * Enable CloudMap service discovery for the service
|
438 | *
|
439 | * @returns The created CloudMap service
|
440 | */
|
441 | enableCloudMap(options) {
|
442 | var _c;
|
443 | try {
|
444 | jsiiDeprecationWarnings._aws_cdk_aws_ecs_CloudMapOptions(options);
|
445 | }
|
446 | catch (error) {
|
447 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
448 | Error.captureStackTrace(error, this.enableCloudMap);
|
449 | }
|
450 | throw error;
|
451 | }
|
452 | const sdNamespace = (_c = options.cloudMapNamespace) !== null && _c !== void 0 ? _c : this.cluster.defaultCloudMapNamespace;
|
453 | if (sdNamespace === undefined) {
|
454 | throw new Error('Cannot enable service discovery if a Cloudmap Namespace has not been created in the cluster.');
|
455 | }
|
456 | // Determine DNS type based on network mode
|
457 | const networkMode = this.taskDefinition.networkMode;
|
458 | if (networkMode === task_definition_1.NetworkMode.NONE) {
|
459 | throw new Error('Cannot use a service discovery if NetworkMode is None. Use Bridge, Host or AwsVpc instead.');
|
460 | }
|
461 | // Bridge or host network mode requires SRV records
|
462 | let dnsRecordType = options.dnsRecordType;
|
463 | if (networkMode === task_definition_1.NetworkMode.BRIDGE || networkMode === task_definition_1.NetworkMode.HOST) {
|
464 | if (dnsRecordType === undefined) {
|
465 | dnsRecordType = cloudmap.DnsRecordType.SRV;
|
466 | }
|
467 | if (dnsRecordType !== cloudmap.DnsRecordType.SRV) {
|
468 | throw new Error('SRV records must be used when network mode is Bridge or Host.');
|
469 | }
|
470 | }
|
471 | // Default DNS record type for AwsVpc network mode is A Records
|
472 | if (networkMode === task_definition_1.NetworkMode.AWS_VPC) {
|
473 | if (dnsRecordType === undefined) {
|
474 | dnsRecordType = cloudmap.DnsRecordType.A;
|
475 | }
|
476 | }
|
477 | const { containerName, containerPort } = determineContainerNameAndPort({
|
478 | taskDefinition: this.taskDefinition,
|
479 | dnsRecordType: dnsRecordType,
|
480 | container: options.container,
|
481 | containerPort: options.containerPort,
|
482 | });
|
483 | const cloudmapService = new cloudmap.Service(this, 'CloudmapService', {
|
484 | namespace: sdNamespace,
|
485 | name: options.name,
|
486 | dnsRecordType: dnsRecordType,
|
487 | customHealthCheck: { failureThreshold: options.failureThreshold || 1 },
|
488 | dnsTtl: options.dnsTtl,
|
489 | });
|
490 | const serviceArn = cloudmapService.serviceArn;
|
491 | // add Cloudmap service to the ECS Service's serviceRegistry
|
492 | this.addServiceRegistry({
|
493 | arn: serviceArn,
|
494 | containerName,
|
495 | containerPort,
|
496 | });
|
497 | this.cloudmapService = cloudmapService;
|
498 | return cloudmapService;
|
499 | }
|
500 | /**
|
501 | * Associates this service with a CloudMap service
|
502 | */
|
503 | associateCloudMapService(options) {
|
504 | try {
|
505 | jsiiDeprecationWarnings._aws_cdk_aws_ecs_AssociateCloudMapServiceOptions(options);
|
506 | }
|
507 | catch (error) {
|
508 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
509 | Error.captureStackTrace(error, this.associateCloudMapService);
|
510 | }
|
511 | throw error;
|
512 | }
|
513 | const service = options.service;
|
514 | const { containerName, containerPort } = determineContainerNameAndPort({
|
515 | taskDefinition: this.taskDefinition,
|
516 | dnsRecordType: service.dnsRecordType,
|
517 | container: options.container,
|
518 | containerPort: options.containerPort,
|
519 | });
|
520 | // add Cloudmap service to the ECS Service's serviceRegistry
|
521 | this.addServiceRegistry({
|
522 | arn: service.serviceArn,
|
523 | containerName,
|
524 | containerPort,
|
525 | });
|
526 | }
|
527 | /**
|
528 | * This method returns the specified CloudWatch metric name for this service.
|
529 | */
|
530 | metric(metricName, props) {
|
531 | return new cloudwatch.Metric({
|
532 | namespace: 'AWS/ECS',
|
533 | metricName,
|
534 | dimensionsMap: { ClusterName: this.cluster.clusterName, ServiceName: this.serviceName },
|
535 | ...props,
|
536 | }).attachTo(this);
|
537 | }
|
538 | /**
|
539 | * This method returns the CloudWatch metric for this service's memory utilization.
|
540 | *
|
541 | * @default average over 5 minutes
|
542 | */
|
543 | metricMemoryUtilization(props) {
|
544 | return this.metric('MemoryUtilization', props);
|
545 | }
|
546 | /**
|
547 | * This method returns the CloudWatch metric for this service's CPU utilization.
|
548 | *
|
549 | * @default average over 5 minutes
|
550 | */
|
551 | metricCpuUtilization(props) {
|
552 | return this.metric('CPUUtilization', props);
|
553 | }
|
554 | /**
|
555 | * This method is called to create a networkConfiguration.
|
556 | * @deprecated use configureAwsVpcNetworkingWithSecurityGroups instead.
|
557 | */
|
558 | // eslint-disable-next-line max-len
|
559 | configureAwsVpcNetworking(vpc, assignPublicIp, vpcSubnets, securityGroup) {
|
560 | try {
|
561 | jsiiDeprecationWarnings.print("@aws-cdk/aws-ecs.BaseService#configureAwsVpcNetworking", "use configureAwsVpcNetworkingWithSecurityGroups instead.");
|
562 | }
|
563 | catch (error) {
|
564 | if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
|
565 | Error.captureStackTrace(error, this.configureAwsVpcNetworking);
|
566 | }
|
567 | throw error;
|
568 | }
|
569 | if (vpcSubnets === undefined) {
|
570 | vpcSubnets = assignPublicIp ? { subnetType: ec2.SubnetType.PUBLIC } : {};
|
571 | }
|
572 | if (securityGroup === undefined) {
|
573 | securityGroup = new ec2.SecurityGroup(this, 'SecurityGroup', { vpc });
|
574 | }
|
575 | this.connections.addSecurityGroup(securityGroup);
|
576 | this.networkConfiguration = {
|
577 | awsvpcConfiguration: {
|
578 | assignPublicIp: assignPublicIp ? 'ENABLED' : 'DISABLED',
|
579 | subnets: vpc.selectSubnets(vpcSubnets).subnetIds,
|
580 | securityGroups: core_1.Lazy.list({ produce: () => [securityGroup.securityGroupId] }),
|
581 | },
|
582 | };
|
583 | }
|
584 | /**
|
585 | * This method is called to create a networkConfiguration.
|
586 | */
|
587 | // eslint-disable-next-line max-len
|
588 | configureAwsVpcNetworkingWithSecurityGroups(vpc, assignPublicIp, vpcSubnets, securityGroups) {
|
589 | if (vpcSubnets === undefined) {
|
590 | vpcSubnets = assignPublicIp ? { subnetType: ec2.SubnetType.PUBLIC } : {};
|
591 | }
|
592 | if (securityGroups === undefined || securityGroups.length === 0) {
|
593 | securityGroups = [new ec2.SecurityGroup(this, 'SecurityGroup', { vpc })];
|
594 | }
|
595 | securityGroups.forEach((sg) => { this.connections.addSecurityGroup(sg); }, this);
|
596 | this.networkConfiguration = {
|
597 | awsvpcConfiguration: {
|
598 | assignPublicIp: assignPublicIp ? 'ENABLED' : 'DISABLED',
|
599 | subnets: vpc.selectSubnets(vpcSubnets).subnetIds,
|
600 | securityGroups: securityGroups.map((sg) => sg.securityGroupId),
|
601 | },
|
602 | };
|
603 | }
|
604 | renderServiceRegistry(registry) {
|
605 | return {
|
606 | registryArn: registry.arn,
|
607 | containerName: registry.containerName,
|
608 | containerPort: registry.containerPort,
|
609 | };
|
610 | }
|
611 | /**
|
612 | * Shared logic for attaching to an ELB
|
613 | */
|
614 | attachToELB(loadBalancer, containerName, containerPort) {
|
615 | if (this.taskDefinition.networkMode === task_definition_1.NetworkMode.AWS_VPC) {
|
616 | throw new Error('Cannot use a Classic Load Balancer if NetworkMode is AwsVpc. Use Host or Bridge instead.');
|
617 | }
|
618 | if (this.taskDefinition.networkMode === task_definition_1.NetworkMode.NONE) {
|
619 | throw new Error('Cannot use a Classic Load Balancer if NetworkMode is None. Use Host or Bridge instead.');
|
620 | }
|
621 | this.loadBalancers.push({
|
622 | loadBalancerName: loadBalancer.loadBalancerName,
|
623 | containerName,
|
624 | containerPort,
|
625 | });
|
626 | }
|
627 | /**
|
628 | * Shared logic for attaching to an ELBv2
|
629 | */
|
630 | attachToELBv2(targetGroup, containerName, containerPort) {
|
631 | if (this.taskDefinition.networkMode === task_definition_1.NetworkMode.NONE) {
|
632 | throw new Error('Cannot use a load balancer if NetworkMode is None. Use Bridge, Host or AwsVpc instead.');
|
633 | }
|
634 | this.loadBalancers.push({
|
635 | targetGroupArn: targetGroup.targetGroupArn,
|
636 | containerName,
|
637 | containerPort,
|
638 | });
|
639 | // Service creation can only happen after the load balancer has
|
640 | // been associated with our target group(s), so add ordering dependency.
|
641 | this.resource.node.addDependency(targetGroup.loadBalancerAttached);
|
642 | const targetType = this.taskDefinition.networkMode === task_definition_1.NetworkMode.AWS_VPC ? elbv2.TargetType.IP : elbv2.TargetType.INSTANCE;
|
643 | return { targetType };
|
644 | }
|
645 | get defaultLoadBalancerTarget() {
|
646 | return this.loadBalancerTarget({
|
647 | containerName: this.taskDefinition.defaultContainer.containerName,
|
648 | });
|
649 | }
|
650 | /**
|
651 | * Generate the role that will be used for autoscaling this service
|
652 | */
|
653 | makeAutoScalingRole() {
|
654 | // Use a Service Linked Role.
|
655 | return iam.Role.fromRoleArn(this, 'ScalingRole', core_1.Stack.of(this).formatArn({
|
656 | region: '',
|
657 | service: 'iam',
|
658 | resource: 'role/aws-service-role/ecs.application-autoscaling.amazonaws.com',
|
659 | resourceName: 'AWSServiceRoleForApplicationAutoScaling_ECSService',
|
660 | }));
|
661 | }
|
662 | /**
|
663 | * Associate Service Discovery (Cloud Map) service
|
664 | */
|
665 | addServiceRegistry(registry) {
|
666 | if (this.serviceRegistries.length >= 1) {
|
667 | throw new Error('Cannot associate with the given service discovery registry. ECS supports at most one service registry per service.');
|
668 | }
|
669 | const sr = this.renderServiceRegistry(registry);
|
670 | this.serviceRegistries.push(sr);
|
671 | }
|
672 | /**
|
673 | * Return the default grace period when load balancers are configured and
|
674 | * healthCheckGracePeriod is not already set
|
675 | */
|
676 | evaluateHealthGracePeriod(providedHealthCheckGracePeriod) {
|
677 | return core_1.Lazy.any({
|
678 | produce: () => { var _c; return (_c = providedHealthCheckGracePeriod === null || providedHealthCheckGracePeriod === void 0 ? void 0 : providedHealthCheckGracePeriod.toSeconds()) !== null && _c !== void 0 ? _c : (this.loadBalancers.length > 0 ? 60 : undefined); },
|
679 | });
|
680 | }
|
681 | enableExecuteCommand() {
|
682 | this.taskDefinition.addToTaskRolePolicy(new iam.PolicyStatement({
|
683 | actions: [
|
684 | 'ssmmessages:CreateControlChannel',
|
685 | 'ssmmessages:CreateDataChannel',
|
686 | 'ssmmessages:OpenControlChannel',
|
687 | 'ssmmessages:OpenDataChannel',
|
688 | ],
|
689 | resources: ['*'],
|
690 | }));
|
691 | }
|
692 | }
|
693 | exports.BaseService = BaseService;
|
694 | _b = JSII_RTTI_SYMBOL_1;
|
695 | BaseService[_b] = { fqn: "@aws-cdk/aws-ecs.BaseService", version: "1.156.1" };
|
696 | /**
|
697 | * The launch type of an ECS service
|
698 | */
|
699 | var LaunchType;
|
700 | (function (LaunchType) {
|
701 | /**
|
702 | * The service will be launched using the EC2 launch type
|
703 | */
|
704 | LaunchType["EC2"] = "EC2";
|
705 | /**
|
706 | * The service will be launched using the FARGATE launch type
|
707 | */
|
708 | LaunchType["FARGATE"] = "FARGATE";
|
709 | /**
|
710 | * The service will be launched using the EXTERNAL launch type
|
711 | */
|
712 | LaunchType["EXTERNAL"] = "EXTERNAL";
|
713 | })(LaunchType = exports.LaunchType || (exports.LaunchType = {}));
|
714 | /**
|
715 | * The deployment controller type to use for the service.
|
716 | */
|
717 | var DeploymentControllerType;
|
718 | (function (DeploymentControllerType) {
|
719 | /**
|
720 | * The rolling update (ECS) deployment type involves replacing the current
|
721 | * running version of the container with the latest version.
|
722 | */
|
723 | DeploymentControllerType["ECS"] = "ECS";
|
724 | /**
|
725 | * The blue/green (CODE_DEPLOY) deployment type uses the blue/green deployment model powered by AWS CodeDeploy
|
726 | */
|
727 | DeploymentControllerType["CODE_DEPLOY"] = "CODE_DEPLOY";
|
728 | /**
|
729 | * The external (EXTERNAL) deployment type enables you to use any third-party deployment controller
|
730 | */
|
731 | DeploymentControllerType["EXTERNAL"] = "EXTERNAL";
|
732 | })(DeploymentControllerType = exports.DeploymentControllerType || (exports.DeploymentControllerType = {}));
|
733 | /**
|
734 | * Propagate tags from either service or task definition
|
735 | */
|
736 | var PropagatedTagSource;
|
737 | (function (PropagatedTagSource) {
|
738 | /**
|
739 | * Propagate tags from service
|
740 | */
|
741 | PropagatedTagSource["SERVICE"] = "SERVICE";
|
742 | /**
|
743 | * Propagate tags from task definition
|
744 | */
|
745 | PropagatedTagSource["TASK_DEFINITION"] = "TASK_DEFINITION";
|
746 | /**
|
747 | * Do not propagate
|
748 | */
|
749 | PropagatedTagSource["NONE"] = "NONE";
|
750 | })(PropagatedTagSource = exports.PropagatedTagSource || (exports.PropagatedTagSource = {}));
|
751 | /**
|
752 | * Determine the name of the container and port to target for the service registry.
|
753 | */
|
754 | function determineContainerNameAndPort(options) {
|
755 | var _c, _d;
|
756 | // If the record type is SRV, then provide the containerName and containerPort to target.
|
757 | // We use the name of the default container and the default port of the default container
|
758 | // unless the user specifies otherwise.
|
759 | if (options.dnsRecordType === cloudmap.DnsRecordType.SRV) {
|
760 | // Ensure the user-provided container is from the right task definition.
|
761 | if (options.container && options.container.taskDefinition != options.taskDefinition) {
|
762 | throw new Error('Cannot add discovery for a container from another task definition');
|
763 | }
|
764 | const container = (_c = options.container) !== null && _c !== void 0 ? _c : options.taskDefinition.defaultContainer;
|
765 | // Ensure that any port given by the user is mapped.
|
766 | if (options.containerPort && !container.portMappings.some(mapping => mapping.containerPort === options.containerPort)) {
|
767 | throw new Error('Cannot add discovery for a container port that has not been mapped');
|
768 | }
|
769 | return {
|
770 | containerName: container.containerName,
|
771 | containerPort: (_d = options.containerPort) !== null && _d !== void 0 ? _d : options.taskDefinition.defaultContainer.containerPort,
|
772 | };
|
773 | }
|
774 | return {};
|
775 | }
|
776 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZS1zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiYmFzZS1zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLGtFQUFrRTtBQUNsRSxzREFBc0Q7QUFDdEQsd0NBQXdDO0FBRXhDLDZEQUE2RDtBQUM3RCx3Q0FBd0M7QUFDeEMsMERBQTBEO0FBQzFELHdDQUFnSDtBQUVoSCw2REFBaUc7QUFDakcsd0NBQWdHO0FBRWhHLG9EQUE4QztBQUM5QywrREFBMEQ7QUFxTjFEOztHQUVHO0FBQ0gsTUFBc0IsY0FBYztJQUNsQzs7T0FFRztJQUNJLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxRQUFtQyxFQUFFLEtBQXdDO1FBQzdHLE9BQU8sSUFBSSx5QkFBeUIsQ0FBQyxRQUFRLEVBQUUsS0FBSyxDQUFDLENBQUM7S0FDdkQ7SUFFRDs7T0FFRztJQUNJLE1BQU0sQ0FBQyxlQUFlLENBQUMsUUFBK0IsRUFBRSxLQUFvQztRQUNqRyxPQUFPLElBQUkscUJBQXFCLENBQUMsUUFBUSxFQUFFLEtBQUssQ0FBQyxDQUFDO0tBQ25EOztBQWJILHdDQW1CQzs7O0FBRUQ7O0dBRUc7QUFDSCxNQUFNLHlCQUEwQixTQUFRLGNBQWM7SUFDcEQsWUFBNkIsUUFBbUMsRUFBbUIsS0FBd0M7UUFDekgsS0FBSyxFQUFFLENBQUM7UUFEbUIsYUFBUSxHQUFSLFFBQVEsQ0FBMkI7UUFBbUIsVUFBSyxHQUFMLEtBQUssQ0FBbUM7S0FFMUg7SUFFRDs7T0FFRztJQUNJLFVBQVUsQ0FBQyxFQUFVLEVBQUUsTUFBaUMsRUFBRSxPQUFvQjs7UUFDbkYsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssSUFBSSxFQUFFLENBQUM7UUFDL0IsTUFBTSxRQUFRLEdBQUcsS0FBSyxDQUFDLFFBQVEsQ0FBQztRQUNoQyxNQUFNLElBQUksU0FBRyxLQUFLLENBQUMsSUFBSSxtQ0FBSSxDQUFDLFFBQVEsS0FBSyxLQUFLLENBQUMsbUJBQW1CLENBQUMs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RSxPQUFPLENBQUMsYUFBYSxtQ0FBSSxPQUFPLENBQUMsY0FBYyxDQUFDLGdCQUFpQixDQUFDLGFBQWE7U0FDL0YsQ0FBQztLQUNIO0lBRUQsT0FBTyxFQUFFLENBQUM7QUFDWixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgYXBwc2NhbGluZyBmcm9tICdAYXdzLWNkay9hd3MtYXBwbGljYXRpb25hdXRvc2NhbGluZyc7XG5pbXBvcnQgKiBhcyBjbG91ZHdhdGNoIGZyb20gJ0Bhd3MtY2RrL2F3cy1jbG91ZHdhdGNoJztcbmltcG9ydCAqIGFzIGVjMiBmcm9tICdAYXdzLWNkay9hd3MtZWMyJztcbmltcG9ydCAqIGFzIGVsYiBmcm9tICdAYXdzLWNkay9hd3MtZWxhc3RpY2xvYWRiYWxhbmNpbmcnO1xuaW1wb3J0ICogYXMgZWxidjIgZnJvbSAnQGF3cy1jZGsvYXdzLWVsYXN0aWNsb2FkYmFsYW5jaW5ndjInO1xuaW1wb3J0ICogYXMgaWFtIGZyb20gJ0Bhd3MtY2RrL2F3cy1pYW0nO1xuaW1wb3J0ICogYXMgY2xvdWRtYXAgZnJvbSAnQGF3cy1jZGsvYXdzLXNlcnZpY2VkaXNjb3ZlcnknO1xuaW1wb3J0IHsgQW5ub3RhdGlvbnMsIER1cmF0aW9uLCBJUmVzb2x2YWJsZSwgSVJlc291cmNlLCBMYXp5LCBSZXNvdXJjZSwgU3RhY2ssIEFybkZvcm1hdCB9IGZyb20gJ0Bhd3MtY2RrL2NvcmUnO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgeyBMb2FkQmFsYW5jZXJUYXJnZXRPcHRpb25zLCBOZXR3b3JrTW9kZSwgVGFza0RlZmluaXRpb24gfSBmcm9tICcuLi9iYXNlL3Rhc2stZGVmaW5pdGlvbic7XG5pbXBvcnQgeyBJQ2x1c3RlciwgQ2FwYWNpdHlQcm92aWRlclN0cmF0ZWd5LCBFeGVjdXRlQ29tbWFuZExvZ2dpbmcsIENsdXN0ZXIgfSBmcm9tICcuLi9jbHVzdGVyJztcbmltcG9ydCB7IENvbnRhaW5lckRlZmluaXRpb24sIFByb3RvY29sIH0gZnJvbSAnLi4vY29udGFpbmVyLWRlZmluaXRpb24nO1xuaW1wb3J0IHsgQ2ZuU2VydmljZSB9IGZyb20gJy4uL2Vjcy5nZW5lcmF0ZWQnO1xuaW1wb3J0IHsgU2NhbGFibGVUYXNrQ291bnQgfSBmcm9tICcuL3NjYWxhYmxlLXRhc2stY291bnQnO1xuXG4vKipcbiAqIFRoZSBpbnRlcmZhY2UgZm9yIGEgc2VydmljZS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBJU2VydmljZSBleHRlbmRzIElSZXNvdXJjZSB7XG4gIC8qKlxuICAgKiBUaGUgQW1hem9uIFJlc291cmNlIE5hbWUgKEFSTikgb2YgdGhlIHNlcnZpY2UuXG4gICAqXG4gICAqIEBhdHRyaWJ1dGVcbiAgICovXG4gIHJlYWRvbmx5IHNlcnZpY2VBcm46IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIG5hbWUgb2YgdGhlIHNlcnZpY2UuXG4gICAqXG4gICAqIEBhdHRyaWJ1dGVcbiAgICovXG4gIHJlYWRvbmx5IHNlcnZpY2VOYW1lOiBzdHJpbmc7XG59XG5cbi8qKlxuICogVGhlIGRlcGxveW1lbnQgY29udHJvbGxlciB0byB1c2UgZm9yIHRoZSBzZXJ2aWNlLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIERlcGxveW1lbnRDb250cm9sbGVyIHtcbiAgLyoqXG4gICAqIFRoZSBkZXBsb3ltZW50IGNvbnRyb2xsZXIgdHlwZSB0byB1c2UuXG4gICAqXG4gICAqIEBkZWZhdWx0IERlcGxveW1lbnRDb250cm9sbGVyVHlwZS5FQ1NcbiAgICovXG4gIHJlYWRvbmx5IHR5cGU/OiBEZXBsb3ltZW50Q29udHJvbGxlclR5cGU7XG59XG5cbi8qKlxuICogVGhlIGRlcGxveW1lbnQgY2lyY3VpdCBicmVha2VyIHRvIHVzZSBmb3IgdGhlIHNlcnZpY2VcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBEZXBsb3ltZW50Q2lyY3VpdEJyZWFrZXIge1xuICAvKipcbiAgICogV2hldGhlciB0byBlbmFibGUgcm9sbGJhY2sgb24gZGVwbG95bWVudCBmYWlsdXJlXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSByb2xsYmFjaz86IGJvb2xlYW47XG5cbn1cblxuZXhwb3J0IGludGVyZmFjZSBFY3NUYXJnZXQge1xuICAvKipcbiAgICogVGhlIG5hbWUgb2YgdGhlIGNvbnRhaW5lci5cbiAgICovXG4gIHJlYWRvbmx5IGNvbnRhaW5lck5hbWU6IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIHBvcnQgbnVtYmVyIG9mIHRoZSBjb250YWluZXIuIE9ubHkgYXBwbGljYWJsZSB3aGVuIHVzaW5nIGFwcGxpY2F0aW9uL25ldHdvcmsgbG9hZCBiYWxhbmNlcnMuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gQ29udGFpbmVyIHBvcnQgb2YgdGhlIGZpcnN0IGFkZGVkIHBvcnQgbWFwcGluZy5cbiAgICovXG4gIHJlYWRvbmx5IGNvbnRhaW5lclBvcnQ/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIFRoZSBwcm90b2NvbCB1c2VkIGZvciB0aGUgcG9ydCBtYXBwaW5nLiBPbmx5IGFwcGxpY2FibGUgd2hlbiB1c2luZyBhcHBsaWNhdGlvbiBsb2FkIGJhbGFuY2Vycy5cbiAgICpcbiAgICogQGRlZmF1bHQgUHJvdG9jb2wuVENQXG4gICAqL1xuICByZWFkb25seSBwcm90b2NvbD86IFByb3RvY29sO1xuXG4gIC8qKlxuICAgKiBJRCBmb3IgYSB0YXJnZXQgZ3JvdXAgdG8gYmUgY3JlYXRlZC5cbiAgICovXG4gIHJlYWRvbmx5IG5ld1RhcmdldEdyb3VwSWQ6IHN0cmluZztcblxuICAvKipcbiAgICogTGlzdGVuZXIgYW5kIHByb3BlcnRpZXMgZm9yIGFkZGluZyB0YXJnZXQgZ3JvdXAgdG8gdGhlIGxpc3RlbmVyLlxuICAgKi9cbiAgcmVhZG9ubHkgbGlzdGVuZXI6IExpc3RlbmVyQ29uZmlnO1xufVxuXG4vKipcbiAqIEludGVyZmFjZSBmb3IgRUNTIGxvYWQgYmFsYW5jZXIgdGFyZ2V0LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIElFY3NMb2FkQmFsYW5jZXJUYXJnZXQgZXh0ZW5kcyBlbGJ2Mi5JQXBwbGljYXRpb25Mb2FkQmFsYW5jZXJUYXJnZXQsIGVsYnYyLklOZXR3b3JrTG9hZEJhbGFuY2VyVGFyZ2V0LCBlbGIuSUxvYWRCYWxhbmNlclRhcmdldCB7XG59XG5cbi8qKlxuICogVGhlIHByb3BlcnRpZXMgZm9yIHRoZSBiYXNlIEVjMlNlcnZpY2Ugb3IgRmFyZ2F0ZVNlcnZpY2Ugc2VydmljZS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBCYXNlU2VydmljZU9wdGlvbnMge1xuICAvKipcbiAgICogVGhlIG5hbWUgb2YgdGhlIGNsdXN0ZXIgdGhhdCBob3N0cyB0aGUgc2VydmljZS5cbiAgICovXG4gIHJlYWRvbmx5IGNsdXN0ZXI6IElDbHVzdGVyO1xuXG4gIC8qKlxuICAgKiBUaGUgZGVzaXJlZCBudW1iZXIgb2YgaW5zdGFudGlhdGlvbnMgb2YgdGhlIHRhc2sgZGVmaW5pdGlvbiB0byBrZWVwIHJ1bm5pbmcgb24gdGhlIHNlcnZpY2UuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gV2hlbiBjcmVhdGluZyB0aGUgc2VydmljZSwgZGVmYXVsdCBpcyAxOyB3aGVuIHVwZGF0aW5nIHRoZSBzZXJ2aWNlLCBkZWZhdWx0IHVzZXNcbiAgICogdGhlIGN1cnJlbnQgdGFzayBudW1iZXIuXG4gICAqL1xuICByZWFkb25seSBkZXNpcmVkQ291bnQ/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIFRoZSBuYW1lIG9mIHRoZSBzZXJ2aWNlLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIENsb3VkRm9ybWF0aW9uLWdlbmVyYXRlZCBuYW1lLlxuICAgKi9cbiAgcmVhZG9ubHkgc2VydmljZU5hbWU/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBtYXhpbXVtIG51bWJlciBvZiB0YXNrcywgc3BlY2lmaWVkIGFzIGEgcGVyY2VudGFnZSBvZiB0aGUgQW1hem9uIEVDU1xuICAgKiBzZXJ2aWNlJ3MgRGVzaXJlZENvdW50IHZhbHVlLCB0aGF0IGNhbiBydW4gaW4gYSBzZXJ2aWNlIGR1cmluZyBhXG4gICAqIGRlcGxveW1lbnQuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gMTAwIGlmIGRhZW1vbiwgb3RoZXJ3aXNlIDIwMFxuICAgKi9cbiAgcmVhZG9ubHkgbWF4SGVhbHRoeVBlcmNlbnQ/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIFRoZSBtaW5pbXVtIG51bWJlciBvZiB0YXNrcywgc3BlY2lmaWVkIGFzIGEgcGVyY2VudGFnZSBvZlxuICAgKiB0aGUgQW1hem9uIEVDUyBzZXJ2aWNlJ3MgRGVzaXJlZENvdW50IHZhbHVlLCB0aGF0IG11c3RcbiAgICogY29udGludWUgdG8gcnVuIGFuZCByZW1haW4gaGVhbHRoeSBkdXJpbmcgYSBkZXBsb3ltZW50LlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIDAgaWYgZGFlbW9uLCBvdGhlcndpc2UgNTBcbiAgICovXG4gIHJlYWRvbmx5IG1pbkhlYWx0aHlQZXJjZW50PzogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBUaGUgcGVyaW9kIG9mIHRpbWUsIGluIHNlY29uZHMsIHRoYXQgdGhlIEFtYXpvbiBFQ1Mgc2VydmljZSBzY2hlZHVsZXIgaWdub3JlcyB1bmhlYWx0aHlcbiAgICogRWxhc3RpYyBMb2FkIEJhbGFuY2luZyB0YXJnZXQgaGVhbHRoIGNoZWNrcyBhZnRlciBhIHRhc2sgaGFzIGZpcnN0IHN0YXJ0ZWQuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gZGVmYXVsdHMgdG8gNjAgc2Vjb25kcyBpZiBhdCBsZWFzdCBvbmUgbG9hZCBiYWxhbmNlciBpcyBpbi11c2UgYW5kIGl0IGlzIG5vdCBhbHJlYWR5IHNldFxuICAgKi9cbiAgcmVhZG9ubHkgaGVhbHRoQ2hlY2tHcmFjZVBlcmlvZD86IER1cmF0aW9uO1xuXG4gIC8qKlxuICAgKiBUaGUgb3B0aW9ucyBmb3IgY29uZmlndXJpbmcgYW4gQW1hem9uIEVDUyBzZXJ2aWNlIHRvIHVzZSBzZXJ2aWNlIGRpc2NvdmVyeS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBBV1MgQ2xvdWQgTWFwIHNlcnZpY2UgZGlzY292ZXJ5IGlzIG5vdCBlbmFibGVkLlxuICAgKi9cbiAgcmVhZG9ubHkgY2xvdWRNYXBPcHRpb25zPzogQ2xvdWRNYXBPcHRpb25zO1xuXG4gIC8qKlxuICAgKiBTcGVjaWZpZXMgd2hldGhlciB0byBwcm9wYWdhdGUgdGhlIHRhZ3MgZnJvbSB0aGUgdGFzayBkZWZpbml0aW9uIG9yIHRoZSBzZXJ2aWNlIHRvIHRoZSB0YXNrcyBpbiB0aGUgc2VydmljZVxuICAgKlxuICAgKiBWYWxpZCB2YWx1ZXMgYXJlOiBQcm9wYWdhdGVkVGFnU291cmNlLlNFUlZJQ0UsIFByb3BhZ2F0ZWRUYWdTb3VyY2UuVEFTS19ERUZJTklUSU9OIG9yIFByb3BhZ2F0ZWRUYWdTb3VyY2UuTk9ORVxuICAgKlxuICAgKiBAZGVmYXVsdCBQcm9wYWdhdGVkVGFnU291cmNlLk5PTkVcbiAgICovXG4gIHJlYWRvbmx5IHByb3BhZ2F0ZVRhZ3M/OiBQcm9wYWdhdGVkVGFnU291cmNlO1xuXG4gIC8qKlxuICAgKiBTcGVjaWZpZXMgd2hldGhlciB0byBwcm9wYWdhdGUgdGhlIHRhZ3MgZnJvbSB0aGUgdGFzayBkZWZpbml0aW9uIG9yIHRoZSBzZXJ2aWNlIHRvIHRoZSB0YXNrcyBpbiB0aGUgc2VydmljZS5cbiAgICogVGFncyBjYW4gb25seSBiZSBwcm9wYWdhdGVkIHRvIHRoZSB0YXNrcyB3aXRoaW4gdGhlIHNlcnZpY2UgZHVyaW5nIHNlcnZpY2UgY3JlYXRpb24uXG4gICAqXG4gICAqIEBkZXByZWNhdGVkIFVzZSBgcHJvcGFnYXRlVGFnc2AgaW5zdGVhZC5cbiAgICogQGRlZmF1bHQgUHJvcGFnYXRlZFRhZ1NvdXJjZS5OT05FXG4gICAqL1xuICByZWFkb25seSBwcm9wYWdhdGVUYXNrVGFnc0Zyb20/OiBQcm9wYWdhdGVkVGFnU291cmNlO1xuXG4gIC8qKlxuICAgKiBTcGVjaWZpZXMgd2hldGhlciB0byBlbmFibGUgQW1hem9uIEVDUyBtYW5hZ2VkIHRhZ3MgZm9yIHRoZSB0YXNrcyB3aXRoaW4gdGhlIHNlcnZpY2UuIEZvciBtb3JlIGluZm9ybWF0aW9uLCBzZWVcbiAgICogW1RhZ2dpbmcgWW91ciBBbWF6b24gRUNTIFJlc291cmNlc10oaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL0FtYXpvbkVDUy9sYXRlc3QvZGV2ZWxvcGVyZ3VpZGUvZWNzLXVzaW5nLXRhZ3MuaHRtbClcbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IGVuYWJsZUVDU01hbmFnZWRUYWdzPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogU3BlY2lmaWVzIHdoaWNoIGRlcGxveW1lbnQgY29udHJvbGxlciB0byB1c2UgZm9yIHRoZSBzZXJ2aWNlLiBGb3IgbW9yZSBpbmZvcm1hdGlvbiwgc2VlXG4gICAqIFtBbWF6b24gRUNTIERlcGxveW1lbnQgVHlwZXNdKGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9BbWF6b25FQ1MvbGF0ZXN0L2RldmVsb3Blcmd1aWRlL2RlcGxveW1lbnQtdHlwZXMuaHRtbClcbiAgICpcbiAgICogQGRlZmF1bHQgLSBSb2xsaW5nIHVwZGF0ZSAoRUNTKVxuICAgKi9cbiAgcmVhZG9ubHkgZGVwbG95bWVudENvbnRyb2xsZXI/OiBEZXBsb3ltZW50Q29udHJvbGxlcjtcblxuICAvKipcbiAgICogV2hldGhlciB0byBlbmFibGUgdGhlIGRlcGxveW1lbnQgY2lyY3VpdCBicmVha2VyLiBJZiB0aGlzIHByb3BlcnR5IGlzIGRlZmluZWQsIGNpcmN1aXQgYnJlYWtlciB3aWxsIGJlIGltcGxpY2l0bHlcbiAgICogZW5hYmxlZC5cbiAgICogQGRlZmF1bHQgLSBkaXNhYmxlZFxuICAgKi9cbiAgcmVhZG9ubHkgY2lyY3VpdEJyZWFrZXI/OiBEZXBsb3ltZW50Q2lyY3VpdEJyZWFrZXI7XG5cbiAgLyoqXG4gICAqIEEgbGlzdCBvZiBDYXBhY2l0eSBQcm92aWRlciBzdHJhdGVnaWVzIHVzZWQgdG8gcGxhY2UgYSBzZXJ2aWNlLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIHVuZGVmaW5lZFxuICAgKlxuICAgKi9cbiAgcmVhZG9ubHkgY2FwYWNpdHlQcm92aWRlclN0cmF0ZWdpZXM/OiBDYXBhY2l0eVByb3ZpZGVyU3RyYXRlZ3lbXTtcblxuICAvKipcbiAgICogV2hldGhlciB0byBlbmFibGUgdGhlIGFiaWxpdHkgdG8gZXhlY3V0ZSBpbnRvIGEgY29udGFpbmVyXG4gICAqXG4gICAqICBAZGVmYXVsdCAtIHVuZGVmaW5lZFxuICAgKi9cbiAgcmVhZG9ubHkgZW5hYmxlRXhlY3V0ZUNvbW1hbmQ/OiBib29sZWFuO1xufVxuXG4vKipcbiAqIENvbXBsZXRlIGJhc2Ugc2VydmljZSBwcm9wZXJ0aWVzIHRoYXQgYXJlIHJlcXVpcmVkIHRvIGJlIHN1cHBsaWVkIGJ5IHRoZSBpbXBsZW1lbnRhdGlvblxuICogb2YgdGhlIEJhc2VTZXJ2aWNlIGNsYXNzLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEJhc2VTZXJ2aWNlUHJvcHMgZXh0ZW5kcyBCYXNlU2VydmljZU9wdGlvbnMge1xuICAvKipcbiAgICogVGhlIGxhdW5jaCB0eXBlIG9uIHdoaWNoIHRvIHJ1biB5b3VyIHNlcnZpY2UuXG4gICAqXG4gICAqIExhdW5jaFR5cGUgd2lsbCBiZSBvbWl0dGVkIGlmIGNhcGFjaXR5IHByb3ZpZGVyIHN0cmF0ZWdpZXMgYXJlIHNwZWNpZmllZCBvbiB0aGUgc2VydmljZS5cbiAgICpcbiAgICogQHNlZSAtIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9BV1NDbG91ZEZvcm1hdGlvbi9sYXRlc3QvVXNlckd1aWRlL2F3cy1yZXNvdXJjZS1lY3Mtc2VydmljZS5odG1sI2Nmbi1lY3Mtc2VydmljZS1jYXBhY2l0eXByb3ZpZGVyc3RyYXRlZ3lcbiAgICpcbiAgICogVmFsaWQgdmFsdWVzIGFyZTogTGF1bmNoVHlwZS5FQ1Mgb3IgTGF1bmNoVHlwZS5GQVJHQVRFIG9yIExhdW5jaFR5cGUuRVhURVJOQUxcbiAgICovXG4gIHJlYWRvbmx5IGxhdW5jaFR5cGU6IExhdW5jaFR5cGU7XG59XG5cbi8qKlxuICogQmFzZSBjbGFzcyBmb3IgY29uZmlndXJpbmcgbGlzdGVuZXIgd2hlbiByZWdpc3RlcmluZyB0YXJnZXRzLlxuICovXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgTGlzdGVuZXJDb25maWcge1xuICAvKipcbiAgICogQ3JlYXRlIGEgY29uZmlnIGZvciBhZGRpbmcgdGFyZ2V0IGdyb3VwIHRvIEFMQiBsaXN0ZW5lci5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgYXBwbGljYXRpb25MaXN0ZW5lcihsaXN0ZW5lcjogZWxidjIuQXBwbGljYXRpb25MaXN0ZW5lciwgcHJvcHM/OiBlbGJ2Mi5BZGRBcHBsaWNhdGlvblRhcmdldHNQcm9wcyk6IExpc3RlbmVyQ29uZmlnIHtcbiAgICByZXR1cm4gbmV3IEFwcGxpY2F0aW9uTGlzdGVuZXJDb25maWcobGlzdGVuZXIsIHByb3BzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSBjb25maWcgZm9yIGFkZGluZyB0YXJnZXQgZ3JvdXAgdG8gTkxCIGxpc3RlbmVyLlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBuZXR3b3JrTGlzdGVuZXIobGlzdGVuZXI6IGVsYnYyLk5ldHdvcmtMaXN0ZW5lciwgcHJvcHM/OiBlbGJ2Mi5BZGROZXR3b3JrVGFyZ2V0c1Byb3BzKTogTGlzdGVuZXJDb25maWcge1xuICAgIHJldHVybiBuZXcgTmV0d29ya0xpc3RlbmVyQ29uZmlnKGxpc3RlbmVyLCBwcm9wcyk7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlIGFuZCBhdHRhY2ggYSB0YXJnZXQgZ3JvdXAgdG8gbGlzdGVuZXIuXG4gICAqL1xuICBwdWJsaWMgYWJzdHJhY3QgYWRkVGFyZ2V0cyhpZDogc3RyaW5nLCB0YXJnZXQ6IExvYWRCYWxhbmNlclRhcmdldE9wdGlvbnMsIHNlcnZpY2U6IEJhc2VTZXJ2aWNlKTogdm9pZDtcbn1cblxuLyoqXG4gKiBDbGFzcyBmb3IgY29uZmlndXJpbmcgYXBwbGljYXRpb24gbG9hZCBiYWxhbmNlciBsaXN0ZW5lciB3aGVuIHJlZ2lzdGVyaW5nIHRhcmdldHMuXG4gKi9cbmNsYXNzIEFwcGxpY2F0aW9uTGlzdGVuZXJDb25maWcgZXh0ZW5kcyBMaXN0ZW5lckNvbmZpZyB7XG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgcmVhZG9ubHkgbGlzdGVuZXI6IGVsYnYyLkFwcGxpY2F0aW9uTGlzdGVuZXIsIHByaXZhdGUgcmVhZG9ubHkgcHJvcHM/OiBlbGJ2Mi5BZGRBcHBsaWNhdGlvblRhcmdldHNQcm9wcykge1xuICAgIHN1cGVyKCk7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlIGFuZCBhdHRhY2ggYSB0YXJnZXQgZ3JvdXAgdG8gbGlzdGVuZXIuXG4gICAqL1xuICBwdWJsaWMgYWRkVGFyZ2V0cyhpZDogc3RyaW5nLCB0YXJnZXQ6IExvYWRCYWxhbmNlclRhcmdldE9wdGlvbnMsIHNlcnZpY2U6IEJhc2VTZXJ2aWNlKSB7XG4gICAgY29uc3QgcHJvcHMgPSB0aGlzLnByb3BzIHx8IHt9O1xuICAgIGNvbnN0IHByb3RvY29sID0gcHJvcHMucHJvdG9jb2w7XG4gICAgY29uc3QgcG9ydCA9IHByb3BzLnBvcnQgPz8gKHByb3RvY29sID09PSBlbGJ2Mi5BcHBsaWNhdGlvblByb3RvY29sLkhUVFBTID8gNDQzIDogODApO1xuICAgIHRoaXMubGlzdGVuZXIuYWRkVGFyZ2V0cyhpZCwge1xuICAgICAgLi4uIHByb3BzLFxuICAgICAgdGFyZ2V0czogW1xuICAgICAgICBzZXJ2aWNlLmxvYWRCYWxhbmNlclRhcmdldCh7XG4gICAgICAgICAgLi4udGFyZ2V0LFxuICAgICAgICB9KSxcbiAgICAgIF0sXG4gICAgICBwb3J0LFxuICAgIH0pO1xuICB9XG59XG5cbi8qKlxuICogQ2xhc3MgZm9yIGNvbmZpZ3VyaW5nIG5ldHdvcmsgbG9hZCBiYWxhbmNlciBsaXN0ZW5lciB3aGVuIHJlZ2lzdGVyaW5nIHRhcmdldHMuXG4gKi9cbmNsYXNzIE5ldHdvcmtMaXN0ZW5lckNvbmZpZyBleHRlbmRzIExpc3RlbmVyQ29uZmlnIHtcbiAgY29uc3RydWN0b3IocHJpdmF0ZSByZWFkb25seSBsaXN0ZW5lcjogZWxidjIuTmV0d29ya0xpc3RlbmVyLCBwcml2YXRlIHJlYWRvbmx5IHByb3BzPzogZWxidjIuQWRkTmV0d29ya1RhcmdldHNQcm9wcykge1xuICAgIHN1cGVyKCk7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlIGFuZCBhdHRhY2ggYSB0YXJnZXQgZ3JvdXAgdG8gbGlzdGVuZXIuXG4gICAqL1xuICBwdWJsaWMgYWRkVGFyZ2V0cyhpZDogc3RyaW5nLCB0YXJnZXQ6IExvYWRCYWxhbmNlclRhcmdldE9wdGlvbnMsIHNlcnZpY2U6IEJhc2VTZXJ2aWNlKSB7XG4gICAgY29uc3QgcG9ydCA9IHRoaXMucHJvcHM/LnBvcnQgPz8gODA7XG4gICAgdGhpcy5saXN0ZW5lci5hZGRUYXJnZXRzKGlkLCB7XG4gICAgICAuLi4gdGhpcy5wcm9wcyxcbiAgICAgIHRhcmdldHM6IFtcbiAgICAgICAgc2VydmljZS5sb2FkQmFsYW5jZXJUYXJnZXQoe1xuICAgICAgICAgIC4uLnRhcmdldCxcbiAgICAgICAgfSksXG4gICAgICBdLFxuICAgICAgcG9ydCxcbiAgICB9KTtcbiAgfVxufVxuXG4vKipcbiAqIFRoZSBpbnRlcmZhY2UgZm9yIEJhc2VTZXJ2aWNlLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIElCYXNlU2VydmljZSBleHRlbmRzIElTZXJ2aWNlIHtcbiAgLyoqXG4gICAqIFRoZSBjbHVzdGVyIHRoYXQgaG9zdHMgdGhlIHNlcnZpY2UuXG4gICAqL1xuICByZWFkb25seSBjbHVzdGVyOiBJQ2x1c3Rlcjtcbn1cblxuLyoqXG4gKiBUaGUgYmFzZSBjbGFzcyBmb3IgRWMyU2VydmljZSBhbmQgRmFyZ2F0ZVNlcnZpY2Ugc2VydmljZXMuXG4gKi9cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBCYXNlU2VydmljZSBleHRlbmRzIFJlc291cmNlXG4gIGltcGxlbWVudHMgSUJhc2VTZXJ2aWNlLCBlbGJ2Mi5JQXBwbGljYXRpb25Mb2FkQmFsYW5jZXJUYXJnZXQsIGVsYnYyLklOZXR3b3JrTG9hZEJhbGFuY2VyVGFyZ2V0LCBlbGIuSUxvYWRCYWxhbmNlclRhcmdldCB7XG4gIC8qKlxuICAgKiBJbXBvcnQgYW4gZXhpc3RpbmcgRUNTL0ZhcmdhdGUgU2VydmljZSB1c2luZyB0aGUgc2VydmljZSBjbHVzdGVyIGZvcm1hdC5cbiAgICogVGhlIGZvcm1hdCBpcyB0aGUgXCJuZXdcIiBmb3JtYXQgXCJhcm46YXdzOmVjczpyZWdpb246YXdzX2FjY291bnRfaWQ6c2VydmljZS9jbHVzdGVyLW5hbWUvc2VydmljZS1uYW1lXCIuXG4gICAqIEBzZWUgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL0FtYXpvbkVDUy9sYXRlc3QvZGV2ZWxvcGVyZ3VpZGUvZWNzLWFjY291bnQtc2V0dGluZ3MuaHRtbCNlY3MtcmVzb3VyY2UtaWRzXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGZyb21TZXJ2aWNlQXJuV2l0aENsdXN0ZXIoc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgc2VydmljZUFybjogc3RyaW5nKTogSUJhc2VTZXJ2aWNlIHtcbiAgICBjb25zdCBzdGFjayA9IFN0YWNrLm9mKHNjb3BlKTtcbiAgICBjb25zdCBhcm4gPSBzdGFjay5zcGxpdEFybihzZXJ2aWNlQXJuLCBBcm5Gb3JtYXQuU0xBU0hfUkVTT1VSQ0VfTkFNRSk7XG4gICAgY29uc3QgcmVzb3VyY2VOYW1lID0gYXJuLnJlc291cmNlTmFtZTtcbiAgICBpZiAoIXJlc291cmNlTmFtZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdNaXNzaW5nIHJlc291cmNlIE5hbWUgZnJvbSBzZXJ2aWNlIEFSTjogJHtzZXJ2aWNlQXJufScpO1xuICAgIH1cbiAgICBjb25zdCByZXNvdXJjZU5hbWVQYXJ0cyA9IHJlc291cmNlTmFtZS5zcGxpdCgnLycpO1xuICAgIGlmIChyZXNvdXJjZU5hbWVQYXJ0cy5sZW5ndGggIT09IDIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgcmVzb3VyY2UgbmFtZSAke3Jlc291cmNlTmFtZX0gZnJvbSBzZXJ2aWNlIEFSTjogJHtzZXJ2aWNlQXJufSBpcyBub3QgdXNpbmcgdGhlIEFSTiBjbHVzdGVyIGZvcm1hdGApO1xuICAgIH1cbiAgICBjb25zdCBjbHVzdGVyTmFtZSA9IHJlc291cmNlTmFtZVBhcnRzWzBdO1xuICAgIGNvbnN0IHNlcnZpY2VOYW1lID0gcmVzb3VyY2VOYW1lUGFydHNbMV07XG5cbiAgICBjb25zdCBjbHVzdGVyQXJuID0gU3RhY2sub2Yoc2NvcGUpLmZvcm1hdEFybih7XG4gICAgICBwYXJ0aXRpb246IGFybi5wYXJ0aXRpb24sXG4gICAgICByZWdpb246IGFybi5yZWdpb24sXG4gICAgICBhY2NvdW50OiBhcm4uYWNjb3VudCxcbiAgICAgIHNlcnZpY2U6ICdlY3MnLFxuICAgICAgcmVzb3VyY2U6ICdjbHVzdGVyJyxcbiAgICAgIHJlc291cmNlTmFtZTogY2x1c3Rlck5hbWUsXG4gICAgfSk7XG5cbiAgICBjb25zdCBjbHVzdGVyID0gQ2x1c3Rlci5mcm9tQ2x1c3RlckFybihzY29wZSwgYCR7aWR9Q2x1c3RlcmAsIGNsdXN0ZXJBcm4pO1xuXG4gICAgY2xhc3MgSW1wb3J0IGV4dGVuZHMgUmVzb3VyY2UgaW1wbGVtZW50cyBJQmFzZVNlcnZpY2Uge1xuICAgICAgcHVibGljIHJlYWRvbmx5IHNlcnZpY2VBcm4gPSBzZXJ2aWNlQXJuO1xuICAgICAgcHVibGljIHJlYWRvbmx5IHNlcnZpY2VOYW1lID0gc2VydmljZU5hbWU7XG4gICAgICBwdWJsaWMgcmVhZG9ubHkgY2x1c3RlciA9IGNsdXN0ZXI7XG4gICAgfVxuXG4gICAgcmV0dXJuIG5ldyBJbXBvcnQoc2NvcGUsIGlkLCB7XG4gICAgICBlbnZpcm9ubWVudEZyb21Bcm46IHNlcnZpY2VBcm4sXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogVGhlIHNlY3VyaXR5IGdyb3VwcyB3aGljaCBtYW5hZ2UgdGhlIGFsbG93ZWQgbmV0d29yayB0cmFmZmljIGZvciB0aGUgc2VydmljZS5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBjb25uZWN0aW9uczogZWMyLkNvbm5lY3Rpb25zID0gbmV3IGVjMi5Db25uZWN0aW9ucygpO1xuXG4gIC8qKlxuICAgKiBUaGUgQW1hem9uIFJlc291cmNlIE5hbWUgKEFSTikgb2YgdGhlIHNlcnZpY2UuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgc2VydmljZUFybjogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgbmFtZSBvZiB0aGUgc2VydmljZS5cbiAgICpcbiAgICogQGF0dHJpYnV0ZVxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHNlcnZpY2VOYW1lOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSB0YXNrIGRlZmluaXRpb24gdG8gdXNlIGZvciB0YXNrcyBpbiB0aGUgc2VydmljZS5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSB0YXNrRGVmaW5pdGlvbjogVGFza0RlZmluaXRpb247XG5cbiAgLyoqXG4gICAqIFRoZSBjbHVzdGVyIHRoYXQgaG9zdHMgdGhlIHNlcnZpY2UuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgY2x1c3RlcjogSUNsdXN0ZXI7XG5cbiAgLyoqXG4gICAqIFRoZSBkZXRhaWxzIG9mIHRoZSBBV1MgQ2xvdWQgTWFwIHNlcnZpY2UuXG4gICAqL1xuICBwcm90ZWN0ZWQgY2xvdWRtYXBTZXJ2aWNlPzogY2xvdWRtYXAuU2VydmljZTtcblxuICAvKipcbiAgICogQSBsaXN0IG9mIEVsYXN0aWMgTG9hZCBCYWxhbmNpbmcgbG9hZCBiYWxhbmNlciBvYmplY3RzLCBjb250YWluaW5nIHRoZSBsb2FkIGJhbGFuY2VyIG5hbWUsIHRoZSBjb250YWluZXJcbiAgICogbmFtZSAoYXMgaXQgYXBwZWFycyBpbiBhIGNvbnRhaW5lciBkZWZpbml0aW9uKSwgYW5kIHRoZSBjb250YWluZXIgcG9ydCB0byBhY2Nlc3MgZnJvbSB0aGUgbG9hZCBiYWxhbmNlci5cbiAgICovXG4gIHByb3RlY3RlZCBsb2FkQmFsYW5jZXJzID0gbmV3IEFycmF5PENmblNlcnZpY2UuTG9hZEJhbGFuY2VyUHJvcGVydHk+KCk7XG5cbiAgLyoqXG4gICAqIEEgbGlzdCBvZiBFbGFzdGljIExvYWQgQmFsYW5jaW5nIGxvYWQgYmFsYW5jZXIgb2JqZWN0cywgY29udGFpbmluZyB0aGUgbG9hZCBiYWxhbmNlciBuYW1lLCB0aGUgY29udGFpbmVyXG4gICAqIG5hbWUgKGFzIGl0IGFwcGVhcnMgaW4gYSBjb250YWluZXIgZGVmaW5pdGlvbiksIGFuZCB0aGUgY29udGFpbmVyIHBvcnQgdG8gYWNjZXNzIGZyb20gdGhlIGxvYWQgYmFsYW5jZXIuXG4gICAqL1xuICBwcm90ZWN0ZWQgbmV0d29ya0NvbmZpZ3VyYXRpb24/OiBDZm5TZXJ2aWNlLk5ldHdvcmtDb25maWd1cmF0aW9uUHJvcGVydHk7XG5cbiAgLyoqXG4gICAqIFRoZSBkZXRhaWxzIG9mIHRoZSBzZXJ2aWNlIGRpc2NvdmVyeSByZWdpc3RyaWVzIHRvIGFzc2lnbiB0byB0aGlzIHNlcnZpY2UuXG4gICAqIEZvciBtb3JlIGluZm9ybWF0aW9uLCBzZWUgU2VydmljZSBEaXNjb3ZlcnkuXG4gICAqL1xuICBwcm90ZWN0ZWQgc2VydmljZVJlZ2lzdHJpZXMgPSBuZXcgQXJyYXk8Q2ZuU2VydmljZS5TZXJ2aWNlUmVnaXN0cnlQcm9wZXJ0eT4oKTtcblxuICBwcml2YXRlIHJlYWRvbmx5IHJlc291cmNlOiBDZm5TZXJ2aWNlO1xuICBwcml2YXRlIHNjYWxhYmxlVGFza0NvdW50PzogU2NhbGFibGVUYXNrQ291bnQ7XG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdHMgYSBuZXcgaW5zdGFuY2Ugb2YgdGhlIEJhc2VTZXJ2aWNlIGNsYXNzLlxuICAgKi9cbiAgY29uc3RydWN0b3IoXG4gICAgc2NvcGU6IENvbnN0cnVjdCxcbiAgICBpZDogc3RyaW5nLFxuICAgIHByb3BzOiBCYXNlU2VydmljZVByb3BzLFxuICAgIGFkZGl0aW9uYWxQcm9wczogYW55LFxuICAgIHRhc2tEZWZpbml0aW9uOiBUYXNrRGVmaW5pdGlvbikge1xuICAgIHN1cGVyKHNjb3BlLCBpZCwge1xuICAgICAgcGh5c2ljYWxOYW1lOiBwcm9wcy5zZXJ2aWNlTmFtZSxcbiAgICB9KTtcblxuICAgIGlmIChwcm9wcy5wcm9wYWdhdGVUYWdzICYmIHByb3BzLnByb3BhZ2F0ZVRhc2tUYWdzRnJvbSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdZb3UgY2FuIG9ubHkgc3BlY2lmeSBlaXRoZXIgcHJvcGFnYXRlVGFncyBvciBwcm9wYWdhdGVUYXNrVGFnc0Zyb20uIEFsdGVybmF0aXZlbHksIHlvdSBjYW4gbGVhdmUgYm90aCBibGFuaycpO1xuICAgIH1cblxuICAgIHRoaXMudGFza0RlZmluaXRpb24gPSB0YXNrRGVmaW5pdGlvbjtcblxuICAgIC8vIGxhdW5jaFR5cGUgd2lsbCBzZXQgdG8gdW5kZWZpbmVkIGlmIHVzaW5nIGV4dGVybmFsIERlcGxveW1lbnRDb250cm9sbGVyIG9yIGNhcGFjaXR5UHJvdmlkZXJTdHJhdGVnaWVzXG4gICAgY29uc3QgbGF1bmNoVHlwZSA9IHByb3BzLmRlcGxveW1lbnRDb250cm9sbGVyPy50eXBlID09PSBEZXBsb3ltZW50Q29udHJvbGxlclR5cGUuRVhURVJOQUwgfHxcbiAgICAgIHByb3BzLmNhcGFjaXR5UHJvdmlkZXJTdHJhdGVnaWVzICE9PSB1bmRlZmluZWQgP1xuICAgICAgdW5kZWZpbmVkIDogcHJvcHMubGF1bmNoVHlwZTtcblxuICAgIGNvbnN0IHByb3BhZ2F0ZVRhZ3NGcm9tU291cmNlID0gcHJvcHMucHJvcGFnYXRlVGFza1RhZ3NGcm9tID8/IHByb3BzLnByb3BhZ2F0ZVRhZ3MgPz8gUHJvcGFnYXRlZFRhZ1NvdXJjZS5OT05FO1xuXG4gICAgdGhpcy5yZXNvdXJjZSA9IG5ldyBDZm5TZXJ2aWNlKHRoaXMsICdTZXJ2aWNlJywge1xuICAgICAgZGVzaXJlZENvdW50OiBwcm9wcy5kZXNpcmVkQ291bnQsXG4gICAgICBzZXJ2aWNlTmFtZTogdGhpcy5waHlzaWNhbE5hbWUsXG4gICAgICBsb2FkQmFsYW5jZXJzOiBMYXp5LmFueSh7IHByb2R1Y2U6ICgpID0+IHRoaXMubG9hZEJhbGFuY2VycyB9LCB7IG9taXRFbXB0eUFycmF5OiB0cnVlIH0pLFxuICAgICAgZGVwbG95bWVudENvbmZpZ3VyYXRpb246IHtcbiAgICAgICAgbWF4aW11bVBlcmNlbnQ6IHByb3BzLm1heEhlYWx0aHlQZXJjZW50IHx8IDIwMCxcbiAgICAgICAgbWluaW11bUhlYWx0aHlQZXJjZW50OiBwcm9wcy5taW5IZWFsdGh5UGVyY2VudCA9PT0gdW5kZWZpbmVkID8gNTAgOiBwcm9wcy5taW5IZWFsdGh5UGVyY2VudCxcbiAgICAgICAgZGVwbG95bWVudENpcmN1aXRCcmVha2VyOiBwcm9wcy5jaXJjdWl0QnJlYWtlciA/IHtcbiAgICAgICAgICBlbmFibGU6IHRydWUsXG4gICAgICAgICAgcm9sbGJhY2s6IHByb3BzLmNpcmN1aXRCcmVha2VyLnJvbGxiYWNrID8/IGZhbHNlLFxuICAgICAgICB9IDogdW5kZWZpbmVkLFxuICAgICAgfSxcbiAgICAgIHByb3BhZ2F0ZVRhZ3M6IHByb3BhZ2F0ZVRhZ3NGcm9tU291cmNlID09PSBQcm9wYWdhdGVkVGFnU291cmNlLk5PTkUgPyB1bmRlZmluZWQgOiBwcm9wcy5wcm9wYWdhdGVUYWdzLFxuICAgICAgZW5hYmxlRWNzTWFuYWdlZFRhZ3M6IHByb3BzLmVuYWJsZUVDU01hbmFnZWRUYWdzID8/IGZhbHNlLFxuICAgICAgZGVwbG95bWVudENvbnRyb2xsZXI6IHByb3BzLmNpcmN1aXRCcmVha2VyID8ge1xuICAgICAgICB0eXBlOiBEZXBsb3ltZW50Q29udHJvbGxlclR5cGUuRUNTLFxuICAgICAgfSA6IHByb3BzLmRlcGxveW1lbnRDb250cm9sbGVyLFxuICAgICAgbGF1bmNoVHlwZTogbGF1bmNoVHlwZSxcbiAgICAgIGVuYWJsZUV4ZWN1dGVDb21tYW5kOiBwcm9wcy5lbmFibGVFeGVjdXRlQ29tbWFuZCxcbiAgICAgIGNhcGFjaXR5UHJvdmlkZXJTdHJhdGVneTogcHJvcHMuY2FwYWNpdHlQcm92aWRlclN0cmF0ZWdpZXMsXG4gICAgICBoZWFsdGhDaGVja0dyYWNlUGVyaW9kU2Vjb25kczogdGhpcy5ldmFsdWF0ZUhlYWx0aEdyYWNlUGVyaW9kKHByb3BzLmhlYWx0aENoZWNrR3JhY2VQZXJpb2QpLFxuICAgICAgLyogcm9sZTogbmV2ZXIgc3BlY2lmaWVkLCBzdXBwbGFudGVkIGJ5IFNlcnZpY2UgTGlua2VkIFJvbGUgKi9cbiAgICAgIG5ldHdvcmtDb25maWd1cmF0aW9uOiBMYXp5LmFueSh7IHByb2R1Y2U6ICgpID0+IHRoaXMubmV0d29ya0NvbmZpZ3VyYXRpb24gfSwgeyBvbWl0RW1wdHlBcnJheTogdHJ1ZSB9KSxcbiAgICAgIHNlcnZpY2VSZWdpc3RyaWVzOiBMYXp5LmFueSh7IHByb2R1Y2U6ICgpID0+IHRoaXMuc2VydmljZVJlZ2lzdHJpZXMgfSwgeyBvbWl0RW1wdHlBcnJheTogdHJ1ZSB9KSxcbiAgICAgIC4uLmFkZGl0aW9uYWxQcm9wcyxcbiAgICB9KTtcblxuICAgIGlmIChwcm9wcy5kZXBsb3ltZW50Q29udHJvbGxlcj8udHlwZSA9PT0gRGVwbG95bWVudENvbnRyb2xsZXJUeXBlLkVYVEVSTkFMKSB7XG4gICAgICBBbm5vdGF0aW9ucy5vZih0aGlzKS5hZGRXYXJuaW5nKCd0YXNrRGVmaW5pdGlvbiBhbmQgbGF1bmNoVHlwZSBhcmUgYmxhbmtlZCBvdXQgd2hlbiB1c2luZyBleHRlcm5hbCBkZXBsb3ltZW50IGNvbnRyb2xsZXIuJyk7XG4gICAgfVxuXG4gICAgdGhpcy5zZXJ2aWNlQXJuID0gdGhpcy5nZXRSZXNvdXJjZUFybkF0dHJpYnV0ZSh0aGlzLnJlc291cmNlLnJlZiwge1xuICAgICAgc2VydmljZTogJ2VjcycsXG4gICAgICByZXNvdXJjZTogJ3NlcnZpY2UnLFxuICAgICAgcmVzb3VyY2VOYW1lOiBgJHtwcm9wcy5jbHVzdGVyLmNsdXN0ZXJOYW1lfS8ke3RoaXMucGh5c2ljYWxOYW1lfWAsXG4gICAgfSk7XG4gICAgdGhpcy5zZXJ2aWNlTmFtZSA9IHRoaXMuZ2V0UmVzb3VyY2VOYW1lQXR0cmlidXRlKHRoaXMucmVzb3VyY2UuYXR0ck5hbWUpO1xuXG4gICAgdGhpcy5jbHVzdGVyID0gcHJvcHMuY2x1c3RlcjtcblxuICAgIGlmIChwcm9wcy5jbG91ZE1hcE9wdGlvbnMpIHtcbiAgICAgIHRoaXMuZW5hYmxlQ2xvdWRNYXAocHJvcHMuY2xvdWRNYXBPcHRpb25zKTtcbiAgICB9XG5cbiAgICBpZiAocHJvcHMuZW5hYmxlRXhlY3V0ZUNvbW1hbmQpIHtcbiAgICAgIHRoaXMuZW5hYmxlRXhlY3V0ZUNvbW1hbmQoKTtcblxuICAgICAgY29uc3QgbG9nZ2luZyA9IHRoaXMuY2x1c3Rlci5leGVjdXRlQ29tbWFuZENvbmZpZ3VyYXRpb24/LmxvZ2dpbmcgPz8gRXhlY3V0ZUNvbW1hbmRMb2dnaW5nLkRFRkFVTFQ7XG5cbiAgICAgIGlmICh0aGlzLmNsdXN0ZXIuZXhlY3V0ZUNvbW1hbmRDb25maWd1cmF0aW9uPy5rbXNLZXkpIHtcbiAgICAgICAgdGhpcy5lbmFibGVFeGVjdXRlQ29tbWFuZEVuY3J5cHRpb24obG9nZ2luZyk7XG4gICAgICB9XG4gICAgICBpZiAobG9nZ2luZyAhPT0gRXhlY3V0ZUNvbW1hbmRMb2dnaW5nLk5PTkUpIHtcbiAgICAgICAgdGhpcy5leGVjdXRlQ29tbWFuZExvZ0NvbmZpZ3VyYXRpb24oKTtcbiAgICAgIH1cbiAgICB9XG4gICAgdGhpcy5ub2RlLmRlZmF1bHRDaGlsZCA9IHRoaXMucmVzb3VyY2U7XG4gIH1cblxuICAvKipcbiAgICogVGhlIENsb3VkTWFwIHNlcnZpY2UgY3JlYXRlZCBmb3IgdGhpcyBzZXJ2aWNlLCBpZiBhbnkuXG4gICAqL1xuICBwdWJsaWMgZ2V0IGNsb3VkTWFwU2VydmljZSgpOiBjbG91ZG1hcC5JU2VydmljZSB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuY2xvdWRtYXBTZXJ2aWNlO1xuICB9XG5cbiAgcHJpdmF0ZSBleGVjdXRlQ29tbWFuZExvZ0NvbmZpZ3VyYXRpb24oKSB7XG4gICAgY29uc3QgbG9nQ29uZmlndXJhdGlvbiA9IHRoaXMuY2x1c3Rlci5leGVjdXRlQ29tbWFuZENvbmZpZ3VyYXRpb24/LmxvZ0NvbmZpZ3VyYXRpb247XG4gICAgdGhpcy50YXNrRGVmaW5pdGlvbi5hZGRUb1Rhc2tSb2xlUG9saWN5KG5ldyBpYW0uUG9saWN5U3RhdGVtZW50KHtcbiAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgJ2xvZ3M6RGVzY3JpYmVMb2dHcm91cHMnLFxuICAgICAgXSxcbiAgICAgIHJlc291cmNlczogWycqJ10sXG4gICAgfSkpO1xuXG4gICAgY29uc3QgbG9nR3JvdXBBcm4gPSBsb2dDb25maWd1cmF0aW9uPy5jbG91ZFdhdGNoTG9nR3JvdXAgPyBgYXJuOiR7dGhpcy5zdGFjay5wYXJ0aXRpb259OmxvZ3M6JHt0aGlzLmVudi5yZWdpb259OiR7dGhpcy5lbnYuYWNjb3VudH06bG9nLWdyb3VwOiR7bG9nQ29uZmlndXJhdGlvbi5jbG91ZFdhdGNoTG9nR3JvdXAubG9nR3JvdXBOYW1lfToqYCA6ICcqJztcbiAgICB0aGlzLnRhc2tEZWZpbml0aW9uLmFkZFRvVGFza1JvbGVQb2xpY3kobmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgYWN0aW9uczogW1xuICAgICAgICAnbG9nczpDcmVhdGVMb2dTdHJlYW0nLFxuICAgICAgICAnbG9nczpEZXNjcmliZUxvZ1N0cmVhbXMnLFxuICAgICAgICAnbG9nczpQdXRMb2dFdmVudHMnLFxuICAgICAgXSxcbiAgICAgIHJlc291cmNlczogW2xvZ0dyb3VwQXJuXSxcbiAgICB9KSk7XG5cbiAgICBpZiAobG9nQ29uZmlndXJhdGlvbj8uczNCdWNrZXQ/LmJ1Y2tldE5hbWUpIHtcbiAgICAgIHRoaXMudGFza0RlZmluaXRpb24uYWRkVG9UYXNrUm9sZVBvbGljeShuZXcgaWFtLlBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgICAnczM6R2V0QnVja2V0TG9jYXRpb24nLFxuICAgICAgICBdLFxuICAgICAgICByZXNvdXJjZXM6IFsnKiddLFxuICAgICAgfSkpO1xuICAgICAgdGhpcy50YXNrRGVmaW5pdGlvbi5hZGRUb1Rhc2tSb2xlUG9saWN5KG5ldyBpYW0uUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgYWN0aW9uczogW1xuICAgICAgICAgICdzMzpQdXRPYmplY3QnLFxuICAgICAgICBdLFxuICAgICAgICByZXNvdXJjZXM6IFtgYXJuOiR7dGhpcy5zdGFjay5wYXJ0aXRpb259OnMzOjo6JHtsb2dDb25maWd1cmF0aW9uLnMzQnVja2V0LmJ1Y2tldE5hbWV9LypgXSxcbiAgICAgIH0pKTtcbiAgICAgIGlmIChsb2dDb25maWd1cmF0aW9uLnMzRW5jcnlwdGlvbkVuYWJsZWQpIHtcbiAgICAgICAgdGhpcy50YXNrRGVmaW5pdGlvbi5hZGRUb1Rhc2tSb2xlUG9saWN5KG5ldyBpYW0uUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgICBhY3Rpb25zOiBbXG4gICAgICAgICAgICAnczM6R2V0RW5jcnlwdGlvbkNvbmZpZ3VyYXRpb24nLFxuICAgICAgICAgIF0sXG4gICAgICAgICAgcmVzb3VyY2VzOiBbYGFybjoke3RoaXMuc3RhY2sucGFydGl0aW9ufTpzMzo6OiR7bG9nQ29uZmlndXJhdGlvbi5zM0J1Y2tldC5idWNrZXROYW1lfWBdLFxuICAgICAgICB9KSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBlbmFibGVFeGVjdXRlQ29tbWFuZEVuY3J5cHRpb24obG9nZ2luZzogRXhlY3V0ZUNvbW1hbmRMb2dnaW5nKSB7XG4gICAgdGhpcy50YXNrRGVmaW5pdGlvbi5hZGRUb1Rhc2tSb2xlUG9saWN5KG5ldyBpYW0uUG9saWN5U3RhdGVtZW50KHtcbiAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgJ2ttczpEZWNyeXB0JyxcbiAgICAgICAgJ2ttczpHZW5lcmF0ZURhdGFLZXknLFxuICAgICAgXSxcbiAgICAgIHJlc291cmNlczogW2Ake3RoaXMuY2x1c3Rlci5leGVjdXRlQ29tbWFuZENvbmZpZ3VyYXRpb24/Lmttc0tleT8ua2V5QXJufWBdLFxuICAgIH0pKTtcblxuICAgIHRoaXMuY2x1c3Rlci5leGVjdXRlQ29tbWFuZENvbmZpZ3VyYXRpb24/Lmttc0tleT8uYWRkVG9SZXNvdXJjZVBvbGljeShuZXcgaWFtLlBvbGljeVN0YXRlbWVudCh7XG4gICAgICBhY3Rpb25zOiBbXG4gICAgICAgICdrbXM6KicsXG4gICAgICBdLFxuICAgICAgcmVzb3VyY2VzOiBbJyonXSxcbiAgICAgIHByaW5jaXBhbHM6IFtuZXcgaWFtLkFyblByaW5jaXBhbChgYXJuOiR7dGhpcy5zdGFjay5wYXJ0aXRpb259OmlhbTo6JHt0aGlzLmVudi5hY2NvdW50fTpyb290YCldLFxuICAgIH0pKTtcblxuICAgIGlmIChsb2dnaW5nID09PSBFeGVjdXRlQ29tbWFuZExvZ2dpbmcuREVGQVVMVCB8fCB0aGlzLmNsdXN0ZXIuZXhlY3V0ZUNvbW1hbmRDb25maWd1cmF0aW9uPy5sb2dDb25maWd1cmF0aW9uPy5jbG91ZFdhdGNoRW5jcnlwdGlvbkVuYWJsZWQpIHtcbiAgICAgIHRoaXMuY2x1c3Rlci5leGVjdXRlQ29tbWFuZENvbmZpZ3VyYXRpb24/Lmttc0tleT8uYWRkVG9SZXNvdXJjZVBvbGljeShuZXcgaWFtLlBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgICAna21zOkVuY3J5cHQqJyxcbiAgICAgICAgICAna21zOkRlY3J5cHQqJyxcbiAgICAgICAgICAna21zOlJlRW5jcnlwdConLFxuICAgICAgICAgICdrbXM6R2VuZXJhdGVEYXRhS2V5KicsXG4gICAgICAgICAgJ2ttczpEZXNjcmliZSonLFxuICAgICAgICBdLFxuICAgICAgICByZXNvdXJjZXM6IFsnKiddLFxuICAgICAgICBwcmluY2lwYWxzOiBbbmV3IGlhbS5TZXJ2aWNlUHJpbmNpcGFsKGBsb2dzLiR7dGhpcy5lbnYucmVnaW9ufS5hbWF6b25hd3MuY29tYCldLFxuICAgICAgICBjb25kaXRpb25zOiB7XG4gICAgICAgICAgQXJuTGlrZTogeyAna21zOkVuY3J5cHRpb25Db250ZXh0OmF3czpsb2dzOmFybic6IGBhcm46JHt0aGlzLnN0YWNrLnBhcnRpdGlvbn06bG9nczoke3RoaXMuZW52LnJlZ2lvbn06JHt0aGlzLmVudi5hY2NvdW50fToqYCB9LFxuICAgICAgICB9LFxuICAgICAgfSkpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBUaGlzIG1ldGhvZCBpcyBjYWxsZWQgdG8gYXR0YWNoIHRoaXMgc2VydmljZSB0byBhbiBBcHBsaWNhdGlvbiBMb2FkIEJhbGFuY2VyLlxuICAgKlxuICAgKiBEb24ndCBjYWxsIHRoaXMgZnVuY3Rpb24gZGlyZWN0bHkuIEluc3RlYWQsIGNhbGwgYGxpc3RlbmVyLmFkZFRhcmdldHMoKWBcbiAgICogdG8gYWRkIHRoaXMgc2VydmljZSB0byBhIGxvYWQgYmFsYW5jZXIuXG4gICAqL1xuICBwdWJsaWMgYXR0YWNoVG9BcHBsaWNhdGlvblRhcmdldEdyb3VwKHRhcmdldEdyb3VwOiBlbGJ2Mi5JQXBwbGljYXRpb25UYXJnZXRHcm91cCk6IGVsYnYyLkxvYWRCYWxhbmNlclRhcmdldFByb3BzIHtcbiAgICByZXR1cm4gdGhpcy5kZWZhdWx0TG9hZEJhbGFuY2VyVGFyZ2V0LmF0dGFjaFRvQXBwbGljYXRpb25UYXJnZXRHcm91cCh0YXJnZXRHcm91cCk7XG4gIH1cblxuICAvKipcbiAgICogUmVnaXN0ZXJzIHRoZSBzZXJ2aWNlIGFzIGEgdGFyZ2V0IG9mIGEgQ2xhc3NpYyBMb2FkIEJhbGFuY2VyIChDTEIpLlxuICAgKlxuICAgKiBEb24ndCBjYWxsIHRoaXMuIENhbGwgYGxvYWRCYWxhbmNlci5hZGRUYXJnZXQoKWAgaW5zdGVhZC5cbiAgICovXG4gIHB1YmxpYyBhdHRhY2hUb0NsYXNzaWNMQihsb2FkQmFsYW5jZXI6IGVsYi5Mb2FkQmFsYW5jZXIpOiB2b2lkIHtcbiAgICByZXR1cm4gdGhpcy5kZWZhdWx0TG9hZEJhbGFuY2VyVGFyZ2V0LmF0dGFjaFRvQ2xhc3NpY0xCKGxvYWRCYWxhbmNlcik7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJuIGEgbG9hZCBiYWxhbmNpbmcgdGFyZ2V0IGZvciBhIHNwZWNpZmljIGNvbnRhaW5lciBhbmQgcG9ydC5cbiAgICpcbiAgICogVXNlIHRoaXMgZnVuY3Rpb24gdG8gY3JlYXRlIGEgbG9hZCBiYWxhbmNlciB0YXJnZXQgaWYgeW91IHdhbnQgdG8gbG9hZCBiYWxhbmNlIHRvXG4gICAqIGFub3RoZXIgY29udGFpbmVyIHRoYW4gdGhlIGZpcnN0IGVzc2VudGlhbCBjb250YWluZXIgb3IgdGhlIGZpcnN0IG1hcHBlZCBwb3J0IG9uXG4gICAqIHRoZSBjb250YWluZXIuXG4gICAqXG4gICAqIFVzZSB0aGUgcmV0dXJuIHZhbHVlIG9mIHRoaXMgZnVuY3Rpb24gd2hlcmUgeW91IHdvdWxkIG5vcm1hbGx5IHVzZSBhIGxvYWQgYmFsYW5jZXJcbiAgICogdGFyZ2V0LCBpbnN0ZWFkIG9mIHRoZSBgU2VydmljZWAgb2JqZWN0IGl0c2VsZi5cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogZGVjbGFyZSBjb25zdCBsaXN0ZW5lcjogZWxidjIuQXBwbGljYXRpb25MaXN0ZW5lcjtcbiAgICogZGVjbGFyZSBjb25zdCBzZXJ2aWNlOiBlY3MuQmFzZVNlcnZpY2U7XG4gICAqIGxpc3RlbmVyLmFkZFRhcmdldHMoJ0VDUycsIHtcbiAgICogICBwb3J0OiA4MCxcbiAgICogICB0YXJnZXRzOiBbc2VydmljZS5sb2FkQmFsYW5jZXJUYXJnZXQoe1xuICAgKiAgICAgY29udGFpbmVyTmFtZTogJ015Q29udGFpbmVyJyxcbiAgICogICAgIGNvbnRhaW5lclBvcnQ6IDEyMzQsXG4gICAqICAgfSldLFxuICAgKiB9KTtcbiAgICovXG4gIHB1YmxpYyBsb2FkQmFsYW5jZXJUYXJnZXQob3B0aW9uczogTG9hZEJhbGFuY2VyVGFyZ2V0T3B0aW9ucyk6IElFY3NMb2FkQmFsYW5jZXJUYXJnZXQge1xuICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgIGNvbnN0IHRhcmdldCA9IHRoaXMudGFza0RlZmluaXRpb24uX3ZhbGlkYXRlVGFyZ2V0KG9wdGlvbnMpO1xuICAgIGNvbnN0IGNvbm5lY3Rpb25zID0gc2VsZi5jb25uZWN0aW9ucztcbiAgICByZXR1cm4ge1xuICAgICAgYXR0YWNoVG9BcHBsaWNhdGlvblRhcmdldEdyb3VwKHRhcmdldEdyb3VwOiBlbGJ2Mi5BcHBsaWNhdGlvblRhcmdldEdyb3VwKTogZWxidjIuTG9hZEJhbGFuY2VyVGFyZ2V0UHJvcHMge1xuICAgICAgICB0YXJnZXRHcm91cC5yZWdpc3RlckNvbm5lY3RhYmxlKHNlbGYsIHNlbGYudGFza0RlZmluaXRpb24uX3BvcnRSYW5nZUZyb21Qb3J0TWFwcGluZyh0YXJnZXQucG9ydE1hcHBpbmcpKTtcbiAgICAgICAgcmV0dXJuIHNlbGYuYXR0YWNoVG9FTEJ2Mih0YXJnZXRHcm91cCwgdGFyZ2V0LmNvbnRhaW5lck5hbWUsIHRhcmdldC5wb3J0TWFwcGluZy5jb250YWluZXJQb3J0KTtcbiAgICAgIH0sXG4gICAgICBhdHRhY2hUb05ldHdvcmtUYXJnZXRHcm91cCh0YXJnZXRHcm91cDogZWxidjIuTmV0d29ya1RhcmdldEdyb3VwKTogZWxidjIuTG9hZEJhbGFuY2VyVGFyZ2V0UHJvcHMge1xuICAgICAgICByZXR1cm4gc2VsZi5hdHRhY2hUb0VMQnYyKHRhcmdldEdyb3VwLCB0YXJnZXQuY29udGFpbmVyTmFtZSwgdGFyZ2V0LnBvcnRNYXBwaW5nLmNvbnRhaW5lclBvcnQpO1xuICAgICAgfSxcbiAgICAgIGNvbm5lY3Rpb25zLFxuICAgICAgYXR0YWNoVG9DbGFzc2ljTEIobG9hZEJhbGFuY2VyOiBlbGIuTG9hZEJhbGFuY2VyKTogdm9pZCB7XG4gICAgICAgIHJldHVybiBzZWxmLmF0dGFjaFRvRUxCKGxvYWRCYWxhbmNlciwgdGFyZ2V0LmNvbnRhaW5lck5hbWUsIHRhcmdldC5wb3J0TWFwcGluZy5jb250YWluZXJQb3J0KTtcbiAgICAgIH0sXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBVc2UgdGhpcyBmdW5jdGlvbiB0byBjcmVhdGUgYWxsIGxvYWQgYmFsYW5jZXIgdGFyZ2V0cyB0byBiZSByZWdpc3RlcmVkIGluIHRoaXMgc2VydmljZSwgYWRkIHRoZW0gdG9cbiAgICogdGFyZ2V0IGdyb3VwcywgYW5kIGF0dGFjaCB0YXJnZXQgZ3JvdXBzIHRvIGxpc3RlbmVycyBhY2NvcmRpbmdseS5cbiAgICpcbiAgICogQWx0ZXJuYXRpdmVseSwgeW91IGNhbiB1c2UgYGxpc3RlbmVyLmFkZFRhcmdldHMoKWAgdG8gY3JlYXRlIHRhcmdldHMgYW5kIGFkZCB0aGVtIHRvIHRhcmdldCBncm91cHMuXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqIGRlY2xhcmUgY29uc3QgbGlzdGVuZXI6IGVsYnYyLkFwcGxpY2F0aW9uTGlzdGVuZXI7XG4gICAqIGRlY2xhcmUgY29uc3Qgc2VydmljZTogZWNzLkJhc2VTZXJ2aWNlO1xuICAgKiBzZXJ2aWNlLnJlZ2lzdGVyTG9hZEJhbGFuY2VyVGFyZ2V0cyhcbiAgICogICB7XG4gICAqICAgICBjb250YWluZXJOYW1lOiAnd2ViJyxcbiAgICogICAgIGNvbnRhaW5lclBvcnQ6IDgwLFxuICAgKiAgICAgbmV3VGFyZ2V0R3JvdXBJZDogJ0VDUycsXG4gICAqICAgICBsaXN0ZW5lcjogZWNzLkxpc3RlbmVyQ29uZmlnLmFwcGxpY2F0aW9uTGlzdGVuZXIobGlzdGVuZXIsIHtcbiAgICogICAgICAgcHJvdG9jb2w6IGVsYnYyLkFwcGxpY2F0aW9uUHJvdG9jb2wuSFRUUFNcbiAgICogICAgIH0pLFxuICAgKiAgIH0sXG4gICAqIClcbiAgICovXG4gIHB1YmxpYyByZWdpc3RlckxvYWRCYWxhbmNlclRhcmdldHMoLi4udGFyZ2V0czogRWNzVGFyZ2V0W10pIHtcbiAgICBmb3IgKGNvbnN0IHRhcmdldCBvZiB0YXJnZXRzKSB7XG4gICAgICB0YXJnZXQubGlzdGVuZXIuYWRkVGFyZ2V0cyh0YXJnZXQubmV3VGFyZ2V0R3JvdXBJZCwge1xuICAgICAgICBjb250YWluZXJOYW1lOiB0YXJnZXQuY29udGFpbmVyTmFtZSxcbiAgICAgICAgY29udGFpbmVyUG9ydDogdGFyZ2V0LmNvbnRhaW5lclBvcnQsXG4gICAgICAgIHByb3RvY29sOiB0YXJnZXQucHJvdG9jb2wsXG4gICAgICB9LCB0aGlzKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogVGhpcyBtZXRob2QgaXMgY2FsbGVkIHRvIGF0dGFjaCB0aGlzIHNlcnZpY2UgdG8gYSBOZXR3b3JrIExvYWQgQmFsYW5jZXIuXG4gICAqXG4gICAqIERvbid0IGNhbGwgdGhpcyBmdW5jdGlvbiBkaXJlY3RseS4gSW5zdGVhZCwgY2FsbCBgbGlzdGVuZXIuYWRkVGFyZ2V0cygpYFxuICAgKiB0byBhZGQgdGhpcyBzZXJ2aWNlIHRvIGEgbG9hZCBiYWxhbmNlci5cbiAgICovXG4gIHB1YmxpYyBhdHRhY2hUb05ldHdvcmtUYXJnZXRHcm91cCh0YXJnZXRHcm91cDogZWxidjIuSU5ldHdvcmtUYXJnZXRHcm91cCk6IGVsYnYyLkxvYWRCYWxhbmNlclRhcmdldFByb3BzIHtcbiAgICByZXR1cm4gdGhpcy5kZWZhdWx0TG9hZEJhbGFuY2VyVGFyZ2V0LmF0dGFjaFRvTmV0d29ya1RhcmdldEdyb3VwKHRhcmdldEdyb3VwKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBbiBhdHRyaWJ1dGUgcmVwcmVzZW50aW5nIHRoZSBtaW5pbXVtIGFuZCBtYXhpbXVtIHRhc2sgY291bnQgZm9yIGFuIEF1dG9TY2FsaW5nR3JvdXAuXG4gICAqL1xuICBwdWJsaWMgYXV0b1NjYWxlVGFza0NvdW50KHByb3BzOiBhcHBzY2FsaW5nLkVuYWJsZVNjYWxpbmdQcm9wcykge1xuICAgIGlmICh0aGlzLnNjYWxhYmxlVGFza0NvdW50KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0F1dG9TY2FsaW5nIG9mIHRhc2sgY291bnQgYWxyZWFkeSBlbmFibGVkIGZvciB0aGlzIHNlcnZpY2UnKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5zY2FsYWJsZVRhc2tDb3VudCA9IG5ldyBTY2FsYWJsZVRhc2tDb3VudCh0aGlzLCAnVGFza0NvdW50Jywge1xuICAgICAgc2VydmljZU5hbWVzcGFjZTogYXBwc2NhbGluZy5TZXJ2aWNlTmFtZXNwYWNlLkVDUyxcbiAgICAgIHJlc291cmNlSWQ6IGBzZXJ2aWNlLyR7dGhpcy5jbHVzdGVyLmNsdXN0ZXJOYW1lfS8ke3RoaXMuc2VydmljZU5hbWV9YCxcbiAgICAgIGRpbWVuc2lvbjogJ2VjczpzZXJ2aWNlOkRlc2lyZWRDb3VudCcsXG4gICAgICByb2xlOiB0aGlzLm1ha2VBdXRvU2NhbGluZ1JvbGUoKSxcbiAgICAgIC4uLnByb3BzLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEVuYWJsZSBDbG91ZE1hcCBzZXJ2aWNlIGRpc2NvdmVyeSBmb3IgdGhlIHNlcnZpY2VcbiAgICpcbiAgICogQHJldHVybnMgVGhlIGNyZWF0ZWQgQ2xvdWRNYXAgc2VydmljZVxuICAgKi9cbiAgcHVibGljIGVuYWJsZUNsb3VkTWFwKG9wdGlvbnM6IENsb3VkTWFwT3B0aW9ucyk6IGNsb3VkbWFwLlNlcnZpY2Uge1xuICAgIGNvbnN0IHNkTmFtZXNwYWNlID0gb3B0aW9ucy5jbG91ZE1hcE5hbWVzcGFjZSA/PyB0aGlzLmNsdXN0ZXIuZGVmYXVsdENsb3VkTWFwTmFtZXNwYWNlO1xuICAgIGlmIChzZE5hbWVzcGFjZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Nhbm5vdCBlbmFibGUgc2VydmljZSBkaXNjb3ZlcnkgaWYgYSBDbG91ZG1hcCBOYW1lc3BhY2UgaGFzIG5vdCBiZWVuIGNyZWF0ZWQgaW4gdGhlIGNsdXN0ZXIuJyk7XG4gICAgfVxuXG4gICAgLy8gRGV0ZXJtaW5lIEROUyB0eXBlIGJhc2VkIG9uIG5ldHdvcmsgbW9kZVxuICAgIGNvbnN0IG5ldHdvcmtNb2RlID0gdGhpcy50YXNrRGVmaW5pdGlvbi5uZXR3b3JrTW9kZTtcbiAgICBpZiAobmV0d29ya01vZGUgPT09IE5ldHdvcmtNb2RlLk5PTkUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQ2Fubm90IHVzZSBhIHNlcnZpY2UgZGlzY292ZXJ5IGlmIE5ldHdvcmtNb2RlIGlzIE5vbmUuIFVzZSBCcmlkZ2UsIEhvc3Qgb3IgQXdzVnBjIGluc3RlYWQuJyk7XG4gICAgfVxuXG4gICAgLy8gQnJpZGdlIG9yIGhvc3QgbmV0d29yayBtb2RlIHJlcXVpcmVzIFNSViByZWNvcmRzXG4gICAgbGV0IGRuc1JlY29yZFR5cGUgPSBvcHRpb25zLmRuc1JlY29yZFR5cGU7XG5cbiAgICBpZiAobmV0d29ya01vZGUgPT09IE5ldHdvcmtNb2RlLkJSSURHRSB8fCBuZXR3b3JrTW9kZSA9PT0gTmV0d29ya01vZGUuSE9TVCkge1xuICAgICAgaWYgKGRuc1JlY29yZFR5cGUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICBkbnNSZWNvcmRUeXBlID0gY2xvdWRtYXAuRG5zUmVjb3JkVHlwZS5TUlY7XG4gICAgICB9XG4gICAgICBpZiAoZG5zUmVjb3JkVHlwZSAhPT0gY2xvdWRtYXAuRG5zUmVjb3JkVHlwZS5TUlYpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdTUlYgcmVjb3JkcyBtdXN0IGJlIHVzZWQgd2hlbiBuZXR3b3JrIG1vZGUgaXMgQnJpZGdlIG9yIEhvc3QuJyk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gRGVmYXVsdCBETlMgcmVjb3JkIHR5cGUgZm9yIEF3c1ZwYyBuZXR3b3JrIG1vZGUgaXMgQSBSZWNvcmRzXG4gICAgaWYgKG5ldHdvcmtNb2RlID09PSBOZXR3b3JrTW9kZS5BV1NfVlBDKSB7XG4gICAgICBpZiAoZG5zUmVjb3JkVHlwZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGRuc1JlY29yZFR5cGUgPSBjbG91ZG1hcC5EbnNSZWNvcmRUeXBlLkE7XG4gICAgICB9XG4gICAgfVxuXG4gICAgY29uc3QgeyBjb250YWluZXJOYW1lLCBjb250YWluZXJQb3J0IH0gPSBkZXRlcm1pbmVDb250YWluZXJOYW1lQW5kUG9ydCh7XG4gICAgICB0YXNrRGVmaW5pdGlvbjogdGhpcy50YXNrRGVmaW5pdGlvbixcbiAgICAgIGRuc1JlY29yZFR5cGU6IGRuc1JlY29yZFR5cGUhLFxuICAgICAgY29udGFpbmVyOiBvcHRpb25zLmNvbnRhaW5lcixcbiAgICAgIGNvbnRhaW5lclBvcnQ6IG9wdGlvbnMuY29udGFpbmVyUG9ydCxcbiAgICB9KTtcblxuICAgIGNvbnN0IGNsb3VkbWFwU2VydmljZSA9IG5ldyBjbG91ZG1hcC5TZXJ2aWNlKHRoaXMsICdDbG91ZG1hcFNlcnZpY2UnLCB7XG4gICAgICBuYW1lc3BhY2U6IHNkTmFtZXNwYWNlLFxuICAgICAgbmFtZTogb3B0aW9ucy5uYW1lLFxuICAgICAgZG5zUmVjb3JkVHlwZTogZG5zUmVjb3JkVHlwZSEsXG4gICAgICBjdXN0b21IZWFsdGhDaGVjazogeyBmYWlsdXJlVGhyZXNob2xkOiBvcHRpb25zLmZhaWx1cmVUaHJlc2hvbGQgfHwgMSB9LFxuICAgICAgZG5zVHRsOiBvcHRpb25zLmRuc1R0bCxcbiAgICB9KTtcblxuICAgIGNvbnN0IHNlcnZpY2VBcm4gPSBjbG91ZG1hcFNlcnZpY2Uuc2VydmljZUFybjtcblxuICAgIC8vIGFkZCBDbG91ZG1hcCBzZXJ2aWNlIHRvIHRoZSBFQ1MgU2VydmljZSdzIHNlcnZpY2VSZWdpc3RyeVxuICAgIHRoaXMuYWRkU2VydmljZVJlZ2lzdHJ5KHtcbiAgICAgIGFybjogc2VydmljZUFybixcbiAgICAgIGNvbnRhaW5lck5hbWUsXG4gICAgICBjb250YWluZXJQb3J0LFxuICAgIH0pO1xuXG4gICAgdGhpcy5jbG91ZG1hcFNlcnZpY2UgPSBjbG91ZG1hcFNlcnZpY2U7XG5cbiAgICByZXR1cm4gY2xvdWRtYXBTZXJ2aWNlO1xuICB9XG5cbiAgLyoqXG4gICAqIEFzc29jaWF0ZXMgdGhpcyBzZXJ2aWNlIHdpdGggYSBDbG91ZE1hcCBzZXJ2aWNlXG4gICAqL1xuICBwdWJsaWMgYXNzb2NpYXRlQ2xvdWRNYXBTZXJ2aWNlKG9wdGlvbnM6IEFzc29jaWF0ZUNsb3VkTWFwU2VydmljZU9wdGlvbnMpOiB2b2lkIHtcbiAgICBjb25zdCBzZXJ2aWNlID0gb3B0aW9ucy5zZXJ2aWNlO1xuXG4gICAgY29uc3QgeyBjb250YWluZXJOYW1lLCBjb250YWluZXJQb3J0IH0gPSBkZXRlcm1pbmVDb250YWluZXJOYW1lQW5kUG9ydCh7XG4gICAgICB0YXNrRGVmaW5pdGlvbjogdGhpcy50YXNrRGVmaW5pdGlvbixcbiAgICAgIGRuc1JlY29yZFR5cGU6IHNlcnZpY2UuZG5zUmVjb3JkVHlwZSxcbiAgICAgIGNvbnRhaW5lcjogb3B0aW9ucy5jb250YWluZXIsXG4gICAgICBjb250YWluZXJQb3J0OiBvcHRpb25zLmNvbnRhaW5lclBvcnQsXG4gICAgfSk7XG5cbiAgICAvLyBhZGQgQ2xvdWRtYXAgc2VydmljZSB0byB0aGUgRUNTIFNlcnZpY2UncyBzZXJ2aWNlUmVnaXN0cnlcbiAgICB0aGlzLmFkZFNlcnZpY2VSZWdpc3RyeSh7XG4gICAgICBhcm46IHNlcnZpY2Uuc2VydmljZUFybixcbiAgICAgIGNvbnRhaW5lck5hbWUsXG4gICAgICBjb250YWluZXJQb3J0LFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoaXMgbWV0aG9kIHJldHVybnMgdGhlIHNwZWNpZmllZCBDbG91ZFdhdGNoIG1ldHJpYyBuYW1lIGZvciB0aGlzIHNlcnZpY2UuXG4gICAqL1xuICBwdWJsaWMgbWV0cmljKG1ldHJpY05hbWU6IHN0cmluZywgcHJvcHM/OiBjbG91ZHdhdGNoLk1ldHJpY09wdGlvbnMpOiBjbG91ZHdhdGNoLk1ldHJpYyB7XG4gICAgcmV0dXJuIG5ldyBjbG91ZHdhdGNoLk1ldHJpYyh7XG4gICAgICBuYW1lc3BhY2U6ICdBV1MvRUNTJyxcbiAgICAgIG1ldHJpY05hbWUsXG4gICAgICBkaW1lbnNpb25zTWFwOiB7IENsdXN0ZXJOYW1lOiB0aGlzLmNsdXN0ZXIuY2x1c3Rlck5hbWUsIFNlcnZpY2VOYW1lOiB0aGlzLnNlcnZpY2VOYW1lIH0sXG4gICAgICAuLi5wcm9wcyxcbiAgICB9KS5hdHRhY2hUbyh0aGlzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGlzIG1ldGhvZCByZXR1cm5zIHRoZSBDbG91ZFdhdGNoIG1ldHJpYyBmb3IgdGhpcyBzZXJ2aWNlJ3MgbWVtb3J5IHV0aWxpemF0aW9uLlxuICAgKlxuICAgKiBAZGVmYXVsdCBhdmVyYWdlIG92ZXIgNSBtaW51dGVzXG4gICAqL1xuICBwdWJsaWMgbWV0cmljTWVtb3J5VXRpbGl6YXRpb24ocHJvcHM/OiBjbG91ZHdhdGNoLk1ldHJpY09wdGlvbnMpOiBjbG91ZHdhdGNoLk1ldHJpYyB7XG4gICAgcmV0dXJuIHRoaXMubWV0cmljKCdNZW1vcnlVdGlsaXphdGlvbicsIHByb3BzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGlzIG1ldGhvZCByZXR1cm5zIHRoZSBDbG91ZFdhdGNoIG1ldHJpYyBmb3IgdGhpcyBzZXJ2aWNlJ3MgQ1BVIHV0aWxpemF0aW9uLlxuICAgKlxuICAgKiBAZGVmYXVsdCBhdmVyYWdlIG92ZXIgNSBtaW51dGVzXG4gICAqL1xuICBwdWJsaWMgbWV0cmljQ3B1VXRpbGl6YXRpb24ocHJvcHM/OiBjbG91ZHdhdGNoLk1ldHJpY09wdGlvbnMpOiBjbG91ZHdhdGNoLk1ldHJpYyB7XG4gICAgcmV0dXJuIHRoaXMubWV0cmljKCdDUFVVdGlsaXphdGlvbicsIHByb3BzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGlzIG1ldGhvZCBpcyBjYWxsZWQgdG8gY3JlYXRlIGEgbmV0d29ya0NvbmZpZ3VyYXRpb24uXG4gICAqIEBkZXByZWNhdGVkIHVzZSBjb25maWd1cmVBd3NWcGNOZXR3b3JraW5nV2l0aFNlY3VyaXR5R3JvdXBzIGluc3RlYWQuXG4gICAqL1xuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbWF4LWxlblxuICBwcm90ZWN0ZWQgY29uZmlndXJlQXdzVnBjTmV0d29ya2luZyh2cGM6IGVjMi5JVnBjLCBhc3NpZ25QdWJsaWNJcD86IGJvb2xlYW4sIHZwY1N1Ym5ldHM/OiBlYzIuU3VibmV0U2VsZWN0aW9uLCBzZWN1cml0eUdyb3VwPzogZWMyLklTZWN1cml0eUdyb3VwKSB7XG4gICAgaWYgKHZwY1N1Ym5ldHMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgdnBjU3VibmV0cyA9IGFzc2lnblB1YmxpY0lwID8geyBzdWJuZXRUeXBlOiBlYzIuU3VibmV0VHlwZS5QVUJMSUMgfSA6IHt9O1xuICAgIH1cbiAgICBpZiAoc2VjdXJpdHlHcm91cCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICBzZWN1cml0eUdyb3VwID0gbmV3IGVjMi5TZWN1cml0eUdyb3VwKHRoaXMsICdTZWN1cml0eUdyb3VwJywgeyB2cGMgfSk7XG4gICAgfVxuICAgIHRoaXMuY29ubmVjdGlvbnMuYWRkU2VjdXJpdHlHcm91cChzZWN1cml0eUdyb3VwKTtcblxuICAgIHRoaXMubmV0d29ya0NvbmZpZ3VyYXRpb24gPSB7XG4gICAgICBhd3N2cGNDb25maWd1cmF0aW9uOiB7XG4gICAgICAgIGFzc2lnblB1YmxpY0lwOiBhc3NpZ25QdWJsaWNJcCA/ICdFTkFCTEVEJyA6ICdESVNBQkxFRCcsXG4gICAgICAgIHN1Ym5ldHM6IHZwYy5zZWxlY3RTdWJuZXRzKHZwY1N1Ym5ldHMpLnN1Ym5ldElkcyxcbiAgICAgICAgc2VjdXJpdHlHcm91cHM6IExhenkubGlzdCh7IHByb2R1Y2U6ICgpID0+IFtzZWN1cml0eUdyb3VwIS5zZWN1cml0eUdyb3VwSWRdIH0pLFxuICAgICAgfSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFRoaXMgbWV0aG9kIGlzIGNhbGxlZCB0byBjcmVhdGUgYSBuZXR3b3JrQ29uZmlndXJhdGlvbi5cbiAgICovXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBtYXgtbGVuXG4gIHByb3RlY3RlZCBjb25maWd1cmVBd3NWcGNOZXR3b3JraW5nV2l0aFNlY3VyaXR5R3JvdXBzKHZwYzogZWMyLklWcGMsIGFzc2lnblB1YmxpY0lwPzogYm9vbGVhbiwgdnBjU3VibmV0cz86IGVjMi5TdWJuZXRTZWxlY3Rpb24sIHNlY3VyaXR5R3JvdXBzPzogZWMyLklTZWN1cml0eUdyb3VwW10pIHtcbiAgICBpZiAodnBjU3VibmV0cyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB2cGNTdWJuZXRzID0gYXNzaWduUHVibGljSXAgPyB7IHN1Ym5ldFR5cGU6IGVjMi5TdWJuZXRUeXBlLlBVQkxJQyB9IDoge307XG4gICAgfVxuICAgIGlmIChzZWN1cml0eUdyb3VwcyA9PT0gdW5kZWZpbmVkIHx8IHNlY3VyaXR5R3JvdXBzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgc2VjdXJpdHlHcm91cHMgPSBbbmV3IGVjMi5TZWN1cml0eUdyb3VwKHRoaXMsICdTZWN1cml0eUdyb3VwJywgeyB2cGMgfSldO1xuICAgIH1cblxuICAgIHNlY3VyaXR5R3JvdXBzLmZvckVhY2goKHNnKSA9PiB7IHRoaXMuY29ubmVjdGlvbnMuYWRkU2VjdXJpdHlHcm91cChzZyk7IH0sIHRoaXMpO1xuXG4gICAgdGhpcy5uZXR3b3JrQ29uZmlndXJhdGlvbiA9IHtcbiAgICAgIGF3c3ZwY0NvbmZpZ3VyYXRpb246IHtcbiAgICAgICAgYXNzaWduUHVibGljSXA6IGFzc2lnblB1YmxpY0lwID8gJ0VOQUJMRUQnIDogJ0RJU0FCTEVEJyxcbiAgICAgICAgc3VibmV0czogdnBjLnNlbGVjdFN1Ym5ldHModnBjU3VibmV0cykuc3VibmV0SWRzLFxuICAgICAgICBzZWN1cml0eUdyb3Vwczogc2VjdXJpdHlHcm91cHMubWFwKChzZykgPT4gc2cuc2VjdXJpdHlHcm91cElkKSxcbiAgICAgIH0sXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgcmVuZGVyU2VydmljZVJlZ2lzdHJ5KHJlZ2lzdHJ5OiBTZXJ2aWNlUmVnaXN0cnkpOiBDZm5TZXJ2aWNlLlNlcnZpY2VSZWdpc3RyeVByb3BlcnR5IHtcbiAgICByZXR1cm4ge1xuICAgICAgcmVnaXN0cnlBcm46IHJlZ2lzdHJ5LmFybixcbiAgICAgIGNvbnRhaW5lck5hbWU6IHJlZ2lzdHJ5LmNvbnRhaW5lck5hbWUsXG4gICAgICBjb250YWluZXJQb3J0OiByZWdpc3RyeS5jb250YWluZXJQb3J0LFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogU2hhcmVkIGxvZ2ljIGZvciBhdHRhY2hpbmcgdG8gYW4gRUxCXG4gICAqL1xuICBwcml2YXRlIGF0dGFjaFRvRUxCKGxvYWRCYWxhbmNlcjogZWxiLkxvYWRCYWxhbmNlciwgY29udGFpbmVyTmFtZTogc3RyaW5nLCBjb250YWluZXJQb3J0OiBudW1iZXIpOiB2b2lkIHtcbiAgICBpZiAodGhpcy50YXNrRGVmaW5pdGlvbi5uZXR3b3JrTW9kZSA9PT0gTmV0d29ya01vZGUuQVdTX1ZQQykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdDYW5ub3QgdXNlIGEgQ2xhc3NpYyBMb2FkIEJhbGFuY2VyIGlmIE5ldHdvcmtNb2RlIGlzIEF3c1ZwYy4gVXNlIEhvc3Qgb3IgQnJpZGdlIGluc3RlYWQuJyk7XG4gICAgfVxuICAgIGlmICh0aGlzLnRhc2tEZWZpbml0aW9uLm5ldHdvcmtNb2RlID09PSBOZXR3b3JrTW9kZS5OT05FKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Nhbm5vdCB1c2UgYSBDbGFzc2ljIExvYWQgQmFsYW5jZXIgaWYgTmV0d29ya01vZGUgaXMgTm9uZS4gVXNlIEhvc3Qgb3IgQnJpZGdlIGluc3RlYWQuJyk7XG4gICAgfVxuXG4gICAgdGhpcy5sb2FkQmFsYW5jZXJzLnB1c2goe1xuICAgICAgbG9hZEJhbGFuY2VyTmFtZTogbG9hZEJhbGFuY2VyLmxvYWRCYWxhbmNlck5hbWUsXG4gICAgICBjb250YWluZXJOYW1lLFxuICAgICAgY29udGFpbmVyUG9ydCxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTaGFyZWQgbG9naWMgZm9yIGF0dGFjaGluZyB0byBhbiBFTEJ2MlxuICAgKi9cbiAgcHJpdmF0ZSBhdHRhY2hUb0VMQnYyKHRhcmdldEdyb3VwOiBlbGJ2Mi5JVGFyZ2V0R3JvdXAsIGNvbnRhaW5lck5hbWU6IHN0cmluZywgY29udGFpbmVyUG9ydDogbnVtYmVyKTogZWxidjIuTG9hZEJhbGFuY2VyVGFyZ2V0UHJvcHMge1xuICAgIGlmICh0aGlzLnRhc2tEZWZpbml0aW9uLm5ldHdvcmtNb2RlID09PSBOZXR3b3JrTW9kZS5OT05FKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Nhbm5vdCB1c2UgYSBsb2FkIGJhbGFuY2VyIGlmIE5ldHdvcmtNb2RlIGlzIE5vbmUuIFVzZSBCcmlkZ2UsIEhvc3Qgb3IgQXdzVnBjIGluc3RlYWQuJyk7XG4gICAgfVxuXG4gICAgdGhpcy5sb2FkQmFsYW5jZXJzLnB1c2goe1xuICAgICAgdGFyZ2V0R3JvdXBBcm46IHRhcmdldEdyb3VwLnRhcmdldEdyb3VwQXJuLFxuICAgICAgY29udGFpbmVyTmFtZSxcbiAgICAgIGNvbnRhaW5lclBvcnQsXG4gICAgfSk7XG5cbiAgICAvLyBTZXJ2aWNlIGNyZWF0aW9uIGNhbiBvbmx5IGhhcHBlbiBhZnRlciB0aGUgbG9hZCBiYWxhbmNlciBoYXNcbiAgICAvLyBiZWVuIGFzc29jaWF0ZWQgd2l0aCBvdXIgdGFyZ2V0IGdyb3VwKHMpLCBzbyBhZGQgb3JkZXJpbmcgZGVwZW5kZW5jeS5cbiAgICB0aGlzLnJlc291cmNlLm5vZGUuYWRkRGVwZW5kZW5jeSh0YXJnZXRHcm91cC5sb2FkQmFsYW5jZXJBdHRhY2hlZCk7XG5cbiAgICBjb25zdCB0YXJnZXRUeXBlID0gdGhpcy50YXNrRGVmaW5pdGlvbi5uZXR3b3JrTW9kZSA9PT0gTmV0d29ya01vZGUuQVdTX1ZQQyA/IGVsYnYyLlRhcmdldFR5cGUuSVAgOiBlbGJ2Mi5UYXJnZXRUeXBlLklOU1RBTkNFO1xuICAgIHJldHVybiB7IHRhcmdldFR5cGUgfTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0IGRlZmF1bHRMb2FkQmFsYW5jZXJUYXJnZXQoKSB7XG4gICAgcmV0dXJuIHRoaXMubG9hZEJhbGFuY2VyVGFyZ2V0KHtcbiAgICAgIGNvbnRhaW5lck5hbWU6IHRoaXMudGFza0RlZmluaXRpb24uZGVmYXVsdENvbnRhaW5lciEuY29udGFpbmVyTmFtZSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZSB0aGUgcm9sZSB0aGF0IHdpbGwgYmUgdXNlZCBmb3IgYXV0b3NjYWxpbmcgdGhpcyBzZXJ2aWNlXG4gICAqL1xuICBwcml2YXRlIG1ha2VBdXRvU2NhbGluZ1JvbGUoKTogaWFtLklSb2xlIHtcbiAgICAvLyBVc2UgYSBTZXJ2aWNlIExpbmtlZCBSb2xlLlxuICAgIHJldHVybiBpYW0uUm9sZS5mcm9tUm9sZUFybih0aGlzLCAnU2NhbGluZ1JvbGUnLCBTdGFjay5vZih0aGlzKS5mb3JtYXRBcm4oe1xuICAgICAgcmVnaW9uOiAnJyxcbiAgICAgIHNlcnZpY2U6ICdpYW0nLFxuICAgICAgcmVzb3VyY2U6ICdyb2xlL2F3cy1zZXJ2aWNlLXJvbGUvZWNzLmFwcGxpY2F0aW9uLWF1dG9zY2FsaW5nLmFtYXpvbmF3cy5jb20nLFxuICAgICAgcmVzb3VyY2VOYW1lOiAnQVdTU2VydmljZVJvbGVGb3JBcHBsaWNhdGlvbkF1dG9TY2FsaW5nX0VDU1NlcnZpY2UnLFxuICAgIH0pKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBc3NvY2lhdGUgU2VydmljZSBEaXNjb3ZlcnkgKENsb3VkIE1hcCkgc2VydmljZVxuICAgKi9cbiAgcHJpdmF0ZSBhZGRTZXJ2aWNlUmVnaXN0cnkocmVnaXN0cnk6IFNlcnZpY2VSZWdpc3RyeSkge1xuICAgIGlmICh0aGlzLnNlcnZpY2VSZWdpc3RyaWVzLmxlbmd0aCA+PSAxKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Nhbm5vdCBhc3NvY2lhdGUgd2l0aCB0aGUgZ2l2ZW4gc2VydmljZSBkaXNjb3ZlcnkgcmVnaXN0cnkuIEVDUyBzdXBwb3J0cyBhdCBtb3N0IG9uZSBzZXJ2aWNlIHJlZ2lzdHJ5IHBlciBzZXJ2aWNlLicpO1xuICAgIH1cblxuICAgIGNvbnN0IHNyID0gdGhpcy5yZW5kZXJTZXJ2aWNlUmVnaXN0cnkocmVnaXN0cnkpO1xuICAgIHRoaXMuc2VydmljZVJlZ2lzdHJpZXMucHVzaChzcik7XG4gIH1cblxuICAvKipcbiAgICogIFJldHVybiB0aGUgZGVmYXVsdCBncmFjZSBwZXJpb2Qgd2hlbiBsb2FkIGJhbGFuY2VycyBhcmUgY29uZmlndXJlZCBhbmRcbiAgICogIGhlYWx0aENoZWNrR3JhY2VQZXJpb2QgaXMgbm90IGFscmVhZHkgc2V0XG4gICAqL1xuICBwcml2YXRlIGV2YWx1YXRlSGVhbHRoR3JhY2VQZXJpb2QocHJvdmlkZWRIZWFsdGhDaGVja0dyYWNlUGVyaW9kPzogRHVyYXRpb24pOiBJUmVzb2x2YWJsZSB7XG4gICAgcmV0dXJuIExhenkuYW55KHtcbiAgICAgIHByb2R1Y2U6ICgpID0+IHByb3ZpZGVkSGVhbHRoQ2hlY2tHcmFjZVBlcmlvZD8udG9TZWNvbmRzKCkgPz8gKHRoaXMubG9hZEJhbGFuY2Vycy5sZW5ndGggPiAwID8gNjAgOiB1bmRlZmluZWQpLFxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBlbmFibGVFeGVjdXRlQ29tbWFuZCgpIHtcbiAgICB0aGlzLnRhc2tEZWZpbml0aW9uLmFkZFRvVGFza1JvbGVQb2xpY3kobmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgYWN0aW9uczogW1xuICAgICAgICAnc3NtbWVzc2FnZXM6Q3JlYXRlQ29udHJvbENoYW5uZWwnLFxuICAgICAgICAnc3NtbWVzc2FnZXM6Q3JlYXRlRGF0YUNoYW5uZWwnLFxuICAgICAgICAnc3NtbWVzc2FnZXM6T3BlbkNvbnRyb2xDaGFubmVsJyxcbiAgICAgICAgJ3NzbW1lc3NhZ2VzOk9wZW5EYXRhQ2hhbm5lbCcsXG4gICAgICBdLFxuICAgICAgcmVzb3VyY2VzOiBbJyonXSxcbiAgICB9KSk7XG4gIH1cbn1cblxuLyoqXG4gKiBUaGUgb3B0aW9ucyB0byBlbmFibGluZyBBV1MgQ2xvdWQgTWFwIGZvciBhbiBBbWF6b24gRUNTIHNlcnZpY2UuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ2xvdWRNYXBPcHRpb25zIHtcbiAgLyoqXG4gICAqIFRoZSBuYW1lIG9mIHRoZSBDbG91ZCBNYXAgc2VydmljZSB0byBhdHRhY2ggdG8gdGhlIEVDUyBzZXJ2aWNlLlxuICAgKlxuICAgKiBAZGVmYXVsdCBDbG91ZEZvcm1hdGlvbi1nZW5lcmF0ZWQgbmFtZVxuICAgKi9cbiAgcmVhZG9ubHkgbmFtZT86IHN0cmluZyxcblxuICAvKipcbiAgICogVGhlIHNlcnZpY2UgZGlzY292ZXJ5IG5hbWVzcGFjZSBmb3IgdGhlIENsb3VkIE1hcCBzZXJ2aWNlIHRvIGF0dGFjaCB0byB0aGUgRUNTIHNlcnZpY2UuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gdGhlIGRlZmF1bHRDbG91ZE1hcE5hbWVzcGFjZSBhc3NvY2lhdGVkIHRvIHRoZSBjbHVzdGVyXG4gICAqL1xuICByZWFkb25seSBjbG91ZE1hcE5hbWVzcGFjZT86IGNsb3VkbWFwLklOYW1lc3BhY2U7XG5cbiAgLyoqXG4gICAqIFRoZSBETlMgcmVjb3JkIHR5cGUgdGhhdCB5b3Ugd2FudCBBV1MgQ2xvdWQgTWFwIHRvIGNyZWF0ZS4gVGhlIHN1cHBvcnRlZCByZWNvcmQgdHlwZXMgYXJlIEEgb3IgU1JWLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIERuc1JlY29yZFR5cGUuQSBpZiBUYXNrRGVmaW5pdGlvbi5uZXR3b3JrTW9kZSA9IEFXU19WUEMsIG90aGVyd2lzZSBEbnNSZWNvcmRUeXBlLlNSVlxuICAgKi9cbiAgcmVhZG9ubHkgZG5zUmVjb3JkVHlwZT86IGNsb3VkbWFwLkRuc1JlY29yZFR5cGUuQSB8IGNsb3VkbWFwLkRuc1JlY29yZFR5cGUuU1JWLFxuXG4gIC8qKlxuICAgKiBUaGUgYW1vdW50IG9mIHRpbWUgdGhhdCB5b3Ugd2FudCBETlMgcmVzb2x2ZXJzIHRvIGNhY2hlIHRoZSBzZXR0aW5ncyBmb3IgdGhpcyByZWNvcmQuXG4gICAqXG4gICAqIEBkZWZhdWx0IER1cmF0aW9uLm1pbnV0ZXMoMSlcbiAgICovXG4gIHJlYWRvbmx5IGRuc1R0bD86IER1cmF0aW9uO1xuXG4gIC8qKlxuICAgKiBUaGUgbnVtYmVyIG9mIDMwLXNlY29uZCBpbnRlcnZhbHMgdGhhdCB5b3Ugd2FudCBDbG91ZCBNYXAgdG8gd2FpdCBhZnRlciByZWNlaXZpbmcgYW4gVXBkYXRlSW5zdGFuY2VDdXN0b21IZWFsdGhTdGF0dXNcbiAgICogcmVxdWVzdCBiZWZvcmUgaXQgY2hhbmdlcyB0aGUgaGVhbHRoIHN0YXR1cyBvZiBhIHNlcnZpY2UgaW5zdGFuY2UuXG4gICAqXG4gICAqIE5PVEU6IFRoaXMgaXMgdXNlZCBmb3IgSGVhbHRoQ2hlY2tDdXN0b21Db25maWdcbiAgICovXG4gIHJlYWRvbmx5IGZhaWx1cmVUaHJlc2hvbGQ/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIFRoZSBjb250YWluZXIgdG8gcG9pbnQgdG8gZm9yIGEgU1JWIHJlY29yZC5cbiAgICogQGRlZmF1bHQgLSB0aGUgdGFzayBkZWZpbml0aW9uJ3MgZGVmYXVsdCBjb250YWluZXJcbiAgICovXG4gIHJlYWRvbmx5IGNvbnRhaW5lcj86IENvbnRhaW5lckRlZmluaXRpb247XG5cbiAgLyoqXG4gICAqIFRoZSBwb3J0IHRvIHBvaW50IHRvIGZvciBhIFNSViByZWNvcmQuXG4gICAqIEBkZWZhdWx0IC0gdGhlIGRlZmF1bHQgcG9ydCBvZiB0aGUgdGFzayBkZWZpbml0aW9uJ3MgZGVmYXVsdCBjb250YWluZXJcbiAgICovXG4gIHJlYWRvbmx5IGNvbnRhaW5lclBvcnQ/OiBudW1iZXI7XG59XG5cbi8qKlxuICogVGhlIG9wdGlvbnMgZm9yIHVzaW5nIGEgY2xvdWRtYXAgc2VydmljZS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBBc3NvY2lhdGVDbG91ZE1hcFNlcnZpY2VPcHRpb25zIHtcbiAgLyoqXG4gICAqIFRoZSBjbG91ZG1hcCBzZXJ2aWNlIHRvIHJlZ2lzdGVyIHdpdGguXG4gICAqL1xuICByZWFkb25seSBzZXJ2aWNlOiBjbG91ZG1hcC5JU2VydmljZTtcblxuICAvKipcbiAgICogVGhlIGNvbnRhaW5lciB0byBwb2ludCB0byBmb3IgYSBTUlYgcmVjb3JkLlxuICAgKiBAZGVmYXVsdCAtIHRoZSB0YXNrIGRlZmluaXRpb24ncyBkZWZhdWx0IGNvbnRhaW5lclxuICAgKi9cbiAgcmVhZG9ubHkgY29udGFpbmVyPzogQ29udGFpbmVyRGVmaW5pdGlvbjtcblxuICAvKipcbiAgICogVGhlIHBvcnQgdG8gcG9pbnQgdG8gZm9yIGEgU1JWIHJlY29yZC5cbiAgICogQGRlZmF1bHQgLSB0aGUgZGVmYXVsdCBwb3J0IG9mIHRoZSB0YXNrIGRlZmluaXRpb24ncyBkZWZhdWx0IGNvbnRhaW5lclxuICAgKi9cbiAgcmVhZG9ubHkgY29udGFpbmVyUG9ydD86IG51bWJlcjtcbn1cblxuLyoqXG4gKiBTZXJ2aWNlIFJlZ2lzdHJ5IGZvciBFQ1Mgc2VydmljZVxuICovXG5pbnRlcmZhY2UgU2VydmljZVJlZ2lzdHJ5IHtcbiAgLyoqXG4gICAqIEFybiBvZiB0aGUgQ2xvdWQgTWFwIFNlcnZpY2UgdGhhdCB3aWxsIHJlZ2lzdGVyIGEgQ2xvdWQgTWFwIEluc3RhbmNlIGZvciB5b3VyIEVDUyBTZXJ2aWNlXG4gICAqL1xuICByZWFkb25seSBhcm46IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIGNvbnRhaW5lciBuYW1lIHZhbHVlLCBhbHJlYWR5IHNwZWNpZmllZCBpbiB0aGUgdGFzayBkZWZpbml0aW9uLCB0byBiZSB1c2VkIGZvciB5b3VyIHNlcnZpY2UgZGlzY292ZXJ5IHNlcnZpY2UuXG4gICAqIElmIHRoZSB0YXNrIGRlZmluaXRpb24gdGhhdCB5b3VyIHNlcnZpY2UgdGFzayBzcGVjaWZpZXMgdXNlcyB0aGUgYnJpZGdlIG9yIGhvc3QgbmV0d29yayBtb2RlLFxuICAgKiB5b3UgbXVzdCBzcGVjaWZ5IGEgY29udGFpbmVyTmFtZSBhbmQgY29udGFpbmVyUG9ydCBjb21iaW5hdGlvbiBmcm9tIHRoZSB0YXNrIGRlZmluaXRpb24uXG4gICAqIElmIHRoZSB0YXNrIGRlZmluaXRpb24gdGhhdCB5b3VyIHNlcnZpY2UgdGFzayBzcGVjaWZpZXMgdXNlcyB0aGUgYXdzdnBjIG5ldHdvcmsgbW9kZSBhbmQgYSB0eXBlIFNSViBETlMgcmVjb3JkIGlzXG4gICAqIHVzZWQsIHlvdSBtdXN0IHNwZWNpZnkgZWl0aGVyIGEgY29udGFpbmVyTmFtZSBhbmQgY29udGFpbmVyUG9ydCBjb21iaW5hdGlvbiBvciBhIHBvcnQgdmFsdWUsIGJ1dCBub3QgYm90aC5cbiAgICovXG4gIHJlYWRvbmx5IGNvbnRhaW5lck5hbWU/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBjb250YWluZXIgcG9ydCB2YWx1ZSwgYWxyZWFkeSBzcGVjaWZpZWQgaW4gdGhlIHRhc2sgZGVmaW5pdGlvbiwgdG8gYmUgdXNlZCBmb3IgeW91ciBzZXJ2aWNlIGRpc2NvdmVyeSBzZXJ2aWNlLlxuICAgKiBJZiB0aGUgdGFzayBkZWZpbml0aW9uIHRoYXQgeW91ciBzZXJ2aWNlIHRhc2sgc3BlY2lmaWVzIHVzZXMgdGhlIGJyaWRnZSBvciBob3N0IG5ldHdvcmsgbW9kZSxcbiAgICogeW91IG11c3Qgc3BlY2lmeSBhIGNvbnRhaW5lck5hbWUgYW5kIGNvbnRhaW5lclBvcnQgY29tYmluYXRpb24gZnJvbSB0aGUgdGFzayBkZWZpbml0aW9uLlxuICAgKiBJZiB0aGUgdGFzayBkZWZpbml0aW9uIHRoYXQgeW91ciBzZXJ2aWNlIHRhc2sgc3BlY2lmaWVzIHVzZXMgdGhlIGF3c3ZwYyBuZXR3b3JrIG1vZGUgYW5kIGEgdHlwZSBTUlYgRE5TIHJlY29yZCBpc1xuICAgKiB1c2VkLCB5b3UgbXVzdCBzcGVjaWZ5IGVpdGhlciBhIGNvbnRhaW5lck5hbWUgYW5kIGNvbnRhaW5lclBvcnQgY29tYmluYXRpb24gb3IgYSBwb3J0IHZhbHVlLCBidXQgbm90IGJvdGguXG4gICAqL1xuICByZWFkb25seSBjb250YWluZXJQb3J0PzogbnVtYmVyO1xufVxuXG4vKipcbiAqIFRoZSBsYXVuY2ggdHlwZSBvZiBhbiBFQ1Mgc2VydmljZVxuICovXG5leHBvcnQgZW51bSBMYXVuY2hUeXBlIHtcbiAgLyoqXG4gICAqIFRoZSBzZXJ2aWNlIHdpbGwgYmUgbGF1bmNoZWQgdXNpbmcgdGhlIEVDMiBsYXVuY2ggdHlwZVxuICAgKi9cbiAgRUMyID0gJ0VDMicsXG5cbiAgLyoqXG4gICAqIFRoZSBzZXJ2aWNlIHdpbGwgYmUgbGF1bmNoZWQgdXNpbmcgdGhlIEZBUkdBVEUgbGF1bmNoIHR5cGVcbiAgICovXG4gIEZBUkdBVEUgPSAnRkFSR0FURScsXG5cbiAgLyoqXG4gICAqIFRoZSBzZXJ2aWNlIHdpbGwgYmUgbGF1bmNoZWQgdXNpbmcgdGhlIEVYVEVSTkFMIGxhdW5jaCB0eXBlXG4gICAqL1xuICBFWFRFUk5BTCA9ICdFWFRFUk5BTCdcbn1cblxuLyoqXG4gKiBUaGUgZGVwbG95bWVudCBjb250cm9sbGVyIHR5cGUgdG8gdXNlIGZvciB0aGUgc2VydmljZS5cbiAqL1xuZXhwb3J0IGVudW0gRGVwbG95bWVudENvbnRyb2xsZXJUeXBlIHtcbiAgLyoqXG4gICAqIFRoZSByb2xsaW5nIHVwZGF0ZSAoRUNTKSBkZXBsb3ltZW50IHR5cGUgaW52b2x2ZXMgcmVwbGFjaW5nIHRoZSBjdXJyZW50XG4gICAqIHJ1bm5pbmcgdmVyc2lvbiBvZiB0aGUgY29udGFpbmVyIHdpdGggdGhlIGxhdGVzdCB2ZXJzaW9uLlxuICAgKi9cbiAgRUNTID0gJ0VDUycsXG5cbiAgLyoqXG4gICAqIFRoZSBibHVlL2dyZWVuIChDT0RFX0RFUExPWSkgZGVwbG95bWVudCB0eXBlIHVzZXMgdGhlIGJsdWUvZ3JlZW4gZGVwbG95bWVudCBtb2RlbCBwb3dlcmVkIGJ5IEFXUyBDb2RlRGVwbG95XG4gICAqL1xuICBDT0RFX0RFUExPWSA9ICdDT0RFX0RFUExPWScsXG5cbiAgLyoqXG4gICAqIFRoZSBleHRlcm5hbCAoRVhURVJOQUwpIGRlcGxveW1lbnQgdHlwZSBlbmFibGVzIHlvdSB0byB1c2UgYW55IHRoaXJkLXBhcnR5IGRlcGxveW1lbnQgY29udHJvbGxlclxuICAgKi9cbiAgRVhURVJOQUwgPSAnRVhURVJOQUwnXG59XG5cbi8qKlxuICogUHJvcGFnYXRlIHRhZ3MgZnJvbSBlaXRoZXIgc2VydmljZSBvciB0YXNrIGRlZmluaXRpb25cbiAqL1xuZXhwb3J0IGVudW0gUHJvcGFnYXRlZFRhZ1NvdXJjZSB7XG4gIC8qKlxuICAgKiBQcm9wYWdhdGUgdGFncyBmcm9tIHNlcnZpY2VcbiAgICovXG4gIFNFUlZJQ0UgPSAnU0VSVklDRScsXG5cbiAgLyoqXG4gICAqIFByb3BhZ2F0ZSB0YWdzIGZyb20gdGFzayBkZWZpbml0aW9uXG4gICAqL1xuICBUQVNLX0RFRklOSVRJT04gPSAnVEFTS19ERUZJTklUSU9OJyxcblxuICAvKipcbiAgICogRG8gbm90IHByb3BhZ2F0ZVxuICAgKi9cbiAgTk9ORSA9ICdOT05FJ1xufVxuXG4vKipcbiAqIE9wdGlvbnMgZm9yIGBkZXRlcm1pbmVDb250YWluZXJOYW1lQW5kUG9ydGBcbiAqL1xuaW50ZXJmYWNlIERldGVybWluZUNvbnRhaW5lck5hbWVBbmRQb3J0T3B0aW9ucyB7XG4gIGRuc1JlY29yZFR5cGU6IGNsb3VkbWFwLkRuc1JlY29yZFR5cGU7XG4gIHRhc2tEZWZpbml0aW9uOiBUYXNrRGVmaW5pdGlvbjtcbiAgY29udGFpbmVyPzogQ29udGFpbmVyRGVmaW5pdGlvbjtcbiAgY29udGFpbmVyUG9ydD86IG51bWJlcjtcbn1cblxuLyoqXG4gKiBEZXRlcm1pbmUgdGhlIG5hbWUgb2YgdGhlIGNvbnRhaW5lciBhbmQgcG9ydCB0byB0YXJnZXQgZm9yIHRoZSBzZXJ2aWNlIHJlZ2lzdHJ5LlxuICovXG5mdW5jdGlvbiBkZXRlcm1pbmVDb250YWluZXJOYW1lQW5kUG9ydChvcHRpb25zOiBEZXRlcm1pbmVDb250YWluZXJOYW1lQW5kUG9ydE9wdGlvbnMpIHtcbiAgLy8gSWYgdGhlIHJlY29yZCB0eXBlIGlzIFNSViwgdGhlbiBwcm92aWRlIHRoZSBjb250YWluZXJOYW1lIGFuZCBjb250YWluZXJQb3J0IHRvIHRhcmdldC5cbiAgLy8gV2UgdXNlIHRoZSBuYW1lIG9mIHRoZSBkZWZhdWx0IGNvbnRhaW5lciBhbmQgdGhlIGRlZmF1bHQgcG9ydCBvZiB0aGUgZGVmYXVsdCBjb250YWluZXJcbiAgLy8gdW5sZXNzIHRoZSB1c2VyIHNwZWNpZmllcyBvdGhlcndpc2UuXG4gIGlmIChvcHRpb25zLmRuc1JlY29yZFR5cGUgPT09IGNsb3VkbWFwLkRuc1JlY29yZFR5cGUuU1JWKSB7XG4gICAgLy8gRW5zdXJlIHRoZSB1c2VyLXByb3ZpZGVkIGNvbnRhaW5lciBpcyBmcm9tIHRoZSByaWdodCB0YXNrIGRlZmluaXRpb24uXG4gICAgaWYgKG9wdGlvbnMuY29udGFpbmVyICYmIG9wdGlvbnMuY29udGFpbmVyLnRhc2tEZWZpbml0aW9uICE9IG9wdGlvbnMudGFza0RlZmluaXRpb24pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQ2Fubm90IGFkZCBkaXNjb3ZlcnkgZm9yIGEgY29udGFpbmVyIGZyb20gYW5vdGhlciB0YXNrIGRlZmluaXRpb24nKTtcbiAgICB9XG5cbiAgICBjb25zdCBjb250YWluZXIgPSBvcHRpb25zLmNvbnRhaW5lciA/PyBvcHRpb25zLnRhc2tEZWZpbml0aW9uLmRlZmF1bHRDb250YWluZXIhO1xuXG4gICAgLy8gRW5zdXJlIHRoYXQgYW55IHBvcnQgZ2l2ZW4gYnkgdGhlIHVzZXIgaXMgbWFwcGVkLlxuICAgIGlmIChvcHRpb25zLmNvbnRhaW5lclBvcnQgJiYgIWNvbnRhaW5lci5wb3J0TWFwcGluZ3Muc29tZShtYXBwaW5nID0+IG1hcHBpbmcuY29udGFpbmVyUG9ydCA9PT0gb3B0aW9ucy5jb250YWluZXJQb3J0KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdDYW5ub3QgYWRkIGRpc2NvdmVyeSBmb3IgYSBjb250YWluZXIgcG9ydCB0aGF0IGhhcyBub3QgYmVlbiBtYXBwZWQnKTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgY29udGFpbmVyTmFtZTogY29udGFpbmVyLmNvbnRhaW5lck5hbWUsXG4gICAgICBjb250YWluZXJQb3J0OiBvcHRpb25zLmNvbnRhaW5lclBvcnQgPz8gb3B0aW9ucy50YXNrRGVmaW5pdGlvbi5kZWZhdWx0Q29udGFpbmVyIS5jb250YWluZXJQb3J0LFxuICAgIH07XG4gIH1cblxuICByZXR1cm4ge307XG59XG4iXX0= |
\ | No newline at end of file |