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.

452 lines 80.8 kB
"use strict"; var _a, _b, _c, _d, _e, _f, _g; Object.defineProperty(exports, "__esModule", { value: true }); exports.SqsRecommendedAlarmsAspect = exports.Queue = exports.SqsRecommendedAlarms = exports.SqsNumberOfMessagesSentAlarm = exports.SqsApproximateNumberOfMessagesVisibleAlarm = exports.SqsApproximateNumberOfMessagesNotVisibleAlarm = exports.SqsApproximateAgeOfOldestMessageAlarm = exports.SqsRecommendedAlarmsMetrics = 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 SQS queue alarms. */ var SqsRecommendedAlarmsMetrics; (function (SqsRecommendedAlarmsMetrics) { SqsRecommendedAlarmsMetrics["APPROXIMATE_AGE_OF_OLDEST_MESSAGE"] = "ApproximateAgeOfOldestMessage"; SqsRecommendedAlarmsMetrics["APPROXIMATE_NUMBER_OF_MESSAGES_NOT_VISIBLE"] = "ApproximateNumberOfMessagesNotVisible"; SqsRecommendedAlarmsMetrics["APPROXIMATE_NUMBER_OF_MESSAGES_VISIBLE"] = "ApproximateNumberOfMessagesVisible"; SqsRecommendedAlarmsMetrics["NUMBER_OF_MESSAGES_SENT"] = "NumberOfMessagesSent"; })(SqsRecommendedAlarmsMetrics || (exports.SqsRecommendedAlarmsMetrics = SqsRecommendedAlarmsMetrics = {})); /** * An alarm that watches the age of the oldest message in the queue. * * This alarm is used to detect whether the age of the oldest message * in the QueueName queue is too high. High age can be an indication * that messages are not processed quickly enough or that there are * some poison-pill messages that are stuck in the queue and can't * be processed. * * This alarm is triggered when the age of the oldest message in the * queue exceeds or is equal to the specified threshold. */ class SqsApproximateAgeOfOldestMessageAlarm extends aws_cdk_lib_1.aws_cloudwatch.Alarm { constructor(scope, id, props) { const alarmName = props.alarmName ?? `${props.queue.queueName} - ${SqsRecommendedAlarmsMetrics.APPROXIMATE_AGE_OF_OLDEST_MESSAGE}`; const period = props.period ?? aws_cdk_lib_1.Duration.minutes(1); const evaluationPeriods = props.evaluationPeriods ?? 15; (0, common_1.validateTotalAlarmPeriod)(period, evaluationPeriods, alarmName); super(scope, id, { alarmName, metric: props.queue.metricApproximateAgeOfOldestMessage({ period, }), threshold: props.threshold, evaluationPeriods, datapointsToAlarm: props.datapointsToAlarm ?? 15, treatMissingData: props.treatMissingData, comparisonOperator: aws_cdk_lib_1.aws_cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD, alarmDescription: props.alarmDescription ?? 'This alarm watches the age of the oldest message in the queue. ' + 'You can use this alarm to monitor if your consumers are processing SQS messages at the desired speed. ' + 'Consider increasing the consumer count or consumer throughput to reduce message age. This metric can be ' + 'used in combination with ApproximateNumberOfMessagesVisible to determine how big the queue backlog is and ' + 'how quickly messages are being processed. To prevent messages from being deleted before processed, consider ' + 'configuring the dead-letter queue to sideline potential poison pill messages.', }); if (props.alarmAction) this.addAlarmAction(props.alarmAction); if (props.okAction) this.addOkAction(props.okAction); if (props.insufficientDataAction) this.addInsufficientDataAction(props.insufficientDataAction); } } exports.SqsApproximateAgeOfOldestMessageAlarm = SqsApproximateAgeOfOldestMessageAlarm; _a = JSII_RTTI_SYMBOL_1; SqsApproximateAgeOfOldestMessageAlarm[_a] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.SqsApproximateAgeOfOldestMessageAlarm", version: "0.0.17" }; /** * An alarm that watches the number of messages that are in flight. * * This alarm is used to detect a high number of in-flight messages * in the queue. If consumers do not delete messages within the * visibility timeout period, when the queue is polled, messages * reappear in the queue. For FIFO queues, there can be a maximum * of 20,000 in-flight messages. If you reach this quota, SQS returns * no error messages. A FIFO queue looks through the first 20k * messages to determine available message groups. This means that * if you have a backlog of messages in a single message group, * you cannot consume messages from other message groups that were * sent to the queue at a later time until you successfully * consume the messages from the backlog. * * This alarm is triggered when the number of messages that are in * flight exceeds or is equal to the specified threshold. */ class SqsApproximateNumberOfMessagesNotVisibleAlarm extends aws_cdk_lib_1.aws_cloudwatch.Alarm { constructor(scope, id, props) { const alarmName = props.alarmName ?? `${props.queue.queueName} - ${SqsRecommendedAlarmsMetrics.APPROXIMATE_NUMBER_OF_MESSAGES_NOT_VISIBLE}`; const period = props.period ?? aws_cdk_lib_1.Duration.minutes(1); const evaluationPeriods = props.evaluationPeriods ?? 15; (0, common_1.validateTotalAlarmPeriod)(period, evaluationPeriods, alarmName); super(scope, id, { alarmName, metric: props.queue.metricApproximateNumberOfMessagesNotVisible({ period, }), threshold: props.threshold, evaluationPeriods, datapointsToAlarm: props.datapointsToAlarm ?? 15, treatMissingData: props.treatMissingData, comparisonOperator: aws_cdk_lib_1.aws_cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD, alarmDescription: props.alarmDescription ?? 'This alarm helps to detect a high number of in-flight ' + 'messages with respect to QueueName. For troubleshooting, check message backlog decreasing ' + '(https://repost.aws/knowledge-center/sqs-message-backlog).', }); if (props.alarmAction) this.addAlarmAction(props.alarmAction); if (props.okAction) this.addOkAction(props.okAction); if (props.insufficientDataAction) this.addInsufficientDataAction(props.insufficientDataAction); } } exports.SqsApproximateNumberOfMessagesNotVisibleAlarm = SqsApproximateNumberOfMessagesNotVisibleAlarm; _b = JSII_RTTI_SYMBOL_1; SqsApproximateNumberOfMessagesNotVisibleAlarm[_b] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.SqsApproximateNumberOfMessagesNotVisibleAlarm", version: "0.0.17" }; /** * An alarm that watches the number of messages that * are visible in the queue. * * This alarm is used to detect whether the message * count of the active queue is too high and consumers * are slow to process the messages or there are not * enough consumers to process them. * * This alarm is triggered when the number of messages * that are visible in the queue exceeds or is equal to * the specified threshold. */ class SqsApproximateNumberOfMessagesVisibleAlarm extends aws_cdk_lib_1.aws_cloudwatch.Alarm { constructor(scope, id, props) { const alarmName = props.alarmName ?? `${props.queue.queueName} - ${SqsRecommendedAlarmsMetrics.APPROXIMATE_NUMBER_OF_MESSAGES_VISIBLE}`; const period = props.period ?? aws_cdk_lib_1.Duration.minutes(1); const evaluationPeriods = props.evaluationPeriods ?? 15; (0, common_1.validateTotalAlarmPeriod)(period, evaluationPeriods, alarmName); super(scope, id, { alarmName, metric: props.queue.metricApproximateNumberOfMessagesVisible({ period, }), threshold: props.threshold, evaluationPeriods, datapointsToAlarm: props.datapointsToAlarm ?? 15, treatMissingData: props.treatMissingData, comparisonOperator: aws_cdk_lib_1.aws_cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD, alarmDescription: props.alarmDescription ?? 'This alarm watches for the message queue backlog to be bigger ' + 'than expected, indicating that consumers are too slow or there are not enough consumers.', }); if (props.alarmAction) this.addAlarmAction(props.alarmAction); if (props.okAction) this.addOkAction(props.okAction); if (props.insufficientDataAction) this.addInsufficientDataAction(props.insufficientDataAction); } } exports.SqsApproximateNumberOfMessagesVisibleAlarm = SqsApproximateNumberOfMessagesVisibleAlarm; _c = JSII_RTTI_SYMBOL_1; SqsApproximateNumberOfMessagesVisibleAlarm[_c] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.SqsApproximateNumberOfMessagesVisibleAlarm", version: "0.0.17" }; /** * An alarm that watches the number of messages that are sent. * * This alarm is used to detect when a producer stops sending messages. * * This alarm is triggered when the number of messages sent is less than * or equal to the specified threshold. By default, 0. */ class SqsNumberOfMessagesSentAlarm extends aws_cdk_lib_1.aws_cloudwatch.Alarm { constructor(scope, id, props) { const alarmName = props.alarmName ?? `${props.queue.queueName} - ${SqsRecommendedAlarmsMetrics.NUMBER_OF_MESSAGES_SENT}`; const period = props.period ?? aws_cdk_lib_1.Duration.minutes(1); const evaluationPeriods = props.evaluationPeriods ?? 15; (0, common_1.validateTotalAlarmPeriod)(period, evaluationPeriods, alarmName); super(scope, id, { alarmName, metric: props.queue.metricNumberOfMessagesSent({ period, }), threshold: props.threshold ?? 0, evaluationPeriods, datapointsToAlarm: props.datapointsToAlarm ?? 15, treatMissingData: props.treatMissingData, comparisonOperator: aws_cdk_lib_1.aws_cloudwatch.ComparisonOperator.LESS_THAN_OR_EQUAL_TO_THRESHOLD, alarmDescription: props.alarmDescription ?? 'This alarm helps to detect if there are no messages being sent from a producer with respect to QueueName.', }); if (props.alarmAction) this.addAlarmAction(props.alarmAction); if (props.okAction) this.addOkAction(props.okAction); if (props.insufficientDataAction) this.addInsufficientDataAction(props.insufficientDataAction); } } exports.SqsNumberOfMessagesSentAlarm = SqsNumberOfMessagesSentAlarm; _d = JSII_RTTI_SYMBOL_1; SqsNumberOfMessagesSentAlarm[_d] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.SqsNumberOfMessagesSentAlarm", version: "0.0.17" }; class SqsRecommendedAlarms extends constructs_1.Construct { constructor(scope, id, props) { super(scope, id); if (!props.excludeAlarms?.includes(SqsRecommendedAlarmsMetrics.APPROXIMATE_AGE_OF_OLDEST_MESSAGE)) { this.alarmApproximateAgeOfOldestMessage = new SqsApproximateAgeOfOldestMessageAlarm(this, 'ApproximateAgeOfOldestMessageAlarm', { queue: props.queue, treatMissingData: props.treatMissingData, ...props.configApproximateAgeOfOldestMessageAlarm, }); if (props.defaultAlarmAction && !props.configApproximateAgeOfOldestMessageAlarm.alarmAction) { this.alarmApproximateAgeOfOldestMessage.addAlarmAction(props.defaultAlarmAction); } if (props.defaultOkAction && !props.configApproximateAgeOfOldestMessageAlarm.okAction) { this.alarmApproximateAgeOfOldestMessage.addOkAction(props.defaultOkAction); } if (props.defaultInsufficientDataAction && !props.configApproximateAgeOfOldestMessageAlarm.insufficientDataAction) { this.alarmApproximateAgeOfOldestMessage.addInsufficientDataAction(props.defaultInsufficientDataAction); } } if (!props.excludeAlarms?.includes(SqsRecommendedAlarmsMetrics.APPROXIMATE_NUMBER_OF_MESSAGES_NOT_VISIBLE)) { this.alarmApproximateNumberOfMessagesNotVisible = new SqsApproximateNumberOfMessagesNotVisibleAlarm(this, 'ApproximateNumberOfMessagesNotVisibleAlarm', { queue: props.queue, treatMissingData: props.treatMissingData, ...props.configApproximateNumberOfMessagesNotVisibleAlarm, }); if (props.defaultAlarmAction && !props.configApproximateNumberOfMessagesNotVisibleAlarm.alarmAction) { this.alarmApproximateNumberOfMessagesNotVisible.addAlarmAction(props.defaultAlarmAction); } if (props.defaultOkAction && !props.configApproximateNumberOfMessagesNotVisibleAlarm.okAction) { this.alarmApproximateNumberOfMessagesNotVisible.addOkAction(props.defaultOkAction); } if (props.defaultInsufficientDataAction && !props.configApproximateNumberOfMessagesNotVisibleAlarm.insufficientDataAction) { this.alarmApproximateNumberOfMessagesNotVisible.addInsufficientDataAction(props.defaultInsufficientDataAction); } } if (!props.excludeAlarms?.includes(SqsRecommendedAlarmsMetrics.APPROXIMATE_NUMBER_OF_MESSAGES_VISIBLE)) { this.alarmApproximateNumberOfMessagesVisible = new SqsApproximateNumberOfMessagesVisibleAlarm(this, 'ApproximateNumberOfMessagesVisibleAlarm', { queue: props.queue, treatMissingData: props.treatMissingData, ...props.configApproximateNumberOfMessagesVisibleAlarm, }); if (props.defaultAlarmAction && !props.configApproximateNumberOfMessagesVisibleAlarm.alarmAction) { this.alarmApproximateNumberOfMessagesVisible.addAlarmAction(props.defaultAlarmAction); } if (props.defaultOkAction && !props.configApproximateNumberOfMessagesVisibleAlarm.okAction) { this.alarmApproximateNumberOfMessagesVisible.addOkAction(props.defaultOkAction); } if (props.defaultInsufficientDataAction && !props.configApproximateNumberOfMessagesVisibleAlarm.insufficientDataAction) { this.alarmApproximateNumberOfMessagesVisible.addInsufficientDataAction(props.defaultInsufficientDataAction); } } if (!props.excludeAlarms?.includes(SqsRecommendedAlarmsMetrics.NUMBER_OF_MESSAGES_SENT)) { this.alarmNumberOfMessagesSent = new SqsNumberOfMessagesSentAlarm(this, 'NumberOfMessagesSentAlarm', { queue: props.queue, treatMissingData: props.treatMissingData, ...props.configNumberOfMessagesSentAlarm, }); if (props.defaultAlarmAction && !props.configNumberOfMessagesSentAlarm?.alarmAction) { this.alarmNumberOfMessagesSent.addAlarmAction(props.defaultAlarmAction); } if (props.defaultOkAction && !props.configNumberOfMessagesSentAlarm?.okAction) { this.alarmNumberOfMessagesSent.addOkAction(props.defaultOkAction); } if (props.defaultInsufficientDataAction && !props.configNumberOfMessagesSentAlarm?.insufficientDataAction) { this.alarmNumberOfMessagesSent.addInsufficientDataAction(props.defaultInsufficientDataAction); } } } } exports.SqsRecommendedAlarms = SqsRecommendedAlarms; _e = JSII_RTTI_SYMBOL_1; SqsRecommendedAlarms[_e] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.SqsRecommendedAlarms", version: "0.0.17" }; /** * An extension of the SQS Queue construct that adds methods to create recommended alarms. */ class Queue extends aws_cdk_lib_1.aws_sqs.Queue { constructor(scope, id, props) { super(scope, id, props); } /** * Creates an alarm that watches the age of the oldest message in the queue. */ alarmApproximateAgeOfOldestMessage(props) { return new SqsApproximateAgeOfOldestMessageAlarm(this, 'ApproximateAgeOfOldestMessageAlarm', { queue: this, ...props, }); } /** * Creates an alarm that watches the number of messages that are in flight. */ alarmApproximateNumberOfMessagesNotVisible(props) { return new SqsApproximateNumberOfMessagesNotVisibleAlarm(this, 'ApproximateNumberOfMessagesNotVisibleAlarm', { queue: this, ...props, }); } /** * Creates an alarm that watches the number of messages that are visible in the queue. */ alarmApproximateNumberOfMessagesVisible(props) { return new SqsApproximateNumberOfMessagesVisibleAlarm(this, 'ApproximateNumberOfMessagesVisibleAlarm', { queue: this, ...props, }); } /** * Creates an alarm that watches the number of messages that are sent. */ alarmNumberOfMessagesSent(props) { return new SqsNumberOfMessagesSentAlarm(this, 'NumberOfMessagesSentAlarm', { queue: this, ...props, }); } /** * Creates the recommended alarms for an SQS queue. */ applyRecommendedAlarms(props) { new SqsRecommendedAlarms(this, 'SqsRecommendedAlarms', { queue: this, ...props, }); } } exports.Queue = Queue; _f = JSII_RTTI_SYMBOL_1; Queue[_f] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.Queue", version: "0.0.17" }; /** * Configured the recommended alarms for an SQS queue. Requires defining thresholds for some alarms. * * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html#SQS */ class SqsRecommendedAlarmsAspect { constructor(props) { this.props = props; /** * A list of dead letter queues discovered in the scope. * We exclude these from the recommended alarms * because they don't make sense. */ this.deadLetterQueues = []; /** * A flag to indicate whether dead letter queues have been discovered. * This is used to prevent running the discovery logic on every call to `visit`. */ this.deadLetterQueuesDiscovered = false; } visit(node) { // Constructed list of SQS queues to exclude from the recommended alarms. let excludeResources; /** * If the `dlqsGetFullRecommendedAlarms` prop is false or not set, * we discover dead letter queues in the scope and exclude them * from the normal recommended alarms. */ if (!this.props.dlqsGetFullRecommendedAlarms) { /** * Discover dead letter queues in the scope. * If the node is a Stack or App, we can discover all SQS queues in the scope. * The top level node is supposed to be the first call to `visit`. */ if (!this.deadLetterQueuesDiscovered) { if (node instanceof aws_cdk_lib_1.Stack || node instanceof aws_cdk_lib_1.App) { const queues = node.node.findAll().filter(n => n instanceof aws_cdk_lib_1.aws_sqs.Queue); queues.forEach(queue => { if (queue.deadLetterQueue) { this.deadLetterQueues.push(queue.deadLetterQueue.queue.node.id); } }); const fns = node.node.findAll().filter(n => n instanceof aws_cdk_lib_1.aws_lambda.Function); fns.forEach(fn => { if (fn.deadLetterQueue) { this.deadLetterQueues.push(fn.deadLetterQueue.node.id); } }); const subscriptions = node.node.findAll().filter(n => n instanceof aws_cdk_lib_1.aws_sns.Subscription); subscriptions.forEach(sub => { if (sub.deadLetterQueue) { this.deadLetterQueues.push(sub.deadLetterQueue.node.id); } }); /** * Mark that we have discovered dead letter queues * so we don't run this logic again. * This is to prevent performance issues in large stacks. * We only want to discover dead letter queues once. */ this.deadLetterQueuesDiscovered = true; } } /** * Exclude the dead letter queues as if they were specified in the `excludeResources` prop. */ excludeResources = this.deadLetterQueues.concat(this.props.excludeResources || []); } else { /** * If the `includeDeadLetterQueues` prop is true, we don't exclude dead letter queues. * We use the `excludeResources` prop as is. */ excludeResources = this.props.excludeResources; } if (node instanceof aws_cdk_lib_1.aws_sqs.Queue) { // Normal, unexcluded queues if (!(excludeResources && excludeResources.includes(node.node.id))) { const queue = node; new SqsRecommendedAlarms(queue, 'SqsRecommendedAlarmsFromAspect', { queue, ...this.props, }); } /** * Dead letter queues * * If the `dlqsGetFullRecommendedAlarms` prop is true, * we apply the same recommended alarms as for normal queues and don't process them here. * * If the `dlqsGetFullRecommendedAlarms` prop is false, * we only apply the ApproximateNumberOfMessagesVisible alarm with a default threshold of 1. * But we still check if it's explicitly been excluded from the alarms, and we use the * original `excludeResources` prop to determine if we should skip it, not the list we * constructed above. */ if (this.props.excludeResources && this.props.excludeResources.includes(node.node.id)) { return; } else if (!this.props.dlqsGetFullRecommendedAlarms && this.deadLetterQueues.includes(node.node.id)) { /** * Apply only the recommended alarms that make sense for dead letter queues. * At this time, we only apply the ApproximateNumberOfMessagesVisible alarm, * with a default threshold of 1. * This is because dead letter queues are not expected to have messages * in them, and if they do, it indicates a problem. */ const dlqAlarm = new SqsApproximateNumberOfMessagesVisibleAlarm(node, 'SqsApproximateNumberOfMessagesVisibleAlarm', { queue: node, treatMissingData: this.props.treatMissingData, threshold: 1, ...this.props.configDlqApproximateNumberOfMessagesVisibleAlarm, }); if (this.props.defaultAlarmAction && !this.props.configDlqApproximateNumberOfMessagesVisibleAlarm?.alarmAction) { dlqAlarm.addAlarmAction(this.props.defaultAlarmAction); } if (this.props.defaultOkAction && !this.props.configDlqApproximateNumberOfMessagesVisibleAlarm?.okAction) { dlqAlarm.addOkAction(this.props.defaultOkAction); } if (this.props.defaultInsufficientDataAction && !this.props.configDlqApproximateNumberOfMessagesVisibleAlarm?.insufficientDataAction) { dlqAlarm.addInsufficientDataAction(this.props.defaultInsufficientDataAction); } } } } } exports.SqsRecommendedAlarmsAspect = SqsRecommendedAlarmsAspect; _g = JSII_RTTI_SYMBOL_1; SqsRecommendedAlarmsAspect[_g] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.SqsRecommendedAlarmsAspect", version: "0.0.17" }; ; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3FzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3Nxcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLDZDQVNxQjtBQUNyQiwyQ0FBbUQ7QUFDbkQscUNBQW9FO0FBRXBFOztHQUVHO0FBQ0gsSUFBWSwyQkFLWDtBQUxELFdBQVksMkJBQTJCO0lBQ3JDLGtHQUFtRSxDQUFBO0lBQ25FLG1IQUFvRixDQUFBO0lBQ3BGLDRHQUE2RSxDQUFBO0lBQzdFLCtFQUFnRCxDQUFBO0FBQ2xELENBQUMsRUFMVywyQkFBMkIsMkNBQTNCLDJCQUEyQixRQUt0QztBQWlFRDs7Ozs7Ozs7Ozs7R0FXRztBQUNILE1BQWEscUNBQXNDLFNBQVEsNEJBQVUsQ0FBQyxLQUFLO0lBQ3pFLFlBQVksS0FBaUIsRUFBRSxFQUFVLEVBQUUsS0FBaUQ7UUFDMUYsTUFBTSxTQUFTLEdBQUcsS0FBSyxDQUFDLFNBQVMsSUFBSSxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUMsU0FBUyxNQUFNLDJCQUEyQixDQUFDLGlDQUFpQyxFQUFFLENBQUM7UUFDbkksTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLE1BQU0sSUFBSSxzQkFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNuRCxNQUFNLGlCQUFpQixHQUFHLEtBQUssQ0FBQyxpQkFBaUIsSUFBSSxFQUFFLENBQUM7UUFFeEQsSUFBQSxpQ0FBd0IsRUFBQyxNQUFNLEVBQUUsaUJBQWlCLEVBQUUsU0FBUyxDQUFDLENBQUM7UUFFL0QsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLEVBQUU7WUFDZixTQUFTO1lBQ1QsTUFBTSxFQUFFLEtBQUssQ0FBQyxLQUFLLENBQUMsbUNBQW1DLENBQUM7Z0JBQ3RELE1BQU07YUFDUCxDQUFDO1lBQ0YsU0FBUyxFQUFFLEtBQUssQ0FBQyxTQUFTO1lBQzFCLGlCQUFpQjtZQUNqQixpQkFBaUIsRUFBRSxLQUFLLENBQUMsaUJBQWlCLElBQUksRUFBRTtZQUNo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Q0FBQztnQkFFSCxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsa0JBQWtCLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLGdEQUFnRCxFQUFFLFdBQVcsRUFBRSxDQUFDO29CQUMvRyxRQUFRLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsa0JBQWtCLENBQUMsQ0FBQztnQkFDekQsQ0FBQztnQkFFRCxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsZUFBZSxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxnREFBZ0QsRUFBRSxRQUFRLEVBQUUsQ0FBQztvQkFDekcsUUFBUSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLGVBQWUsQ0FBQyxDQUFDO2dCQUNuRCxDQUFDO2dCQUVELElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyw2QkFBNkIsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsZ0RBQWdELEVBQUUsc0JBQXNCLEVBQUUsQ0FBQztvQkFDckksUUFBUSxDQUFDLHlCQUF5QixDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsNkJBQTZCLENBQUMsQ0FBQztnQkFDL0UsQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQzs7QUEvSEgsZ0VBZ0lDOzs7QUFBQSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQXBwLFxuICBTdGFjayxcbiAgSUFzcGVjdCxcbiAgYXdzX2xhbWJkYSBhcyBsYW1iZGEsXG4gIGF3c19zbnMgYXMgc25zLFxuICBhd3Nfc3FzIGFzIHNxcyxcbiAgYXdzX2Nsb3Vkd2F0Y2ggYXMgY2xvdWR3YXRjaCxcbiAgRHVyYXRpb24sXG59IGZyb20gJ2F3cy1jZGstbGliJztcbmltcG9ydCB7IElDb25zdHJ1Y3QsIENvbnN0cnVjdCB9IGZyb20gJ2NvbnN0cnVjdHMnO1xuaW1wb3J0IHsgQWxhcm1CYXNlUHJvcHMsIHZhbGlkYXRlVG90YWxBbGFybVBlcmlvZCB9IGZyb20gJy4vY29tbW9uJztcblxuLyoqXG4gKiBUaGUgcmVjb21tZW5kZWQgbWV0cmljcyBmb3IgU1FTIHF1ZXVlIGFsYXJtcy5cbiAqL1xuZXhwb3J0IGVudW0gU3FzUmVjb21tZW5kZWRBbGFybXNNZXRyaWNzIHtcbiAgQVBQUk9YSU1BVEVfQUdFX09GX09MREVTVF9NRVNTQUdFID0gJ0FwcHJveGltYXRlQWdlT2ZPbGRlc3RNZXNzYWdlJyxcbiAgQVBQUk9YSU1BVEVfTlVNQkVSX09GX01FU1NBR0VTX05PVF9WSVNJQkxFID0gJ0FwcHJveGltYXRlTnVtYmVyT2ZNZXNzYWdlc05vdFZpc2libGUnLFxuICBBUFBST1hJTUFURV9OVU1CRVJfT0ZfTUVTU0FHRVNfVklTSUJMRSA9ICdBcHByb3hpbWF0ZU51bWJlck9mTWVzc2FnZXNWaXNpYmxlJyxcbiAgTlVNQkVSX09GX01FU1NBR0VTX1NFTlQgPSAnTnVtYmVyT2ZNZXNzYWdlc1NlbnQnLFxufVxuXG5leHBvcnQgaW50ZXJmYWNlIFNxc0FsYXJtQmFzZUNvbmZpZyBleHRlbmRzIEFsYXJtQmFzZVByb3BzIHtcbiAgLyoqXG4gICAqIFRoZSBwZXJpb2Qgb3ZlciB3aGljaCB0aGUgc3BlY2lmaWVkIHN0YXRpc3RpYyBpcyBhcHBsaWVkLlxuICAgKlxuICAgKiBAZGVmYXVsdCBEdXJhdGlvbi5taW51dGVzKDEpXG4gICAqL1xuICByZWFkb25seSBwZXJpb2Q/OiBEdXJhdGlvbjtcbiAgLyoqXG4gICAqIFRoZSBudW1iZXIgb2YgcGVyaW9kcyBvdmVyIHdoaWNoIGRhdGEgaXMgY29tcGFyZWQgdG8gdGhlIHNwZWNpZmllZCB0aHJlc2hvbGQuXG4gICAqXG4gICAqIEBkZWZhdWx0IDE1XG4gICAqL1xuICByZWFkb25seSBldmFsdWF0aW9uUGVyaW9kcz86IG51bWJlcjtcbiAgLyoqXG4gICAqIFRoZSBudW1iZXIgb2YgZGF0YSBwb2ludHMgdGhhdCBtdXN0IGJlIGJyZWFjaGluZyB0byB0cmlnZ2VyIHRoZSBhbGFybS5cbiAgICpcbiAgICogQGRlZmF1bHQgMTVcbiAgICovXG4gIHJlYWRvbmx5IGRhdGFwb2ludHNUb0FsYXJtPzogbnVtYmVyO1xufVxuXG4vKipcbiAqIENvbmZpZ3VyYXRpb24gZm9yIHRoZSBBcHByb3hpbWF0ZUFnZU9mT2xkZXN0TWVzc2FnZSBhbGFybS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTcXNBcHByb3hpbWF0ZUFnZU9mT2xkZXN0TWVzc2FnZUFsYXJtQ29uZmlnIGV4dGVuZHMgU3FzQWxhcm1CYXNlQ29uZmlnIHtcbiAgLyoqXG4gICAqIFRoZSB2YWx1ZSBhZ2FpbnN0IHdoaWNoIHRoZSBzcGVjaWZpZWQgc3RhdGlzdGljIGlzIGNvbXBhcmVkLlxuICAgKlxuICAgKiBUaGUgcmVjb21tZW5kZWQgdGhyZXNob2xkIHZhbHVlIGZvciB0aGlzIGFsYXJtIGlzIGhpZ2hseSBkZXBlbmRlbnQgb24gdGhlIGV4cGVjdGVkIG1lc3NhZ2VcbiAgICogcHJvY2Vzc2luZyB0aW1lLiBZb3UgY2FuIHVzZSBoaXN0b3JpY2FsIGRhdGEgdG8gY2FsY3VsYXRlIHRoZSBhdmVyYWdlIG1lc3NhZ2UgcHJvY2Vzc2luZyB0aW1lLFxuICAgKiBhbmQgdGhlbiBzZXQgdGhlIHRocmVzaG9sZCB0byA1MCUgaGlnaGVyIHRoYW4gdGhlIG1heGltdW0gZXhwZWN0ZWQgU1FTIG1lc3NhZ2UgcHJvY2Vzc2luZ1xuICAgKiB0aW1lIGJ5IHF1ZXVlIGNvbnN1bWVycy5cbiAgICovXG4gIHJlYWRvbmx5IHRocmVzaG9sZDogbnVtYmVyO1xuICAvKipcbiAgICogVGhlIGFsYXJtIG5hbWUuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gcXVldWUucXVldWVOYW1lICsgJyAtIEFwcHJveGltYXRlQWdlT2ZPbGRlc3RNZXNzYWdlJ1xuICAgKi9cbiAgcmVhZG9ubHkgYWxhcm1OYW1lPzogc3RyaW5nO1xuICAvKipcbiAgICogVGhlIGRlc2NyaXB0aW9uIG9mIHRoZSBhbGFybS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSAgVGhpcyBhbGFybSB3YXRjaGVzIHRoZSBhZ2Ugb2YgdGhlIG9sZGVzdCBtZXNzYWdlIGluIHRoZSBxdWV1ZS4gWW91IGNhbiB1c2UgdGhpcyBhbGFybVxuICAgKiB0byBtb25pdG9yIGlmIHlvdXIgY29uc3VtZXJzIGFyZSBwcm9jZXNzaW5nIFNRUyBtZXNzYWdlcyBhdCB0aGUgZGVzaXJlZCBzcGVlZC4gQ29uc2lkZXIgaW5jcmVhc2luZ1xuICAgKiB0aGUgY29uc3VtZXIgY291bnQgb3IgY29uc3VtZXIgdGhyb3VnaHB1dCB0byByZWR1Y2UgbWVzc2FnZSBhZ2UuIFRoaXMgbWV0cmljIGNhbiBiZSB1c2VkIGluXG4gICAqIGNvbWJpbmF0aW9uIHdpdGggQXBwcm94aW1hdGVOdW1iZXJPZk1lc3NhZ2VzVmlzaWJsZSB0byBkZXRlcm1pbmUgaG93IGJpZyB0aGUgcXVldWUgYmFja2xvZyBpc1xuICAgKiBhbmQgaG93IHF1aWNrbHkgbWVzc2FnZXMgYXJlIGJlaW5nIHByb2Nlc3NlZC4gVG8gcHJldmVudCBtZXNzYWdlcyBmcm9tIGJlaW5nIGRlbGV0ZWQgYmVmb3JlIHByb2Nlc3NlZCxcbiAgICogY29uc2lkZXIgY29uZmlndXJpbmcgdGhlIGRlYWQtbGV0dGVyIHF1ZXVlIHRvIHNpZGVsaW5lIHBvdGVudGlhbCBwb2lzb24gcGlsbCBtZXNzYWdlcy5cbiAgICovXG4gIHJlYWRvbmx5IGFsYXJtRGVzY3JpcHRpb24/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogUHJvcGVydGllcyBmb3IgdGhlIFNxc0FwcHJveGltYXRlQWdlT2ZPbGRlc3RNZXNzYWdlQWxhcm0gY29uc3RydWN0LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFNxc0FwcHJveGltYXRlQWdlT2ZPbGRlc3RNZXNzYWdlQWxhcm1Qcm9wcyBleHRlbmRzIFNxc0FwcHJveGltYXRlQWdlT2ZPbGRlc3RNZXNzYWdlQWxhcm1Db25maWcge1xuICAvKipcbiAgICogVGhlIFNRUyBxdWV1ZSBmb3Igd2hpY2ggdG8gY3JlYXRlIHRoZSBhbGFybS5cbiAgICovXG4gIHJlYWRvbmx5IHF1ZXVlOiBzcXMuSVF1ZXVlO1xufVxuXG4vKipcbiAqIEFuIGFsYXJtIHRoYXQgd2F0Y2hlcyB0aGUgYWdlIG9mIHRoZSBvbGRlc3QgbWVzc2FnZSBpbiB0aGUgcXVldWUuXG4gKlxuICogVGhpcyBhbGFybSBpcyB1c2VkIHRvIGRldGVjdCB3aGV0aGVyIHRoZSBhZ2Ugb2YgdGhlIG9sZGVzdCBtZXNzYWdlXG4gKiBpbiB0aGUgUXVldWVOYW1lIHF1ZXVlIGlzIHRvbyBoaWdoLiBIaWdoIGFnZSBjYW4gYmUgYW4gaW5kaWNhdGlvblxuICogdGhhdCBtZXNzYWdlcyBhcmUgbm90IHByb2Nlc3NlZCBxdWlja2x5IGVub3VnaCBvciB0aGF0IHRoZXJlIGFyZVxuICogc29tZSBwb2lzb24tcGlsbCBtZXNzYWdlcyB0aGF0IGFyZSBzdHVjayBpbiB0aGUgcXVldWUgYW5kIGNhbid0XG4gKiBiZSBwcm9jZXNzZWQuXG4gKlxuICogVGhpcyBhbGFybSBpcyB0cmlnZ2VyZWQgd2hlbiB0aGUgYWdlIG9mIHRoZSBvbGRlc3QgbWVzc2FnZSBpbiB0aGVcbiAqIHF1ZXVlIGV4Y2VlZHMgb3IgaXMgZXF1YWwgdG8gdGhlIHNwZWNpZmllZCB0aHJlc2hvbGQuXG4gKi9cbmV4cG9ydCBjbGFzcyBTcXNBcHByb3hpbWF0ZUFnZU9mT2xkZXN0TWVzc2FnZUFsYXJtIGV4dGVuZHMgY2xvdWR3YXRjaC5BbGFybSB7XG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBJQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogU3FzQXBwcm94aW1hdGVBZ2VPZk9sZGVzdE1lc3NhZ2VBbGFybVByb3BzKSB7XG4gICAgY29uc3QgYWxhcm1OYW1lID0gcHJvcHMuYWxhcm1OYW1lID8/IGAke3Byb3BzLnF1ZXVlLnF1ZXVlTmFtZX0gLSAke1Nxc1JlY29tbWVuZGVkQWxhcm1zTWV0cmljcy5BUFBST1hJTUFURV9BR0VfT0ZfT0xERVNUX01FU1NBR0V9YDtcbiAgICBjb25zdCBwZXJpb2QgPSBwcm9wcy5wZXJpb2QgPz8gRHVyYXRpb24ubWludXRlcygxKTtcbiAgICBjb25zdCBldmFsdWF0aW9uUGVyaW9kcyA9IHByb3BzLmV2YWx1YXRpb25QZXJpb2RzID8/IDE1O1xuXG4gICAgdmFsaWRhdGVUb3RhbEFsYXJtUGVyaW9kKHBlcmlvZCwgZXZhbHVhdGlvblBlcmlvZHMsIGFsYXJtTmFtZSk7XG5cbiAgICBzdXBlcihzY29wZSwgaWQsIHtcbiAgICAgIGFsYXJtTmFtZSxcbiAgICAgIG1ldHJpYzogcHJvcHMucXVldWUubWV0cmljQXBwcm94aW1hdGVBZ2VPZk9sZGVzdE1lc3NhZ2Uoe1xuICAgICAgICBwZXJpb2QsXG4gICAgICB9KSxcbiAgICAgIHRocmVzaG9sZDogcHJvcHMudGhyZXNob2xkLFxuICAgICAgZXZhbHVhdGlvblBlcmlvZHMsXG4gICAgICBkYXRhcG9pbnRzVG9BbGFybTogcHJvcHMuZGF0YXBvaW50c1RvQWxhcm0gPz8gMTUsXG4gICAgICB0cmVhdE1pc3NpbmdEYXRhOiBwcm9wcy50cmVhdE1pc3NpbmdEYXRhLFxuICAgICAgY29tcGFyaXNvbk9wZXJhdG9yOiBjbG91ZHdhdGNoLkNvbXBhcmlzb25PcGVyYXRvci5HUkVBVEVSX1RIQU5fT1JfRVFVQUxfVE9fVEhSRVNIT0xELFxuICAgICAgYWxhcm1EZXNjcmlwdGlvbjogcHJvcHMuYWxhcm1EZXNjcmlwdGlvbiA/PyAnVGhpcyBhbGFybSB3YXRjaGVzIHRoZSBhZ2Ugb2YgdGhlIG9sZGVzdCBtZXNzYWdlIGluIHRoZSBxdWV1ZS4gJ1xuICAgICAgICArICdZb3UgY2FuIHVzZSB0aGlzIGFsYXJtIHRvIG1vbml0b3IgaWYgeW91ciBjb25zdW1lcnMgYXJlIHByb2Nlc3NpbmcgU1FTIG1lc3NhZ2VzIGF0IHRoZSBkZXNpcmVkIHNwZWVkLiAnXG4gICAgICAgICsgJ0NvbnNpZGVyIGluY3JlYXNpbmcgdGhlIGNvbnN1bWVyIGNvdW50IG9yIGNvbnN1bWVyIHRocm91Z2hwdXQgdG8gcmVkdWNlIG1lc3NhZ2UgYWdlLiBUaGlzIG1ldHJpYyBjYW4gYmUgJ1xuICAgICAgICArICd1c2VkIGluIGNvbWJpbmF0aW9uIHdpdGggQXBwcm94aW1hdGVOdW1iZXJPZk1lc3NhZ2VzVmlzaWJsZSB0byBkZXRlcm1pbmUgaG93IGJpZyB0aGUgcXVldWUgYmFja2xvZyBpcyBhbmQgJ1xuICAgICAgICArICdob3cgcXVpY2tseSBtZXNzYWdlcyBhcmUgYmVpbmcgcHJvY2Vzc2VkLiBUbyBwcmV2ZW50IG1lc3NhZ2VzIGZyb20gYmVpbmcgZGVsZXRlZCBiZWZvcmUgcHJvY2Vzc2VkLCBjb25zaWRlciAnXG4gICAgICAgICsgJ2NvbmZpZ3VyaW5nIHRoZSBkZWFkLWxldHRlciBxdWV1ZSB0byBzaWRlbGluZSBwb3RlbnRpYWwgcG9pc29uIHBpbGwgbWVzc2FnZXMuJyxcbiAgICB9KTtcblxuICAgIGlmIChwcm9wcy5hbGFybUFjdGlvbikgdGhpcy5hZGRBbGFybUFjdGlvbihwcm9wcy5hbGFybUFjdGlvbik7XG4gICAgaWYgKHByb3BzLm9rQWN0aW9uKSB0aGlzLmFkZE9rQWN0aW9uKHByb3BzLm9rQWN0aW9uKTtcbiAgICBpZiAocHJvcHMuaW5zdWZmaWNpZW50RGF0YUFjdGlvbikgdGhpcy5hZGRJbnN1ZmZpY2llbnREYXRhQWN0aW9uKHByb3BzLmluc3VmZmljaWVudERhdGFBY3Rpb24pO1xuICB9XG59XG5cbi8qKlxuICogQ29uZmlndXJhdGlvbiBmb3IgdGhlIEFwcHJveGltYXRlTnVtYmVyT2ZNZXNzYWdlc05vdFZpc2libGUgYWxhcm0uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU3FzQXBwcm94aW1hdGVOdW1iZXJPZk1lc3NhZ2VzTm90VmlzaWJsZUFsYXJtQ29uZmlnIGV4dGVuZHMgU3FzQWxhcm1CYXNlQ29uZmlnIHtcbiAgLyoqXG4gICAqIFRoZSB2YWx1ZSBhZ2FpbnN0IHdoaWNoIHRoZSBzcGVjaWZpZWQgc3RhdGlzdGljIGlzIGNvbXBhcmVkLlxuICAgKlxuICAgKiBUaGUgcmVjb21tZW5kZWQgdGhyZXNob2xkIHZhbHVlIGZvciB0aGlzIGFsYXJtIGlzIGhpZ2hseSBkZXBlbmRlbnQgb24gdGhlIGV4cGVjdGVkIG51bWJlclxuICAgKiBvZiBtZXNzYWdlcyBpbiBmbGlnaHQuIFlvdSBjYW4gdXNlIGhpc3RvcmljYWwgZGF0YSB0byBjYWxjdWxhdGUgdGhlIG1heGltdW0gZXhwZWN0ZWRcbiAgICogbnVtYmVyIG9mIG1lc3NhZ2VzIGluIGZsaWdodCBhbmQgc2V0IHRoZSB0aHJlc2hvbGQgdG8gNTAlIG92ZXIgdGhpcyB2YWx1ZS4gSWYgY29uc3VtZXJzXG4gICAqIG9mIHRoZSBxdWV1ZSBhcmUgcHJvY2Vzc2luZyBidXQgbm90IGRlbGV0aW5nIG1lc3NhZ2VzIGZyb20gdGhlIHF1ZXVlLCB0aGlzIG51bWJlciB3aWxsXG4gICAqIHN1ZGRlbmx5IGluY3JlYXNlLlxuICAgKi9cbiAgcmVhZG9ubHkgdGhyZXNob2xkOiBudW1iZXI7XG4gIC8qKlxuICAgKiBUaGUgYWxhcm0gbmFtZS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBxdWV1ZS5xdWV1ZU5hbWUgKyAnIC0gQXBwcm94aW1hdGVOdW1iZXJPZk1lc3NhZ2VzTm90VmlzaWJsZSdcbiAgICovXG4gIHJlYWRvbmx5IGFsYXJtTmFtZT86IHN0cmluZztcbiAgLyoqXG4gICAqIFRoZSBkZXNjcmlwdGlvbiBvZiB0aGUgYWxhcm0uXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gVGhpcyBhbGFybSBoZWxwcyB0byBkZXRlY3QgYSBoaWdoIG51bWJlciBvZiBpbi1mbGlnaHQgbWVzc2FnZXMgd2l0aCByZXNwZWN0IHRvIFF1ZXVlTmFtZS5cbiAgICogRm9yIHRyb3VibGVzaG9vdGluZywgY2hlY2sgbWVzc2FnZSBiYWNrbG9nIGRlY3JlYXNpbmcgKGh0dHBzOi8vcmVwb3N0LmF3cy9rbm93bGVkZ2UtY2VudGVyL3Nxcy1tZXNzYWdlLWJhY2tsb2cpLlxuICAgKi9cbiAgcmVhZG9ubHkgYWxhcm1EZXNjcmlwdGlvbj86IHN0cmluZztcbn1cblxuLyoqXG4gKiBQcm9wZXJ0aWVzIGZvciB0aGUgU3FzQXBwcm94aW1hdGVOdW1iZXJPZk1lc3NhZ2VzTm90VmlzaWJsZUFsYXJtIGNvbnN0cnVjdC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTcXNBcHByb3hpbWF0ZU51bWJlck9mTWVzc2FnZXNOb3RWaXNpYmxlQWxhcm1Qcm9wcyBleHRlbmRzIFNxc0FwcHJveGltYXRlTnVtYmVyT2ZNZXNzYWdlc05vdFZpc2libGVBbGFybUNvbmZpZyB7XG4gIC8qKlxuICAgKiBUaGUgU1FTIHF1ZXVlIGZvciB3aGljaCB0byBjcmVhdGUgdGhlIGFsYXJtLlxuICAgKi9cbiAgcmVhZG9ubHkgcXVldWU6IHNxcy5JUXVldWU7XG59XG5cbi8qKlxuICogQW4gYWxhcm0gdGhhdCB3YXRjaGVzIHRoZSBudW1iZXIgb2YgbWVzc2FnZXMgdGhhdCBhcmUgaW4gZmxpZ2h0LlxuICpcbiAqIFRoaXMgYWxhcm0gaXMgdXNlZCB0byBkZXRlY3QgYSBoaWdoIG51bWJlciBvZiBpbi1mbGlnaHQgbWVzc2FnZXNcbiAqIGluIHRoZSBxdWV1ZS4gSWYgY29uc3VtZXJzIGRvIG5vdCBkZWxldGUgbWVzc2FnZXMgd2l0aGluIHRoZVxuICogdmlzaWJpbGl0eSB0aW1lb3V0IHBlcmlvZCwgd2hlbiB0aGUgcXVldWUgaXMgcG9sbGVkLCBtZXNzYWdlc1xuICogcmVhcHBlYXIgaW4gdGhlIHF1ZXVlLiBGb3IgRklGTyBxdWV1ZXMsIHRoZXJlIGNhbiBiZSBhIG1heGltdW1cbiAqIG9mIDIwLDAwMCBpbi1mbGlnaHQgbWVzc2FnZXMuIElmIHlvdSByZWFjaCB0aGlzIHF1b3RhLCBTUVMgcmV0dXJuc1xuICogbm8gZXJyb3IgbWVzc2FnZXMuIEEgRklGTyBxdWV1ZSBsb29rcyB0aHJvdWdoIHRoZSBmaXJzdCAyMGtcbiAqIG1lc3NhZ2VzIHRvIGRldGVybWluZSBhdmFpbGFibGUgbWVzc2FnZSBncm91cHMuIFRoaXMgbWVhbnMgdGhhdFxuICogaWYgeW91IGhhdmUgYSBiYWNrbG9nIG9mIG1lc3NhZ2VzIGluIGEgc2luZ2xlIG1lc3NhZ2UgZ3JvdXAsXG4gKiB5b3UgY2Fubm90IGNvbnN1bWUgbWVzc2FnZXMgZnJvbSBvdGhlciBtZXNzYWdlIGdyb3VwcyB0aGF0IHdlcmVcbiAqIHNlbnQgdG8gdGhlIHF1ZXVlIGF0IGEgbGF0ZXIgdGltZSB1bnRpbCB5b3Ugc3VjY2Vzc2Z1bGx5XG4gKiBjb25zdW1lIHRoZSBtZXNzYWdlcyBmcm9tIHRoZSBiYWNrbG9nLlxuICpcbiAqIFRoaXMgYWxhcm0gaXMgdHJpZ2dlcmVkIHdoZW4gdGhlIG51bWJlciBvZiBtZXNzYWdlcyB0aGF0IGFyZSBpblxuICogZmxpZ2h0IGV4Y2VlZHMgb3IgaXMgZXF1YWwgdG8gdGhlIHNwZWNpZmllZCB0aHJlc2hvbGQuXG4gKi9cbmV4cG9ydCBjbGFzcyBTcXNBcHByb3hpbWF0ZU51bWJlck9mTW