@cdklabs/multi-az-observability 0.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.jsii +10177 -0
- package/API.md +5119 -0
- package/LICENSE +202 -0
- package/README.md +175 -0
- package/cdk.json +68 -0
- package/lib/alarmsandrules/AvailabilityAndLatencyAlarmsAndRules.d.ts +214 -0
- package/lib/alarmsandrules/AvailabilityAndLatencyAlarmsAndRules.js +763 -0
- package/lib/alarmsandrules/BaseOperationRegionalAlarmsAndRules.d.ts +22 -0
- package/lib/alarmsandrules/BaseOperationRegionalAlarmsAndRules.js +21 -0
- package/lib/alarmsandrules/BaseOperationZonalAlarmsAndRules.d.ts +34 -0
- package/lib/alarmsandrules/BaseOperationZonalAlarmsAndRules.js +39 -0
- package/lib/alarmsandrules/CanaryOperationRegionalAlarmsAndRules.d.ts +7 -0
- package/lib/alarmsandrules/CanaryOperationRegionalAlarmsAndRules.js +11 -0
- package/lib/alarmsandrules/CanaryOperationZonalAlarmsAndRules.d.ts +16 -0
- package/lib/alarmsandrules/CanaryOperationZonalAlarmsAndRules.js +17 -0
- package/lib/alarmsandrules/IBaseOperationRegionalAlarmsAndRules.d.ts +18 -0
- package/lib/alarmsandrules/IBaseOperationRegionalAlarmsAndRules.js +3 -0
- package/lib/alarmsandrules/IBaseOperationZonalAlarmsAndRules.d.ts +30 -0
- package/lib/alarmsandrules/IBaseOperationZonalAlarmsAndRules.js +3 -0
- package/lib/alarmsandrules/ICanaryOperationRegionalAlarmsAndRules.d.ts +6 -0
- package/lib/alarmsandrules/ICanaryOperationRegionalAlarmsAndRules.js +3 -0
- package/lib/alarmsandrules/ICanaryOperationZonalAlarmsAndRules.d.ts +12 -0
- package/lib/alarmsandrules/ICanaryOperationZonalAlarmsAndRules.js +3 -0
- package/lib/alarmsandrules/IOperationAlarmsAndRules.d.ts +55 -0
- package/lib/alarmsandrules/IOperationAlarmsAndRules.js +3 -0
- package/lib/alarmsandrules/IServerSideOperationRegionalAlarmsAndRules.d.ts +15 -0
- package/lib/alarmsandrules/IServerSideOperationRegionalAlarmsAndRules.js +3 -0
- package/lib/alarmsandrules/IServerSideOperationZonalAlarmsAndRules.d.ts +36 -0
- package/lib/alarmsandrules/IServerSideOperationZonalAlarmsAndRules.js +3 -0
- package/lib/alarmsandrules/IServiceAlarmsAndRules.d.ts +44 -0
- package/lib/alarmsandrules/IServiceAlarmsAndRules.js +3 -0
- package/lib/alarmsandrules/InsightRuleBody.d.ts +67 -0
- package/lib/alarmsandrules/InsightRuleBody.js +46 -0
- package/lib/alarmsandrules/OperationAlarmsAndRules.d.ts +59 -0
- package/lib/alarmsandrules/OperationAlarmsAndRules.js +135 -0
- package/lib/alarmsandrules/ServerSideOperationRegionalAlarmsAndRules.d.ts +19 -0
- package/lib/alarmsandrules/ServerSideOperationRegionalAlarmsAndRules.js +22 -0
- package/lib/alarmsandrules/ServerSideOperationZonalAlarmsAndRules.d.ts +40 -0
- package/lib/alarmsandrules/ServerSideOperationZonalAlarmsAndRules.js +46 -0
- package/lib/alarmsandrules/ServiceAlarmsAndRules.d.ts +48 -0
- package/lib/alarmsandrules/ServiceAlarmsAndRules.js +166 -0
- package/lib/alarmsandrules/props/BaseOperationRegionalAlarmsAndRulesProps.d.ts +24 -0
- package/lib/alarmsandrules/props/BaseOperationRegionalAlarmsAndRulesProps.js +3 -0
- package/lib/alarmsandrules/props/BaseOperationZonalAlarmsAndRulesProps.d.ts +62 -0
- package/lib/alarmsandrules/props/BaseOperationZonalAlarmsAndRulesProps.js +3 -0
- package/lib/alarmsandrules/props/CanaryOperationRegionalAlarmsAndRulesProps.d.ts +6 -0
- package/lib/alarmsandrules/props/CanaryOperationRegionalAlarmsAndRulesProps.js +3 -0
- package/lib/alarmsandrules/props/CanaryOperationZonalAlarmsAndRulesProps.d.ts +6 -0
- package/lib/alarmsandrules/props/CanaryOperationZonalAlarmsAndRulesProps.js +3 -0
- package/lib/alarmsandrules/props/OperationAlarmsAndRulesProps.d.ts +45 -0
- package/lib/alarmsandrules/props/OperationAlarmsAndRulesProps.js +3 -0
- package/lib/alarmsandrules/props/ServerSideOperationRegionalAlarmsAndRulesProps.d.ts +6 -0
- package/lib/alarmsandrules/props/ServerSideOperationRegionalAlarmsAndRulesProps.js +3 -0
- package/lib/alarmsandrules/props/ServerSideOperationZonalAlarmsAndRulesProps.d.ts +6 -0
- package/lib/alarmsandrules/props/ServerSideOperationZonalAlarmsAndRulesProps.js +3 -0
- package/lib/alarmsandrules/props/ServiceAlarmsAndRulesProps.d.ts +13 -0
- package/lib/alarmsandrules/props/ServiceAlarmsAndRulesProps.js +3 -0
- package/lib/azmapper/AvailabilityZoneMapper.d.ts +86 -0
- package/lib/azmapper/AvailabilityZoneMapper.js +200 -0
- package/lib/azmapper/IAvailabilityZoneMapper.d.ts +86 -0
- package/lib/azmapper/IAvailabilityZoneMapper.js +3 -0
- package/lib/azmapper/props/AvailabilityZoneMapperProps.d.ts +13 -0
- package/lib/azmapper/props/AvailabilityZoneMapperProps.js +3 -0
- package/lib/azmapper/src/index.py +107 -0
- package/lib/canaries/CanaryFunction.d.ts +16 -0
- package/lib/canaries/CanaryFunction.js +152 -0
- package/lib/canaries/CanaryTest.d.ts +10 -0
- package/lib/canaries/CanaryTest.js +84 -0
- package/lib/canaries/ICanaryFunction.d.ts +6 -0
- package/lib/canaries/ICanaryFunction.js +3 -0
- package/lib/canaries/props/AddCanaryTestProps.d.ts +66 -0
- package/lib/canaries/props/AddCanaryTestProps.js +3 -0
- package/lib/canaries/props/CanaryFunctionProps.d.ts +29 -0
- package/lib/canaries/props/CanaryFunctionProps.js +3 -0
- package/lib/canaries/props/CanaryTestProps.d.ts +21 -0
- package/lib/canaries/props/CanaryTestProps.js +3 -0
- package/lib/canaries/props/NetworkConfigurationProps.d.ts +16 -0
- package/lib/canaries/props/NetworkConfigurationProps.js +3 -0
- package/lib/canaries/src/canary.zip +0 -0
- package/lib/dashboards/BasicServiceDashboard.d.ts +10 -0
- package/lib/dashboards/BasicServiceDashboard.js +130 -0
- package/lib/dashboards/ContributorInsightsWidget.d.ts +22 -0
- package/lib/dashboards/ContributorInsightsWidget.js +55 -0
- package/lib/dashboards/IOperationAvailabilityAndLatencyDashboard.d.ts +10 -0
- package/lib/dashboards/IOperationAvailabilityAndLatencyDashboard.js +3 -0
- package/lib/dashboards/IServiceAvailabilityAndLatencyDashboard.d.ts +10 -0
- package/lib/dashboards/IServiceAvailabilityAndLatencyDashboard.js +3 -0
- package/lib/dashboards/OperationAvailabilityAndLatencyDashboard.d.ts +20 -0
- package/lib/dashboards/OperationAvailabilityAndLatencyDashboard.js +588 -0
- package/lib/dashboards/ServiceAvailabilityAndLatencyDashboard.d.ts +24 -0
- package/lib/dashboards/ServiceAvailabilityAndLatencyDashboard.js +475 -0
- package/lib/dashboards/props/BasicServiceDashboardProps.d.ts +23 -0
- package/lib/dashboards/props/BasicServiceDashboardProps.js +3 -0
- package/lib/dashboards/props/ContributorInsightWidgetProps.d.ts +31 -0
- package/lib/dashboards/props/ContributorInsightWidgetProps.js +3 -0
- package/lib/dashboards/props/OperationAvailabilityAndLatencyDashboardProps.d.ts +84 -0
- package/lib/dashboards/props/OperationAvailabilityAndLatencyDashboardProps.js +3 -0
- package/lib/dashboards/props/OperationAvailabilityWidgetProps.d.ts +37 -0
- package/lib/dashboards/props/OperationAvailabilityWidgetProps.js +3 -0
- package/lib/dashboards/props/OperationLatencyWidgetProps.d.ts +37 -0
- package/lib/dashboards/props/OperationLatencyWidgetProps.js +3 -0
- package/lib/dashboards/props/ServiceAvailabilityAndLatencyDashboardProps.d.ts +30 -0
- package/lib/dashboards/props/ServiceAvailabilityAndLatencyDashboardProps.js +3 -0
- package/lib/index.d.ts +35 -0
- package/lib/index.js +30 -0
- package/lib/metrics/ApplicationLoadBalancerMetrics.d.ts +36 -0
- package/lib/metrics/ApplicationLoadBalancerMetrics.js +150 -0
- package/lib/metrics/AvailabilityAndLatencyMetrics.d.ts +61 -0
- package/lib/metrics/AvailabilityAndLatencyMetrics.js +212 -0
- package/lib/metrics/NetworkLoadBalancerMetrics.d.ts +19 -0
- package/lib/metrics/NetworkLoadBalancerMetrics.js +48 -0
- package/lib/metrics/RegionalAvailabilityMetrics.d.ts +19 -0
- package/lib/metrics/RegionalAvailabilityMetrics.js +71 -0
- package/lib/metrics/RegionalLatencyMetrics.d.ts +33 -0
- package/lib/metrics/RegionalLatencyMetrics.js +69 -0
- package/lib/metrics/ZonalAvailabilityMetrics.d.ts +19 -0
- package/lib/metrics/ZonalAvailabilityMetrics.js +71 -0
- package/lib/metrics/ZonalLatencyMetrics.d.ts +29 -0
- package/lib/metrics/ZonalLatencyMetrics.js +65 -0
- package/lib/metrics/props/AvailabilityAndLatencyMetricProps.d.ts +23 -0
- package/lib/metrics/props/AvailabilityAndLatencyMetricProps.js +3 -0
- package/lib/metrics/props/AvailabilityMetricProps.d.ts +11 -0
- package/lib/metrics/props/AvailabilityMetricProps.js +3 -0
- package/lib/metrics/props/LatencyMetricProps.d.ts +15 -0
- package/lib/metrics/props/LatencyMetricProps.js +3 -0
- package/lib/metrics/props/RegionalAvailabilityMetricProps.d.ts +6 -0
- package/lib/metrics/props/RegionalAvailabilityMetricProps.js +3 -0
- package/lib/metrics/props/RegionalLatencyMetricProps.d.ts +6 -0
- package/lib/metrics/props/RegionalLatencyMetricProps.js +3 -0
- package/lib/metrics/props/ServiceAvailabilityMetricProps.d.ts +23 -0
- package/lib/metrics/props/ServiceAvailabilityMetricProps.js +3 -0
- package/lib/metrics/props/ServiceLatencyMericProps.d.ts +23 -0
- package/lib/metrics/props/ServiceLatencyMericProps.js +3 -0
- package/lib/metrics/props/ZonalAvailabilityMetricProps.d.ts +10 -0
- package/lib/metrics/props/ZonalAvailabilityMetricProps.js +3 -0
- package/lib/metrics/props/ZonalLatencyMetricProps.d.ts +10 -0
- package/lib/metrics/props/ZonalLatencyMetricProps.js +3 -0
- package/lib/monitoring/src/monitoring-layer.zip +0 -0
- package/lib/outlier-detection/IOutlierDetectionFunction.d.ts +12 -0
- package/lib/outlier-detection/IOutlierDetectionFunction.js +3 -0
- package/lib/outlier-detection/OutlierDetectionFunction.d.ts +16 -0
- package/lib/outlier-detection/OutlierDetectionFunction.js +126 -0
- package/lib/outlier-detection/props/OutlierDetectionFunctionProps.d.ts +12 -0
- package/lib/outlier-detection/props/OutlierDetectionFunctionProps.js +3 -0
- package/lib/outlier-detection/src/outlier-detection.zip +0 -0
- package/lib/outlier-detection/src/scipy-layer.zip +0 -0
- package/lib/services/BasicServiceMultiAZObservability.d.ts +64 -0
- package/lib/services/BasicServiceMultiAZObservability.js +504 -0
- package/lib/services/CanaryMetrics.d.ts +17 -0
- package/lib/services/CanaryMetrics.js +19 -0
- package/lib/services/CanaryTestMetricsOverride.d.ts +39 -0
- package/lib/services/CanaryTestMetricsOverride.js +23 -0
- package/lib/services/ContributorInsightRuleDetails.d.ts +42 -0
- package/lib/services/ContributorInsightRuleDetails.js +23 -0
- package/lib/services/IBasicServiceMultiAZObservability.d.ts +45 -0
- package/lib/services/IBasicServiceMultiAZObservability.js +3 -0
- package/lib/services/ICanaryMetrics.d.ts +14 -0
- package/lib/services/ICanaryMetrics.js +3 -0
- package/lib/services/ICanaryTestMetricsOverride.d.ts +36 -0
- package/lib/services/ICanaryTestMetricsOverride.js +3 -0
- package/lib/services/IContributorInsightRuleDetails.d.ts +38 -0
- package/lib/services/IContributorInsightRuleDetails.js +3 -0
- package/lib/services/IInstrumentedServiceMultiAZObservability.d.ts +39 -0
- package/lib/services/IInstrumentedServiceMultiAZObservability.js +3 -0
- package/lib/services/IOperation.d.ts +75 -0
- package/lib/services/IOperation.js +3 -0
- package/lib/services/IOperationMetricDetails.d.ts +78 -0
- package/lib/services/IOperationMetricDetails.js +3 -0
- package/lib/services/IService.d.ts +76 -0
- package/lib/services/IService.js +3 -0
- package/lib/services/IServiceMetricDetails.d.ts +68 -0
- package/lib/services/IServiceMetricDetails.js +3 -0
- package/lib/services/InstrumentedServiceMultiAZObservability.d.ts +55 -0
- package/lib/services/InstrumentedServiceMultiAZObservability.js +310 -0
- package/lib/services/Operation.d.ts +78 -0
- package/lib/services/Operation.js +34 -0
- package/lib/services/OperationMetricDetails.d.ts +82 -0
- package/lib/services/OperationMetricDetails.js +50 -0
- package/lib/services/Service.d.ts +80 -0
- package/lib/services/Service.js +36 -0
- package/lib/services/ServiceMetricDetails.d.ts +71 -0
- package/lib/services/ServiceMetricDetails.js +28 -0
- package/lib/services/props/BasicServiceMultiAZObservabilityProps.d.ts +126 -0
- package/lib/services/props/BasicServiceMultiAZObservabilityProps.js +3 -0
- package/lib/services/props/CanaryMetricProps.d.ts +14 -0
- package/lib/services/props/CanaryMetricProps.js +3 -0
- package/lib/services/props/CanaryTestMetricsOverrideProps.d.ts +47 -0
- package/lib/services/props/CanaryTestMetricsOverrideProps.js +3 -0
- package/lib/services/props/ContributorInsightRuleDetailsProps.d.ts +38 -0
- package/lib/services/props/ContributorInsightRuleDetailsProps.js +3 -0
- package/lib/services/props/InstrumentedServiceMultiAZObservabilityProps.d.ts +88 -0
- package/lib/services/props/InstrumentedServiceMultiAZObservabilityProps.js +3 -0
- package/lib/services/props/MetricDimensions.d.ts +61 -0
- package/lib/services/props/MetricDimensions.js +63 -0
- package/lib/services/props/OperationMetricDetailsProps.d.ts +97 -0
- package/lib/services/props/OperationMetricDetailsProps.js +3 -0
- package/lib/services/props/OperationProps.d.ts +93 -0
- package/lib/services/props/OperationProps.js +3 -0
- package/lib/services/props/ServiceMetricDetailsProps.d.ts +68 -0
- package/lib/services/props/ServiceMetricDetailsProps.js +3 -0
- package/lib/services/props/ServiceProps.d.ts +69 -0
- package/lib/services/props/ServiceProps.js +3 -0
- package/lib/utilities/AvailabilityMetricType.d.ts +26 -0
- package/lib/utilities/AvailabilityMetricType.js +33 -0
- package/lib/utilities/LatencyMetricType.d.ts +13 -0
- package/lib/utilities/LatencyMetricType.js +20 -0
- package/lib/utilities/OutlierDetectionAlgorithm.d.ts +42 -0
- package/lib/utilities/OutlierDetectionAlgorithm.js +49 -0
- package/lib/utilities/StackWithDynamicSource.d.ts +14 -0
- package/lib/utilities/StackWithDynamicSource.js +82 -0
- package/package.json +176 -0
- package/rosetta/default.ts-fixture +13 -0
|
@@ -0,0 +1,504 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var _a;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.BasicServiceMultiAZObservability = void 0;
|
|
5
|
+
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
|
|
6
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
7
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
8
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
9
|
+
const aws_cloudwatch_1 = require("aws-cdk-lib/aws-cloudwatch");
|
|
10
|
+
const aws_elasticloadbalancingv2_1 = require("aws-cdk-lib/aws-elasticloadbalancingv2");
|
|
11
|
+
const constructs_1 = require("constructs");
|
|
12
|
+
const AvailabilityAndLatencyAlarmsAndRules_1 = require("../alarmsandrules/AvailabilityAndLatencyAlarmsAndRules");
|
|
13
|
+
const AvailabilityZoneMapper_1 = require("../azmapper/AvailabilityZoneMapper");
|
|
14
|
+
const BasicServiceDashboard_1 = require("../dashboards/BasicServiceDashboard");
|
|
15
|
+
const AvailabilityAndLatencyMetrics_1 = require("../metrics/AvailabilityAndLatencyMetrics");
|
|
16
|
+
const OutlierDetectionFunction_1 = require("../outlier-detection/OutlierDetectionFunction");
|
|
17
|
+
const OutlierDetectionAlgorithm_1 = require("../utilities/OutlierDetectionAlgorithm");
|
|
18
|
+
const StackWithDynamicSource_1 = require("../utilities/StackWithDynamicSource");
|
|
19
|
+
/**
|
|
20
|
+
* Basic observability for a service using metrics from
|
|
21
|
+
* ALBs and NAT Gateways
|
|
22
|
+
*/
|
|
23
|
+
class BasicServiceMultiAZObservability extends constructs_1.Construct {
|
|
24
|
+
constructor(scope, id, props) {
|
|
25
|
+
super(scope, id);
|
|
26
|
+
// Initialize class properties
|
|
27
|
+
this.serviceName = props.serviceName;
|
|
28
|
+
this.applicationLoadBalancers = props.applicationLoadBalancers;
|
|
29
|
+
this.natGateways = props.natGateways;
|
|
30
|
+
this._natGWZonalIsolatedImpactAlarms = {};
|
|
31
|
+
this._albZonalIsolatedImpactAlarms = {};
|
|
32
|
+
this.aggregateZonalIsolatedImpactAlarms = {};
|
|
33
|
+
this._packetDropsPerZone = {};
|
|
34
|
+
this._faultsPerZone = {};
|
|
35
|
+
let outlierThreshold;
|
|
36
|
+
if (!props.outlierThreshold) {
|
|
37
|
+
switch (props.outlierDetectionAlgorithm) {
|
|
38
|
+
case OutlierDetectionAlgorithm_1.OutlierDetectionAlgorithm.CHI_SQUARED:
|
|
39
|
+
outlierThreshold = 0.05;
|
|
40
|
+
break;
|
|
41
|
+
case OutlierDetectionAlgorithm_1.OutlierDetectionAlgorithm.IQR:
|
|
42
|
+
outlierThreshold = 1.5;
|
|
43
|
+
break;
|
|
44
|
+
case OutlierDetectionAlgorithm_1.OutlierDetectionAlgorithm.MAD:
|
|
45
|
+
outlierThreshold = 3;
|
|
46
|
+
break;
|
|
47
|
+
case OutlierDetectionAlgorithm_1.OutlierDetectionAlgorithm.STATIC:
|
|
48
|
+
outlierThreshold = 0.7;
|
|
49
|
+
break;
|
|
50
|
+
case OutlierDetectionAlgorithm_1.OutlierDetectionAlgorithm.Z_SCORE:
|
|
51
|
+
outlierThreshold = 2;
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
outlierThreshold = props.outlierThreshold;
|
|
57
|
+
}
|
|
58
|
+
// Create the AZ mapper resource to translate AZ names to ids
|
|
59
|
+
this.azMapper = new AvailabilityZoneMapper_1.AvailabilityZoneMapper(this, 'AvailabilityZoneMapper');
|
|
60
|
+
if (props.outlierDetectionAlgorithm != OutlierDetectionAlgorithm_1.OutlierDetectionAlgorithm.STATIC) {
|
|
61
|
+
let outlierDetectionStack = new StackWithDynamicSource_1.StackWithDynamicSource(this, 'OutlierDetectionStack', {
|
|
62
|
+
assetsBucketsParameterName: props.assetsBucketParameterName,
|
|
63
|
+
assetsBucketPrefixParameterName: props.assetsBucketPrefixParameterName,
|
|
64
|
+
});
|
|
65
|
+
this.outlierDetectionFunction = new OutlierDetectionFunction_1.OutlierDetectionFunction(outlierDetectionStack, 'OutlierDetectionFunction', {}).function;
|
|
66
|
+
}
|
|
67
|
+
// Create metrics and alarms for just load balancers if they were provided
|
|
68
|
+
if (this.applicationLoadBalancers !== undefined &&
|
|
69
|
+
this.applicationLoadBalancers != null) {
|
|
70
|
+
this.doAlbMetrics(props, outlierThreshold);
|
|
71
|
+
}
|
|
72
|
+
// Create NAT Gateway metrics and alarms
|
|
73
|
+
if (this.natGateways !== undefined && this.natGateways != null) {
|
|
74
|
+
this.doNatGatewayMetrics(props, outlierThreshold);
|
|
75
|
+
}
|
|
76
|
+
let counter = 1;
|
|
77
|
+
// Go through the ALB zonal isolated impact alarms and see if there is a NAT GW
|
|
78
|
+
// isolated impact alarm for the same AZ ID, if so, create a composite alarm with both
|
|
79
|
+
// otherwise create a composite alarm with just the ALB
|
|
80
|
+
Object.keys(this._albZonalIsolatedImpactAlarms).forEach((az) => {
|
|
81
|
+
let tmp = [];
|
|
82
|
+
tmp.push(this._albZonalIsolatedImpactAlarms[az]);
|
|
83
|
+
if (this._natGWZonalIsolatedImpactAlarms[az] !== undefined &&
|
|
84
|
+
this._natGWZonalIsolatedImpactAlarms[az] != null) {
|
|
85
|
+
tmp.push(this._natGWZonalIsolatedImpactAlarms[az]);
|
|
86
|
+
}
|
|
87
|
+
let availabilityZoneId = this.azMapper.availabilityZoneIdFromAvailabilityZoneLetter(az.substring(az.length - 1));
|
|
88
|
+
this.aggregateZonalIsolatedImpactAlarms[az] = new aws_cloudwatch_1.CompositeAlarm(this, 'AZ' + counter++ + 'AggregateIsolatedImpactAlarm', {
|
|
89
|
+
compositeAlarmName: availabilityZoneId + '-aggregate-isolated-impact',
|
|
90
|
+
alarmRule: aws_cloudwatch_1.AlarmRule.anyOf(...tmp),
|
|
91
|
+
actionsEnabled: false,
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
// In case there were AZs with only a NAT GW and no ALB, create a composite alarm
|
|
95
|
+
// for the NAT GW metrics
|
|
96
|
+
Object.keys(this._natGWZonalIsolatedImpactAlarms).forEach((az) => {
|
|
97
|
+
// If we don't yet have an isolated impact alarm for this AZ, proceed
|
|
98
|
+
if (this.aggregateZonalIsolatedImpactAlarms[az] === undefined ||
|
|
99
|
+
this.aggregateZonalIsolatedImpactAlarms[az] == null) {
|
|
100
|
+
let tmp = [];
|
|
101
|
+
tmp.push(this._natGWZonalIsolatedImpactAlarms[az]);
|
|
102
|
+
if (this._albZonalIsolatedImpactAlarms[az] !== undefined &&
|
|
103
|
+
this.albZonalIsolatedImpactAlarms != null) {
|
|
104
|
+
tmp.push(this.albZonalIsolatedImpactAlarms[az]);
|
|
105
|
+
}
|
|
106
|
+
let availabilityZoneId = this.azMapper.availabilityZoneIdFromAvailabilityZoneLetter(az.substring(az.length - 1));
|
|
107
|
+
this.aggregateZonalIsolatedImpactAlarms[az] = new aws_cloudwatch_1.CompositeAlarm(this, 'AZ' + counter++ + 'AggregateIsolatedImpactAlarm', {
|
|
108
|
+
compositeAlarmName: availabilityZoneId + '-aggregate-isolated-impact',
|
|
109
|
+
alarmRule: aws_cloudwatch_1.AlarmRule.anyOf(...tmp),
|
|
110
|
+
actionsEnabled: false,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
this.albZonalIsolatedImpactAlarms = this._albZonalIsolatedImpactAlarms;
|
|
115
|
+
this.natGWZonalIsolatedImpactAlarms = this._natGWZonalIsolatedImpactAlarms;
|
|
116
|
+
// Should we create the dashboard
|
|
117
|
+
if (props.createDashboard == true) {
|
|
118
|
+
this.dashboard = new BasicServiceDashboard_1.BasicServiceDashboard(this, 'BasicServiceDashboard', {
|
|
119
|
+
serviceName: props.serviceName.toLowerCase(),
|
|
120
|
+
zonalAggregateIsolatedImpactAlarms: this.aggregateZonalIsolatedImpactAlarms,
|
|
121
|
+
zonalLoadBalancerIsolatedImpactAlarms: this.albZonalIsolatedImpactAlarms,
|
|
122
|
+
zonalNatGatewayIsolatedImpactAlarms: this.natGWZonalIsolatedImpactAlarms,
|
|
123
|
+
interval: props.interval,
|
|
124
|
+
zonalLoadBalancerFaultRateMetrics: this._faultsPerZone,
|
|
125
|
+
zonalNatGatewayPacketDropMetrics: this._packetDropsPerZone,
|
|
126
|
+
azMapper: this.azMapper,
|
|
127
|
+
}).dashboard;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
doAlbMetrics(props, outlierThreshold) {
|
|
131
|
+
// Collect total fault count metrics per AZ
|
|
132
|
+
let albZoneFaultCountMetrics = {};
|
|
133
|
+
// Create fault rate alarms per AZ indicating at least 1 ALB
|
|
134
|
+
// in the AZ saw a fault rate that exceeded the threshold
|
|
135
|
+
let faultRatePercentageAlarms = {};
|
|
136
|
+
let keyPrefix = AvailabilityAndLatencyMetrics_1.AvailabilityAndLatencyMetrics.nextChar('');
|
|
137
|
+
// Iterate each ALB
|
|
138
|
+
this.applicationLoadBalancers.forEach((alb) => {
|
|
139
|
+
// Iterate each AZ in the VPC
|
|
140
|
+
alb.vpc?.availabilityZones.forEach((az, index) => {
|
|
141
|
+
let azLetter = az.substring(az.length - 1);
|
|
142
|
+
let availabilityZoneId = this.azMapper.availabilityZoneIdFromAvailabilityZoneLetter(azLetter);
|
|
143
|
+
faultRatePercentageAlarms[azLetter] = [];
|
|
144
|
+
// 5xx responses from targets
|
|
145
|
+
let target5xx = alb.metrics.httpCodeTarget(aws_elasticloadbalancingv2_1.HttpCodeTarget.TARGET_5XX_COUNT, {
|
|
146
|
+
dimensionsMap: {
|
|
147
|
+
AvailabilityZone: az,
|
|
148
|
+
LoadBalancer: alb
|
|
149
|
+
.loadBalancerFullName,
|
|
150
|
+
},
|
|
151
|
+
label: availabilityZoneId,
|
|
152
|
+
period: props.period,
|
|
153
|
+
});
|
|
154
|
+
// 5xx responses from ELB
|
|
155
|
+
let elb5xx = alb.metrics.httpCodeElb(aws_elasticloadbalancingv2_1.HttpCodeElb.ELB_5XX_COUNT, {
|
|
156
|
+
dimensionsMap: {
|
|
157
|
+
AvailabilityZone: az,
|
|
158
|
+
LoadBalancer: alb
|
|
159
|
+
.loadBalancerFullName,
|
|
160
|
+
},
|
|
161
|
+
label: availabilityZoneId,
|
|
162
|
+
period: props.period,
|
|
163
|
+
});
|
|
164
|
+
// 2xx responses from targets
|
|
165
|
+
let target2xx = alb.metrics.httpCodeTarget(aws_elasticloadbalancingv2_1.HttpCodeTarget.TARGET_2XX_COUNT, {
|
|
166
|
+
dimensionsMap: {
|
|
167
|
+
AvailabilityZone: az,
|
|
168
|
+
LoadBalancer: alb
|
|
169
|
+
.loadBalancerFullName,
|
|
170
|
+
},
|
|
171
|
+
label: availabilityZoneId,
|
|
172
|
+
period: props.period,
|
|
173
|
+
});
|
|
174
|
+
// 3xx responses from targets
|
|
175
|
+
let target3xx = alb.metrics.httpCodeTarget(aws_elasticloadbalancingv2_1.HttpCodeTarget.TARGET_3XX_COUNT, {
|
|
176
|
+
dimensionsMap: {
|
|
177
|
+
AvailabilityZone: az,
|
|
178
|
+
LoadBalancer: alb
|
|
179
|
+
.loadBalancerFullName,
|
|
180
|
+
},
|
|
181
|
+
label: availabilityZoneId,
|
|
182
|
+
period: props.period,
|
|
183
|
+
});
|
|
184
|
+
// 3xx responess from ELB
|
|
185
|
+
let elb3xx = alb.metrics.httpCodeElb(aws_elasticloadbalancingv2_1.HttpCodeElb.ELB_3XX_COUNT, {
|
|
186
|
+
dimensionsMap: {
|
|
187
|
+
AvailabilityZone: az,
|
|
188
|
+
LoadBalancer: alb
|
|
189
|
+
.loadBalancerFullName,
|
|
190
|
+
},
|
|
191
|
+
label: availabilityZoneId,
|
|
192
|
+
period: props.period,
|
|
193
|
+
});
|
|
194
|
+
// Create metrics for total fault count from this ALB
|
|
195
|
+
let usingMetrics = {};
|
|
196
|
+
usingMetrics[`${keyPrefix}1`] = target5xx;
|
|
197
|
+
usingMetrics[`${keyPrefix}2`] = elb5xx;
|
|
198
|
+
if (albZoneFaultCountMetrics[azLetter] === undefined ||
|
|
199
|
+
albZoneFaultCountMetrics[azLetter] == null) {
|
|
200
|
+
albZoneFaultCountMetrics[azLetter] = [];
|
|
201
|
+
}
|
|
202
|
+
albZoneFaultCountMetrics[azLetter].push(new aws_cloudwatch_1.MathExpression({
|
|
203
|
+
expression: `(${keyPrefix}1 + ${keyPrefix}2)`,
|
|
204
|
+
usingMetrics: usingMetrics,
|
|
205
|
+
label: availabilityZoneId + ' ' + alb.loadBalancerArn + ' fault count',
|
|
206
|
+
period: props.period,
|
|
207
|
+
}));
|
|
208
|
+
// Create metrics to calculate fault rate for this ALB
|
|
209
|
+
usingMetrics = {};
|
|
210
|
+
usingMetrics[`${keyPrefix}1`] = target2xx;
|
|
211
|
+
usingMetrics[`${keyPrefix}2`] = target3xx;
|
|
212
|
+
usingMetrics[`${keyPrefix}3`] = elb3xx;
|
|
213
|
+
usingMetrics[`${keyPrefix}4`] = target5xx;
|
|
214
|
+
usingMetrics[`${keyPrefix}5`] = elb5xx;
|
|
215
|
+
// The ALB fault rate
|
|
216
|
+
let faultRate = new aws_cloudwatch_1.MathExpression({
|
|
217
|
+
expression: `((${keyPrefix}4+${keyPrefix}5)/(${keyPrefix}1+${keyPrefix}2+${keyPrefix}3+${keyPrefix}4+${keyPrefix}5)) * 100`,
|
|
218
|
+
usingMetrics: usingMetrics,
|
|
219
|
+
label: availabilityZoneId + ' ' + alb.loadBalancerArn + ' fault rate',
|
|
220
|
+
period: props.period,
|
|
221
|
+
});
|
|
222
|
+
let threshold = props.faultCountPercentageThreshold ?? 5;
|
|
223
|
+
// Create a fault rate alarm for the ALB
|
|
224
|
+
let faultRateAlarm = new aws_cloudwatch_1.Alarm(this, 'AZ' + index + keyPrefix + 'FaultRatePercentageAlarm', {
|
|
225
|
+
alarmName: availabilityZoneId + '-' + alb.loadBalancerArn + '-fault-rate',
|
|
226
|
+
actionsEnabled: false,
|
|
227
|
+
metric: faultRate,
|
|
228
|
+
evaluationPeriods: props.evaluationPeriods,
|
|
229
|
+
datapointsToAlarm: props.datapointsToAlarm,
|
|
230
|
+
threshold: threshold,
|
|
231
|
+
comparisonOperator: aws_cloudwatch_1.ComparisonOperator.GREATER_THAN_THRESHOLD,
|
|
232
|
+
});
|
|
233
|
+
// Add this ALB's fault rate alarm
|
|
234
|
+
faultRatePercentageAlarms[azLetter].push(faultRateAlarm);
|
|
235
|
+
// Get next unique key
|
|
236
|
+
keyPrefix = AvailabilityAndLatencyMetrics_1.AvailabilityAndLatencyMetrics.nextChar(keyPrefix);
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
// Iterate AZs for the ALB fault count metrics
|
|
240
|
+
Object.keys(albZoneFaultCountMetrics).forEach((azLetter) => {
|
|
241
|
+
let availabilityZoneId = this.azMapper.availabilityZoneIdFromAvailabilityZoneLetter(azLetter);
|
|
242
|
+
keyPrefix = AvailabilityAndLatencyMetrics_1.AvailabilityAndLatencyMetrics.nextChar(keyPrefix);
|
|
243
|
+
let counter = 1;
|
|
244
|
+
let usingMetrics = {};
|
|
245
|
+
// Add each ALB's fault count metrics to the dictionary
|
|
246
|
+
albZoneFaultCountMetrics[azLetter].forEach((metric) => {
|
|
247
|
+
usingMetrics[`${keyPrefix}${counter++}`] = metric;
|
|
248
|
+
});
|
|
249
|
+
// Sum the total faults for the availability zone across all ALBs
|
|
250
|
+
let totalFaultsPerZone = new aws_cloudwatch_1.MathExpression({
|
|
251
|
+
expression: Object.keys(usingMetrics).join('+'),
|
|
252
|
+
usingMetrics: usingMetrics,
|
|
253
|
+
label: availabilityZoneId + ' fault count',
|
|
254
|
+
period: props.period,
|
|
255
|
+
});
|
|
256
|
+
keyPrefix = AvailabilityAndLatencyMetrics_1.AvailabilityAndLatencyMetrics.nextChar(keyPrefix);
|
|
257
|
+
counter = 1;
|
|
258
|
+
// Assign the total faults per zone to the dictionary
|
|
259
|
+
this._faultsPerZone[azLetter] = totalFaultsPerZone;
|
|
260
|
+
});
|
|
261
|
+
keyPrefix = AvailabilityAndLatencyMetrics_1.AvailabilityAndLatencyMetrics.nextChar(keyPrefix);
|
|
262
|
+
let tmp = {};
|
|
263
|
+
Object.keys(this._faultsPerZone).forEach((azLetter, index) => {
|
|
264
|
+
tmp[`${keyPrefix}${index}`] = this._faultsPerZone[azLetter];
|
|
265
|
+
});
|
|
266
|
+
// Calculate the total faults in the region by adding all AZs together
|
|
267
|
+
let totalFaults = new aws_cloudwatch_1.MathExpression({
|
|
268
|
+
expression: Object.keys(tmp).join('+'),
|
|
269
|
+
usingMetrics: tmp,
|
|
270
|
+
label: aws_cdk_lib_1.Fn.sub('${AWS::Region} fault count'),
|
|
271
|
+
period: props.period,
|
|
272
|
+
});
|
|
273
|
+
if (props.outlierDetectionAlgorithm == OutlierDetectionAlgorithm_1.OutlierDetectionAlgorithm.STATIC) {
|
|
274
|
+
// Finally, iterate back through each AZ
|
|
275
|
+
Object.keys(this._faultsPerZone).forEach((azLetter, index) => {
|
|
276
|
+
keyPrefix = AvailabilityAndLatencyMetrics_1.AvailabilityAndLatencyMetrics.nextChar(keyPrefix);
|
|
277
|
+
let availabilityZoneId = this.azMapper.availabilityZoneIdFromAvailabilityZoneLetter(azLetter);
|
|
278
|
+
// Determine if AZ is an outlier for faults by exceeding
|
|
279
|
+
// a static threshold
|
|
280
|
+
let outlierMetrics;
|
|
281
|
+
// These metrics will give the percent of faults for the AZ
|
|
282
|
+
let usingMetrics = {};
|
|
283
|
+
usingMetrics[`${keyPrefix}1`] = this._faultsPerZone[azLetter];
|
|
284
|
+
usingMetrics[`${keyPrefix}2`] = totalFaults;
|
|
285
|
+
outlierMetrics = new aws_cloudwatch_1.MathExpression({
|
|
286
|
+
expression: `${keyPrefix}1 / ${keyPrefix}2`,
|
|
287
|
+
usingMetrics: usingMetrics,
|
|
288
|
+
});
|
|
289
|
+
let azIsOutlierForFaults = new aws_cloudwatch_1.Alarm(this, 'AZ' + index + 'FaultCountOutlierAlarm', {
|
|
290
|
+
alarmName: availabilityZoneId + '-fault-count-outlier',
|
|
291
|
+
metric: outlierMetrics,
|
|
292
|
+
threshold: outlierThreshold,
|
|
293
|
+
evaluationPeriods: props.evaluationPeriods,
|
|
294
|
+
datapointsToAlarm: props.datapointsToAlarm,
|
|
295
|
+
actionsEnabled: false,
|
|
296
|
+
treatMissingData: aws_cloudwatch_1.TreatMissingData.IGNORE,
|
|
297
|
+
comparisonOperator: aws_cloudwatch_1.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD,
|
|
298
|
+
});
|
|
299
|
+
// Create isolated AZ impact alarms by determining
|
|
300
|
+
// if the AZ is an outlier for fault count and at least
|
|
301
|
+
// one ALB exceeds the fault rate threshold provided
|
|
302
|
+
this._albZonalIsolatedImpactAlarms[azLetter] = new aws_cloudwatch_1.CompositeAlarm(this, 'AZ' + index + 'IsolatedFaultCountImpact', {
|
|
303
|
+
compositeAlarmName: availabilityZoneId + '-isolated-fault-count-impact',
|
|
304
|
+
alarmRule: aws_cloudwatch_1.AlarmRule.allOf(azIsOutlierForFaults, aws_cloudwatch_1.AlarmRule.anyOf(...faultRatePercentageAlarms[azLetter])),
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
let allAZs = Array.from(new Set(this.applicationLoadBalancers.flatMap((x) => {
|
|
310
|
+
return x.vpc.availabilityZones;
|
|
311
|
+
})));
|
|
312
|
+
allAZs.forEach((az, index) => {
|
|
313
|
+
let azLetter = az.substring(az.length - 1);
|
|
314
|
+
let availabilityZoneId = this.azMapper.availabilityZoneIdFromAvailabilityZoneLetter(azLetter);
|
|
315
|
+
let azIsOutlierForFaults = AvailabilityAndLatencyAlarmsAndRules_1.AvailabilityAndLatencyAlarmsAndRules.createZonalFaultRateOutlierAlarmForAlb(this, props.applicationLoadBalancers, availabilityZoneId, outlierThreshold, this.outlierDetectionFunction, props.outlierDetectionAlgorithm, this.azMapper, index, props.evaluationPeriods, props.datapointsToAlarm, '');
|
|
316
|
+
// In addition to being an outlier for fault count, make sure
|
|
317
|
+
// the fault count is substantial enough to trigger the alarm
|
|
318
|
+
// by making sure at least 1 ALB sees packet loss that exceeds the threshold
|
|
319
|
+
let azIsOutlierAndSeesImpact = new aws_cloudwatch_1.CompositeAlarm(this, 'AZ' + index + 'ALBIsolatedImpact', {
|
|
320
|
+
compositeAlarmName: availabilityZoneId + '-isolated-fault-count-impact',
|
|
321
|
+
alarmRule: aws_cloudwatch_1.AlarmRule.allOf(azIsOutlierForFaults, aws_cloudwatch_1.AlarmRule.anyOf(...faultRatePercentageAlarms[azLetter])),
|
|
322
|
+
});
|
|
323
|
+
// Record these so they can be used in dashboard or for combination
|
|
324
|
+
// with AZ
|
|
325
|
+
this._albZonalIsolatedImpactAlarms[azLetter] = azIsOutlierAndSeesImpact;
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
doNatGatewayMetrics(props, outlierThreshold) {
|
|
330
|
+
let keyPrefix = AvailabilityAndLatencyMetrics_1.AvailabilityAndLatencyMetrics.nextChar('');
|
|
331
|
+
// Collect alarms for packet drops exceeding a threshold per NAT GW
|
|
332
|
+
let packetDropPercentageAlarms = {};
|
|
333
|
+
// For each AZ, create metrics for each NAT GW
|
|
334
|
+
Object.entries(this.natGateways).forEach((entry, index) => {
|
|
335
|
+
// The number of packet drops for each NAT GW in the AZ
|
|
336
|
+
let packetDropMetricsForAZ = {};
|
|
337
|
+
let az = entry[0];
|
|
338
|
+
let azLetter = az.substring(az.length - 1);
|
|
339
|
+
let availabilityZoneId = this.azMapper.availabilityZoneIdFromAvailabilityZoneLetter(azLetter);
|
|
340
|
+
packetDropPercentageAlarms[azLetter] = [];
|
|
341
|
+
// Iterate through each NAT GW in the current AZ
|
|
342
|
+
entry[1].forEach((natgw) => {
|
|
343
|
+
// Calculate packet drops
|
|
344
|
+
let packetDropCount = new aws_cloudwatch_1.Metric({
|
|
345
|
+
metricName: 'PacketsDropCount',
|
|
346
|
+
namespace: 'AWS/NATGateway',
|
|
347
|
+
statistic: 'Sum',
|
|
348
|
+
unit: aws_cloudwatch_1.Unit.COUNT,
|
|
349
|
+
label: availabilityZoneId + ' packet drops',
|
|
350
|
+
dimensionsMap: {
|
|
351
|
+
NatGatewayId: natgw.attrNatGatewayId,
|
|
352
|
+
},
|
|
353
|
+
period: props.period,
|
|
354
|
+
});
|
|
355
|
+
// Calculate packets in from source
|
|
356
|
+
let packetsInFromSourceCount = new aws_cloudwatch_1.Metric({
|
|
357
|
+
metricName: 'PacketsInFromSource',
|
|
358
|
+
namespace: 'AWS/NATGateway',
|
|
359
|
+
statistic: 'Sum',
|
|
360
|
+
unit: aws_cloudwatch_1.Unit.COUNT,
|
|
361
|
+
label: availabilityZoneId + ' packets in from source',
|
|
362
|
+
dimensionsMap: {
|
|
363
|
+
NatGatewayId: natgw.attrNatGatewayId,
|
|
364
|
+
},
|
|
365
|
+
period: props.period,
|
|
366
|
+
});
|
|
367
|
+
// Calculate packets in from destination
|
|
368
|
+
let packetsInFromDestinationCount = new aws_cloudwatch_1.Metric({
|
|
369
|
+
metricName: 'PacketsInFromDestination',
|
|
370
|
+
namespace: 'AWS/NATGateway',
|
|
371
|
+
statistic: 'Sum',
|
|
372
|
+
unit: aws_cloudwatch_1.Unit.COUNT,
|
|
373
|
+
label: availabilityZoneId + ' packets in from destination',
|
|
374
|
+
dimensionsMap: {
|
|
375
|
+
NatGatewayId: natgw.attrNatGatewayId,
|
|
376
|
+
},
|
|
377
|
+
period: props.period,
|
|
378
|
+
});
|
|
379
|
+
let usingMetrics = {};
|
|
380
|
+
usingMetrics[`${keyPrefix}1`] = packetDropCount;
|
|
381
|
+
usingMetrics[`${keyPrefix}2`] = packetsInFromSourceCount;
|
|
382
|
+
usingMetrics[`${keyPrefix}3`] = packetsInFromDestinationCount;
|
|
383
|
+
// Calculate a percentage of dropped packets for the NAT GW
|
|
384
|
+
let packetDropPercentage = new aws_cloudwatch_1.MathExpression({
|
|
385
|
+
expression: `(${keyPrefix}1 / (${keyPrefix}2 + ${keyPrefix}3)) * 100`,
|
|
386
|
+
usingMetrics: usingMetrics,
|
|
387
|
+
label: availabilityZoneId + ' packet drop percentage',
|
|
388
|
+
period: props.period,
|
|
389
|
+
});
|
|
390
|
+
let threshold = props.packetLossImpactPercentageThreshold ?? 0.01;
|
|
391
|
+
// Create an alarm for this NAT GW if packet drops exceed the specified threshold
|
|
392
|
+
let packetDropImpactAlarm = new aws_cloudwatch_1.Alarm(this, 'AZ' + (index + 1) + 'PacketDropImpactAlarm', {
|
|
393
|
+
alarmName: availabilityZoneId +
|
|
394
|
+
'-' +
|
|
395
|
+
natgw.attrNatGatewayId +
|
|
396
|
+
'-packet-drop-impact',
|
|
397
|
+
actionsEnabled: false,
|
|
398
|
+
metric: packetDropPercentage,
|
|
399
|
+
threshold: threshold,
|
|
400
|
+
comparisonOperator: aws_cloudwatch_1.ComparisonOperator.GREATER_THAN_THRESHOLD,
|
|
401
|
+
evaluationPeriods: props.evaluationPeriods,
|
|
402
|
+
datapointsToAlarm: props.datapointsToAlarm,
|
|
403
|
+
});
|
|
404
|
+
// Collect all of the packet drop impact alarms for each
|
|
405
|
+
// NAT GW in this AZ, need to know at least 1 sees substantial
|
|
406
|
+
// enough impact to consider the AZ as impaired
|
|
407
|
+
packetDropPercentageAlarms[azLetter].push(packetDropImpactAlarm);
|
|
408
|
+
// Collect the packet drop metrics for this AZ so we can
|
|
409
|
+
// add them all together and count total packet drops
|
|
410
|
+
// for all NAT GWs in the AZ
|
|
411
|
+
packetDropMetricsForAZ[`m${index}`] = packetDropCount;
|
|
412
|
+
});
|
|
413
|
+
// Create a metric that adds up all packets drops from each
|
|
414
|
+
// NAT GW in the AZ
|
|
415
|
+
let packetDropsInThisAZ = new aws_cloudwatch_1.MathExpression({
|
|
416
|
+
expression: Object.keys(packetDropMetricsForAZ).join('+'),
|
|
417
|
+
usingMetrics: packetDropMetricsForAZ,
|
|
418
|
+
label: availabilityZoneId + ' dropped packets',
|
|
419
|
+
period: props.period,
|
|
420
|
+
});
|
|
421
|
+
// Record these so we can add them up
|
|
422
|
+
// and get a total amount of packet drops
|
|
423
|
+
// in the region across all AZs
|
|
424
|
+
this._packetDropsPerZone[azLetter] = packetDropsInThisAZ;
|
|
425
|
+
});
|
|
426
|
+
keyPrefix = AvailabilityAndLatencyMetrics_1.AvailabilityAndLatencyMetrics.nextChar(keyPrefix);
|
|
427
|
+
let tmp = {};
|
|
428
|
+
Object.keys(this._packetDropsPerZone).forEach((azLetter, index) => {
|
|
429
|
+
tmp[`${keyPrefix}${index}`] = this._packetDropsPerZone[azLetter];
|
|
430
|
+
});
|
|
431
|
+
// Calculate total packet drops for the region
|
|
432
|
+
let totalPacketDrops = new aws_cloudwatch_1.MathExpression({
|
|
433
|
+
expression: Object.keys(tmp).join('+'),
|
|
434
|
+
usingMetrics: tmp,
|
|
435
|
+
label: aws_cdk_lib_1.Fn.ref('AWS::Region') + ' dropped packets',
|
|
436
|
+
period: props.period,
|
|
437
|
+
});
|
|
438
|
+
if (props.outlierDetectionAlgorithm == OutlierDetectionAlgorithm_1.OutlierDetectionAlgorithm.STATIC) {
|
|
439
|
+
// Create outlier detection alarms by comparing packet
|
|
440
|
+
// drops in one AZ versus total packet drops in the region
|
|
441
|
+
Object.keys(this._packetDropsPerZone).forEach((azLetter, index) => {
|
|
442
|
+
let azIsOutlierForPacketDrops;
|
|
443
|
+
keyPrefix = AvailabilityAndLatencyMetrics_1.AvailabilityAndLatencyMetrics.nextChar(keyPrefix);
|
|
444
|
+
let availabilityZoneId = this.azMapper.availabilityZoneIdFromAvailabilityZoneLetter(azLetter);
|
|
445
|
+
// Determine if AZ is an outlier for faults by exceeding
|
|
446
|
+
// a static threshold
|
|
447
|
+
let outlierMetrics;
|
|
448
|
+
// These metrics will give the percent of faults for the AZ
|
|
449
|
+
let usingMetrics = {};
|
|
450
|
+
usingMetrics[`${keyPrefix}1`] = this._packetDropsPerZone[azLetter];
|
|
451
|
+
usingMetrics[`${keyPrefix}2`] = totalPacketDrops;
|
|
452
|
+
outlierMetrics = new aws_cloudwatch_1.MathExpression({
|
|
453
|
+
expression: `(${keyPrefix}1 / ${keyPrefix}2) * 100`,
|
|
454
|
+
usingMetrics: usingMetrics,
|
|
455
|
+
label: availabilityZoneId + ' percentage of dropped packets',
|
|
456
|
+
});
|
|
457
|
+
azIsOutlierForPacketDrops = new aws_cloudwatch_1.Alarm(this, 'AZ' + (index + 1) + 'NATGWDroppedPacketsOutlierAlarm', {
|
|
458
|
+
metric: outlierMetrics,
|
|
459
|
+
alarmName: availabilityZoneId + '-dropped-packets-outlier',
|
|
460
|
+
evaluationPeriods: props.evaluationPeriods,
|
|
461
|
+
datapointsToAlarm: props.datapointsToAlarm,
|
|
462
|
+
threshold: outlierThreshold,
|
|
463
|
+
actionsEnabled: false,
|
|
464
|
+
treatMissingData: aws_cloudwatch_1.TreatMissingData.IGNORE,
|
|
465
|
+
comparisonOperator: aws_cloudwatch_1.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD,
|
|
466
|
+
});
|
|
467
|
+
// In addition to being an outlier for packet drops, make sure
|
|
468
|
+
// the packet loss is substantial enough to trigger the alarm
|
|
469
|
+
// by making sure at least 1 NAT GW sees packet loss more than 0.01%
|
|
470
|
+
let azIsOutlierAndSeesImpact = new aws_cloudwatch_1.CompositeAlarm(this, 'AZ' + index + 'NATGWIsolatedImpact', {
|
|
471
|
+
compositeAlarmName: availabilityZoneId + '-isolated-natgw-impact',
|
|
472
|
+
alarmRule: aws_cloudwatch_1.AlarmRule.allOf(azIsOutlierForPacketDrops, aws_cloudwatch_1.AlarmRule.anyOf(...packetDropPercentageAlarms[azLetter])),
|
|
473
|
+
});
|
|
474
|
+
// Record these so they can be used in dashboard or for combination
|
|
475
|
+
// with AZ
|
|
476
|
+
this._natGWZonalIsolatedImpactAlarms[azLetter] =
|
|
477
|
+
azIsOutlierAndSeesImpact;
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
else {
|
|
481
|
+
Object.keys(props.natGateways).forEach((az, index) => {
|
|
482
|
+
let azLetter = az.substring(az.length - 1);
|
|
483
|
+
let availabilityZoneId = this.azMapper.availabilityZoneIdFromAvailabilityZoneLetter(azLetter);
|
|
484
|
+
// Iterate all NAT GWs in this AZ
|
|
485
|
+
let azIsOutlierForPacketDrops = AvailabilityAndLatencyAlarmsAndRules_1.AvailabilityAndLatencyAlarmsAndRules.createZonalFaultRateOutlierAlarmForNatGW(this, this.natGateways, availabilityZoneId, outlierThreshold, this.outlierDetectionFunction, props.outlierDetectionAlgorithm, this.azMapper, index, props.evaluationPeriods, props.datapointsToAlarm, '');
|
|
486
|
+
// In addition to being an outlier for packet drops, make sure
|
|
487
|
+
// the packet loss is substantial enough to trigger the alarm
|
|
488
|
+
// by making sure at least 1 NAT GW sees packet loss more than 0.01%
|
|
489
|
+
let azIsOutlierAndSeesImpact = new aws_cloudwatch_1.CompositeAlarm(this, 'AZ' + index + 'NATGWIsolatedImpact', {
|
|
490
|
+
compositeAlarmName: availabilityZoneId + '-isolated-natgw-impact',
|
|
491
|
+
alarmRule: aws_cloudwatch_1.AlarmRule.allOf(azIsOutlierForPacketDrops, aws_cloudwatch_1.AlarmRule.anyOf(...packetDropPercentageAlarms[azLetter])),
|
|
492
|
+
});
|
|
493
|
+
// Record these so they can be used in dashboard or for combination
|
|
494
|
+
// with AZ
|
|
495
|
+
this._natGWZonalIsolatedImpactAlarms[azLetter] =
|
|
496
|
+
azIsOutlierAndSeesImpact;
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
exports.BasicServiceMultiAZObservability = BasicServiceMultiAZObservability;
|
|
502
|
+
_a = JSII_RTTI_SYMBOL_1;
|
|
503
|
+
BasicServiceMultiAZObservability[_a] = { fqn: "@cdklabs/multi-az-observability.BasicServiceMultiAZObservability", version: "0.0.0-alpha.0" };
|
|
504
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQmFzaWNTZXJ2aWNlTXVsdGlBWk9ic2VydmFiaWxpdHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VydmljZXMvQmFzaWNTZXJ2aWNlTXVsdGlBWk9ic2VydmFiaWxpdHkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSxxRUFBcUU7QUFDckUsc0NBQXNDO0FBQ3RDLDZDQUFpQztBQUNqQywrREFZb0M7QUFFcEMsdUZBTWdEO0FBRWhELDJDQUF1QztBQUd2QyxpSEFBOEc7QUFDOUcsK0VBQTRFO0FBRTVFLCtFQUE0RTtBQUM1RSw0RkFBeUY7QUFDekYsNEZBQXlGO0FBQ3pGLHNGQUFtRjtBQUNuRixnRkFBNkU7QUFFN0U7OztHQUdHO0FBQ0gsTUFBYSxnQ0FDWCxTQUFRLHNCQUFTO0lBd0RqQixZQUNFLEtBQWdCLEVBQ2hCLEVBQVUsRUFDVixLQUE0QztRQUU1QyxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBRWpCLDhCQUE4QjtRQUM5QixJQUFJLENBQUMsV0FBVyxHQUFHLEtBQUssQ0FBQyxXQUFXLENBQUM7UUFDckMsSUFBSSxDQUFDLHdCQUF3QixHQUFHLEtBQUssQ0FBQyx3QkFBd0IsQ0FBQztRQUMvRCxJQUFJLENBQUMsV0FBVyxHQUFHLEtBQUssQ0FBQyxXQUFXLENBQUM7UUFDckMsSUFBSSxDQUFDLCtCQUErQixHQUFHLEVBQUUsQ0FBQztRQUMxQyxJQUFJLENBQUMsNkJBQTZCLEdBQUcsRUFBRSxDQUFDO1FBQ3hDLElBQUksQ0FBQyxrQ0FBa0MsR0FBRyxFQUFFLENBQUM7UUFDN0MsSUFBSSxDQUFDLG1CQUFtQixHQUFHLEVBQUUsQ0FBQztRQUM5QixJQUFJLENBQUMsY0FBYyxHQUFHLEVBQUUsQ0FBQztRQUV6QixJQUFJLGdCQUF3QixDQUFDO1FBRTdCLElBQUksQ0FBQyxLQUFLLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztZQUM1QixRQUFRLEtBQUssQ0FBQyx5QkFBeUIsRUFB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QixFQUFFLGtCQUFrQixHQUFHLHdCQUF3QjtvQkFDakUsU0FBUyxFQUFFLDBCQUFTLENBQUMsS0FBSyxDQUN4Qix5QkFBeUIsRUFDekIsMEJBQVMsQ0FBQyxLQUFLLENBQUMsR0FBRywwQkFBMEIsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUN6RDtpQkFDRixDQUNGLENBQUM7Z0JBRUYsbUVBQW1FO2dCQUNuRSxVQUFVO2dCQUNWLElBQUksQ0FBQywrQkFBK0IsQ0FBQyxRQUFRLENBQUM7b0JBQzVDLHdCQUF3QixDQUFDO1lBQzdCLENBQUMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztJQUNILENBQUM7O0FBL3ZCSCw0RUFnd0JDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IEFtYXpvbi5jb20sIEluYy4gb3IgaXRzIGFmZmlsaWF0ZXMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuaW1wb3J0IHsgRm4gfSBmcm9tICdhd3MtY2RrLWxpYic7XG5pbXBvcnQge1xuICBBbGFybSxcbiAgQWxhcm1SdWxlLFxuICBDb21wYXJpc29uT3BlcmF0b3IsXG4gIENvbXBvc2l0ZUFsYXJtLFxuICBEYXNoYm9hcmQsXG4gIElBbGFybSxcbiAgSU1ldHJpYyxcbiAgTWF0aEV4cHJlc3Npb24sXG4gIE1ldHJpYyxcbiAgVHJlYXRNaXNzaW5nRGF0YSxcbiAgVW5pdCxcbn0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWNsb3Vkd2F0Y2gnO1xuaW1wb3J0IHsgQ2ZuTmF0R2F0ZXdheSB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1lYzInO1xuaW1wb3J0IHtcbiAgQmFzZUxvYWRCYWxhbmNlcixcbiAgSHR0cENvZGVFbGIsXG4gIEh0dHBDb2RlVGFyZ2V0LFxuICBJQXBwbGljYXRpb25Mb2FkQmFsYW5jZXIsXG4gIElMb2FkQmFsYW5jZXJWMixcbn0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWVsYXN0aWNsb2FkYmFsYW5jaW5ndjInO1xuaW1wb3J0IHsgSUZ1bmN0aW9uIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWxhbWJkYSc7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcbmltcG9ydCB7IElCYXNpY1NlcnZpY2VNdWx0aUFaT2JzZXJ2YWJpbGl0eSB9IGZyb20gJy4vSUJhc2ljU2VydmljZU11bHRpQVpPYnNlcnZhYmlsaXR5JztcbmltcG9ydCB7IEJhc2ljU2VydmljZU11bHRpQVpPYnNlcnZhYmlsaXR5UHJvcHMgfSBmcm9tICcuL3Byb3BzL0Jhc2ljU2VydmljZU11bHRpQVpPYnNlcnZhYmlsaXR5UHJvcHMnO1xuaW1wb3J0IHsgQXZhaWxhYmlsaXR5QW5kTGF0ZW5jeUFsYXJtc0FuZFJ1bGVzIH0gZnJvbSAnLi4vYWxhcm1zYW5kcnVsZXMvQXZhaWxhYmlsaXR5QW5kTGF0ZW5jeUFsYXJtc0FuZFJ1bGVzJztcbmltcG9ydCB7IEF2YWlsYWJpbGl0eVpvbmVNYXBwZXIgfSBmcm9tICcuLi9hem1hcHBlci9BdmFpbGFiaWxpdHlab25lTWFwcGVyJztcbmltcG9ydCB7IElBdmFpbGFiaWxpdHlab25lTWFwcGVyIH0gZnJvbSAnLi4vYXptYXBwZXIvSUF2YWlsYWJpbGl0eVpvbmVNYXBwZXInO1xuaW1wb3J0IHsgQmFzaWNTZXJ2aWNlRGFzaGJvYXJkIH0gZnJvbSAnLi4vZGFzaGJvYXJkcy9CYXNpY1NlcnZpY2VEYXNoYm9hcmQnO1xuaW1wb3J0IHsgQXZhaWxhYmlsaXR5QW5kTGF0ZW5jeU1ldHJpY3MgfSBmcm9tICcuLi9tZXRyaWNzL0F2YWlsYWJpbGl0eUFuZExhdGVuY3lNZXRyaWNzJztcbmltcG9ydCB7IE91dGxpZXJEZXRlY3Rpb25GdW5jdGlvbiB9IGZyb20gJy4uL291dGxpZXItZGV0ZWN0aW9uL091dGxpZXJEZXRlY3Rpb25GdW5jdGlvbic7XG5pbXBvcnQgeyBPdXRsaWVyRGV0ZWN0aW9uQWxnb3JpdGhtIH0gZnJvbSAnLi4vdXRpbGl0aWVzL091dGxpZXJEZXRlY3Rpb25BbGdvcml0aG0nO1xuaW1wb3J0IHsgU3RhY2tXaXRoRHluYW1pY1NvdXJjZSB9IGZyb20gJy4uL3V0aWxpdGllcy9TdGFja1dpdGhEeW5hbWljU291cmNlJztcblxuLyoqXG4gKiBCYXNpYyBvYnNlcnZhYmlsaXR5IGZvciBhIHNlcnZpY2UgdXNpbmcgbWV0cmljcyBmcm9tXG4gKiBBTEJzIGFuZCBOQVQgR2F0ZXdheXNcbiAqL1xuZXhwb3J0IGNsYXNzIEJhc2ljU2VydmljZU11bHRpQVpPYnNlcnZhYmlsaXR5XG4gIGV4dGVuZHMgQ29uc3RydWN0XG4gIGltcGxlbWVudHMgSUJhc2ljU2VydmljZU11bHRpQVpPYnNlcnZhYmlsaXR5IHtcbiAgLyoqXG4gICAqIFRoZSBOQVQgR2F0ZXdheXMgYmVpbmcgdXNlZCBpbiB0aGUgc2VydmljZSwgZWFjaCBzZXQgb2YgTkFUIEdhdGV3YXlzXG4gICAqIGFyZSBrZXllZCBieSB0aGVpciBBdmFpbGFiaWxpdHkgWm9uZSBJZFxuICAgKi9cbiAgbmF0R2F0ZXdheXM/OiB7IFtrZXk6IHN0cmluZ106IENmbk5hdEdhdGV3YXlbXSB9O1xuXG4gIC8qKlxuICAgKiBUaGUgYXBwbGljYXRpb24gbG9hZCBiYWxhbmNlcnMgYmVpbmcgdXNlZCBieSB0aGUgc2VydmljZVxuICAgKi9cbiAgYXBwbGljYXRpb25Mb2FkQmFsYW5jZXJzPzogSUFwcGxpY2F0aW9uTG9hZEJhbGFuY2VyW107XG5cbiAgLyoqXG4gICAqIFRoZSBuYW1lIG9mIHRoZSBzZXJ2aWNlXG4gICAqL1xuICBzZXJ2aWNlTmFtZTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgYWxhcm1zIGluZGljYXRpbmcgaWYgYW4gQVogaXMgYW4gb3V0bGllciBmb3IgTkFUIEdXXG4gICAqIHBhY2tldCBsb3NzIGFuZCBoYXMgaXNvbGF0ZWQgaW1wYWN0XG4gICAqL1xuICBuYXRHV1pvbmFsSXNvbGF0ZWRJbXBhY3RBbGFybXM/OiB7IFtrZXk6IHN0cmluZ106IElBbGFybSB9O1xuXG4gIC8qKlxuICAgKiBUaGUgYWxhcm1zIGluZGljYXRpbmcgaWYgYW4gQVogaXMgYW4gb3V0bGllciBmb3IgQUxCXG4gICAqIGZhdWx0cyBhbmQgaGFzIGlzb2xhdGVkIGltcGFjdFxuICAgKi9cbiAgYWxiWm9uYWxJc29sYXRlZEltcGFjdEFsYXJtcz86IHsgW2tleTogc3RyaW5nXTogSUFsYXJtIH07XG5cbiAgLyoqXG4gICAqIFRoZSBhbGFybXMgaW5kaWNhdGluZyBpZiBhbiBBWiBoYXMgaXNvbGF0ZWQgaW1wYWN0XG4gICAqIGZyb20gZWl0aGVyIEFMQiBvciBOQVQgR1cgbWV0cmljc1xuICAgKi9cbiAgYWdncmVnYXRlWm9uYWxJc29sYXRlZEltcGFjdEFsYXJtczogeyBba2V5OiBzdHJpbmddOiBJQWxhcm0gfTtcblxuICAvKipcbiAgICogVGhlIGRhc2hib2FyZCB0aGF0IGlzIG9wdGlvbmFsbHkgY3JlYXRlZFxuICAgKi9cbiAgZGFzaGJvYXJkPzogRGFzaGJvYXJkO1xuXG4gIC8qKlxuICAgKiBUaGUgY2hpLXNxdWFyZWQgZnVuY3Rpb25cbiAgICovXG4gIHByaXZhdGUgb3V0bGllckRldGVjdGlvbkZ1bmN0aW9uPzogSUZ1bmN0aW9uO1xuXG4gIHByaXZhdGUgYXpNYXBwZXI6IElBdmFpbGFiaWxpdHlab25lTWFwcGVyO1xuXG4gIHByaXZhdGUgX25hdEdXWm9uYWxJc29sYXRlZEltcGFjdEFsYXJtczogeyBba2V5OiBzdHJpbmddOiBJQWxhcm0gfTtcblxuICBwcml2YXRlIF9hbGJab25hbElzb2xhdGVkSW1wYWN0QWxhcm1zOiB7IFtrZXk6IHN0cmluZ106IElBbGFybSB9O1xuXG4gIHByaXZhdGUgX3BhY2tldERyb3BzUGVyWm9uZTogeyBba2V5OiBzdHJpbmddOiBJTWV0cmljIH07XG5cbiAgcHJpdmF0ZSBfZmF1bHRzUGVyWm9uZTogeyBba2V5OiBzdHJpbmddOiBJTWV0cmljIH07XG5cbiAgY29uc3RydWN0b3IoXG4gICAgc2NvcGU6IENvbnN0cnVjdCxcbiAgICBpZDogc3RyaW5nLFxuICAgIHByb3BzOiBCYXNpY1NlcnZpY2VNdWx0aUFaT2JzZXJ2YWJpbGl0eVByb3BzLFxuICApIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgLy8gSW5pdGlhbGl6ZSBjbGFzcyBwcm9wZXJ0aWVzXG4gICAgdGhpcy5zZXJ2aWNlTmFtZSA9IHByb3BzLnNlcnZpY2VOYW1lO1xuICAgIHRoaXMuYXBwbGljYXRpb25Mb2FkQmFsYW5jZXJzID0gcHJvcHMuYXBwbGljYXRpb25Mb2FkQmFsYW5jZXJzO1xuICAgIHRoaXMubmF0R2F0ZXdheXMgPSBwcm9wcy5uYXRHYXRld2F5cztcbiAgICB0aGlzLl9uYXRHV1pvbmFsSXNvbGF0ZWRJbXBhY3RBbGFybXMgPSB7fTtcbiAgICB0aGlzLl9hbGJab25hbElzb2xhdGVkSW1wYWN0QWxhcm1zID0ge307XG4gICAgdGhpcy5hZ2dyZWdhdGVab25hbElzb2xhdGVkSW1wYWN0QWxhcm1zID0ge307XG4gICAgdGhpcy5fcGFja2V0RHJvcHNQZXJab25lID0ge307XG4gICAgdGhpcy5fZmF1bHRzUGVyWm9uZSA9IHt9O1xuXG4gICAgbGV0IG91dGxpZXJUaHJlc2hvbGQ6IG51bWJlcjtcblxuICAgIGlmICghcHJvcHMub3V0bGllclRocmVzaG9sZCkge1xuICAgICAgc3dpdGNoIChwcm9wcy5vdXRsaWVyRGV0ZWN0aW9uQWxnb3JpdGhtKSB7XG4gICAgICAgIGNhc2UgT3V0bGllckRldGVjdGlvbkFsZ29yaXRobS5DSElfU1FVQVJFRDpcbiAgICAgICAgICBvdXRsaWVyVGhyZXNob2xkID0gMC4wNTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSBPdXRsaWVyRGV0ZWN0aW9uQWxnb3JpdGhtLklRUjpcbiAgICAgICAgICBvdXRsaWVyVGhyZXNob2xkID0gMS41O1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIE91dGxpZXJEZXRlY3Rpb25BbGdvcml0aG0uTUFEOlxuICAgICAgICAgIG91dGxpZXJUaHJlc2hvbGQgPSAzO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIE91dGxpZXJEZXRlY3Rpb25BbGdvcml0aG0uU1RBVElDOlxuICAgICAgICAgIG91dGxpZXJUaHJlc2hvbGQgPSAwLjc7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgT3V0bGllckRldGVjdGlvbkFsZ29yaXRobS5aX1NDT1JFOlxuICAgICAgICAgIG91dGxpZXJUaHJlc2hvbGQgPSAyO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBvdXRsaWVyVGhyZXNob2xkID0gcHJvcHMub3V0bGllclRocmVzaG9sZDtcbiAgICB9XG5cbiAgICAvLyBDcmVhdGUgdGhlIEFaIG1hcHBlciByZXNvdXJjZSB0byB0cmFuc2xhdGUgQVogbmFtZXMgdG8gaWRzXG4gICAgdGhpcy5hek1hcHBlciA9IG5ldyBBdmFpbGFiaWxpdHlab25lTWFwcGVyKHRoaXMsICdBdmFpbGFiaWxpdHlab25lTWFwcGVyJyk7XG5cbiAgICBpZiAocHJvcHMub3V0bGllckRldGVjdGlvbkFsZ29yaXRobSAhPSBPdXRsaWVyRGV0ZWN0aW9uQWxnb3JpdGhtLlNUQVRJQykge1xuICAgICAgbGV0IG91dGxpZXJEZXRlY3Rpb25TdGFjazogU3RhY2tXaXRoRHluYW1pY1NvdXJjZSA9XG4gICAgICAgIG5ldyBTdGFja1dpdGhEeW5hbWljU291cmNlKHRoaXMsICdPdXRsaWVyRGV0ZWN0aW9uU3RhY2snLCB7XG4gICAgICAgICAgYXNzZXRzQnVja2V0c1BhcmFtZXRlck5hbWU6IHByb3BzLmFzc2V0c0J1Y2tldFBhcmFtZXRlck5hbWUsXG4gICAgICAgICAgYXNzZXRzQnVja2V0UHJlZml4UGFyYW1ldGVyTmFtZTpcbiAgICAgICAgICAgIHByb3BzLmFzc2V0c0J1Y2tldFByZWZpeFBhcmFtZXRlck5hbWUsXG4gICAgICAgIH0pO1xuXG4gICAgICB0aGlzLm91dGxpZXJEZXRlY3Rpb25GdW5jdGlvbiA9IG5ldyBPdXRsaWVyRGV0ZWN0aW9uRnVuY3Rpb24oXG4gICAgICAgIG91dGxpZXJEZXRlY3Rpb25TdGFjayxcbiAgICAgICAgJ091dGxpZXJEZXRlY3Rpb25GdW5jdGlvbicsXG4gICAgICAgIHt9LFxuICAgICAgKS5mdW5jdGlvbjtcbiAgICB9XG5cbiAgICAvLyBDcmVhdGUgbWV0cmljcyBhbmQgYWxhcm1zIGZvciBqdXN0IGxvYWQgYmFsYW5jZXJzIGlmIHRoZXkgd2VyZSBwcm92aWRlZFxuICAgIGlmIChcbiAgICAgIHRoaXMuYXBwbGljYXRpb25Mb2FkQmFsYW5jZXJzICE9PSB1bmRlZmluZWQgJiZcbiAgICAgIHRoaXMuYXBwbGljYXRpb25Mb2FkQmFsYW5jZXJzICE9IG51bGxcbiAgICApIHtcbiAgICAgIHRoaXMuZG9BbGJNZXRyaWNzKHByb3BzLCBvdXRsaWVyVGhyZXNob2xkKTtcbiAgICB9XG5cbiAgICAvLyBDcmVhdGUgTkFUIEdhdGV3YXkgbWV0cmljcyBhbmQgYWxhcm1zXG4gICAgaWYgKHRoaXMubmF0R2F0ZXdheXMgIT09IHVuZGVmaW5lZCAmJiB0aGlzLm5hdEdhdGV3YXlzICE9IG51bGwpIHtcbiAgICAgIHRoaXMuZG9OYXRHYXRld2F5TWV0cmljcyhwcm9wcywgb3V0bGllclRocmVzaG9sZCk7XG4gICAgfVxuXG4gICAgbGV0IGNvdW50ZXI6IG51bWJlciA9IDE7XG4gICAgLy8gR28gdGhyb3VnaCB0aGUgQUxCIHpvbmFsIGlzb2xhdGVkIGltcGFjdCBhbGFybXMgYW5kIHNlZSBpZiB0aGVyZSBpcyBhIE5BVCBHV1xuICAgIC8vIGlzb2xhdGVkIGltcGFjdCBhbGFybSBmb3IgdGhlIHNhbWUgQVogSUQsIGlmIHNvLCBjcmVhdGUgYSBjb21wb3NpdGUgYWxhcm0gd2l0aCBib3RoXG4gICAgLy8gb3RoZXJ3aXNlIGNyZWF0ZSBhIGNvbXBvc2l0ZSBhbGFybSB3aXRoIGp1c3QgdGhlIEFMQlxuICAgIE9iamVjdC5rZXlzKHRoaXMuX2FsYlpvbmFsSXNvbGF0ZWRJbXBhY3RBbGFybXMpLmZvckVhY2goKGF6OiBzdHJpbmcpID0+IHtcbiAgICAgIGxldCB0bXA6IElBbGFybVtdID0gW107XG4gICAgICB0bXAucHVzaCh0aGlzLl9hbGJab25hbElzb2xhdGVkSW1wYWN0QWxhcm1zW2F6XSk7XG4gICAgICBpZiAoXG4gICAgICAgIHRoaXMuX25hdEdXWm9uYWxJc29sYXRlZEltcGFjdEFsYXJtc1thel0gIT09IHVuZGVmaW5lZCAmJlxuICAgICAgICB0aGlzLl9uYXRHV1pvbmFsSXNvbGF0ZWRJbXBhY3RBbGFybXNbYXpdICE9IG51bGxcbiAgICAgICkge1xuICAgICAgICB0bXAucHVzaCh0aGlzLl9uYXRHV1pvbmFsSXNvbGF0ZWRJbXBhY3RBbGFybXNbYXpdKTtcbiAgICAgIH1cbiAgICAgIGxldCBhdmFpbGFiaWxpdHlab25lSWQ6IHN0cmluZyA9XG4gICAgICAgIHRoaXMuYXpNYXBwZXIuYXZhaWxhYmlsaXR5Wm9uZUlkRnJvbUF2YWlsYWJpbGl0eVpvbmVMZXR0ZXIoXG4gICAgICAgICAgYXouc3Vic3RyaW5nKGF6Lmxlbmd0aCAtIDEpLFxuICAgICAgICApO1xuXG4gICAgICB0aGlzLmFnZ3JlZ2F0ZVpvbmFsSXNvbGF0ZWRJbXBhY3RBbGFybXNbYXpdID0gbmV3IENvbXBvc2l0ZUFsYXJtKFxuICAgICAgICB0aGlzLFxuICAgICAgICAnQVonICsgY291bnRlcisrICsgJ0FnZ3JlZ2F0ZUlzb2xhdGVkSW1wYWN0QWxhcm0nLFxuICAgICAgICB7XG4gICAgICAgICAgY29tcG9zaXRlQWxhcm1OYW1lOiBhdmFpbGFiaWxpdHlab25lSWQgKyAnLWFnZ3JlZ2F0ZS1pc29sYXRlZC1pbXBhY3QnLFxuICAgICAgICAgIGFsYXJtUnVsZTogQWxhcm1SdWxlLmFueU9mKC4uLnRtcCksXG4gICAgICAgICAgYWN0aW9uc0VuYWJsZWQ6IGZhbHNlLFxuICAgICAgICB9LFxuICAgICAgKTtcbiAgICB9KTtcblxuICAgIC8vIEluIGNhc2UgdGhlcmUgd2VyZSBBWnMgd2l0aCBvbmx5IGEgTkFUIEdXIGFuZCBubyBBTEIsIGNyZWF0ZSBhIGNvbXBvc2l0ZSBhbGFybVxuICAgIC8vIGZvciB0aGUgTkFUIEdXIG1ldHJpY3NcbiAgICBPYmplY3Qua2V5cyh0aGlzLl9uYXRHV1pvbmFsSXNvbGF0ZWRJbXBhY3RBbGFybXMpLmZvckVhY2goKGF6OiBzdHJpbmcpID0+IHtcbiAgICAgIC8vIElmIHdlIGRvbid0IHlldCBoYXZlIGFuIGlzb2xhdGVkIGltcGFjdCBhbGFybSBmb3IgdGhpcyBBWiwgcHJvY2VlZFxuICAgICAgaWYgKFxuICAgICAgICB0aGlzLmFnZ3JlZ2F0ZVpvbmFsSXNvbGF0ZWRJbXBhY3RBbGFybXNbYXpdID09PSB1bmRlZmluZWQgfHxcbiAgICAgICAgdGhpcy5hZ2dyZWdhdGVab25hbElzb2xhdGVkSW1wYWN0QWxhcm1zW2F6XSA9PSBudWxsXG4gICAgICApIHtcbiAgICAgICAgbGV0IHRtcDogSUFsYXJtW10gPSBbXTtcbiAgICAgICAgdG1wLnB1c2godGhpcy5fbmF0R1dab25hbElzb2xhdGVkSW1wYWN0QWxhcm1zW2F6XSk7XG5cbiAgICAgICAgaWYgKFxuICAgICAgICAgIHRoaXMuX2FsYlpvbmFsSXNvbGF0ZWRJbXBhY3RBbGFybXNbYXpdICE9PSB1bmRlZmluZWQgJiZcbiAgICAgICAgICB0aGlzLmFsYlpvbmFsSXNvbGF0ZWRJbXBhY3RBbGFybXMgIT0gbnVsbFxuICAgICAgICApIHtcbiAgICAgICAgICB0bXAucHVzaCh0aGlzLmFsYlpvbmFsSXNvbGF0ZWRJbXBhY3RBbGFybXNbYXpdKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBhdmFpbGFiaWxpdHlab25lSWQ6IHN0cmluZyA9XG4gICAgICAgICAgdGhpcy5hek1hcHBlci5hdmFpbGFiaWxpdHlab25lSWRGcm9tQXZhaWxhYmlsaXR5Wm9uZUxldHRlcihcbiAgICAgICAgICAgIGF6LnN1YnN0cmluZyhhei5sZW5ndGggLSAxKSxcbiAgICAgICAgICApO1xuXG4gICAgICAgIHRoaXMuYWdncmVnYXRlWm9uYWxJc29sYXRlZEltcGFjdEFsYXJtc1thel0gPSBuZXcgQ29tcG9zaXRlQWxhcm0oXG4gICAgICAgICAgdGhpcyxcbiAgICAgICAgICAnQVonICsgY291bnRlcisrICsgJ0FnZ3JlZ2F0ZUlzb2xhdGVkSW1wYWN0QWxhcm0nLFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGNvbXBvc2l0ZUFsYXJtTmFtZTpcbiAgICAgICAgICAgICAgYXZhaWxhYmlsaXR5Wm9uZUlkICsgJy1hZ2dyZWdhdGUtaXNvbGF0ZWQtaW1wYWN0JyxcbiAgICAgICAgICAgIGFsYXJtUnVsZTogQWxhcm1SdWxlLmFueU9mKC4uLnRtcCksXG4gICAgICAgICAgICBhY3Rpb25zRW5hYmxlZDogZmFsc2UsXG4gICAgICAgICAgfSxcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRoaXMuYWxiWm9uYWxJc29sYXRlZEltcGFjdEFsYXJtcyA9IHRoaXMuX2FsYlpvbmFsSXNvbGF0ZWRJbXBhY3RBbGFybXM7XG4gICAgdGhpcy5uYXRHV1pvbmFsSXNvbGF0ZWRJbXBhY3RBbGFybXMgPSB0aGlzLl9uYXRHV1pvbmFsSXNvbGF0ZWRJbXBhY3RBbGFybXM7XG5cbiAgICAvLyBTaG91bGQgd2UgY3JlYXRlIHRoZSBkYXNoYm9hcmRcbiAgICBpZiAocHJvcHMuY3JlYXRlRGFzaGJvYXJkID09IHRydWUpIHtcbiAgICAgIHRoaXMuZGFzaGJvYXJkID0gbmV3IEJhc2ljU2VydmljZURhc2hib2FyZChcbiAgICAgICAgdGhpcyxcbiAgICAgICAgJ0Jhc2ljU2VydmljZURhc2hib2FyZCcsXG4gICAgICAgIHtcbiAgICAgICAgICBzZXJ2aWNlTmFtZTogcHJvcHMuc2VydmljZU5hbWUudG9Mb3dlckNhc2UoKSxcbiAgICAgICAgICB6b25hbEFnZ3JlZ2F0ZUlzb2xhdGVkSW1wYWN0QWxhcm1zOlxuICAgICAgICAgICAgdGhpcy5hZ2dyZWdhdGVab25hbElzb2xhdGVkSW1wYWN0QWxhcm1zLFxuICAgICAgICAgIHpvbmFsTG9hZEJhbGFuY2VySXNvbGF0ZWRJbXBhY3RBbGFybXM6XG4gICAgICAgICAgICB0aGlzLmFsYlpvbmFsSXNvbGF0ZWRJbXBhY3RBbGFybXMsXG4gICAgICAgICAgem9uYWxOYXRHYXRld2F5SXNvbGF0ZWRJbXBhY3RBbGFybXM6XG4gICAgICAgICAgICB0aGlzLm5hdEdXWm9uYWxJc29sYXRlZEltcGFjdEFsYXJtcyxcbiAgICAgICAgICBpbnRlcnZhbDogcHJvcHMuaW50ZXJ2YWwsXG4gICAgICAgICAgem9uYWxMb2FkQmFsYW5jZXJGYXVsdFJhdGVNZXRyaWNzOiB0aGlzLl9mYXVsdHNQZXJab25lLFxuICAgICAgICAgIHpvbmFsTmF0R2F0ZXdheVBhY2tldERyb3BNZXRyaWNzOiB0aGlzLl9wYWNrZXREcm9wc1BlclpvbmUsXG4gICAgICAgICAgYXpNYXBwZXI6IHRoaXMuYXpNYXBwZXIsXG4gICAgICAgIH0sXG4gICAgICApLmRhc2hib2FyZDtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGRvQWxiTWV0cmljcyhcbiAgICBwcm9wczogQmFzaWNTZXJ2aWNlTXVsdGlBWk9ic2VydmFiaWxpdHlQcm9wcyxcbiAgICBvdXRsaWVyVGhyZXNob2xkOiBudW1iZXIsXG4gICkge1xuICAgIC8vIENvbGxlY3QgdG90YWwgZmF1bHQgY291bnQgbWV0cmljcyBwZXIgQVpcbiAgICBsZXQgYWxiWm9uZUZhdWx0Q291bnRNZXRyaWNzOiB7IFtrZXk6IHN0cmluZ106IElNZXRyaWNbXSB9ID0ge307XG5cbiAgICAvLyBDcmVhdGUgZmF1bHQgcmF0ZSBhbGFybXMgcGVyIEFaIGluZGljYXRpbmcgYXQgbGVhc3QgMSBBTEJcbiAgICAvLyBpbiB0aGUgQVogc2F3IGEgZmF1bHQgcmF0ZSB0aGF0IGV4Y2VlZGVkIHRoZSB0aHJlc2hvbGRcbiAgICBsZXQgZmF1bHRSYXRlUGVyY2VudGFnZUFsYXJtczogeyBba2V5OiBzdHJpbmddOiBJQWxhcm1bXSB9ID0ge307XG5cbiAgICBsZXQga2V5UHJlZml4OiBzdHJpbmcgPSBBdmFpbGFiaWxpdHlBbmRMYXRlbmN5TWV0cmljcy5uZXh0Q2hhcignJyk7XG5cbiAgICAvLyBJdGVyYXRlIGVhY2ggQUxCXG4gICAgdGhpcy5hcHBsaWNhdGlvbkxvYWRCYWxhbmNlcnMhLmZvckVhY2goKGFsYikgPT4ge1xuICAgICAgLy8gSXRlcmF0ZSBlYWNoIEFaIGluIHRoZSBWUENcbiAgICAgIGFsYi52cGM/LmF2YWlsYWJpbGl0eVpvbmVzLmZvckVhY2goKGF6LCBpbmRleCkgPT4ge1xuICAgICAgICBsZXQgYXpMZXR0ZXIgPSBhei5zdWJzdHJpbmcoYXoubGVuZ3RoIC0gMSk7XG5cbiAgICAgICAgbGV0IGF2YWlsYWJpbGl0eVpvbmVJZDogc3RyaW5nID1cbiAgICAgICAgICB0aGlzLmF6TWFwcGVyLmF2YWlsYWJpbGl0eVpvbmVJZEZyb21BdmFpbGFiaWxpdHlab25lTGV0dGVyKGF6TGV0dGVyKTtcbiAgICAgICAgZmF1bHRSYXRlUGVyY2VudGFnZUFsYXJtc1thekxldHRlcl0gPSBbXTtcblxuICAgICAgICAvLyA1eHggcmVzcG9uc2VzIGZyb20gdGFyZ2V0c1xuICAgICAgICBsZXQgdGFyZ2V0NXh4OiBJTWV0cmljID0gYWxiLm1ldHJpY3MuaHR0cENvZGVUYXJnZXQoXG4gICAgICAgICAgSHR0cENvZGVUYXJnZXQuVEFSR0VUXzVYWF9DT1VOVCxcbiAgICAgICAgICB7XG4gICAgICAgICAgICBkaW1lbnNpb25zTWFwOiB7XG4gICAgICAgICAgICAgIEF2YWlsYWJpbGl0eVpvbmU6IGF6LFxuICAgICAgICAgICAgICBMb2FkQmFsYW5jZXI6IChhbGIgYXMgSUxvYWRCYWxhbmNlclYyIGFzIEJhc2VMb2FkQmFsYW5jZXIpXG4gICAgICAgICAgICAgICAgLmxvYWRCYWxhbmNlckZ1bGxOYW1lLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGxhYmVsOiBhdmFpbGFiaWxpdHlab25lSWQsXG4gICAgICAgICAgICBwZXJpb2Q6IHByb3BzLnBlcmlvZCxcbiAgICAgICAgICB9LFxuICAgICAgICApO1xuXG4gICAgICAgIC8vIDV4eCByZXNwb25zZXMgZnJvbSBFTEJcbiAgICAgICAgbGV0IGVsYjV4eDogSU1ldHJpYyA9IGFsYi5tZXRyaWNzLmh0dHBDb2RlRWxiKFxuICAgICAgICAgIEh0dHBDb2RlRWxiLkVMQl81WFhfQ09VTlQsXG4gICAgICAgICAge1xuICAgICAgICAgICAgZGltZW5zaW9uc01hcDoge1xuICAgICAgICAgICAgICBBdmFpbGFiaWxpdHlab25lOiBheixcbiAgICAgICAgICAgICAgTG9hZEJhbGFuY2VyOiAoYWxiIGFzIElMb2FkQmFsYW5jZXJWMiBhcyBCYXNlTG9hZEJhbGFuY2VyKVxuICAgICAgICAgICAgICAgIC5sb2FkQmFsYW5jZXJGdWxsTmFtZSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBsYWJlbDogYXZhaWxhYmlsaXR5Wm9uZUlkLFxuICAgICAgICAgICAgcGVyaW9kOiBwcm9wcy5wZXJpb2QsXG4gICAgICAgICAgfSxcbiAgICAgICAgKTtcblxuICAgICAgICAvLyAyeHggcmVzcG9uc2VzIGZyb20gdGFyZ2V0c1xuICAgICAgICBsZXQgdGFyZ2V0Mnh4OiBJTWV0cmljID0gYWxiLm1ldHJpY3MuaHR0cENvZGVUYXJnZXQoXG4gICAgICAgICAgSHR0cENvZGVUYXJnZXQuVEFSR0VUXzJYWF9DT1VOVCxcbiAgICAgICAgICB7XG4gICAgICAgICAgICBkaW1lbnNpb25zTWFwOiB7XG4gICAgICAgICAgICAgIEF2YWlsYWJpbGl0eVpvbmU6IGF6LFxuICAgICAgICAgICAgICBMb2FkQmFsYW5jZXI6IChhbGIgYXMgSUxvYWRCYWxhbmNlclYyIGFzIEJhc2VMb2FkQmFsYW5jZXIpXG4gICAgICAgICAgICAgICAgLmxvYWRCYWxhbmNlckZ1bGxOYW1lLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGxhYmVsOiBhdmFpbGFiaWxpdHlab25lSWQsXG4gICAgICAgICAgICBwZXJpb2Q6IHByb3BzLnBlcmlvZCxcbiAgICAgICAgICB9LFxuICAgICAgICApO1xuXG4gICAgICAgIC8vIDN4eCByZXNwb25zZXMgZnJvbSB0YXJnZXRzXG4gICAgICAgIGxldCB0YXJnZXQzeHg6IElNZXRyaWMgPSBhbGIubWV0cmljcy5odHRwQ29kZVRhcmdldChcbiAgICAgICAgICBIdHRwQ29kZVRhcmdldC5UQVJHRVRfM1hYX0NPVU5ULFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGRpbWVuc2lvbnNNYXA6IHtcbiAgICAgICAgICAgICAgQXZhaWxhYmlsaXR5Wm9uZTogYXosXG4gICAgICAgICAgICAgIExvYWRCYWxhbmNlcjogKGFsYiBhcyBJTG9hZEJhbGFuY2VyVjIgYXMgQmFzZUxvYWRCYWxhbmNlcilcbiAgICAgICAgICAgICAgICAubG9hZEJhbGFuY2VyRnVsbE5hbWUsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgbGFiZWw6IGF2YWlsYWJpbGl0eVpvbmVJZCxcbiAgICAgICAgICAgIHBlcmlvZDogcHJvcHMucGVyaW9kLFxuICAgICAgICAgIH0sXG4gICAgICAgICk7XG5cbiAgICAgICAgLy8gM3h4IHJlc3BvbmVzcyBmcm9tIEVMQlxuICAgICAgICBsZXQgZWxiM3h4OiBJTWV0cmljID0gYWxiLm1ldHJpY3MuaHR0cENvZGVFbGIoXG4gICAgICAgICAgSHR0cENvZGVFbGIuRUxCXzNYWF9DT1VOVCxcbiAgICAgICAgICB7XG4gICAgICAgICAgICBkaW1lbnNpb25zTWFwOiB7XG4gICAgICAgICAgICAgIEF2YWlsYWJpbGl0eVpvbmU6IGF6LFxuICAgICAgICAgICAgICBMb2FkQmFsYW5jZXI6IChhbGIgYXMgSUxvYWRCYWxhbmNlclYyIGFzIEJhc2VMb2FkQmFsYW5jZXIpXG4gICAgICAgICAgICAgICAgLmxvYWRCYWxhbmNlckZ1bGxOYW1lLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGxhYmVsOiBhdmFpbGFiaWxpdHlab25lSWQsXG4gICAgICAgICAgICBwZXJpb2Q6IHByb3BzLnBlcmlvZCxcbiAgICAgICAgICB9LFxuICAgICAgICApO1xuXG4gICAgICAgIC8vIENyZWF0ZSBtZXRyaWNzIGZvciB0b3RhbCBmYXVsdCBjb3VudCBmcm9tIHRoaXMgQUxCXG4gICAgICAgIGxldCB1c2luZ01ldHJpY3M6IHsgW2tleTogc3RyaW5nXTogSU1ldHJpYyB9ID0ge307XG4gICAgICAgIHVzaW5nTWV0cmljc1tgJHtrZXlQcmVmaXh9MWBdID0gdGFyZ2V0NXh4O1xuICAgICAgICB1c2luZ01ldHJpY3NbYCR7a2V5UHJlZml4fTJgXSA9IGVsYjV4eDtcblxuICAgICAgICBpZiAoXG4gICAgICAgICAgYWxiWm9uZUZhdWx0Q291bnRNZXRyaWNzW2F6TGV0dGVyXSA9PT0gdW5kZWZpbmVkIHx8XG4gICAgICAgICAgYWxiWm9uZUZhdWx0Q291bnRNZXRyaWNzW2F6TGV0dGVyXSA9PSBudWxsXG4gICAgICAgICkge1xuICAgICAgICAgIGFsYlpvbmVGYXVsdENvdW50TWV0cmljc1thekxldHRlcl0gPSBbXTtcbiAgICAgICAgfVxuXG4gICAgICAgIGFsYlpvbmVGYXVsdENvdW50TWV0cmljc1thekxldHRlcl0ucHVzaChcbiAgICAgICAgICBuZXcgTWF0aEV4cHJlc3Npb24oe1xuICAgICAgICAgICAgZXhwcmVzc2lvbjogYCgke2tleVByZWZpeH0xICsgJHtrZXlQcmVmaXh9MilgLFxuICAgICAgICAgICAgdXNpbmdNZXRyaWNzOiB1c2luZ01ldHJpY3MsXG4gICAgICAgICAgICBsYWJlbDpcbiAgICAgICAgICAgICAgYXZhaWxhYmlsaXR5Wm9uZUlkICsgJyAnICsgYWxiLmxvYWRCYWxhbmNlckFybiArICcgZmF1bHQgY291bnQnLFxuICAgICAgICAgICAgcGVyaW9kOiBwcm9wcy5wZXJpb2QsXG4gICAgICAgICAgfSksXG4gICAgICAgICk7XG5cbiAgICAgICAgLy8gQ3JlYXRlIG1ldHJpY3MgdG8gY2FsY3VsYXRlIGZhdWx0IHJhdGUgZm9yIHRoaXMgQUxCXG4gICAgICAgIHVzaW5nTWV0cmljcyA9IHt9O1xuICAgICAgICB1c2luZ01ldHJpY3NbYCR7a2V5UHJlZml4fTFgXSA9IHRhcmdldDJ4eDtcbiAgICAgICAgdXNpbmdNZXRyaWNzW2Ake2tleVByZWZpeH0yYF0gPSB0YXJnZXQzeHg7XG4gICAgICAgIHVzaW5nTWV0cmljc1tgJHtrZXlQcmVmaXh9M2BdID0gZWxiM3h4O1xuICAgICAgICB1c2luZ01ldHJpY3NbYCR7a2V5UHJlZml4fTRgXSA9IHRhcmdldDV4eDtcbiAgICAgICAgdXNpbmdNZXRyaWNzW2Ake2tleVByZWZpeH01YF0gPSBlbGI1eHg7XG5cbiAgICAgICAgLy8gVGhlIEFMQiBmYXVsdCByYXRlXG4gICAgICAgIGxldCBmYXVsdFJhdGU6IElNZXRyaWMgPSBuZXcgTWF0aEV4cHJlc3Npb24oe1xuICAgICAgICAgIGV4cHJlc3Npb246IGAoKCR7a2V5UHJlZml4fTQrJHtrZXlQcmVmaXh9NSkvKCR7a2V5UHJlZml4fTErJHtrZXlQcmVmaXh9Miske2tleVByZWZpeH0zKyR7a2V5UHJlZml4fTQrJHtrZXlQcmVmaXh9NSkpICogMTAwYCxcbiAgICAgICAgICB1c2luZ01ldHJpY3M6IHVzaW5nTWV0cmljcyxcbiAgICAgICAgICBsYWJlbDogYXZhaWxhYmlsaXR5Wm9uZUlkICsgJyAnICsgYWxiLmxvYWRCYWxhbmNlckFybiArICcgZmF1bHQgcmF0ZScsXG4gICAgICAgICAgcGVyaW9kOiBwcm9wcy5wZXJpb2QsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGxldCB0aHJlc2hvbGQ6IG51bWJlciA9IHByb3BzLmZhdWx0Q291bnRQZXJjZW50YWdlVGhyZXNob2xkID8/IDU7XG5cbiAgICAgICAgLy8gQ3JlYXRlIGEgZmF1bHQgcmF0ZSBhbGFybSBmb3IgdGhlIEFMQlxuICAgICAgICBsZXQgZmF1bHRSYXRlQWxhcm06IElBbGFybSA9IG5ldyBBbGFybShcbiAgICAgICAgICB0aGlzLFxuICAgICAgICAgICdBWicgKyBpbmRleCArIGtleVByZWZpeCArICdGYXVsdFJhdGVQZXJjZW50YWdlQWxhcm0nLFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGFsYXJtTmFtZTpcbiAgICAgICAgICAgICAgYXZhaWxhYmlsaXR5Wm9uZUlkICsgJy0nICsgYWxiLmxvYWRCYWxhbmNlckFybiArICctZmF1bHQtcmF0ZScsXG4gICAgICAgICAgICBhY3Rpb25zRW5hYmxlZDogZmFsc2UsXG4gICAgICAgICAgICBtZXRyaWM6IGZhdWx0UmF0ZSxcbiAgICAgICAgICAgIGV2YWx1YXRpb25QZXJpb2RzOiBwcm9wcy5ldmFsdWF0aW9uUGVyaW9kcyxcbiAgICAgICAgICAgIGRhdGFwb2ludHNUb0FsYXJtOiBwcm9wcy5kYXRhcG9pbnRzVG9BbGFybSxcbiAgICAgICAgICAgIHRocmVzaG9sZDogdGhyZXNob2xkLFxuICAgICAgICAgICAgY29tcGFyaXNvbk9wZXJhdG9yOiBDb21wYXJpc29uT3BlcmF0b3IuR1JFQVRFUl9USEFOX1RIUkVTSE9MRCxcbiAgICAgICAgICB9LFxuICAgICAgICApO1xuXG4gICAgICAgIC8vIEFkZCB0aGlzIEFMQidzIGZhdWx0IHJhdGUgYWxhcm1cbiAgICAgICAgZmF1bHRSYXRlUGVyY2VudGFnZUFsYXJtc1thekxldHRlcl0ucHVzaChmYXVsdFJhdGVBbGFybSk7XG5cbiAgICAgICAgLy8gR2V0IG5leHQgdW5pcXVlIGtleVxuICAgICAgICBrZXlQcmVmaXggPSBBdmFpbGFiaWxpdHlBbmRMYXRlbmN5TWV0cmljcy5uZXh0Q2hhcihrZXlQcmVmaXgpO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICAvLyBJdGVyYXRlIEFacyBmb3IgdGhlIEFMQiBmYXVsdCBjb3VudCBtZXRyaWNzXG4gICAgT2JqZWN0LmtleXMoYWxiWm9uZUZhdWx0Q291bnRNZXRyaWNzKS5mb3JFYWNoKChhekxldHRlcikgPT4ge1xuICAgICAgbGV0IGF2YWlsYWJpbGl0eVpvbmVJZDogc3RyaW5nID1cbiAgICAgICAgdGhpcy5hek1hcHBlci5hdmFpbGFiaWxpdHlab25lSWRGcm9tQXZhaWxhYmlsaXR5Wm9uZUxldHRlcihhekxldHRlcik7XG5cbiAgICAgIGtleVByZWZpeCA9IEF2YWlsYWJpbGl0eUFuZExhdGVuY3lNZXRyaWNzLm5leHRDaGFyKGtleVByZWZpeCk7XG5cbiAgICAgIGxldCBjb3VudGVyOiBudW1iZXIgPSAxO1xuICAgICAgbGV0IHVzaW5nTWV0cmljczogeyBba2V5OiBzdHJpbmddOiBJTWV0cmljIH0gPSB7fTtcblxuICAgICAgLy8gQWRkIGVhY2ggQUxCJ3MgZmF1bHQgY291bnQgbWV0cmljcyB0byB0aGUgZGljdGlvbmFyeVxuICAgICAgYWxiWm9uZUZhdWx0Q291bnRNZXRyaWNzW2F6TGV0dGVyXS5mb3JFYWNoKChtZXRyaWMpID0+IHtcbiAgICAgICAgdXNpbmdNZXRyaWNzW2Ake2tleVByZWZpeH0ke2NvdW50ZXIrK31gXSA9IG1ldHJpYztcbiAgICAgIH0pO1xuXG4gICAgICAvLyBTdW0gdGhlIHRvdGFsIGZhdWx0cyBmb3IgdGhlIGF2YWlsYWJpbGl0eSB6b25lIGFjcm9zcyBhbGwgQUxCc1xuICAgICAgbGV0IHRvdGFsRmF1bHRzUGVyWm9uZTogSU1ldHJpYyA9IG5ldyBNYXRoRXhwcmVzc2lvbih7XG4gICAgICAgIGV4cHJlc3Npb246IE9iamVjdC5rZXlzKHVzaW5nTWV0cmljcykuam9pbignKycpLFxuICAgICAgICB1c2luZ01ldHJpY3M6IHVzaW5nTWV0cmljcyxcbiAgICAgICAgbGFiZWw6IGF2YWlsYWJpbGl0eVpvbmVJZCArICcgZmF1bHQgY291bnQnLFxuICAgICAgICBwZXJpb2Q6IHByb3BzLnBlcmlvZCxcbiAgICAgIH0pO1xuXG4gICAgICBrZXlQcmVmaXggPSBBdmFpbGFiaWxpdHlBbmRMYXRlbmN5TWV0cmljcy5uZXh0Q2hhcihrZXlQcmVmaXgpO1xuICAgICAgY291bnRlciA9IDE7XG5cbiAgICAgIC8vIEFzc2lnbiB0aGUgdG90YWwgZmF1bHRzIHBlciB6b25lIHRvIHRoZSBkaWN0aW9uYXJ5XG4gICAgICB0aGlzLl9mYXVsdHNQZXJab25lW2F6TGV0dGVyXSA9IHRvdGFsRmF1bHRzUGVyWm9uZTtcbiAgICB9KTtcblxuICAgIGtleVByZWZpeCA9IEF2YWlsYWJpbGl0eUFuZExhdGVuY3lNZXRyaWNzLm5leHRDaGFyKGtleVByZWZpeCk7XG5cbiAgICBsZXQgdG1wOiB7IFtrZXk6IHN0cmluZ106IElNZXRyaWMgfSA9IHt9O1xuICAgIE9iamVjdC5rZXlzKHRoaXMuX2ZhdWx0c1BlclpvbmUpLmZvckVhY2goKGF6TGV0dGVyLCBpbmRleCkgPT4ge1xuICAgICAgdG1wW2Ake2tleVByZWZpeH0ke2luZGV4fWBdID0gdGhpcy5fZmF1bHRzUGVyWm9uZVthekxldHRlcl07XG4gICAgfSk7XG5cbiAgICAvLyBDYWxjdWxhdGUgdGhlIHRvdGFsIGZhdWx0cyBpbiB0aGUgcmVnaW9uIGJ5IGFkZGluZyBhbGwgQVpzIHRvZ2V0aGVyXG4gICAgbGV0IHRvdGFsRmF1bHRzOiBJTWV0cmljID0gbmV3IE1hdGhFeHByZXNzaW9uKHtcbiAgICAgIGV4cHJlc3Npb246IE9iamVjdC5rZXlzKHRtcCkuam9pbignKycpLFxuICAgICAgdXNpbmdNZXRyaWNzOiB0bXAsXG4gICAgICBsYWJlbDogRm4uc3ViKCcke0FXUzo6UmVnaW9ufSBmYXVsdCBjb3VudCcpLFxuICAgICAgcGVyaW9kOiBwcm9wcy5wZXJpb2QsXG4gICAgfSk7XG5cbiAgICBpZiAocHJvcHMub3V0bGllckRldGVjdGlvbkFsZ29yaXRobSA9PSBPdXRsaWVyRGV0ZWN0aW9uQWxnb3JpdGhtLlNUQVRJQykge1xuICAgICAgLy8gRmluYWxseSwgaXRlcmF0ZSBiYWNrIHRocm91Z2ggZWFjaCBBWlxuICAgICAgT2JqZWN0LmtleXModGhpcy5fZmF1bHRzUGVyWm9uZSkuZm9yRWFjaCgoYXpMZXR0ZXIsIGluZGV4KSA9PiB7XG4gICAgICAgIGtleVByZWZpeCA9IEF2YWlsYWJpbGl0eUFuZExhdGVuY3lNZXRyaWNzLm5leHRDaGFyKGtleVByZWZpeCk7XG4gICAgICAgIGxldCBhdmFpbGFiaWxpdHlab25lSWQ6IHN0cmluZyA9XG4gICAgICAgICAgdGhpcy5hek1hcHBlci5hdmFpbGFiaWxpdHlab25lSWRGcm9tQXZhaWxhYmlsaXR5Wm9uZUxldHRlcihhekxldHRlcik7XG5cbiAgICAgICAgLy8gRGV0ZXJtaW5lIGlmIEFaIGlzIGFuIG91dGxpZXIgZm9yIGZhdWx0cyBieSBleGNlZWRpbmdcbiAgICAgICAgLy8gYSBzdGF0aWMgdGhyZXNob2xkXG4gICAgICAgIGxldCBvdXRsaWVyTWV0cmljczogSU1ldHJpYztcblxuICAgICAgICAvLyBUaGVzZSBtZXRyaWNzIHdpbGwgZ2l2ZSB0aGUgcGVyY2VudCBvZiBmYXVsdHMgZm9yIHRoZSBBWlxuICAgICAgICBsZXQgdXNpbmdNZXRyaWNzOiB7IFtrZXk6IHN0cmluZ106IElNZXRyaWMgfSA9IHt9O1xuICAgICAgICB1c2luZ01ldHJpY3NbYCR7a2V5UHJlZml4fTFgXSA9IHRoaXMuX2ZhdWx0c1BlclpvbmVbYXpMZXR0ZXJdO1xuICAgICAgICB1c2luZ01ldHJpY3NbYCR7a2V5UHJlZml4fTJgXSA9IHRvdGFsRmF1bHRzO1xuICAgICAgICBvdXRsaWVyTWV0cmljcyA9IG5ldyBNYXRoRXhwcmVzc2lvbih7XG4gICAgICAgICAgZXhwcmVzc2lvbjogYCR7a2V5UHJlZml4fTEgLyAke2tleVByZWZpeH0yYCxcbiAgICAgICAgICB1c2luZ01ldHJpY3M6IHVzaW5nTWV0cmljcyxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgbGV0IGF6SXNPdXRsaWVyRm9yRmF1bHRzOiBJQWxhcm0gPSBuZXcgQWxhcm0oXG4gICAgICAgICAgdGhpcyxcbiAgICAgICAgICAnQVonICsgaW5kZXggKyAnRmF1bHRDb3VudE91dGxpZXJBbGFybScsXG4gICAgICAgICAge1xuICAgICAgICAgICAgYWxhcm1OYW1lOiBhdmFpbGFiaWxpdHlab25lSWQgKyAnLWZhdWx0LWNvdW50LW91dGxpZXInLFxuICAgICAgICAgICAgbWV0cmljOiBvdXRsaWVyTWV0cmljcyxcbiAgICAgICAgICAgIHRocmVzaG9sZDogb3V0bGllclRocmVzaG9sZCxcbiAgICAgICAgICAgIGV2YWx1YXRpb25QZXJpb2RzOiBwcm9wcy5ldmFsdWF0aW9uUGVyaW9kcyxcbiAgICAgICAgICAgIGRhdGFwb2ludHNUb0FsYXJtOiBwcm9wcy5kYXRhcG9pbnRzVG9BbGFybSxcbiAgICAgICAgICAgIGFjdGlvbnNFbmFibGVkOiBmYWxzZSxcbiAgICAgICAgICAgIHRyZWF0TWlzc2luZ0RhdGE6IFRyZWF0TWlzc2luZ0RhdGEuSUdOT1JFLFxuICAgICAgICAgICAgY29tcGFyaXNvbk9wZXJhdG9yOlxuICAgICAgICAgICAgICBDb21wYXJpc29uT3BlcmF0b3IuR1JFQVRFUl9USEFOX09SX0VRVUFMX1RPX1RIUkVTSE9MRCxcbiAgICAgICAgICB9LFxuICAgICAgICApO1xuXG4gICAgICAgIC8vIENyZWF0ZSBpc29sYXRlZCBBWiBpbXBhY3QgYWxhcm1zIGJ5IGRldGVybWluaW5nXG4gICAgICAgIC8vIGlmIHRoZSBBWiBpcyBhbiBvdXRsaWVyIGZvciBmYXVsdCBjb3VudCBhbmQgYXQgbGVhc3RcbiAgICAgICAgLy8gb25lIEFMQiBleGNlZWRzIHRoZSBmYXVsdCByYXRlIHRocmVzaG9sZCBwcm92aWRlZFxuICAgICAgICB0aGlzLl9hbGJab25hbElzb2xhdGVkSW1wYWN0QWxhcm1zW2F6TGV0dGVyXSA9IG5ldyBDb21wb3NpdGVBbGFybShcbiAgICAgICAgICB0aGlzLFxuICAgICAgICAgICdBWicgKyBpbmRleCArICdJc29sYXRlZEZhdWx0Q291bnRJbXBhY3QnLFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGNvbXBvc2l0ZUFsYXJtTmFtZTpcbiAgICAgICAgICAgICAgYXZhaWxhYmlsaXR5Wm9uZUlkICsgJy1pc29sYXRlZC1mYXVsdC1jb3VudC1pbXBhY3QnLFxuICAgICAgICAgICAgYWxhcm1SdWxlOiBBbGFybVJ1bGUuYWxsT2YoXG4gICAgICAgICAgICAgIGF6SXNPdXRsaWVyRm9yRmF1bHRzLFxuICAgICAgICAgICAgICBBbGFybVJ1bGUuYW55T2YoLi4uZmF1bHRSYXRlUGVyY2VudGFnZUFsYXJtc1thekxldHRlcl0pLFxuICAgICAgICAgICAgKSxcbiAgICAgICAgICB9LFxuICAgICAgICApO1xuICAgICAgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGxldCBhbGxBWnM6IHN0cmluZ1tdID0gQXJyYXkuZnJvbShcbiAgICAgICAgbmV3IFNldChcbiAgICAgICAgICB0aGlzLmFwcGxpY2F0aW9uTG9hZEJhbGFuY2VycyEuZmxhdE1hcCgoeCkgPT4ge1xuICAgICAgICAgICAgcmV0dXJuIHgudnBjIS5hdmFpbGFiaWxpdHlab25lcztcbiAgICAgICAgICB9KSxcbiAgICAgICAgKSxcbiAgICAgICk7XG5cbiAgICAgIGFsbEFacy5mb3JFYWNoKChhejogc3RyaW5nLCBpbmRleDogbnVtYmVyKSA9PiB7XG4gICAgICAgIGxldCBhekxldHRlcjogc3RyaW5nID0gYXouc3Vic3RyaW5nKGF6Lmxlbmd0aCAtIDEpO1xuICAgICAgICBsZXQgYXZhaWxhYmlsaXR5Wm9uZUlkOiBzdHJpbmcgPVxuICAgICAgICAgIHRoaXMuYXpNYXBwZXIuYXZhaWxhYmlsaXR5Wm9uZUlkRnJvbUF2YWlsYWJpbGl0eVpvbmVMZXR0ZXIoYXpMZXR0ZXIpO1xuXG4gICAgICAgIGxldCBheklzT3V0bGllckZvckZhdWx0czogSUFsYXJtID1cbiAgICAgICAgICBBdmFpbGFiaWxpdHlBbmRMYXRlbmN5QWxhcm1zQW5kUnVsZXMuY3JlYXRlWm9uYWxGYXVsdFJhdGVPdXRsaWVyQWxhcm1Gb3JBbGIoXG4gICAgICAgICAgICB0aGlzLFxuICAgICAgICAgICAgcHJvcHMuYXBwbGljYXRpb25Mb2FkQmFsYW5jZXJzISxcbiAgICAgICAgICAgIGF2YWlsYWJpbGl0eVpvbmVJZCxcbiAgICAgICAgICAgIG91dGxpZXJUaHJlc2hvbGQsXG4gICAgICAgICAgICB0aGlzLm91dGxpZXJEZXRlY3Rpb25GdW5jdGlvbiEsXG4gICAgICAgICAgICBwcm9wcy5vdXRsaWVyRGV0ZWN0aW9uQWxnb3JpdGhtLFxuICAgICAgICAgICAgdGhpcy5hek1hcHBlcixcbiAgICAgICAgICAgIGluZGV4LFxuICAgICAgICAgICAgcHJvcHMuZXZhbHVhdGlvblBlcmlvZHMsXG4gICAgICAgICAgICBwcm9wcy5kYXRhcG9pbnRzVG9BbGFybSxcbiAgICAgICAgICAgICcnLFxuICAgICAgICAgICk7XG5cbiAgICAgICAgLy8gSW4gYWRkaXRpb24gdG8gYmVpbmcgYW4gb3V0bGllciBmb3IgZmF1bHQgY291bnQsIG1ha2Ugc3VyZVxuICAgICAgICAvLyB0aGUgZmF1bHQgY291bnQgaXMgc3Vic3RhbnRpYWwgZW5vdWdoIHRvIHRyaWdnZXIgdGhlIGFsYXJtXG4gICAgICAgIC8vIGJ5IG1ha2luZyBzdXJlIGF0IGxlYXN0IDEgQUxCIHNlZXMgcGFja2V0IGxvc3MgdGhhdCBleGNlZWRzIHRoZSB0aHJlc2hvbGRcbiAgICAgICAgbGV0IGF6SXNPdXRsaWVyQW5kU2Vlc0ltcGFjdDogSUFsYXJtID0gbmV3IENvbXBvc2l0ZUFsYXJtKFxuICAgICAgICAgIHRoaXMsXG4gICAgICAgICAgJ0FaJyArIGluZGV4ICsgJ0FMQklzb2xhdGVkSW1wYWN0JyxcbiAgICAgICAgICB7XG4gICAgICAgICAgICBjb21wb3NpdGVBbGFybU5hbWU6XG4gICAgICAgICAgICAgIGF2YWlsYWJpbGl0eVpvbmVJZCArICctaXNvbGF0ZWQtZmF1bHQtY291bnQtaW1wYWN0JyxcbiAgICAgICAgICAgIGFsYXJtUnVsZTogQWxhcm1SdWxlLmFsbE9mKFxuICAgICAgICAgICAgICBheklzT3V0bGllckZvckZhdWx0cyxcbiAgICAgICAgICAgICAgQWxhcm1SdWxlLmFueU9mKC4uLmZhdWx0UmF0ZVBlcmNlbnRhZ2VBbGFybXNbYXpMZXR0ZXJdKSxcbiAgICAgICAgICAgICksXG4gICAgICAgICAgfSxcbiAgICAgICAgKTtcblxuICAgICAgICAvLyBSZWNvcmQgdGhlc2Ugc28gdGhleSBjYW4gYmUgdXNlZCBpbiBkYXNoYm9hcmQgb3IgZm9yIGNvbWJpbmF0aW9uXG4gICAgICAgIC8vIHdpdGggQVpcbiAgICAgICAgdGhpcy5fYWxiWm9uYWxJc29sYXRlZEltcGFjdEFsYXJtc1thekxldHRlcl0gPSBheklzT3V0bGllckFuZFNlZXNJbXBhY3Q7XG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGRvTmF0R2F0ZXdheU1ldHJpY3MoXG4gICAgcHJvcHM6IEJhc2ljU2VydmljZU11bHRpQVpPYnNlcnZhYmlsaXR5UHJvcHMsXG4gICAgb3V0bGllclRocmVzaG9sZDogbnVtYmVyLFxuICApIHtcbiAgICBsZXQga2V5UHJlZml4OiBzdHJpbmcgPSBBdmFpbGFiaWxpdHlBbmRMYXRlbmN5TWV0cmljcy5uZXh0Q2hhcignJyk7XG5cbiAgICAvLyBDb2xsZWN0IGFsYXJtcyBmb3IgcGFja2V0IGRyb3BzIGV4Y2VlZGluZyBhIHRocmVzaG9sZCBwZXIgTkFUIEdXXG4gICAgbGV0IHBhY2tldERyb3BQZXJjZW50YWdlQWxhcm1zOiB7IFtrZXk6IHN0cmluZ106IElBbGFybVtdIH0gPSB7fTtcblxuICAgIC8vIEZvciBlYWNoIEFaLCBjcmVhdGUgbWV0cmljcyBmb3IgZWFjaCBOQVQgR1dcbiAgICBPYmplY3QuZW50cmllcyh0aGlzLm5hdEdhdGV3YXlzISkuZm9yRWFjaCgoZW50cnksIGluZGV4KSA9PiB7XG4gICAgICAvLyBUaGUgbnVtYmVyIG9mIHBhY2tldCBkcm9wcyBmb3IgZWFjaCBOQVQgR1cgaW4gdGhlIEFaXG4gICAgICBsZXQgcGFja2V0RHJvcE1ldHJpY3NGb3JBWjogeyBba2V5OiBzdHJpbmddOiBJTWV0cmljIH0gPSB7fTtcblxuICAgICAgbGV0IGF6OiBzdHJpbmcgPSBlbnRyeVswXTtcbiAgICAgIGxldCBhekxldHRlcjogc3RyaW5nID0gYXouc3Vic3RyaW5nKGF6Lmxlbmd0aCAtIDEpO1xuICAgICAgbGV0IGF2YWlsYWJpbGl0eVpvbmVJZCA9XG4gICAgICAgIHRoaXMuYXpNYXBwZXIuYXZhaWxhYmlsaXR5Wm9uZUlkRnJvbUF2YWlsYWJpbGl0eVpvbmVMZXR0ZXIoYXpMZXR0ZXIpO1xuXG4gICAgICBwYWNrZXREcm9wUGVyY2VudGFnZUFsYXJtc1thekxldHRlcl0gPSBbXTtcblxuICAgICAgLy8gSXRlcmF0ZSB0aHJvdWdoIGVhY2ggTkFUIEdXIGluIHRoZSBjdXJyZW50IEFaXG4gICAgICBlbnRyeVsxXS5mb3JFYWNoKChuYXRndykgPT4ge1xuICAgICAgICAvLyBDYWxjdWxhdGUgcGFja2V0IGRyb3BzXG4gICAgICAgIGxldCBwYWNrZXREcm9wQ291bnQ6IElNZXRyaWMgPSBuZXcgTWV0cmljKHtcbiAgICAgICAgICBtZXRyaWNOYW1lOiAnUGFja2V0c0Ryb3BDb3VudCcsXG4gICAgICAgICAgbmFtZXNwYWNlOiAnQVdTL05BVEdhdGV3YXknLFxuICAgICAgICAgIHN0YXRpc3RpYzogJ1N1bScsXG4gICAgICAgICAgdW5pdDogVW5pdC5DT1VOVCxcbiAgICAgICAgICBsYWJlbDogYXZhaWxhYmlsaXR5Wm9uZUlkICsgJyBwYWNrZXQgZHJvcHMnLFxuICAgICAgICAgIGRpbWVuc2lvbnNNYXA6IHtcbiAgICAgICAgICAgIE5hdEdhdGV3YXlJZDogbmF0Z3cuYXR0ck5hdEdhdGV3YXlJZCxcbiAgICAgICAgICB9LFxuICAgICAgICAgIHBlcmlvZDogcHJvcHMucGVyaW9kLFxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBDYWxjdWxhdGUgcGFja2V0cyBpbiBmcm9tIHNvdXJjZVxuICAgICAgICBsZXQgcGFja2V0c0luRnJvbVNvdXJjZUNvdW50OiBJTWV0cmljID0gbmV3IE1ldHJpYyh7XG4gICAgICAgICAgbWV0cmljTmFtZTogJ1BhY2tldHNJbkZyb21Tb3VyY2UnLFxuICAgICAgICAgIG5hbWVzcGFjZTogJ0FXUy9OQVRHYXRld2F5JyxcbiAgICAgICAgICBzdGF0aXN0aWM6ICdTdW0nLFxuICAgICAgICAgIHVuaXQ6IFVuaXQuQ09VTlQsXG4gICAgICAgICAgbGFiZWw6IGF2YWlsYWJpbGl0eVpvbmVJZCArICcgcGFja2V0cyBpbiBmcm9tIHNvdXJjZScsXG4gICAgICAgICAgZGltZW5zaW9uc01hcDoge1xuICAgICAgICAgICAgTmF0R2F0ZXdheUlkOiBuYXRndy5hdHRyTmF0R2F0ZXdheUlkLFxuICAgICAgICAgIH0sXG4gICAgICAgICAgcGVyaW9kOiBwcm9wcy5wZXJpb2QsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIENhbGN1bGF0ZSBwYWNrZXRzIGluIGZyb20gZGVzdGluYXRpb25cbiAgICAgICAgbGV0IHBhY2tldHNJbkZyb21EZXN0aW5hdGlvbkNvdW50OiBJTWV0cmljID0gbmV3IE1ldHJpYyh7XG4gICAgICAgICAgbWV0cmljTmFtZTogJ1BhY2tldHNJbkZyb21EZXN0aW5hdGlvbicsXG4gICAgICAgICAgbmFtZXNwYWNlOiAnQVdTL05BVEdhdGV3YXknLFxuICAgICAgICAgIHN0YXRpc3RpYzogJ1N1bScsXG4gICAgICAgICAgdW5pdDogVW5pdC5DT1VOVCxcbiAgICAgICAgICBsYWJlbDogYXZhaWxhYmlsaXR5Wm9uZUlkICsgJyBwYWNrZXRzIGluIGZyb20gZGVzdGluYXRpb24nLFxuICAgICAgICAgIGRpbWVuc2lvbnNNYXA6IHtcbiAgICAgICAgICAgIE5hdEdhdGV3YXlJZDogbmF0Z3cuYXR0ck5hdEdhdGV3YXlJZCxcbiAgICAgICAgICB9LFxuICAgICAgICAgIHBlcmlvZDogcHJvcHMucGVyaW9kLFxuICAgICAgICB9KTtcblxuICAgICAgICBsZXQgdXNpbmdNZXRyaWNzOiB7IFtrZXk6IHN0cmluZ106IElNZXRyaWMgfSA9IHt9O1xuICAgICAgICB1c2luZ01ldHJpY3NbYCR7a2V5UHJlZml4fTFgXSA9IHBhY2tldERyb3BDb3VudDtcbiAgICAgICAgdXNpbmdNZXRyaWNzW2Ake2tleVByZWZpeH0yYF0gPSBwYWNrZXRzSW5Gcm9tU291cmNlQ291bnQ7XG4gICAgICAgIHVzaW5nTWV0cmljc1tgJHtrZXlQcmVmaXh9M2BdID0gcGFja2V0c0luRnJvbURlc3RpbmF0aW9uQ291bnQ7XG5cbiAgICAgICAgLy8gQ2FsY3VsYXRlIGEgcGVyY2VudGFnZSBvZiBkcm9wcGVkIHBhY2tldHMgZm9yIHRoZSBOQVQgR1dcbiAgICAgICAgbGV0IHBhY2tldERyb3BQZXJjZW50YWdlOiBJTWV0cmljID0gbmV3IE1hdGhFeHByZXNzaW9uKHtcbiAgICAgICAgICBleHByZXNzaW9uOiBgKCR7a2V5UHJlZml4fTEgLyAoJHtrZXlQcmVmaXh9MiArICR7a2V5UHJlZml4fTMpKSAqIDEwMGAsXG4gICAgICAgICAgdXNpbmdNZXRyaWNzOiB1c2luZ01ldHJpY3MsXG4gICAgICAgICAgbGFiZWw6IGF2YWlsYWJpbGl0eVpvbmVJZCArICcgcGFja2V0IGRyb3AgcGVyY2VudGFnZScsXG4gICAgICAgICAgcGVyaW9kOiBwcm9wcy5wZXJpb2QsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGxldCB0aHJlc2hvbGQ6IG51bWJlciA9XG4gICAgICAgICAgcHJvcHMucGFja2V0TG9zc0ltcGFjdFBlcmNlbnRhZ2VUaHJlc2hvbGQgPz8gMC4wMTtcblxuICAgICAgICAvLyBDcmVhdGUgYW4gYWxhcm0gZm9yIHRoaXMgTkFUIEdXIGlmIHBhY2tldCBkcm9wcyBleGNlZWQgdGhlIHNwZWNpZmllZCB0aHJlc2hvbGRcbiAgICAgICAgbGV0IHBhY2tldERyb3BJbXBhY3RBbGFybTogSUFsYXJtID0gbmV3IEFsYXJtKFxuICAgICAgICAgIHRoaXMsXG4gICAgICAgICAgJ0FaJyArIChpbmRleCArIDEpICsgJ1BhY2tldERyb3BJbXBhY3RBbGFybScsXG4gICAgICAgICAge1xuICAgICAgICAgICAgYWxhcm1OYW1lOlxuICAgICAgICAgICAgICBhdmFpbGFiaWxpdHlab25lSWQgK1xuICAgICAgICAgICAgICAnLScgK1xuICAgICAgICAgICAgICBuYXRndy5hdHRyTmF0R2F0ZXdheUlkICtcbiAgICAgICAgICAgICAgJy1wYWNrZXQtZHJvcC1pbXBhY3QnLFxuICAgICAgICAgICAgYWN0aW9uc0VuYWJsZWQ6IGZhbHNlLFxuICAgICAgICAgICAgbWV0cmljOiBwYWNrZXREcm9wUGVyY2VudGFnZSxcbiAgICAgICAgICAgIHRocmVzaG9sZDogdGhyZXNob2xkLFxuICAgICAgICAgICAgY29tcGFyaXNvbk9wZXJhdG9yOiBDb21wYXJpc29uT3BlcmF0b3IuR1JFQVRFUl9USEFOX1RIUkVTSE9MRCxcbiAgICAgICAgICAgIGV2YWx1YXRpb25QZXJpb2RzOiBwcm9wcy5ldmFsdWF0aW9uUGVyaW9kcyxcbiAgICAgICAgICAgIGRhdGFwb2ludHNUb0FsYXJtOiBwcm9wcy5kYXRhcG9pbnRzVG9BbGFybSxcbiAgICAgICAgICB9LFxuICAgICAgICApO1xuXG4gICAgICAgIC8vIENvbGxlY3QgYWxsIG9mIHRoZSBwYWNrZXQgZHJvcCBpbXBhY3QgYWxhcm1zIGZvciBlYWNoXG4gICAgICAgIC8vIE5BVCBHVyBpbiB0aGlzIEFaLCBuZWVkIHRvIGtub3cgYXQgbGVhc3QgMSBzZWVzIHN1YnN0YW50aWFsXG4gICAgICAgIC8vIGVub3VnaCBpbXBhY3QgdG8gY29uc2lkZXIgdGhlIEFaIGFzIGltcGFpcmVkXG4gICAgICAgIHBhY2tldERyb3BQZXJjZW50YWdlQWxhcm1zW2F6TGV0dGVyXS5wdXNoKHBhY2tldERyb3BJbXBhY3RBbGFybSk7XG5cbiAgICAgICAgLy8gQ29sbGVjdCB0aGUgcGFja2V0IGRyb3AgbWV0cmljcyBmb3IgdGhpcyBBWiBzbyB3ZSBjYW5cbiAgICAgICAgLy8gYWRkIHRoZW0gYWxsIHRvZ2V0aGVyIGFuZCBjb3VudCB0b3RhbCBwYWNrZXQgZHJvcHNcbiAgICAgICAgLy8gZm9yIGFsbCBOQVQgR1dzIGluIHRoZSBBWlxuICAgICAgICBwYWNrZXREcm9wTWV0cmljc0ZvckFaW2BtJHtpbmRleH1gXSA9IHBhY2tldERyb3BDb3VudDtcbiAgICAgIH0pO1xuXG4gICAgICAvLyBDcmVhdGUgYSBtZXRyaWMgdGhhdCBhZGRzIHVwIGFsbCBwYWNrZXRzIGRyb3BzIGZyb20gZWFjaFxuICAgICAgLy8gTkFUIEdXIGluIHRoZSBBWlxuICAgICAgbGV0IHBhY2tldERyb3BzSW5UaGlzQVo6IElNZXRyaWMgPSBuZXcgTWF0aEV4cHJlc3Npb24oe1xuICAgICAgICBleHByZXNzaW9uOiBPYmplY3Qua2V5cyhwYWNrZXREcm9wTWV0cmljc0ZvckFaKS5qb2luKCcrJyksXG4gICAgICAgIHVzaW5nTWV0cmljczogcGFja2V0RHJvcE1ldHJpY3NGb3JBWixcbiAgICAgICAgbGFiZWw6IGF2YWlsYWJpbGl0eVpvbmVJZCArICcgZHJvcHBlZCBwYWNrZXRzJyxcbiAgICAgICAgcGVyaW9kOiBwcm9wcy5wZXJpb2QsXG4gICAgICB9KTtcblxuICAgICAgLy8gUmVjb3JkIHRoZXNlIHNvIHdlIGNhbiBhZGQgdGhlbSB1cFxuICAgICAgLy8gYW5kIGdldCBhIHRvdGFsIGFtb3VudCBvZiBwYWNrZXQgZHJvcHNcbiAgICAgIC8vIGluIHRoZSByZWdpb24gYWNyb3NzIGFsbCBBWnNcbiAgICAgIHRoaXMuX3BhY2tldERyb3BzUGVyWm9uZVthekxldHRlcl0gPSBwYWNrZXREcm9wc0luVGhpc0FaO1xuICAgIH0pO1xuXG4gICAga2V5UHJlZml4ID0gQXZhaWxhYmlsaXR5QW5kTGF0ZW5jeU1ldHJpY3MubmV4dENoYXIoa2V5UHJlZml4KTtcblxuICAgIGxldCB0bXA6IHsgW2tleTogc3RyaW5nXTogSU1ldHJpYyB9ID0ge307XG4gICAgT2JqZWN0LmtleXModGhpcy5fcGFja2V0RHJvcHNQZXJab25lKS5mb3JFYWNoKChhekxldHRlciwgaW5kZXgpID0+IHtcbiAgICAgIHRtcFtgJHtrZXlQcmVmaXh9JHtpbmRleH1gXSA9IHRoaXMuX3BhY2tldERyb3BzUGVyWm9uZVthekxldHRlcl07XG4gICAgfSk7XG5cbiAgICAvLyBDYWxjdWxhdGUgdG90YWwgcGFja2V0IGRyb3BzIGZvciB0aGUgcmVnaW9uXG4gICAgbGV0IHRvdGFsUGFja2V0RHJvcHM6IElNZXRyaWMgPSBuZXcgTWF0aEV4cHJlc3Npb24oe1xuICAgICAgZXhwcmVzc2lvbjogT2JqZWN0LmtleXModG1wKS5qb2luKCcrJyksXG4gICAgICB1c2luZ01ldHJpY3M6IHRtcCxcbiAgICAgIGxhYmVsOiBGbi5yZWYoJ0FXUzo6UmVnaW9uJykgKyAnIGRyb3BwZWQgcGFja2V0cycsXG4gICAgICBwZXJpb2Q6IHByb3BzLnBlcmlvZCxcbiAgICB9KTtcblxuICAgIGlmIChwcm9wcy5vdXRsaWVyRGV0ZWN0aW9uQWxnb3JpdGhtID09IE91dGxpZXJEZXRlY3Rpb25BbGdvcml0aG0uU1RBVElDKSB7XG4gICAgICAvLyBDcmVhdGUgb3V0bGllciBkZXRlY3Rpb24gYWxhcm1zIGJ5IGNvbXBhcmluZyBwYWNrZXRcbiAgICAgIC8vIGRyb3BzIGluIG9uZSBBWiB2ZXJzdXMgdG90YWwgcGFja2V0IGRyb3BzIGluIHRoZSByZWdpb25cbiAgICAgIE9iamVjdC5rZXlzKHRoaXMuX3BhY2tldERyb3BzUGVyWm9uZSkuZm9yRWFjaCgoYXpMZXR0ZXIsIGluZGV4KSA9PiB7XG4gICAgICAgIGxldCBheklzT3V0bGllckZvclBhY2tldERyb3BzOiBJQWxhcm07XG4gICAgICAgIGtleVByZWZpeCA9IEF2YWlsYWJpbGl0eUFuZExhdGVuY3lNZXRyaWNzLm5leHRDaGFyKGtleVByZWZpeCk7XG4gICAgICAgIGxldCBhdmFpbGFiaWxpdHlab25lSWQ6IHN0cmluZyA9XG4gICAgICAgICAgdGhpcy5hek1hcHBlci5hdmFpbGFiaWxpdHlab25lSWRGcm9tQXZhaWxhYmlsaXR5Wm9uZUxldHRlcihhekxldHRlcik7XG5cbiAgICAgICAgLy8gRGV0ZXJtaW5lIGlmIEFaIGlzIGFuIG91dGxpZXIgZm9yIGZhdWx0cyBieSBleGNlZWRpbmdcbiAgICAgICAgLy8gYSBzdGF0aWMgdGhyZXNob2xkXG4gICAgICAgIGxldCBvdXRsaWVyTWV0cmljczogSU1ldHJpYztcblxuICAgICAgICAvLyBUaGVzZSBtZXRyaWNzIHdpbGwgZ2l2ZSB0aGUgcGVyY2VudCBvZiBmYXVsdHMgZm9yIHRoZSBBWlxuICAgICAgICBsZXQgdXNpbmdNZXRyaWNzOiB7IFtrZXk6IHN0cmluZ106IElNZXRyaWMgfSA9IHt9O1xuICAgICAgICB1c2luZ01ldHJpY3NbYCR7a2V5UHJlZml4fTFgXSA9IHRoaXMuX3BhY2tldERyb3BzUGVyWm9uZVthekxldHRlcl07XG4gICAgICAgIHVzaW5nTWV0cmljc1tgJHtrZXlQcmVmaXh9MmBdID0gdG90YWxQYWNrZXREcm9wcztcblxuICAgICAgICBvdXRsaWVyTWV0cmljcyA9IG5ldyBNYXRoRXhwcmVzc2lvbih7XG4gICAgICAgICAgZXhwcmVzc2lvbjogYCgke2tleVByZWZpeH0xIC8gJHtrZXlQcmVmaXh9MikgKiAxMDBgLFxuICAgICAgICAgIHVzaW5nTWV0cmljczogdXNpbmdNZXRyaWNzLFxuICAgICAgICAgIGxhYmVsOiBhdmFpbGFiaWxpdHlab25lSWQgKyAnIHBlcmNlbnRhZ2Ugb2YgZHJvcHBlZCBwYWNrZXRzJyxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgYXpJc091dGxpZXJGb3JQYWNrZXREcm9wcyA9IG5ldyBBbGFybShcbiAgICAgICAgICB0aGlzLFxuICAgICAgICAgICdBWicgKyAoaW5kZXggKyAxKSArICdOQVRHV0Ryb3BwZWRQYWNrZXRzT3V0bGllckFsYXJtJyxcbiAgICAgICAgICB7XG4gICAgICAgICAgICBtZXRyaWM6IG91dGxpZXJNZXRyaWNzLFxuICAgICAgICAgICAgYWxhcm1OYW1lOiBhdmFpbGFiaWxpdHlab25lSWQgKyAnLWRyb3BwZWQtcGFja2V0cy1vdXRsaWVyJyxcbiAgICAgICAgICAgIGV2YWx1YXRpb25QZXJpb2RzOiBwcm9wcy5ldmFsdWF0aW9uUGVyaW9kcyxcbiAgICAgICAgICAgIGRhdGFwb2ludHNUb0FsYXJtOiBwcm9wcy5kYXRhcG9pbnRzVG9BbGFybSxcbiAgICAgICAgICAgIHRocmVzaG9sZDogb3V0bGllclRocmVzaG9sZCxcbiAgICAgICAgICAgIGFjdGlvbnNFbmFibGVkOiBmYWxzZSxcbiAgICAgICAgICAgIHRyZWF0TWlzc2luZ0RhdGE6IFRyZWF0TWlzc2luZ0RhdGEuSUdOT1JFLFxuICAgICAgICAgICAgY29tcGFyaXNvbk9wZXJhdG9yOlxuICAgICAgICAgICAgICBDb21wYXJpc29uT3BlcmF0b3IuR1JFQVRFUl9USEFOX09SX0VRVUFMX1RPX1RIUkVTSE9MRCxcbiAgICAgICAgICB9LFxuICAgICAgICApO1xuXG4gICAgICAgIC8vIEluIGFkZGl0aW9uIHRvIGJlaW5nIGFuIG91dGxpZXIgZm9yIHBhY2tldCBkcm9wcywgbWFrZSBzdXJlXG4gICAgICAgIC8vIHRoZSBwYWNrZXQgbG9zcyBpcyBzdWJzdGFudGlhbCBlbm91Z2ggdG8gdHJpZ2dlciB0aGUgYWxhcm1cbiAgICAgICAgLy8gYnkgbWFraW5nIHN1cmUgYXQgbGVhc3QgMSBOQVQgR1cgc2VlcyBwYWNrZXQgbG9zcyBtb3JlIHRoYW4gMC4wMSVcbiAgICAgICAgbGV0IGF6SXNPdXRsaWVyQW5kU2Vlc0ltcGFjdDogSUFsYXJtID0gbmV3IENvbXBvc2l0ZUFsYXJtKFxuICAgICAgICAgIHRoaXMsXG4gICAgICAgICAgJ0FaJyArIGluZGV4ICsgJ05BVEdXSXNvbGF0ZWRJbXBhY3QnLFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGNvbXBvc2l0ZUFsYXJtTmFtZTogYXZhaWxhYmlsaXR5Wm9uZUlkICsgJy1pc29sYXRlZC1uYXRndy1pbXBhY3QnLFxuICAgICAgICAgICAgYWxhcm1SdWxlOiBBbGFybVJ1bGUuYWxsT2YoXG4gICAgICAgICAgICAgIGF6SXNPdXRsaWVyRm9yUGFja2V0RHJvcHMsXG4gICAgICAgICAgICAgIEFsYXJtUnVsZS5hbnlPZiguLi5wYWNrZXREcm9wUGVyY2VudGFnZUFsYXJtc1thekxldHRlcl0pLFxuICAgICAgICAgICAgKSxcbiAgICAgICAgICB9LFxuICAgICAgICApO1xuXG4gICAgICAgIC8vIFJlY29yZCB0aGVzZSBzbyB0aGV5IGNhbiBiZSB1c2VkIGluIGRhc2hib2FyZCBvciBmb3IgY29tYmluYXRpb25cbiAgICAgICAgLy8gd2l0aCBBWlxuICAgICAgICB0aGlzLl9uYXRHV1pvbmFsSXNvbGF0ZWRJbXBhY3RBbGFybXNbYXpMZXR0ZXJdID1cbiAgICAgICAgICBheklzT3V0bGllckFuZFNlZXNJbXBhY3Q7XG4gICAgICB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgT2JqZWN0LmtleXMocHJvcHMubmF0R2F0ZXdheXMhKS5mb3JFYWNoKChhejogc3RyaW5nLCBpbmRleDogbnVtYmVyKSA9PiB7XG4gICAgICAgIGxldCBhekxldHRlcjogc3RyaW5nID0gYXouc3Vic3RyaW5nKGF6Lmxlbmd0aCAtIDEpO1xuICAgICAgICBsZXQgYXZhaWxhYmlsaXR5Wm9uZUlkOiBzdHJpbmcgPVxuICAgICAgICAgIHRoaXMuYXpNYXBwZXIuYXZhaWxhYmlsaXR5Wm9uZUlkRnJvbUF2YWlsYWJpbGl0eVpvbmVMZXR0ZXIoYXpMZXR0ZXIpO1xuXG4gICAgICAgIC8vIEl0ZXJhdGUgYWxsIE5BVCBHV3MgaW4gdGhpcyBBWlxuXG4gICAgICAgIGxldCBheklzT3V0bGllckZvclBhY2tldERyb3BzOiBJQWxhcm0gPVxuICAgICAgICAgIEF2YWlsYWJpbGl0eUFuZExhdGVuY3lBbGFybXNBbmRSdWxlcy5jcmVhdGVab25hbEZhdWx0UmF0ZU91dGxpZXJBbGFybUZvck5hdEdXKFxuICAgICAgICAgICAgdGhpcyxcbiAgICAgICAgICAgIHRoaXMubmF0R2F0ZXdheXMhLFxuICAgICAgICAgICAgYXZhaWxhYmlsaXR5Wm9uZUlkLFxuICAgICAgICAgICAgb3V0bGllclRocmVzaG9sZCxcbiAgICAgICAgICAgIHRoaXMub3V0bGllckRldGVjdGlvbkZ1bmN0aW9uISxcbiAgICAgICAgICAgIHByb3BzLm91dGxpZXJEZXRlY3Rpb25BbGdvcml0aG0sXG4gICAgICAgICAgICB0aGlzLmF6TWFwcGVyLFxuICAgICAgICAgICAgaW5kZXgsXG4gICAgICAgICAgICBwcm9wcy5ldmFsdWF0aW9uUGVyaW9kcyxcbiAgICAgICAgICAgIHByb3BzLmRhdGFwb2ludHNUb0FsYXJtLFxuICAgICAgICAgICAgJycsXG4gICAgICAgICAgKTtcblxuICAgICAgICAvLyBJbiBhZGRpdGlvbiB0byBiZWluZyBhbiBvdXRsaWVyIGZvciBwYWNrZXQgZHJvcHMsIG1ha2Ugc3VyZVxuICAgICAgICAvLyB0aGUgcGFja2V0IGxvc3MgaXMgc3Vic3RhbnRpYWwgZW5vdWdoIHRvIHRyaWdnZXIgdGhlIGFsYXJtXG4gICAgICAgIC8vIGJ5IG1ha2luZyBzdXJlIGF0IGxlYXN0IDEgTkFUIEdXIHNlZXMgcGFja2V0IGxvc3MgbW9yZSB0aGFuIDAuMDElXG4gICAgICAgIGxldCBheklzT3V0bGllckFuZFNlZXNJbXBhY3Q6IElBbGFybSA9IG5ldyBDb21wb3NpdGVBbGFybShcbiAgICAgICAgICB0aGlzLFxuICAgICAgICAgICdBWicgKyBpbmRleCArICdOQVRHV0lzb2xhdGVkSW1wYWN0JyxcbiAgICAgICAgICB7XG4gICAgICAgICAgICBjb21wb3NpdGVBbGFybU5hbWU6IGF2YWlsYWJpbGl0eVpvbmVJZCArICctaXNvbGF0ZWQtbmF0Z3ctaW1wYWN0JyxcbiAgICAgICAgICAgIGFsYXJtUnVsZTogQWxhcm1SdWxlLmFsbE9mKFxuICAgICAgICAgICAgICBheklzT3V0bGllckZvclBhY2tldERyb3BzLFxuICAgICAgICAgICAgICBBbGFybVJ1bGUuYW55T2YoLi4ucGFja2V0RHJvcFBlcmNlbnRhZ2VBbGFybXNbYXpMZXR0ZXJdKSxcbiAgICAgICAgICAgICksXG4gICAgICAgICAgfSxcbiAgICAgICAgKTtcblxuICAgICAgICAvLyBSZWNvcmQgdGhlc2Ugc28gdGhleSBjYW4gYmUgdXNlZCBpbiBkYXNoYm9hcmQgb3IgZm9yIGNvbWJpbmF0aW9uXG4gICAgICAgIC8vIHdpdGggQVpcbiAgICAgICAgdGhpcy5fbmF0R1dab25hbElzb2xhdGVkSW1wYWN0QWxhcm1zW2F6TGV0dGVyXSA9XG4gICAgICAgICAgYXpJc091dGxpZXJBbmRTZWVzSW1wYWN0O1xuICAgICAgfSk7XG4gICAgfVxuICB9XG59XG4iXX0=
|