@cloudcamp/aws-runtime
Version:
CloudCamp - Launch faster by building scalable infrastructure in few lines of code.
334 lines • 48.9 kB
JavaScript
"use strict";
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.WebService = void 0;
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
const path = require("path");
const app_1 = require("./app");
const _ = require("lodash");
const ec2 = require("aws-cdk-lib/aws-ec2");
const logs = require("aws-cdk-lib/aws-logs");
const ecs = require("aws-cdk-lib/aws-ecs");
const ecs_patterns = require("aws-cdk-lib/aws-ecs-patterns");
const cdk = require("aws-cdk-lib/core");
const elasticloadbalancingv2 = require("aws-cdk-lib/aws-elasticloadbalancingv2");
const chatbot = require("aws-cdk-lib/aws-chatbot");
const sns = require("aws-cdk-lib/aws-sns");
const cloudwatch = require("aws-cdk-lib/aws-cloudwatch");
const cloudwatch_actions = require("aws-cdk-lib/aws-cloudwatch-actions");
const subscriptions = require("aws-cdk-lib/aws-sns-subscriptions");
const applicationautoscaling = require("aws-cdk-lib/aws-applicationautoscaling");
const utils_1 = require("./utils");
const _1 = require(".");
const constructs_1 = require("constructs");
/**
* (experimental) A scalable web server running one or more docker containers behind a load balancer.
*
* `WebService` runs any web application behing a load balancers as docker
* containers. For example, this runs a web application as a single container
* exposed on port 8080:
*
* ```ts
* void 0;
* import { App, WebService } from "@cloudcamp/aws-runtime";
* let app = new App();
* void 'show';
* new WebService(app.production, "prod-web", {
* dockerfile: "../Dockerfile",
* port: 8080
* });
* ```
*
* @experimental
* @order 4
*/
class WebService extends constructs_1.Construct {
/**
* (experimental) Initialize a new web service.
*
* *Examples:*
*
* To use your own domain and serve traffic via SSL, use the `domain`
* and `ssl` properties:
* ```ts
* void 0;
* import { App, WebService } from "@cloudcamp/aws-runtime";
* let app = new App();
* void 'show';
*
* new WebService(app.production, "prod", {
* dockerfile: "../Dockerfile",
* domain: "example.com",
* ssl: true
* });
* ```
*
* See `{@link "command/domain/#domain-create" | domain:create}` and
* `{@link "command/cert/#cert-create" | cert:create}` for more information on
* setting up domains/SSL.
*
* @param scope the parent, i.e. a stack.
* @param id a unique identifier within the parent scope.
* @param props the properties of WebService.
* @experimental
* @remarks During initialization you can configure: Custom domains, SSL,
* machine configuration, health checks and the default number of instances.
* @topic Initialization
*/
constructor(scope, id, props) {
super(scope, id);
let appName = app_1.App.instance.configuration.name;
let vpc = ec2.Vpc.fromLookup(this, "vpc", {
vpcId: app_1.App.instance.configuration.vpcId,
});
let logGroup = new logs.LogGroup(this, "log-group", {
logGroupName: `/${appName}/webserver/${id}`,
retention: logs.RetentionDays.ONE_MONTH,
removalPolicy: cdk.RemovalPolicy.DESTROY,
});
let certificate = undefined;
if (props.domain) {
certificate = _1.Ref.getCertificate(this, props.domain + "-certificate", {
appName: app_1.App.instance.configuration.name,
name: props.domain,
});
}
this.fargateService =
new ecs_patterns.ApplicationLoadBalancedFargateService(this, "fargate-service", {
vpc: vpc,
cpu: props.cpu,
memoryLimitMiB: props.memory,
desiredCount: props.desiredCount,
assignPublicIp: true,
publicLoadBalancer: true,
domainName: props.domain,
certificate: certificate,
redirectHTTP: certificate ? true : false,
serviceName: id,
protocol: certificate
? elasticloadbalancingv2.ApplicationProtocol.HTTPS
: elasticloadbalancingv2.ApplicationProtocol.HTTP,
taskImageOptions: {
image: ecs.ContainerImage.fromAsset(path.dirname(props.dockerfile), {
file: path.basename(props.dockerfile),
// exclude is deprecated, but this seems to be just a
// side-effect of internal refactoring
// https://github.com/aws/aws-cdk/issues/10125
exclude: ["cdk.out"],
}),
containerPort: props.port || 80,
enableLogging: true,
logDriver: ecs.LogDriver.awsLogs({
streamPrefix: "ecs",
logGroup: logGroup,
}),
environment: props.environment,
},
});
if (props.healthCheckPath) {
this.fargateService.targetGroup.configureHealthCheck({
path: props.healthCheckPath,
port: (props.port || 80).toString(),
});
}
}
/**
* @experimental
*/
scaleOnSchedule(props) {
let task = this.fargateService.service.autoScaleTaskCount({
minCapacity: props.min,
maxCapacity: props.max,
});
for (let schedule of props.schedule) {
task.scaleOnSchedule(schedule.id, {
schedule: applicationautoscaling.Schedule.cron(schedule),
});
}
}
/**
* @experimental
*/
scaleOnMetric(props) {
let task = this.fargateService.service.autoScaleTaskCount({
minCapacity: props.min,
maxCapacity: props.max,
});
if (props.cpu !== undefined) {
task.scaleOnCpuUtilization("autoscale-cpu", {
targetUtilizationPercent: props.cpu,
});
}
if (props.memory !== undefined) {
task.scaleOnMemoryUtilization("autoscale-memory", {
targetUtilizationPercent: props.memory,
});
}
if (props.requestCount !== undefined) {
task.scaleOnRequestCount("autoscale-request-count", {
requestsPerTarget: props.requestCount,
targetGroup: this.fargateService.targetGroup,
});
}
}
/**
* @experimental
*/
alarms(props) {
var _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
props = utils_1.setDefaults(props, {
slack: undefined,
emails: [],
phones: [],
http5xx: {
duration: 1,
threshold: 1,
enabled: true,
},
http4xx: {
duration: 1,
threshold: 5,
enabled: true,
},
rejected: {
duration: 1,
threshold: 5,
enabled: true,
},
slow: {
duration: 1,
threshold: 5,
enabled: true,
},
});
let appName = app_1.App.instance.configuration.name;
let topic = new sns.Topic(this, "web-service-alarms-topic", {
displayName: "Web service Alarms Topic",
});
if (props.slack !== undefined) {
new chatbot.SlackChannelConfiguration(this, "slack-channel", {
slackChannelConfigurationName: "Slack Alarms Channel",
slackWorkspaceId: props.slack.workspaceId,
slackChannelId: props.slack.channelId,
notificationTopics: [topic],
loggingLevel: chatbot.LoggingLevel.INFO,
});
}
for (let email of props.email) {
topic.addSubscription(new subscriptions.EmailSubscription(email));
}
for (let sms of props.sms) {
topic.addSubscription(new subscriptions.SmsSubscription(sms));
}
if ((_b = props === null || props === void 0 ? void 0 : props.http5xx) === null || _b === void 0 ? void 0 : _b.enabled) {
this.addHttpAlarm("HTTP_5XX", `${appName}/${this.node.id}: HTTP 5XX threshold exceeded`, topic, (_c = props === null || props === void 0 ? void 0 : props.http5xx) === null || _c === void 0 ? void 0 : _c.threshold, (_d = props === null || props === void 0 ? void 0 : props.http5xx) === null || _d === void 0 ? void 0 : _d.duration);
}
if ((_e = props === null || props === void 0 ? void 0 : props.http4xx) === null || _e === void 0 ? void 0 : _e.enabled) {
this.addHttpAlarm("HTTP_4XX", `${appName}/${this.node.id}: HTTP 4XX threshold exceeded`, topic, (_f = props === null || props === void 0 ? void 0 : props.http4xx) === null || _f === void 0 ? void 0 : _f.threshold, (_g = props === null || props === void 0 ? void 0 : props.http4xx) === null || _g === void 0 ? void 0 : _g.duration);
}
if ((_h = props === null || props === void 0 ? void 0 : props.rejected) === null || _h === void 0 ? void 0 : _h.enabled) {
this.addRejectedAlarm(topic, (_j = props === null || props === void 0 ? void 0 : props.rejected) === null || _j === void 0 ? void 0 : _j.threshold, (_k = props === null || props === void 0 ? void 0 : props.rejected) === null || _k === void 0 ? void 0 : _k.duration);
}
if ((_l = props === null || props === void 0 ? void 0 : props.slow) === null || _l === void 0 ? void 0 : _l.enabled) {
this.addSlowAlarm(topic, (_m = props === null || props === void 0 ? void 0 : props.slow) === null || _m === void 0 ? void 0 : _m.threshold, (_o = props === null || props === void 0 ? void 0 : props.slow) === null || _o === void 0 ? void 0 : _o.duration);
}
}
addHttpAlarm(name, description, topic, threshold, period) {
let elbCode;
switch (name) {
case "HTTP_5XX":
elbCode = elasticloadbalancingv2.HttpCodeElb.ELB_5XX_COUNT;
break;
case "HTTP_4XX":
elbCode = elasticloadbalancingv2.HttpCodeElb.ELB_4XX_COUNT;
break;
}
let elbAlarm = new cloudwatch.Alarm(this, _.kebabCase(name + "-elb-alarm"), {
alarmName: name,
alarmDescription: description,
comparisonOperator: cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD,
threshold: threshold,
evaluationPeriods: 1,
treatMissingData: cloudwatch.TreatMissingData.NOT_BREACHING,
metric: this.fargateService.loadBalancer.metricHttpCodeElb(elbCode, {
period: cdk.Duration.minutes(period),
statistic: "Sum",
dimensionsMap: {
LoadBalancer: this.fargateService.loadBalancer.loadBalancerFullName,
},
}),
});
elbAlarm.addAlarmAction(new cloudwatch_actions.SnsAction(topic));
elbAlarm.addOkAction(new cloudwatch_actions.SnsAction(topic));
let targetCode;
switch (name) {
case "HTTP_5XX":
targetCode = elasticloadbalancingv2.HttpCodeTarget.TARGET_5XX_COUNT;
break;
case "HTTP_4XX":
targetCode = elasticloadbalancingv2.HttpCodeTarget.TARGET_4XX_COUNT;
break;
}
let targetAlarm = new cloudwatch.Alarm(this, _.kebabCase(name + "-target-alarm"), {
alarmName: name,
alarmDescription: description,
comparisonOperator: cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD,
threshold: threshold,
evaluationPeriods: 1,
treatMissingData: cloudwatch.TreatMissingData.NOT_BREACHING,
metric: this.fargateService.loadBalancer.metricHttpCodeTarget(targetCode, {
period: cdk.Duration.minutes(period),
statistic: "Sum",
dimensionsMap: {
LoadBalancer: this.fargateService.loadBalancer.loadBalancerFullName,
},
}),
});
targetAlarm.addAlarmAction(new cloudwatch_actions.SnsAction(topic));
targetAlarm.addOkAction(new cloudwatch_actions.SnsAction(topic));
}
addRejectedAlarm(topic, threshold, period) {
let appName = app_1.App.instance.configuration.name;
let alarm = new cloudwatch.Alarm(this, "rejected-connections-alarm", {
alarmName: "REJECTED",
alarmDescription: `${appName}/${this.node.id}: Rejected connections threshold exceeded`,
comparisonOperator: cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD,
threshold: threshold,
evaluationPeriods: 1,
treatMissingData: cloudwatch.TreatMissingData.NOT_BREACHING,
metric: this.fargateService.loadBalancer.metricRejectedConnectionCount({
period: cdk.Duration.minutes(period),
statistic: "Sum",
dimensionsMap: {
LoadBalancer: this.fargateService.loadBalancer.loadBalancerFullName,
},
}),
});
alarm.addAlarmAction(new cloudwatch_actions.SnsAction(topic));
alarm.addOkAction(new cloudwatch_actions.SnsAction(topic));
}
addSlowAlarm(topic, threshold, period) {
let appName = app_1.App.instance.configuration.name;
let alarm = new cloudwatch.Alarm(this, "rejected-connections-alarm", {
alarmName: "REJECTED",
alarmDescription: `${appName}/${this.node.id}: Rejected connections threshold exceeded`,
comparisonOperator: cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD,
threshold: threshold,
evaluationPeriods: 1,
treatMissingData: cloudwatch.TreatMissingData.NOT_BREACHING,
metric: this.fargateService.loadBalancer.metricTargetResponseTime({
period: cdk.Duration.minutes(period),
statistic: "Sum",
dimensionsMap: {
LoadBalancer: this.fargateService.loadBalancer.loadBalancerFullName,
},
}),
});
alarm.addAlarmAction(new cloudwatch_actions.SnsAction(topic));
alarm.addOkAction(new cloudwatch_actions.SnsAction(topic));
}
}
exports.WebService = WebService;
_a = JSII_RTTI_SYMBOL_1;
WebService[_a] = { fqn: "@cloudcamp/aws-runtime.WebService", version: "0.0.1" };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2Vic2VydmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3dlYnNlcnZlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLDZCQUE2QjtBQUM3QiwrQkFBNEI7QUFDNUIsNEJBQTZCO0FBQzdCLDJDQUEyQztBQUMzQyw2Q0FBNkM7QUFDN0MsMkNBQTJDO0FBQzNDLDZEQUE2RDtBQUM3RCx3Q0FBd0M7QUFDeEMsaUZBQWlGO0FBQ2pGLG1EQUFtRDtBQUNuRCwyQ0FBMkM7QUFDM0MseURBQXlEO0FBQ3pELHlFQUF5RTtBQUN6RSxtRUFBbUU7QUFDbkUsaUZBQWlGO0FBQ2pGLG1DQUFzQztBQUV0Qyx3QkFBd0I7QUFDeEIsMkNBQXVDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBNEV2QyxNQUFhLFVBQVcsU0FBUSxzQkFBUzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0lBRXZDLFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBc0I7UUFDOUQsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUVqQixJQUFJLE9BQU8sR0FBRyxTQUFHLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUM7UUFFOUMsSUFBSSxHQUFHLEdBQUcsR0FBRyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRTtZQUN4QyxLQUFLLEVBQUUsU0FBRyxDQUFDLFFBQVEsQ0FBQyxhQUFhLENBQUMsS0FBSztTQUN4QyxDQUFDLENBQUM7UUFFSCxJQUFJLFFBQVEsR0FBRyxJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLFdBQVcsRUFBRTtZQUNsRCxZQUFZLEVBQUUsSUFBSSxPQUFPLGNBQWMsRUFBRSxFQUFFO1lBQzNDLFNBQVMsRUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDLFNBQVM7WUFDdkMsYUFBYSxFQUFFLEdBQUcsQ0FBQyxhQUFhLENBQUMsT0FBTztTQUN6QyxD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b3J0IHsgQXBwIH0gZnJvbSBcIi4vYXBwXCI7XG5pbXBvcnQgXyA9IHJlcXVpcmUoXCJsb2Rhc2hcIik7XG5pbXBvcnQgKiBhcyBlYzIgZnJvbSBcImF3cy1jZGstbGliL2F3cy1lYzJcIjtcbmltcG9ydCAqIGFzIGxvZ3MgZnJvbSBcImF3cy1jZGstbGliL2F3cy1sb2dzXCI7XG5pbXBvcnQgKiBhcyBlY3MgZnJvbSBcImF3cy1jZGstbGliL2F3cy1lY3NcIjtcbmltcG9ydCAqIGFzIGVjc19wYXR0ZXJucyBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWVjcy1wYXR0ZXJuc1wiO1xuaW1wb3J0ICogYXMgY2RrIGZyb20gXCJhd3MtY2RrLWxpYi9jb3JlXCI7XG5pbXBvcnQgKiBhcyBlbGFzdGljbG9hZGJhbGFuY2luZ3YyIGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtZWxhc3RpY2xvYWRiYWxhbmNpbmd2MlwiO1xuaW1wb3J0ICogYXMgY2hhdGJvdCBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWNoYXRib3RcIjtcbmltcG9ydCAqIGFzIHNucyBmcm9tIFwiYXdzLWNkay1saWIvYXdzLXNuc1wiO1xuaW1wb3J0ICogYXMgY2xvdWR3YXRjaCBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWNsb3Vkd2F0Y2hcIjtcbmltcG9ydCAqIGFzIGNsb3Vkd2F0Y2hfYWN0aW9ucyBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWNsb3Vkd2F0Y2gtYWN0aW9uc1wiO1xuaW1wb3J0ICogYXMgc3Vic2NyaXB0aW9ucyBmcm9tIFwiYXdzLWNkay1saWIvYXdzLXNucy1zdWJzY3JpcHRpb25zXCI7XG5pbXBvcnQgKiBhcyBhcHBsaWNhdGlvbmF1dG9zY2FsaW5nIGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtYXBwbGljYXRpb25hdXRvc2NhbGluZ1wiO1xuaW1wb3J0IHsgc2V0RGVmYXVsdHMgfSBmcm9tIFwiLi91dGlsc1wiO1xuaW1wb3J0IHsgSUNlcnRpZmljYXRlIH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1jZXJ0aWZpY2F0ZW1hbmFnZXJcIjtcbmltcG9ydCB7IFJlZiB9IGZyb20gXCIuXCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tIFwiY29uc3RydWN0c1wiO1xuXG4vLyBUT0RPIGFkZCByZWRpcmVjdEhUVFBcbi8vIFRPRE8gYWRkIG11bHRpcGxlIGRvbWFpbnMgaHR0cHM6Ly9qZXJlbXluYWdlbC5tZWRpdW0uY29tL2FkZGluZy1tdWx0aXBsZS1jZXJ0aWZpY2F0ZXMtdG8tYS1hcHBsaWNhdGlvbmxvYWRiYWxhbmNlZGZhcmdhdGVzZXJ2aWNlLXdpdGgtY2RrLWFkYzg3N2UyODMxZFxuZXhwb3J0IGludGVyZmFjZSBXZWJTZXJ2aWNlUHJvcHMge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gIHJlYWRvbmx5IGRvY2tlcmZpbGU6IHN0cmluZztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gIHJlYWRvbmx5IHBvcnQ/OiBudW1iZXI7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbiAgcmVhZG9ubHkgZW52aXJvbm1lbnQ/OiB7XG4gICAgW2tleTogc3RyaW5nXTogc3RyaW5nO1xuICB9O1xuICAgICAgICAgICAgICAgICAgICAgXG4gIHJlYWRvbmx5IGRvbWFpbj86IHN0cmluZztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gIHJlYWRvbmx5IGNwdT86IG51bWJlcjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gIHJlYWRvbmx5IG1lbW9yeT86IG51bWJlcjtcblxuICByZWFkb25seSBkZXNpcmVkQ291bnQ/OiBudW1iZXI7XG4gIHJlYWRvbmx5IGhlYWx0aENoZWNrUGF0aD86IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBBbGFybUNvbmZpZ3VyYXRpb24ge1xuICByZWFkb25seSBkdXJhdGlvbj86IG51bWJlcjtcbiAgcmVhZG9ubHkgdGhyZXNob2xkPzogbnVtYmVyO1xuICByZWFkb25seSBlbmFibGVkPzogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBTbGFja0NvbmZpZ3VyYXRpb24ge1xuICByZWFkb25seSB3b3Jrc3BhY2VJZDogc3RyaW5nO1xuICByZWFkb25seSBjaGFubmVsSWQ6IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBXZWJTZXJ2aWNlQWxhcm1Qcm9wcyB7XG4gIHJlYWRvbmx5IHNsYWNrPzogU2xhY2tDb25maWd1cmF0aW9uO1xuICByZWFkb25seSBlbWFpbD86IHN0cmluZ1tdO1xuICByZWFkb25seSBzbXM/OiBzdHJpbmdbXTtcbiAgcmVhZG9ubHkgaHR0cDV4eD86IEFsYXJtQ29uZmlndXJhdGlvbjtcbiAgcmVhZG9ubHkgaHR0cDR4eD86IEFsYXJtQ29uZmlndXJhdGlvbjtcbiAgcmVhZG9ubHkgcmVqZWN0ZWQ/OiBBbGFybUNvbmZpZ3VyYXRpb247XG4gIHJlYWRvbmx5IHNsb3c/OiBBbGFybUNvbmZpZ3VyYXRpb247XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2NhbGluZ1NjaGVkdWxlIHtcbiAgcmVhZG9ubHkgaWQ6IHN0cmluZztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbiAgcmVhZG9ubHkgbWludXRlPzogc3RyaW5nO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gIHJlYWRvbmx5IGhvdXI/OiBzdHJpbmc7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbiAgcmVhZG9ubHkgZGF5Pzogc3RyaW5nO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbiAgcmVhZG9ubHkgbW9udGg/OiBzdHJpbmc7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbiAgcmVhZG9ubHkgeWVhcj86IHN0cmluZztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gIHJlYWRvbmx5IHdlZWtEYXk/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2NoZWR1bGVTY2FsaW5nUHJvcHMge1xuICByZWFkb25seSBtaW46IG51bWJlcjtcbiAgcmVhZG9ubHkgbWF4OiBudW1iZXI7XG4gIHJlYWRvbmx5IHNjaGVkdWxlOiBTY2FsaW5nU2NoZWR1bGVbXTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBNZXRyaWNTY2FsaW5nUHJvcHMge1xuICByZWFkb25seSBtaW46IG51bWJlcjtcbiAgcmVhZG9ubHkgbWF4OiBudW1iZXI7XG4gIHJlYWRvbmx5IGNwdT86IG51bWJlcjtcbiAgcmVhZG9ubHkgbWVtb3J5PzogbnVtYmVyO1xuICByZWFkb25seSByZXF1ZXN0Q291bnQ/OiBudW1iZXI7XG59XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbmV4cG9ydCBjbGFzcyBXZWJTZXJ2aWNlIGV4dGVuZHMgQ29uc3RydWN0IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogV2ViU2VydmljZVByb3BzKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkKTtcblxuICAgIGxldCBhcHBOYW1lID0gQXBwLmluc3RhbmNlLmNvbmZpZ3VyYXRpb24ubmFtZTtcblxuICAgIGxldCB2cGMgPSBlYzIuVnBjLmZyb21Mb29rdXAodGhpcywgXCJ2cGNcIiwge1xuICAgICAgdnBjSWQ6IEFwcC5pbnN0YW5jZS5jb25maWd1cmF0aW9uLnZwY0lkLFxuICAgIH0pO1xuXG4gICAgbGV0IGxvZ0dyb3VwID0gbmV3IGxvZ3MuTG9nR3JvdXAodGhpcywgXCJsb2ctZ3JvdXBcIiwge1xuICAgICAgbG9nR3JvdXBOYW1lOiBgLyR7YXBwTmFtZX0vd2Vic2VydmVyLyR7aWR9YCxcbiAgICAgIHJldGVudGlvbjogbG9ncy5SZXRlbnRpb25EYXlzLk9ORV9NT05USCxcbiAgICAgIHJlbW92YWxQb2xpY3k6IGNkay5SZW1vdmFsUG9saWN5LkRFU1RST1ksXG4gICAgfSk7XG5cbiAgICBsZXQgY2VydGlmaWNhdGU6IElDZXJ0aWZpY2F0ZSB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcblxuICAgIGlmIChwcm9wcy5kb21haW4pIHtcbiAgICAgIGNlcnRpZmljYXRlID0gUmVmLmdldENlcnRpZmljYXRlKHRoaXMsIHByb3BzLmRvbWFpbiEgKyBcIi1jZXJ0aWZpY2F0ZVwiLCB7XG4gICAgICAgIGFwcE5hbWU6IEFwcC5pbnN0YW5jZS5jb25maWd1cmF0aW9uLm5hbWUsXG4gICAgICAgIG5hbWU6IHByb3BzLmRvbWFpbiEsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICB0aGlzLmZhcmdhdGVTZXJ2aWNlID1cbiAgICAgIG5ldyBlY3NfcGF0dGVybnMuQXBwbGljYXRpb25Mb2FkQmFsYW5jZWRGYXJnYXRlU2VydmljZShcbiAgICAgICAgdGhpcyxcbiAgICAgICAgXCJmYXJnYXRlLXNlcnZpY2VcIixcbiAgICAgICAge1xuICAgICAgICAgIHZwYzogdnBjLFxuICAgICAgICAgIGNwdTogcHJvcHMuY3B1LFxuICAgICAgICAgIG1lbW9yeUxpbWl0TWlCOiBwcm9wcy5tZW1vcnksXG4gICAgICAgICAgZGVzaXJlZENvdW50OiBwcm9wcy5kZXNpcmVkQ291bnQsXG4gICAgICAgICAgYXNzaWduUHVibGljSXA6IHRydWUsXG4gICAgICAgICAgcHVibGljTG9hZEJhbGFuY2VyOiB0cnVlLFxuICAgICAgICAgIGRvbWFpbk5hbWU6IHByb3BzLmRvbWFpbixcbiAgICAgICAgICBjZXJ0aWZpY2F0ZTogY2VydGlmaWNhdGUsXG4gICAgICAgICAgcmVkaXJlY3RIVFRQOiBjZXJ0aWZpY2F0ZSA/IHRydWUgOiBmYWxzZSxcbiAgICAgICAgICBzZXJ2aWNlTmFtZTogaWQsXG4gICAgICAgICAgcHJvdG9jb2w6IGNlcnRpZmljYXRlXG4gICAgICAgICAgICA/IGVsYXN0aWNsb2FkYmFsYW5jaW5ndjIuQXBwbGljYXRpb25Qcm90b2NvbC5IVFRQU1xuICAgICAgICAgICAgOiBlbGFzdGljbG9hZGJhbGFuY2luZ3YyLkFwcGxpY2F0aW9uUHJvdG9jb2wuSFRUUCxcbiAgICAgICAgICB0YXNrSW1hZ2VPcHRpb25zOiB7XG4gICAgICAgICAgICBpbWFnZTogZWNzLkNvbnRhaW5lckltYWdlLmZyb21Bc3NldChcbiAgICAgICAgICAgICAgcGF0aC5kaXJuYW1lKHByb3BzLmRvY2tlcmZpbGUpLFxuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgZmlsZTogcGF0aC5iYXNlbmFtZShwcm9wcy5kb2NrZXJmaWxlKSxcblxuICAgICAgICAgICAgICAgIC8vIGV4Y2x1ZGUgaXMgZGVwcmVjYXRlZCwgYnV0IHRoaXMgc2VlbXMgdG8gYmUganVzdCBhXG4gICAgICAgICAgICAgICAgLy8gc2lkZS1lZmZlY3Qgb2YgaW50ZXJuYWwgcmVmYWN0b3JpbmdcbiAgICAgICAgICAgICAgICAvLyBodHRwczovL2dpdGh1Yi5jb20vYXdzL2F3cy1jZGsvaXNzdWVzLzEwMTI1XG4gICAgICAgICAgICAgICAgZXhjbHVkZTogW1wiY2RrLm91dFwiXSxcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgKSxcbiAgICAgICAgICAgIGNvbnRhaW5lclBvcnQ6IHByb3BzLnBvcnQgfHwgODAsXG4gICAgICAgICAgICBlbmFibGVMb2dnaW5nOiB0cnVlLFxuICAgICAgICAgICAgbG9nRHJpdmVyOiBlY3MuTG9nRHJpdmVyLmF3c0xvZ3Moe1xuICAgICAgICAgICAgICBzdHJlYW1QcmVmaXg6IFwiZWNzXCIsXG4gICAgICAgICAgICAgIGxvZ0dyb3VwOiBsb2dHcm91cCxcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgZW52aXJvbm1lbnQ6IHByb3BzLmVudmlyb25tZW50LFxuICAgICAgICAgIH0sXG4gICAgICAgIH1cbiAgICAgICk7XG5cbiAgICBpZiAocHJvcHMuaGVhbHRoQ2hlY2tQYXRoKSB7XG4gICAgICB0aGlzLmZhcmdhdGVTZXJ2aWNlLnRhcmdldEdyb3VwLmNvbmZpZ3VyZUhlYWx0aENoZWNrKHtcbiAgICAgICAgcGF0aDogcHJvcHMuaGVhbHRoQ2hlY2tQYXRoLFxuICAgICAgICBwb3J0OiAocHJvcHMucG9ydCB8fCA4MCkudG9TdHJpbmcoKSxcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIGZhcmdhdGVTZXJ2aWNlOiBlY3NfcGF0dGVybnMuQXBwbGljYXRpb25Mb2FkQmFsYW5jZWRGYXJnYXRlU2VydmljZTtcblxuICBzY2FsZU9uU2NoZWR1bGUocHJvcHM6IFNjaGVkdWxlU2NhbGluZ1Byb3BzKSB7XG4gICAgbGV0IHRhc2sgPSB0aGlzLmZhcmdhdGVTZXJ2aWNlLnNlcnZpY2UuYXV0b1NjYWxlVGFza0NvdW50KHtcbiAgICAgIG1pbkNhcGFjaXR5OiBwcm9wcy5taW4sXG4gICAgICBtYXhDYXBhY2l0eTogcHJvcHMubWF4LFxuICAgIH0pO1xuICAgIGZvciAobGV0IHNjaGVkdWxlIG9mIHByb3BzLnNjaGVkdWxlKSB7XG4gICAgICB0YXNrLnNjYWxlT25TY2hlZHVsZShzY2hlZHVsZS5pZCwge1xuICAgICAgICBzY2hlZHVsZTogYXBwbGljYXRpb25hdXRvc2NhbGluZy5TY2hlZHVsZS5jcm9uKHNjaGVkdWxlKSxcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIHNjYWxlT25NZXRyaWMocHJvcHM6IE1ldHJpY1NjYWxpbmdQcm9wcykge1xuICAgIGxldCB0YXNrID0gdGhpcy5mYXJnYXRlU2VydmljZS5zZXJ2aWNlLmF1dG9TY2FsZVRhc2tDb3VudCh7XG4gICAgICBtaW5DYXBhY2l0eTogcHJvcHMubWluLFxuICAgICAgbWF4Q2FwYWNpdHk6IHByb3BzLm1heCxcbiAgICB9KTtcbiAgICBpZiAocHJvcHMuY3B1ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHRhc2suc2NhbGVPbkNwdVV0aWxpemF0aW9uKFwiYXV0b3NjYWxlLWNwdVwiLCB7XG4gICAgICAgIHRhcmdldFV0aWxpemF0aW9uUGVyY2VudDogcHJvcHMuY3B1LFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKHByb3BzLm1lbW9yeSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICB0YXNrLnNjYWxlT25NZW1vcnlVdGlsaXphdGlvbihcImF1dG9zY2FsZS1tZW1vcnlcIiwge1xuICAgICAgICB0YXJnZXRVdGlsaXphdGlvblBlcmNlbnQ6IHByb3BzLm1lbW9yeSxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmIChwcm9wcy5yZXF1ZXN0Q291bnQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgdGFzay5zY2FsZU9uUmVxdWVzdENvdW50KFwiYXV0b3NjYWxlLXJlcXVlc3QtY291bnRcIiwge1xuICAgICAgICByZXF1ZXN0c1BlclRhcmdldDogcHJvcHMucmVxdWVzdENvdW50LFxuICAgICAgICB0YXJnZXRHcm91cDogdGhpcy5mYXJnYXRlU2VydmljZS50YXJnZXRHcm91cCxcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIGFsYXJtcyhwcm9wcz86IFdlYlNlcnZpY2VBbGFybVByb3BzKSB7XG4gICAgcHJvcHMgPSBzZXREZWZhdWx0cyhwcm9wcywge1xuICAgICAgc2xhY2s6IHVuZGVmaW5lZCxcbiAgICAgIGVtYWlsczogW10sXG4gICAgICBwaG9uZXM6IFtdLFxuICAgICAgaHR0cDV4eDoge1xuICAgICAgICBkdXJhdGlvbjogMSxcbiAgICAgICAgdGhyZXNob2xkOiAxLFxuICAgICAgICBlbmFibGVkOiB0cnVlLFxuICAgICAgfSxcbiAgICAgIGh0dHA0eHg6IHtcbiAgICAgICAgZHVyYXRpb246IDEsXG4gICAgICAgIHRocmVzaG9sZDogNSxcbiAgICAgICAgZW5hYmxlZDogdHJ1ZSxcbiAgICAgIH0sXG4gICAgICByZWplY3RlZDoge1xuICAgICAgICBkdXJhdGlvbjogMSxcbiAgICAgICAgdGhyZXNob2xkOiA1LFxuICAgICAgICBlbmFibGVkOiB0cnVlLFxuICAgICAgfSxcbiAgICAgIHNsb3c6IHtcbiAgICAgICAgZHVyYXRpb246IDEsXG4gICAgICAgIHRocmVzaG9sZDogNSxcbiAgICAgICAgZW5hYmxlZDogdHJ1ZSxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICBsZXQgYXBwTmFtZSA9IEFwcC5pbnN0YW5jZS5jb25maWd1cmF0aW9uLm5hbWU7XG5cbiAgICBsZXQgdG9waWMgPSBuZXcgc25zLlRvcGljKHRoaXMsIFwid2ViLXNlcnZpY2UtYWxhcm1zLXRvcGljXCIsIHtcbiAgICAgIGRpc3BsYXlOYW1lOiBcIldlYiBzZXJ2aWNlIEFsYXJtcyBUb3BpY1wiLFxuICAgIH0pO1xuXG4gICAgaWYgKHByb3BzLnNsYWNrICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIG5ldyBjaGF0Ym90LlNsYWNrQ2hhbm5lbENvbmZpZ3VyYXRpb24odGhpcywgXCJzbGFjay1jaGFubmVsXCIsIHtcbiAgICAgICAgc2xhY2tDaGFubmVsQ29uZmlndXJhdGlvbk5hbWU6IFwiU2xhY2sgQWxhcm1zIENoYW5uZWxcIixcbiAgICAgICAgc2xhY2tXb3Jrc3BhY2VJZDogcHJvcHMuc2xhY2sud29ya3NwYWNlSWQsXG4gICAgICAgIHNsYWNrQ2hhbm5lbElkOiBwcm9wcy5zbGFjay5jaGFubmVsSWQsXG4gICAgICAgIG5vdGlmaWNhdGlvblRvcGljczogW3RvcGljXSxcbiAgICAgICAgbG9nZ2luZ0xldmVsOiBjaGF0Ym90LkxvZ2dpbmdMZXZlbC5JTkZPLCAvLyBUT0RPIHNob3VsZCBiZSBFUlJPUj9cbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGZvciAobGV0IGVtYWlsIG9mIHByb3BzLmVtYWlsIGFzIHN0cmluZ1tdKSB7XG4gICAgICB0b3BpYy5hZGRTdWJzY3JpcHRpb24obmV3IHN1YnNjcmlwdGlvbnMuRW1haWxTdWJzY3JpcHRpb24oZW1haWwpKTtcbiAgICB9XG5cbiAgICBmb3IgKGxldCBzbXMgb2YgcHJvcHMuc21zIGFzIHN0cmluZ1tdKSB7XG4gICAgICB0b3BpYy5hZGRTdWJzY3JpcHRpb24obmV3IHN1YnNjcmlwdGlvbnMuU21zU3Vic2NyaXB0aW9uKHNtcykpO1xuICAgIH1cblxuICAgIGlmIChwcm9wcz8uaHR0cDV4eD8uZW5hYmxlZCkge1xuICAgICAgdGhpcy5hZGRIdHRwQWxhcm0oXG4gICAgICAgIFwiSFRUUF81WFhcIixcbiAgICAgICAgYCR7YXBwTmFtZX0vJHt0aGlzLm5vZGUuaWR9OiBIVFRQIDVYWCB0aHJlc2hvbGQgZXhjZWVkZWRgLFxuICAgICAgICB0b3BpYyxcbiAgICAgICAgcHJvcHM/Lmh0dHA1eHg/LnRocmVzaG9sZCBhcyBudW1iZXIsXG4gICAgICAgIHByb3BzPy5odHRwNXh4Py5kdXJhdGlvbiBhcyBudW1iZXJcbiAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKHByb3BzPy5odHRwNHh4Py5lbmFibGVkKSB7XG4gICAgICB0aGlzLmFkZEh0dHBBbGFybShcbiAgICAgICAgXCJIVFRQXzRYWFwiLFxuICAgICAgICBgJHthcHBOYW1lfS8ke3RoaXMubm9kZS5pZH06IEhUVFAgNFhYIHRocmVzaG9sZCBleGNlZWRlZGAsXG4gICAgICAgIHRvcGljLFxuICAgICAgICBwcm9wcz8uaHR0cDR4eD8udGhyZXNob2xkIGFzIG51bWJlcixcbiAgICAgICAgcHJvcHM/Lmh0dHA0eHg/LmR1cmF0aW9uIGFzIG51bWJlclxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAocHJvcHM/LnJlamVjdGVkPy5lbmFibGVkKSB7XG4gICAgICB0aGlzLmFkZFJlamVjdGVkQWxhcm0oXG4gICAgICAgIHRvcGljLFxuICAgICAgICBwcm9wcz8ucmVqZWN0ZWQ/LnRocmVzaG9sZCBhcyBudW1iZXIsXG4gICAgICAgIHByb3BzPy5yZWplY3RlZD8uZHVyYXRpb24gYXMgbnVtYmVyXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmIChwcm9wcz8uc2xvdz8uZW5hYmxlZCkge1xuICAgICAgdGhpcy5hZGRTbG93QWxhcm0oXG4gICAgICAgIHRvcGljLFxuICAgICAgICBwcm9wcz8uc2xvdz8udGhyZXNob2xkIGFzIG51bWJlcixcbiAgICAgICAgcHJvcHM/LnNsb3c/LmR1cmF0aW9uIGFzIG51bWJlclxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFkZEh0dHBBbGFybShcbiAgICBuYW1lOiBcIkhUVFBfNVhYXCIgfCBcIkhUVFBfNFhYXCIsXG4gICAgZGVzY3JpcHRpb246IHN0cmluZyxcbiAgICB0b3BpYzogc25zLklUb3BpYyxcbiAgICB0aHJlc2hvbGQ6IG51bWJlcixcbiAgICBwZXJpb2Q6IG51bWJlclxuICApIHtcbiAgICBsZXQgZWxiQ29kZTogZWxhc3RpY2xvYWRiYWxhbmNpbmd2Mi5IdHRwQ29kZUVsYjtcbiAgICBzd2l0Y2ggKG5hbWUpIHtcbiAgICAgIGNhc2UgXCJIVFRQXzVYWFwiOlxuICAgICAgICBlbGJDb2RlID0gZWxhc3RpY2xvYWRiYWxhbmNpbmd2Mi5IdHRwQ29kZUVsYi5FTEJfNVhYX0NPVU5UO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgXCJIVFRQXzRYWFwiOlxuICAgICAgICBlbGJDb2RlID0gZWxhc3RpY2xvYWRiYWxhbmNpbmd2Mi5IdHRwQ29kZUVsYi5FTEJfNFhYX0NPVU5UO1xuICAgICAgICBicmVhaztcbiAgICB9XG5cbiAgICBsZXQgZWxiQWxhcm0gPSBuZXcgY2xvdWR3YXRjaC5BbGFybShcbiAgICAgIHRoaXMsXG4gICAgICBfLmtlYmFiQ2FzZShuYW1lICsgXCItZWxiLWFsYXJtXCIpLFxuICAgICAge1xuICAgICAgICBhbGFybU5hbWU6IG5hbWUsXG4gICAgICAgIGFsYXJtRGVzY3JpcHRpb246IGRlc2NyaXB0aW9uLFxuICAgICAgICBjb21wYXJpc29uT3BlcmF0b3I6XG4gICAgICAgICAgY2xvdWR3YXRjaC5Db21wYXJpc29uT3BlcmF0b3IuR1JFQVRFUl9USEFOX09SX0VRVUFMX1RPX1RIUkVTSE9MRCxcbiAgICAgICAgdGhyZXNob2xkOiB0aHJlc2hvbGQsXG4gICAgICAgIGV2YWx1YXRpb25QZXJpb2RzOiAxLFxuICAgICAgICB0cmVhdE1pc3NpbmdEYXRhOiBjbG91ZHdhdGNoLlRyZWF0TWlzc2luZ0RhdGEuTk9UX0JSRUFDSElORyxcbiAgICAgICAgbWV0cmljOiB0aGlzLmZhcmdhdGVTZXJ2aWNlLmxvYWRCYWxhbmNlci5tZXRyaWNIdHRwQ29kZUVsYihlbGJDb2RlLCB7XG4gICAgICAgICAgcGVyaW9kOiBjZGsuRHVyYXRpb24ubWludXRlcyhwZXJpb2QpLFxuICAgICAgICAgIHN0YXRpc3RpYzogXCJTdW1cIixcbiAgICAgICAgICBkaW1lbnNpb25zTWFwOiB7XG4gICAgICAgICAgICBMb2FkQmFsYW5jZXI6IHRoaXMuZmFyZ2F0ZVNlcnZpY2UubG9hZEJhbGFuY2VyLmxvYWRCYWxhbmNlckZ1bGxOYW1lLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0pLFxuICAgICAgfVxuICAgICk7XG4gICAgZWxiQWxhcm0uYWRkQWxhcm1BY3Rpb24obmV3IGNsb3Vkd2F0Y2hfYWN0aW9ucy5TbnNBY3Rpb24odG9waWMpKTtcbiAgICBlbGJBbGFybS5hZGRPa0FjdGlvbihuZXcgY2xvdWR3YXRjaF9hY3Rpb25zLlNuc0FjdGlvbih0b3BpYykpO1xuXG4gICAgbGV0IHRhcmdldENvZGU6IGVsYXN0aWNsb2FkYmFsYW5jaW5ndjIuSHR0cENvZGVUYXJnZXQ7XG4gICAgc3dpdGNoIChuYW1lKSB7XG4gICAgICBjYXNlIFwiSFRUUF81WFhcIjpcbiAgICAgICAgdGFyZ2V0Q29kZSA9IGVsYXN0aWNsb2FkYmFsYW5jaW5ndjIuSHR0cENvZGVUYXJnZXQuVEFSR0VUXzVYWF9DT1VOVDtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIFwiSFRUUF80WFhcIjpcbiAgICAgICAgdGFyZ2V0Q29kZSA9IGVsYXN0aWNsb2FkYmFsYW5jaW5ndjIuSHR0cENvZGVUYXJnZXQuVEFSR0VUXzRYWF9DT1VOVDtcbiAgICAgICAgYnJlYWs7XG4gICAgfVxuXG4gICAgbGV0IHRhcmdldEFsYXJtID0gbmV3IGNsb3Vkd2F0Y2guQWxhcm0oXG4gICAgICB0aGlzLFxuICAgICAgXy5rZWJhYkNhc2UobmFtZSArIFwiLXRhcmdldC1hbGFybVwiKSxcbiAgICAgIHtcbiAgICAgICAgYWxhcm1OYW1lOiBuYW1lLFxuICAgICAgICBhbGFybURlc2NyaXB0aW9uOiBkZXNjcmlwdGlvbixcbiAgICAgICAgY29tcGFyaXNvbk9wZXJhdG9yOlxuICAgICAgICAgIGNsb3Vkd2F0Y2guQ29tcGFyaXNvbk9wZXJhdG9yLkdSRUFURVJfVEhBTl9PUl9FUVVBTF9UT19USFJFU0hPTEQsXG4gICAgICAgIHRocmVzaG9sZDogdGhyZXNob2xkLFxuICAgICAgICBldmFsdWF0aW9uUGVyaW9kczogMSxcbiAgICAgICAgdHJlYXRNaXNzaW5nRGF0YTogY2xvdWR3YXRjaC5UcmVhdE1pc3NpbmdEYXRhLk5PVF9CUkVBQ0hJTkcsXG4gICAgICAgIG1ldHJpYzogdGhpcy5mYXJnYXRlU2VydmljZS5sb2FkQmFsYW5jZXIubWV0cmljSHR0cENvZGVUYXJnZXQoXG4gICAgICAgICAgdGFyZ2V0Q29kZSxcbiAgICAgICAgICB7XG4gICAgICAgICAgICBwZXJpb2Q6IGNkay5EdXJhdGlvbi5taW51dGVzKHBlcmlvZCksXG4gICAgICAgICAgICBzdGF0aXN0aWM6IFwiU3VtXCIsXG4gICAgICAgICAgICBkaW1lbnNpb25zTWFwOiB7XG4gICAgICAgICAgICAgIExvYWRCYWxhbmNlcjpcbiAgICAgICAgICAgICAgICB0aGlzLmZhcmdhdGVTZXJ2aWNlLmxvYWRCYWxhbmNlci5sb2FkQmFsYW5jZXJGdWxsTmFtZSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfVxuICAgICAgICApLFxuICAgICAgfVxuICAgICk7XG4gICAgdGFyZ2V0QWxhcm0uYWRkQWxhcm1BY3Rpb24obmV3IGNsb3Vkd2F0Y2hfYWN0aW9ucy5TbnNBY3Rpb24odG9waWMpKTtcbiAgICB0YXJnZXRBbGFybS5hZGRPa0FjdGlvbihuZXcgY2xvdWR3YXRjaF9hY3Rpb25zLlNuc0FjdGlvbih0b3BpYykpO1xuICB9XG5cbiAgcHJpdmF0ZSBhZGRSZWplY3RlZEFsYXJtKFxuICAgIHRvcGljOiBzbnMuSVRvcGljLFxuICAgIHRocmVzaG9sZDogbnVtYmVyLFxuICAgIHBlcmlvZDogbnVtYmVyXG4gICkge1xuICAgIGxldCBhcHBOYW1lID0gQXBwLmluc3RhbmNlLmNvbmZpZ3VyYXRpb24ubmFtZTtcbiAgICBsZXQgYWxhcm0gPSBuZXcgY2xvdWR3YXRjaC5BbGFybSh0aGlzLCBcInJlamVjdGVkLWNvbm5lY3Rpb25zLWFsYXJtXCIsIHtcbiAgICAgIGFsYXJtTmFtZTogXCJSRUpFQ1RFRFwiLFxuICAgICAgYWxhcm1EZXNjcmlwdGlvbjogYCR7YXBwTmFtZX0vJHt0aGlzLm5vZGUuaWR9OiBSZWplY3RlZCBjb25uZWN0aW9ucyB0aHJlc2hvbGQgZXhjZWVkZWRgLFxuICAgICAgY29tcGFyaXNvbk9wZXJhdG9yOlxuICAgICAgICBjbG91ZHdhdGNoLkNvbXBhcmlzb25PcGVyYXRvci5HUkVBVEVSX1RIQU5fT1JfRVFVQUxfVE9fVEhSRVNIT0xELFxuICAgICAgdGhyZXNob2xkOiB0aHJlc2hvbGQsXG4gICAgICBldmFsdWF0aW9uUGVyaW9kczogMSxcbiAgICAgIHRyZWF0TWlzc2luZ0RhdGE6IGNsb3Vkd2F0Y2guVHJlYXRNaXNzaW5nRGF0YS5OT1RfQlJFQUNISU5HLFxuICAgICAgbWV0cmljOiB0aGlzLmZhcmdhdGVTZXJ2aWNlLmxvYWRCYWxhbmNlci5tZXRyaWNSZWplY3RlZENvbm5lY3Rpb25Db3VudCh7XG4gICAgICAgIHBlcmlvZDogY2RrLkR1cmF0aW9uLm1pbnV0ZXMocGVyaW9kKSxcbiAgICAgICAgc3RhdGlzdGljOiBcIlN1bVwiLFxuICAgICAgICBkaW1lbnNpb25zTWFwOiB7XG4gICAgICAgICAgTG9hZEJhbGFuY2VyOiB0aGlzLmZhcmdhdGVTZXJ2aWNlLmxvYWRCYWxhbmNlci5sb2FkQmFsYW5jZXJGdWxsTmFtZSxcbiAgICAgICAgfSxcbiAgICAgIH0pLFxuICAgIH0pO1xuICAgIGFsYXJtLmFkZEFsYXJtQWN0aW9uKG5ldyBjbG91ZHdhdGNoX2FjdGlvbnMuU25zQWN0aW9uKHRvcGljKSk7XG4gICAgYWxhcm0uYWRkT2tBY3Rpb24obmV3IGNsb3Vkd2F0Y2hfYWN0aW9ucy5TbnNBY3Rpb24odG9waWMpKTtcbiAgfVxuXG4gIHByaXZhdGUgYWRkU2xvd0FsYXJtKHRvcGljOiBzbnMuSVRvcGljLCB0aHJlc2hvbGQ6IG51bWJlciwgcGVyaW9kOiBudW1iZXIpIHtcbiAgICBsZXQgYXBwTmFtZSA9IEFwcC5pbnN0YW5jZS5jb25maWd1cmF0aW9uLm5hbWU7XG4gICAgbGV0IGFsYXJtID0gbmV3IGNsb3Vkd2F0Y2guQWxhcm0odGhpcywgXCJyZWplY3RlZC1jb25uZWN0aW9ucy1hbGFybVwiLCB7XG4gICAgICBhbGFybU5hbWU6IFwiUkVKRUNURURcIixcbiAgICAgIGFsYXJtRGVzY3JpcHRpb246IGAke2FwcE5hbWV9LyR7dGhpcy5ub2RlLmlkfTogUmVqZWN0ZWQgY29ubmVjdGlvbnMgdGhyZXNob2xkIGV4Y2VlZGVkYCxcbiAgICAgIGNvbXBhcmlzb25PcGVyYXRvcjpcbiAgICAgICAgY2xvdWR3YXRjaC5Db21wYXJpc29uT3BlcmF0b3IuR1JFQVRFUl9USEFOX09SX0VRVUFMX1RPX1RIUkVTSE9MRCxcbiAgICAgIHRocmVzaG9sZDogdGhyZXNob2xkLFxuICAgICAgZXZhbHVhdGlvblBlcmlvZHM6IDEsXG4gICAgICB0cmVhdE1pc3NpbmdEYXRhOiBjbG91ZHdhdGNoLlRyZWF0TWlzc2luZ0RhdGEuTk9UX0JSRUFDSElORyxcbiAgICAgIG1ldHJpYzogdGhpcy5mYXJnYXRlU2VydmljZS5sb2FkQmFsYW5jZXIubWV0cmljVGFyZ2V0UmVzcG9uc2VUaW1lKHtcbiAgICAgICAgcGVyaW9kOiBjZGsuRHVyYXRpb24ubWludXRlcyhwZXJpb2QpLFxuICAgICAgICBzdGF0aXN0aWM6IFwiU3VtXCIsXG4gICAgICAgIGRpbWVuc2lvbnNNYXA6IHtcbiAgICAgICAgICBMb2FkQmFsYW5jZXI6IHRoaXMuZmFyZ2F0ZVNlcnZpY2UubG9hZEJhbGFuY2VyLmxvYWRCYWxhbmNlckZ1bGxOYW1lLFxuICAgICAgICB9LFxuICAgICAgfSksXG4gICAgfSk7XG4gICAgYWxhcm0uYWRkQWxhcm1BY3Rpb24obmV3IGNsb3Vkd2F0Y2hfYWN0aW9ucy5TbnNBY3Rpb24odG9waWMpKTtcbiAgICBhbGFybS5hZGRPa0FjdGlvbihuZXcgY2xvdWR3YXRjaF9hY3Rpb25zLlNuc0FjdGlvbih0b3BpYykpO1xuICB9XG59XG4iXX0=