@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.
431 lines • 76.1 kB
JavaScript
"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.13" };
/**
* 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.13" };
/**
* 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.13" };
/**
* 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.13" };
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.13" };
/**
* 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.13" };
/**
* 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);
}
});
/**
* 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 0.
* 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 0.
* This is because dead letter queues are not expected to have messages
* in them, and if they do, it indicates a problem.
*/
new SqsApproximateNumberOfMessagesVisibleAlarm(node, 'SqsApproximateNumberOfMessagesVisibleAlarm', {
queue: node,
treatMissingData: this.props.treatMissingData,
threshold: 0,
...this.props.configDlqApproximateNumberOfMessagesVisibleAlarm,
});
}
}
}
}
exports.SqsRecommendedAlarmsAspect = SqsRecommendedAlarmsAspect;
_g = JSII_RTTI_SYMBOL_1;
SqsRecommendedAlarmsAspect[_g] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.SqsRecommendedAlarmsAspect", version: "0.0.13" };
;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3FzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3Nxcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLDZDQU9xQjtBQUNyQiwyQ0FBbUQ7QUFDbkQscUNBQW9FO0FBRXBFOztHQUVHO0FBQ0gsSUFBWSwyQkFLWDtBQUxELFdBQVksMkJBQTJCO0lBQ3JDLGtHQUFtRSxDQUFBO0lBQ25FLG1IQUFvRixDQUFBO0lBQ3BGLDRHQUE2RSxDQUFBO0lBQzdFLCtFQUFnRCxDQUFBO0FBQ2xELENBQUMsRUFMVywyQkFBMkIsMkNBQTNCLDJCQUEyQixRQUt0QztBQWlFRDs7Ozs7Ozs7Ozs7R0FXRztBQUNILE1BQWEscUNBQXNDLFNBQVEsNEJBQVUsQ0FBQyxLQUFLO0lBQ3pFLFlBQVksS0FBaUIsRUFBRSxFQUFVLEVBQUUsS0FBaUQ7UUFDMUYsTUFBTSxTQUFTLEdBQUcsS0FBSyxDQUFDLFNBQVMsSUFBSSxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUMsU0FBUyxNQUFNLDJCQUEyQixDQUFDLGlDQUFpQyxFQUFFLENBQUM7UUFDbkksTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLE1BQU0sSUFBSSxzQkFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNuRCxNQUFNLGlCQUFpQixHQUFHLEtBQUssQ0FBQyxpQkFBaUIsSUFBSSxFQUFFLENBQUM7UUFFeEQsSUFBQSxpQ0FBd0IsRUFBQyxNQUFNLEVBQUUsaUJBQWlCLEVBQUUsU0FBUyxDQUFDLENBQUM7UUFFL0QsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLEVBQUU7WUFDZixTQUFTO1lBQ1QsTUFBTSxFQUFFLEtBQUssQ0FBQyxLQUFLLENBQUMsbUNBQW1DLENBQUM7Z0JBQ3RELE1BQU07YUFDUCxDQUFDO1lBQ0YsU0FBUyxFQUFFLEtBQUssQ0FBQyxTQUFTO1lBQzFCLGlCQUFpQjtZQUNqQixpQkFBaUIsRUFBRSxLQUFLLENBQUMsaUJBQWlCLElBQUksRUFBRTtZQUNo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LENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDO2dCQUNwRzs7Ozs7O21CQU1HO2dCQUNILElBQUksMENBQTBDLENBQUMsSUFBSSxFQUFFLDRDQUE0QyxFQUFFO29CQUNqRyxLQUFLLEVBQUUsSUFBSTtvQkFDWCxnQkFBZ0IsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLGdCQUFnQjtvQkFDN0MsU0FBUyxFQUFFLENBQUM7b0JBQ1osR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLGdEQUFnRDtpQkFDL0QsQ0FBQyxDQUFDO1lBQ0wsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDOztBQXJHSCxnRUFzR0M7OztBQUFBLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBBcHAsXG4gIFN0YWNrLFxuICBJQXNwZWN0LFxuICBhd3Nfc3FzIGFzIHNxcyxcbiAgYXdzX2Nsb3Vkd2F0Y2ggYXMgY2xvdWR3YXRjaCxcbiAgRHVyYXRpb24sXG59IGZyb20gJ2F3cy1jZGstbGliJztcbmltcG9ydCB7IElDb25zdHJ1Y3QsIENvbnN0cnVjdCB9IGZyb20gJ2NvbnN0cnVjdHMnO1xuaW1wb3J0IHsgQWxhcm1CYXNlUHJvcHMsIHZhbGlkYXRlVG90YWxBbGFybVBlcmlvZCB9IGZyb20gJy4vY29tbW9uJztcblxuLyoqXG4gKiBUaGUgcmVjb21tZW5kZWQgbWV0cmljcyBmb3IgU1FTIHF1ZXVlIGFsYXJtcy5cbiAqL1xuZXhwb3J0IGVudW0gU3FzUmVjb21tZW5kZWRBbGFybXNNZXRyaWNzIHtcbiAgQVBQUk9YSU1BVEVfQUdFX09GX09MREVTVF9NRVNTQUdFID0gJ0FwcHJveGltYXRlQWdlT2ZPbGRlc3RNZXNzYWdlJyxcbiAgQVBQUk9YSU1BVEVfTlVNQkVSX09GX01FU1NBR0VTX05PVF9WSVNJQkxFID0gJ0FwcHJveGltYXRlTnVtYmVyT2ZNZXNzYWdlc05vdFZpc2libGUnLFxuICBBUFBST1hJTUFURV9OVU1CRVJfT0ZfTUVTU0FHRVNfVklTSUJMRSA9ICdBcHByb3hpbWF0ZU51bWJlck9mTWVzc2FnZXNWaXNpYmxlJyxcbiAgTlVNQkVSX09GX01FU1NBR0VTX1NFTlQgPSAnTnVtYmVyT2ZNZXNzYWdlc1NlbnQnLFxufVxuXG5leHBvcnQgaW50ZXJmYWNlIFNxc0FsYXJtQmFzZUNvbmZpZyBleHRlbmRzIEFsYXJtQmFzZVByb3BzIHtcbiAgLyoqXG4gICAqIFRoZSBwZXJpb2Qgb3ZlciB3aGljaCB0aGUgc3BlY2lmaWVkIHN0YXRpc3RpYyBpcyBhcHBsaWVkLlxuICAgKlxuICAgKiBAZGVmYXVsdCBEdXJhdGlvbi5taW51dGVzKDEpXG4gICAqL1xuICByZWFkb25seSBwZXJpb2Q/OiBEdXJhdGlvbjtcbiAgLyoqXG4gICAqIFRoZSBudW1iZXIgb2YgcGVyaW9kcyBvdmVyIHdoaWNoIGRhdGEgaXMgY29tcGFyZWQgdG8gdGhlIHNwZWNpZmllZCB0aHJlc2hvbGQuXG4gICAqXG4gICAqIEBkZWZhdWx0IDE1XG4gICAqL1xuICByZWFkb25seSBldmFsdWF0aW9uUGVyaW9kcz86IG51bWJlcjtcbiAgLyoqXG4gICAqIFRoZSBudW1iZXIgb2YgZGF0YSBwb2ludHMgdGhhdCBtdXN0IGJlIGJyZWFjaGluZyB0byB0cmlnZ2VyIHRoZSBhbGFybS5cbiAgICpcbiAgICogQGRlZmF1bHQgMTVcbiAgICovXG4gIHJlYWRvbmx5IGRhdGFwb2ludHNUb0FsYXJtPzogbnVtYmVyO1xufVxuXG4vKipcbiAqIENvbmZpZ3VyYXRpb24gZm9yIHRoZSBBcHByb3hpbWF0ZUFnZU9mT2xkZXN0TWVzc2FnZSBhbGFybS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTcXNBcHByb3hpbWF0ZUFnZU9mT2xkZXN0TWVzc2FnZUFsYXJtQ29uZmlnIGV4dGVuZHMgU3FzQWxhcm1CYXNlQ29uZmlnIHtcbiAgLyoqXG4gICAqIFRoZSB2YWx1ZSBhZ2FpbnN0IHdoaWNoIHRoZSBzcGVjaWZpZWQgc3RhdGlzdGljIGlzIGNvbXBhcmVkLlxuICAgKlxuICAgKiBUaGUgcmVjb21tZW5kZWQgdGhyZXNob2xkIHZhbHVlIGZvciB0aGlzIGFsYXJtIGlzIGhpZ2hseSBkZXBlbmRlbnQgb24gdGhlIGV4cGVjdGVkIG1lc3NhZ2VcbiAgICogcHJvY2Vzc2luZyB0aW1lLiBZb3UgY2FuIHVzZSBoaXN0b3JpY2FsIGRhdGEgdG8gY2FsY3VsYXRlIHRoZSBhdmVyYWdlIG1lc3NhZ2UgcHJvY2Vzc2luZyB0aW1lLFxuICAgKiBhbmQgdGhlbiBzZXQgdGhlIHRocmVzaG9sZCB0byA1MCUgaGlnaGVyIHRoYW4gdGhlIG1heGltdW0gZXhwZWN0ZWQgU1FTIG1lc3NhZ2UgcHJvY2Vzc2luZ1xuICAgKiB0aW1lIGJ5IHF1ZXVlIGNvbnN1bWVycy5cbiAgICovXG4gIHJlYWRvbmx5IHRocmVzaG9sZDogbnVtYmVyO1xuICAvKipcbiAgICogVGhlIGFsYXJtIG5hbWUuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gcXVldWUucXVldWVOYW1lICsgJyAtIEFwcHJveGltYXRlQWdlT2ZPbGRlc3RNZXNzYWdlJ1xuICAgKi9cbiAgcmVhZG9ubHkgYWxhcm1OYW1lPzogc3RyaW5nO1xuICAvKipcbiAgICogVGhlIGRlc2NyaXB0aW9uIG9mIHRoZSBhbGFybS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSAgVGhpcyBhbGFybSB3YXRjaGVzIHRoZSBhZ2Ugb2YgdGhlIG9sZGVzdCBtZXNzYWdlIGluIHRoZSBxdWV1ZS4gWW91IGNhbiB1c2UgdGhpcyBhbGFybVxuICAgKiB0byBtb25pdG9yIGlmIHlvdXIgY29uc3VtZXJzIGFyZSBwcm9jZXNzaW5nIFNRUyBtZXNzYWdlcyBhdCB0aGUgZGVzaXJlZCBzcGVlZC4gQ29uc2lkZXIgaW5jcmVhc2luZ1xuICAgKiB0aGUgY29uc3VtZXIgY291bnQgb3IgY29uc3VtZXIgdGhyb3VnaHB1dCB0byByZWR1Y2UgbWVzc2FnZSBhZ2UuIFRoaXMgbWV0cmljIGNhbiBiZSB1c2VkIGluXG4gICAqIGNvbWJpbmF0aW9uIHdpdGggQXBwcm94aW1hdGVOdW1iZXJPZk1lc3NhZ2VzVmlzaWJsZSB0byBkZXRlcm1pbmUgaG93IGJpZyB0aGUgcXVldWUgYmFja2xvZyBpc1xuICAgKiBhbmQgaG93IHF1aWNrbHkgbWVzc2FnZXMgYXJlIGJlaW5nIHByb2Nlc3NlZC4gVG8gcHJldmVudCBtZXNzYWdlcyBmcm9tIGJlaW5nIGRlbGV0ZWQgYmVmb3JlIHByb2Nlc3NlZCxcbiAgICogY29uc2lkZXIgY29uZmlndXJpbmcgdGhlIGRlYWQtbGV0dGVyIHF1ZXVlIHRvIHNpZGVsaW5lIHBvdGVudGlhbCBwb2lzb24gcGlsbCBtZXNzYWdlcy5cbiAgICovXG4gIHJlYWRvbmx5IGFsYXJtRGVzY3JpcHRpb24/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogUHJvcGVydGllcyBmb3IgdGhlIFNxc0FwcHJveGltYXRlQWdlT2ZPbGRlc3RNZXNzYWdlQWxhcm0gY29uc3RydWN0LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFNxc0FwcHJveGltYXRlQWdlT2ZPbGRlc3RNZXNzYWdlQWxhcm1Qcm9wcyBleHRlbmRzIFNxc0FwcHJveGltYXRlQWdlT2ZPbGRlc3RNZXNzYWdlQWxhcm1Db25maWcge1xuICAvKipcbiAgICogVGhlIFNRUyBxdWV1ZSBmb3Igd2hpY2ggdG8gY3JlYXRlIHRoZSBhbGFybS5cbiAgICovXG4gIHJlYWRvbmx5IHF1ZXVlOiBzcXMuSVF1ZXVlO1xufVxuXG4vKipcbiAqIEFuIGFsYXJtIHRoYXQgd2F0Y2hlcyB0aGUgYWdlIG9mIHRoZSBvbGRlc3QgbWVzc2FnZSBpbiB0aGUgcXVldWUuXG4gKlxuICogVGhpcyBhbGFybSBpcyB1c2VkIHRvIGRldGVjdCB3aGV0aGVyIHRoZSBhZ2Ugb2YgdGhlIG9sZGVzdCBtZXNzYWdlXG4gKiBpbiB0aGUgUXVldWVOYW1lIHF1ZXVlIGlzIHRvbyBoaWdoLiBIaWdoIGFnZSBjYW4gYmUgYW4gaW5kaWNhdGlvblxuICogdGhhdCBtZXNzYWdlcyBhcmUgbm90IHByb2Nlc3NlZCBxdWlja2x5IGVub3VnaCBvciB0aGF0IHRoZXJlIGFyZVxuICogc29tZSBwb2lzb24tcGlsbCBtZXNzYWdlcyB0aGF0IGFyZSBzdHVjayBpbiB0aGUgcXVldWUgYW5kIGNhbid0XG4gKiBiZSBwcm9jZXNzZWQuXG4gKlxuICogVGhpcyBhbGFybSBpcyB0cmlnZ2VyZWQgd2hlbiB0aGUgYWdlIG9mIHRoZSBvbGRlc3QgbWVzc2FnZSBpbiB0aGVcbiAqIHF1ZXVlIGV4Y2VlZHMgb3IgaXMgZXF1YWwgdG8gdGhlIHNwZWNpZmllZCB0aHJlc2hvbGQuXG4gKi9cbmV4cG9ydCBjbGFzcyBTcXNBcHByb3hpbWF0ZUFnZU9mT2xkZXN0TWVzc2FnZUFsYXJtIGV4dGVuZHMgY2xvdWR3YXRjaC5BbGFybSB7XG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBJQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogU3FzQXBwcm94aW1hdGVBZ2VPZk9sZGVzdE1lc3NhZ2VBbGFybVByb3BzKSB7XG4gICAgY29uc3QgYWxhcm1OYW1lID0gcHJvcHMuYWxhcm1OYW1lID8/IGAke3Byb3BzLnF1ZXVlLnF1ZXVlTmFtZX0gLSAke1Nxc1JlY29tbWVuZGVkQWxhcm1zTWV0cmljcy5BUFBST1hJTUFURV9BR0VfT0ZfT0xERVNUX01FU1NBR0V9YDtcbiAgICBjb25zdCBwZXJpb2QgPSBwcm9wcy5wZXJpb2QgPz8gRHVyYXRpb24ubWludXRlcygxKTtcbiAgICBjb25zdCBldmFsdWF0aW9uUGVyaW9kcyA9IHByb3BzLmV2YWx1YXRpb25QZXJpb2RzID8/IDE1O1xuXG4gICAgdmFsaWRhdGVUb3RhbEFsYXJtUGVyaW9kKHBlcmlvZCwgZXZhbHVhdGlvblBlcmlvZHMsIGFsYXJtTmFtZSk7XG5cbiAgICBzdXBlcihzY29wZSwgaWQsIHtcbiAgICAgIGFsYXJtTmFtZSxcbiAgICAgIG1ldHJpYzogcHJvcHMucXVldWUubWV0cmljQXBwcm94aW1hdGVBZ2VPZk9sZGVzdE1lc3NhZ2Uoe1xuICAgICAgICBwZXJpb2QsXG4gICAgICB9KSxcbiAgICAgIHRocmVzaG9sZDogcHJvcHMudGhyZXNob2xkLFxuICAgICAgZXZhbHVhdGlvblBlcmlvZHMsXG4gICAgICBkYXRhcG9pbnRzVG9BbGFybTogcHJvcHMuZGF0YXBvaW50c1RvQWxhcm0gPz8gMTUsXG4gICAgICB0cmVhdE1pc3NpbmdEYXRhOiBwcm9wcy50cmVhdE1pc3NpbmdEYXRhLFxuICAgICAgY29tcGFyaXNvbk9wZXJhdG9yOiBjbG91ZHdhdGNoLkNvbXBhcmlzb25PcGVyYXRvci5HUkVBVEVSX1RIQU5fT1JfRVFVQUxfVE9fVEhSRVNIT0xELFxuICAgICAgYWxhcm1EZXNjcmlwdGlvbjogcHJvcHMuYWxhcm1EZXNjcmlwdGlvbiA/PyAnVGhpcyBhbGFybSB3YXRjaGVzIHRoZSBhZ2Ugb2YgdGhlIG9sZGVzdCBtZXNzYWdlIGluIHRoZSBxdWV1ZS4gJ1xuICAgICAgICArICdZb3UgY2FuIHVzZSB0aGlzIGFsYXJtIHRvIG1vbml0b3IgaWYgeW91ciBjb25zdW1lcnMgYXJlIHByb2Nlc3NpbmcgU1FTIG1lc3NhZ2VzIGF0IHRoZSBkZXNpcmVkIHNwZWVkLiAnXG4gICAgICAgICsgJ0NvbnNpZGVyIGluY3JlYXNpbmcgdGhlIGNvbnN1bWVyIGNvdW50IG9yIGNvbnN1bWVyIHRocm91Z2hwdXQgdG8gcmVkdWNlIG1lc3NhZ2UgYWdlLiBUaGlzIG1ldHJpYyBjYW4gYmUgJ1xuICAgICAgICArICd1c2VkIGluIGNvbWJpbmF0aW9uIHdpdGggQXBwcm94aW1hdGVOdW1iZXJPZk1lc3NhZ2VzVmlzaWJsZSB0byBkZXRlcm1pbmUgaG93IGJpZyB0aGUgcXVldWUgYmFja2xvZyBpcyBhbmQgJ1xuICAgICAgICArICdob3cgcXVpY2tseSBtZXNzYWdlcyBhcmUgYmVpbmcgcHJvY2Vzc2VkLiBUbyBwcmV2ZW50IG1lc3NhZ2VzIGZyb20gYmVpbmcgZGVsZXRlZCBiZWZvcmUgcHJvY2Vzc2VkLCBjb25zaWRlciAnXG4gICAgICAgICsgJ2NvbmZpZ3VyaW5nIHRoZSBkZWFkLWxldHRlciBxdWV1ZSB0byBzaWRlbGluZSBwb3RlbnRpYWwgcG9pc29uIHBpbGwgbWVzc2FnZXMuJyxcbiAgICB9KTtcblxuICAgIGlmIChwcm9wcy5hbGFybUFjdGlvbikgdGhpcy5hZGRBbGFybUFjdGlvbihwcm9wcy5hbGFybUFjdGlvbik7XG4gICAgaWYgKHByb3BzLm9rQWN0aW9uKSB0aGlzLmFkZE9rQWN0aW9uKHByb3BzLm9rQWN0aW9uKTtcbiAgICBpZiAocHJvcHMuaW5zdWZmaWNpZW50RGF0YUFjdGlvbikgdGhpcy5hZGRJbnN1ZmZpY2llbnREYXRhQWN0aW9uKHByb3BzLmluc3VmZmljaWVudERhdGFBY3Rpb24pO1xuICB9XG59XG5cbi8qKlxuICogQ29uZmlndXJhdGlvbiBmb3IgdGhlIEFwcHJveGltYXRlTnVtYmVyT2ZNZXNzYWdlc05vdFZpc2libGUgYWxhcm0uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU3FzQXBwcm94aW1hdGVOdW1iZXJPZk1lc3NhZ2VzTm90VmlzaWJsZUFsYXJtQ29uZmlnIGV4dGVuZHMgU3FzQWxhcm1CYXNlQ29uZmlnIHtcbiAgLyoqXG4gICAqIFRoZSB2YWx1ZSBhZ2FpbnN0IHdoaWNoIHRoZSBzcGVjaWZpZWQgc3RhdGlzdGljIGlzIGNvbXBhcmVkLlxuICAgKlxuICAgKiBUaGUgcmVjb21tZW5kZWQgdGhyZXNob2xkIHZhbHVlIGZvciB0aGlzIGFsYXJtIGlzIGhpZ2hseSBkZXBlbmRlbnQgb24gdGhlIGV4cGVjdGVkIG51bWJlclxuICAgKiBvZiBtZXNzYWdlcyBpbiBmbGlnaHQuIFlvdSBjYW4gdXNlIGhpc3RvcmljYWwgZGF0YSB0byBjYWxjdWxhdGUgdGhlIG1heGltdW0gZXhwZWN0ZWRcbiAgICogbnVtYmVyIG9mIG1lc3NhZ2VzIGluIGZsaWdodCBhbmQgc2V0IHRoZSB0aHJlc2hvbGQgdG8gNTAlIG92ZXIgdGhpcyB2YWx1ZS4gSWYgY29uc3VtZXJzXG4gICAqIG9mIHRoZSBxdWV1ZSBhcmUgcHJvY2Vzc2luZyBidXQgbm90IGRlbGV0aW5nIG1lc3NhZ2VzIGZyb20gdGhlIHF1ZXVlLCB0aGlzIG51bWJlciB3aWxsXG4gICAqIHN1ZGRlbmx5IGluY3JlYXNlLlxuICAgKi9cbiAgcmVhZG9ubHkgdGhyZXNob2xkOiBudW1iZXI7XG4gIC8qKlxuICAgKiBUaGUgYWxhcm0gbmFtZS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBxdWV1ZS5xdWV1ZU5hbWUgKyAnIC0gQXBwcm94aW1hdGVOdW1iZXJPZk1lc3NhZ2VzTm90VmlzaWJsZSdcbiAgICovXG4gIHJlYWRvbmx5IGFsYXJtTmFtZT86IHN0cmluZztcbiAgLyoqXG4gICAqIFRoZSBkZXNjcmlwdGlvbiBvZiB0aGUgYWxhcm0uXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gVGhpcyBhbGFybSBoZWxwcyB0byBkZXRlY3QgYSBoaWdoIG51bWJlciBvZiBpbi1mbGlnaHQgbWVzc2FnZXMgd2l0aCByZXNwZWN0IHRvIFF1ZXVlTmFtZS5cbiAgICogRm9yIHRyb3VibGVzaG9vdGluZywgY2hlY2sgbWVzc2FnZSBiYWNrbG9nIGRlY3JlYXNpbmcgKGh0dHBzOi8vcmVwb3N0LmF3cy9rbm93bGVkZ2UtY2VudGVyL3Nxcy1tZXNzYWdlLWJhY2tsb2cpLlxuICAgKi9cbiAgcmVhZG9ubHkgYWxhcm1EZXNjcmlwdGlvbj86IHN0cmluZztcbn1cblxuLyoqXG4gKiBQcm9wZXJ0aWVzIGZvciB0aGUgU3FzQXBwcm94aW1hdGVOdW1iZXJPZk1lc3NhZ2VzTm90VmlzaWJsZUFsYXJtIGNvbnN0cnVjdC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTcXNBcHByb3hpbWF0ZU51bWJlck9mTWVzc2FnZXNOb3RWaXNpYmxlQWxhcm1Qcm9wcyBleHRlbmRzIFNxc0FwcHJveGltYXRlTnVtYmVyT2ZNZXNzYWdlc05vdFZpc2libGVBbGFybUNvbmZpZyB7XG4gIC8qKlxuICAgKiBUaGUgU1FTIHF1ZXVlIGZvciB3aGljaCB0byBjcmVhdGUgdGhlIGFsYXJtLlxuICAgKi9cbiAgcmVhZG9ubHkgcXVldWU6IHNxcy5JUXVldWU7XG59XG5cbi8qKlxuICogQW4gYWxhcm0gdGhhdCB3YXRjaGVzIHRoZSBudW1iZXIgb2YgbWVzc2FnZXMgdGhhdCBhcmUgaW4gZmxpZ2h0LlxuICpcbiAqIFRoaXMgYWxhcm0gaXMgdXNlZCB0byBkZXRlY3QgYSBoaWdoIG51bWJlciBvZiBpbi1mbGlnaHQgbWVzc2FnZXNcbiAqIGluIHRoZSBxdWV1ZS4gSWYgY29uc3VtZXJzIGRvIG5vdCBkZWxldGUgbWVzc2FnZXMgd2l0aGluIHRoZVxuICogdmlzaWJpbGl0eSB0aW1lb3V0IHBlcmlvZCwgd2hlbiB0aGUgcXVldWUgaXMgcG9sbGVkLCBtZXNzYWdlc1xuICogcmVhcHBlYXIgaW4gdGhlIHF1ZXVlLiBGb3IgRklGTyBxdWV1ZXMsIHRoZXJlIGNhbiBiZSBhIG1heGltdW1cbiAqIG9mIDIwLDAwMCBpbi1mbGlnaHQgbWVzc2FnZXMuIElmIHlvdSByZWFjaCB0aGlzIHF1b3RhLCBTUVMgcmV0dXJuc1xuICogbm8gZXJyb3IgbWVzc2FnZXMuIEEgRklGTyBxdWV1ZSBsb29rcyB0aHJvdWdoIHRoZSBmaXJzdCAyMGtcbiAqIG1lc3NhZ2VzIHRvIGRldGVybWluZSBhdmFpbGFibGUgbWVzc2FnZSBncm91cHMuIFRoaXMgbWVhbnMgdGhhdFxuICogaWYgeW91IGhhdmUgYSBiYWNrbG9nIG9mIG1lc3NhZ2VzIGluIGEgc2luZ2xlIG1lc3NhZ2UgZ3JvdXAsXG4gKiB5b3UgY2Fubm90IGNvbnN1bWUgbWVzc2FnZXMgZnJvbSBvdGhlciBtZXNzYWdlIGdyb3VwcyB0aGF0IHdlcmVcbiAqIHNlbnQgdG8gdGhlIHF1ZXVlIGF0IGEgbGF0ZXIgdGltZSB1bnRpbCB5b3Ugc3VjY2Vzc2Z1bGx5XG4gKiBjb25zdW1lIHRoZSBtZXNzYWdlcyBmcm9tIHRoZSBiYWNrbG9nLlxuICpcbiAqIFRoaXMgYWxhcm0gaXMgdHJpZ2dlcmVkIHdoZW4gdGhlIG51bWJlciBvZiBtZXNzYWdlcyB0aGF0IGFyZSBpblxuICogZmxpZ2h0IGV4Y2VlZHMgb3IgaXMgZXF1YWwgdG8gdGhlIHNwZWNpZmllZCB0aHJlc2hvbGQuXG4gKi9cbmV4cG9ydCBjbGFzcyBTcXNBcHByb3hpbWF0ZU51bWJlck9mTWVzc2FnZXNOb3RWaXNpYmxlQWxhcm0gZXh0ZW5kcyBjbG91ZHdhdGNoLkFsYXJtIHtcbiAgY29uc3RydWN0b3Ioc2NvcGU6IElDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBTcXNBcHByb3hpbWF0ZU51bWJlck9mTWVzc2FnZXNOb3RWaXNpYmxlQWxhcm1Qcm9wcykge1xuICAgIGNvbnN0IGFsYXJtTmFtZSA9IHByb3BzLmFsYXJtTmFtZSA/PyBgJHtwcm9wcy5xdWV1ZS5xdWV1ZU5hbWV9IC0gJHtTcXNSZWNvbW1lbmRlZEFsYXJtc01ldHJpY3MuQVBQUk9YSU1BVEVfTlVNQkVSX09GX01FU1NBR0VTX05PVF9WSVNJQkxFfWA7XG4gICAgY29uc3QgcGVyaW9kID0gcHJvcHMucGVyaW9kID8/IER1cmF0aW9uLm1pbnV0ZXMoMSk7XG4gICAgY29uc3QgZXZhbHVhdGlvblBlcmlvZHMgPSBwcm9wcy5ldmFsdWF0aW9uUGVyaW9kcyA/PyAxNTtcblxuICAgIHZhbGlkYXRlVG90YWxBbGFybVBlcmlvZChwZXJpb2QsIGV2YWx1YXRpb25QZXJpb2RzLCBhbGFybU5hbWUpO1xuXG4gICAgc3VwZXIoc2NvcGUsIGlkLCB7XG4gICAgICBhbGFybU5hbWUsXG4gICAgICBtZXRyaWM6IHByb3BzLnF1ZXVlLm1ldHJpY0FwcHJveGltYXRlTnVtYmVyT2ZNZXNzYWdlc05vdFZpc2libGUoe1xuICAgICAgICBwZXJpb2QsXG4gICAgICB9KSxcbiAgICAgIHRocmVzaG9sZDogcHJvcHMudGhyZXNob2xkLFxuICAgICAgZXZhbHVhdGlvblBlcmlvZHMsXG4gICAgICBkYXRhcG9pbnRzVG9BbGFybTogcHJvcHMuZGF0YXBvaW50c1RvQWxhcm0gPz8gMTUsXG4gICAgICB0cmVhdE1pc3NpbmdEYXRhOiBwcm9wcy50cmVhdE1pc3NpbmdEYXRhLFxuICAgICAgY29tcGFyaXNvbk9wZXJhdG9yOiBjbG91ZHdhdGNoLkNvbXBhcmlzb25PcGVyYXRvci5HUkVBVEVSX1RIQU5fT1JfRVFVQUxfVE9fVEhSRVNIT0xELFxuICAgICAgYWxhcm1EZXNjcmlwdGlvbjogcHJvcHMuYWxhcm1EZXNjcmlwdGlvbiA/PyAnVGhpcyBhbGFybSBoZWxwcyB0byBkZXRlY3QgYSBoaWdoIG51bWJlciBvZiBpbi1mbGlnaHQgJ1xuICAgICAgICArICdtZXNzYWdlcyB3aXRoIHJlc3BlY3QgdG8gUXVldWVOYW1lLiBGb3IgdHJvdWJsZXNob290aW5nLCBjaGVjayBtZXNzYWdlIGJhY2tsb2cgZGVjcmVhc2luZyAnXG4gICAgICAgICsgJyhodHRwczovL3JlcG9zdC5hd3Mva25vd2xlZGdlLWNlbnRlci9zcXMtbWVzc2FnZS1iYWNrbG9nKS4nLFxuICAgIH0pO1xuXG4gICAgaWYgKHByb3BzLmFsYXJtQWN0aW9uKSB0aGlzLmFkZEFsYXJtQWN0aW9uKHByb3BzLmFsYXJtQWN0aW9uKTtcbiAgICBpZiAocHJvcHMub2tBY3Rpb24pIHRoaXMuYWRkT2tBY3Rpb24ocHJvcHMub2tBY3Rpb24pO1xuICAgIGlmIChwcm9wcy5pbnN1ZmZpY2llbnREYXRhQWN0aW9uKSB0aGlzLmFkZEluc3VmZmljaWVudERhdGFBY3Rpb24ocHJvcHMuaW5zdWZmaWNpZW50RGF0YUFjdGlvbik7XG4gIH1cbn1cblxuLyoqXG4gKiBDb25maWd1cmF0aW9uIGZvciB0aGUgQXBwcm94aW1hdGVOdW1iZXJPZk1lc3NhZ2VzVmlzaWJsZSBhbGFybS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTcXNBcHByb3hpbWF0ZU51bWJlck9mTWVzc2FnZXNWaXNpYmxlQWxhcm1Db25maWcgZXh0ZW5kcyBTcXNBbGFybUJhc2VDb25maWcge1xuICAvKipcbiAgICogVGhlIHZhbHVlIGFnYWluc3Qgd2hpY2ggdGhlIHNwZWNpZmllZCBzdGF0aXN0aWMgaXMgY29tcGFyZWQuXG4gICAqXG4gICAqIEFuIHVuZXhwZWN0ZWRseSBoaWdoIG51bWJlciBvZiBtZXNzYWdlcyB2aXNpYmxlIGluZGljYXRlcyB0aGF0IG1lc3NhZ2VzIGFyZSBub3QgYmVpbmdcbiAgICogcHJvY2Vzc2VkIGJ5IGEgY29uc3VtZXIgYXQgdGhlIGV4cGVjdGVkIHJhdGUuIFlvdSBzaG91bGQgY29uc2lkZXIgaGlzdG9yaWNhbCBkYXRhIHdoZW5cbiAgICogeW91IHNldCB0aGlzIHRocmVzaG9sZC5cbiAgICovXG4gIHJlYWRvbmx5IHRocmVzaG9sZDogbnVtYmVyO1xuICAvKipcbiAgICogVGhlIGFsYXJtIG5hbWUuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gcXVldWUucXVldWVOYW1lICsgJyAtIEFwcHJveGltYXRlTnVtYmVyT2ZNZXNzYWdlc1Zpc2libGUnXG4gICAqL1xuICByZWFkb25seSBhbGFybU5hbWU/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBUaGUgZGVzY3JpcHRpb24gb2YgdGhlIGFsYXJtLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIFRoaXMgYWxhcm0gaGVscHMgdG8gZGV0ZWN0IGEgaGlnaCBudW1iZXIgb2YgaW4tZmxpZ2h0IG1lc3NhZ2VzIHdpdGggcmVzcGVjdCB0byBRdWV1ZU5hbWUuXG4gICAqIEZvciB0cm91Ymxlc2hvb3RpbmcsIGNoZ