UNPKG

@renovosolutions/cdk-library-cloudwatch-alarms

Version:

AWS CDK Construct Library to automatically create CloudWatch Alarms for resources in a CDK app based on resource type.

500 lines 90 kB
"use strict"; var _a, _b, _c, _d, _e, _f, _g, _h; Object.defineProperty(exports, "__esModule", { value: true }); exports.CloudFrontRecommendedAlarmsAspect = exports.Distribution = exports.CloudFrontDistributionRecommendedAlarms = exports.CloudFrontDistributionDetailedFunctionThrottlesAlarm = exports.CloudFrontDistributionDetailedFunctionExecutionErrorsAlarm = exports.CloudFrontDistributionDetailedFunctionValidationErrorsAlarm = exports.CloudFrontDistributionOriginLatencyAlarm = exports.CloudFrontDistribution5xxErrorRateAlarm = exports.CloudFrontRecommendedAlarmsMetrics = void 0; const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); const aws_cdk_lib_1 = require("aws-cdk-lib"); const constructs_1 = require("constructs"); const common_1 = require("./common"); /** * The recommended metrics for CloudFront alarms. */ var CloudFrontRecommendedAlarmsMetrics; (function (CloudFrontRecommendedAlarmsMetrics) { /** * The percentage of all viewer requests for which the response's HTTP status code is 5xx. */ CloudFrontRecommendedAlarmsMetrics["ERROR_RATE_5XX"] = "5xxErrorRate"; /** * The total time spent from when CloudFront receives a request to when it starts providing * a response to the network (not the viewer), for requests that are served from the origin, * not the CloudFront cache. This is also known as first byte latency, or time-to-first-byte. */ CloudFrontRecommendedAlarmsMetrics["ORIGIN_LATENCY"] = "OriginLatency"; /** * The number of validation errors produced by the function in a given time period. * Validation errors occur when the function runs successfully but returns invalid data * (an invalid {@link https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/functions-event-structure.html|event object}). */ CloudFrontRecommendedAlarmsMetrics["FUNCTION_VALIDATION_ERRORS"] = "FunctionValidationErrors"; /** * The number of execution errors that occurred in a given time period. Execution errors occur * when the function fails to complete successfully. */ CloudFrontRecommendedAlarmsMetrics["FUNCTION_EXECUTION_ERRORS"] = "FunctionExecutionErrors"; /** * The number of times that the function was throttled in a given time period. * Functions can be throttled for the following reasons: * - The function continuously exceeds the maximum time allowed for execution * - The function results in compilation errors * - There is an unusually high number of requests per second */ CloudFrontRecommendedAlarmsMetrics["FUNCTION_THROTTLES"] = "FunctionThrottles"; })(CloudFrontRecommendedAlarmsMetrics || (exports.CloudFrontRecommendedAlarmsMetrics = CloudFrontRecommendedAlarmsMetrics = {})); /** * This alarm monitors the percentage of 5xx error responses from your origin server, to help you detect if * the CloudFront service is having issues. * * See {@link https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/troubleshooting-response-errors.html|Troubleshooting error responses from your origin} for information to help you understand the problems with your server. * * The alarm is triggered when the percentage exceeds the threshold. */ class CloudFrontDistribution5xxErrorRateAlarm extends aws_cdk_lib_1.aws_cloudwatch.Alarm { constructor(scope, id, props) { const alarmName = props.alarmName ?? `${props.distribution.distributionId} - ${CloudFrontRecommendedAlarmsMetrics.ERROR_RATE_5XX}`; const period = props.period ?? aws_cdk_lib_1.Duration.minutes(1); const evaluationPeriods = props.evaluationPeriods ?? 5; const datapointsToAlarm = props.datapointsToAlarm ?? 5; const threshold = props.threshold; const treatMissingData = props.treatMissingData ?? aws_cdk_lib_1.aws_cloudwatch.TreatMissingData.MISSING; const alarmDescription = props.alarmDescription ?? 'This alarm is used to detect problems with serving requests from the origin' + ' server, or problems with communication between CloudFront and your origin server.'; (0, common_1.validateTotalAlarmPeriod)(period, evaluationPeriods, alarmName); super(scope, id, { alarmName, metric: props.distribution.metric5xxErrorRate({ period, }), threshold, evaluationPeriods, datapointsToAlarm, treatMissingData, comparisonOperator: aws_cdk_lib_1.aws_cloudwatch.ComparisonOperator.GREATER_THAN_THRESHOLD, alarmDescription, }); if (props.alarmAction) this.addAlarmAction(props.alarmAction); if (props.okAction) this.addOkAction(props.okAction); if (props.insufficientDataAction) this.addInsufficientDataAction(props.insufficientDataAction); } } exports.CloudFrontDistribution5xxErrorRateAlarm = CloudFrontDistribution5xxErrorRateAlarm; _a = JSII_RTTI_SYMBOL_1; CloudFrontDistribution5xxErrorRateAlarm[_a] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.CloudFrontDistribution5xxErrorRateAlarm", version: "0.0.13" }; ; /** * The alarm helps to monitor if the origin server is taking too long to respond. * * If the server takes too long to respond, it might lead to a timeout. * Refer to {@link https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/http-504-gateway-timeout.html#http-504-gateway-timeout-slow-application|find and fix delayed responses from applications on your origin server} * if you experience consistently high OriginLatency values. * * The alarm is triggered when the percentage is lower or equals the threshold. */ class CloudFrontDistributionOriginLatencyAlarm extends aws_cdk_lib_1.aws_cloudwatch.Alarm { constructor(scope, id, props) { const alarmName = props.alarmName ?? `${props.distribution.distributionId} - ${CloudFrontRecommendedAlarmsMetrics.ORIGIN_LATENCY}`; const period = props.period ?? aws_cdk_lib_1.Duration.minutes(1); const evaluationPeriods = props.evaluationPeriods ?? 5; const datapointsToAlarm = props.datapointsToAlarm ?? 5; const threshold = props.threshold; const treatMissingData = props.treatMissingData ?? aws_cdk_lib_1.aws_cloudwatch.TreatMissingData.MISSING; const alarmDescription = props.alarmDescription ?? 'This alarm is used to detect problems with the origin server taking' + ' too long to respond.'; (0, common_1.validateTotalAlarmPeriod)(period, evaluationPeriods, alarmName); super(scope, id, { alarmName, metric: props.distribution.metricOriginLatency({ period, statistic: 'p90', }), threshold, evaluationPeriods, datapointsToAlarm, treatMissingData, comparisonOperator: aws_cdk_lib_1.aws_cloudwatch.ComparisonOperator.GREATER_THAN_THRESHOLD, alarmDescription, }); if (props.alarmAction) this.addAlarmAction(props.alarmAction); if (props.okAction) this.addOkAction(props.okAction); if (props.insufficientDataAction) this.addInsufficientDataAction(props.insufficientDataAction); } } exports.CloudFrontDistributionOriginLatencyAlarm = CloudFrontDistributionOriginLatencyAlarm; _b = JSII_RTTI_SYMBOL_1; CloudFrontDistributionOriginLatencyAlarm[_b] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.CloudFrontDistributionOriginLatencyAlarm", version: "0.0.13" }; ; /** * This alarm helps you monitor validation errors from CloudFront functions so that you can take * steps to resolve them. * * Analyze the CloudWatch function logs and look at the function code to find and resolve the root * cause of the problem. * * The alarm is triggered when the number of validation errors is greater than threshold. */ class CloudFrontDistributionDetailedFunctionValidationErrorsAlarm extends aws_cdk_lib_1.aws_cloudwatch.Alarm { constructor(scope, id, props) { const alarmName = props.alarmName ?? `${props.distribution.distributionId}-${props.functionName} - ${CloudFrontRecommendedAlarmsMetrics.FUNCTION_VALIDATION_ERRORS}`; const period = props.period ?? aws_cdk_lib_1.Duration.minutes(1); const evaluationPeriods = props.evaluationPeriods ?? 2; const datapointsToAlarm = props.datapointsToAlarm ?? 2; const threshold = props.threshold ?? 0; const treatMissingData = props.treatMissingData ?? aws_cdk_lib_1.aws_cloudwatch.TreatMissingData.MISSING; const alarmDescription = props.alarmDescription ?? 'This alarm is used to detect validation errors from CloudFront functions.'; (0, common_1.validateTotalAlarmPeriod)(period, evaluationPeriods, alarmName); super(scope, id, { alarmName, metric: new aws_cdk_lib_1.aws_cloudwatch.Metric({ namespace: 'AWS/CloudFront', metricName: CloudFrontRecommendedAlarmsMetrics.FUNCTION_VALIDATION_ERRORS, dimensionsMap: { DistributionId: props.distribution.distributionId, FunctionName: props.functionName, Region: 'GLOBAL', }, period, statistic: 'Sum', }), threshold, evaluationPeriods, datapointsToAlarm, treatMissingData, comparisonOperator: aws_cdk_lib_1.aws_cloudwatch.ComparisonOperator.GREATER_THAN_THRESHOLD, alarmDescription, }); if (props.alarmAction) this.addAlarmAction(props.alarmAction); if (props.okAction) this.addOkAction(props.okAction); if (props.insufficientDataAction) this.addInsufficientDataAction(props.insufficientDataAction); } } exports.CloudFrontDistributionDetailedFunctionValidationErrorsAlarm = CloudFrontDistributionDetailedFunctionValidationErrorsAlarm; _c = JSII_RTTI_SYMBOL_1; CloudFrontDistributionDetailedFunctionValidationErrorsAlarm[_c] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.CloudFrontDistributionDetailedFunctionValidationErrorsAlarm", version: "0.0.13" }; ; /** * This alarm helps you monitor execution errors from CloudFront functions so that you can take * steps to resolve them. * * Analyze the CloudWatch function logs and look at the function code to find and resolve the root * cause of the problem. * * The alarm is triggered when the number of execution errors is greater than threshold. */ class CloudFrontDistributionDetailedFunctionExecutionErrorsAlarm extends aws_cdk_lib_1.aws_cloudwatch.Alarm { constructor(scope, id, props) { const alarmName = props.alarmName ?? `${props.distribution.distributionId}-${props.functionName} - ${CloudFrontRecommendedAlarmsMetrics.FUNCTION_EXECUTION_ERRORS}`; const period = props.period ?? aws_cdk_lib_1.Duration.minutes(1); const evaluationPeriods = props.evaluationPeriods ?? 5; const datapointsToAlarm = props.datapointsToAlarm ?? 5; const threshold = props.threshold ?? 0; const treatMissingData = props.treatMissingData ?? aws_cdk_lib_1.aws_cloudwatch.TreatMissingData.MISSING; const alarmDescription = props.alarmDescription ?? 'This alarm is used to detect execution errors from CloudFront functions.'; (0, common_1.validateTotalAlarmPeriod)(period, evaluationPeriods, alarmName); super(scope, id, { alarmName, metric: new aws_cdk_lib_1.aws_cloudwatch.Metric({ namespace: 'AWS/CloudFront', metricName: CloudFrontRecommendedAlarmsMetrics.FUNCTION_EXECUTION_ERRORS, dimensionsMap: { DistributionId: props.distribution.distributionId, FunctionName: props.functionName, Region: 'GLOBAL', }, period, statistic: 'Sum', }), threshold, evaluationPeriods, datapointsToAlarm, treatMissingData, comparisonOperator: aws_cdk_lib_1.aws_cloudwatch.ComparisonOperator.GREATER_THAN_THRESHOLD, alarmDescription, }); if (props.alarmAction) this.addAlarmAction(props.alarmAction); if (props.okAction) this.addOkAction(props.okAction); if (props.insufficientDataAction) this.addInsufficientDataAction(props.insufficientDataAction); } } exports.CloudFrontDistributionDetailedFunctionExecutionErrorsAlarm = CloudFrontDistributionDetailedFunctionExecutionErrorsAlarm; _d = JSII_RTTI_SYMBOL_1; CloudFrontDistributionDetailedFunctionExecutionErrorsAlarm[_d] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.CloudFrontDistributionDetailedFunctionExecutionErrorsAlarm", version: "0.0.13" }; ; /** * This alarm helps you to monitor if your CloudFront function is throttled. * * If your function is throttled, it means that it is taking too long to execute. * To avoid function throttles, consider optimizing the function code. * * The alarm is triggered when the number of times the function was throttled is greater than threshold. */ class CloudFrontDistributionDetailedFunctionThrottlesAlarm extends aws_cdk_lib_1.aws_cloudwatch.Alarm { constructor(scope, id, props) { const alarmName = props.alarmName ?? `${props.distribution.distributionId}-${props.functionName} - ${CloudFrontRecommendedAlarmsMetrics.FUNCTION_THROTTLES}`; const period = props.period ?? aws_cdk_lib_1.Duration.minutes(1); const evaluationPeriods = props.evaluationPeriods ?? 5; const datapointsToAlarm = props.datapointsToAlarm ?? 5; const threshold = props.threshold ?? 0; const treatMissingData = props.treatMissingData ?? aws_cdk_lib_1.aws_cloudwatch.TreatMissingData.MISSING; const alarmDescription = props.alarmDescription ?? 'This alarm can detect when your CloudFront function is throttled' + ' so that you can react and resolve the issue for a smooth customer experience.'; (0, common_1.validateTotalAlarmPeriod)(period, evaluationPeriods, alarmName); super(scope, id, { alarmName, metric: new aws_cdk_lib_1.aws_cloudwatch.Metric({ namespace: 'AWS/CloudFront', metricName: CloudFrontRecommendedAlarmsMetrics.FUNCTION_THROTTLES, dimensionsMap: { DistributionId: props.distribution.distributionId, FunctionName: props.functionName, Region: 'GLOBAL', }, period, statistic: 'Sum', }), threshold, evaluationPeriods, datapointsToAlarm, treatMissingData, comparisonOperator: aws_cdk_lib_1.aws_cloudwatch.ComparisonOperator.GREATER_THAN_THRESHOLD, alarmDescription, }); if (props.alarmAction) this.addAlarmAction(props.alarmAction); if (props.okAction) this.addOkAction(props.okAction); if (props.insufficientDataAction) this.addInsufficientDataAction(props.insufficientDataAction); } } exports.CloudFrontDistributionDetailedFunctionThrottlesAlarm = CloudFrontDistributionDetailedFunctionThrottlesAlarm; _e = JSII_RTTI_SYMBOL_1; CloudFrontDistributionDetailedFunctionThrottlesAlarm[_e] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.CloudFrontDistributionDetailedFunctionThrottlesAlarm", version: "0.0.13" }; ; /** * A construct that creates the recommended alarms for an CloudFront Distribution. * * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html#CloudFront */ class CloudFrontDistributionRecommendedAlarms extends constructs_1.Construct { constructor(scope, id, props) { super(scope, id); if (!props.excludeAlarms?.includes(CloudFrontRecommendedAlarmsMetrics.ERROR_RATE_5XX)) { this.alarm5xxErrorRate = new CloudFrontDistribution5xxErrorRateAlarm(this, `${props.distribution.node.id}_5xxErrorRate`, { distribution: props.distribution, treatMissingData: props.treatMissingData, ...props.config5xxErrorRateAlarm, }); if (props.defaultAlarmAction && !props.config5xxErrorRateAlarm.alarmAction) { this.alarm5xxErrorRate.addAlarmAction(props.defaultAlarmAction); } if (props.defaultOkAction && !props.config5xxErrorRateAlarm.okAction) { this.alarm5xxErrorRate.addOkAction(props.defaultOkAction); } if (props.defaultInsufficientDataAction && !props.config5xxErrorRateAlarm.insufficientDataAction) { this.alarm5xxErrorRate.addInsufficientDataAction(props.defaultInsufficientDataAction); } } if (!props.excludeAlarms?.includes(CloudFrontRecommendedAlarmsMetrics.ORIGIN_LATENCY)) { this.alarmOriginLatency = new CloudFrontDistributionOriginLatencyAlarm(this, `${props.distribution.node.id}_OriginLatency`, { distribution: props.distribution, treatMissingData: props.treatMissingData, ...props.configOriginLatencyAlarm, }); if (props.defaultAlarmAction && !props.configOriginLatencyAlarm.alarmAction) { this.alarmOriginLatency.addAlarmAction(props.defaultAlarmAction); } if (props.defaultOkAction && !props.configOriginLatencyAlarm.okAction) { this.alarmOriginLatency.addOkAction(props.defaultOkAction); } if (props.defaultInsufficientDataAction && !props.configOriginLatencyAlarm.insufficientDataAction) { this.alarmOriginLatency.addInsufficientDataAction(props.defaultInsufficientDataAction); } } if (!props.excludeAlarms?.includes(CloudFrontRecommendedAlarmsMetrics.FUNCTION_VALIDATION_ERRORS) && props.configDetailedFunctionValidationErrorsAlarmList) { props.configDetailedFunctionValidationErrorsAlarmList.forEach((config, index) => { let alarmConfig = { distribution: props.distribution, treatMissingData: props.treatMissingData, ...config, }; if (props.defaultAlarmAction && !config.alarmAction) { alarmConfig = { ...alarmConfig, alarmAction: props.defaultAlarmAction }; } if (props.defaultOkAction && !config.okAction) { alarmConfig = { ...alarmConfig, okAction: props.defaultOkAction }; } if (props.defaultInsufficientDataAction && !config.insufficientDataAction) { alarmConfig = { ...alarmConfig, insufficientDataAction: props.defaultInsufficientDataAction }; } new CloudFrontDistributionDetailedFunctionValidationErrorsAlarm(this, `${props.distribution.node.id}_DetailedFunctionValidationErrors${index}`, alarmConfig); }); } if (!props.excludeAlarms?.includes(CloudFrontRecommendedAlarmsMetrics.FUNCTION_EXECUTION_ERRORS) && props.configDetailedFunctionExecutionErrorsAlarmList) { props.configDetailedFunctionExecutionErrorsAlarmList.forEach((config, index) => { let alarmConfig = { distribution: props.distribution, treatMissingData: props.treatMissingData, ...config, }; if (props.defaultAlarmAction && !config.alarmAction) { alarmConfig = { ...alarmConfig, alarmAction: props.defaultAlarmAction }; } if (props.defaultOkAction && !config.okAction) { alarmConfig = { ...alarmConfig, okAction: props.defaultOkAction }; } if (props.defaultInsufficientDataAction && !config.insufficientDataAction) { alarmConfig = { ...alarmConfig, insufficientDataAction: props.defaultInsufficientDataAction }; } new CloudFrontDistributionDetailedFunctionExecutionErrorsAlarm(this, `${props.distribution.node.id}_DetailedFunctionExecutionErrors${index}`, alarmConfig); }); } if (!props.excludeAlarms?.includes(CloudFrontRecommendedAlarmsMetrics.FUNCTION_THROTTLES) && props.configDetailedFunctionThrottlesAlarmList) { props.configDetailedFunctionThrottlesAlarmList.forEach((config, index) => { let alarmConfig = { distribution: props.distribution, treatMissingData: props.treatMissingData, ...config, }; if (props.defaultAlarmAction && !config.alarmAction) { alarmConfig = { ...alarmConfig, alarmAction: props.defaultAlarmAction }; } if (props.defaultOkAction && !config.okAction) { alarmConfig = { ...alarmConfig, okAction: props.defaultOkAction }; } if (props.defaultInsufficientDataAction && !config.insufficientDataAction) { alarmConfig = { ...alarmConfig, insufficientDataAction: props.defaultInsufficientDataAction }; } new CloudFrontDistributionDetailedFunctionThrottlesAlarm(this, `${props.distribution.node.id}_DetailedFunctionThrottles${index}`, alarmConfig); }); } } } exports.CloudFrontDistributionRecommendedAlarms = CloudFrontDistributionRecommendedAlarms; _f = JSII_RTTI_SYMBOL_1; CloudFrontDistributionRecommendedAlarms[_f] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.CloudFrontDistributionRecommendedAlarms", version: "0.0.13" }; /** * An extension for the Distribution construct that provides methods * to create recommended alarms. */ class Distribution extends aws_cdk_lib_1.aws_cloudfront.Distribution { constructor(scope, id, props) { super(scope, id, props); } /** * Creates an alarm that monitors the 5xxErrorRate for the CloudFront distribution. */ alarm5xxErrorRate(props) { return new CloudFrontDistribution5xxErrorRateAlarm(this, '5xxErrorRateAlarm', { distribution: this, ...props, }); } /** * Creates an alarm that monitors the OriginLatency for the CloudFront distribution. */ alarmOriginLatency(props) { return new CloudFrontDistributionOriginLatencyAlarm(this, 'OriginLatencyAlarm', { distribution: this, ...props, }); } /** * Creates a list of alarms that monitor the total number of validation errors produced by the function in a given time period. */ alarmDetailedFunctionValidationErrors(props) { let alarmList = []; props.forEach((config, index) => { const alarm = new CloudFrontDistributionDetailedFunctionValidationErrorsAlarm(this, `DetailedFunctionValidationErrors${index}`, { distribution: this, ...config, }); alarmList.push(alarm); }); return alarmList; } /** * Creates a list of alarms that monitor the total number of execution errors produced by the function in a given time period. */ alarmDetailedFunctionExecutionErrors(props) { let alarmList = []; props.forEach((config, index) => { const alarm = new CloudFrontDistributionDetailedFunctionExecutionErrorsAlarm(this, `DetailedFunctionExecutionErrors${index}`, { distribution: this, ...config, }); alarmList.push(alarm); }); return alarmList; } /** * Creates a list of alarms that monitor the total number of times that the function was throttled in a given time period. */ alarmDetailedFunctionThrottles(props) { let alarmList = []; props.forEach((config, index) => { const alarm = new CloudFrontDistributionDetailedFunctionThrottlesAlarm(this, `DetailedFunctionThrottles${index}`, { distribution: this, ...config, }); alarmList.push(alarm); }); return alarmList; } /** * Creates the recommended alarms for the CloudFront Distribution. * * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html#CloudFront */ applyRecommendedAlarms(props) { return new CloudFrontDistributionRecommendedAlarms(this, 'CloudFrontDistributionRecommendedAlarms', { distribution: this, ...props, }); } } exports.Distribution = Distribution; _g = JSII_RTTI_SYMBOL_1; Distribution[_g] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.Distribution", version: "0.0.13" }; /** * Configures the recommended alarms for an CloudFront Distribution. * * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html#CloudFront */ class CloudFrontRecommendedAlarmsAspect { constructor(props) { this.props = props; } visit(node) { if (node instanceof aws_cdk_lib_1.aws_cloudfront.Distribution) { if (this.props.excludeResources && this.props.excludeResources.includes(node.node.id)) { return; } else { const distribution = node; new CloudFrontDistributionRecommendedAlarms(distribution, 'CloudFrontDistributionRecommendedAlarmsFromAspect', { distribution, ...this.props, }); } } } } exports.CloudFrontRecommendedAlarmsAspect = CloudFrontRecommendedAlarmsAspect; _h = JSII_RTTI_SYMBOL_1; CloudFrontRecommendedAlarmsAspect[_h] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.CloudFrontRecommendedAlarmsAspect", version: "0.0.13" }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xvdWRmcm9udC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9jbG91ZGZyb250LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsNkNBS3FCO0FBQ3JCLDJDQUFtRDtBQUNuRCxxQ0FBb0U7QUFFcEU7O0dBRUc7QUFDSCxJQUFZLGtDQThCWDtBQTlCRCxXQUFZLGtDQUFrQztJQUM1Qzs7T0FFRztJQUNILHFFQUErQixDQUFBO0lBQy9COzs7O09BSUc7SUFDSCxzRUFBZ0MsQ0FBQTtJQUNoQzs7OztPQUlHO0lBQ0gsNkZBQXVELENBQUE7SUFDdkQ7OztPQUdHO0lBQ0gsMkZBQXFELENBQUE7SUFDckQ7Ozs7OztPQU1HO0lBQ0gsOEVBQXdDLENBQUE7QUFDMUMsQ0FBQyxFQTlCVyxrQ0FBa0Msa0RBQWxDLGtDQUFrQyxRQThCN0M7QUE2RUQ7Ozs7Ozs7R0FPRztBQUNILE1BQWEsdUNBQXdDLFNBQVEsNEJBQVUsQ0FBQyxLQUFLO0lBQzNFLFlBQVksS0FBaUIsRUFBRSxFQUFVLEVBQUUsS0FBbUQ7UUFDNUYsTUFBTSxTQUFTLEdBQUcsS0FBSyxDQUFDLFNBQVMsSUFBSSxHQUFHLEtBQUssQ0FBQyxZQUFZLENBQUMsY0FBYyxNQUFNLGtDQUFrQyxDQUFDLGNBQWMsRUFBRSxDQUFDO1FBQ25JLE1BQU0sTUFBTSxHQUFHLEtBQUssQ0FBQyxNQUFNLElBQUksc0JBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDbkQsTUFBTSxpQkFBaUIsR0FBRyxLQUFLLENBQUMsaUJBQWlCLElBQUksQ0FBQyxDQUFDO1FBQ3ZELE1BQU0saUJBQWlCLEdBQUcsS0FBSyxDQUFDLGlCQUFpQixJQUFJLENBQUMsQ0FBQztRQUN2RCxNQUFNLFNBQVMsR0FBRyxLQUFLLENBQUMsU0FBUyxDQUFDO1FBQ2xDLE1BQU0sZ0JBQWdCLEdBQUcsS0FBSyxDQUFDLGdCQUFnQixJQUFJLDRCQUFVLENBQUMsZ0JBQWdCLENBQUMsT0FBTyxDQUFD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LElBQUksRUFBRSx5Q0FBeUMsRUFBRTtZQUNsRyxZQUFZLEVBQUUsSUFBSTtZQUNsQixHQUFHLEtBQUs7U0FDVCxDQUFDLENBQUM7SUFDTCxDQUFDOztBQXpGSCxvQ0EwRkM7OztBQUVEOzs7O0dBSUc7QUFDSCxNQUFhLGlDQUFpQztJQUM1QyxZQUE2QixLQUFvRDtRQUFwRCxVQUFLLEdBQUwsS0FBSyxDQUErQztJQUFHLENBQUM7SUFFOUUsS0FBSyxDQUFDLElBQWdCO1FBQzNCLElBQUksSUFBSSxZQUFZLDRCQUFVLENBQUMsWUFBWSxFQUFFLENBQUM7WUFDNUMsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLGdCQUFnQixJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsZ0JBQWdCLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQztnQkFDdEYsT0FBTztZQUNULENBQUM7aUJBQU0sQ0FBQztnQkFDTixNQUFNLFlBQVksR0FBRyxJQUErQixDQUFDO2dCQUVyRCxJQUFJLHVDQUF1QyxDQUFDLFlBQVksRUFBRSxtREFBbUQsRUFBRTtvQkFDN0csWUFBWTtvQkFDWixHQUFHLElBQUksQ0FBQyxLQUFLO2lCQUNkLENBQUMsQ0FBQztZQUNMLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQzs7QUFoQkgsOEVBaUJDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgSUFzcGVjdCxcbiAgYXdzX2Nsb3VkZnJvbnQgYXMgY2xvdWRmcm9udCxcbiAgYXdzX2Nsb3Vkd2F0Y2ggYXMgY2xvdWR3YXRjaCxcbiAgRHVyYXRpb24sXG59IGZyb20gJ2F3cy1jZGstbGliJztcbmltcG9ydCB7IENvbnN0cnVjdCwgSUNvbnN0cnVjdCB9IGZyb20gJ2NvbnN0cnVjdHMnO1xuaW1wb3J0IHsgQWxhcm1CYXNlUHJvcHMsIHZhbGlkYXRlVG90YWxBbGFybVBlcmlvZCB9IGZyb20gJy4vY29tbW9uJztcblxuLyoqXG4gKiBUaGUgcmVjb21tZW5kZWQgbWV0cmljcyBmb3IgQ2xvdWRGcm9udCBhbGFybXMuXG4gKi9cbmV4cG9ydCBlbnVtIENsb3VkRnJvbnRSZWNvbW1lbmRlZEFsYXJtc01ldHJpY3Mge1xuICAvKipcbiAgICogVGhlIHBlcmNlbnRhZ2Ugb2YgYWxsIHZpZXdlciByZXF1ZXN0cyBmb3Igd2hpY2ggdGhlIHJlc3BvbnNlJ3MgSFRUUCBzdGF0dXMgY29kZSBpcyA1eHguXG4gICAqL1xuICBFUlJPUl9SQVRFXzVYWCA9ICc1eHhFcnJvclJhdGUnLFxuICAvKipcbiAgICogVGhlIHRvdGFsIHRpbWUgc3BlbnQgZnJvbSB3aGVuIENsb3VkRnJvbnQgcmVjZWl2ZXMgYSByZXF1ZXN0IHRvIHdoZW4gaXQgc3RhcnRzIHByb3ZpZGluZ1xuICAgKiBhIHJlc3BvbnNlIHRvIHRoZSBuZXR3b3JrIChub3QgdGhlIHZpZXdlciksIGZvciByZXF1ZXN0cyB0aGF0IGFyZSBzZXJ2ZWQgZnJvbSB0aGUgb3JpZ2luLFxuICAgKiBub3QgdGhlIENsb3VkRnJvbnQgY2FjaGUuIFRoaXMgaXMgYWxzbyBrbm93biBhcyBmaXJzdCBieXRlIGxhdGVuY3ksIG9yIHRpbWUtdG8tZmlyc3QtYnl0ZS5cbiAgICovXG4gIE9SSUdJTl9MQVRFTkNZID0gJ09yaWdpbkxhdGVuY3knLFxuICAvKipcbiAgICogVGhlIG51bWJlciBvZiB2YWxpZGF0aW9uIGVycm9ycyBwcm9kdWNlZCBieSB0aGUgZnVuY3Rpb24gaW4gYSBnaXZlbiB0aW1lIHBlcmlvZC5cbiAgICogVmFsaWRhdGlvbiBlcnJvcnMgb2NjdXIgd2hlbiB0aGUgZnVuY3Rpb24gcnVucyBzdWNjZXNzZnVsbHkgYnV0IHJldHVybnMgaW52YWxpZCBkYXRhXG4gICAqIChhbiBpbnZhbGlkIHtAbGluayBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQW1hem9uQ2xvdWRGcm9udC9sYXRlc3QvRGV2ZWxvcGVyR3VpZGUvZnVuY3Rpb25zLWV2ZW50LXN0cnVjdHVyZS5odG1sfGV2ZW50IG9iamVjdH0pLlxuICAgKi9cbiAgRlVOQ1RJT05fVkFMSURBVElPTl9FUlJPUlMgPSAnRnVuY3Rpb25WYWxpZGF0aW9uRXJyb3JzJyxcbiAgLyoqXG4gICAqIFRoZSBudW1iZXIgb2YgZXhlY3V0aW9uIGVycm9ycyB0aGF0IG9jY3VycmVkIGluIGEgZ2l2ZW4gdGltZSBwZXJpb2QuIEV4ZWN1dGlvbiBlcnJvcnMgb2NjdXJcbiAgICogd2hlbiB0aGUgZnVuY3Rpb24gZmFpbHMgdG8gY29tcGxldGUgc3VjY2Vzc2Z1bGx5LlxuICAgKi9cbiAgRlVOQ1RJT05fRVhFQ1VUSU9OX0VSUk9SUyA9ICdGdW5jdGlvbkV4ZWN1dGlvbkVycm9ycycsXG4gIC8qKlxuICAgKiBUaGUgbnVtYmVyIG9mIHRpbWVzIHRoYXQgdGhlIGZ1bmN0aW9uIHdhcyB0aHJvdHRsZWQgaW4gYSBnaXZlbiB0aW1lIHBlcmlvZC5cbiAgICogRnVuY3Rpb25zIGNhbiBiZSB0aHJvdHRsZWQgZm9yIHRoZSBmb2xsb3dpbmcgcmVhc29uczpcbiAgICogLSBUaGUgZnVuY3Rpb24gY29udGludW91c2x5IGV4Y2VlZHMgdGhlIG1heGltdW0gdGltZSBhbGxvd2VkIGZvciBleGVjdXRpb25cbiAgICogLSBUaGUgZnVuY3Rpb24gcmVzdWx0cyBpbiBjb21waWxhdGlvbiBlcnJvcnNcbiAgICogLSBUaGVyZSBpcyBhbiB1bnVzdWFsbHkgaGlnaCBudW1iZXIgb2YgcmVxdWVzdHMgcGVyIHNlY29uZFxuICAgKi9cbiAgRlVOQ1RJT05fVEhST1RUTEVTID0gJ0Z1bmN0aW9uVGhyb3R0bGVzJyxcbn1cblxuLyoqXG4gKiBUaGUgY29tbW9uIG9wdGlvbmFsIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBhbGFybXMuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ2xvdWRGcm9udEFsYXJtQmFzZUNvbmZpZyBleHRlbmRzIEFsYXJtQmFzZVByb3BzIHtcbiAgLyoqXG4gICAqIFRoZSBwZXJpb2Qgb3ZlciB3aGljaCB0aGUgc3BlY2lmaWVkIHN0YXRpc3RpYyBpcyBhcHBsaWVkLlxuICAgKlxuICAgKiBAZGVmYXVsdCBEdXJhdGlvbi5taW51dGVzKDEpXG4gICAqL1xuICByZWFkb25seSBwZXJpb2Q/OiBEdXJhdGlvbjtcbn1cblxuLyoqXG4gKiBUaGUgY29tbW9uIHByb3BlcnRpZXMgZm9yIHRoZSBDbG91ZEZyb250IGFsYXJtcyB3aGVuIG1vbml0b3JpbmcgcmVzb3VyY2UgYW5kIG1ldGhvZCBkaW1lbnNpb25zLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIENsb3VkRnJvbnREZXRhaWxlZEFsYXJtQ29uZmlnIHtcbiAgLyoqXG4gICAqIFRoZSBuYW1lIG9mIHRoZSBmdW5jdGlvbiB0byBtb25pdG9yLCB1c2VkIGFzIGEgZGlzY3JpbWluYXRvciBpbiB0aGUgYWxhcm0gbmFtZS5cbiAgICovXG4gIHJlYWRvbmx5IGZ1bmN0aW9uTmFtZTogc3RyaW5nO1xufVxuXG4vKipcbiAqIFRoZSBjb21tb24gcHJvcGVydGllcyBmb3IgdGhlIENsb3VkRnJvbnQgRGlzdHJpYnV0aW9uIGFsYXJtcy5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDbG91ZEZyb250RGlzdHJpYnV0aW9uQWxhcm1Qcm9wcyB7XG4gIC8qKlxuICAgKiBUaGUgQ2xvdWRGcm9udCBEaXN0cmlidXRpb24gdG8gbW9uaXRvci5cbiAgICovXG4gIHJlYWRvbmx5IGRpc3RyaWJ1dGlvbjogY2xvdWRmcm9udC5EaXN0cmlidXRpb247XG59XG5cbi8qKlxuICogQ29uZmlndXJhdGlvbiBmb3IgdGhlIDV4eEVycm9yUmF0ZSBhbGFybS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDbG91ZEZyb250NXh4RXJyb3JSYXRlQWxhcm1Db25maWcgZXh0ZW5kcyBDbG91ZEZyb250QWxhcm1CYXNlQ29uZmlnIHtcbiAgLyoqXG4gICAqIFRoZSByZWNvbW1lbmRlZCB0aHJlc2hvbGQgdmFsdWUgZm9yIHRoaXMgYWxhcm0gaXMgaGlnaGx5IGRlcGVuZGVudCBvbiB0aGUgdG9sZXJhbmNlXG4gICAqIGZvciA1eHggcmVzcG9uc2VzLiBZb3UgY2FuIGFuYWx5emUgaGlzdG9yaWNhbCBkYXRhIGFuZCB0cmVuZHMsIGFuZCB0aGVuIHNldCB0aGUgdGhyZXNob2xkXG4gICAqIGFjY29yZGluZ2x5LiBCZWNhdXNlIDV4eCBlcnJvcnMgY2FuIGJlIGNhdXNlZCBieSB0cmFuc2llbnQgaXNzdWVzLCB3ZSByZWNvbW1lbmQgdGhhdCB5b3VcbiAgICogc2V0IHRoZSB0aHJlc2hvbGQgdG8gYSB2YWx1ZSBncmVhdGVyIHRoYW4gMCBzbyB0aGF0IHRoZSBhbGFybSBpcyBub3QgdG9vIHNlbnNpdGl2ZS5cbiAgICovXG4gIHJlYWRvbmx5IHRocmVzaG9sZDogbnVtYmVyO1xuICAvKipcbiAgICogVGhlIG51bWJlciBvZiBwZXJpb2RzIG92ZXIgd2hpY2ggZGF0YSBpcyBjb21wYXJlZCB0byB0aGUgc3BlY2lmaWVkIHRocmVzaG9sZC5cbiAgICpcbiAgICogQGRlZmF1bHQgNVxuICAgKi9cbiAgcmVhZG9ubHkgZXZhbHVhdGlvblBlcmlvZHM/OiBudW1iZXI7XG4gIC8qKlxuICAgKiBUaGUgbnVtYmVyIG9mIGRhdGEgcG9pbnRzIHRoYXQgbXVzdCBiZSBicmVhY2hpbmcgdG8gdHJpZ2dlciB0aGUgYWxhcm0uXG4gICAqXG4gICAqIEBkZWZhdWx0IDVcbiAgICovXG4gIHJlYWRvbmx5IGRhdGFwb2ludHNUb0FsYXJtPzogbnVtYmVyO1xuICAvKipcbiAgICogVGhlIGFsYXJtIG5hbWUuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gZGlzdHJpYnV0aW9uSWQgKyAnIC0gNXh4RXJyb3JSYXRlJ1xuICAgKi9cbiAgcmVhZG9ubHkgYWxhcm1OYW1lPzogc3RyaW5nO1xuICAvKipcbiAgICogVGhlIGRlc2NyaXB0aW9uIG9mIHRoZSBhbGFybS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBUaGlzIGFsYXJtIGlzIHVzZWQgdG8gZGV0ZWN0IHByb2JsZW1zIHdpdGggc2VydmluZyByZXF1ZXN0cyBmcm9tIHRoZSBvcmlnaW4gc2VydmVyLFxuICAgKiBvciBwcm9ibGVtcyB3aXRoIGNvbW11bmljYXRpb24gYmV0d2VlbiBDbG91ZEZyb250IGFuZCB5b3VyIG9yaWdpbiBzZXJ2ZXIuXG4gICAqL1xuICByZWFkb25seSBhbGFybURlc2NyaXB0aW9uPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIFRoZSBwcm9wZXJ0aWVzIGZvciB0aGUgQ2xvdWRGcm9udERpc3RyaWJ1dGlvbjV4eEVycm9yUmF0ZUFsYXJtIGNvbnN0cnVjdC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDbG91ZEZyb250RGlzdHJpYnV0aW9uNXh4RXJyb3JSYXRlQWxhcm1Qcm9wcyBleHRlbmRzIENsb3VkRnJvbnREaXN0cmlidXRpb25BbGFybVByb3BzLCBDbG91ZEZyb250NXh4RXJyb3JSYXRlQWxhcm1Db25maWcge31cblxuLyoqXG4gKiBUaGlzIGFsYXJtIG1vbml0b3JzIHRoZSBwZXJjZW50YWdlIG9mIDV4eCBlcnJvciByZXNwb25zZXMgZnJvbSB5b3VyIG9yaWdpbiBzZXJ2ZXIsIHRvIGhlbHAgeW91IGRldGVjdCBpZlxuICogdGhlIENsb3VkRnJvbnQgc2VydmljZSBpcyBoYXZpbmcgaXNzdWVzLlxuICpcbiAqIFNlZSB7QGxpbmsgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL0FtYXpvbkNsb3VkRnJvbnQvbGF0ZXN0L0RldmVsb3Blckd1aWRlL3Ryb3VibGVzaG9vdGluZy1yZXNwb25zZS1lc