cdk-monitoring-constructs
Version:
[](https://badge.fury.io/js/cdk-monitoring-constructs) [](https://m
268 lines • 53.6 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 || (exports.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 ??
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)
: 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 +
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 +
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: "9.7.1" };
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ3VzdG9tTW9uaXRvcmluZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIkN1c3RvbU1vbml0b3JpbmcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFDQSwrREFZb0M7QUFFcEMseUNBaUJzQjtBQUN0QiwrQ0FHeUI7QUFFekIsSUFBWSxZQUdYO0FBSEQsV0FBWSxZQUFZO0lBQ3RCLDZCQUFhLENBQUE7SUFDYiwrQkFBZSxDQUFBO0FBQ2pCLENBQUMsRUFIVyxZQUFZLEdBQVosb0JBQVksS0FBWixvQkFBWSxRQUd2QjtBQThORDs7Ozs7O0dBTUc7QUFDSCxNQUFhLGdCQUFpQixTQUFRLG1CQUFVO0lBVTlDLFlBQVksS0FBc0IsRUFBRSxLQUE0QjtRQUM5RCxLQUFLLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBRXBCLE1BQU0sY0FBYyxHQUFHLElBQUksb0NBQXdCLENBQUMsRUFBRSxHQUFHLEtBQUssRUFBRSxDQUFDLENBQUM7UUFDbEUsSUFBSSxDQUFDLEtBQUssR0FBRyxjQUFjLENBQUMsd0JBQXdCLEVBQUUsQ0FBQztRQUV2RCxJQUFJLENBQUMsV0FBVyxHQUFHLEtBQUssQ0FBQyxXQUFXLENBQUM7UUFDckMsSUFBSSxDQUFDLHVCQUF1QixHQUFHLEtBQUssQ0FBQyx1QkFBdUIsQ0FBQztRQUM3RCxJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUM7UUFDM0IsSUFBSSxDQUFDLHFCQUFxQixHQUFHLEtBQUssQ0FBQyxxQkFBcUIsSUFBSSxLQUFLLENBQUM7UUFFbEUsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLGtCQUFrQixDQUMxQyxjQUFjLENBQUMsd0JBQXdCLEVBQUUsQ0FDMUMsQ0FBQztRQUNGLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxJQUFJLDJCQUFrQixDQUFDLFlBQVksQ0FBQyxDQUFDO1FBQy9ELElBQUksQ0FBQyw0QkFBNEIsR0FBRyxJQUFJLHFDQUE0QixDQUNsRSxZQUFZLENBQ2Is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RDtRQUM3RCxtQkFBbUIsQ0FBQyxtQkFBbUIsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQztRQUNuRSxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IER1cmF0aW9uIH0gZnJvbSBcImF3cy1jZGstbGliXCI7XG5pbXBvcnQge1xuICBEaW1lbnNpb25zTWFwLFxuICBHcmFwaFdpZGdldCxcbiAgR3JhcGhXaWRnZXRQcm9wcyxcbiAgSG9yaXpvbnRhbEFubm90YXRpb24sXG4gIElNZXRyaWMsXG4gIElXaWRnZXQsXG4gIExlZ2VuZFBvc2l0aW9uLFxuICBSb3csXG4gIFRleHRXaWRnZXQsXG4gIFZlcnRpY2FsQW5ub3RhdGlvbixcbiAgWUF4aXNQcm9wcyxcbn0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1jbG91ZHdhdGNoXCI7XG5cbmltcG9ydCB7XG4gIEFub21hbHlEZXRlY3RpbmdBbGFybUZhY3RvcnksXG4gIEFub21hbHlEZXRlY3Rpb25UaHJlc2hvbGQsXG4gIEJhc2VNb25pdG9yaW5nUHJvcHMsXG4gIGNyZWF0ZUdyYXBoV2lkZ2V0LFxuICBDdXN0b21BbGFybUZhY3RvcnksXG4gIEN1c3RvbVRocmVzaG9sZCxcbiAgRGVmYXVsdEdyYXBoV2lkZ2V0SGVpZ2h0LFxuICBEZWZhdWx0U3VtbWFyeVdpZGdldEhlaWdodCxcbiAgRnVsbFdpZHRoLFxuICBnZXRIYXNoRm9yTWV0cmljRXhwcmVzc2lvbklkLFxuICBHcmFwaFdpZGdldFR5cGUsXG4gIE1ldHJpY1N0YXRpc3RpYyxcbiAgTWV0cmljV2l0aEFsYXJtU3VwcG9ydCxcbiAgTW9uaXRvcmluZyxcbiAgTW9uaXRvcmluZ1Njb3BlLFxuICByZWNvbW1lbmRlZFdpZGdldFdpZHRoLFxufSBmcm9tIFwiLi4vLi4vY29tbW9uXCI7XG5pbXBvcnQge1xuICBNb25pdG9yaW5nSGVhZGVyV2lkZ2V0LFxuICBNb25pdG9yaW5nTmFtaW5nU3RyYXRlZ3ksXG59IGZyb20gXCIuLi8uLi9kYXNoYm9hcmRcIjtcblxuZXhwb3J0IGVudW0gQXhpc1Bvc2l0aW9uIHtcbiAgTEVGVCA9IFwibGVmdFwiLFxuICBSSUdIVCA9IFwicmlnaHRcIixcbn1cblxuLyoqXG4gKiBDdXN0b20gbWV0cmljIHdpdGggYW4gYWxhcm0gZGVmaW5lZC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDdXN0b21NZXRyaWNXaXRoQWxhcm0ge1xuICAvKipcbiAgICogbWV0cmljIHRvIGFsYXJtIG9uXG4gICAqL1xuICByZWFkb25seSBtZXRyaWM6IE1ldHJpY1dpdGhBbGFybVN1cHBvcnQ7XG4gIC8qKlxuICAgKiBhbGFybSBmcmllbmRseSBuYW1lXG4gICAqL1xuICByZWFkb25seSBhbGFybUZyaWVuZGx5TmFtZTogc3RyaW5nO1xuICAvKipcbiAgICogYWxhcm0gZGVmaW5pdGlvbnNcbiAgICovXG4gIHJlYWRvbmx5IGFkZEFsYXJtOiBSZWNvcmQ8c3RyaW5nLCBDdXN0b21UaHJlc2hvbGQ+O1xuICAvKipcbiAgICogYXhpcyAocmlnaHQgb3IgbGVmdCkgb24gd2hpY2ggdG8gZ3JhcGggbWV0cmljXG4gICAqIGRlZmF1bHQ6IEF4aXNQb3NpdGlvbi5MRUZUXG4gICAqL1xuICByZWFkb25seSBwb3NpdGlvbj86IEF4aXNQb3NpdGlvbjtcbn1cblxuLyoqXG4gKiBDdXN0b20gbWV0cmljIHdpdGggYW5vbWFseSBkZXRlY3Rpb24uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ3VzdG9tTWV0cmljV2l0aEFub21hbHlEZXRlY3Rpb24ge1xuICAvKipcbiAgICogbWV0cmljIHRvIGFsYXJtIG9uXG4gICAqL1xuICByZWFkb25seSBtZXRyaWM6IE1ldHJpY1dpdGhBbGFybVN1cHBvcnQ7XG4gIC8qKlxuICAgKiBhbm9tYWx5IGRldGVjdGlvbiBwZXJpb2RcbiAgICogQGRlZmF1bHQgLSBtZXRyaWMgcGVyaW9kIChpZiBkZWZpbmVkKSBvciBnbG9iYWwgZGVmYXVsdFxuICAgKi9cbiAgcmVhZG9ubHkgcGVyaW9kPzogRHVyYXRpb247XG4gIC8qKlxuICAgKiBhbGFybSBmcmllbmRseSBuYW1lXG4gICAqL1xuICByZWFkb25seSBhbGFybUZyaWVuZGx5TmFtZTogc3RyaW5nO1xuICAvKipcbiAgICogc3RhbmRhcmQgZGV2aWF0aW9uIGZvciB0aGUgYW5vbWFseSBkZXRlY3Rpb24gdG8gYmUgcmVuZGVyZWQgb24gdGhlIGdyYXBoIHdpZGdldFxuICAgKi9cbiAgcmVhZG9ubHkgYW5vbWFseURldGVjdGlvblN0YW5kYXJkRGV2aWF0aW9uVG9SZW5kZXI6IG51bWJlcjtcbiAgLyoqXG4gICAqIGFkZHMgYWxhcm0gb24gYSBkZXRlY3RlZCBhbm9tYWx5XG4gICAqL1xuICByZWFkb25seSBhZGRBbGFybU9uQW5vbWFseT86IFJlY29yZDxzdHJpbmcsIEFub21hbHlEZXRlY3Rpb25UaHJlc2hvbGQ+O1xufVxuXG4vKipcbiAqIEN1c3RvbSBtZXRyaWMgc2VhcmNoLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEN1c3RvbU1ldHJpY1NlYXJjaCB7XG4gIC8qKlxuICAgKiBtZXRyaWMgbmFtZXNwYWNlXG4gICAqIEBkZWZhdWx0IC0gbm9uZVxuICAgKi9cbiAgcmVhZG9ubHkgbmFtZXNwYWNlPzogc3RyaW5nO1xuICAvKipcbiAgICogc2VhcmNoIHF1ZXJ5IChjYW4gYmUgZW1wdHkpXG4gICAqL1xuICByZWFkb25seSBzZWFyY2hRdWVyeTogc3RyaW5nO1xuICAvKipcbiAgICogY3VzdG9tIGxhYmVsIGZvciB0aGUgbWV0cmljc1xuICAgKiBAZGVmYXVsdCAtIFwiIFwiXG4gICAqL1xuICByZWFkb25seSBsYWJlbD86IHN0cmluZztcbiAgLyoqXG4gICAqIHNlYXJjaCBkaW1lbnNpb25zIChjYW4gYmUgZW1wdHkpXG4gICAqL1xuICByZWFkb25seSBkaW1lbnNpb25zTWFwOiBEaW1lbnNpb25zTWFwO1xuICAvKipcbiAgICogbWV0cmljIHN0YXRpc3RpY1xuICAgKi9cbiAgcmVhZG9ubHkgc3RhdGlzdGljOiBNZXRyaWNTdGF0aXN0aWM7XG4gIC8qKlxuICAgKiBtZXRyaWMgcGVyaW9kXG4gICAqIEBkZWZhdWx0IC0gZ2xvYmFsIGRlZmF1bHRcbiAgICovXG4gIHJlYWRvbmx5IHBlcmlvZD86IER1cmF0aW9uO1xuICAvKipcbiAgICogYXhpcyAocmlnaHQgb3IgbGVmdCkgb24gd2hpY2ggdG8gZ3JhcGggbWV0cmljXG4gICAqIGRlZmF1bHQ6IEF4aXNQb3NpdGlvbi5MRUZUXG4gICAqL1xuICByZWFkb25seSBwb3NpdGlvbj86IEF4aXNQb3NpdGlvbjtcblxuICAvKipcbiAgICogQWNjb3VudCB3aGljaCB0aGlzIG1ldHJpYyBjb21lcyBmcm9tLlxuICAgKiBOb3RlIHRoYXQgYWxhcm1zIGNhbm5vdCBiZSBjcmVhdGVkIGZvciBjcm9zcy1hY2NvdW50IG1ldHJpY3MuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gRGVwbG95bWVudCBhY2NvdW50LlxuICAgKi9cbiAgcmVhZG9ubHkgYWNjb3VudD86IHN0cmluZztcblxuICAvKipcbiAgICogUmVnaW9uIHdoaWNoIHRoaXMgbWV0cmljIGNvbWVzIGZyb20uXG4gICAqIE5vdGUgdGhhdCBhbGFybXMgY2Fubm90IGJlIGNyZWF0ZWQgZm9yIGNyb3NzLXJlZ2lvbiBtZXRyaWNzLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIERlcGxveW1lbnQgcmVnaW9uLlxuICAgKi9cbiAgcmVhZG9ubHkgcmVnaW9uPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIEVhY2ggY3VzdG9tIG1ldHJpYyBjYW4gYmUgb2YgZm91ciB0eXBlczpcbiAqIEBzZWUgTWV0cmljV2l0aEFsYXJtU3VwcG9ydCBmb3IgYSBzdGFuZGFyZCBtZXRyaWNcbiAqIEBzZWUgQ3VzdG9tTWV0cmljU2VhcmNoIGZvciBhIHNlYXJjaFxuICogQHNlZSBDdXN0b21NZXRyaWNXaXRoQWxhcm0gZm9yIGEgbWV0cmljIHdpdGggYW4gYWxhcm1cbiAqIEBzZWUgQ3VzdG9tTWV0cmljV2l0aEFub21hbHlEZXRlY3Rpb24gZm9yIGEgbWV0cmljIHdpdGggYW4gYW5vbWFseSBkZXRlY3RpbmcgYWxhcm1cbiAqL1xuZXhwb3J0IHR5cGUgQ3VzdG9tTWV0cmljID1cbiAgfCBNZXRyaWNXaXRoQWxhcm1TdXBwb3J0XG4gIHwgQ3VzdG9tTWV0cmljU2VhcmNoXG4gIHwgQ3VzdG9tTWV0cmljV2l0aEFsYXJtXG4gIHwgQ3VzdG9tTWV0cmljV2l0aEFub21hbHlEZXRlY3Rpb247XG5cbi8qKlxuICogQ3VzdG9tIG1ldHJpYyBncm91cCByZXByZXNlbnRzIGEgc2luZ2xlIHdpZGdldC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDdXN0b21NZXRyaWNHcm91cCB7XG4gIC8qKlxuICAgKiB0aXRsZSBvZiB0aGUgd2hvbGUgZ3JvdXBcbiAgICovXG4gIHJlYWRvbmx5IHRpdGxlOiBzdHJpbmc7XG4gIC8qKlxuICAgKiB0eXBlIG9mIHRoZSB3aWRnZXRcbiAgICogQGRlZmF1bHQgbGluZVxuICAgKi9cbiAgcmVhZG9ubHkgZ3JhcGhXaWRnZXRUeXBlPzogR3JhcGhXaWRnZXRUeXBlO1xuICAvKipcbiAgICogb3B0aW9uYWwgYXhpc1xuICAgKiBAZGVmYXVsdCB1bmRlZmluZWRcbiAgICovXG4gIHJlYWRvbmx5IGdyYXBoV2lkZ2V0QXhpcz86IFlBeGlzUHJvcHM7XG4gIC8qKlxuICAgKiBvcHRpb25hbCByaWdodCBheGlzXG4gICAqIEBkZWZhdWx0IHVuZGVmaW5lZFxuICAgKi9cbiAgcmVhZG9ubHkgZ3JhcGhXaWRnZXRSaWdodEF4aXM/OiBZQXhpc1Byb3BzO1xuICAvKipcbiAgICogZ3JhcGggd2lkZ2V0IGxlZ2VuZFxuICAgKiBAZGVmYXVsdCBCT1RUT01cbiAgICovXG4gIHJlYWRvbmx5IGdyYXBoV2lkZ2V0TGVnZW5kPzogTGVnZW5kUG9zaXRpb247XG4gIC8qKlxuICAgKiBAc2VlIHtHcmFwaFdpZGdldFByb3BzLnNldFBlcmlvZFRvVGltZVJhbmdlfVxuICAgKi9cbiAgcmVhZG9ubHkgZ3JhcGhXaWRnZXRTZXRQZXJpb2RUb1RpbWVSYW5nZT86IGJvb2xlYW47XG4gIC8qKlxuICAgKiBXaWR0aCBvZiBncmFwaCB3aWRnZXQuIE5vdGUgdGhhdCB3aWRnZXRzIHdpbGwgb3ZlcmZsb3cgaW50byBuZXcgcm93cyBpZiB0aGUgc3VtbWVkIHdpZHRoXG4gICAqIGV4Y2VlZHMgMjQuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gQXV0b21hdGljYWxseSBjYWxjdWxjYXRlZCB3aWR0aCwgZ2VuZXJhbGx5IGFzIHdpZGUgYXMgcG9zc2libGUgY29uc2lkZXJpbmcgYWxsIG1ldHJpY3MnIHdpZGdldHMuXG4gICAqL1xuICByZWFkb25seSBncmFwaFdpZGdldFdpZHRoPzogbnVtYmVyO1xuICAvKipcbiAgICogQGRlcHJlY2F0ZWQgdXNlIGFkZFRvU3VtbWFyeURhc2hib2FyZC4gYWRkVG9TdW1tYXJ5RGFzaGJvYXJkIHdpbGwgdGFrZSBwcmVjZWRlbmNlIG92ZXIgaW1wb3J0YW50LlxuICAgKiBAc2VlIGFkZFRvU3VtbWFyeURhc2hib2FyZFxuICAgKi9cbiAgcmVhZG9ubHkgaW1wb3J0YW50PzogYm9vbGVhbjtcbiAgLyoqXG4gICAqIEZsYWcgaW5kaWNhdGluZyB0aGlzIG1ldHJpYyBncm91cCBzaG91bGQgYmUgaW5jbHVkZWQgaW4gdGhlIHN1bW1hcnkgYXMgd2VsbC5cbiAgICogQGRlZmF1bHQgLSBhZGRUb1N1bW1hcnlEYXNoYm9hcmQgZnJvbSBDdXN0b21Nb25pdG9yaW5nUHJvcHMsIGRlZmF1bHRpbmcgdG8gZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IGFkZFRvU3VtbWFyeURhc2hib2FyZD86IGJvb2xlYW47XG4gIC8qKlxuICAgKiBsaXN0IG9mIG1ldHJpY3MgaW4gdGhlIGdyb3VwIChjYW4gYmUgZGVmaW5lZCBpbiBkaWZmZXJlbnQgd2F5cywgc2VlIHRoZSB0eXBlIGRvY3VtZW50YXRpb24pXG4gICAqL1xuICByZWFkb25seSBtZXRyaWNzOiBDdXN0b21NZXRyaWNbXTtcbiAgLyoqXG4gICAqIE9wdGlvbmFsIGN1c3RvbSBob3Jpem9udGFsIGFubm90YXRpb25zIHdoaWNoIHdpbGwgYmUgZGlzcGxheWVkIG92ZXIgdGhlIG1ldHJpY3Mgb24gdGhlIGxlZnQgYXhpc1xuICAgKiAoaWYgdGhlcmUgYXJlIGFueSBhbGFybXMsIGFueSBleGlzdGluZyBhbm5vdGF0aW9ucyB3aWxsIGJlIG1lcmdlZCB0b2dldGhlcikuXG4gICAqL1xuICByZWFkb25seSBob3Jpem9udGFsQW5ub3RhdGlvbnM/OiBIb3Jpem9udGFsQW5ub3RhdGlvbltdO1xuICAvKipcbiAgICogT3B0aW9uYWwgY3VzdG9tIGhvcml6b250YWwgYW5ub3RhdGlvbnMgd2hpY2ggd2lsbCBiZSBkaXNwbGF5ZWQgb3ZlciB0aGUgbWV0cmljcyBvbiB0aGUgcmlnaHQgYXhpc1xuICAgKiAoaWYgdGhlcmUgYXJlIGFueSBhbGFybXMsIGFueSBleGlzdGluZyBhbm5vdGF0aW9ucyB3aWxsIGJlIG1lcmdlZCB0b2dldGhlcikuXG4gICAqL1xuICByZWFkb25seSBob3Jpem9udGFsUmlnaHRBbm5vdGF0aW9ucz86IEhvcml6b250YWxBbm5vdGF0aW9uW107XG4gIC8qKlxuICAgKiBPcHRpb25hbCBjdXN0b20gdmVydGljYWwgYW5ub3RhdGlvbnMgd2hpY2ggd2lsbCBiZSBkaXNwbGF5ZWQgb3ZlciB0aGUgbWV0cmljcy5cbiAgICovXG4gIHJlYWRvbmx5IHZlcnRpY2FsQW5ub3RhdGlvbnM/OiBWZXJ0aWNhbEFubm90YXRpb25bXTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBDdXN0b21Nb25pdG9yaW5nUHJvcHMgZXh0ZW5kcyBCYXNlTW9uaXRvcmluZ1Byb3BzIHtcbiAgLyoqXG4gICAqIG9wdGlvbmFsIGRlc2NyaXB0aW9uIG9mIHRoZSB3aG9sZSBzZWN0aW9uLCBpbiBtYXJrZG93blxuICAgKlxuICAgKiBAZGVmYXVsdCAtIG5vIGRlc2NyaXB0aW9uXG4gICAqL1xuICByZWFkb25seSBkZXNjcmlwdGlvbj86IHN0cmluZztcbiAgLyoqXG4gICAqIG9wdGlvbmFsIGhlaWdodCBvZiB0aGUgZGVzY3JpcHRpb24gd2lkZ2V0LCBzbyB0aGUgY29udGVudCBmaXRzXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gbWluaW11bSBoZWlnaHQgKHNob3VsZCBmaXQgb25lIG9yIHR3byBsaW5lcyBvZiB0ZXh0KVxuICAgKi9cbiAgcmVhZG9ubHkgZGVzY3JpcHRpb25XaWRnZXRIZWlnaHQ/OiBudW1iZXI7XG4gIC8qKlxuICAgKiBIZWlnaHQgb3ZlcnJpZGUuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gZGVmYXVsdCBoZWlnaHRcbiAgICovXG4gIHJlYWRvbmx5IGhlaWdodD86IG51bWJlcjtcbiAgLyoqXG4gICAqIGRlZmluZSBtZXRyaWMgZ3JvdXBzIGFuZCBtZXRyaWNzIGluc2lkZSB0aGVtIChlYWNoIG1ldHJpYyBncm91cCByZXByZXNlbnRzIGEgd2lkZ2V0KVxuICAgKi9cbiAgcmVhZG9ubHkgbWV0cmljR3JvdXBzOiBDdXN0b21NZXRyaWNHcm91cFtdO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEN1c3RvbU1ldHJpY0dyb3VwV2l0aEFubm90YXRpb25zIHtcbiAgcmVhZG9ubHkgbWV0cmljR3JvdXA6IEN1c3RvbU1ldHJpY0dyb3VwO1xuICByZWFkb25seSBhbm5vdGF0aW9uczogSG9yaXpvbnRhbEFubm90YXRpb25bXTtcbiAgcmVhZG9ubHkgcmlnaHRBbm5vdGF0aW9uczogSG9yaXpvbnRhbEFubm90YXRpb25bXTtcbiAgcmVhZG9ubHkgdmVydGljYWxBbm5vdGF0aW9uczogVmVydGljYWxBbm5vdGF0aW9uW107XG4gIHJlYWRvbmx5IHRpdGxlQWRkb25zOiBzdHJpbmdbXTtcbiAgcmVhZG9ubHkgaGVpZ2h0PzogbnVtYmVyO1xufVxuXG4vKipcbiAqIEN1c3RvbSBtb25pdG9yaW5nIGlzIGEgY29uc3RydWN0IGFsbG93aW5nIHlvdSB0byBtb25pdG9yIHlvdXIgb3duIGN1c3RvbSBtZXRyaWNzLlxuICogVGhlIGVudGlyZSBjb25zdHJ1Y3QgY29uc2lzdHMgb2YgbWV0cmljIGdyb3Vwcy5cbiAqIEVhY2ggbWV0cmljIGdyb3VwIHJlcHJlc2VudHMgYSBzaW5nbGUgZ3JhcGggd2lkZ2V0IHdpdGggbXVsdGlwbGUgbWV0cmljcy5cbiAqIEVhY2ggbWV0cmljIGluc2lkZSB0aGUgbWV0cmljIGdyb3VwIHJlcHJlc2VudHMgYSBzaW5nbGUgbWV0cmljIGluc2lkZSBhIGdyYXBoLlxuICogVGhlIHdpZGdldHMgd2lsbCBiZSBzaXplZCBhdXRvbWF0aWNhbGx5IHRvIHdhc3RlIGFzIGxpdHRsZSBzcGFjZSBhcyBwb3NzaWJsZS5cbiAqL1xuZXhwb3J0IGNsYXNzIEN1c3RvbU1vbml0b3JpbmcgZXh0ZW5kcyBNb25pdG9yaW5nIHtcbiAgcmVhZG9ubHkgdGl0bGU6IHN0cmluZztcbiAgcmVhZG9ubHkgZGVzY3JpcHRpb24/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGRlc2NyaXB0aW9uV2lkZ2V0SGVpZ2h0PzogbnVtYmVyO1xuICByZWFkb25seSBoZWlnaHQ/OiBudW1iZXI7XG4gIHJlYWRvbmx5IGFkZFRvU3VtbWFyeURhc2hib2FyZDogYm9vbGVhbjtcbiAgcmVhZG9ubHkgY3VzdG9tQWxhcm1GYWN0b3J5OiBDdXN0b21BbGFybUZhY3Rvcnk7XG4gIHJlYWRvbmx5IGFub21hbHlEZXRlY3RpbmdBbGFybUZhY3Rvcnk6IEFub21hbHlEZXRlY3RpbmdBbGFybUZhY3Rvcnk7XG4gIHJlYWRvbmx5IG1ldHJpY0dyb3VwczogQ3VzdG9tTWV0cmljR3JvdXBXaXRoQW5ub3RhdGlvbnNbXTtcblxuICBjb25zdHJ1Y3RvcihzY29wZTogTW9uaXRvcmluZ1Njb3BlLCBwcm9wczogQ3VzdG9tTW9uaXRvcmluZ1Byb3BzKSB7XG4gICAgc3VwZXIoc2NvcGUsIHByb3BzKTtcblxuICAgIGNvbnN0IG5hbWluZ1N0cmF0ZWd5ID0gbmV3IE1vbml0b3JpbmdOYW1pbmdTdHJhdGVneSh7IC4uLnByb3BzIH0pO1xuICAgIHRoaXMudGl0bGUgPSBuYW1pbmdTdHJhdGVneS5yZXNvbHZlSHVtYW5SZWFkYWJsZU5hbWUoKTtcblxuICAgIHRoaXMuZGVzY3JpcHRpb24gPSBwcm9wcy5kZXNjcmlwdGlvbjtcbiAgICB0aGlzLmRlc2NyaXB0aW9uV2lkZ2V0SGVpZ2h0ID0gcHJvcHMuZGVzY3JpcHRpb25XaWRnZXRIZWlnaHQ7XG4gICAgdGhpcy5oZWlnaHQgPSBwcm9wcy5oZWlnaHQ7XG4gICAgdGhpcy5hZGRUb1N1bW1hcnlEYXNoYm9hcmQgPSBwcm9wcy5hZGRUb1N1bW1hcnlEYXNoYm9hcmQgPz8gZmFsc2U7XG5cbiAgICBjb25zdCBhbGFybUZhY3RvcnkgPSB0aGlzLmNyZWF0ZUFsYXJtRmFjdG9yeShcbiAgICAgIG5hbWluZ1N0cmF0ZWd5LnJlc29sdmVBbGFybUZyaWVuZGx5TmFtZSgpLFxuICAgICk7XG4gICAgdGhpcy5jdXN0b21BbGFybUZhY3RvcnkgPSBuZXcgQ3VzdG9tQWxhcm1GYWN0b3J5KGFsYXJtRmFjdG9yeSk7XG4gICAgdGhpcy5hbm9tYWx5RGV0ZWN0aW5nQWxhcm1GYWN0b3J5ID0gbmV3IEFub21hbHlEZXRlY3RpbmdBbGFybUZhY3RvcnkoXG4gICAgICBhbGFybUZhY3RvcnksXG4gICAgKTtcblxuICAgIHRoaXMubWV0cmljR3JvdXBzID0gcHJvcHMubWV0cmljR3JvdXBzLm1hcCgobWV0cmljR3JvdXApID0+IHtcbiAgICAgIGNvbnN0IG1ldHJpY0dyb3VwV2l0aEFubm90YXRpb246IEN1c3RvbU1ldHJpY0dyb3VwV2l0aEFubm90YXRpb25zID0ge1xuICAgICAgICBtZXRyaWNHcm91cCxcbiAgICAgICAgYW5ub3RhdGlvbnM6IFtdLFxuICAgICAgICByaWdodEFubm90YXRpb25zOiBbXSxcbiAgICAgICAgdmVydGljYWxBbm5vdGF0aW9uczogW10sXG4gICAgICAgIHRpdGxlQWRkb25zOiBbXSxcbiAgICAgIH07XG5cbiAgICAgIGlmIChtZXRyaWNHcm91cC5ob3Jpem9udGFsQW5ub3RhdGlvbnMpIHtcbiAgICAgICAgbWV0cmljR3JvdXBXaXRoQW5ub3RhdGlvbi5hbm5vdGF0aW9ucy5wdXNoKFxuICAgICAgICAgIC4uLm1ldHJpY0dyb3VwLmhvcml6b250YWxBbm5vdGF0aW9ucyxcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIGlmIChtZXRyaWNHcm91cC5ob3Jpem9udGFsUmlnaHRBbm5vdGF0aW9ucykge1xuICAgICAgICBtZXRyaWNHcm91cFdpdGhBbm5vdGF0aW9uLnJpZ2h0QW5ub3RhdGlvbnMucHVzaChcbiAgICAgICAgICAuLi5tZXRyaWNHcm91cC5ob3Jpem9udGFsUmlnaHRBbm5vdGF0aW9ucyxcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIGlmIChtZXRyaWNHcm91cC52ZXJ0aWNhbEFubm90YXRpb25zKSB7XG4gICAgICAgIG1ldHJpY0dyb3VwV2l0aEFubm90YXRpb24udmVydGljYWxBbm5vdGF0aW9ucy5wdXNoKFxuICAgICAgICAgIC4uLm1ldHJpY0dyb3VwLnZlcnRpY2FsQW5ub3RhdGlvbnMsXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIG1ldHJpY0dyb3VwLm1ldHJpY3MuZm9yRWFjaCgobWV0cmljKSA9PiB7XG4gICAgICAgIGlmICh0aGlzLmhhc0FsYXJtKG1ldHJpYykgJiYgdGhpcy5oYXNBbm9tYWx5RGV0ZWN0aW9uKG1ldHJpYykpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICBcIkFkZGluZyBib3RoIGEgcmVndWxhciBhbGFybSBhbmQgYW4gYW5vbWFseSBkZXRlY3Rpb24gYWxhcm0gYXQgdGhlIHNhbWUgdGltZSBpcyBub3Qgc3VwcG9ydGVkXCIsXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0aGlzLmhhc0FsYXJtKG1ldHJpYykpIHtcbiAgICAgICAgICB0aGlzLnNldHVwQWxhcm0obWV0cmljR3JvdXBXaXRoQW5ub3RhdGlvbiwgbWV0cmljKTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLmhhc0Fub21hbHlEZXRlY3Rpb24obWV0cmljKSkge1xuICAgICAgICAgIHRoaXMuc2V0dXBBbm9tYWx5RGV0ZWN0aW9uQWxhcm0obWV0cmljR3JvdXBXaXRoQW5ub3RhdGlvbiwgbWV0cmljKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG5cbiAgICAgIHJldHVybiBtZXRyaWNHcm91cFdpdGhBbm5vdGF0aW9uO1xuICAgIH0pO1xuXG4gICAgcHJvcHMudXNlQ3JlYXRlZEFsYXJtcz8uY29uc3VtZSh0aGlzLmNyZWF0ZWRBbGFybXMoKSk7XG4gIH1cblxuICBzdW1tYXJ5V2lkZ2V0cygpOiBJV2lkZ2V0W10ge1xuICAgIHJldHVybiB0aGlzLmdldEFsbFdpZGdldHModHJ1ZSk7XG4gIH1cblxuICB3aWRnZXRzKCk6IElXaWRnZXRbXSB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0QWxsV2lkZ2V0cyhmYWxzZSk7XG4gIH1cblxuICBwcml2YXRlIGdldEFsbFdpZGdldHMoc3VtbWFyeTogYm9vbGVhbik6IElXaWRnZXRbXSB7XG4gICAgY29uc3QgZmlsdGVyZWRNZXRyaWNHcm91cHMgPSBzdW1tYXJ5XG4gICAgICA/IHRoaXMubWV0cmljR3JvdXBzLmZpbHRlcihcbiAgICAgICAgICAoZ3JvdXApID0+XG4gICAgICAgICAgICBncm91cC5tZXRyaWNHcm91cC5hZGRUb1N1bW1hcnlEYXNoYm9hcmQgPz9cbiAgICAgICAgICAgIGdyb3VwLm1ldHJpY0dyb3VwLmltcG9ydGFudCA/P1xuICAgICAgICAgICAgdGhpcy5hZGRUb1N1bW1hcnlEYXNoYm9hcmQsXG4gICAgICAgIClcbiAgICAgIDogdGhpcy5tZXRyaWNHcm91cHM7XG5cbiAgICBpZiAoZmlsdGVyZWRNZXRyaWNHcm91cHMubGVuZ3RoIDwgMSkge1xuICAgICAgLy8gc2hvcnQtY2lyY3VpdCBpZiB0aGVyZSBhcmUgbm8gbWV0cmljcyBzcGVjaWZpZWRcbiAgICAgIHJldHVybiBbXTtcbiAgICB9XG5cbiAgICBjb25zdCByb3dzOiBSb3dbXSA9IFtdO1xuXG4gICAgLy8gaGVhZGVyIGFuZCBkZXNjcmlwdGlvblxuICAgIHJvd3MucHVzaChuZXcgUm93KG5ldyBNb25pdG9yaW5nSGVhZGVyV2lkZ2V0KHsgdGl0bGU6IHRoaXMudGl0bGUgfSkpKTtcbiAgICBpZiAodGhpcy5kZXNjcmlwdGlvbiAmJiAhc3VtbWFyeSkge1xuICAgICAgcm93cy5wdXNoKFxuICAgICAgICBuZXcgUm93KFxuICAgICAgICAgIHRoaXMuY3JlYXRlRGVzY3JpcHRpb25XaWRnZXQoXG4gICAgICAgICAgICB0aGlzLmRlc2NyaXB0aW9uLFxuICAgICAgICAgICAgdGhpcy5kZXNjcmlwdGlvbldpZGdldEhlaWdodCxcbiAgICAgICAgICApLFxuICAgICAgICApLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBncmFwaHNcbiAgICByb3dzLnB1c2goXG4gICAgICBuZXcgUm93KFxuICAgICAgICAuLi50aGlzLmNyZWF0ZUN1c3RvbU1ldHJpY0dyb3VwV2lkZ2V0cyhmaWx0ZXJlZE1ldHJpY0dyb3Vwcywgc3VtbWFyeSksXG4gICAgICApLFxuICAgICk7XG5cbiAgICByZXR1cm4gcm93cztcbiAgfVxuXG4gIHByaXZhdGUgY3JlYXRlRGVzY3JpcHRpb25XaWRnZXQoXG4gICAgbWFya2Rvd246IHN0cmluZyxcbiAgICBkZXNjcmlwdGlvbldpZGdldEhlaWdodD86IG51bWJlcixcbiAgKSB7XG4gICAgcmV0dXJuIG5ldyBUZXh0V2lkZ2V0KHtcbiAgICAgIG1hcmtkb3duLFxuICAgICAgd2lkdGg6IEZ1bGxXaWR0aCxcbiAgICAgIGhlaWdodDogZGVzY3JpcHRpb25XaWRnZXRIZWlnaHQgPz8gMSxcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgY3JlYXRlQ3VzdG9tTWV0cmljR3JvdXBXaWRnZXRzKFxuICAgIGFubm90YXRlZEdyb3VwczogQ3VzdG9tTWV0cmljR3JvdXBXaXRoQW5ub3RhdGlvbnNbXSxcbiAgICBzdW1tYXJ5OiBib29sZWFuLFxuICApIHtcbiAgICBjb25zdCB3aWRnZXRzOiBJV2lkZ2V0W10gPSBbXTtcbiAgICBjb25zdCBtZXRyaWNHcm91cFdpZGdldEhlaWdodERlZmF1bHQgPSBzdW1tYXJ5XG4gICAgICA/IERlZmF1bHRTdW1tYXJ5V2lkZ2V0SGVpZ2h0XG4gICAgICA6IERlZmF1bHRHcmFwaFdpZGdldEhlaWdodDtcbiAgICBjb25zdCBtZXRyaWNHcm91cFdpZGdldEhlaWdodCA9XG4gICAgICB0aGlzLmhlaWdodCA/PyBtZXRyaWNHcm91cFdpZGdldEhlaWdodERlZmF1bHQ7XG5cbiAgICBhbm5vdGF0ZWRHcm91cHMuZm9yRWFjaCgoYW5ub3RhdGVkR3JvdXApID0+IHtcbiAgICAgIGNvbnN0IG1ldHJpY3MgPSBhbm5vdGF0ZWRHcm91cC5tZXRyaWNHcm91cC5tZXRyaWNzO1xuICAgICAgY29uc3QgbGVmdCA9IHRoaXMudG9NZXRyaWNzKFxuICAgICAgICBtZXRyaWNzLmZpbHRlcihcbiAgICAgICAgICAobWV0cmljKSA9PlxuICAgICAgICAgICAgKChtZXRyaWMgYXMgYW55KS5wb3NpdGlvbiA/PyBBeGlzUG9zaXRpb24uTEVGVCkgPT1cbiAgICAgICAgICAgIEF4aXNQb3NpdGlvbi5MRUZULFxuICAgICAgICApLFxuICAgICAgKTtcbiAgICAgIGNvbnN0IHJpZ2h0ID0gdGhpcy50b01ldHJpY3MoXG4gICAgICAgIG1ldHJpY3MuZmlsdGVyKFxuICAgICAgICAgIChtZXRyaWMpID0+XG4gICAgICAgICAgICAoKG1ldHJpYyBhcyBhbnkpLnBvc2l0aW9uID8/IEF4aXNQb3NpdGlvbi5MRUZUKSA9PVxuICAgICAgICAgICAgQXhpc1Bvc2l0aW9uLlJJR0hULFxuICAgICAgICApLFxuICAgICAgKTtcbiAgICAgIGNvbnN0IGhhc09uZU1ldHJpY09ubHkgPSBtZXRyaWNzLmxlbmd0aCA9PT0gMTtcbiAgICAgIGNvbnN0IGhhc0Fub21hbHlEZXRlY3Rpb24gPVxuICAgICAgICBtZXRyaWNzLmZpbHRlcigobWV0cmljKSA9PiB0aGlzLmhhc0Fub21hbHlEZXRlY3Rpb24obWV0cmljKSkubGVuZ3RoID4gMDtcbiAgICAgIGNvbnN0IHVzZUFub21hbHlEZXRlY3Rpb25XaWRnZXQgPSBoYXNPbmVNZXRyaWNPbmx5ICYmIGhhc0Fub21hbHlEZXRlY3Rpb247XG4gICAgICBsZXQgdGl0bGUgPSBhbm5vdGF0ZWRHcm91cC5tZXRyaWNHcm91cC50aXRsZTtcblxuICAgICAgaWYgKGFubm90YXRlZEdyb3VwLnRpdGxlQWRkb25zLmxlbmd0aCA+IDApIHtcbiAgICAgICAgdGl0bGUgPSBgJHt0aXRsZX0gKCR7YW5ub3RhdGVkR3JvdXAudGl0bGVBZGRvbnMuam9pbihcIiwgXCIpfSlgO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBncmFwaFdpZGdldFByb3BzOiBHcmFwaFdpZGdldFByb3BzID0ge1xuICAgICAgICB0aXRsZSxcbiAgICAgICAgd2lkdGg6XG4gICAgICAgICAgYW5ub3RhdGVkR3JvdXAubWV0cmljR3JvdXAuZ3JhcGhXaWRnZXRXaWR0aCA/P1xuICAgICAgICAgIHJlY29tbWVuZGVkV2lkZ2V0V2lkdGgoYW5ub3RhdGVkR3JvdXBzLmxlbmd0aCksXG4gICAgICAgIGhlaWdodDogbWV0cmljR3JvdXBXaWRnZXRIZWlnaHQsXG4gICAgICAgIGxlZnQsXG4gICAgICAgIHJpZ2h0LFxuICAgICAgICBsZWZ0QW5ub3RhdGlvbnM6IGFubm90YXRlZEdyb3VwLmFubm90YXRpb25zLFxuICAgICAgICByaWdodEFubm90YXRpb25zOiBhbm5vdGF0ZWRHcm91cC5yaWdodEFubm90YXRpb25zLFxuICAgICAgICBsZWZ0WUF4aXM6IGFubm90YXRlZEdyb3VwLm1ldHJpY0dyb3VwLmdyYXBoV2lkZ2V0QXhpcyxcbiAgICAgICAgcmlnaHRZQXhpczogYW5ub3RhdGVkR3JvdXAubWV0cmljR3JvdXAuZ3JhcGhXaWRnZXRSaWdodEF4aXMsXG4gICAgICAgIHZlcnRpY2FsQW5ub3RhdGlvbnM6IGFubm90YXRlZEdyb3VwLnZlcnRpY2FsQW5ub3RhdGlvbnMsXG4gICAgICAgIGxlZ2VuZFBvc2l0aW9uOiBhbm5vdGF0ZWRHcm91cC5tZXRyaWNHcm91cC5ncmFwaFdpZGdldExlZ2VuZCxcbiAgICAgICAgc2V0UGVyaW9kVG9UaW1lUmFuZ2U6XG4gICAgICAgICAgYW5ub3RhdGVkR3JvdXAubWV0cmljR3JvdXAuZ3JhcGhXaWRnZXRTZXRQZXJpb2RUb1RpbWVSYW5nZSxcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IHdpZGdldCA9IHVzZUFub21hbHlEZXRlY3Rpb25XaWRnZXRcbiAgICAgICAgPyBuZXcgQW5vbWFseURldGVjdGlvbkdyYXBoV2lkZ2V0KGdyYXBoV2lkZ2V0UHJvcHMpXG4gICAgICAgIDogY3JlYXRlR3JhcGhXaWRnZXQoXG4gICAgICAgICAgICBhbm5vdGF0ZWRHcm91cC5tZXRyaWNHcm91cC5ncmFwaFdpZGdldFR5cGUgPz8gR3JhcGhXaWRnZXRUeXBlLkxJTkUsXG4gICAgICAgICAgICBncmFwaFdpZGdldFByb3BzLFxuICAgICAgICAgICk7XG5cbiAgICAgIHdpZGdldHMucHVzaCh3aWRnZXQpO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIHdpZGdldHM7XG4gIH1cblxuICBwcml2YXRlIHRvTWV0cmljcyhtZXRyaWNzOiBDdXN0b21NZXRyaWNbXSk6IElNZXRyaWNbXSB7XG4gICAgY29uc3QgbWV0cmljRmFjdG9yeSA9IHRoaXMuY3JlYXRlTWV0cmljRmFjdG9yeSgpO1xuXG4gICAgcmV0dXJuIG1ldHJpY3MubWFwKChtZXRyaWMpID0+IHtcbiAgICAgIGlmICh0aGlzLmhhc0FsYXJtKG1ldHJpYykpIHtcbiAgICAgICAgLy8gbWV0cmljIHdpdGggYWxhcm1cbiAgICAgICAgcmV0dXJuIG1ldHJpY0ZhY3RvcnkuYWRhcHRNZXRyaWNQcmVzZXJ2aW5nUGVyaW9kKG1ldHJpYy5tZXRyaWMpO1xuICAgICAgfSBlbHNlIGlmICh0aGlzLmhhc0Fub21hbHlEZXRlY3Rpb24obWV0cmljKSkge1xuICAgICAgICAvLyBtZXRyaWMgd2l0aCBhbm9tYWx5IGRldGVjdGlvblxuICAgICAgICByZXR1cm4gbWV0cmljRmFjdG9yeS5jcmVhdGVNZXRyaWNBbm9tYWx5RGV0ZWN0aW9uKFxuICAgICAgICAgIG1ldHJpYy5tZXRyaWMsXG4gICAgICAgICAgbWV0cmljLmFub21hbHlEZXRlY3Rpb25TdGFuZGFyZERldmlhdGlvblRvUmVuZGVyLFxuICAgICAgICAgIGBFeHBlY3RlZCAoc3RkZXYgPSAke21ldHJpYy5hbm9tYWx5RGV0ZWN0aW9uU3RhbmRhcmREZXZpYXRpb25Ub1JlbmRlcn0pYCxcbiAgICAgICAgICB1bmRlZmluZWQsXG4gICAgICAgICAgLy8gbmVlZHMgdG8gYmUgdW5pcXVlIGluIHRoZSB3aG9sZSB3aWRnZXQgYW5kIHN0YXJ0IHdpdGggbG93ZXJjYXNlXG4gICAgICAgICAgQW5vbWFseURldGVjdGlvbk1ldHJpY0lkUHJlZml4ICtcbiAgICAgICAgICAgIGdldEhhc2hGb3JNZXRyaWNFeHByZXNzaW9uSWQobWV0cmljLmFsYXJtRnJpZW5kbHlOYW1lKSxcbiAgICAgICAgICAvLyBwcmVzZXJ2ZSB0aGUgbW9zdCBzcGVjaWZpYyBtZXRyaWMgcGVyaW9kXG4gICAgICAgICAgbWV0cmljLnBlcmlvZCA/PyBtZXRyaWMubWV0cmljLnBlcmlvZCxcbiAgICAgICAgKTtcbiAgICAgIH0gZWxzZSBpZiAodGhpcy5pc1NlYXJjaChtZXRyaWMpKSB7XG4gICAgICAgIC8vIG1ldHJpYyBzZWFyY2hcbiAgICAgICAgcmV0dXJuIG1ldHJpY0ZhY3RvcnkuY3JlYXRlTWV0cmljU2VhcmNoKFxuICAgICAgICAgIG1ldHJpYy5zZWFyY2hRdWVyeSxcbiAgICAgICAgICBtZXRyaWMuZGltZW5zaW9uc01hcCxcbiAgICAgICAgICBtZXRyaWMuc3RhdGlzdGljLFxuICAgICAgICAgIG1ldHJpYy5uYW1lc3BhY2UsXG4gICAgICAgICAgbWV0cmljLmxhYmVsLFxuICAgICAgICAgIG1ldHJpYy5wZXJpb2QsXG4gICAgICAgICAgbWV0cmljLnJlZ2lvbixcbiAgICAgICAgICBtZXRyaWMuYWNjb3VudCxcbiAgICAgICAgKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIGdlbmVyYWwgbWV0cmljXG4gICAgICAgIHJldHVybiBtZXRyaWNGYWN0b3J5LmFkYXB0TWV0cmljUHJlc2VydmluZ1BlcmlvZChtZXRyaWMpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBoYXNBbGFybShtZXRyaWM6IEN1c3RvbU1ldHJpYyk6IG1ldHJpYyBpcyBDdXN0b21NZXRyaWNXaXRoQWxhcm0ge1xuICAgIC8vIHR5cGUgZ3VhcmRcbiAgICByZXR1cm4gKG1ldHJpYyBhcyBDdXN0b21NZXRyaWNXaXRoQWxhcm0pLmFkZEFsYXJtICE9PSB1bmRlZmluZWQ7XG4gIH1cblxuICBwcml2YXRlIGhhc0Fub21hbHlEZXRlY3Rpb24oXG4gICAgbWV0cmljOiBDdXN0b21NZXRyaWMsXG4gICk6IG1ldHJpYyBpcyBDdXN0b21NZXRyaWNXaXRoQW5vbWFseURldGVjdGlvbiB7XG4gICAgLy8gdHlwZSBndWFyZFxuICAgIHJldHVybiAoXG4gICAgICAobWV0cmljIGFzIEN1c3RvbU1ldHJpY1dpdGhBbm9tYWx5RGV0ZWN0aW9uKVxuICAgICAgICAuYW5vbWFseURldGVjdGlvblN0YW5kYXJkRGV2aWF0aW9uVG9SZW5kZXIgIT09IHVuZGVmaW5lZFxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIGlzU2VhcmNoKG1ldHJpYzogQ3VzdG9tTWV0cmljKTogbWV0cmljIGlzIEN1c3RvbU1ldHJpY1NlYXJjaCB7XG4gICAgLy8gdHlwZSBndWFyZFxuICAgIHJldHVybiAobWV0cmljIGFzIEN1c3RvbU1ldHJpY1NlYXJjaCkuc2VhcmNoUXVlcnkgIT09IHVuZGVmaW5lZDtcbiAgfVxuXG4gIHByaXZhdGUgc2V0dXBBbGFybShcbiAgICBtZXRyaWNHcm91cDogQ3VzdG9tTWV0cmljR3JvdXBXaXRoQW5ub3RhdGlvbnMsXG4gICAgbWV0cmljOiBDdXN0b21NZXRyaWNXaXRoQWxhcm0sXG4gICkge1xuICAgIGlmICh0aGlzLmlzU2VhcmNoKG1ldHJpYykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgXCJBbGFybWluZyBvbiBzZWFyY2ggcXVlcmllcyBpcyBub3Qgc3VwcG9ydGVkIGJ5IENsb3VkV2F0Y2hcIixcbiAgICAgICk7XG4gICAgfVxuXG4gICAgZm9yIChjb25zdCBkaXNhbWJpZ3VhdG9yIGluIG1ldHJpYy5hZGRBbGFybSkge1xuICAgICAgY29uc3QgYWxhcm1Qcm9wcyA9IG1ldHJpYy5hZGRBbGFybVtkaXNhbWJpZ3VhdG9yXTtcbiAgICAgIGNvbnN0IGNyZWF0ZWRBbGFybSA9IHRoaXMuY3VzdG9tQWxhcm1GYWN0b3J5LmFkZEN1c3RvbUFsYXJtKFxuICAgICAgICBtZXRyaWMubWV0cmljLFxuICAgICAgICBtZXRyaWMuYWxhcm1GcmllbmRseU5hbWUsXG4gICAgICAgIGRpc2FtYmlndWF0b3IsXG4gICAgICAgIGFsYXJtUHJvcHMsXG4gICAgICApO1xuICAgICAgY29uc3QgdGFyZ2V0QW5ub3RhdGlvbnMgPVxuICAgICAgICAobWV0cmljLnBvc2l0aW9uID8/IEF4aXNQb3NpdGlvbi5MRUZUKSA9PSBBeGlzUG9zaXRpb24uTEVGVFxuICAgICAgICAgID8gbWV0cmljR3JvdXAuYW5ub3RhdGlvbnNcbiAgICAgICAgICA6IG1ldHJpY0dyb3VwLnJpZ2h0QW5ub3RhdGlvbnM7XG4gICAgICB0YXJnZXRBbm5vdGF0aW9ucy5wdXNoKGNyZWF0ZWRBbGFybS5hbm5vdGF0aW9uKTtcbiAgICAgIHRoaXMuYWRkQWxhcm0oY3JlYXRlZEFsYXJtKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHNldHVwQW5vbWFseURldGVjdGlvbkFsYXJtKFxuICAgIG1ldHJpY0dyb3VwOiBDdXN0b21NZXRyaWNHcm91cFdpdGhBbm5vdGF0aW9ucyxcbiAgICBtZXRyaWM6IEN1c3RvbU1ldHJpY1dpdGhBbm9tYWx5RGV0ZWN0aW9uLFxuICApIHtcbiAgICBpZiAodGhpcy5pc1NlYXJjaChtZXRyaWMpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIFwiQWxhcm1pbmcgb24gc2VhcmNoIHF1ZXJpZXMgaXMgbm90IHN1cHBvcnRlZCBieSBDbG91ZFdhdGNoXCIsXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IGFsYXJtU3REZXZzID0gbmV3IFNldDxudW1iZXI+KCk7XG4gICAgY29uc3QgbWV0cmljRmFjdG9yeSA9IHRoaXMuY3JlYXRlTWV0cmljRmFjdG9yeSgpO1xuXG4gICAgZm9yIChjb25zdCBkaXNhbWJpZ3VhdG9yIGluIG1ldHJpYy5hZGRBbGFybU9uQW5vbWFseSkge1xuICAgICAgY29uc3QgYWxhcm1Qcm9wcyA9IG1ldHJpYy5hZGRBbGFybU9uQW5vbWFseVtkaXNhbWJpZ3VhdG9yXTtcbiAgICAgIGlmIChcbiAgICAgICAgYWxhcm1Qcm9wcy5hbGFybVdoZW5BYm92ZVRoZUJhbmQgfHxcbiAgICAgICAgYWxhcm1Qcm9wcy5hbGFybVdoZW5CZWxvd1RoZUJhbmRcbiAgICAgICkge1xuICAgICAgICBjb25zdCBhbm9tYWx5TWV0cmljID0gbWV0cmljRmFjdG9yeS5jcmVhdGVNZXRyaWNBbm9tYWx5RGV0ZWN0aW9uKFxuICAgICAgICAgIC8vIEJlY2F1c2UgdGhlIG1ldHJpYyB3YXMgcHJvdmlkZWQgdG8gdXMsIHdlIHVzZSBtZXRyaWNGYWN0b3J5Lm92ZXJyaWRlTmFtZXNwYWNlKCkgdG9cbiAgICAgICAgICAvLyBjb25maXJtIGl0IGFsaWducyB3aXRoIGFueSBuYW1lc3BhY2Ugb3ZlcnJpZGVzIHJlcXVlc3RlZCBmb3IgdGhpcyBNb25pdG9yaW5nRmFjYWRlXG4gICAgICAgICAgbWV0cmljRmFjdG9yeS5hZGFwdE1ldHJpY1ByZXNlcnZpbmdQZXJpb2QobWV0cmljLm1ldHJpYyksXG4gICAgICAgICAgYWxhcm1Qcm9wcy5zdGFuZGFyZERldmlhdGlvbkZvckFsYXJtLFxuICAgICAgICAgIGBCYW5kIChzdGRldiAke2FsYXJtUHJvcHMuc3RhbmRhcmREZXZpYXRpb25Gb3JBbGFybX0pYCxcbiAgICAgICAgICB1bmRlZmluZWQsXG4gICAgICAgICAgLy8gZXhwcmVzc2lvbiBJRCBuZWVkcyB0byBiZSB1bmlxdWUgYWNyb3NzIHRoZSB3aG9sZSB3aWRnZXQ7IG5lZWRzIHRvIHN0YXJ0IHdpdGggYSBsb3dlcmNhc2UgbGV0dGVyXG4gICAgICAgICAgQW5vbWFseURldGVjdGlvbkFsYXJtSWRQcmVmaXggK1xuICAgICAgICAgICAgZ2V0SGFzaEZvck1ldHJpY0V4cHJlc3Npb25JZChcbiAgICAgICAgICAgICAgbWV0cmljLmFsYXJtRnJpZW5kbHlOYW1lICsgXCJfXCIgKyBkaXNhbWJpZ3VhdG9yLFxuICAgICAgICAgICAgKSxcbiAgICAgICAgICAvLyBwcmVzZXJ2ZSB