cdk-monitoring-constructs
Version:
[](https://badge.fury.io/js/cdk-monitoring-constructs) [](https://m
268 lines • 54 kB
JavaScript
"use strict";
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.CustomMonitoring = exports.AxisPosition = void 0;
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
const aws_cloudwatch_1 = require("aws-cdk-lib/aws-cloudwatch");
const common_1 = require("../../common");
const dashboard_1 = require("../../dashboard");
var AxisPosition;
(function (AxisPosition) {
AxisPosition["LEFT"] = "left";
AxisPosition["RIGHT"] = "right";
})(AxisPosition || (exports.AxisPosition = AxisPosition = {}));
/**
* Custom monitoring is a construct allowing you to monitor your own custom metrics.
* The entire construct consists of metric groups.
* Each metric group represents a single graph widget with multiple metrics.
* Each metric inside the metric group represents a single metric inside a graph.
* The widgets will be sized automatically to waste as little space as possible.
*/
class CustomMonitoring extends common_1.Monitoring {
constructor(scope, props) {
super(scope, props);
const namingStrategy = new dashboard_1.MonitoringNamingStrategy({ ...props });
this.title = namingStrategy.resolveHumanReadableName();
this.description = props.description;
this.descriptionWidgetHeight = props.descriptionWidgetHeight;
this.height = props.height;
this.addToSummaryDashboard = props.addToSummaryDashboard ?? false;
const alarmFactory = this.createAlarmFactory(namingStrategy.resolveAlarmFriendlyName());
this.customAlarmFactory = new common_1.CustomAlarmFactory(alarmFactory);
this.anomalyDetectingAlarmFactory = new common_1.AnomalyDetectingAlarmFactory(alarmFactory);
this.metricGroups = props.metricGroups.map((metricGroup) => {
const metricGroupWithAnnotation = {
metricGroup,
annotations: [],
rightAnnotations: [],
verticalAnnotations: [],
titleAddons: [],
};
if (metricGroup.horizontalAnnotations) {
metricGroupWithAnnotation.annotations.push(...metricGroup.horizontalAnnotations);
}
if (metricGroup.horizontalRightAnnotations) {
metricGroupWithAnnotation.rightAnnotations.push(...metricGroup.horizontalRightAnnotations);
}
if (metricGroup.verticalAnnotations) {
metricGroupWithAnnotation.verticalAnnotations.push(...metricGroup.verticalAnnotations);
}
metricGroup.metrics.forEach((metric) => {
if (this.hasAlarm(metric) && this.hasAnomalyDetection(metric)) {
throw new Error("Adding both a regular alarm and an anomaly detection alarm at the same time is not supported");
}
if (this.hasAlarm(metric)) {
this.setupAlarm(metricGroupWithAnnotation, metric);
}
else if (this.hasAnomalyDetection(metric)) {
this.setupAnomalyDetectionAlarm(metricGroupWithAnnotation, metric);
}
});
return metricGroupWithAnnotation;
});
props.useCreatedAlarms?.consume(this.createdAlarms());
}
summaryWidgets() {
return this.getAllWidgets(true);
}
widgets() {
return this.getAllWidgets(false);
}
getAllWidgets(summary) {
const filteredMetricGroups = summary
? this.metricGroups.filter((group) => group.metricGroup.addToSummaryDashboard ??
group.metricGroup.important ??
this.addToSummaryDashboard)
: this.metricGroups;
if (filteredMetricGroups.length < 1) {
// short-circuit if there are no metrics specified
return [];
}
const rows = [];
// header and description
rows.push(new aws_cloudwatch_1.Row(new dashboard_1.MonitoringHeaderWidget({ title: this.title })));
if (this.description && !summary) {
rows.push(new aws_cloudwatch_1.Row(this.createDescriptionWidget(this.description, this.descriptionWidgetHeight)));
}
// graphs
rows.push(new aws_cloudwatch_1.Row(...this.createCustomMetricGroupWidgets(filteredMetricGroups, summary)));
return rows;
}
createDescriptionWidget(markdown, descriptionWidgetHeight) {
return new aws_cloudwatch_1.TextWidget({
markdown,
width: common_1.FullWidth,
height: descriptionWidgetHeight ?? 1,
});
}
createCustomMetricGroupWidgets(annotatedGroups, summary) {
const widgets = [];
const metricGroupWidgetHeightDefault = summary
? common_1.DefaultSummaryWidgetHeight
: common_1.DefaultGraphWidgetHeight;
const metricGroupWidgetHeight = this.height ?? metricGroupWidgetHeightDefault;
annotatedGroups.forEach((annotatedGroup) => {
const metrics = annotatedGroup.metricGroup.metrics;
const left = this.toMetrics(metrics.filter((metric) => (metric.position ?? AxisPosition.LEFT) ==
AxisPosition.LEFT));
const right = this.toMetrics(metrics.filter((metric) => (metric.position ?? AxisPosition.LEFT) ==
AxisPosition.RIGHT));
const hasOneMetricOnly = metrics.length === 1;
const hasAnomalyDetection = metrics.filter((metric) => this.hasAnomalyDetection(metric)).length > 0;
const useAnomalyDetectionWidget = hasOneMetricOnly && hasAnomalyDetection;
let title = annotatedGroup.metricGroup.title;
if (annotatedGroup.titleAddons.length > 0) {
title = `${title} (${annotatedGroup.titleAddons.join(", ")})`;
}
const graphWidgetProps = {
title,
width: annotatedGroup.metricGroup.graphWidgetWidth ??
(0, common_1.recommendedWidgetWidth)(annotatedGroups.length),
height: metricGroupWidgetHeight,
left,
right,
leftAnnotations: annotatedGroup.annotations,
rightAnnotations: annotatedGroup.rightAnnotations,
leftYAxis: annotatedGroup.metricGroup.graphWidgetAxis,
rightYAxis: annotatedGroup.metricGroup.graphWidgetRightAxis,
verticalAnnotations: annotatedGroup.verticalAnnotations,
legendPosition: annotatedGroup.metricGroup.graphWidgetLegend,
setPeriodToTimeRange: annotatedGroup.metricGroup.graphWidgetSetPeriodToTimeRange,
};
const widget = useAnomalyDetectionWidget
? new AnomalyDetectionGraphWidget(graphWidgetProps)
: (0, common_1.createGraphWidget)(annotatedGroup.metricGroup.graphWidgetType ?? common_1.GraphWidgetType.LINE, graphWidgetProps);
widgets.push(widget);
});
return widgets;
}
toMetrics(metrics) {
const metricFactory = this.createMetricFactory();
return metrics.map((metric) => {
if (this.hasAlarm(metric)) {
// metric with alarm
return metricFactory.adaptMetricPreservingPeriod(metric.metric);
}
else if (this.hasAnomalyDetection(metric)) {
// metric with anomaly detection
return metricFactory.createMetricAnomalyDetection(metric.metric, metric.anomalyDetectionStandardDeviationToRender, `Expected (stdev = ${metric.anomalyDetectionStandardDeviationToRender})`, undefined,
// needs to be unique in the whole widget and start with lowercase
AnomalyDetectionMetricIdPrefix +
(0, common_1.getHashForMetricExpressionId)(metric.alarmFriendlyName),
// preserve the most specific metric period
metric.period ?? metric.metric.period);
}
else if (this.isSearch(metric)) {
// metric search
return metricFactory.createMetricSearch(metric.searchQuery, metric.dimensionsMap, metric.statistic, metric.namespace, metric.label, metric.period, metric.region, metric.account);
}
else {
// general metric
return metricFactory.adaptMetricPreservingPeriod(metric);
}
});
}
hasAlarm(metric) {
// type guard
return metric.addAlarm !== undefined;
}
hasAnomalyDetection(metric) {
// type guard
return (metric
.anomalyDetectionStandardDeviationToRender !== undefined);
}
isSearch(metric) {
// type guard
return metric.searchQuery !== undefined;
}
setupAlarm(metricGroup, metric) {
if (this.isSearch(metric)) {
throw new Error("Alarming on search queries is not supported by CloudWatch");
}
for (const disambiguator in metric.addAlarm) {
const alarmProps = metric.addAlarm[disambiguator];
const createdAlarm = this.customAlarmFactory.addCustomAlarm(metric.metric, metric.alarmFriendlyName, disambiguator, alarmProps);
const targetAnnotations = (metric.position ?? AxisPosition.LEFT) == AxisPosition.LEFT
? metricGroup.annotations
: metricGroup.rightAnnotations;
targetAnnotations.push(createdAlarm.annotation);
this.addAlarm(createdAlarm);
}
}
setupAnomalyDetectionAlarm(metricGroup, metric) {
if (this.isSearch(metric)) {
throw new Error("Alarming on search queries is not supported by CloudWatch");
}
const alarmStDevs = new Set();
const metricFactory = this.createMetricFactory();
for (const disambiguator in metric.addAlarmOnAnomaly) {
const alarmProps = metric.addAlarmOnAnomaly[disambiguator];
if (alarmProps.alarmWhenAboveTheBand ||
alarmProps.alarmWhenBelowTheBand) {
const anomalyMetric = metricFactory.createMetricAnomalyDetection(
// Because the metric was provided to us, we use metricFactory.overrideNamespace() to
// confirm it aligns with any namespace overrides requested for this MonitoringFacade
metricFactory.adaptMetricPreservingPeriod(metric.metric), alarmProps.standardDeviationForAlarm, `Band (stdev ${alarmProps.standardDeviationForAlarm})`, undefined,
// expression ID needs to be unique across the whole widget; needs to start with a lowercase letter
AnomalyDetectionAlarmIdPrefix +
(0, common_1.getHashForMetricExpressionId)(metric.alarmFriendlyName + "_" + disambiguator),
// preserve the most-specific metric period
metric.period ?? metric.metric.period);
const createdAlarm = this.anomalyDetectingAlarmFactory.addAlarmWhenOutOfBand(anomalyMetric, metric.alarmFriendlyName, disambiguator, alarmProps);
// no need to add annotation since the bands are rendered automatically
this.addAlarm(createdAlarm);
alarmStDevs.add(alarmProps.standardDeviationForAlarm);
}
}
if (alarmStDevs.size > 0) {
const alarmStDevsString = Array.from(alarmStDevs).sort().join(", ");
metricGroup.titleAddons.push(`alarms with stdev ${alarmStDevsString}`);
}
}
}
exports.CustomMonitoring = CustomMonitoring;
_a = JSII_RTTI_SYMBOL_1;
CustomMonitoring[_a] = { fqn: "cdk-monitoring-constructs.CustomMonitoring", version: "10.0.0" };
const AnomalyDetectionAlarmIdPrefix = "alarm_";
const AnomalyDetectionMetricIdPrefix = "anomaly_";
const AnomalyBandMetricIdSuffix = "_band";
/**
* INTERNAL - PLEASE DO NOT USE
* This is a hacky solution to make band visible in GraphWidget (default widget only renders lines, not the band).
* The class makes assumptions about the internal JSON structure but found no other way :(.
* Ideally, we want to remove this hack once the anomaly detection rendering in CDK gets improved
*/
class AnomalyDetectionGraphWidget extends aws_cloudwatch_1.GraphWidget {
constructor(props) {
super(props);
}
toJson() {
const json = super.toJson();
if (json.length !== 1 || !json?.[0]?.properties?.metrics) {
throw new Error("The JSON is expected to have exactly one element with properties.metrics property.");
}
const metrics = json[0].properties.metrics;
if (metrics.length < 2) {
throw new Error("The number of metrics must be at least two (metric + anomaly detection math).");
}
const anomalyDetectionMetricPart = metrics[0]?.value;
if (!anomalyDetectionMetricPart ||
anomalyDetectionMetricPart.length !== 1) {
throw new Error("First metric must be a math expression.");
}
const evaluatedMetricPart = metrics[1]?.value;
if (!evaluatedMetricPart ||
evaluatedMetricPart.length < 1 ||
!evaluatedMetricPart[evaluatedMetricPart.length - 1].id) {
throw new Error("Second metric must have an ID.");
}
// band rendering requires ID to be set
anomalyDetectionMetricPart[0].id =
evaluatedMetricPart[evaluatedMetricPart.length - 1].id +
AnomalyBandMetricIdSuffix;
// band rendering requires the evaluated metric to be visible
evaluatedMetricPart[evaluatedMetricPart.length - 1].visible = true;
return json;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ3VzdG9tTW9uaXRvcmluZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIkN1c3RvbU1vbml0b3JpbmcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFDQSwrREFZb0M7QUFFcEMseUNBaUJzQjtBQUN0QiwrQ0FHeUI7QUFFekIsSUFBWSxZQUdYO0FBSEQsV0FBWSxZQUFZO0lBQ3RCLDZCQUFhLENBQUE7SUFDYiwrQkFBZSxDQUFBO0FBQ2pCLENBQUMsRUFIVyxZQUFZLDRCQUFaLFlBQVksUUFHdkI7QUE4TkQ7Ozs7OztHQU1HO0FBQ0gsTUFBYSxnQkFBaUIsU0FBUSxtQkFBVTtJQVU5QyxZQUFZLEtBQXNCLEVBQUUsS0FBNEI7UUFDOUQsS0FBSyxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztRQUVwQixNQUFNLGNBQWMsR0FBRyxJQUFJLG9DQUF3QixDQUFDLEVBQUUsR0FBRyxLQUFLLEVBQUUsQ0FBQyxDQUFDO1FBQ2xFLElBQUksQ0FBQyxLQUFLLEdBQUcsY0FBYyxDQUFDLHdCQUF3QixFQUFFLENBQUM7UUFFdkQsSUFBSSxDQUFDLFdBQVcsR0FBRyxLQUFLLENBQUMsV0FBVyxDQUFDO1FBQ3JDLElBQUksQ0FBQyx1QkFBdUIsR0FBRyxLQUFLLENBQUMsdUJBQXVCLENBQUM7UUFDN0QsSUFBSSxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDO1FBQzNCLElBQUksQ0FBQyxxQkFBcUIsR0FBRyxLQUFLLENBQUMscUJBQXFCLElBQUksS0FBSyxDQUFDO1FBRWxFLE1BQU0sWUFBWSxHQUFHLElBQUksQ0FBQyxrQkFBa0IsQ0FDMUMsY0FBYyxDQUFDLHdCQUF3QixFQUFFLENBQzFDLENBQUM7UUFDRixJQUFJLENBQUMsa0JBQWtCLEdBQUcsSUFBSSwyQkFBa0IsQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUMvRCxJQUFJLENBQUMsNEJBQTRCLEdBQUcsSUFBSSxxQ0FBNEIsQ0FDbEUsWUFBWSxDQUNiLENBQUM7UUFFRixJQUFJLENBQUMsWUFBWSxHQUFHLEtBQUssQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLENBQUMsV0FBVyxFQUFFLEVBQUU7WUFDekQsTUFBTSx5QkFBeUIsR0FBcUM7Z0JBQ2xFLFdBQVc7Z0JBQ1gsV0FBVyxFQUFFLEVBQUU7Z0JBQ2YsZ0JBQWdCLEVBQUUsRUFBRTtnQkFDcEIsbUJBQW1CLEVBQUUsRUFBRTtnQkFDdkIsV0FBVyxFQUFFLEVBQUU7YUFDaEIsQ0FBQztZQUVGLElBQUksV0FBVyxDQUFDLHFCQUFxQixFQUFFLENBQUM7Z0JBQ3RDLHlCQUF5QixDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQ3hDLEdBQUcsV0FBVyxDQUFDLHFCQUFxQixDQUNyQyxDQUFDO1lBQ0osQ0FBQztZQUNELElBQUksV0FBVyxDQUFDLDBCQUEwQixFQUFFLENBQUM7Z0JBQzNDLHlCQUF5QixDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FDN0MsR0FBRyxXQUFXLENBQUMsMEJBQTBCLENBQzFDLENBQUM7WUFDSixDQUFDO1lBQ0QsSUFBSSxXQUFXLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztnQkFDcEMseUJBQXlCLENBQUMsbUJBQW1CLENBQUMsSUFBSSxDQUNoRCxHQUFHLFdBQVcsQ0FBQyxtQkFBbUIsQ0FDbkMsQ0FBQztZQUNKLENBQUM7WUFFRCxXQUFXLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFO2dCQUNyQyxJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLElBQUksSUFBSSxDQUFDLG1CQUFtQixDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7b0JBQzlELE1BQU0sSUFBSSxLQUFLLENBQ2IsOEZBQThGLENBQy9GLENBQUM7Z0JBQ0osQ0FBQztnQkFFRCxJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztvQkFDMUIsSUFBSSxDQUFDLFVBQVUsQ0FBQyx5QkFBeUIsRUFBRSxNQUFNLENBQUMsQ0FBQztnQkFDckQsQ0FBQztxQkFBTSxJQUFJLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO29CQUM1QyxJQUFJLENBQUMsMEJBQTBCLENBQUMseUJBQXlCLEVBQUUsTUFBTSxDQUFDLENBQUM7Z0JBQ3JFLENBQUM7WUFDSCxDQUFDLENBQUMsQ0FBQztZQUVILE9BQU8seUJBQXlCLENBQUM7UUFDbkMsQ0FBQyxDQUFDLENBQUM7UUFFSCxLQUFLLENBQUMsZ0JBQWdCLEVBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQyxDQUFDO0lBQ3hELENBQUM7SUFFRCxjQUFjO1FBQ1osT0FBTyxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2xDLENBQUM7SUFFRCxPQUFPO1FBQ0wsT0FBTyxJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ25DLENBQUM7SUFFTyxhQUFhLENBQUMsT0FBZ0I7UUFDcEMsTUFBTSxvQkFBb0IsR0FBRyxPQUFPO1lBQ2xDLENBQUMsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FDdEIsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUNSLEtBQUssQ0FBQyxXQUFXLENBQUMscUJBQXFCO2dCQUN2QyxLQUFLLENBQUMsV0FBVyxDQUFDLFNBQVM7Z0JBQzNCLElBQUksQ0FBQyxxQkFBcUIsQ0FDN0I7WUFDSCxDQUFDLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQztRQUV0QixJQUFJLG9CQUFvQixDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUNwQyxrREFBa0Q7WUFDbEQsT0FBTyxFQUFFLENBQUM7UUFDWixDQUFDO1FBRUQsTUFBTSxJQUFJLEdBQVUsRUFBRSxDQUFDO1FBRXZCLHlCQUF5QjtRQUN6QixJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksb0JBQUcsQ0FBQyxJQUFJLGtDQUFzQixDQUFDLEVBQUUsS0FBSyxFQUFFLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN0RSxJQUFJLElBQUksQ0FBQyxXQUFXLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNqQyxJQUFJLENBQUMsSUFBSSxDQUNQLElBQUksb0JBQUcsQ0FDTCxJQUFJLENBQUMsdUJBQXVCLENBQzFCLElBQUksQ0FBQyxXQUFXLEVBQ2hCLElBQUksQ0FBQyx1QkFBdUIsQ0FDN0IsQ0FDRixDQUNGLENBQUM7UUFDSixDQUFDO1FBRUQsU0FBUztRQUNULElBQUksQ0FBQyxJQUFJLENBQ1AsSUFBSSxvQkFBRyxDQUNMLEdBQUcsSUFBSSxDQUFDLDhCQUE4QixDQUFDLG9CQUFvQixFQUFFLE9BQU8sQ0FBQyxDQUN0RSxDQUNGLENBQUM7UUFFRixPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFTyx1QkFBdUIsQ0FDN0IsUUFBZ0IsRUFDaEIsdUJBQWdDO1FBRWhDLE9BQU8sSUFBSSwyQkFBVSxDQUFDO1lBQ3BCLFFBQVE7WUFDUixLQUFLLEVBQUUsa0JBQVM7WUFDaEIsTUFBTSxFQUFFLHVCQUF1QixJQUFJLENBQUM7U0FDckMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVPLDhCQUE4QixDQUNwQyxlQUFtRCxFQUNuRCxPQUFnQjtRQUVoQixNQUFNLE9BQU8sR0FBYyxFQUFFLENBQUM7UUFDOUIsTUFBTSw4QkFBOEIsR0FBRyxPQUFPO1lBQzVDLENBQUMsQ0FBQyxtQ0FBMEI7WUFDNUIsQ0FBQyxDQUFDLGlDQUF3QixDQUFDO1FBQzdCLE1BQU0sdUJBQXVCLEdBQzNCLElBQUksQ0FBQyxNQUFNLElBQUksOEJBQThCLENBQUM7UUFFaEQsZUFBZSxDQUFDLE9BQU8sQ0FBQyxDQUFDLGNBQWMsRUFBRSxFQUFFO1lBQ3pDLE1BQU0sT0FBTyxHQUFHLGNBQWMsQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDO1lBQ25ELE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQ3pCLE9BQU8sQ0FBQyxNQUFNLENBQ1osQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUNULENBQUUsTUFBYyxDQUFDLFFBQVEsSUFBSSxZQUFZLENBQUMsSUFBSSxDQUFDO2dCQUMvQyxZQUFZLENBQUMsSUFBSSxDQUNwQixDQUNGLENBQUM7WUFDRixNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsU0FBUyxDQUMxQixPQUFPLENBQUMsTUFBTSxDQUNaLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FDVCxDQUFFLE1BQWMsQ0FBQyxRQUFRLElBQUksWUFBWSxDQUFDLElBQUksQ0FBQztnQkFDL0MsWUFBWSxDQUFDLEtBQUssQ0FDckIsQ0FDRixDQUFDO1lBQ0YsTUFBTSxnQkFBZ0IsR0FBRyxPQUFPLENBQUMsTUFBTSxLQUFLLENBQUMsQ0FBQztZQUM5QyxNQUFNLG1CQUFtQixHQUN2QixPQUFPLENBQUMsTUFBTSxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsbUJBQW1CLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDO1lBQzFFLE1BQU0seUJBQXlCLEdBQUcsZ0JBQWdCLElBQUksbUJBQW1CLENBQUM7WUFDMUUsSUFBSSxLQUFLLEdBQUcsY0FBYyxDQUFDLFdBQVcsQ0FBQyxLQUFLLENBQUM7WUFFN0MsSUFBSSxjQUFjLENBQUMsV0FBVyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDMUMsS0FBSyxHQUFHLEdBQUcsS0FBSyxLQUFLLGNBQWMsQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUM7WUFDaEUsQ0FBQztZQUVELE1BQU0sZ0JBQWdCLEdBQXFCO2dCQUN6QyxLQUFLO2dCQUNMLEtBQUssRUFDSCxjQUFjLENBQUMsV0FBVyxDQUFDLGdCQUFnQjtvQkFDM0MsSUFBQSwrQkFBc0IsRUFBQyxlQUFlLENBQUMsTUFBTSxDQUFDO2dCQUNoRCxNQUFNLEVBQUUsdUJBQXVCO2dCQUMvQixJQUFJO2dCQUNKLEtBQUs7Z0JBQ0wsZUFBZSxFQUFFLGNBQWMsQ0FBQyxXQUFXO2dCQUMzQyxnQkFBZ0IsRUFBRSxjQUFjLENBQUMsZ0JBQWdCO2dCQUNqRCxTQUFTLEVBQUUsY0FBYyxDQUFDLFdBQVcsQ0FBQyxlQUFlO2dCQUNyRCxVQUFVLEVBQUUsY0FBYyxDQUFDLFdBQVcsQ0FBQyxvQkFBb0I7Z0JBQzNELG1CQUFtQixFQUFFLGNBQWMsQ0FBQyxtQkFBbUI7Z0JBQ3ZELGNBQWMsRUFBRSxjQUFjLENBQUMsV0FBVyxDQUFDLGlCQUFpQjtnQkFDNUQsb0JBQW9CLEVBQ2xCLGNBQWMsQ0FBQyxXQUFXLENBQUMsK0JBQStCO2FBQzdELENBQUM7WUFFRixNQUFNLE1BQU0sR0FBRyx5QkFBeUI7Z0JBQ3RDLENBQUMsQ0FBQyxJQUFJLDJCQUEyQixDQUFDLGdCQUFnQixDQUFDO2dCQUNuRCxDQUFDLENBQUMsSUFBQSwwQkFBaUIsRUFDZixjQUFjLENBQUMsV0FBVyxDQUFDLGVBQWUsSUFBSSx3QkFBZSxDQUFDLElBQUksRUFDbEUsZ0JBQWdCLENBQ2pCLENBQUM7WUFFTixPQUFPLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3ZCLENBQUMsQ0FBQyxDQUFDO1FBRUgsT0FBTyxPQUFPLENBQUM7SUFDakIsQ0FBQztJQUVPLFNBQVMsQ0FBQyxPQUF1QjtRQUN2QyxNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztRQUVqRCxPQUFPLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRTtZQUM1QixJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztnQkFDMUIsb0JBQW9CO2dCQUNwQixPQUFPLGFBQWEsQ0FBQywyQkFBMkIsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDbEUsQ0FBQztpQkFBTSxJQUFJLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO2dCQUM1QyxnQ0FBZ0M7Z0JBQ2hDLE9BQU8sYUFBYSxDQUFDLDRCQUE0QixDQUMvQyxNQUFNLENBQUMsTUFBTSxFQUNiLE1BQU0sQ0FBQyx5Q0FBeUMsRUFDaEQscUJBQXFCLE1BQU0sQ0FBQyx5Q0FBeUMsR0FBRyxFQUN4RSxTQUFTO2dCQUNULGtFQUFrRTtnQkFDbEUsOEJBQThCO29CQUM1QixJQUFBLHFDQUE0QixFQUFDLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQztnQkFDeEQsMkNBQTJDO2dCQUMzQyxNQUFNLENBQUMsTUFBTSxJQUFJLE1BQU0sQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUN0QyxDQUFDO1lBQ0osQ0FBQztpQkFBTSxJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztnQkFDakMsZ0JBQWdCO2dCQUNoQixPQUFPLGFBQWEsQ0FBQyxrQkFBa0IsQ0FDckMsTUFBTSxDQUFDLFdBQVcsRUFDbEIsTUFBTSxDQUFDLGFBQWEsRUFDcEIsTUFBTSxDQUFDLFNBQVMsRUFDaEIsTUFBTSxDQUFDLFNBQVMsRUFDaEIsTUFBTSxDQUFDLEtBQUssRUFDWixNQUFNLENBQUMsTUFBTSxFQUNiLE1BQU0sQ0FBQyxNQUFNLEVBQ2IsTUFBTSxDQUFDLE9BQU8sQ0FDZixDQUFDO1lBQ0osQ0FBQztpQkFBTSxDQUFDO2dCQUNOLGlCQUFpQjtnQkFDakIsT0FBTyxhQUFhLENBQUMsMkJBQTJCLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDM0QsQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVPLFFBQVEsQ0FBQyxNQUFvQjtRQUNuQyxhQUFhO1FBQ2IsT0FBUSxNQUFnQyxDQUFDLFFBQVEsS0FBSyxTQUFTLENBQUM7SUFDbEUsQ0FBQztJQUVPLG1CQUFtQixDQUN6QixNQUFvQjtRQUVwQixhQUFhO1FBQ2IsT0FBTyxDQUNKLE1BQTJDO2FBQ3pDLHlDQUF5QyxLQUFLLFNBQVMsQ0FDM0QsQ0FBQztJQUNKLENBQUM7SUFFTyxRQUFRLENBQUMsTUFBb0I7UUFDbkMsYUFBYTtRQUNiLE9BQVEsTUFBNkIsQ0FBQyxXQUFXLEtBQUssU0FBUyxDQUFDO0lBQ2xFLENBQUM7SUFFTyxVQUFVLENBQ2hCLFdBQTZDLEVBQzdDLE1BQTZCO1FBRTdCLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO1lBQzFCLE1BQU0sSUFBSSxLQUFLLENBQ2IsMkRBQTJELENBQzVELENBQUM7UUFDSixDQUFDO1FBRUQsS0FBSyxNQUFNLGFBQWEsSUFBSSxNQUFNLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDNUMsTUFBTSxVQUFVLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQyxhQUFhLENBQUMsQ0FBQztZQUNsRCxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsa0JBQWtCLENBQUMsY0FBYyxDQUN6RCxNQUFNLENBQUMsTUFBTSxFQUNiLE1BQU0sQ0FBQyxpQkFBaUIsRUFDeEIsYUFBYSxFQUNiLFVBQVUsQ0FDWCxDQUFDO1lBQ0YsTUFBTSxpQkFBaUIsR0FDckIsQ0FBQyxNQUFNLENBQUMsUUFBUSxJQUFJLFlBQVksQ0FBQyxJQUFJLENBQUMsSUFBSSxZQUFZLENBQUMsSUFBSTtnQkFDekQsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxXQUFXO2dCQUN6QixDQUFDLENBQUMsV0FBVyxDQUFDLGdCQUFnQixDQUFDO1lBQ25DLGlCQUFpQixDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsVUFBVSxDQUFDLENBQUM7WUFDaEQsSUFBSSxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUM5QixDQUFDO0lBQ0gsQ0FBQztJQUVPLDBCQUEwQixDQUNoQyxXQUE2QyxFQUM3QyxNQUF3QztRQUV4QyxJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztZQUMxQixNQUFNLElBQUksS0FBSyxDQUNiLDJEQUEyRCxDQUM1RCxDQUFDO1FBQ0osQ0FBQztRQUVELE1BQU0sV0FBVyxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7UUFDdEMsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLG1CQUFtQixFQUFFLENBQUM7UUFFakQsS0FBSyxNQUFNLGFBQWEsSUFBSSxNQUFNLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztZQUNyRCxNQUFNLFVBQVUsR0FBRyxNQUFNLENBQUMsaUJBQWlCLENBQUMsYUFBYSxDQUFDLENBQUM7WUFDM0QsSUFDRSxVQUFVLENBQUMscUJBQXFCO2dCQUNoQyxVQUFVLENBQUMscUJBQXFCLEVBQ2hDLENBQUM7Z0JBQ0QsTUFBTSxhQUFhLEdBQUcsYUFBYSxDQUFDLDRCQUE0QjtnQkFDOUQscUZBQXFGO2dCQUNyRixxRkFBcUY7Z0JBQ3JGLGFBQWEsQ0FBQywyQkFBMkIsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLEVBQ3hELFVBQVUsQ0FBQyx5QkFBeUIsRUFDcEMsZUFBZSxVQUFVLENBQUMseUJBQXlCLEdBQUcsRUFDdEQsU0FBUztnQkFDVCxtR0FBbUc7Z0JBQ25HLDZCQUE2QjtvQkFDM0IsSUFBQSxxQ0FBNEIsRUFDMUIsTUFBTSxDQUFDLGlCQUFpQixHQUFHLEdBQUcsR0FBRyxhQUFhLENBQy9DO2dCQUNILDJDQUEyQztnQkFDM0MsTUFBTSxDQUFDLE1BQU0sSUFBSSxNQUFNLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FDdEMsQ0FBQztnQkFFRixNQUFNLFlBQVksR0FDaEIsSUFBSSxDQUFDLDRCQUE0QixDQUFDLHFCQUFxQixDQUNyRCxhQUFhLEVBQ2IsTUFBTSxDQUFDLGlCQUFpQixFQUN4QixhQUFhLEVBQ2IsVUFBVSxDQUNYLENBQUM7Z0JBRUosdUVBQXVFO2dCQUN2RSxJQUFJLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBQyxDQUFDO2dCQUM1QixXQUFXLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyx5QkFBeUIsQ0FBQyxDQUFDO1lBQ3hELENBQUM7UUFDSCxDQUFDO1FBRUQsSUFBSSxXQUFXLENBQUMsSUFBSSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3pCLE1BQU0saUJBQWlCLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDcEUsV0FBVyxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMscUJBQXFCLGlCQUFpQixFQUFFLENBQUMsQ0FBQztRQUN6RSxDQUFDO0lBQ0gsQ0FBQzs7QUFwVkgsNENBcVZDOzs7QUFFRCxNQUFNLDZCQUE2QixHQUFHLFFBQVEsQ0FBQztBQUMvQyxNQUFNLDhCQUE4QixHQUFHLFVBQVUsQ0FBQztBQUNsRCxNQUFNLHlCQUF5QixHQUFHLE9BQU8sQ0FBQztBQUUxQzs7Ozs7R0FLRztBQUNILE1BQU0sMkJBQTRCLFNBQVEsNEJBQVc7SUFDbkQsWUFBWSxLQUF1QjtRQUNqQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDZixDQUFDO0lBRUQsTUFBTTtRQUNKLE1BQU0sSUFBSSxHQUFHLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUM1QixJQUFJLElBQUksQ0FBQyxNQUFNLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsVUFBVSxFQUFFLE9BQU8sRUFBRSxDQUFDO1lBQ3pELE1BQU0sSUFBSSxLQUFLLENBQ2Isb0ZBQW9GLENBQ3JGLENBQUM7UUFDSixDQUFDO1FBQ0QsTUFBTSxPQUFPLEdBQVUsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUM7UUFDbEQsSUFBSSxPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3ZCLE1BQU0sSUFBSSxLQUFLLENBQ2IsK0VBQStFLENBQ2hGLENBQUM7UUFDSixDQUFDO1FBQ0QsTUFBTSwwQkFBMEIsR0FBVSxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDO1FBQzVELElBQ0UsQ0FBQywwQkFBMEI7WUFDM0IsMEJBQTBCLENBQUMsTUFBTSxLQUFLLENBQUMsRUFDdkMsQ0FBQztZQUNELE1BQU0sSUFBSSxLQUFLLENBQUMseUNBQXlDLENBQUMsQ0FBQztRQUM3RCxDQUFDO1FBQ0QsTUFBTSxtQkFBbUIsR0FBVSxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDO1FBQ3JELElBQ0UsQ0FBQyxtQkFBbUI7WUFDcEIsbUJBQW1CLENBQUMsTUFBTSxHQUFHLENBQUM7WUFDOUIsQ0FBQyxtQkFBbUIsQ0FBQyxtQkFBbUIsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUN2RCxDQUFDO1lBQ0QsTUFBTSxJQUFJLEtBQUssQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFDO1FBQ3BELENBQUM7UUFDRCx1Q0FBdUM7UUFDdkMsMEJBQTBCLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRTtZQUM5QixtQkFBbUIsQ0FBQyxtQkFBbUIsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRTtnQkFDdEQseUJBQXlCLENBQUM7UUFDNUIsNkRBQTZEO1FBQzdELG1CQUFtQixDQUFDLG1CQUFtQixDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDO1FBQ25FLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRHVyYXRpb24gfSBmcm9tIFwiYXdzLWNkay1saWJcIjtcbmltcG9ydCB7XG4gIERpbWVuc2lvbnNNYXAsXG4gIEdyYXBoV2lkZ2V0LFxuICBHcmFwaFdpZGdldFByb3BzLFxuICBIb3Jpem9udGFsQW5ub3RhdGlvbixcbiAgSU1ldHJpYyxcbiAgSVdpZGdldCxcbiAgTGVnZW5kUG9zaXRpb24sXG4gIFJvdyxcbiAgVGV4dFdpZGdldCxcbiAgVmVydGljYWxBbm5vdGF0aW9uLFxuICBZQXhpc1Byb3BzLFxufSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWNsb3Vkd2F0Y2hcIjtcblxuaW1wb3J0IHtcbiAgQW5vbWFseURldGVjdGluZ0FsYXJtRmFjdG9yeSxcbiAgQW5vbWFseURldGVjdGlvblRocmVzaG9sZCxcbiAgQmFzZU1vbml0b3JpbmdQcm9wcyxcbiAgY3JlYXRlR3JhcGhXaWRnZXQsXG4gIEN1c3RvbUFsYXJtRmFjdG9yeSxcbiAgQ3VzdG9tVGhyZXNob2xkLFxuICBEZWZhdWx0R3JhcGhXaWRnZXRIZWlnaHQsXG4gIERlZmF1bHRTdW1tYXJ5V2lkZ2V0SGVpZ2h0LFxuICBGdWxsV2lkdGgsXG4gIGdldEhhc2hGb3JNZXRyaWNFeHByZXNzaW9uSWQsXG4gIEdyYXBoV2lkZ2V0VHlwZSxcbiAgTWV0cmljU3RhdGlzdGljLFxuICBNZXRyaWNXaXRoQWxhcm1TdXBwb3J0LFxuICBNb25pdG9yaW5nLFxuICBNb25pdG9yaW5nU2NvcGUsXG4gIHJlY29tbWVuZGVkV2lkZ2V0V2lkdGgsXG59IGZyb20gXCIuLi8uLi9jb21tb25cIjtcbmltcG9ydCB7XG4gIE1vbml0b3JpbmdIZWFkZXJXaWRnZXQsXG4gIE1vbml0b3JpbmdOYW1pbmdTdHJhdGVneSxcbn0gZnJvbSBcIi4uLy4uL2Rhc2hib2FyZFwiO1xuXG5leHBvcnQgZW51bSBBeGlzUG9zaXRpb24ge1xuICBMRUZUID0gXCJsZWZ0XCIsXG4gIFJJR0hUID0gXCJyaWdodFwiLFxufVxuXG4vKipcbiAqIEN1c3RvbSBtZXRyaWMgd2l0aCBhbiBhbGFybSBkZWZpbmVkLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEN1c3RvbU1ldHJpY1dpdGhBbGFybSB7XG4gIC8qKlxuICAgKiBtZXRyaWMgdG8gYWxhcm0gb25cbiAgICovXG4gIHJlYWRvbmx5IG1ldHJpYzogTWV0cmljV2l0aEFsYXJtU3VwcG9ydDtcbiAgLyoqXG4gICAqIGFsYXJtIGZyaWVuZGx5IG5hbWVcbiAgICovXG4gIHJlYWRvbmx5IGFsYXJtRnJpZW5kbHlOYW1lOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBhbGFybSBkZWZpbml0aW9uc1xuICAgKi9cbiAgcmVhZG9ubHkgYWRkQWxhcm06IFJlY29yZDxzdHJpbmcsIEN1c3RvbVRocmVzaG9sZD47XG4gIC8qKlxuICAgKiBheGlzIChyaWdodCBvciBsZWZ0KSBvbiB3aGljaCB0byBncmFwaCBtZXRyaWNcbiAgICogZGVmYXVsdDogQXhpc1Bvc2l0aW9uLkxFRlRcbiAgICovXG4gIHJlYWRvbmx5IHBvc2l0aW9uPzogQXhpc1Bvc2l0aW9uO1xufVxuXG4vKipcbiAqIEN1c3RvbSBtZXRyaWMgd2l0aCBhbm9tYWx5IGRldGVjdGlvbi5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDdXN0b21NZXRyaWNXaXRoQW5vbWFseURldGVjdGlvbiB7XG4gIC8qKlxuICAgKiBtZXRyaWMgdG8gYWxhcm0gb25cbiAgICovXG4gIHJlYWRvbmx5IG1ldHJpYzogTWV0cmljV2l0aEFsYXJtU3VwcG9ydDtcbiAgLyoqXG4gICAqIGFub21hbHkgZGV0ZWN0aW9uIHBlcmlvZFxuICAgKiBAZGVmYXVsdCAtIG1ldHJpYyBwZXJpb2QgKGlmIGRlZmluZWQpIG9yIGdsb2JhbCBkZWZhdWx0XG4gICAqL1xuICByZWFkb25seSBwZXJpb2Q/OiBEdXJhdGlvbjtcbiAgLyoqXG4gICAqIGFsYXJtIGZyaWVuZGx5IG5hbWVcbiAgICovXG4gIHJlYWRvbmx5IGFsYXJtRnJpZW5kbHlOYW1lOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBzdGFuZGFyZCBkZXZpYXRpb24gZm9yIHRoZSBhbm9tYWx5IGRldGVjdGlvbiB0byBiZSByZW5kZXJlZCBvbiB0aGUgZ3JhcGggd2lkZ2V0XG4gICAqL1xuICByZWFkb25seSBhbm9tYWx5RGV0ZWN0aW9uU3RhbmRhcmREZXZpYXRpb25Ub1JlbmRlcjogbnVtYmVyO1xuICAvKipcbiAgICogYWRkcyBhbGFybSBvbiBhIGRldGVjdGVkIGFub21hbHlcbiAgICovXG4gIHJlYWRvbmx5IGFkZEFsYXJtT25Bbm9tYWx5PzogUmVjb3JkPHN0cmluZywgQW5vbWFseURldGVjdGlvblRocmVzaG9sZD47XG59XG5cbi8qKlxuICogQ3VzdG9tIG1ldHJpYyBzZWFyY2guXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ3VzdG9tTWV0cmljU2VhcmNoIHtcbiAgLyoqXG4gICAqIG1ldHJpYyBuYW1lc3BhY2VcbiAgICogQGRlZmF1bHQgLSBub25lXG4gICAqL1xuICByZWFkb25seSBuYW1lc3BhY2U/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBzZWFyY2ggcXVlcnkgKGNhbiBiZSBlbXB0eSlcbiAgICovXG4gIHJlYWRvbmx5IHNlYXJjaFF1ZXJ5OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBjdXN0b20gbGFiZWwgZm9yIHRoZSBtZXRyaWNzXG4gICAqIEBkZWZhdWx0IC0gXCIgXCJcbiAgICovXG4gIHJlYWRvbmx5IGxhYmVsPzogc3RyaW5nO1xuICAvKipcbiAgICogc2VhcmNoIGRpbWVuc2lvbnMgKGNhbiBiZSBlbXB0eSlcbiAgICovXG4gIHJlYWRvbmx5IGRpbWVuc2lvbnNNYXA6IERpbWVuc2lvbnNNYXA7XG4gIC8qKlxuICAgKiBtZXRyaWMgc3RhdGlzdGljXG4gICAqL1xuICByZWFkb25seSBzdGF0aXN0aWM6IE1ldHJpY1N0YXRpc3RpYztcbiAgLyoqXG4gICAqIG1ldHJpYyBwZXJpb2RcbiAgICogQGRlZmF1bHQgLSBnbG9iYWwgZGVmYXVsdFxuICAgKi9cbiAgcmVhZG9ubHkgcGVyaW9kPzogRHVyYXRpb247XG4gIC8qKlxuICAgKiBheGlzIChyaWdodCBvciBsZWZ0KSBvbiB3aGljaCB0byBncmFwaCBtZXRyaWNcbiAgICogZGVmYXVsdDogQXhpc1Bvc2l0aW9uLkxFRlRcbiAgICovXG4gIHJlYWRvbmx5IHBvc2l0aW9uPzogQXhpc1Bvc2l0aW9uO1xuXG4gIC8qKlxuICAgKiBBY2NvdW50IHdoaWNoIHRoaXMgbWV0cmljIGNvbWVzIGZyb20uXG4gICAqIE5vdGUgdGhhdCBhbGFybXMgY2Fubm90IGJlIGNyZWF0ZWQgZm9yIGNyb3NzLWFjY291bnQgbWV0cmljcy5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBEZXBsb3ltZW50IGFjY291bnQuXG4gICAqL1xuICByZWFkb25seSBhY2NvdW50Pzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBSZWdpb24gd2hpY2ggdGhpcyBtZXRyaWMgY29tZXMgZnJvbS5cbiAgICogTm90ZSB0aGF0IGFsYXJtcyBjYW5ub3QgYmUgY3JlYXRlZCBmb3IgY3Jvc3MtcmVnaW9uIG1ldHJpY3MuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gRGVwbG95bWVudCByZWdpb24uXG4gICAqL1xuICByZWFkb25seSByZWdpb24/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogRWFjaCBjdXN0b20gbWV0cmljIGNhbiBiZSBvZiBmb3VyIHR5cGVzOlxuICogQHNlZSBNZXRyaWNXaXRoQWxhcm1TdXBwb3J0IGZvciBhIHN0YW5kYXJkIG1ldHJpY1xuICogQHNlZSBDdXN0b21NZXRyaWNTZWFyY2ggZm9yIGEgc2VhcmNoXG4gKiBAc2VlIEN1c3RvbU1ldHJpY1dpdGhBbGFybSBmb3IgYSBtZXRyaWMgd2l0aCBhbiBhbGFybVxuICogQHNlZSBDdXN0b21NZXRyaWNXaXRoQW5vbWFseURldGVjdGlvbiBmb3IgYSBtZXRyaWMgd2l0aCBhbiBhbm9tYWx5IGRldGVjdGluZyBhbGFybVxuICovXG5leHBvcnQgdHlwZSBDdXN0b21NZXRyaWMgPVxuICB8IE1ldHJpY1dpdGhBbGFybVN1cHBvcnRcbiAgfCBDdXN0b21NZXRyaWNTZWFyY2hcbiAgfCBDdXN0b21NZXRyaWNXaXRoQWxhcm1cbiAgfCBDdXN0b21NZXRyaWNXaXRoQW5vbWFseURldGVjdGlvbjtcblxuLyoqXG4gKiBDdXN0b20gbWV0cmljIGdyb3VwIHJlcHJlc2VudHMgYSBzaW5nbGUgd2lkZ2V0LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEN1c3RvbU1ldHJpY0dyb3VwIHtcbiAgLyoqXG4gICAqIHRpdGxlIG9mIHRoZSB3aG9sZSBncm91cFxuICAgKi9cbiAgcmVhZG9ubHkgdGl0bGU6IHN0cmluZztcbiAgLyoqXG4gICAqIHR5cGUgb2YgdGhlIHdpZGdldFxuICAgKiBAZGVmYXVsdCBsaW5lXG4gICAqL1xuICByZWFkb25seSBncmFwaFdpZGdldFR5cGU/OiBHcmFwaFdpZGdldFR5cGU7XG4gIC8qKlxuICAgKiBvcHRpb25hbCBheGlzXG4gICAqIEBkZWZhdWx0IHVuZGVmaW5lZFxuICAgKi9cbiAgcmVhZG9ubHkgZ3JhcGhXaWRnZXRBeGlzPzogWUF4aXNQcm9wcztcbiAgLyoqXG4gICAqIG9wdGlvbmFsIHJpZ2h0IGF4aXNcbiAgICogQGRlZmF1bHQgdW5kZWZpbmVkXG4gICAqL1xuICByZWFkb25seSBncmFwaFdpZGdldFJpZ2h0QXhpcz86IFlBeGlzUHJvcHM7XG4gIC8qKlxuICAgKiBncmFwaCB3aWRnZXQgbGVnZW5kXG4gICAqIEBkZWZhdWx0IEJPVFRPTVxuICAgKi9cbiAgcmVhZG9ubHkgZ3JhcGhXaWRnZXRMZWdlbmQ/OiBMZWdlbmRQb3NpdGlvbjtcbiAgLyoqXG4gICAqIEBzZWUge0dyYXBoV2lkZ2V0UHJvcHMuc2V0UGVyaW9kVG9UaW1lUmFuZ2V9XG4gICAqL1xuICByZWFkb25seSBncmFwaFdpZGdldFNldFBlcmlvZFRvVGltZVJhbmdlPzogYm9vbGVhbjtcbiAgLyoqXG4gICAqIFdpZHRoIG9mIGdyYXBoIHdpZGdldC4gTm90ZSB0aGF0IHdpZGdldHMgd2lsbCBvdmVyZmxvdyBpbnRvIG5ldyByb3dzIGlmIHRoZSBzdW1tZWQgd2lkdGhcbiAgICogZXhjZWVkcyAyNC5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBBdXRvbWF0aWNhbGx5IGNhbGN1bGNhdGVkIHdpZHRoLCBnZW5lcmFsbHkgYXMgd2lkZSBhcyBwb3NzaWJsZSBjb25zaWRlcmluZyBhbGwgbWV0cmljcycgd2lkZ2V0cy5cbiAgICovXG4gIHJlYWRvbmx5IGdyYXBoV2lkZ2V0V2lkdGg/OiBudW1iZXI7XG4gIC8qKlxuICAgKiBAZGVwcmVjYXRlZCB1c2UgYWRkVG9TdW1tYXJ5RGFzaGJvYXJkLiBhZGRUb1N1bW1hcnlEYXNoYm9hcmQgd2lsbCB0YWtlIHByZWNlZGVuY2Ugb3ZlciBpbXBvcnRhbnQuXG4gICAqIEBzZWUgYWRkVG9TdW1tYXJ5RGFzaGJvYXJkXG4gICAqL1xuICByZWFkb25seSBpbXBvcnRhbnQ/OiBib29sZWFuO1xuICAvKipcbiAgICogRmxhZyBpbmRpY2F0aW5nIHRoaXMgbWV0cmljIGdyb3VwIHNob3VsZCBiZSBpbmNsdWRlZCBpbiB0aGUgc3VtbWFyeSBhcyB3ZWxsLlxuICAgKiBAZGVmYXVsdCAtIGFkZFRvU3VtbWFyeURhc2hib2FyZCBmcm9tIEN1c3RvbU1vbml0b3JpbmdQcm9wcywgZGVmYXVsdGluZyB0byBmYWxzZVxuICAgKi9cbiAgcmVhZG9ubHkgYWRkVG9TdW1tYXJ5RGFzaGJvYXJkPzogYm9vbGVhbjtcbiAgLyoqXG4gICAqIGxpc3Qgb2YgbWV0cmljcyBpbiB0aGUgZ3JvdXAgKGNhbiBiZSBkZWZpbmVkIGluIGRpZmZlcmVudCB3YXlzLCBzZWUgdGhlIHR5cGUgZG9jdW1lbnRhdGlvbilcbiAgICovXG4gIHJlYWRvbmx5IG1ldHJpY3M6IEN1c3RvbU1ldHJpY1tdO1xuICAvKipcbiAgICogT3B0aW9uYWwgY3VzdG9tIGhvcml6b250YWwgYW5ub3RhdGlvbnMgd2hpY2ggd2lsbCBiZSBkaXNwbGF5ZWQgb3ZlciB0aGUgbWV0cmljcyBvbiB0aGUgbGVmdCBheGlzXG4gICAqIChpZiB0aGVyZSBhcmUgYW55IGFsYXJtcywgYW55IGV4aXN0aW5nIGFubm90YXRpb25zIHdpbGwgYmUgbWVyZ2VkIHRvZ2V0aGVyKS5cbiAgICovXG4gIHJlYWRvbmx5IGhvcml6b250YWxBbm5vdGF0aW9ucz86IEhvcml6b250YWxBbm5vdGF0aW9uW107XG4gIC8qKlxuICAgKiBPcHRpb25hbCBjdXN0b20gaG9yaXpvbnRhbCBhbm5vdGF0aW9ucyB3aGljaCB3aWxsIGJlIGRpc3BsYXllZCBvdmVyIHRoZSBtZXRyaWNzIG9uIHRoZSByaWdodCBheGlzXG4gICAqIChpZiB0aGVyZSBhcmUgYW55IGFsYXJtcywgYW55IGV4aXN0aW5nIGFubm90YXRpb25zIHdpbGwgYmUgbWVyZ2VkIHRvZ2V0aGVyKS5cbiAgICovXG4gIHJlYWRvbmx5IGhvcml6b250YWxSaWdodEFubm90YXRpb25zPzogSG9yaXpvbnRhbEFubm90YXRpb25bXTtcbiAgLyoqXG4gICAqIE9wdGlvbmFsIGN1c3RvbSB2ZXJ0aWNhbCBhbm5vdGF0aW9ucyB3aGljaCB3aWxsIGJlIGRpc3BsYXllZCBvdmVyIHRoZSBtZXRyaWNzLlxuICAgKi9cbiAgcmVhZG9ubHkgdmVydGljYWxBbm5vdGF0aW9ucz86IFZlcnRpY2FsQW5ub3RhdGlvbltdO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEN1c3RvbU1vbml0b3JpbmdQcm9wcyBleHRlbmRzIEJhc2VNb25pdG9yaW5nUHJvcHMge1xuICAvKipcbiAgICogb3B0aW9uYWwgZGVzY3JpcHRpb24gb2YgdGhlIHdob2xlIHNlY3Rpb24sIGluIG1hcmtkb3duXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gbm8gZGVzY3JpcHRpb25cbiAgICovXG4gIHJlYWRvbmx5IGRlc2NyaXB0aW9uPzogc3RyaW5nO1xuICAvKipcbiAgICogb3B0aW9uYWwgaGVpZ2h0IG9mIHRoZSBkZXNjcmlwdGlvbiB3aWRnZXQsIHNvIHRoZSBjb250ZW50IGZpdHNcbiAgICpcbiAgICogQGRlZmF1bHQgLSBtaW5pbXVtIGhlaWdodCAoc2hvdWxkIGZpdCBvbmUgb3IgdHdvIGxpbmVzIG9mIHRleHQpXG4gICAqL1xuICByZWFkb25seSBkZXNjcmlwdGlvbldpZGdldEhlaWdodD86IG51bWJlcjtcbiAgLyoqXG4gICAqIEhlaWdodCBvdmVycmlkZS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBkZWZhdWx0IGhlaWdodFxuICAgKi9cbiAgcmVhZG9ubHkgaGVpZ2h0PzogbnVtYmVyO1xuICAvKipcbiAgICogZGVmaW5lIG1ldHJpYyBncm91cHMgYW5kIG1ldHJpY3MgaW5zaWRlIHRoZW0gKGVhY2ggbWV0cmljIGdyb3VwIHJlcHJlc2VudHMgYSB3aWRnZXQpXG4gICAqL1xuICByZWFkb25seSBtZXRyaWNHcm91cHM6IEN1c3RvbU1ldHJpY0dyb3VwW107XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ3VzdG9tTWV0cmljR3JvdXBXaXRoQW5ub3RhdGlvbnMge1xuICByZWFkb25seSBtZXRyaWNHcm91cDogQ3VzdG9tTWV0cmljR3JvdXA7XG4gIHJlYWRvbmx5IGFubm90YXRpb25zOiBIb3Jpem9udGFsQW5ub3RhdGlvbltdO1xuICByZWFkb25seSByaWdodEFubm90YXRpb25zOiBIb3Jpem9udGFsQW5ub3RhdGlvbltdO1xuICByZWFkb25seSB2ZXJ0aWNhbEFubm90YXRpb25zOiBWZXJ0aWNhbEFubm90YXRpb25bXTtcbiAgcmVhZG9ubHkgdGl0bGVBZGRvbnM6IHN0cmluZ1tdO1xuICByZWFkb25seSBoZWlnaHQ/OiBudW1iZXI7XG59XG5cbi8qKlxuICogQ3VzdG9tIG1vbml0b3JpbmcgaXMgYSBjb25zdHJ1Y3QgYWxsb3dpbmcgeW91IHRvIG1vbml0b3IgeW91ciBvd24gY3VzdG9tIG1ldHJpY3MuXG4gKiBUaGUgZW50aXJlIGNvbnN0cnVjdCBjb25zaXN0cyBvZiBtZXRyaWMgZ3JvdXBzLlxuICogRWFjaCBtZXRyaWMgZ3JvdXAgcmVwcmVzZW50cyBhIHNpbmdsZSBncmFwaCB3aWRnZXQgd2l0aCBtdWx0aXBsZSBtZXRyaWNzLlxuICogRWFjaCBtZXRyaWMgaW5zaWRlIHRoZSBtZXRyaWMgZ3JvdXAgcmVwcmVzZW50cyBhIHNpbmdsZSBtZXRyaWMgaW5zaWRlIGEgZ3JhcGguXG4gKiBUaGUgd2lkZ2V0cyB3aWxsIGJlIHNpemVkIGF1dG9tYXRpY2FsbHkgdG8gd2FzdGUgYXMgbGl0dGxlIHNwYWNlIGFzIHBvc3NpYmxlLlxuICovXG5leHBvcnQgY2xhc3MgQ3VzdG9tTW9uaXRvcmluZyBleHRlbmRzIE1vbml0b3Jpbmcge1xuICByZWFkb25seSB0aXRsZTogc3RyaW5nO1xuICByZWFkb25seSBkZXNjcmlwdGlvbj86IHN0cmluZztcbiAgcmVhZG9ubHkgZGVzY3JpcHRpb25XaWRnZXRIZWlnaHQ/OiBudW1iZXI7XG4gIHJlYWRvbmx5IGhlaWdodD86IG51bWJlcjtcbiAgcmVhZG9ubHkgYWRkVG9TdW1tYXJ5RGFzaGJvYXJkOiBib29sZWFuO1xuICByZWFkb25seSBjdXN0b21BbGFybUZhY3Rvcnk6IEN1c3RvbUFsYXJtRmFjdG9yeTtcbiAgcmVhZG9ubHkgYW5vbWFseURldGVjdGluZ0FsYXJtRmFjdG9yeTogQW5vbWFseURldGVjdGluZ0FsYXJtRmFjdG9yeTtcbiAgcmVhZG9ubHkgbWV0cmljR3JvdXBzOiBDdXN0b21NZXRyaWNHcm91cFdpdGhBbm5vdGF0aW9uc1tdO1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBNb25pdG9yaW5nU2NvcGUsIHByb3BzOiBDdXN0b21Nb25pdG9yaW5nUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgcHJvcHMpO1xuXG4gICAgY29uc3QgbmFtaW5nU3RyYXRlZ3kgPSBuZXcgTW9uaXRvcmluZ05hbWluZ1N0cmF0ZWd5KHsgLi4ucHJvcHMgfSk7XG4gICAgdGhpcy50aXRsZSA9IG5hbWluZ1N0cmF0ZWd5LnJlc29sdmVIdW1hblJlYWRhYmxlTmFtZSgpO1xuXG4gICAgdGhpcy5kZXNjcmlwdGlvbiA9IHByb3BzLmRlc2NyaXB0aW9uO1xuICAgIHRoaXMuZGVzY3JpcHRpb25XaWRnZXRIZWlnaHQgPSBwcm9wcy5kZXNjcmlwdGlvbldpZGdldEhlaWdodDtcbiAgICB0aGlzLmhlaWdodCA9IHByb3BzLmhlaWdodDtcbiAgICB0aGlzLmFkZFRvU3VtbWFyeURhc2hib2FyZCA9IHByb3BzLmFkZFRvU3VtbWFyeURhc2hib2FyZCA/PyBmYWxzZTtcblxuICAgIGNvbnN0IGFsYXJtRmFjdG9yeSA9IHRoaXMuY3JlYXRlQWxhcm1GYWN0b3J5KFxuICAgICAgbmFtaW5nU3RyYXRlZ3kucmVzb2x2ZUFsYXJtRnJpZW5kbHlOYW1lKCksXG4gICAgKTtcbiAgICB0aGlzLmN1c3RvbUFsYXJtRmFjdG9yeSA9IG5ldyBDdXN0b21BbGFybUZhY3RvcnkoYWxhcm1GYWN0b3J5KTtcbiAgICB0aGlzLmFub21hbHlEZXRlY3RpbmdBbGFybUZhY3RvcnkgPSBuZXcgQW5vbWFseURldGVjdGluZ0FsYXJtRmFjdG9yeShcbiAgICAgIGFsYXJtRmFjdG9yeSxcbiAgICApO1xuXG4gICAgdGhpcy5tZXRyaWNHcm91cHMgPSBwcm9wcy5tZXRyaWNHcm91cHMubWFwKChtZXRyaWNHcm91cCkgPT4ge1xuICAgICAgY29uc3QgbWV0cmljR3JvdXBXaXRoQW5ub3RhdGlvbjogQ3VzdG9tTWV0cmljR3JvdXBXaXRoQW5ub3RhdGlvbnMgPSB7XG4gICAgICAgIG1ldHJpY0dyb3VwLFxuICAgICAgICBhbm5vdGF0aW9uczogW10sXG4gICAgICAgIHJpZ2h0QW5ub3RhdGlvbnM6IFtdLFxuICAgICAgICB2ZXJ0aWNhbEFubm90YXRpb25zOiBbXSxcbiAgICAgICAgdGl0bGVBZGRvbnM6IFtdLFxuICAgICAgfTtcblxuICAgICAgaWYgKG1ldHJpY0dyb3VwLmhvcml6b250YWxBbm5vdGF0aW9ucykge1xuICAgICAgICBtZXRyaWNHcm91cFdpdGhBbm5vdGF0aW9uLmFubm90YXRpb25zLnB1c2goXG4gICAgICAgICAgLi4ubWV0cmljR3JvdXAuaG9yaXpvbnRhbEFubm90YXRpb25zLFxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgaWYgKG1ldHJpY0dyb3VwLmhvcml6b250YWxSaWdodEFubm90YXRpb25zKSB7XG4gICAgICAgIG1ldHJpY0dyb3VwV2l0aEFubm90YXRpb24ucmlnaHRBbm5vdGF0aW9ucy5wdXNoKFxuICAgICAgICAgIC4uLm1ldHJpY0dyb3VwLmhvcml6b250YWxSaWdodEFubm90YXRpb25zLFxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgaWYgKG1ldHJpY0dyb3VwLnZlcnRpY2FsQW5ub3RhdGlvbnMpIHtcbiAgICAgICAgbWV0cmljR3JvdXBXaXRoQW5ub3RhdGlvbi52ZXJ0aWNhbEFubm90YXRpb25zLnB1c2goXG4gICAgICAgICAgLi4ubWV0cmljR3JvdXAudmVydGljYWxBbm5vdGF0aW9ucyxcbiAgICAgICAgKTtcbiAgICAgIH1cblxuICAgICAgbWV0cmljR3JvdXAubWV0cmljcy5mb3JFYWNoKChtZXRyaWMpID0+IHtcbiAgICAgICAgaWYgKHRoaXMuaGFzQWxhcm0obWV0cmljKSAmJiB0aGlzLmhhc0Fub21hbHlEZXRlY3Rpb24obWV0cmljKSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgIFwiQWRkaW5nIGJvdGggYSByZWd1bGFyIGFsYXJtIGFuZCBhbiBhbm9tYWx5IGRldGVjdGlvbiBhbGFybSBhdCB0aGUgc2FtZSB0aW1lIGlzIG5vdCBzdXBwb3J0ZWRcIixcbiAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMuaGFzQWxhcm0obWV0cmljKSkge1xuICAgICAgICAgIHRoaXMuc2V0dXBBbGFybShtZXRyaWNHcm91cFdpdGhBbm5vdGF0aW9uLCBtZXRyaWMpO1xuICAgICAgICB9IGVsc2UgaWYgKHRoaXMuaGFzQW5vbWFseURldGVjdGlvbihtZXRyaWMpKSB7XG4gICAgICAgICAgdGhpcy5zZXR1cEFub21hbHlEZXRlY3Rpb25BbGFybShtZXRyaWNHcm91cFdpdGhBbm5vdGF0aW9uLCBtZXRyaWMpO1xuICAgICAgICB9XG4gICAgICB9KTtcblxuICAgICAgcmV0dXJuIG1ldHJpY0dyb3VwV2l0aEFubm90YXRpb247XG4gICAgfSk7XG5cbiAgICBwcm9wcy51c2VDcmVhdGVkQWxhcm1zPy5jb25zdW1lKHRoaXMuY3JlYXRlZEFsYXJtcygpKTtcbiAgfVxuXG4gIHN1bW1hcnlXaWRnZXRzKCk6IElXaWRnZXRbXSB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0QWxsV2lkZ2V0cyh0cnVlKTtcbiAgfVxuXG4gIHdpZGdldHMoKTogSVdpZGdldFtdIHtcbiAgICByZXR1cm4gdGhpcy5nZXRBbGxXaWRnZXRzKGZhbHNlKTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0QWxsV2lkZ2V0cyhzdW1tYXJ5OiBib29sZWFuKTogSVdpZGdldFtdIHtcbiAgICBjb25zdCBmaWx0ZXJlZE1ldHJpY0dyb3VwcyA9IHN1bW1hcnlcbiAgICAgID8gdGhpcy5tZXRyaWNHcm91cHMuZmlsdGVyKFxuICAgICAgICAgIChncm91cCkgPT5cbiAgICAgICAgICAgIGdyb3VwLm1ldHJpY0dyb3VwLmFkZFRvU3VtbWFyeURhc2hib2FyZCA/P1xuICAgICAgICAgICAgZ3JvdXAubWV0cmljR3JvdXAuaW1wb3J0YW50ID8/XG4gICAgICAgICAgICB0aGlzLmFkZFRvU3VtbWFyeURhc2hib2FyZCxcbiAgICAgICAgKVxuICAgICAgOiB0aGlzLm1ldHJpY0dyb3VwcztcblxuICAgIGlmIChmaWx0ZXJlZE1ldHJpY0dyb3Vwcy5sZW5ndGggPCAxKSB7XG4gICAgICAvLyBzaG9ydC1jaXJjdWl0IGlmIHRoZXJlIGFyZSBubyBtZXRyaWNzIHNwZWNpZmllZFxuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cblxuICAgIGNvbnN0IHJvd3M6IFJvd1tdID0gW107XG5cbiAgICAvLyBoZWFkZXIgYW5kIGRlc2NyaXB0aW9uXG4gICAgcm93cy5wdXNoKG5ldyBSb3cobmV3IE1vbml0b3JpbmdIZWFkZXJXaWRnZXQoeyB0aXRsZTogdGhpcy50aXRsZSB9KSkpO1xuICAgIGlmICh0aGlzLmRlc2NyaXB0aW9uICYmICFzdW1tYXJ5KSB7XG4gICAgICByb3dzLnB1c2goXG4gICAgICAgIG5ldyBSb3coXG4gICAgICAgICAgdGhpcy5jcmVhdGVEZXNjcmlwdGlvbldpZGdldChcbiAgICAgICAgICAgIHRoaXMuZGVzY3JpcHRpb24sXG4gICAgICAgICAgICB0aGlzLmRlc2NyaXB0aW9uV2lkZ2V0SGVpZ2h0LFxuICAgICAgICAgICksXG4gICAgICAgICksXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIGdyYXBoc1xuICAgIHJvd3MucHVzaChcbiAgICAgIG5ldyBSb3coXG4gICAgICAgIC4uLnRoaXMuY3JlYXRlQ3VzdG9tTWV0cmljR3JvdXBXaWRnZXRzKGZpbHRlcmVkTWV0cmljR3JvdXBzLCBzdW1tYXJ5KSxcbiAgICAgICksXG4gICAgKTtcblxuICAgIHJldHVybiByb3dzO1xuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVEZXNjcmlwdGlvbldpZGdldChcbiAgICBtYXJrZG93bjogc3RyaW5nLFxuICAgIGRlc2NyaXB0aW9uV2lkZ2V0SGVpZ2h0PzogbnVtYmVyLFxuICApIHtcbiAgICByZXR1cm4gbmV3IFRleHRXaWRnZXQoe1xuICAgICAgbWFya2Rvd24sXG4gICAgICB3aWR0aDogRnVsbFdpZHRoLFxuICAgICAgaGVpZ2h0OiBkZXNjcmlwdGlvbldpZGdldEhlaWdodCA/PyAxLFxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVDdXN0b21NZXRyaWNHcm91cFdpZGdldHMoXG4gICAgYW5ub3RhdGVkR3JvdXBzOiBDdXN0b21NZXRyaWNHcm91cFdpdGhBbm5vdGF0aW9uc1tdLFxuICAgIHN1bW1hcnk6IGJvb2xlYW4sXG4gICkge1xuICAgIGNvbnN0IHdpZGdldHM6IElXaWRnZXRbXSA9IFtdO1xuICAgIGNvbnN0IG1ldHJpY0dyb3VwV2lkZ2V0SGVpZ2h0RGVmYXVsdCA9IHN1bW1hcnlcbiAgICAgID8gRGVmYXVsdFN1bW1hcnlXaWRnZXRIZWlnaHRcbiAgICAgIDogRGVmYXVsdEdyYXBoV2lkZ2V0SGVpZ2h0O1xuICAgIGNvbnN0IG1ldHJpY0dyb3VwV2lkZ2V0SGVpZ2h0ID1cbiAgICAgIHRoaXMuaGVpZ2h0ID8/IG1ldHJpY0dyb3VwV2lkZ2V0SGVpZ2h0RGVmYXVsdDtcblxuICAgIGFubm90YXRlZEdyb3Vwcy5mb3JFYWNoKChhbm5vdGF0ZWRHcm91cCkgPT4ge1xuICAgICAgY29uc3QgbWV0cmljcyA9IGFubm90YXRlZEdyb3VwLm1ldHJpY0dyb3VwLm1ldHJpY3M7XG4gICAgICBjb25zdCBsZWZ0ID0gdGhpcy50b01ldHJpY3MoXG4gICAgICAgIG1ldHJpY3MuZmlsdGVyKFxuICAgICAgICAgIChtZXRyaWMpID0+XG4gICAgICAgICAgICAoKG1ldHJpYyBhcyBhbnkpLnBvc2l0aW9uID8/IEF4aXNQb3NpdGlvbi5MRUZUKSA9PVxuICAgICAgICAgICAgQXhpc1Bvc2l0aW9uLkxFRlQsXG4gICAgICAgICksXG4gICAgICApO1xuICAgICAgY29uc3QgcmlnaHQgPSB0aGlzLnRvTWV0cmljcyhcbiAgICAgICAgbWV0cmljcy5maWx0ZXIoXG4gICAgICAgICAgKG1ldHJpYykgPT5cbiAgICAgICAgICAgICgobWV0cmljIGFzIGFueSkucG9zaXRpb24gPz8gQXhpc1Bvc2l0aW9uLkxFRlQpID09XG4gICAgICAgICAgICBBeGlzUG9zaXRpb24uUklHSFQsXG4gICAgICAgICksXG4gICAgICApO1xuICAgICAgY29uc3QgaGFzT25lTWV0cmljT25seSA9IG1ldHJpY3MubGVuZ3RoID09PSAxO1xuICAgICAgY29uc3QgaGFzQW5vbWFseURldGVjdGlvbiA9XG4gICAgICAgIG1ldHJpY3MuZmlsdGVyKChtZXRyaWMpID0+IHRoaXMuaGFzQW5vbWFseURldGVjdGlvbihtZXRyaWMpKS5sZW5ndGggPiAwO1xuICAgICAgY29uc3QgdXNlQW5vbWFseURldGVjdGlvbldpZGdldCA9IGhhc09uZU1ldHJpY09ubHkgJiYgaGFzQW5vbWFseURldGVjdGlvbjtcbiAgICAgIGxldCB0aXRsZSA9IGFubm90YXRlZEdyb3VwLm1ldHJpY0dyb3VwLnRpdGxlO1xuXG4gICAgICBpZiAoYW5ub3RhdGVkR3JvdXAudGl0bGVBZGRvbnMubGVuZ3RoID4gMCkge1xuICAgICAgICB0aXRsZSA9IGAke3RpdGxlfSAoJHthbm5vdGF0ZWRHcm91cC50aXRsZUFkZG9ucy5qb2luKFwiLCBcIil9KWA7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGdyYXBoV2lkZ2V0UHJvcHM6IEdyYXBoV2lkZ2V0UHJvcHMgPSB7XG4gICAgICAgIHRpdGxlLFxuICAgICAgICB3aWR0aDpcbiAgICAgICAgICBhbm5vdGF0ZWRHcm91cC5tZXRyaWNHcm91cC5ncmFwaFdpZGdldFdpZHRoID8/XG4gICAgICAgICAgcmVjb21tZW5kZWRXaWRnZXRXaWR0aChhbm5vdGF0ZWRHcm91cHMubGVuZ3RoKSxcbiAgICAgICAgaGVpZ2h0OiBtZXRyaWNHcm91cFdpZGdldEhlaWdodCxcbiAgICAgICAgbGVmdCxcbiAgICAgICAgcmlnaHQsXG4gICAgICAgIGxlZnRBbm5vdGF0aW9uczogYW5ub3RhdGVkR3JvdXAuYW5ub3RhdGlvbnMsXG4gICAgICAgIHJpZ2h0QW5ub3RhdGlvbnM6IGFubm90YXRlZEdyb3VwLnJpZ2h0QW5ub3RhdGlvbnMsXG4gICAgICAgIGxlZnRZQXhpczogYW5ub3RhdGVkR3JvdXAubWV0cmljR3JvdXAuZ3JhcGhXaWRnZXRBeGlzLFxuICAgICAgICByaWdodFlBeGlzOiBhbm5vdGF0ZWRHcm91cC5tZXRyaWNHcm91cC5ncmFwaFdpZGdldFJpZ2h0QXhpcyxcbiAgICAgICAgdmVydGljYWxBbm5vdGF0aW9uczogYW5ub3RhdGVkR3JvdXAudmVydGljYWxBbm5vdGF0aW9ucyxcbiAgICAgICAgbGVnZW5kUG9zaXRpb246IGFubm90YXRlZEdyb3VwLm1ldHJpY0dyb3VwLmdyYXBoV2lkZ2V0TGVnZW5kLFxuICAgICAgICBzZXRQZXJpb2RUb1RpbWVSYW5nZTpcbiAgICAgICAgICBhbm5vdGF0ZWRHcm91cC5tZXRyaWNHcm91cC5ncmFwaFdpZGdldFNldFBlcmlvZFRvVGltZVJhbmdlLFxuICAgICAgfTtcblxuICAgICAgY29uc3Qgd2lkZ2V0ID0gdXNlQW5vbWFseURldGVjdGlvbldpZGdldFxuICAgICAgICA/IG5ldyBBbm9tYWx5RGV0ZWN0aW9uR3JhcGhXaWRnZXQoZ3JhcGhXaWRnZXRQcm9wcylcbiAgICAgICAgOiBjcmVhdGVHcmFwaFdpZGdldChcbiAgICAgICAgICAgIGFubm90YXRlZEdyb3VwLm1ldHJpY0dyb3VwLmdyYXBoV2lkZ2V0VHlwZSA/PyBHcmFwaFdpZGdldFR5cGUuTElORSxcbiAgICAgICAgICAgIGdyYXBoV2lkZ2V0UHJvcHMsXG4gICAgICAgICAgKTtcblxuICAgICAgd2lkZ2V0cy5wdXNoKHdpZGdldCk7XG4gICAgfSk7XG5cbiAgICByZXR1cm4gd2lkZ2V0cztcbiAgfVxuXG4gIHByaXZhdGUgdG9NZXRyaWNzKG1ldHJpY3M6IEN1c3RvbU1ldHJpY1tdKTogSU1ldHJpY1tdIHtcbiAgICBjb25zdCBtZXRyaWNGYWN0b3J5ID0gdGhpcy5jcmVhdGVNZXRyaWNGYWN0b3J5KCk7XG5cbiAgICByZXR1cm4gbWV0cmljcy5tYXAoKG1ldHJpYykgPT4ge1xuICAgICAgaWYgKHRoaXMuaGFzQWxhcm0obWV0cmljKSkge1xuICAgICAgICAvLyBtZXRyaWMgd2l0aCBhbGFybVxuICAgICAgICByZXR1cm4gbWV0cmljRmFjdG9yeS5hZGFwdE1ldHJpY1ByZXNlcnZpbmdQZXJpb2QobWV0cmljLm1ldHJpYyk7XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuaGFzQW5vbWFseURldGVjdGlvbihtZXRyaWMpKSB7XG4gICAgICAgIC8vIG1ldHJpYyB3aXRoIGFub21hbHkgZGV0ZWN0aW9uXG4gICAgICAgIHJldHVybiBtZXRyaWNGYWN0b3J5LmNyZWF0ZU1ldHJpY0Fub21hbHlEZXRlY3Rpb24oXG4gICAgICAgICAgbWV0cmljLm1ldHJpYyxcbiAgICAgICAgICBtZXRyaWMuYW5vbWFseURldGVjdGlvblN0YW5kYXJkRGV2aWF0aW9uVG9SZW5kZXIsXG4gICAgICAgICAgYEV4cGVjdGVkIChzdGRldiA9ICR7bWV0cmljLmFub21hbHlEZXRlY3Rpb25TdGFuZGFyZERldmlhdGlvblRvUmVuZGVyfSlgLFxuICAgICAgICAgIHVuZGVmaW5lZCxcbiAgICAgICAgICAvLyBuZWVkcyB0byBiZSB1bmlxdWUgaW4gdGhlIHdob2xlIHdpZGdldCBhbmQgc3RhcnQgd2l0aCBsb3dlcmNhc2VcbiAgICAgICAgICBBbm9tYWx5RGV0ZWN0aW9uTWV0cmljSWRQcmVmaXggK1xuICAgICAgICAgICAgZ2V0SGFzaEZvck1ldHJpY0V4cHJlc3Npb25JZChtZXRyaWMuYWxhcm1GcmllbmRseU5hbWUpLFxuICAgICAgICAgIC8vIHByZXNlcnZlIHRoZSBtb3N0IHNwZWNpZmljIG1ldHJpYyBwZXJpb2RcbiAgICAgICAgICBtZXRyaWMucGVyaW9kID8/IG1ldHJpYy5tZXRyaWMucGVyaW9kLFxuICAgICAgICApO1xuICAgICAgfSBlbHNlIGlmICh0aGlzLmlzU2VhcmNoKG1ldHJpYykpIHtcbiAgICAgICAgLy8gbWV0cmljIHNlYXJjaFxuICAgICAgICByZXR1cm4gbWV0cmljRmFjdG9yeS5jcmVhdGVNZXRyaWNTZWFyY2goXG4gICAgICAgICAgbWV0cmljLnNlYXJjaFF1ZXJ5LFxuICAgICAgICAgIG1ldHJpYy5kaW1lbnNpb25zTWFwLFxuICAgICAgICAgIG1ldHJpYy5zdGF0aXN0aWMsXG4gICAgICAgICAgbWV0cmljLm5hbWVzcGFjZSxcbiAgICAgICAgICBtZXRyaWMubGFiZWwsXG4gICAgICAgICAgbWV0cmljLnBlcmlvZCxcbiAgICAgICAgICBtZXRyaWMucmVnaW9uLFxuICAgICAgICAgIG1ldHJpYy5hY2NvdW50LFxuICAgICAgICApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gZ2VuZXJhbCBtZXRyaWNcbiAgICAgICAgcmV0dXJuIG1ldHJpY0ZhY3RvcnkuYWRhcHRNZXRyaWNQcmVzZXJ2aW5nUGVyaW9kKG1ldHJpYyk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGhhc0FsYXJtKG1ldHJpYzogQ3VzdG9tTWV0cmljKTogbWV0cmljIGlzIEN1c3RvbU1ldHJpY1dpdGhBbGFybSB7XG4gICAgLy8gdHlwZSBndWFyZFxuICAgIHJldHVybiAobWV0cmljIGFzIEN1c3RvbU1ldHJpY1dpdGhBbGFybSkuYWRkQWxhcm0gIT09IHVuZGVmaW5lZDtcbiAgfVxuXG4gIHByaXZhdGUgaGFzQW5vbWFseURldGVjdGlvbihcbiAgICBtZXRyaWM6IEN1c3RvbU1ldHJpYyxcbiAgKTogbWV0cmljIGlzIEN1c3RvbU1ldHJpY1dpdGhBbm9tYWx5RGV0ZWN0aW9uIHtcbiAgICAvLyB0eXBlIGd1YXJkXG4gICAgcmV0dXJuIChcbiAgICAgIChtZXRyaWMgYXMgQ3VzdG9tTWV0cmljV2l0aEFub21hbHlEZXRlY3Rpb24pXG4gICAgICAgIC5hbm9tYWx5RGV0ZWN0aW9uU3RhbmRhcmREZXZpYXRpb25Ub1JlbmRlciAhPT0gdW5kZWZpbmVkXG4gICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgaXNTZWFyY2gobWV0cmljOiBDdXN0b21NZXRyaWMpOiBtZXRyaWMgaXMgQ3VzdG9tTWV0cmljU2VhcmNoIHtcbiAgICAvLyB0eXBlIGd1YXJkXG4gICAgcmV0dXJuIChtZXRyaWMgYXMgQ3VzdG9tTWV0cmljU2VhcmNoKS5zZWFyY2hRdWVyeSAhPT0gdW5kZWZpbmVkO1xuICB9XG5cbiAgcHJpdmF0ZSBzZXR1cEFsYXJtKFxuICAgIG1ldHJpY0dyb3VwOiBDdXN0b21NZXRyaWNHcm91cFdpdGhBbm5vdGF0aW9ucyxcbiAgICBtZXRyaWM6IEN1c3RvbU1ldHJpY1dpdGhBbGFybSxcbiAgKSB7XG4gICAgaWYgKHRoaXMuaXNTZWFyY2gobWV0cmljKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBcIkFsYXJtaW5nIG9uIHNlYXJjaCBxdWVyaWVzIGlzIG5vdCBzdXBwb3J0ZWQgYnkgQ2xvdWRXYXRjaFwiLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IGRpc2FtYmlndWF0b3IgaW4gbWV0cmljLmFkZEFsYXJtKSB7XG4gICAgICBjb25zdCBhbGFybVByb3BzID0gbWV0cmljLmFkZEFsYXJtW2Rpc2FtYmlndWF0b3JdO1xuICAgICAgY29uc3QgY3JlYXRlZEFsYXJtID0gdGhpcy5jdXN0b21BbGFybUZhY3RvcnkuYWRkQ3VzdG9tQWxhcm0oXG4gICAgICAgIG1ldHJpYy5tZXRyaWMsXG4gICAgICAgIG1ldHJpYy5hbGFybUZyaWVuZGx5TmFtZSxcbiAgICAgICAgZGlzYW1iaWd1YXRvcixcbiAgICAgICAgYWxhcm1Qcm9wcyxcbiAgICAgICk7XG4gICAgICBjb25zdCB0YXJnZXRBbm5vdGF0aW9ucyA9XG4gICAgICAgIChtZXRyaWMucG9zaXRpb24gPz8gQXhpc1Bvc2l0aW9uLkxFRlQpID09IEF4aXNQb3NpdGlvbi5MRUZUXG4gICAgICAgICAgPyBtZXRyaWNHcm91cC5hbm5vdGF0aW9uc1xuICAgICAgICAgIDogbWV0cmljR3JvdXAucmlnaHRBbm5vdGF0aW9ucztcbiAgICAgIHRhcmdldEFubm90YXRpb25zLnB1c2goY3JlYXRlZEFsYXJtLmFubm90YXRpb24pO1xuICAgICAgdGhpcy5hZGRBbGFybShjcmVhdGVkQWxhcm0pO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgc2V0dXBBbm9tYWx5RGV0ZWN0aW9uQWxhcm0oXG4gICAgbWV0cmljR3JvdXA6IEN1c3RvbU1ldHJpY0dyb3VwV2l0aEFubm90YXRpb25zLFxuICAgIG1ldHJpYzogQ3VzdG9tTWV0cmljV2l0aEFub21hbHlEZXRlY3Rpb24sXG4gICkge1xuICAgIGlmICh0aGlzLmlzU2VhcmNoKG1ldHJpYykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgXCJBbGFybWluZyBvbiBzZWFyY2ggcXVlcmllcyBpcyBub3Qgc3VwcG9ydGVkIGJ5IENsb3VkV2F0Y2hcIixcbiAgICAgICk7XG4gICAgfVxuXG4gICAgY29uc3QgYWxhcm1TdERldnMgPSBuZXcgU2V0PG51bWJlcj4oKTtcbiAgICBjb25zdCBtZXRyaWNGYWN0b3J5ID0gdGhpcy5jcmVhdGVNZXRyaWNGYWN0b3J5KCk7XG5cbiAgICBmb3IgKGNvbnN0IGRpc2FtYmlndWF0b3IgaW4gbWV0cmljLmFkZEFsYXJtT25Bbm9tYWx5KSB7XG4gICAgICBjb25zdCBhbGFybVByb3BzID0gbWV0cmljLmFkZEFsYXJtT25Bbm9tYWx5W2Rpc2FtYmlndWF0b3JdO1xuICAgICAgaWYgKFxuICAgICAgICBhbGFybVByb3BzLmFsYXJtV2hlbkFib3ZlVGhlQmFuZCB8fFxuICAgICAgICBhbGFybVByb3BzLmFsYXJtV2hlbkJlbG93VGhlQmFuZFxuICAgICAgKSB7XG4gICAgICAgIGNvbnN0IGFub21hbHlNZXRyaWMgPSBtZXRyaWNGYWN0b3J5LmNyZWF0ZU1ldHJpY0Fub21hbHlEZXRlY3Rpb24oXG4gICAgICAgICAgLy8gQmVjYXVzZSB0aGUgbWV0cmljIHdhcyBwcm92aWRlZCB0byB1cywgd2UgdXNlIG1ldHJpY0ZhY3Rvcnkub3ZlcnJpZGVOYW1lc3BhY2UoKSB0b1xuICAgICAgICAgIC8vIGNvbmZpcm0gaXQgYWxpZ25zIHdpdGggYW55IG5hbWVzcGFjZSBvdmVycmlkZXMgcmVxdWVzdGVkIGZvciB0aGlzIE1vbml0b3JpbmdGYWNhZGVcbiAgICAgICAgICBtZXRyaWNGYWN0b3J5LmFkYXB0TWV0cmljUHJlc2VydmluZ1BlcmlvZChtZXRyaWMubWV0cmljKSxcbiAgICAgICAgICBhbGFybVByb3BzLnN0YW5kYXJkRGV2aWF0aW9uRm9yQWxhcm0sXG4gICAgICAgICAgYEJhbmQgKHN0ZGV2ICR7YWxhcm1Qcm9wcy5zdGFuZGFyZERldmlhdGlvbkZvckFsYXJtfSlgLFxuICAgICAgICAgIHVuZGVmaW5lZCxcbiAgICAgICAgICAvLyBleHByZXNzaW9uIElEIG5lZWRzIHRvIGJlIHVuaXF1ZSBhY3Jvc3