@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.
Files changed (212) hide show
  1. package/.jsii +10177 -0
  2. package/API.md +5119 -0
  3. package/LICENSE +202 -0
  4. package/README.md +175 -0
  5. package/cdk.json +68 -0
  6. package/lib/alarmsandrules/AvailabilityAndLatencyAlarmsAndRules.d.ts +214 -0
  7. package/lib/alarmsandrules/AvailabilityAndLatencyAlarmsAndRules.js +763 -0
  8. package/lib/alarmsandrules/BaseOperationRegionalAlarmsAndRules.d.ts +22 -0
  9. package/lib/alarmsandrules/BaseOperationRegionalAlarmsAndRules.js +21 -0
  10. package/lib/alarmsandrules/BaseOperationZonalAlarmsAndRules.d.ts +34 -0
  11. package/lib/alarmsandrules/BaseOperationZonalAlarmsAndRules.js +39 -0
  12. package/lib/alarmsandrules/CanaryOperationRegionalAlarmsAndRules.d.ts +7 -0
  13. package/lib/alarmsandrules/CanaryOperationRegionalAlarmsAndRules.js +11 -0
  14. package/lib/alarmsandrules/CanaryOperationZonalAlarmsAndRules.d.ts +16 -0
  15. package/lib/alarmsandrules/CanaryOperationZonalAlarmsAndRules.js +17 -0
  16. package/lib/alarmsandrules/IBaseOperationRegionalAlarmsAndRules.d.ts +18 -0
  17. package/lib/alarmsandrules/IBaseOperationRegionalAlarmsAndRules.js +3 -0
  18. package/lib/alarmsandrules/IBaseOperationZonalAlarmsAndRules.d.ts +30 -0
  19. package/lib/alarmsandrules/IBaseOperationZonalAlarmsAndRules.js +3 -0
  20. package/lib/alarmsandrules/ICanaryOperationRegionalAlarmsAndRules.d.ts +6 -0
  21. package/lib/alarmsandrules/ICanaryOperationRegionalAlarmsAndRules.js +3 -0
  22. package/lib/alarmsandrules/ICanaryOperationZonalAlarmsAndRules.d.ts +12 -0
  23. package/lib/alarmsandrules/ICanaryOperationZonalAlarmsAndRules.js +3 -0
  24. package/lib/alarmsandrules/IOperationAlarmsAndRules.d.ts +55 -0
  25. package/lib/alarmsandrules/IOperationAlarmsAndRules.js +3 -0
  26. package/lib/alarmsandrules/IServerSideOperationRegionalAlarmsAndRules.d.ts +15 -0
  27. package/lib/alarmsandrules/IServerSideOperationRegionalAlarmsAndRules.js +3 -0
  28. package/lib/alarmsandrules/IServerSideOperationZonalAlarmsAndRules.d.ts +36 -0
  29. package/lib/alarmsandrules/IServerSideOperationZonalAlarmsAndRules.js +3 -0
  30. package/lib/alarmsandrules/IServiceAlarmsAndRules.d.ts +44 -0
  31. package/lib/alarmsandrules/IServiceAlarmsAndRules.js +3 -0
  32. package/lib/alarmsandrules/InsightRuleBody.d.ts +67 -0
  33. package/lib/alarmsandrules/InsightRuleBody.js +46 -0
  34. package/lib/alarmsandrules/OperationAlarmsAndRules.d.ts +59 -0
  35. package/lib/alarmsandrules/OperationAlarmsAndRules.js +135 -0
  36. package/lib/alarmsandrules/ServerSideOperationRegionalAlarmsAndRules.d.ts +19 -0
  37. package/lib/alarmsandrules/ServerSideOperationRegionalAlarmsAndRules.js +22 -0
  38. package/lib/alarmsandrules/ServerSideOperationZonalAlarmsAndRules.d.ts +40 -0
  39. package/lib/alarmsandrules/ServerSideOperationZonalAlarmsAndRules.js +46 -0
  40. package/lib/alarmsandrules/ServiceAlarmsAndRules.d.ts +48 -0
  41. package/lib/alarmsandrules/ServiceAlarmsAndRules.js +166 -0
  42. package/lib/alarmsandrules/props/BaseOperationRegionalAlarmsAndRulesProps.d.ts +24 -0
  43. package/lib/alarmsandrules/props/BaseOperationRegionalAlarmsAndRulesProps.js +3 -0
  44. package/lib/alarmsandrules/props/BaseOperationZonalAlarmsAndRulesProps.d.ts +62 -0
  45. package/lib/alarmsandrules/props/BaseOperationZonalAlarmsAndRulesProps.js +3 -0
  46. package/lib/alarmsandrules/props/CanaryOperationRegionalAlarmsAndRulesProps.d.ts +6 -0
  47. package/lib/alarmsandrules/props/CanaryOperationRegionalAlarmsAndRulesProps.js +3 -0
  48. package/lib/alarmsandrules/props/CanaryOperationZonalAlarmsAndRulesProps.d.ts +6 -0
  49. package/lib/alarmsandrules/props/CanaryOperationZonalAlarmsAndRulesProps.js +3 -0
  50. package/lib/alarmsandrules/props/OperationAlarmsAndRulesProps.d.ts +45 -0
  51. package/lib/alarmsandrules/props/OperationAlarmsAndRulesProps.js +3 -0
  52. package/lib/alarmsandrules/props/ServerSideOperationRegionalAlarmsAndRulesProps.d.ts +6 -0
  53. package/lib/alarmsandrules/props/ServerSideOperationRegionalAlarmsAndRulesProps.js +3 -0
  54. package/lib/alarmsandrules/props/ServerSideOperationZonalAlarmsAndRulesProps.d.ts +6 -0
  55. package/lib/alarmsandrules/props/ServerSideOperationZonalAlarmsAndRulesProps.js +3 -0
  56. package/lib/alarmsandrules/props/ServiceAlarmsAndRulesProps.d.ts +13 -0
  57. package/lib/alarmsandrules/props/ServiceAlarmsAndRulesProps.js +3 -0
  58. package/lib/azmapper/AvailabilityZoneMapper.d.ts +86 -0
  59. package/lib/azmapper/AvailabilityZoneMapper.js +200 -0
  60. package/lib/azmapper/IAvailabilityZoneMapper.d.ts +86 -0
  61. package/lib/azmapper/IAvailabilityZoneMapper.js +3 -0
  62. package/lib/azmapper/props/AvailabilityZoneMapperProps.d.ts +13 -0
  63. package/lib/azmapper/props/AvailabilityZoneMapperProps.js +3 -0
  64. package/lib/azmapper/src/index.py +107 -0
  65. package/lib/canaries/CanaryFunction.d.ts +16 -0
  66. package/lib/canaries/CanaryFunction.js +152 -0
  67. package/lib/canaries/CanaryTest.d.ts +10 -0
  68. package/lib/canaries/CanaryTest.js +84 -0
  69. package/lib/canaries/ICanaryFunction.d.ts +6 -0
  70. package/lib/canaries/ICanaryFunction.js +3 -0
  71. package/lib/canaries/props/AddCanaryTestProps.d.ts +66 -0
  72. package/lib/canaries/props/AddCanaryTestProps.js +3 -0
  73. package/lib/canaries/props/CanaryFunctionProps.d.ts +29 -0
  74. package/lib/canaries/props/CanaryFunctionProps.js +3 -0
  75. package/lib/canaries/props/CanaryTestProps.d.ts +21 -0
  76. package/lib/canaries/props/CanaryTestProps.js +3 -0
  77. package/lib/canaries/props/NetworkConfigurationProps.d.ts +16 -0
  78. package/lib/canaries/props/NetworkConfigurationProps.js +3 -0
  79. package/lib/canaries/src/canary.zip +0 -0
  80. package/lib/dashboards/BasicServiceDashboard.d.ts +10 -0
  81. package/lib/dashboards/BasicServiceDashboard.js +130 -0
  82. package/lib/dashboards/ContributorInsightsWidget.d.ts +22 -0
  83. package/lib/dashboards/ContributorInsightsWidget.js +55 -0
  84. package/lib/dashboards/IOperationAvailabilityAndLatencyDashboard.d.ts +10 -0
  85. package/lib/dashboards/IOperationAvailabilityAndLatencyDashboard.js +3 -0
  86. package/lib/dashboards/IServiceAvailabilityAndLatencyDashboard.d.ts +10 -0
  87. package/lib/dashboards/IServiceAvailabilityAndLatencyDashboard.js +3 -0
  88. package/lib/dashboards/OperationAvailabilityAndLatencyDashboard.d.ts +20 -0
  89. package/lib/dashboards/OperationAvailabilityAndLatencyDashboard.js +588 -0
  90. package/lib/dashboards/ServiceAvailabilityAndLatencyDashboard.d.ts +24 -0
  91. package/lib/dashboards/ServiceAvailabilityAndLatencyDashboard.js +475 -0
  92. package/lib/dashboards/props/BasicServiceDashboardProps.d.ts +23 -0
  93. package/lib/dashboards/props/BasicServiceDashboardProps.js +3 -0
  94. package/lib/dashboards/props/ContributorInsightWidgetProps.d.ts +31 -0
  95. package/lib/dashboards/props/ContributorInsightWidgetProps.js +3 -0
  96. package/lib/dashboards/props/OperationAvailabilityAndLatencyDashboardProps.d.ts +84 -0
  97. package/lib/dashboards/props/OperationAvailabilityAndLatencyDashboardProps.js +3 -0
  98. package/lib/dashboards/props/OperationAvailabilityWidgetProps.d.ts +37 -0
  99. package/lib/dashboards/props/OperationAvailabilityWidgetProps.js +3 -0
  100. package/lib/dashboards/props/OperationLatencyWidgetProps.d.ts +37 -0
  101. package/lib/dashboards/props/OperationLatencyWidgetProps.js +3 -0
  102. package/lib/dashboards/props/ServiceAvailabilityAndLatencyDashboardProps.d.ts +30 -0
  103. package/lib/dashboards/props/ServiceAvailabilityAndLatencyDashboardProps.js +3 -0
  104. package/lib/index.d.ts +35 -0
  105. package/lib/index.js +30 -0
  106. package/lib/metrics/ApplicationLoadBalancerMetrics.d.ts +36 -0
  107. package/lib/metrics/ApplicationLoadBalancerMetrics.js +150 -0
  108. package/lib/metrics/AvailabilityAndLatencyMetrics.d.ts +61 -0
  109. package/lib/metrics/AvailabilityAndLatencyMetrics.js +212 -0
  110. package/lib/metrics/NetworkLoadBalancerMetrics.d.ts +19 -0
  111. package/lib/metrics/NetworkLoadBalancerMetrics.js +48 -0
  112. package/lib/metrics/RegionalAvailabilityMetrics.d.ts +19 -0
  113. package/lib/metrics/RegionalAvailabilityMetrics.js +71 -0
  114. package/lib/metrics/RegionalLatencyMetrics.d.ts +33 -0
  115. package/lib/metrics/RegionalLatencyMetrics.js +69 -0
  116. package/lib/metrics/ZonalAvailabilityMetrics.d.ts +19 -0
  117. package/lib/metrics/ZonalAvailabilityMetrics.js +71 -0
  118. package/lib/metrics/ZonalLatencyMetrics.d.ts +29 -0
  119. package/lib/metrics/ZonalLatencyMetrics.js +65 -0
  120. package/lib/metrics/props/AvailabilityAndLatencyMetricProps.d.ts +23 -0
  121. package/lib/metrics/props/AvailabilityAndLatencyMetricProps.js +3 -0
  122. package/lib/metrics/props/AvailabilityMetricProps.d.ts +11 -0
  123. package/lib/metrics/props/AvailabilityMetricProps.js +3 -0
  124. package/lib/metrics/props/LatencyMetricProps.d.ts +15 -0
  125. package/lib/metrics/props/LatencyMetricProps.js +3 -0
  126. package/lib/metrics/props/RegionalAvailabilityMetricProps.d.ts +6 -0
  127. package/lib/metrics/props/RegionalAvailabilityMetricProps.js +3 -0
  128. package/lib/metrics/props/RegionalLatencyMetricProps.d.ts +6 -0
  129. package/lib/metrics/props/RegionalLatencyMetricProps.js +3 -0
  130. package/lib/metrics/props/ServiceAvailabilityMetricProps.d.ts +23 -0
  131. package/lib/metrics/props/ServiceAvailabilityMetricProps.js +3 -0
  132. package/lib/metrics/props/ServiceLatencyMericProps.d.ts +23 -0
  133. package/lib/metrics/props/ServiceLatencyMericProps.js +3 -0
  134. package/lib/metrics/props/ZonalAvailabilityMetricProps.d.ts +10 -0
  135. package/lib/metrics/props/ZonalAvailabilityMetricProps.js +3 -0
  136. package/lib/metrics/props/ZonalLatencyMetricProps.d.ts +10 -0
  137. package/lib/metrics/props/ZonalLatencyMetricProps.js +3 -0
  138. package/lib/monitoring/src/monitoring-layer.zip +0 -0
  139. package/lib/outlier-detection/IOutlierDetectionFunction.d.ts +12 -0
  140. package/lib/outlier-detection/IOutlierDetectionFunction.js +3 -0
  141. package/lib/outlier-detection/OutlierDetectionFunction.d.ts +16 -0
  142. package/lib/outlier-detection/OutlierDetectionFunction.js +126 -0
  143. package/lib/outlier-detection/props/OutlierDetectionFunctionProps.d.ts +12 -0
  144. package/lib/outlier-detection/props/OutlierDetectionFunctionProps.js +3 -0
  145. package/lib/outlier-detection/src/outlier-detection.zip +0 -0
  146. package/lib/outlier-detection/src/scipy-layer.zip +0 -0
  147. package/lib/services/BasicServiceMultiAZObservability.d.ts +64 -0
  148. package/lib/services/BasicServiceMultiAZObservability.js +504 -0
  149. package/lib/services/CanaryMetrics.d.ts +17 -0
  150. package/lib/services/CanaryMetrics.js +19 -0
  151. package/lib/services/CanaryTestMetricsOverride.d.ts +39 -0
  152. package/lib/services/CanaryTestMetricsOverride.js +23 -0
  153. package/lib/services/ContributorInsightRuleDetails.d.ts +42 -0
  154. package/lib/services/ContributorInsightRuleDetails.js +23 -0
  155. package/lib/services/IBasicServiceMultiAZObservability.d.ts +45 -0
  156. package/lib/services/IBasicServiceMultiAZObservability.js +3 -0
  157. package/lib/services/ICanaryMetrics.d.ts +14 -0
  158. package/lib/services/ICanaryMetrics.js +3 -0
  159. package/lib/services/ICanaryTestMetricsOverride.d.ts +36 -0
  160. package/lib/services/ICanaryTestMetricsOverride.js +3 -0
  161. package/lib/services/IContributorInsightRuleDetails.d.ts +38 -0
  162. package/lib/services/IContributorInsightRuleDetails.js +3 -0
  163. package/lib/services/IInstrumentedServiceMultiAZObservability.d.ts +39 -0
  164. package/lib/services/IInstrumentedServiceMultiAZObservability.js +3 -0
  165. package/lib/services/IOperation.d.ts +75 -0
  166. package/lib/services/IOperation.js +3 -0
  167. package/lib/services/IOperationMetricDetails.d.ts +78 -0
  168. package/lib/services/IOperationMetricDetails.js +3 -0
  169. package/lib/services/IService.d.ts +76 -0
  170. package/lib/services/IService.js +3 -0
  171. package/lib/services/IServiceMetricDetails.d.ts +68 -0
  172. package/lib/services/IServiceMetricDetails.js +3 -0
  173. package/lib/services/InstrumentedServiceMultiAZObservability.d.ts +55 -0
  174. package/lib/services/InstrumentedServiceMultiAZObservability.js +310 -0
  175. package/lib/services/Operation.d.ts +78 -0
  176. package/lib/services/Operation.js +34 -0
  177. package/lib/services/OperationMetricDetails.d.ts +82 -0
  178. package/lib/services/OperationMetricDetails.js +50 -0
  179. package/lib/services/Service.d.ts +80 -0
  180. package/lib/services/Service.js +36 -0
  181. package/lib/services/ServiceMetricDetails.d.ts +71 -0
  182. package/lib/services/ServiceMetricDetails.js +28 -0
  183. package/lib/services/props/BasicServiceMultiAZObservabilityProps.d.ts +126 -0
  184. package/lib/services/props/BasicServiceMultiAZObservabilityProps.js +3 -0
  185. package/lib/services/props/CanaryMetricProps.d.ts +14 -0
  186. package/lib/services/props/CanaryMetricProps.js +3 -0
  187. package/lib/services/props/CanaryTestMetricsOverrideProps.d.ts +47 -0
  188. package/lib/services/props/CanaryTestMetricsOverrideProps.js +3 -0
  189. package/lib/services/props/ContributorInsightRuleDetailsProps.d.ts +38 -0
  190. package/lib/services/props/ContributorInsightRuleDetailsProps.js +3 -0
  191. package/lib/services/props/InstrumentedServiceMultiAZObservabilityProps.d.ts +88 -0
  192. package/lib/services/props/InstrumentedServiceMultiAZObservabilityProps.js +3 -0
  193. package/lib/services/props/MetricDimensions.d.ts +61 -0
  194. package/lib/services/props/MetricDimensions.js +63 -0
  195. package/lib/services/props/OperationMetricDetailsProps.d.ts +97 -0
  196. package/lib/services/props/OperationMetricDetailsProps.js +3 -0
  197. package/lib/services/props/OperationProps.d.ts +93 -0
  198. package/lib/services/props/OperationProps.js +3 -0
  199. package/lib/services/props/ServiceMetricDetailsProps.d.ts +68 -0
  200. package/lib/services/props/ServiceMetricDetailsProps.js +3 -0
  201. package/lib/services/props/ServiceProps.d.ts +69 -0
  202. package/lib/services/props/ServiceProps.js +3 -0
  203. package/lib/utilities/AvailabilityMetricType.d.ts +26 -0
  204. package/lib/utilities/AvailabilityMetricType.js +33 -0
  205. package/lib/utilities/LatencyMetricType.d.ts +13 -0
  206. package/lib/utilities/LatencyMetricType.js +20 -0
  207. package/lib/utilities/OutlierDetectionAlgorithm.d.ts +42 -0
  208. package/lib/utilities/OutlierDetectionAlgorithm.js +49 -0
  209. package/lib/utilities/StackWithDynamicSource.d.ts +14 -0
  210. package/lib/utilities/StackWithDynamicSource.js +82 -0
  211. package/package.json +176 -0
  212. 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=