UNPKG

cdk-monitoring-constructs

Version:

[![NPM version](https://badge.fury.io/js/cdk-monitoring-constructs.svg)](https://badge.fury.io/js/cdk-monitoring-constructs) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.github.cdklabs/cdkmonitoringconstructs/badge.svg)](https://m

268 lines 53.6 kB
"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