UNPKG

cdk-monitoring-constructs

Version:

[![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/cdklabs/cdk-monitoring-constructs) [![NPM version](https://badge.fury.io/js/cdk-monitoring-constructs.svg)](https://badge

253 lines 48.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; 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: [], titleAddons: [], }; if (metricGroup.horizontalAnnotations) { metricGroupWithAnnotation.annotations.push(...metricGroup.horizontalAnnotations); } if (metricGroup.horizontalRightAnnotations) { metricGroupWithAnnotation.rightAnnotations.push(...metricGroup.horizontalRightAnnotations); } metricGroup.metrics.forEach((metric) => { if (this.hasAlarm(metric) && this.hasAnomalyDetection(metric)) { throw new Error("Adding both a regular alarm and an anomoly 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.important ?? false) : 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 metricGroupWidgetWidth = common_1.recommendedWidgetWidth(annotatedGroups.length); 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: metricGroupWidgetWidth, height: summary ? common_1.DefaultSummaryWidgetHeight : common_1.DefaultGraphWidgetHeight, left, right, leftAnnotations: annotatedGroup.annotations, rightAnnotations: annotatedGroup.rightAnnotations, leftYAxis: annotatedGroup.metricGroup.graphWidgetAxis, rightYAxis: annotatedGroup.metricGroup.graphWidgetRightAxis, legendPosition: annotatedGroup.metricGroup.graphWidgetLegend, }; 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); } 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: "1.21.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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ3VzdG9tTW9uaXRvcmluZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIkN1c3RvbU1vbml0b3JpbmcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFDQSwrREFXb0M7QUFFcEMseUNBaUJzQjtBQUN0QiwrQ0FHeUI7QUFFekIsSUFBWSxZQUdYO0FBSEQsV0FBWSxZQUFZO0lBQ3RCLDZCQUFhLENBQUE7SUFDYiwrQkFBZSxDQUFBO0FBQ2pCLENBQUMsRUFIVyxZQUFZLEdBQVosb0JBQVksS0FBWixvQkFBWSxRQUd2QjtBQXFLRDs7Ozs7O0dBTUc7QUFDSCxNQUFhLGdCQUFpQixTQUFRLG1CQUFVO0lBUTlDLFlBQVksS0FBc0IsRUFBRSxLQUE0QjtRQUM5RCxLQUFLLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBRXBCLE1BQU0sY0FBYyxHQUFHLElBQUksb0NBQXdCLENBQUMsRUFBRSxHQUFHLEtBQUssRUFBRSxDQUFDLENBQUM7UUFDbEUsSUFBSSxDQUFDLEtBQUssR0FBRyxjQUFjLENBQUMsd0JBQXdCLEVBQUUsQ0FBQztRQUV2RCxJQUFJLENBQUMsV0FBVyxHQUFHLEtBQUssQ0FBQyxXQUFXLENBQUM7UUFDckMsSUFBSSxDQUFDLHVCQUF1QixHQUFHLEtBQUssQ0FBQyx1QkFBdUIsQ0FBQztRQUU3RCxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsa0JBQWtCLENBQzFDLGNBQWMsQ0FBQyx3QkFBd0IsRUFBRSxDQUMxQyxDQUFDO1FBQ0YsSUFBSSxDQUFDLGtCQUFrQixHQUFHLElBQUksMkJBQWtCLENBQUMsWUFBWSxDQUFDLENBQUM7UUFDL0QsSUFBSSxDQUFDLDRCQUE0QixHQUFHLElBQUkscUNBQTRCLENBQ2xFLFlBQVksQ0FDYixDQUFDO1FBRUYsSUFBSSxDQUFDLFlBQVksR0FBRyxLQUFLLENBQUMsWUFBWSxDQUFDLEdBQUcsQ0FBQyxDQUFDLFdBQVcsRUFBRSxFQUFFO1lBQ3pELE1BQU0seUJBQXlCLEdBQXFDO2dC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Q0FBeUMsQ0FBQyxDQUFDO1NBQzVEO1FBQ0QsTUFBTSxtQkFBbUIsR0FBVSxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDO1FBQ3JELElBQ0UsQ0FBQyxtQkFBbUI7WUFDcEIsbUJBQW1CLENBQUMsTUFBTSxHQUFHLENBQUM7WUFDOUIsQ0FBQyxtQkFBbUIsQ0FBQyxtQkFBbUIsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUN2RDtZQUNBLE1BQU0sSUFBSSxLQUFLLENBQUMsZ0NBQWdDLENBQUMsQ0FBQztTQUNuRDtRQUNELHVDQUF1QztRQUN2QywwQkFBMEIsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFO1lBQzlCLG1CQUFtQixDQUFDLG1CQUFtQixDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFO2dCQUN0RCx5QkFBeUIsQ0FBQztRQUM1Qiw2REFBNkQ7UUFDN0QsbUJBQW1CLENBQUMsbUJBQW1CLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUM7UUFDbkUsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBEdXJhdGlvbiB9IGZyb20gXCJhd3MtY2RrLWxpYlwiO1xuaW1wb3J0IHtcbiAgRGltZW5zaW9uc01hcCxcbiAgR3JhcGhXaWRnZXQsXG4gIEdyYXBoV2lkZ2V0UHJvcHMsXG4gIEhvcml6b250YWxBbm5vdGF0aW9uLFxuICBJTWV0cmljLFxuICBJV2lkZ2V0LFxuICBMZWdlbmRQb3NpdGlvbixcbiAgUm93LFxuICBUZXh0V2lkZ2V0LFxuICBZQXhpc1Byb3BzLFxufSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWNsb3Vkd2F0Y2hcIjtcblxuaW1wb3J0IHtcbiAgQW5vbWFseURldGVjdGluZ0FsYXJtRmFjdG9yeSxcbiAgQW5vbWFseURldGVjdGlvblRocmVzaG9sZCxcbiAgQmFzZU1vbml0b3JpbmdQcm9wcyxcbiAgY3JlYXRlR3JhcGhXaWRnZXQsXG4gIEN1c3RvbUFsYXJtRmFjdG9yeSxcbiAgQ3VzdG9tVGhyZXNob2xkLFxuICBEZWZhdWx0R3JhcGhXaWRnZXRIZWlnaHQsXG4gIERlZmF1bHRTdW1tYXJ5V2lkZ2V0SGVpZ2h0LFxuICBGdWxsV2lkdGgsXG4gIGdldEhhc2hGb3JNZXRyaWNFeHByZXNzaW9uSWQsXG4gIEdyYXBoV2lkZ2V0VHlwZSxcbiAgTWV0cmljU3RhdGlzdGljLFxuICBNZXRyaWNXaXRoQWxhcm1TdXBwb3J0LFxuICBNb25pdG9yaW5nLFxuICBNb25pdG9yaW5nU2NvcGUsXG4gIHJlY29tbWVuZGVkV2lkZ2V0V2lkdGgsXG59IGZyb20gXCIuLi8uLi9jb21tb25cIjtcbmltcG9ydCB7XG4gIE1vbml0b3JpbmdIZWFkZXJXaWRnZXQsXG4gIE1vbml0b3JpbmdOYW1pbmdTdHJhdGVneSxcbn0gZnJvbSBcIi4uLy4uL2Rhc2hib2FyZFwiO1xuXG5leHBvcnQgZW51bSBBeGlzUG9zaXRpb24ge1xuICBMRUZUID0gXCJsZWZ0XCIsXG4gIFJJR0hUID0gXCJyaWdodFwiLFxufVxuXG4vKipcbiAqIEN1c3RvbSBtZXRyaWMgd2l0aCBhbiBhbGFybSBkZWZpbmVkLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEN1c3RvbU1ldHJpY1dpdGhBbGFybSB7XG4gIC8qKlxuICAgKiBtZXRyaWMgdG8gYWxhcm0gb25cbiAgICovXG4gIHJlYWRvbmx5IG1ldHJpYzogTWV0cmljV2l0aEFsYXJtU3VwcG9ydDtcbiAgLyoqXG4gICAqIGFsYXJtIGZyaWVuZGx5IG5hbWVcbiAgICovXG4gIHJlYWRvbmx5IGFsYXJtRnJpZW5kbHlOYW1lOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBhbGFybSBkZWZpbml0aW9uc1xuICAgKi9cbiAgcmVhZG9ubHkgYWRkQWxhcm06IFJlY29yZDxzdHJpbmcsIEN1c3RvbVRocmVzaG9sZD47XG4gIC8qKlxuICAgKiBheGlzIChyaWdodCBvciBsZWZ0KSBvbiB3aGljaCB0byBncmFwaCBtZXRyaWNcbiAgICogZGVmYXVsdDogQXhpc1Bvc2l0aW9uLkxFRlRcbiAgICovXG4gIHJlYWRvbmx5IHBvc2l0aW9uPzogQXhpc1Bvc2l0aW9uO1xufVxuXG4vKipcbiAqIEN1c3RvbSBtZXRyaWMgd2l0aCBhbm9tYWx5IGRldGVjdGlvbi5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDdXN0b21NZXRyaWNXaXRoQW5vbWFseURldGVjdGlvbiB7XG4gIC8qKlxuICAgKiBtZXRyaWMgdG8gYWxhcm0gb25cbiAgICovXG4gIHJlYWRvbmx5IG1ldHJpYzogTWV0cmljV2l0aEFsYXJtU3VwcG9ydDtcbiAgLyoqXG4gICAqIGFub21hbHkgZGV0ZWN0aW9uIHBlcmlvZFxuICAgKiBAZGVmYXVsdCAtIG1ldHJpYyBwZXJpb2QgKGlmIGRlZmluZWQpIG9yIGdsb2JhbCBkZWZhdWx0XG4gICAqL1xuICByZWFkb25seSBwZXJpb2Q/OiBEdXJhdGlvbjtcbiAgLyoqXG4gICAqIGFsYXJtIGZyaWVuZGx5IG5hbWVcbiAgICovXG4gIHJlYWRvbmx5IGFsYXJtRnJpZW5kbHlOYW1lOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBzdGFuZGFyZCBkZXZpYXRpb24gZm9yIHRoZSBhbm9tYWx5IGRldGVjdGlvbiB0byBiZSByZW5kZXJlZCBvbiB0aGUgZ3JhcGggd2lkZ2V0XG4gICAqL1xuICByZWFkb25seSBhbm9tYWx5RGV0ZWN0aW9uU3RhbmRhcmREZXZpYXRpb25Ub1JlbmRlcjogbnVtYmVyO1xuICAvKipcbiAgICogYWRkcyBhbGFybSBvbiBhIGRldGVjdGVkIGFub21hbHlcbiAgICovXG4gIHJlYWRvbmx5IGFkZEFsYXJtT25Bbm9tYWx5PzogUmVjb3JkPHN0cmluZywgQW5vbWFseURldGVjdGlvblRocmVzaG9sZD47XG59XG5cbi8qKlxuICogQ3VzdG9tIG1ldHJpYyBzZWFyY2guXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ3VzdG9tTWV0cmljU2VhcmNoIHtcbiAgLyoqXG4gICAqIG1ldHJpYyBuYW1lc3BhY2VcbiAgICogQGRlZmF1bHQgLSBub25lXG4gICAqL1xuICByZWFkb25seSBuYW1lc3BhY2U/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBzZWFyY2ggcXVlcnkgKGNhbiBiZSBlbXB0eSlcbiAgICovXG4gIHJlYWRvbmx5IHNlYXJjaFF1ZXJ5OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBjdXN0b20gbGFiZWwgZm9yIHRoZSBtZXRyaWNzXG4gICAqIEBkZWZhdWx0IC0gXCIgXCJcbiAgICovXG4gIHJlYWRvbmx5IGxhYmVsPzogc3RyaW5nO1xuICAvKipcbiAgICogc2VhcmNoIGRpbWVuc2lvbnMgKGNhbiBiZSBlbXB0eSlcbiAgICovXG4gIHJlYWRvbmx5IGRpbWVuc2lvbnNNYXA6IERpbWVuc2lvbnNNYXA7XG4gIC8qKlxuICAgKiBtZXRyaWMgc3RhdGlzdGljXG4gICAqL1xuICByZWFkb25seSBzdGF0aXN0aWM6IE1ldHJpY1N0YXRpc3RpYztcbiAgLyoqXG4gICAqIG1ldHJpYyBwZXJpb2RcbiAgICogQGRlZmF1bHQgLSBnbG9iYWwgZGVmYXVsdFxuICAgKi9cbiAgcmVhZG9ubHkgcGVyaW9kPzogRHVyYXRpb247XG4gIC8qKlxuICAgKiBheGlzIChyaWdodCBvciBsZWZ0KSBvbiB3aGljaCB0byBncmFwaCBtZXRyaWNcbiAgICogZGVmYXVsdDogQXhpc1Bvc2l0aW9uLkxFRlRcbiAgICovXG4gIHJlYWRvbmx5IHBvc2l0aW9uPzogQXhpc1Bvc2l0aW9uO1xufVxuXG4vKipcbiAqIEVhY2ggY3VzdG9tIG1ldHJpYyBjYW4gYmUgb2YgZm91ciB0eXBlczpcbiAqIEBzZWUgTWV0cmljV2l0aEFsYXJtU3VwcG9ydCBmb3IgYSBzdGFuZGFyZCBtZXRyaWNcbiAqIEBzZWUgQ3VzdG9tTWV0cmljU2VhcmNoIGZvciBhIHNlYXJjaFxuICogQHNlZSBDdXN0b21NZXRyaWNXaXRoQWxhcm0gZm9yIGEgbWV0cmljIHdpdGggYW4gYWxhcm1cbiAqIEBzZWUgQ3VzdG9tTWV0cmljV2l0aEFub21hbHlEZXRlY3Rpb24gZm9yIGEgbWV0cmljIHdpdGggYW4gYW5vbWFseSBkZXRlY3RpbmcgYWxhcm1cbiAqL1xuZXhwb3J0IHR5cGUgQ3VzdG9tTWV0cmljID1cbiAgfCBNZXRyaWNXaXRoQWxhcm1TdXBwb3J0XG4gIHwgQ3VzdG9tTWV0cmljU2VhcmNoXG4gIHwgQ3VzdG9tTWV0cmljV2l0aEFsYXJtXG4gIHwgQ3VzdG9tTWV0cmljV2l0aEFub21hbHlEZXRlY3Rpb247XG5cbi8qKlxuICogQ3VzdG9tIG1ldHJpYyBncm91cCByZXByZXNlbnRzIGEgc2luZ2xlIHdpZGdldC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDdXN0b21NZXRyaWNHcm91cCB7XG4gIC8qKlxuICAgKiB0aXRsZSBvZiB0aGUgd2hvbGUgZ3JvdXBcbiAgICovXG4gIHJlYWRvbmx5IHRpdGxlOiBzdHJpbmc7XG4gIC8qKlxuICAgKiB0eXBlIG9mIHRoZSB3aWRnZXRcbiAgICogQGRlZmF1bHQgbGluZVxuICAgKi9cbiAgcmVhZG9ubHkgZ3JhcGhXaWRnZXRUeXBlPzogR3JhcGhXaWRnZXRUeXBlO1xuICAvKipcbiAgICogb3B0aW9uYWwgYXhpc1xuICAgKiBAZGVmYXVsdCB1bmRlZmluZWRcbiAgICovXG4gIHJlYWRvbmx5IGdyYXBoV2lkZ2V0QXhpcz86IFlBeGlzUHJvcHM7XG4gIC8qKlxuICAgKiBvcHRpb25hbCByaWdodCBheGlzXG4gICAqIEBkZWZhdWx0IHVuZGVmaW5lZFxuICAgKi9cbiAgcmVhZG9ubHkgZ3JhcGhXaWRnZXRSaWdodEF4aXM/OiBZQXhpc1Byb3BzO1xuICAvKipcbiAgICogZ3JhcGggd2lkZ2V0IGxlZ2VuZFxuICAgKiBAZGVmYXVsdCBCT1RUT01cbiAgICovXG4gIHJlYWRvbmx5IGdyYXBoV2lkZ2V0TGVnZW5kPzogTGVnZW5kUG9zaXRpb247XG4gIC8qKlxuICAgKiBGbGFnIGluZGljYXRpbmcsIHdoZXRoZXIgdGhpcyBpcyBhbiBpbXBvcnRhbnQgbWV0cmljIGdyb3VwIHRoYXQgc2hvdWxkIGJlIGluY2x1ZGVkIGluIHRoZSBzdW1tYXJ5IGFzIHdlbGwuXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBpbXBvcnRhbnQ/OiBib29sZWFuO1xuICAvKipcbiAgICogbGlzdCBvZiBtZXRyaWNzIGluIHRoZSBncm91cCAoY2FuIGJlIGRlZmluZWQgaW4gZGlmZmVyZW50IHdheXMsIHNlZSB0aGUgdHlwZSBkb2N1bWVudGF0aW9uKVxuICAgKi9cbiAgcmVhZG9ubHkgbWV0cmljczogQ3VzdG9tTWV0cmljW107XG4gIC8qKlxuICAgKiBvcHRpb25hbCBjdXN0b20gaG9yaXpvbnRhbCBhbm5vdGF0aW9ucyB3aGljaCB3aWxsIGJlIGRpc3BsYXllZCBvdmVyIHRoZSBtZXRyaWNzIG9uIHRoZSBsZWZ0IGF4aXNcbiAgICogKGlmIHRoZXJlIGFyZSBhbnkgYWxhcm1zLCBhbnkgZXhpc3RpbmcgYW5ub3RhdGlvbnMgd2lsbCBiZSBtZXJnZWQgdG9nZXRoZXIpXG4gICAqL1xuICByZWFkb25seSBob3Jpem9udGFsQW5ub3RhdGlvbnM/OiBIb3Jpem9udGFsQW5ub3RhdGlvbltdO1xuICAvKipcbiAgICogb3B0aW9uYWwgY3VzdG9tIGhvcml6b250YWwgYW5ub3RhdGlvbnMgd2hpY2ggd2lsbCBiZSBkaXNwbGF5ZWQgb3ZlciB0aGUgbWV0cmljcyBvbiB0aGUgcmlnaHQgYXhpc1xuICAgKiAoaWYgdGhlcmUgYXJlIGFueSBhbGFybXMsIGFueSBleGlzdGluZyBhbm5vdGF0aW9ucyB3aWxsIGJlIG1lcmdlZCB0b2dldGhlcilcbiAgICovXG4gIHJlYWRvbmx5IGhvcml6b250YWxSaWdodEFubm90YXRpb25zPzogSG9yaXpvbnRhbEFubm90YXRpb25bXTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBDdXN0b21Nb25pdG9yaW5nUHJvcHMgZXh0ZW5kcyBCYXNlTW9uaXRvcmluZ1Byb3BzIHtcbiAgcmVhZG9ubHkgZGVzY3JpcHRpb24/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGRlc2NyaXB0aW9uV2lkZ2V0SGVpZ2h0PzogbnVtYmVyO1xuICByZWFkb25seSBtZXRyaWNHcm91cHM6IEN1c3RvbU1ldHJpY0dyb3VwW107XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ3VzdG9tTWV0cmljR3JvdXBXaXRoQW5ub3RhdGlvbnMge1xuICByZWFkb25seSBtZXRyaWNHcm91cDogQ3VzdG9tTWV0cmljR3JvdXA7XG4gIHJlYWRvbmx5IGFubm90YXRpb25zOiBIb3Jpem9udGFsQW5ub3RhdGlvbltdO1xuICByZWFkb25seSByaWdodEFubm90YXRpb25zOiBIb3Jpem9udGFsQW5ub3RhdGlvbltdO1xuICByZWFkb25seSB0aXRsZUFkZG9uczogc3RyaW5nW107XG59XG5cbi8qKlxuICogQ3VzdG9tIG1vbml0b3JpbmcgaXMgYSBjb25zdHJ1Y3QgYWxsb3dpbmcgeW91IHRvIG1vbml0b3IgeW91ciBvd24gY3VzdG9tIG1ldHJpY3MuXG4gKiBUaGUgZW50aXJlIGNvbnN0cnVjdCBjb25zaXN0cyBvZiBtZXRyaWMgZ3JvdXBzLlxuICogRWFjaCBtZXRyaWMgZ3JvdXAgcmVwcmVzZW50cyBhIHNpbmdsZSBncmFwaCB3aWRnZXQgd2l0aCBtdWx0aXBsZSBtZXRyaWNzLlxuICogRWFjaCBtZXRyaWMgaW5zaWRlIHRoZSBtZXRyaWMgZ3JvdXAgcmVwcmVzZW50cyBhIHNpbmdsZSBtZXRyaWMgaW5zaWRlIGEgZ3JhcGguXG4gKiBUaGUgd2lkZ2V0cyB3aWxsIGJlIHNpemVkIGF1dG9tYXRpY2FsbHkgdG8gd2FzdGUgYXMgbGl0dGxlIHNwYWNlIGFzIHBvc3NpYmxlLlxuICovXG5leHBvcnQgY2xhc3MgQ3VzdG9tTW9uaXRvcmluZyBleHRlbmRzIE1vbml0b3Jpbmcge1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgdGl0bGU6IHN0cmluZztcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGRlc2NyaXB0aW9uPzogc3RyaW5nO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgZGVzY3JpcHRpb25XaWRnZXRIZWlnaHQ/OiBudW1iZXI7XG4gIHByb3RlY3RlZCByZWFkb25seSBjdXN0b21BbGFybUZhY3Rvcnk6IEN1c3RvbUFsYXJtRmFjdG9yeTtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGFub21hbHlEZXRlY3RpbmdBbGFybUZhY3Rvcnk6IEFub21hbHlEZXRlY3RpbmdBbGFybUZhY3Rvcnk7XG4gIHByb3RlY3RlZCByZWFkb25seSBtZXRyaWNHcm91cHM6IEN1c3RvbU1ldHJpY0dyb3VwV2l0aEFubm90YXRpb25zW107XG5cbiAgY29uc3RydWN0b3Ioc2NvcGU6IE1vbml0b3JpbmdTY29wZSwgcHJvcHM6IEN1c3RvbU1vbml0b3JpbmdQcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBwcm9wcyk7XG5cbiAgICBjb25zdCBuYW1pbmdTdHJhdGVneSA9IG5ldyBNb25pdG9yaW5nTmFtaW5nU3RyYXRlZ3koeyAuLi5wcm9wcyB9KTtcbiAgICB0aGlzLnRpdGxlID0gbmFtaW5nU3RyYXRlZ3kucmVzb2x2ZUh1bWFuUmVhZGFibGVOYW1lKCk7XG5cbiAgICB0aGlzLmRlc2NyaXB0aW9uID0gcHJvcHMuZGVzY3JpcHRpb247XG4gICAgdGhpcy5kZXNjcmlwdGlvbldpZGdldEhlaWdodCA9IHByb3BzLmRlc2NyaXB0aW9uV2lkZ2V0SGVpZ2h0O1xuXG4gICAgY29uc3QgYWxhcm1GYWN0b3J5ID0gdGhpcy5jcmVhdGVBbGFybUZhY3RvcnkoXG4gICAgICBuYW1pbmdTdHJhdGVneS5yZXNvbHZlQWxhcm1GcmllbmRseU5hbWUoKVxuICAgICk7XG4gICAgdGhpcy5jdXN0b21BbGFybUZhY3RvcnkgPSBuZXcgQ3VzdG9tQWxhcm1GYWN0b3J5KGFsYXJtRmFjdG9yeSk7XG4gICAgdGhpcy5hbm9tYWx5RGV0ZWN0aW5nQWxhcm1GYWN0b3J5ID0gbmV3IEFub21hbHlEZXRlY3RpbmdBbGFybUZhY3RvcnkoXG4gICAgICBhbGFybUZhY3RvcnlcbiAgICApO1xuXG4gICAgdGhpcy5tZXRyaWNHcm91cHMgPSBwcm9wcy5tZXRyaWNHcm91cHMubWFwKChtZXRyaWNHcm91cCkgPT4ge1xuICAgICAgY29uc3QgbWV0cmljR3JvdXBXaXRoQW5ub3RhdGlvbjogQ3VzdG9tTWV0cmljR3JvdXBXaXRoQW5ub3RhdGlvbnMgPSB7XG4gICAgICAgIG1ldHJpY0dyb3VwLFxuICAgICAgICBhbm5vdGF0aW9uczogW10sXG4gICAgICAgIHJpZ2h0QW5ub3RhdGlvbnM6IFtdLFxuICAgICAgICB0aXRsZUFkZG9uczogW10sXG4gICAgICB9O1xuXG4gICAgICBpZiAobWV0cmljR3JvdXAuaG9yaXpvbnRhbEFubm90YXRpb25zKSB7XG4gICAgICAgIG1ldHJpY0dyb3VwV2l0aEFubm90YXRpb24uYW5ub3RhdGlvbnMucHVzaChcbiAgICAgICAgICAuLi5tZXRyaWNHcm91cC5ob3Jpem9udGFsQW5ub3RhdGlvbnNcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIGlmIChtZXRyaWNHcm91cC5ob3Jpem9udGFsUmlnaHRBbm5vdGF0aW9ucykge1xuICAgICAgICBtZXRyaWNHcm91cFdpdGhBbm5vdGF0aW9uLnJpZ2h0QW5ub3RhdGlvbnMucHVzaChcbiAgICAgICAgICAuLi5tZXRyaWNHcm91cC5ob3Jpem9udGFsUmlnaHRBbm5vdGF0aW9uc1xuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICBtZXRyaWNHcm91cC5tZXRyaWNzLmZvckVhY2goKG1ldHJpYykgPT4ge1xuICAgICAgICBpZiAodGhpcy5oYXNBbGFybShtZXRyaWMpICYmIHRoaXMuaGFzQW5vbWFseURldGVjdGlvbihtZXRyaWMpKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgXCJBZGRpbmcgYm90aCBhIHJlZ3VsYXIgYWxhcm0gYW5kIGFuIGFub21vbHkgZGV0ZWN0aW9uIGFsYXJtIGF0IHRoZSBzYW1lIHRpbWUgaXMgbm90IHN1cHBvcnRlZFwiXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0aGlzLmhhc0FsYXJtKG1ldHJpYykpIHtcbiAgICAgICAgICB0aGlzLnNldHVwQWxhcm0obWV0cmljR3JvdXBXaXRoQW5ub3RhdGlvbiwgbWV0cmljKTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLmhhc0Fub21hbHlEZXRlY3Rpb24obWV0cmljKSkge1xuICAgICAgICAgIHRoaXMuc2V0dXBBbm9tYWx5RGV0ZWN0aW9uQWxhcm0obWV0cmljR3JvdXBXaXRoQW5ub3RhdGlvbiwgbWV0cmljKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG5cbiAgICAgIHJldHVybiBtZXRyaWNHcm91cFdpdGhBbm5vdGF0aW9uO1xuICAgIH0pO1xuXG4gICAgcHJvcHMudXNlQ3JlYXRlZEFsYXJtcz8uY29uc3VtZSh0aGlzLmNyZWF0ZWRBbGFybXMoKSk7XG4gIH1cblxuICBzdW1tYXJ5V2lkZ2V0cygpOiBJV2lkZ2V0W10ge1xuICAgIHJldHVybiB0aGlzLmdldEFsbFdpZGdldHModHJ1ZSk7XG4gIH1cblxuICB3aWRnZXRzKCk6IElXaWRnZXRbXSB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0QWxsV2lkZ2V0cyhmYWxzZSk7XG4gIH1cblxuICBwcml2YXRlIGdldEFsbFdpZGdldHMoc3VtbWFyeTogYm9vbGVhbik6IElXaWRnZXRbXSB7XG4gICAgY29uc3QgZmlsdGVyZWRNZXRyaWNHcm91cHMgPSBzdW1tYXJ5XG4gICAgICA/IHRoaXMubWV0cmljR3JvdXBzLmZpbHRlcihcbiAgICAgICAgICAoZ3JvdXApID0+IGdyb3VwLm1ldHJpY0dyb3VwLmltcG9ydGFudCA/PyBmYWxzZVxuICAgICAgICApXG4gICAgICA6IHRoaXMubWV0cmljR3JvdXBzO1xuXG4gICAgaWYgKGZpbHRlcmVkTWV0cmljR3JvdXBzLmxlbmd0aCA8IDEpIHtcbiAgICAgIC8vIHNob3J0LWNpcmN1aXQgaWYgdGhlcmUgYXJlIG5vIG1ldHJpY3Mgc3BlY2lmaWVkXG4gICAgICByZXR1cm4gW107XG4gICAgfVxuXG4gICAgY29uc3Qgcm93czogUm93W10gPSBbXTtcblxuICAgIC8vIGhlYWRlciBhbmQgZGVzY3JpcHRpb25cbiAgICByb3dzLnB1c2gobmV3IFJvdyhuZXcgTW9uaXRvcmluZ0hlYWRlcldpZGdldCh7IHRpdGxlOiB0aGlzLnRpdGxlIH0pKSk7XG4gICAgaWYgKHRoaXMuZGVzY3JpcHRpb24gJiYgIXN1bW1hcnkpIHtcbiAgICAgIHJvd3MucHVzaChcbiAgICAgICAgbmV3IFJvdyhcbiAgICAgICAgICB0aGlzLmNyZWF0ZURlc2NyaXB0aW9uV2lkZ2V0KFxuICAgICAgICAgICAgdGhpcy5kZXNjcmlwdGlvbixcbiAgICAgICAgICAgIHRoaXMuZGVzY3JpcHRpb25XaWRnZXRIZWlnaHRcbiAgICAgICAgICApXG4gICAgICAgIClcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gZ3JhcGhzXG4gICAgcm93cy5wdXNoKFxuICAgICAgbmV3IFJvdyhcbiAgICAgICAgLi4udGhpcy5jcmVhdGVDdXN0b21NZXRyaWNHcm91cFdpZGdldHMoZmlsdGVyZWRNZXRyaWNHcm91cHMsIHN1bW1hcnkpXG4gICAgICApXG4gICAgKTtcblxuICAgIHJldHVybiByb3dzO1xuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVEZXNjcmlwdGlvbldpZGdldChcbiAgICBtYXJrZG93bjogc3RyaW5nLFxuICAgIGRlc2NyaXB0aW9uV2lkZ2V0SGVpZ2h0PzogbnVtYmVyXG4gICkge1xuICAgIHJldHVybiBuZXcgVGV4dFdpZGdldCh7XG4gICAgICBtYXJrZG93bixcbiAgICAgIHdpZHRoOiBGdWxsV2lkdGgsXG4gICAgICBoZWlnaHQ6IGRlc2NyaXB0aW9uV2lkZ2V0SGVpZ2h0ID8/IDEsXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGNyZWF0ZUN1c3RvbU1ldHJpY0dyb3VwV2lkZ2V0cyhcbiAgICBhbm5vdGF0ZWRHcm91cHM6IEN1c3RvbU1ldHJpY0dyb3VwV2l0aEFubm90YXRpb25zW10sXG4gICAgc3VtbWFyeTogYm9vbGVhblxuICApIHtcbiAgICBjb25zdCB3aWRnZXRzOiBJV2lkZ2V0W10gPSBbXTtcbiAgICBjb25zdCBtZXRyaWNHcm91cFdpZGdldFdpZHRoID0gcmVjb21tZW5kZWRXaWRnZXRXaWR0aChcbiAgICAgIGFubm90YXRlZEdyb3Vwcy5sZW5ndGhcbiAgICApO1xuXG4gICAgYW5ub3RhdGVkR3JvdXBzLmZvckVhY2goKGFubm90YXRlZEdyb3VwKSA9PiB7XG4gICAgICBjb25zdCBtZXRyaWNzID0gYW5ub3RhdGVkR3JvdXAubWV0cmljR3JvdXAubWV0cmljcztcbiAgICAgIGNvbnN0IGxlZnQgPSB0aGlzLnRvTWV0cmljcyhcbiAgICAgICAgbWV0cmljcy5maWx0ZXIoXG4gICAgICAgICAgKG1ldHJpYykgPT5cbiAgICAgICAgICAgICgobWV0cmljIGFzIGFueSkucG9zaXRpb24gPz8gQXhpc1Bvc2l0aW9uLkxFRlQpID09IEF4aXNQb3NpdGlvbi5MRUZUXG4gICAgICAgIClcbiAgICAgICk7XG4gICAgICBjb25zdCByaWdodCA9IHRoaXMudG9NZXRyaWNzKFxuICAgICAgICBtZXRyaWNzLmZpbHRlcihcbiAgICAgICAgICAobWV0cmljKSA9PlxuICAgICAgICAgICAgKChtZXRyaWMgYXMgYW55KS5wb3NpdGlvbiA/PyBBeGlzUG9zaXRpb24uTEVGVCkgPT1cbiAgICAgICAgICAgIEF4aXNQb3NpdGlvbi5SSUdIVFxuICAgICAgICApXG4gICAgICApO1xuICAgICAgY29uc3QgaGFzT25lTWV0cmljT25seSA9IG1ldHJpY3MubGVuZ3RoID09PSAxO1xuICAgICAgY29uc3QgaGFzQW5vbWFseURldGVjdGlvbiA9XG4gICAgICAgIG1ldHJpY3MuZmlsdGVyKChtZXRyaWMpID0+IHRoaXMuaGFzQW5vbWFseURldGVjdGlvbihtZXRyaWMpKS5sZW5ndGggPiAwO1xuICAgICAgY29uc3QgdXNlQW5vbWFseURldGVjdGlvbldpZGdldCA9IGhhc09uZU1ldHJpY09ubHkgJiYgaGFzQW5vbWFseURldGVjdGlvbjtcbiAgICAgIGxldCB0aXRsZSA9IGFubm90YXRlZEdyb3VwLm1ldHJpY0dyb3VwLnRpdGxlO1xuXG4gICAgICBpZiAoYW5ub3RhdGVkR3JvdXAudGl0bGVBZGRvbnMubGVuZ3RoID4gMCkge1xuICAgICAgICB0aXRsZSA9IGAke3RpdGxlfSAoJHthbm5vdGF0ZWRHcm91cC50aXRsZUFkZG9ucy5qb2luKFwiLCBcIil9KWA7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGdyYXBoV2lkZ2V0UHJvcHM6IEdyYXBoV2lkZ2V0UHJvcHMgPSB7XG4gICAgICAgIHRpdGxlLFxuICAgICAgICB3aWR0aDogbWV0cmljR3JvdXBXaWRnZXRXaWR0aCxcbiAgICAgICAgaGVpZ2h0OiBzdW1tYXJ5ID8gRGVmYXVsdFN1bW1hcnlXaWRnZXRIZWlnaHQgOiBEZWZhdWx0R3JhcGhXaWRnZXRIZWlnaHQsXG4gICAgICAgIGxlZnQsXG4gICAgICAgIHJpZ2h0LFxuICAgICAgICBsZWZ0QW5ub3RhdGlvbnM6IGFubm90YXRlZEdyb3VwLmFubm90YXRpb25zLFxuICAgICAgICByaWdodEFubm90YXRpb25zOiBhbm5vdGF0ZWRHcm91cC5yaWdodEFubm90YXRpb25zLFxuICAgICAgICBsZWZ0WUF4aXM6IGFubm90YXRlZEdyb3VwLm1ldHJpY0dyb3VwLmdyYXBoV2lkZ2V0QXhpcyxcbiAgICAgICAgcmlnaHRZQXhpczogYW5ub3RhdGVkR3JvdXAubWV0cmljR3JvdXAuZ3JhcGhXaWRnZXRSaWdodEF4aXMsXG4gICAgICAgIGxlZ2VuZFBvc2l0aW9uOiBhbm5vdGF0ZWRHcm91cC5tZXRyaWNHcm91cC5ncmFwaFdpZGdldExlZ2VuZCxcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IHdpZGdldCA9IHVzZUFub21hbHlEZXRlY3Rpb25XaWRnZXRcbiAgICAgICAgPyBuZXcgQW5vbWFseURldGVjdGlvbkdyYXBoV2lkZ2V0KGdyYXBoV2lkZ2V0UHJvcHMpXG4gICAgICAgIDogY3JlYXRlR3JhcGhXaWRnZXQoXG4gICAgICAgICAgICBhbm5vdGF0ZWRHcm91cC5tZXRyaWNHcm91cC5ncmFwaFdpZGdldFR5cGUgPz8gR3JhcGhXaWRnZXRUeXBlLkxJTkUsXG4gICAgICAgICAgICBncmFwaFdpZGdldFByb3BzXG4gICAgICAgICAgKTtcblxuICAgICAgd2lkZ2V0cy5wdXNoKHdpZGdldCk7XG4gICAgfSk7XG5cbiAgICByZXR1cm4gd2lkZ2V0cztcbiAgfVxuXG4gIHByaXZhdGUgdG9NZXRyaWNzKG1ldHJpY3M6IEN1c3RvbU1ldHJpY1tdKTogSU1ldHJpY1tdIHtcbiAgICBjb25zdCBtZXRyaWNGYWN0b3J5ID0gdGhpcy5jcmVhdGVNZXRyaWNGYWN0b3J5KCk7XG5cbiAgICByZXR1cm4gbWV0cmljcy5tYXAoKG1ldHJpYykgPT4ge1xuICAgICAgaWYgKHRoaXMuaGFzQWxhcm0obWV0cmljKSkge1xuICAgICAgICAvLyBtZXRyaWMgd2l0aCBhbGFybVxuICAgICAgICByZXR1cm4gbWV0cmljRmFjdG9yeS5hZGFwdE1ldHJpY1ByZXNlcnZpbmdQZXJpb2QobWV0cmljLm1ldHJpYyk7XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuaGFzQW5vbWFseURldGVjdGlvbihtZXRyaWMpKSB7XG4gICAgICAgIC8vIG1ldHJpYyB3aXRoIGFub21hbHkgZGV0ZWN0aW9uXG4gICAgICAgIHJldHVybiBtZXRyaWNGYWN0b3J5LmNyZWF0ZU1ldHJpY0Fub21hbHlEZXRlY3Rpb24oXG4gICAgICAgICAgbWV0cmljLm1ldHJpYyxcbiAgICAgICAgICBtZXRyaWMuYW5vbWFseURldGVjdGlvblN0YW5kYXJkRGV2aWF0aW9uVG9SZW5kZXIsXG4gICAgICAgICAgYEV4cGVjdGVkIChzdGRldiA9ICR7bWV0cmljLmFub21hbHlEZXRlY3Rpb25TdGFuZGFyZERldmlhdGlvblRvUmVuZGVyfSlgLFxuICAgICAgICAgIHVuZGVmaW5lZCxcbiAgICAgICAgICAvLyBuZWVkcyB0byBiZSB1bmlxdWUgaW4gdGhlIHdob2xlIHdpZGdldCBhbmQgc3RhcnQgd2l0aCBsb3dlcmNhc2VcbiAgICAgICAgICBBbm9tYWx5RGV0ZWN0aW9uTWV0cmljSWRQcmVmaXggK1xuICAgICAgICAgICAgZ2V0SGFzaEZvck1ldHJpY0V4cHJlc3Npb25JZChtZXRyaWMuYWxhcm1GcmllbmRseU5hbWUpLFxuICAgICAgICAgIC8vIHByZXNlcnZlIHRoZSBtb3N0IHNwZWNpZmljIG1ldHJpYyBwZXJpb2RcbiAgICAgICAgICBtZXRyaWMucGVyaW9kID8/IG1ldHJpYy5tZXRyaWMucGVyaW9kXG4gICAgICAgICk7XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuaXNTZWFyY2gobWV0cmljKSkge1xuICAgICAgICAvLyBtZXRyaWMgc2VhcmNoXG4gICAgICAgIHJldHVybiBtZXRyaWNGYWN0b3J5LmNyZWF0ZU1ldHJpY1NlYXJjaChcbiAgICAgICAgICBtZXRyaWMuc2VhcmNoUXVlcnksXG4gICAgICAgICAgbWV0cmljLmRpbWVuc2lvbnNNYXAsXG4gICAgICAgICAgbWV0cmljLnN0YXRpc3RpYyxcbiAgICAgICAgICBtZXRyaWMubmFtZXNwYWNlLFxuICAgICAgICAgIG1ldHJpYy5sYWJlbCxcbiAgICAgICAgICBtZXRyaWMucGVyaW9kXG4gICAgICAgICk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBnZW5lcmFsIG1ldHJpY1xuICAgICAgICByZXR1cm4gbWV0cmljRmFjdG9yeS5hZGFwdE1ldHJpY1ByZXNlcnZpbmdQZXJpb2QobWV0cmljKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgaGFzQWxhcm0obWV0cmljOiBDdXN0b21NZXRyaWMpOiBtZXRyaWMgaXMgQ3VzdG9tTWV0cmljV2l0aEFsYXJtIHtcbiAgICAvLyB0eXBlIGd1YXJkXG4gICAgcmV0dXJuIChtZXRyaWMgYXMgQ3VzdG9tTWV0cmljV2l0aEFsYXJtKS5hZGRBbGFybSAhPT0gdW5kZWZpbmVkO1xuICB9XG5cbiAgcHJpdmF0ZSBoYXNBbm9tYWx5RGV0ZWN0aW9uKFxuICAgIG1ldHJpYzogQ3VzdG9tTWV0cmljXG4gICk6IG1ldHJpYyBpcyBDdXN0b21NZXRyaWNXaXRoQW5vbWFseURldGVjdGlvbiB7XG4gICAgLy8gdHlwZSBndWFyZFxuICAgIHJldHVybiAoXG4gICAgICAobWV0cmljIGFzIEN1c3RvbU1ldHJpY1dpdGhBbm9tYWx5RGV0ZWN0aW9uKVxuICAgICAgICAuYW5vbWFseURldGVjdGlvblN0YW5kYXJkRGV2aWF0aW9uVG9SZW5kZXIgIT09IHVuZGVmaW5lZFxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIGlzU2VhcmNoKG1ldHJpYzogQ3VzdG9tTWV0cmljKTogbWV0cmljIGlzIEN1c3RvbU1ldHJpY1NlYXJjaCB7XG4gICAgLy8gdHlwZSBndWFyZFxuICAgIHJldHVybiAobWV0cmljIGFzIEN1c3RvbU1ldHJpY1NlYXJjaCkuc2VhcmNoUXVlcnkgIT09IHVuZGVmaW5lZDtcbiAgfVxuXG4gIHByaXZhdGUgc2V0dXBBbGFybShcbiAgICBtZXRyaWNHcm91cDogQ3VzdG9tTWV0cmljR3JvdXBXaXRoQW5ub3RhdGlvbnMsXG4gICAgbWV0cmljOiBDdXN0b21NZXRyaWNXaXRoQWxhcm1cbiAgKSB7XG4gICAgaWYgKHRoaXMuaXNTZWFyY2gobWV0cmljKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBcIkFsYXJtaW5nIG9uIHNlYXJjaCBxdWVyaWVzIGlzIG5vdCBzdXBwb3J0ZWQgYnkgQ2xvdWRXYXRjaFwiXG4gICAgICApO1xuICAgIH1cblxuICAgIGZvciAoY29uc3QgZGlzYW1iaWd1YXRvciBpbiBtZXRyaWMuYWRkQWxhcm0pIHtcbiAgICAgIGNvbnN0IGFsYXJtUHJvcHMgPSBtZXRyaWMuYWRkQWxhcm1bZGlzYW1iaWd1YXRvcl07XG4gICAgICBjb25zdCBjcmVhdGVkQWxhcm0gPSB0aGlzLmN1c3RvbUFsYXJtRmFjdG9yeS5hZGRDdXN0b21BbGFybShcbiAgICAgICAgbWV0cmljLm1ldHJpYyxcbiAgICAgICAgbWV0cmljLmFsYXJtRnJpZW5kbHlOYW1lLFxuICAgICAgICBkaXNhbWJpZ3VhdG9yLFxuICAgICAgICBhbGFybVByb3BzXG4gICAgICApO1xuICAgICAgY29uc3QgdGFyZ2V0QW5ub3RhdGlvbnMgPVxuICAgICAgICAobWV0cmljLnBvc2l0aW9uID8/IEF4aXNQb3NpdGlvbi5MRUZUKSA9PSBBeGlzUG9zaXRpb24uTEVGVFxuICAgICAgICAgID8gbWV0cmljR3JvdXAuYW5ub3RhdGlvbnNcbiAgICAgICAgICA6IG1ldHJpY0dyb3VwLnJpZ2h0QW5ub3RhdGlvbnM7XG4gICAgICB0YXJnZXRBbm5vdGF0aW9ucy5wdXNoKGNyZWF0ZWRBbGFybS5hbm5vdGF0aW9uKTtcbiAgICAgIHRoaXMuYWRkQWxhcm0oY3JlYXRlZEFsYXJtKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHNldHVwQW5vbWFseURldGVjdGlvbkFsYXJtKFxuICAgIG1ldHJpY0dyb3VwOiBDdXN0b21NZXRyaWNHcm91cFdpdGhBbm5vdGF0aW9ucyxcbiAgICBtZXRyaWM6IEN1c3RvbU1ldHJpY1dpdGhBbm9tYWx5RGV0ZWN0aW9uXG4gICkge1xuICAgIGlmICh0aGlzLmlzU2VhcmNoKG1ldHJpYykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgXCJBbGFybWluZyBvbiBzZWFyY2ggcXVlcmllcyBpcyBub3Qgc3VwcG9ydGVkIGJ5IENsb3VkV2F0Y2hcIlxuICAgICAgKTtcbiAgICB9XG5cbiAgICBjb25zdCBhbGFybVN0RGV2cyA9IG5ldyBTZXQ8bnVtYmVyPigpO1xuICAgIGNvbnN0IG1ldHJpY0ZhY3RvcnkgPSB0aGlzLmNyZWF0ZU1ldHJpY0ZhY3RvcnkoKTtcblxuICAgIGZvciAoY29uc3QgZGlzYW1iaWd1YXRvciBpbiBtZXRyaWMuYWRkQWxhcm1PbkFub21hbHkpIHtcbiAgICAgIGNvbnN0IGFsYXJtUHJvcHMgPSBtZXRyaWMuYWRkQWxhcm1PbkFub21hbHlbZGlzYW1iaWd1YXRvcl07XG4gICAgICBpZiAoXG4gICAgICAgIGFsYXJtUHJvcHMuYWxhcm1XaGVuQWJvdmVUaGVCYW5kIHx8XG4gICAgICAgIGFsYXJtUHJvcHMuYWxhcm1XaGVuQmVsb3dUaGVCYW5kXG4gICAgICApIHtcbiAgICAgICAgY29uc3QgYW5vbWFseU1ldHJpYyA9IG1ldHJpY0ZhY3RvcnkuY3JlYXRlTWV0cmljQW5vbWFseURldGVjdGlvbihcbiAgICAgICAgICAvLyBCZWNhdXNlIHRoZSBtZXRyaWMgd2FzIHByb3ZpZGVkIHRvIHVzLCB3ZSB1c2UgbWV0cmljRmFjdG9yeS5vdmVycmlkZU5hbWVzcGFjZSgpIHRvXG4gICAgICAgICAgLy8gY29uZmlybSBpdCBhbGlnbnMgd2l0aCBhbnkgbmFtZXNwYWNlIG92ZXJyaWRlcyByZXF1ZXN0ZWQgZm9yIHRoaXMgTW9uaXRvcmluZ0ZhY2FkZVxuICAgICAgICAgIG1ldHJpY0ZhY3RvcnkuYWRhcHRNZXRyaWNQcmVzZXJ2aW5nUGVyaW9kKG1ldHJpYy5tZXRyaWMpLFxuICAgICAgICAgIGFsYXJtUHJvcHMuc3RhbmRhcmREZXZpYXRpb25Gb3JBbGFybSxcbiAgICAgICAgICBgQmFuZCAoc3RkZXYgJHthbGFybVByb3BzLnN0YW5kYXJkRGV2aWF0aW9uRm9yQWxhcm19KWAsXG4gICAgICAgICAgdW5kZWZpbmVkLFxuICAgICAgICAgIC8vIGV4cHJlc3Npb24gSUQgbmVlZHMgdG8gYmUgdW5pcXVlIGFjcm9zcyB0aGUgd2hvbGUgd2lkZ2V0OyBuZWVkcyB0byBzdGFydCB3aXRoIGEgbG93ZXJjYXNlIGxldHRlclxuICAgICAgICAgIEFub21hbHlEZXRlY3Rpb25BbGFybUlkUHJlZml4ICtcbiAgICAgICAgICAgIGdldEhhc2hGb3JNZXRyaWNFeHByZXNzaW9uSWQoXG4gICAgICAgICAgICAgIG1ldHJpYy5hbGFybUZyaWVuZGx5TmFtZSArIFwiX1wiICsgZGlzYW1iaWd1YXRvclxuICAgICAgICAgICAgKSxcbiAgICAgICAgICAvLyBwcmVzZXJ2ZSB0aGUgbW9zdC1zcGVjaWZpYyBtZXRyaWMgcGVyaW9kXG4gICAgICAgICAgbWV0cmljLnBlcmlvZCA/PyBtZXRyaWMubWV0cmljLnBlcmlvZFxuICAgICAgICApO1xuXG4gICAgICAgIGNvbnN0IGNyZWF0ZWRBbGFybSA9XG4gICAgICAgICAgdGhpcy5hbm9tYWx5RGV0ZWN0aW5nQWxhcm1GYWN0b3J5LmFkZEFsYXJtV2hlbk91dE9mQmFuZChcbiAgICAgICAgICAgIGFub21hbHlNZXRyaWMsXG4gICAgICAgICAgICBtZXRyaWMuYWxhcm1GcmllbmRseU5hbWUsXG4gICAgICAgICAgICBkaXNhbWJpZ3VhdG9yLFxuICAgICAgICAgICAgYWxhcm1Qcm9wc1xuICAgICAgICAgICk7XG5cbiAgICAgICAgLy8gbm8gbmVlZCB0byBhZGQgYW5ub3RhdGlvbiBzaW5jZSB0aGUgYmFuZHMgYXJlIHJlbmRlcmVkIGF1dG9tYXRpY2FsbHlcbiAgICAgICAgdGhpcy5hZGRBbGFybShjcmVhdGVkQWxhcm0pO1xuICAgICAgICBhbGFybVN0RGV2cy5hZGQoYWxhcm1Qcm9wcy5zdGFuZGFyZERldmlhdGlvbkZvckFsYXJtKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoYWxhcm1TdERldnMuc2l6ZSA+IDApIHtcbiAgICAgIGNvbnN0IGFsYXJtU3REZXZzU3RyaW5nID0gQXJyYXkuZnJvbShhbGFybVN0RGV2cykuc29ydCgpLmpvaW4oXCIsIFwiKTtcbiAgICAgIG1ldHJpY0dyb3VwLnRpdGxlQWRkb25zLnB1c2goYGFsYXJtcyB3aXRoIHN0ZGV2ICR7YWxhcm1TdERldnNTdHJpbmd9YCk7XG4gICAgfVxuICB9XG59XG5cbmNvbnN0IEFub21hbHlEZXRlY3Rpb25BbGFybUlkUHJlZml4ID0gXCJhbGFybV9cIjtcbmNvbnN0IEFub21hbHlEZXRlY3Rpb25NZXRyaWNJZFByZWZpeCA9IFwiYW5vbWFseV9cIjtcbmNvbnN0IEFub21hbHlCYW5kTWV0cmljSWRTdWZmaXggPSBcIl9iYW5kXCI7XG5cbi8qKlxuICogSU5URVJOQUwgLSBQTEVBU0UgRE8gTk9UIFVTRVxuICogVGhpcyBpcyBhIGhhY2t5IHNvbHV0aW9uIHRvIG1ha2UgYmFuZCB2aXNpYmxlIGluIEdyYXBoV2lkZ2V0IChkZWZhdWx0IHdpZGdldCBvbmx5IHJlbmRlcnMgbGluZXMsIG5vdCB0aGUgYmFuZCkuXG4gKiBUaGUgY2xhc3MgbWFrZXMgYXNzdW1wdGlvbnMgYWJvdXQgdGhlIGludGVybmFsIEpTT04gc3RydWN0dXJlIGJ1dCBmb3VuZCBubyBvdGhlciB3YXkgOiguXG4gKiBJZGVhbGx5LCB3ZSB3YW50IHRvIHJlbW92ZSB0aGlzIGhhY2sgb25jZSB0aGUgYW5vbWFseSBkZXRlY3Rpb24gcmVuZGVyaW5nIGluIENESyBnZXRzIGltcHJvdmVkXG4gKi9cbmNsYXNzIEFub21hbHlEZXRlY3Rpb25HcmFwaFdpZGdldCBleHRlbmRzIEdyYXBoV2lkZ2V0IHtcbiAgY29uc3RydWN0b3IocHJvcHM6IEdyYXBoV2lkZ2V0UHJvcHMpIHtcbiAgICBzdXBlcihwcm9wcyk7XG4gIH1cblxuICB0b0pzb24oKSB7XG4gICAgY29uc3QganNvbiA9IHN1cGVyLnRvSnNvbigpO1xuICAgIGlmIChqc29uLmxlbmd0aCAhPT0gMSB8fCAhanNvbj8uWzBdPy5wcm9wZXJ0aWVzPy5tZXRyaWNzKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIFwiVGhlIEpTT04gaXMgZXhwZWN0ZWQgdG8gaGF2ZSBleGFjdGx5IG9uZSBlbGVtZW50IHdpdGggcHJvcGVydGllcy5tZXRyaWNzIHByb3BlcnR5LlwiXG4gICAgICApO1xuICAgIH1cbiAgICBjb25zdCBtZXRyaWNzOiBhbnlbXSA9IGpzb25bMF0ucHJvcGVydGllcy5tZXRyaWNzO1xuICAgIGlmIChtZXRyaWNzLmxlbmd0aCA8IDIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgXCJUaGUgbnVtYmVyIG9mIG1ldHJpY3MgbXVzdCBiZSBhdCBsZWFzdCB0d28gKG1ldHJpYyArIGFub21hbHkgZGV0ZWN0aW9uIG1hdGgpLlwiXG4gICAgICApO1xuICAgIH1cbiAgICBjb25zdCBhbm9tYWx5RGV0ZWN0aW9uTWV0cmljUGFydDogYW55W10gPSBtZXRyaWNzWzBdPy52YWx1ZTtcbiAgICBpZiAoXG4gICAgICAhYW5vbWFseURldGVjdGlvbk1ldHJpY1BhcnQgfHxcbiAgICAgIGFub21hbHlEZXRlY3Rpb25NZXRyaWNQYXJ0Lmxlbmd0aCAhPT0gMVxuICAgICkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiRmlyc3QgbWV0cmljIG11c3QgYmUgYSBtYXRoIGV4cHJlc3Npb24uXCIpO1xuICAgIH1cbiAgICBjb25zdCBldmFsdWF0ZWRNZXRyaWNQYXJ0OiBhbnlbXSA9IG1ldHJpY3NbMV0/LnZhbHVlO1xuICAgIGlmIChcbiAgICAgICFldmFsdWF0ZWRNZXRyaWNQYXJ0IHx8XG4gICAgICBldmFsdWF0ZWRNZXRyaWNQYXJ0Lmxlbmd0aCA8IDEgfHxcbiAgICAgICFldmFsdWF0ZWRNZXRyaWNQYXJ0W2V2YWx1YXRlZE1ldHJpY1BhcnQubGVuZ3RoIC0gMV0uaWRcbiAgICApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIlNlY29uZCBtZXRyaWMgbXVzdCBoYXZlIGFuIElELlwiKTtcbiAgICB9XG4gICAgLy8gYmFuZCByZW5kZXJpbmcgcmVxdWlyZXMgSUQgdG8gYmUgc2V0XG4gICAgYW5vbWFseURldGVjdGlvbk1ldHJpY1BhcnRbMF0uaWQgPVxuICAgICAgZXZhbHVhdGVkTWV0cmljUGFydFtldmFsdWF0ZWRNZXRyaWNQYXJ0Lmxlbmd0aCAtIDFdLmlkICtcbiAgICAgIEFub21hbHlCYW5kTWV0cmljSWRTdWZmaXg7XG4gICAgLy8gYmFuZCByZW5kZXJpbmcgcmVxdWlyZXMgdGhlIGV2YWx1YXRlZCBtZXRyaWMgdG8gYmUgdmlzaWJsZVxuICAgIGV2YWx1YXRlZE1ldHJpY1BhcnRbZXZhbHVhdGVkTWV0cmljUGFydC5sZW5ndGggLSAxXS52aXNpYmxlID0gdHJ1ZTtcbiAgICByZXR1cm4ganNvbjtcbiAgfVxufVxuIl19