@cdklabs/multi-az-observability 0.0.0-alpha.0 → 0.0.1-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.
Files changed (65) hide show
  1. package/.jsii +85 -84
  2. package/API.md +54 -64
  3. package/lib/alarmsandrules/AvailabilityAndLatencyAlarmsAndRules.d.ts +15 -0
  4. package/lib/alarmsandrules/AvailabilityAndLatencyAlarmsAndRules.js +127 -1
  5. package/lib/alarmsandrules/BaseOperationZonalAlarmsAndRules.d.ts +2 -2
  6. package/lib/alarmsandrules/BaseOperationZonalAlarmsAndRules.js +1 -18
  7. package/lib/alarmsandrules/CanaryOperationZonalAlarmsAndRules.d.ts +8 -0
  8. package/lib/alarmsandrules/CanaryOperationZonalAlarmsAndRules.js +18 -1
  9. package/lib/alarmsandrules/ServerSideOperationZonalAlarmsAndRules.d.ts +8 -0
  10. package/lib/alarmsandrules/ServerSideOperationZonalAlarmsAndRules.js +18 -1
  11. package/lib/alarmsandrules/ServiceAlarmsAndRules.js +3 -3
  12. package/lib/alarmsandrules/props/CanaryOperationZonalAlarmsAndRulesProps.js +1 -1
  13. package/lib/azmapper/AvailabilityZoneMapper.js +1 -1
  14. package/lib/basic_observability/BasicServiceDashboard.js +130 -0
  15. package/lib/{services → basic_observability}/BasicServiceMultiAZObservability.d.ts +9 -7
  16. package/lib/basic_observability/BasicServiceMultiAZObservability.js +429 -0
  17. package/lib/basic_observability/IBasicServiceMultiAZObservability.d.ts +51 -0
  18. package/lib/basic_observability/IBasicServiceMultiAZObservability.js +5 -0
  19. package/lib/{dashboards → basic_observability}/props/BasicServiceDashboardProps.d.ts +3 -0
  20. package/lib/basic_observability/props/BasicServiceDashboardProps.js +3 -0
  21. package/lib/{services → basic_observability}/props/BasicServiceMultiAZObservabilityProps.d.ts +29 -46
  22. package/lib/basic_observability/props/BasicServiceMultiAZObservabilityProps.js +5 -0
  23. package/lib/basic_observability/props/RegionalApplicationLoadBalancerAvailabilityMetricProps.d.ts +8 -0
  24. package/lib/basic_observability/props/RegionalApplicationLoadBalancerAvailabilityMetricProps.js +3 -0
  25. package/lib/basic_observability/props/RegionalApplicationLoadBalancerLatencyMetricProps.d.ts +8 -0
  26. package/lib/basic_observability/props/RegionalApplicationLoadBalancerLatencyMetricProps.js +3 -0
  27. package/lib/basic_observability/props/ZonalApplicationLoadBalancerAvailabilityMetricProps.d.ts +10 -0
  28. package/lib/basic_observability/props/ZonalApplicationLoadBalancerAvailabilityMetricProps.js +3 -0
  29. package/lib/basic_observability/props/ZonalApplicationLoadBalancerLatencyMetricProps.d.ts +10 -0
  30. package/lib/basic_observability/props/ZonalApplicationLoadBalancerLatencyMetricProps.js +3 -0
  31. package/lib/canaries/src/canary.zip +0 -0
  32. package/lib/dashboards/OperationAvailabilityAndLatencyDashboard.js +14 -16
  33. package/lib/dashboards/ServiceAvailabilityAndLatencyDashboard.js +16 -7
  34. package/lib/index.d.ts +2 -2
  35. package/lib/index.js +2 -2
  36. package/lib/metrics/ApplicationLoadBalancerMetrics.d.ts +55 -17
  37. package/lib/metrics/ApplicationLoadBalancerMetrics.js +459 -105
  38. package/lib/metrics/AvailabilityAndLatencyMetrics.d.ts +0 -11
  39. package/lib/metrics/AvailabilityAndLatencyMetrics.js +1 -24
  40. package/lib/metrics/RegionalLatencyMetrics.js +7 -6
  41. package/lib/metrics/ZonalAvailabilityMetrics.js +2 -2
  42. package/lib/metrics/ZonalLatencyMetrics.js +4 -3
  43. package/lib/monitoring/src/monitoring-layer.zip +0 -0
  44. package/lib/outlier-detection/OutlierDetectionFunction.js +5 -5
  45. package/lib/outlier-detection/src/outlier-detection.zip +0 -0
  46. package/lib/outlier-detection/src/scipy-layer.zip +0 -0
  47. package/lib/services/CanaryMetrics.js +1 -1
  48. package/lib/services/CanaryTestMetricsOverride.js +1 -1
  49. package/lib/services/ContributorInsightRuleDetails.js +1 -1
  50. package/lib/services/InstrumentedServiceMultiAZObservability.js +1 -1
  51. package/lib/services/Operation.js +1 -1
  52. package/lib/services/OperationMetricDetails.js +1 -1
  53. package/lib/services/Service.js +1 -1
  54. package/lib/services/ServiceMetricDetails.js +1 -1
  55. package/lib/services/props/MetricDimensions.js +1 -1
  56. package/lib/utilities/LatencyMetricType.d.ts +5 -1
  57. package/lib/utilities/LatencyMetricType.js +5 -1
  58. package/lib/utilities/MetricsHelper.d.ts +13 -0
  59. package/lib/utilities/MetricsHelper.js +30 -0
  60. package/package.json +7 -7
  61. package/lib/dashboards/BasicServiceDashboard.js +0 -130
  62. package/lib/dashboards/props/BasicServiceDashboardProps.js +0 -3
  63. package/lib/services/BasicServiceMultiAZObservability.js +0 -504
  64. package/lib/services/props/BasicServiceMultiAZObservabilityProps.js +0 -3
  65. /package/lib/{dashboards → basic_observability}/BasicServiceDashboard.d.ts +0 -0
@@ -1,504 +0,0 @@
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=