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.

364 lines 62.8 kB
"use strict"; var _a, _b, _c, _d, _e, _f, _g; Object.defineProperty(exports, "__esModule", { value: true }); exports.LambdaRecommendedAlarmsAspect = exports.Function = exports.LambdaRecommendedAlarms = exports.LambdaConcurrentExecutionsAlarm = exports.LambdaDurationAlarm = exports.LambdaThrottlesAlarm = exports.LambdaErrorsAlarm = exports.LambdaRecommendedAlarmsMetrics = 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 Lambda alarms. */ var LambdaRecommendedAlarmsMetrics; (function (LambdaRecommendedAlarmsMetrics) { /** * Errors include the exceptions thrown by the code as well as exceptions thrown by the Lambda runtime. */ LambdaRecommendedAlarmsMetrics["ERRORS"] = "Errors"; /** * Throttles occur when there is no concurrency available for scale up. */ LambdaRecommendedAlarmsMetrics["THROTTLES"] = "Throttles"; /** * Duration is the time taken for the function to process an event. */ LambdaRecommendedAlarmsMetrics["DURATION"] = "Duration"; /** * ConcurrentExecutions is the number of concurrent executions of the function. */ LambdaRecommendedAlarmsMetrics["CONCURRENT_EXECUTIONS"] = "ConcurrentExecutions"; })(LambdaRecommendedAlarmsMetrics || (exports.LambdaRecommendedAlarmsMetrics = LambdaRecommendedAlarmsMetrics = {})); /** * The alarm helps detect high error counts in function invocations. * * The alarm is triggered when the number of errors exceeds the specified * threshold. */ class LambdaErrorsAlarm extends aws_cdk_lib_1.aws_cloudwatch.Alarm { constructor(scope, id, props) { const alarmName = props.alarmName ?? `${props.lambdaFunction.functionName} - ${LambdaRecommendedAlarmsMetrics.ERRORS}`; const period = props.period ?? aws_cdk_lib_1.Duration.minutes(1); const evaluationPeriods = props.evaluationPeriods ?? 3; (0, common_1.validateTotalAlarmPeriod)(period, evaluationPeriods, alarmName); super(scope, id, { alarmName, metric: props.lambdaFunction.metricErrors({ period, }), threshold: props.threshold, evaluationPeriods, datapointsToAlarm: props.datapointsToAlarm ?? 3, treatMissingData: props.treatMissingData, comparisonOperator: aws_cdk_lib_1.aws_cloudwatch.ComparisonOperator.GREATER_THAN_THRESHOLD, alarmDescription: props.alarmDescription ?? 'This alarm detects high error counts. Errors includes the exceptions ' + 'thrown by the code as well as exceptions thrown by the Lambda runtime. You can check the logs related to the ' + 'function to diagnose the issue.', }); if (props.alarmAction) this.addAlarmAction(props.alarmAction); if (props.okAction) this.addOkAction(props.okAction); if (props.insufficientDataAction) this.addInsufficientDataAction(props.insufficientDataAction); } } exports.LambdaErrorsAlarm = LambdaErrorsAlarm; _a = JSII_RTTI_SYMBOL_1; LambdaErrorsAlarm[_a] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.LambdaErrorsAlarm", version: "0.0.17" }; /** * The alarm helps detect a high number of throttled invocation requests * for a Lambda function. It is important to know if requests are constantly * getting rejected due to throttling and if you need to improve Lambda * function performance or increase concurrency capacity to avoid constant * throttling. * * The alarm is triggered when the number of throttles exceeds or equals * the specified threshold. */ class LambdaThrottlesAlarm extends aws_cdk_lib_1.aws_cloudwatch.Alarm { constructor(scope, id, props) { const alarmName = props.alarmName ?? `${props.lambdaFunction.functionName} - ${LambdaRecommendedAlarmsMetrics.THROTTLES}`; const period = props.period ?? aws_cdk_lib_1.Duration.minutes(1); const evaluationPeriods = props.evaluationPeriods ?? 5; (0, common_1.validateTotalAlarmPeriod)(period, evaluationPeriods, alarmName); super(scope, id, { alarmName, metric: props.lambdaFunction.metricThrottles({ period, }), threshold: props.threshold, evaluationPeriods, datapointsToAlarm: props.datapointsToAlarm ?? 5, treatMissingData: props.treatMissingData, comparisonOperator: aws_cdk_lib_1.aws_cloudwatch.ComparisonOperator.GREATER_THAN_THRESHOLD, alarmDescription: props.alarmDescription ?? 'This alarm detects a high number of throttled invocation requests. ' + 'Throttling occurs when there is no concurrency is available for scale up. There are several approaches to ' + 'resolve this issue. 1) Request a concurrency increase from AWS Support in this Region. 2) Identify performance ' + 'issues in the function to improve the speed of processing and therefore improve throughput. 3) Increase the batch ' + 'size of the function, so that more messages are processed by each function invocation.', }); if (props.alarmAction) this.addAlarmAction(props.alarmAction); if (props.okAction) this.addOkAction(props.okAction); if (props.insufficientDataAction) this.addInsufficientDataAction(props.insufficientDataAction); } } exports.LambdaThrottlesAlarm = LambdaThrottlesAlarm; _b = JSII_RTTI_SYMBOL_1; LambdaThrottlesAlarm[_b] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.LambdaThrottlesAlarm", version: "0.0.17" }; /** * This alarm can detect a long running duration of a * Lambda function. High runtime duration indicates that * a function is taking a longer time for invocation, and * can also impact the concurrency capacity of invocation * if Lambda is handling a higher number of events. It is * critical to know if the Lambda function is constantly * taking longer execution time than expected. * * The alarm is triggered when the duration of the function * invocations exceeds the specified threshold. */ class LambdaDurationAlarm extends aws_cdk_lib_1.aws_cloudwatch.Alarm { constructor(scope, id, props) { const alarmName = props.alarmName ?? `${props.lambdaFunction.functionName} - ${LambdaRecommendedAlarmsMetrics.DURATION}`; 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.lambdaFunction.metricDuration({ period, }), threshold: props.threshold, evaluationPeriods, datapointsToAlarm: props.datapointsToAlarm ?? 15, treatMissingData: props.treatMissingData, comparisonOperator: aws_cdk_lib_1.aws_cloudwatch.ComparisonOperator.GREATER_THAN_THRESHOLD, alarmDescription: props.alarmDescription ?? 'This alarm detects long duration times for processing an event by a ' + 'Lambda function. Long durations might be because of changes in function code making the function take longer to ' + 'execute, or the function\'s dependencies taking longer.', }); if (props.alarmAction) this.addAlarmAction(props.alarmAction); if (props.okAction) this.addOkAction(props.okAction); if (props.insufficientDataAction) this.addInsufficientDataAction(props.insufficientDataAction); } } exports.LambdaDurationAlarm = LambdaDurationAlarm; _c = JSII_RTTI_SYMBOL_1; LambdaDurationAlarm[_c] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.LambdaDurationAlarm", version: "0.0.17" }; /** * This alarm can proactively detect if the concurrency of the * function is approaching the Region-level concurrency quota * of your account, so that you can act on it. A function is * throttled if it reaches the Region-level concurrency quota * of the account. * * The alarm is triggered when the number of concurrent executions * exceeds the specified threshold. */ class LambdaConcurrentExecutionsAlarm extends aws_cdk_lib_1.aws_cloudwatch.Alarm { constructor(scope, id, props) { const alarmName = props.alarmName ?? `${props.lambdaFunction.functionName} - ${LambdaRecommendedAlarmsMetrics.CONCURRENT_EXECUTIONS}`; const period = props.period ?? aws_cdk_lib_1.Duration.minutes(1); const evaluationPeriods = props.evaluationPeriods ?? 10; (0, common_1.validateTotalAlarmPeriod)(period, evaluationPeriods, alarmName); super(scope, id, { alarmName, metric: new aws_cdk_lib_1.aws_cloudwatch.Metric({ namespace: 'AWS/Lambda', metricName: LambdaRecommendedAlarmsMetrics.CONCURRENT_EXECUTIONS, dimensionsMap: { FunctionName: props.lambdaFunction.functionName, }, period, statistic: 'Maximum', }), threshold: props.threshold ?? 900, evaluationPeriods, datapointsToAlarm: props.datapointsToAlarm ?? 10, treatMissingData: props.treatMissingData, comparisonOperator: aws_cdk_lib_1.aws_cloudwatch.ComparisonOperator.GREATER_THAN_THRESHOLD, alarmDescription: props.alarmDescription ?? 'This alarm helps to monitor if the concurrency of the function is ' + 'approaching the Region-level concurrency limit of your account. A function starts to be throttled if it ' + 'reaches the concurrency limit.', }); if (props.alarmAction) this.addAlarmAction(props.alarmAction); if (props.okAction) this.addOkAction(props.okAction); if (props.insufficientDataAction) this.addInsufficientDataAction(props.insufficientDataAction); } } exports.LambdaConcurrentExecutionsAlarm = LambdaConcurrentExecutionsAlarm; _d = JSII_RTTI_SYMBOL_1; LambdaConcurrentExecutionsAlarm[_d] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.LambdaConcurrentExecutionsAlarm", version: "0.0.17" }; /** * A construct that creates recommended alarms for a Lambda function. * * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html#Lambda */ class LambdaRecommendedAlarms extends constructs_1.Construct { constructor(scope, id, props) { super(scope, id); if (!props.excludeAlarms?.includes(LambdaRecommendedAlarmsMetrics.ERRORS)) { this.alarmErrors = new LambdaErrorsAlarm(this, 'ErrorsAlarm', { lambdaFunction: props.lambdaFunction, treatMissingData: props.treatMissingData, ...props.configErrorsAlarm, }); if (props.defaultAlarmAction && !props.configErrorsAlarm.alarmAction) { this.alarmErrors.addAlarmAction(props.defaultAlarmAction); } if (props.defaultOkAction && !props.configErrorsAlarm.okAction) { this.alarmErrors.addOkAction(props.defaultOkAction); } if (props.defaultInsufficientDataAction && !props.configErrorsAlarm.insufficientDataAction) { this.alarmErrors.addInsufficientDataAction(props.defaultInsufficientDataAction); } } if (!props.excludeAlarms?.includes(LambdaRecommendedAlarmsMetrics.THROTTLES)) { this.alarmThrottles = new LambdaThrottlesAlarm(this, 'ThrottlesAlarm', { lambdaFunction: props.lambdaFunction, treatMissingData: props.treatMissingData, ...props.configThrottlesAlarm, }); if (props.defaultAlarmAction && !props.configThrottlesAlarm.alarmAction) { this.alarmThrottles.addAlarmAction(props.defaultAlarmAction); } if (props.defaultOkAction && !props.configThrottlesAlarm.okAction) { this.alarmThrottles.addOkAction(props.defaultOkAction); } if (props.defaultInsufficientDataAction && !props.configThrottlesAlarm.insufficientDataAction) { this.alarmThrottles.addInsufficientDataAction(props.defaultInsufficientDataAction); } } if (!props.excludeAlarms?.includes(LambdaRecommendedAlarmsMetrics.DURATION)) { this.alarmDuration = new LambdaDurationAlarm(this, 'DurationAlarm', { lambdaFunction: props.lambdaFunction, treatMissingData: props.treatMissingData, ...props.configDurationAlarm, }); if (props.defaultAlarmAction && !props.configDurationAlarm.alarmAction) { this.alarmDuration.addAlarmAction(props.defaultAlarmAction); } if (props.defaultOkAction && !props.configDurationAlarm.okAction) { this.alarmDuration.addOkAction(props.defaultOkAction); } if (props.defaultInsufficientDataAction && !props.configDurationAlarm.insufficientDataAction) { this.alarmDuration.addInsufficientDataAction(props.defaultInsufficientDataAction); } } if (!props.excludeAlarms?.includes(LambdaRecommendedAlarmsMetrics.CONCURRENT_EXECUTIONS)) { this.alarmConcurrentExecutions = new LambdaConcurrentExecutionsAlarm(this, 'ConcurrentExecutionsAlarm', { lambdaFunction: props.lambdaFunction, treatMissingData: props.treatMissingData, ...props.configConcurrentExecutionsAlarm, }); if (props.defaultAlarmAction && !props.configConcurrentExecutionsAlarm?.alarmAction) { this.alarmConcurrentExecutions.addAlarmAction(props.defaultAlarmAction); } if (props.defaultOkAction && !props.configConcurrentExecutionsAlarm?.okAction) { this.alarmConcurrentExecutions.addOkAction(props.defaultOkAction); } if (props.defaultInsufficientDataAction && !props.configConcurrentExecutionsAlarm?.insufficientDataAction) { this.alarmConcurrentExecutions.addInsufficientDataAction(props.defaultInsufficientDataAction); } } } } exports.LambdaRecommendedAlarms = LambdaRecommendedAlarms; _e = JSII_RTTI_SYMBOL_1; LambdaRecommendedAlarms[_e] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.LambdaRecommendedAlarms", version: "0.0.17" }; /** * An extension of the Lambda function construct * that provides methods to create recommended alarms */ class Function extends aws_cdk_lib_1.aws_lambda.Function { constructor(scope, id, props) { super(scope, id, props); } /** * Creates an alarm that monitors the number of errors */ alarmErrors(props) { return new LambdaErrorsAlarm(this, 'ErrorsAlarm', { lambdaFunction: this, ...props, }); } /** * Creates an alarm that monitors the number of throttles */ alarmThrottles(props) { return new LambdaThrottlesAlarm(this, 'ThrottlesAlarm', { lambdaFunction: this, ...props, }); } /** * Creates an alarm that monitors the duration of the function invocations */ alarmDuration(props) { return new LambdaDurationAlarm(this, 'DurationAlarm', { lambdaFunction: this, ...props, }); } /** * Creates an alarm that monitors the number of concurrent executions */ alarmConcurrentExecutions(props) { return new LambdaConcurrentExecutionsAlarm(this, 'ConcurrentExecutionsAlarm', { lambdaFunction: this, ...props, }); } /** * Creates recommended alarms for the Lambda function. * * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html#Lambda */ applyRecommendedAlarms(props) { return new LambdaRecommendedAlarms(this, 'LambdaRecommendedAlarms', { lambdaFunction: this, ...props, }); } } exports.Function = Function; _f = JSII_RTTI_SYMBOL_1; Function[_f] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.Function", version: "0.0.17" }; /** * An aspect that applies recommended alarms for Lambda functions. * * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html#Lambda */ class LambdaRecommendedAlarmsAspect { constructor(props) { this.props = props; } visit(node) { if (node instanceof aws_cdk_lib_1.aws_lambda.Function) { if (this.props.excludeResources && this.props.excludeResources.includes(node.node.id)) { return; } else { const lambdaFunction = node; new LambdaRecommendedAlarms(node, 'LambdaRecommendedAlarmsFromAspect', { lambdaFunction, ...this.props, }); } } } } exports.LambdaRecommendedAlarmsAspect = LambdaRecommendedAlarmsAspect; _g = JSII_RTTI_SYMBOL_1; LambdaRecommendedAlarmsAspect[_g] = { fqn: "@renovosolutions/cdk-library-cloudwatch-alarms.LambdaRecommendedAlarmsAspect", version: "0.0.17" }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGFtYmRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2xhbWJkYS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLDZDQUtxQjtBQUNyQiwyQ0FBbUQ7QUFDbkQscUNBQW9FO0FBRXBFOztHQUVHO0FBQ0gsSUFBWSw4QkFpQlg7QUFqQkQsV0FBWSw4QkFBOEI7SUFDeEM7O09BRUc7SUFDSCxtREFBaUIsQ0FBQTtJQUNqQjs7T0FFRztJQUNILHlEQUF1QixDQUFBO0lBQ3ZCOztPQUVHO0lBQ0gsdURBQXFCLENBQUE7SUFDckI7O09BRUc7SUFDSCxnRkFBOEMsQ0FBQTtBQUNoRCxDQUFDLEVBakJXLDhCQUE4Qiw4Q0FBOUIsOEJBQThCLFFBaUJ6QztBQWdFRDs7Ozs7R0FLRztBQUNILE1BQWEsaUJBQWtCLFNBQVEsNEJBQVUsQ0FBQyxLQUFLO0lBQ3JELFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBNkI7UUFDckUsTUFBTSxTQUFTLEdBQUcsS0FBSyxDQUFDLFNBQVMsSUFBSSxHQUFHLEtBQUssQ0FBQyxjQUFjLENBQUMsWUFBWSxNQUFNLDhCQUE4QixDQUFDLE1BQU0sRUFBRSxDQUFDO1FBQ3ZILE1BQU0sTUFBTSxHQUFHLEtBQUssQ0FBQyxNQUFNLElBQUksc0JBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDbkQsTUFBTSxpQkFBaUIsR0FBRyxLQUFLLENBQUMsaUJBQWlCLElBQUksQ0FBQyxDQUFDO1FBRXZELElBQUEsaUNBQXdCLEVBQUMsTUFBTSxFQUFFLGlCQUFpQixFQUFFLFNBQVMsQ0FBQyxDQUFDO1FBRS9ELEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxFQUFFO1lBQ2YsU0FBUztZQUNULE1BQU0sRUFBRSxLQUFLLENBQUMsY0FBYyxDQUFDLFlBQVksQ0FBQztnQkFDeEMsTUFBTTthQUNQLENBQUM7WUFDRixTQUFTLEVBQUUsS0FBSyxDQUFDLFNBQVM7WUFDMUIsaUJBQWlCO1lBQ2pCLGlCQUFpQixFQUFFLEtBQUssQ0FBQyxpQkFBaUIsSUFBSSxDQUFDO1lBQy9DLGdCQUFnQixFQUFFLEtBQUssQ0FBQyxnQkFBZ0I7WUFDeEMsa0JBQWtCLEVBQUUsNEJBQVUsQ0FBQyxrQkFBa0IsQ0FBQyxzQkFBc0I7WUFDeEUsZ0JBQWdCLEVBQUUsS0FBSyxDQUFDLGdCQUFnQixJQUFJLHVFQUF1RTtrQkFDL0csK0dBQStHO2tCQUMvRyxpQ0FBaUM7U0FDdEMsQ0FBQyxDQUFDO1FBRUgsSUFBSSxLQUFLLENBQUMsV0FBVztZQUFFLElBQUksQ0FBQyxjQUFjLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQzlELElBQUksS0FBSyxDQUFDLFFBQVE7WUFBRSxJQUFJLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUNyRCxJQUFJLEtBQUssQ0FBQyxzQkFBc0I7WUFBRSxJQUFJLENBQUMseUJBQXlCLENBQUMsS0FBSyxDQUFDLHNCQUFzQixDQUFDLENBQUM7SUFDakcsQ0FBQzs7QUExQkgsOENBMkJDOzs7QUF1REQ7Ozs7Ozs7OztHQVNHO0FBQ0gsTUFBYSxvQkFBcUIsU0FBUSw0QkFBVSxDQUFDLEtBQUs7SUFDeEQsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxLQUFnQztRQUN4RSxNQUFNLFNBQVMsR0FBRyxLQUFLLENBQUMsU0FBUyxJQUFJLEdBQUcsS0FBSyxDQUFDLGNBQWMsQ0FBQyxZQUFZLE1BQU0sOEJBQThCLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDMUgsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLE1BQU0sSUFBSSxzQkFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNuRCxNQUFNLGlCQUFpQixHQUFHLEtBQUssQ0FBQyxpQkFBaUIsSUFBSSxDQUFDLENBQUM7UUFFdkQsSUFBQSxpQ0FBd0IsRUFBQyxNQUFNLEVBQUUsaUJBQWlCLEVBQUUsU0FBUyxDQUFDLENBQUM7UUFFL0QsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLEVBQUU7WUFDZixTQUFTO1lBQ1QsTUFBTSxFQUFFLEtBQUssQ0FBQyxjQUFjLENBQUMsZUFBZSxDQUFDO2dCQUMzQyxNQUFNO2FBQ1AsQ0FBQztZQUNGLFNBQVMsRUFBRSxLQUFLLENBQUMsU0FBUztZQUMxQixpQkFBaUI7WUFDakIsaUJBQWlCLEVBQUUsS0FBSyxDQUFDLGlCQUFpQixJQUFJLENBQUM7WUFDL0MsZ0JBQWdCLEVBQUUsS0FBSyxDQUFDLGdCQUFnQjtZQUN4QyxrQkFBa0IsRUFBRSw0QkFBVSxDQUFDLGtCQUFrQixDQUFDLHNCQUFzQjtZQUN4RSxnQkFBZ0IsRUFBRSxLQUFLLENBQUMsZ0JBQWdCLElBQUkscUVBQXFFO2tCQUM3Ryw0R0FBNEc7a0JBQzVHLGlIQUFpSDtrQkFDakgsb0hBQW9IO2tCQUNwSCx3RkFBd0Y7U0FDN0YsQ0FBQyxDQUFDO1FBRUgsSUFBSSxLQUFLLENBQUMsV0FBVztZQUFFLElBQUksQ0FBQyxjQUFjLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQzlELElBQUksS0FBSyxDQUFDLFFBQVE7WUFBRSxJQUFJLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUNyRCxJQUFJLEtBQUssQ0FBQyxzQkFBc0I7WUFBRSxJQUFJLENBQUMseUJBQXlCLENBQUMsS0FBSyxDQUFDLHNCQUFzQixDQUFDLENBQUM7SUFDakcsQ0FBQzs7QUE1Qkgsb0RBNkJDOzs7QUF5REQ7Ozs7Ozs7Ozs7O0dBV0c7QUFDSCxNQUFhLG1CQUFvQixTQUFRLDRCQUFVLENBQUMsS0FBSztJQUN2RCxZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLEtBQStCO1FBQ3ZFLE1BQU0sU0FBUyxHQUFHLEtBQUssQ0FBQyxTQUFTLElBQUksR0FBRyxLQUFLLENBQUMsY0FBYyxDQUFDLFlBQVksTUFBTSw4QkFBOEIsQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUN6SCxNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsTUFBTSxJQUFJLHNCQUFRLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ25ELE1BQU0saUJBQWlCLEdBQUcsS0FBSyxDQUFDLGlCQUFpQixJQUFJLEVBQUUsQ0FBQztRQUV4RCxJQUFBLGlDQUF3QixFQUFDLE1BQU0sRUFBRSxpQkFBaUIsRUFBRSxTQUFTLENBQUMsQ0FBQztRQUUvRCxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRTtZQUNmLFNBQVM7WUFDVCxNQUFNLEVBQUUsS0FBSyxDQUFDLGNBQWMsQ0FBQyxjQUFjLENBQUM7Z0JBQzFDLE1BQU07YUFDUCxDQUFDO1lBQ0YsU0FBUyxFQUFFLEtBQUssQ0FBQyxTQUFTO1lBQzFCLGlCQUFpQjtZQUNqQixpQkFBaUIsRUFBRSxLQUFLLENBQUMsaUJBQWlCLElBQUksRUFBRTtZQUNoRCxnQkFBZ0IsRUFBRSxLQUFLLENBQUMsZ0JBQWdCO1lBQ3hDLGtCQUFrQixFQUFFLDRCQUFVLENBQUMsa0JBQWtCLENBQUMsc0JBQXNCO1lBQ3hFLGdCQUFnQixFQUFFLEtBQUssQ0FBQyxnQkFBZ0IsSUFBSSxzRUFBc0U7a0JBQ2hILGtIQUFrSDtrQkFDbEgseURBQXlEO1NBQzVELENBQUMsQ0FBQztRQUVILElBQUksS0FBSyxDQUFDLFdBQVc7WUFBRSxJQUFJLENBQUMsY0FBYyxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUM5RCxJQUFJLEtBQUssQ0FBQyxRQUFRO1lBQUUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDckQsSUFBSSxLQUFLLENBQUMsc0JBQXNCO1lBQUUsSUFBSSxDQUFDLHlCQUF5QixDQUFDLEtBQUssQ0FBQyxzQkFBc0IsQ0FBQyxDQUFDO0lBQ2pHLENBQUM7O0FBMUJILGtEQTJCQzs7O0FBdUREOzs7Ozs7Ozs7R0FTRztBQUNILE1BQWEsK0JBQWdDLFNBQVEsNEJBQVUsQ0FBQyxLQUFLO0lBQ25FLFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBMkM7UUFDbkYsTUFBTSxTQUFTLEdBQUcsS0FBSyxDQUFDLFNBQVMsSUFBSSxHQUFHLEtBQUssQ0FBQyxjQUFjLENBQUMsWUFBWSxNQUFNLDhCQUE4QixDQUFDLHFCQUFxQixFQUFFLENBQUM7UUFDdEksTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLE1BQU0sSUFBSSxzQkFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNuRCxNQUFNLGlCQUFpQixHQUFHLEtBQUssQ0FBQyxpQkFBaUIsSUFBSSxFQUFFLENBQUM7UUFFeEQsSUFBQSxpQ0FBd0IsRUFBQyxNQUFNLEVBQUUsaUJBQWlCLEVBQUUsU0FBUyxDQUFDLENBQUM7UUFFL0QsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLEVBQUU7WUFDZixTQUFTO1lBQ1QsTUFBTSxFQUFFLElBQUksNEJBQVUsQ0FBQyxNQUFNLENBQUM7Z0JBQzVCLFNBQVMsRUFBRSxZQUFZO2dCQUN2QixVQUFVLEVBQUUsOEJBQThCLENBQUMscUJBQXFCO2dCQUNoRSxhQUFhLEVBQUU7b0JBQ2IsWUFBWSxFQUFFLEtBQUssQ0FBQyxjQUFjLENBQUMsWUFBWTtpQkFDaEQ7Z0JBQ0QsTUFBTTtnQkFDTixTQUFTLEVBQUUsU0FBUzthQUNyQixDQUFDO1lBQ0YsU0FBUyxFQUFFLEtBQUssQ0FBQyxTQUFTLElBQUksR0FBRztZQUNqQyxpQkFBaUI7WUFDakIsaUJBQWlCLEVBQUUsS0FBSyxDQUFDLGlCQUFpQixJQUFJLEVBQUU7WUFDaEQsZ0JBQWdCLEVBQUUsS0FBSyxDQUFDLGdCQUFnQjtZQUN4QyxrQkFBa0IsRUFBRSw0QkFBVSxDQUFDLGtCQUFrQixDQUFDLHNCQUFzQjtZQUN4RSxnQkFBZ0IsRUFBRSxLQUFLLENBQUMsZ0JBQWdCLElBQUksb0VBQW9FO2tCQUM1RywwR0FBMEc7a0JBQzFHLGdDQUFnQztTQUNyQyxDQUFDLENBQUM7UUFFSCxJQUFJLEtBQUssQ0FBQyxXQUFXO1lBQUUsSUFBSSxDQUFDLGNBQWMsQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDOUQsSUFBSSxLQUFLLENBQUMsUUFBUTtZQUFFLElBQUksQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ3JELElBQUksS0FBSyxDQUFDLHNCQUFzQjtZQUFFLElBQUksQ0FBQyx5QkFBeUIsQ0FBQyxLQUFLLENBQUMsc0JBQXNCLENBQUMsQ0FBQztJQUNqRyxDQUFDOztBQWhDSCwwRUFpQ0M7OztBQXNFRDs7OztHQUlHO0FBQ0gsTUFBYSx1QkFBd0IsU0FBUSxzQkFBUztJQWtCcEQsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxLQUFtQztRQUMzRSxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBRWpCLElBQUksQ0FBQyxLQUFLLENBQUMsYUFBYSxFQUFFLFFBQVEsQ0FBQyw4QkFBOEIsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO1lBQzFFLElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxpQkFBaUIsQ0FBQyxJQUFJLEVBQUUsYUFBYSxFQUFFO2dCQUM1RCxjQUFjLEVBQUUsS0FBSyxDQUFDLGNBQWM7Z0JBQ3BDLGdCQUFnQixFQUFFLEtBQUssQ0FBQyxnQkFBZ0I7Z0JBQ3hDLEdBQUcsS0FBSyxDQUFDLGlCQUFpQjthQUMzQixDQUFDLENBQUM7WUFFSCxJQUFJLEtBQUssQ0FBQyxrQkFBa0IsSUFBSSxDQUFDLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxXQUFXLEVBQUUsQ0FBQztnQkFDckUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxjQUFjLENBQUMsS0FBSyxDQUFDLGtCQUFrQixDQUFDLENBQUM7WUFDNUQsQ0FBQztZQUVELElBQUksS0FBSyxDQUFDLGVBQWUsSUFBSSxDQUFDLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxRQUFRLEVBQUUsQ0FBQztnQkFDL0QsSUFBSSxDQUFDLFdBQVcsQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLGVBQWUsQ0FBQyxDQUFDO1lBQ3RELENBQUM7WUFFRCxJQUFJLEtBQUssQ0FBQyw2QkFBNkIsSUFBSSxDQUFDLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxzQkFBc0IsRUFBRSxDQUFDO2dCQUMzRixJQUFJLENBQUMsV0FBVyxDQUFDLHlCQUF5QixDQUFDLEtBQUssQ0FBQyw2QkFBNkIsQ0FBQyxDQUFDO1lBQ2xGLENBQUM7UUFDSCxDQUFDO1FBRUQsSUFBSSxDQUFDLEtBQUssQ0FBQyxhQUFhLEVBQUUsUUFBUSxDQUFDLDhCQUE4QixDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUM7WUFDN0UsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLG9CQUFvQixDQUFDLElBQUksRUFBRSxnQkFBZ0IsRUFBRTtnQkFDckUsY0FBYyxFQUFFLEtBQUssQ0FBQyxjQUFjO2dCQUNwQyxnQkFBZ0IsRUFBRSxLQUFLLENBQUMsZ0JBQWdCO2dCQUN4QyxHQUFHLEtBQUssQ0FBQyxvQkFBb0I7YUFDOUIsQ0FBQyxDQUFDO1lBRUgsSUFBSSxLQUFLLENBQUMsa0JBQWtCLElBQUksQ0FBQyxLQUFLLENBQUMsb0JBQW9CLENBQUMsV0FBVyxFQUFFLENBQUM7Z0JBQ3hFLElBQUksQ0FBQyxjQUFjLENBQUMsY0FBYyxDQUFDLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO1lBQy9ELENBQUM7WUFFRCxJQUFJLEtBQUssQ0FBQyxlQUFlLElBQUksQ0FBQyxLQUFLLENBQUMsb0JBQW9CLENBQUMsUUFBUSxFQUFFLENBQUM7Z0JBQ2xFLElBQUksQ0FBQyxjQUFjLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxlQUFlLENBQUMsQ0FBQztZQUN6RCxDQUFDO1lBRUQsSUFBSSxLQUFLLENBQUMsNkJBQTZCLElBQUksQ0FBQyxLQUFLLENBQUMsb0JBQW9CLENBQUMsc0JBQXNCLEVBQUUsQ0FBQztnQkFDOUYsSUFBSSxDQUFDLGNBQWMsQ0FBQyx5QkFBeUIsQ0FBQyxLQUFLLENBQUMsNkJBQTZCLENBQUMsQ0FBQztZQUNyRixDQUFDO1FBQ0gsQ0FBQztRQUVELElBQUksQ0FBQyxLQUFLLENBQUMsYUFBYSxFQUFFLFFBQVEsQ0FBQyw4QkFBOEIsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO1lBQzVFLElBQUksQ0FBQyxhQUFhLEdBQUcsSUFBSSxtQkFBbUIsQ0FBQyxJQUFJLEVBQUUsZUFBZSxFQUFFO2dCQUNsRSxjQUFjLEVBQUUsS0FBSyxDQUFDLGNBQWM7Z0JBQ3BDLGdCQUFnQixFQUFFLEtBQUssQ0FBQyxnQkFBZ0I7Z0JBQ3hDLEdBQUcsS0FBSyxDQUFDLG1CQUFtQjthQUM3QixDQUFDLENBQUM7WUFFSCxJQUFJLEtBQUssQ0FBQyxrQkFBa0IsSUFBSSxDQUFDLEtBQUssQ0FBQyxtQkFBbUIsQ0FBQyxXQUFXLEVBQUUsQ0FBQztnQkFDdkUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxjQUFjLENBQUMsS0FBSyxDQUFDLGtCQUFrQixDQUFDLENBQUM7WUFDOUQsQ0FBQztZQUVELElBQUksS0FBSyxDQUFDLGVBQWUsSUFBSSxDQUFDLEtBQUssQ0FBQyxtQkFBbUIsQ0FBQyxRQUFRLEVBQUUsQ0FBQztnQkFDakUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLGVBQWUsQ0FBQyxDQUFDO1lBQ3hELENBQUM7WUFFRCxJQUFJLEtBQUssQ0FBQyw2QkFBNkIsSUFBSSxDQUFDLEtBQUssQ0FBQyxtQkFBbUIsQ0FBQyxzQkFBc0IsRUFBRSxDQUFDO2dCQUM3RixJQUFJLENBQUMsYUFBYSxDQUFDLHlCQUF5QixDQUFDLEtBQUssQ0FBQyw2QkFBNkIsQ0FBQyxDQUFDO1lBQ3BGLENBQUM7UUFDSCxDQUFDO1FBRUQsSUFBSSxDQUFDLEtBQUssQ0FBQyxhQUFhLEVBQUUsUUFBUSxDQUFDLDhCQUE4QixDQUFDLHFCQUFxQixDQUFDLEVBQUUsQ0FBQztZQUN6RixJQUFJLENBQUMseUJBQXlCLEdBQUcsSUFBSSwrQkFBK0IsQ0FBQyxJQUFJLEVBQUUsMkJBQTJCLEVBQUU7Z0JBQ3RHLGNBQWMsRUFBRSxLQUFLLENBQUMsY0FBYztnQkFDcEMsZ0JBQWdCLEVBQUUsS0FBSyxDQUFDLGdCQUFnQjtnQkFDeEMsR0FBRyxLQUFLLENBQUMsK0JBQStCO2FBQ3pDLENBQUMsQ0FBQztZQUVILElBQUksS0FBSyxDQUFDLGtCQUFrQixJQUFJLENBQUMsS0FBSyxDQUFDLCtCQUErQixFQUFFLFdBQVcsRUFBRSxDQUFDO2dCQUNwRixJQUFJLENBQUMseUJBQXlCLENBQUMsY0FBYyxDQUFDLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO1lBQzFFLENBQUM7WUFFRCxJQUFJLEtBQUssQ0FBQyxlQUFlLElBQUksQ0FBQyxLQUFLLENBQUMsK0JBQStCLEVBQUUsUUFBUSxFQUFFLENBQUM7Z0JBQzlFLElBQUksQ0FBQyx5QkFBeUIsQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLGVBQWUsQ0FBQyxDQUFDO1lBQ3BFLENBQUM7WUFFRCxJQUFJLEtBQUssQ0FBQyw2QkFBNkIsSUFBSSxDQUFDLEtBQUssQ0FBQywrQkFBK0IsRUFBRSxzQkFBc0IsRUFBRSxDQUFDO2dCQUMxRyxJQUFJLENBQUMseUJBQXlCLENBQUMseUJBQXlCLENBQUMsS0FBSyxDQUFDLDZCQUE2QixDQUFDLENBQUM7WUFDaEcsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDOztBQXBHSCwwREFxR0M7OztBQUVEOzs7R0FHRztBQUNILE1BQWEsUUFBUyxTQUFRLHdCQUFNLENBQUMsUUFBUTtJQUMzQyxZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLEtBQTJCO1FBQ25FLEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQzFCLENBQUM7SUFFRDs7T0FFRztJQUNJLFdBQVcsQ0FBQyxLQUE4QjtRQUMvQyxPQUFPLElBQUksaUJBQWlCLENBQUMsSUFBSSxFQUFFLGFBQWEsRUFBRTtZQUNoRCxjQUFjLEVBQUUsSUFBSTtZQUNwQixHQUFHLEtBQUs7U0FDVCxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7O09BRUc7SUFDSSxjQUFjLENBQUMsS0FBaUM7UUFDckQsT0FBTyxJQUFJLG9CQUFvQixDQUFDLElBQUksRUFBRSxnQkFBZ0IsRUFBRTtZQUN0RCxjQUFjLEVBQUUsSUFBSTtZQUNwQixHQUFHLEtBQUs7U0FDVCxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7O09BRUc7SUFDSSxhQUFhLENBQUMsS0FBZ0M7UUFDbkQsT0FBTyxJQUFJLG1CQUFtQixDQUFDLElBQUksRUFBRSxlQUFlLEVBQUU7WUFDcEQsY0FBYyxFQUFFLElBQUk7WUFDcEIsR0FBRyxLQUFLO1NBQ1QsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVEOztPQUVHO0lBQ0kseUJBQXlCLENBQUMsS0FBNkM7UUFDNUUsT0FBTyxJQUFJLCtCQUErQixDQUFDLElBQUksRUFBRSwyQkFBMkIsRUFBRTtZQUM1RSxjQUFjLEVBQUUsSUFBSTtZQUNwQixHQUFHLEtBQUs7U0FDVCxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNJLHNCQUFzQixDQUFDLEtBQW9DO1FBQ2hFLE9BQU8sSUFBSSx1QkFBdUIsQ0FBQyxJQUFJLEVBQUUseUJBQXlCLEVBQUU7WUFDbEUsY0FBYyxFQUFFLElBQUk7WUFDcEIsR0FBRyxLQUFLO1NBQ1QsQ0FBQyxDQUFDO0lBQ0wsQ0FBQzs7QUF2REgsNEJBd0RDOzs7QUFFRDs7OztHQUlHO0FBQ0gsTUFBYSw2QkFBNkI7SUFDeEMsWUFBNkIsS0FBb0M7UUFBcEMsVUFBSyxHQUFMLEtBQUssQ0FBK0I7SUFBRyxDQUFDO0lBRTlELEtBQUssQ0FBQyxJQUFnQjtRQUMzQixJQUFJLElBQUksWUFBWSx3QkFBTSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ3BDLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxnQkFBZ0IsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLGdCQUFnQixDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUM7Z0JBQ3RGLE9BQU87WUFDVCxDQUFDO2lCQUFNLENBQUM7Z0JBQ04sTUFBTSxjQUFjLEdBQUcsSUFBd0IsQ0FBQztnQkFFaEQsSUFBSSx1QkFBdUIsQ0FBQyxJQUFJLEVBQUUsbUNBQW1DLEVBQUU7b0JBQ3JFLGNBQWM7b0JBQ2QsR0FBRyxJQUFJLENBQUMsS0FBSztpQkFDZCxDQUFDLENBQUM7WUFDTCxDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7O0FBaEJILHNFQWlCQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIElBc3BlY3QsXG4gIGF3c19sYW1iZGEgYXMgbGFtYmRhLFxuICBhd3NfY2xvdWR3YXRjaCBhcyBjbG91ZHdhdGNoLFxuICBEdXJhdGlvbixcbn0gZnJvbSAnYXdzLWNkay1saWInO1xuaW1wb3J0IHsgSUNvbnN0cnVjdCwgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgeyBBbGFybUJhc2VQcm9wcywgdmFsaWRhdGVUb3RhbEFsYXJtUGVyaW9kIH0gZnJvbSAnLi9jb21tb24nO1xuXG4vKipcbiAqIFRoZSByZWNvbW1lbmRlZCBtZXRyaWNzIGZvciBMYW1iZGEgYWxhcm1zLlxuICovXG5leHBvcnQgZW51bSBMYW1iZGFSZWNvbW1lbmRlZEFsYXJtc01ldHJpY3Mge1xuICAvKipcbiAgICogRXJyb3JzIGluY2x1ZGUgdGhlIGV4Y2VwdGlvbnMgdGhyb3duIGJ5IHRoZSBjb2RlIGFzIHdlbGwgYXMgZXhjZXB0aW9ucyB0aHJvd24gYnkgdGhlIExhbWJkYSBydW50aW1lLlxuICAgKi9cbiAgRVJST1JTID0gJ0Vycm9ycycsXG4gIC8qKlxuICAgKiBUaHJvdHRsZXMgb2NjdXIgd2hlbiB0aGVyZSBpcyBubyBjb25jdXJyZW5jeSBhdmFpbGFibGUgZm9yIHNjYWxlIHVwLlxuICAgKi9cbiAgVEhST1RUTEVTID0gJ1Rocm90dGxlcycsXG4gIC8qKlxuICAgKiBEdXJhdGlvbiBpcyB0aGUgdGltZSB0YWtlbiBmb3IgdGhlIGZ1bmN0aW9uIHRvIHByb2Nlc3MgYW4gZXZlbnQuXG4gICAqL1xuICBEVVJBVElPTiA9ICdEdXJhdGlvbicsXG4gIC8qKlxuICAgKiBDb25jdXJyZW50RXhlY3V0aW9ucyBpcyB0aGUgbnVtYmVyIG9mIGNvbmN1cnJlbnQgZXhlY3V0aW9ucyBvZiB0aGUgZnVuY3Rpb24uXG4gICAqL1xuICBDT05DVVJSRU5UX0VYRUNVVElPTlMgPSAnQ29uY3VycmVudEV4ZWN1dGlvbnMnLFxufVxuXG5leHBvcnQgaW50ZXJmYWNlIExhbWJkYUFsYXJtQmFzZUNvbmZpZyBleHRlbmRzIEFsYXJtQmFzZVByb3BzIHtcbiAgLyoqXG4gICAqIFRoZSBwZXJpb2Qgb3ZlciB3aGljaCB0aGUgc3BlY2lmaWVkIHN0YXRpc3RpYyBpcyBhcHBsaWVkLlxuICAgKlxuICAgKiBAZGVmYXVsdCBEdXJhdGlvbi5taW51dGVzKDEpXG4gICAqL1xuICByZWFkb25seSBwZXJpb2Q/OiBEdXJhdGlvbjtcbn1cblxuLyoqXG4gKiBDb25maWd1cmF0aW9uIGZvciB0aGUgRXJyb3JzIGFsYXJtLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIExhbWJkYUVycm9yc0FsYXJtQ29uZmlnIGV4dGVuZHMgTGFtYmRhQWxhcm1CYXNlQ29uZmlnIHtcbiAgLyoqXG4gICAqIFRoZSB2YWx1ZSBhZ2FpbnN0IHdoaWNoIHRoZSBzcGVjaWZpZWQgc3RhdGlzdGljcyBpcyBjb21wYXJlZC5cbiAgICpcbiAgICogU2V0IHRoZSB0aHJlc2hvbGQgdG8gYSBudW1iZXIgZ3JlYXRlciB0aGFuIHplcm8uIFRoZSBleGFjdFxuICAgKiB2YWx1ZSBjYW4gZGVwZW5kIG9uIHRoZSB0b2xlcmFuY2UgZm9yIGVycm9ycyBpbiB5b3VyXG4gICAqIGFwcGxpY2F0aW9uLiBVbmRlcnN0YW5kIHRoZSBjcml0aWNhbGl0eSBvZiB0aGUgaW52b2NhdGlvbnNcbiAgICogdGhhdCB0aGUgZnVuY3Rpb24gaXMgaGFuZGxpbmcuIEZvciBzb21lIGFwcGxpY2F0aW9ucywgYW55XG4gICAqIGVycm9yIG1pZ2h0IGJlIHVuYWNjZXB0YWJsZSwgd2hpbGUgb3RoZXIgYXBwbGljYXRpb25zIG1pZ2h0XG4gICAqIGFsbG93IGZvciBhIGNlcnRhaW4gbWFyZ2luIG9mIGVycm9yLlxuICAgKi9cbiAgcmVhZG9ubHkgdGhyZXNob2xkOiBudW1iZXI7XG4gIC8qKlxuICAgKiBUaGUgbnVtYmVyIG9mIHBlcmlvZHMgb3ZlciB3aGljaCBkYXRhIGlzIGNvbXBhcmVkIHRvIHRoZSBzcGVjaWZpZWQgdGhyZXNob2xkLlxuICAgKlxuICAgKiBAZGVmYXVsdCAzXG4gICAqL1xuICByZWFkb25seSBldmFsdWF0aW9uUGVyaW9kcz86IG51bWJlcjtcbiAgLyoqXG4gICAqIFRoZSBudW1iZXIgb2YgZGF0YSBwb2ludHMgdGhhdCBtdXN0IGJlIGJyZWFjaGluZyB0byB0cmlnZ2VyIHRoZSBhbGFybS5cbiAgICpcbiAgICogQGRlZmF1bHQgM1xuICAgKi9cbiAgcmVhZG9ubHkgZGF0YXBvaW50c1RvQWxhcm0/OiBudW1iZXI7XG4gIC8qKlxuICAgKiBUaGUgYWxhcm0gbmFtZS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBsYW1iZGFGdW5jdGlvbi5mdW5jdGlvbk5hbWUgKyAnIC0gRXJyb3JzJ1xuICAgKi9cbiAgcmVhZG9ubHkgYWxhcm1OYW1lPzogc3RyaW5nO1xuICAvKipcbiAgICogVGhlIGRlc2NyaXB0aW9uIG9mIHRoZSBhbGFybS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSAgVGhpcyBhbGFybSBkZXRlY3RzIGhpZ2ggZXJyb3IgY291bnRzLiBFcnJvcnMgaW5jbHVkZXMgdGhlIGV4Y2VwdGlvbnMgdGhyb3duIGJ5IHRoZSBjb2RlXG4gICAqIGFzIHdlbGwgYXMgZXhjZXB0aW9ucyB0aHJvd24gYnkgdGhlIExhbWJkYSBydW50aW1lLiBZb3UgY2FuIGNoZWNrIHRoZSBsb2dzIHJlbGF0ZWQgdG8gdGhlIGZ1bmN0aW9uXG4gICAqIHRvIGRpYWdub3NlIHRoZSBpc3N1ZS5cbiAgICovXG4gIHJlYWRvbmx5IGFsYXJtRGVzY3JpcHRpb24/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogVGhlIHByb3BlcnRpZXMgZm9yIHRoZSBMYW1iZGFFcnJvcnNBbGFybSBjb25zdHJ1Y3QuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTGFtYmRhRXJyb3JzQWxhcm1Qcm9wcyBleHRlbmRzIExhbWJkYUVycm9yc0FsYXJtQ29uZmlnIHtcbiAgLyoqXG4gICAqIFRoZSBMYW1iZGEgZnVuY3Rpb24gdG8gbW9uaXRvci5cbiAgICovXG4gIHJlYWRvbmx5IGxhbWJkYUZ1bmN0aW9uOiBsYW1iZGEuSUZ1bmN0aW9uO1xufVxuXG4vKipcbiAqIFRoZSBhbGFybSBoZWxwcyBkZXRlY3QgaGlnaCBlcnJvciBjb3VudHMgaW4gZnVuY3Rpb24gaW52b2NhdGlvbnMuXG4gKlxuICogVGhlIGFsYXJtIGlzIHRyaWdnZXJlZCB3aGVuIHRoZSBudW1iZXIgb2YgZXJyb3JzIGV4Y2VlZHMgdGhlIHNwZWNpZmllZFxuICogdGhyZXNob2xkLlxuICovXG5leHBvcnQgY2xhc3MgTGFtYmRhRXJyb3JzQWxhcm0gZXh0ZW5kcyBjbG91ZHdhdGNoLkFsYXJtIHtcbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IExhbWJkYUVycm9yc0FsYXJtUHJvcHMpIHtcbiAgICBjb25zdCBhbGFybU5hbWUgPSBwcm9wcy5hbGFybU5hbWUgPz8gYCR7cHJvcHMubGFtYmRhRnVuY3Rpb24uZnVuY3Rpb25OYW1lfSAtICR7TGFtYmRhUmVjb21tZW5kZWRBbGFybXNNZXRyaWNzLkVSUk9SU31gO1xuICAgIGNvbnN0IHBlcmlvZCA9IHByb3BzLnBlcmlvZCA/PyBEdXJhdGlvbi5taW51dGVzKDEpO1xuICAgIGNvbnN0IGV2YWx1YXRpb25QZXJpb2RzID0gcHJvcHMuZXZhbHVhdGlvblBlcmlvZHMgPz8gMztcblxuICAgIHZhbGlkYXRlVG90YWxBbGFybVBlcmlvZChwZXJpb2QsIGV2YWx1YXRpb25QZXJpb2RzLCBhbGFybU5hbWUpO1xuXG4gICAgc3VwZXIoc2NvcGUsIGlkLCB7XG4gICAgICBhbGFybU5hbWUsXG4gICAgICBtZXRyaWM6IHByb3BzLmxhbWJkYUZ1bmN0aW9uLm1ldHJpY0Vycm9ycyh7XG4gICAgICAgIHBlcmlvZCxcbiAgICAgIH0pLFxuICAgICAgdGhyZXNob2xkOiBwcm9wcy50aHJlc2hvbGQsXG4gICAgICBldmFsdWF0aW9uUGVyaW9kcyxcbiAgICAgIGRhdGFwb2ludHNUb0FsYXJtOiBwcm9wcy5kYXRhcG9pbnRzVG9BbGFybSA/PyAzLFxuICAgICAgdHJlYXRNaXNzaW5nRGF0YTogcHJvcHMudHJlYXRNaXNzaW5nRGF0YSxcbiAgICAgIGNvbXBhcmlzb25PcGVyYXRvcjogY2xvdWR3YXRjaC5Db21wYXJpc29uT3BlcmF0b3IuR1JFQVRFUl9USEFOX1RIUkVTSE9MRCxcbiAgICAgIGFsYXJtRGVzY3JpcHRpb246IHByb3BzLmFsYXJtRGVzY3JpcHRpb24gPz8gJ1RoaXMgYWxhcm0gZGV0ZWN0cyBoaWdoIGVycm9yIGNvdW50cy4gRXJyb3JzIGluY2x1ZGVzIHRoZSBleGNlcHRpb25zICdcbiAgICAgICAgKyAndGhyb3duIGJ5IHRoZSBjb2RlIGFzIHdlbGwgYXMgZXhjZXB0aW9ucyB0aHJvd24gYnkgdGhlIExhbWJkYSBydW50aW1lLiBZb3UgY2FuIGNoZWNrIHRoZSBsb2dzIHJlbGF0ZWQgdG8gdGhlICdcbiAgICAgICAgKyAnZnVuY3Rpb24gdG8gZGlhZ25vc2UgdGhlIGlzc3VlLicsXG4gICAgfSk7XG5cbiAgICBpZiAocHJvcHMuYWxhcm1BY3Rpb24pIHRoaXMuYWRkQWxhcm1BY3Rpb24ocHJvcHMuYWxhcm1BY3Rpb24pO1xuICAgIGlmIChwcm9wcy5va0FjdGlvbikgdGhpcy5hZGRPa0FjdGlvbihwcm9wcy5va0FjdGlvbik7XG4gICAgaWYgKHByb3BzLmluc3VmZmljaWVudERhdGFBY3Rpb24pIHRoaXMuYWRkSW5zdWZmaWNpZW50RGF0YUFjdGlvbihwcm9wcy5pbnN1ZmZpY2llbnREYXRhQWN0aW9uKTtcbiAgfVxufVxuXG4vKipcbiAqIENvbmZpZ3VyYXRpb24gZm9yIHRoZSBUaHJvdHRsZXMgYWxhcm0uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTGFtYmRhVGhyb3R0bGVzQWxhcm1Db25maWcgZXh0ZW5kcyBMYW1iZGFBbGFybUJhc2VDb25maWcge1xuICAvKipcbiAgICogVGhlIHZhbHVlIGFnYWluc3Qgd2hpY2ggdGhlIHNwZWNpZmllZCBzdGF0aWN0aXMgaXMgY29tcGFyZWQuXG4gICAqXG4gICAqIFNldCB0aGUgdGhyZXNob2xkIHRvIGEgbnVtYmVyIGdyZWF0ZXIgdGhhbiB6ZXJvLiBUaGUgZXhhY3QgdmFsdWVcbiAgICogb2YgdGhlIHRocmVzaG9sZCBjYW4gZGVwZW5kIG9uIHRoZSB0b2xlcmFuY2Ugb2YgdGhlIGFwcGxpY2F0aW9uLlxuICAgKiBTZXQgdGhlIHRocmVzaG9sZCBhY2NvcmRpbmcgdG8gaXRzIHVzYWdlIGFuZCBzY2FsaW5nIHJlcXVpcmVtZW50c1xuICAgKiBvZiB0aGUgZnVuY3Rpb24uXG4gICAqL1xuICByZWFkb25seSB0aHJlc2hvbGQ6IG51bWJlcjtcbiAgLyoqXG4gICAqIFRoZSBudW1iZXIgb2YgcGVyaW9kcyBvdmVyIHdoaWNoIGRhdGEgaXMgY29tcGFyZWQgdG8gdGhlIHNwZWNpZmllZCB0aHJlc2hvbGQuXG4gICAqXG4gICAqIEBkZWZhdWx0IDVcbiAgICovXG4gIHJlYWRvbmx5IGV2YWx1YXRpb25QZXJpb2RzPzogbnVtYmVyO1xuICAvKipcbiAgICogVGhlIG51bWJlciBvZiBkYXRhIHBvaW50cyB0aGF0IG11c3QgYmUgYnJlYWNoaW5nIHRvIHRyaWdnZXIgdGhlIGFsYXJtLlxuICAgKlxuICAgKiBAZGVmYXVsdCA1XG4gICAqL1xuICByZWFkb25seSBkYXRhcG9pbnRzVG9BbGFybT86IG51bWJlcjtcbiAgLyoqXG4gICAqIFRoZSBhbGFybSBuYW1lLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIGxhbWJkYUZ1bmN0aW9uLmZ1bmN0aW9uTmFtZSArICcgLSBUaHJvdHRsZXMnXG4gICAqL1xuICByZWFkb25seSBhbGFybU5hbWU/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBUaGUgZGVzY3JpcHRpb24gb2YgdGhlIGFsYXJtLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtICBUaGlzIGFsYXJtIGRldGVjdHMgYSBoaWdoIG51bWJlciBvZiB0aHJvdHRsZWQgaW52b2NhdGlvbiByZXF1ZXN0cy4gVGhyb3R0bGluZyBvY2N1cnMgd2hlblxuICAgKiB0aGVyZSBpcyBubyBjb25jdXJyZW5jeSBpcyBhdmFpbGFibGUgZm9yIHNjYWxlIHVwLiBUaGVyZSBhcmUgc2V2ZXJhbCBhcHByb2FjaGVzIHRvIHJlc29sdmUgdGhpcyBpc3N1ZS5cbiAgICogMSkgUmVxdWVzdCBhIGNvbmN1cnJlbmN5IGluY3JlYXNlIGZyb20gQVdTIFN1cHBvcnQgaW4gdGhpcyBSZWdpb24uIDIpIElkZW50aWZ5IHBlcmZvcm1hbmNlIGlzc3VlcyBpblxuICAgKiB0aGUgZnVuY3Rpb24gdG8gaW1wcm92ZSB0aGUgc3BlZWQgb2YgcHJvY2Vzc2luZyBhbmQgdGhlcmVmb3JlIGltcHJvdmUgdGhyb3VnaHB1dC4gMykgSW5jcmVhc2UgdGhlIGJhdGNoXG4gICAqIHNpemUgb2YgdGhlIGZ1bmN0aW9uLCBzbyB0aGF0IG1vcmUgbWVzc2FnZXMgYXJlIHByb2Nlc3NlZCBieSBlYWNoIGZ1bmN0aW9uIGludm9jYXRpb24uXG4gICAqL1xuICByZWFkb25seSBhbGFybURlc2NyaXB0aW9uPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIFRoZSBwcm9wZXJ0aWVzIGZvciB0aGUgTGFtYmRhVGhyb3R0bGVzQWxhcm0gY29uc3RydWN0LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIExhbWJkYVRocm90dGxlc0FsYXJtUHJvcHMgZXh0ZW5kcyBMYW1iZGFUaHJvdHRsZXNBbGFybUNvbmZpZyB7XG4gIC8qKlxuICAgKiBUaGUgTGFtYmRhIGZ1bmN0aW9uIHRvIG1vbml0b3IuXG4gICAqL1xuICByZWFkb25seSBsYW1iZGFGdW5jdGlvbjogbGFtYmRhLklGdW5jdGlvbjtcbn1cblxuLyoqXG4gKiBUaGUgYWxhcm0gaGVscHMgZGV0ZWN0IGEgaGlnaCBudW1iZXIgb2YgdGhyb3R0bGVkIGludm9jYXRpb24gcmVxdWVzdHNcbiAqIGZvciBhIExhbWJkYSBmdW5jdGlvbi4gSXQgaXMgaW1wb3J0YW50IHRvIGtub3cgaWYgcmVxdWVzdHMgYXJlIGNvbnN0YW50bHlcbiAqIGdldHRpbmcgcmVqZWN0ZWQgZHVlIHRvIHRocm90dGxpbmcgYW5kIGlmIHlvdSBuZWVkIHRvIGltcHJvdmUgTGFtYmRhXG4gKiBmdW5jdGlvbiBwZXJmb3JtYW5jZSBvciBpbmNyZWFzZSBjb25jdXJyZW5jeSBjYXBhY2l0eSB0byBhdm9pZCBjb25zdGFudFxuICogdGhyb3R0bGluZy5cbiAqXG4gKiBUaGUgYWxhcm0gaXMgdHJpZ2dlcmVkIHdoZW4gdGhlIG51bWJlciBvZiB0aHJvdHRsZXMgZXhjZWVkcyBvciBlcXVhbHNcbiAqIHRoZSBzcGVjaWZpZWQgdGhyZXNob2xkLlxuICovXG5leHBvcnQgY2xhc3MgTGFtYmRhVGhyb3R0bGVzQWxhcm0gZXh0ZW5kcyBjbG91ZHdhdGNoLkFsYXJtIHtcbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IExhbWJkYVRocm90dGxlc0FsYXJtUHJvcHMpIHtcbiAgICBjb25zdCBhbGFybU5hbWUgPSBwcm9wcy5hbGFybU5hbWUgPz8gYCR7cHJvcHMubGFtYmRhRnVuY3Rpb24uZnVuY3Rpb25OYW1lfSAtICR7TGFtYmRhUmVjb21tZW5kZWRBbGFybXNNZXRyaWNzLlRIUk9UVExFU31gO1xuICAgIGNvbnN0IHBlcmlvZCA9IHByb3BzLnBlcmlvZCA/PyBEdXJhdGlvbi5taW51dGVzKDEpO1xuICAgIGNvbnN0IGV2YWx1YXRpb25QZXJpb2RzID0gcHJvcHMuZXZhbHVhdGlvblBlcmlvZHMgPz8gNTtcblxuICAgIHZhbGlkYXRlVG90YWxBbGFybVBlcmlvZChwZXJpb2QsIGV2YWx1YXRpb25QZXJpb2RzLCBhbGFybU5hbWUpO1xuXG4gICAgc3VwZXIoc2NvcGUsIGlkLCB7XG4gICAgICBhbGFybU5hbWUsXG4gICAgICBtZXRyaWM6IHByb3BzLmxhbWJkYUZ1bmN0aW9uLm1ldHJpY1Rocm90dGxlcyh7XG4gICAgICAgIHBlcmlvZCxcbiAgICAgIH0pLFxuICAgICAgdGhyZXNob2xkOiBwcm9wcy50aHJlc2hvbGQsXG4gICAgICBldmFsdWF0aW9uUGVyaW9kcyxcbiAgICAgIGRhdGFwb2ludHNUb0FsYXJtOiBwcm9wcy5kYXRhcG9pbnRzVG9BbGFybSA/PyA1LFxuICAgICAgdHJlYXRNaXNzaW5nRGF0YTogcHJvcHMudHJlYXRNaXNzaW5nRGF0YSxcbiAgICAgIGNvbXBhcmlzb25PcGVyYXRvcjogY2xvdWR3YXRjaC5Db21wYXJpc29uT3BlcmF0b3IuR1JFQVRFUl9USEFOX1RIUkVTSE9MRCxcbiAgICAgIGFsYXJtRGVzY3JpcHRpb246IHByb3BzLmFsYXJtRGVzY3JpcHRpb24gPz8gJ1RoaXMgYWxhcm0gZGV0ZWN0cyBhIGhpZ2ggbnVtYmVyIG9mIHRocm90dGxlZCBpbnZvY2F0aW9uIHJlcXVlc3RzLiAnXG4gICAgICAgICsgJ1Rocm90dGxpbmcgb2NjdXJzIHdoZW4gdGhlcmUgaXMgbm8gY29uY3VycmVuY3kgaXMgYXZhaWxhYmxlIGZvciBzY2FsZSB1cC4gVGhlcmUgYXJlIHNldmVyYWwgYXBwcm9hY2hlcyB0byAnXG4gICAgICAgICsgJ3Jlc29sdmUgdGhpcyBpc3N1ZS4gMSkgUmVxdWVzdCBhIGNvbmN1cnJlbmN5IGluY3JlYXNlIGZyb20gQVdTIFN1cHBvcnQgaW4gdGhpcyBSZWdpb24uIDIpIElkZW50aWZ5IHBlcmZvcm1hbmNlICdcbiAgICAgICAgKyAnaXNzdWVzIGluIHRoZSBmdW5jdGlvbiB0byBpbXByb3ZlIHRoZSBzcGVlZCBvZiBwcm9jZXNzaW5nIGFuZCB0aGVyZWZvcmUgaW1wcm92ZSB0aHJvdWdocHV0LiAzKSBJbmNyZWFzZSB0aGUgYmF0Y2ggJ1xuICAgICAgICArICdzaXplIG9mIHRoZSBmdW5jdGlvbiwgc28gdGhhdCBtb3JlIG1lc3NhZ2VzIGFyZSBwcm9jZXNzZWQgYnkgZWFjaCBmdW5jdGlvbiBpbnZvY2F0aW9uLicsXG4gICAgfSk7XG5cbiAgICBpZiAocHJvcHMuYWxhcm1BY3Rpb24pIHRoaXMuYWRkQWxhcm1BY3Rpb24ocHJvcHMuYWxhcm1BY3Rpb24pO1xuICAgIGlmIChwcm9wcy5va0FjdGlvbikgdGhpcy5hZGRPa0FjdGlvbihwcm9wcy5va0FjdGlvbik7XG4gICAgaWYgKHByb3BzLmluc3VmZmljaWVudERhdGFBY3Rpb24pIHRoaXMuYWRkSW5zdWZmaWNpZW50RGF0YUFjdGlvbihwcm9wcy5pbnN1ZmZpY2llbnREYXRhQWN0aW9uKTtcbiAgfVxufVxuXG4vKipcbiAqIENvbmZpZ3VyYXRpb24gZm9yIHRoZSBEdXJhdGlvbiBhbGFybS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBMYW1iZGFEdXJhdGlvbkFsYXJtQ29uZmlnIGV4dGVuZHMgTGFtYmRhQWxhcm1CYXNlQ29uZmlnIHtcbiAgLyoqXG4gICAqIFRoZSB2YWx1ZSBhZ2FpbnN0IHdoaWNoIHRoZSBzcGVjaWZpZWQgc3RhdGljdGlzIGlzIGNvbXBhcmVkLlxuICAgKlxuICAgKiBUaGUgdGhyZXNob2xkIGZvciB0aGUgZHVyYXRpb24gZGVwZW5kcyBvbiB5b3VyIGFwcGxpY2F0aW9uXG4gICAqIGFuZCB3b3JrbG9hZHMgYW5kIHlvdXIgcGVyZm9ybWFuY2UgcmVxdWlyZW1lbnRzLiBGb3JcbiAgICogaGlnaC1wZXJmb3JtYW5jZSByZXF1aXJlbWVudHMsIHNldCB0aGUgdGhyZXNob2xkIHRvIGFcbiAgICogc2hvcnRlciB0aW1lIHRvIHNlZSBpZiB0aGUgZnVuY3Rpb24gaXMgbWVldGluZyBleHBlY3RhdGlvbnMuXG4gICAqIFlvdSBjYW4gYWxzbyBhbmFseXplIGhpc3RvcmljYWwgZGF0YSBmb3IgZHVyYXRpb24gbWV0cmljc1xuICAgKiB0byBzZWUgdGhlIGlmIHRoZSB0aW1lIHRha2VuIG1hdGNoZXMgdGhlIHBlcmZvcm1hbmNlXG4gICAqIGV4cGVjdGF0aW9uIG9mIHRoZSBmdW5jdGlvbiwgYW5kIHRoZW4gc2V0IHRoZSB0aHJlc2hvbGQgdG9cbiAgICogYSBsb25nZXIgdGltZSB0aGFuIHRoZSBoaXN0b3JpY2FsIGF2ZXJhZ2UuIE1ha2Ugc3VyZSB0b1xuICAgKiBzZXQgdGhlIHRocmVzaG9sZCBsb3dlciB0aGFuIHRoZSBjb25maWd1cmVkIGZ1bmN0aW9uXG4gICAqIHRpbWVvdXQuXG4gICAqL1xuICByZWFkb25seSB0aHJlc2hvbGQ6IG51bWJlcjtcbiAgLyoqXG4gICAqIFRoZSBudW1iZXIgb2YgcGVyaW9kcyBvdmVyIHdoaWNoIGRhdGEgaXMgY29tcGFyZWQgdG8gdGhlIHNwZWNpZmllZCB0aHJlc2hvbGQuXG4gICAqXG4gICAqIEBkZWZhdWx0IDE1XG4gICAqL1xuICByZWFkb25seSBldmFsdWF0aW9uUGVyaW9kcz86IG51bWJlcjtcbiAgLyoqXG4gICAqIFRoZSBudW1iZXIgb2YgZGF0YSBwb2ludHMgdGhhdCBtdXN0IGJlIGJyZWFjaGluZyB0byB0cmlnZ2VyIHRoZSBhbGFybS5cbiAgICpcbiAgICogQGRlZmF1bHQgMTVcbiAgICovXG4gIHJlYWRvbmx5IGRhdGFwb2ludHNUb0FsYXJtPzogbnVtYmVyO1xuICAvKipcbiAgICogVGhlIGFsYXJtIG5hbWUuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gbGFtYmRhRnVuY3Rpb24uZnVuY3Rpb25OYW1lICsgJyAtIER1cmF0aW9uJ1xuICAgKi9cbiAgcmVhZG9ubHkgYWxhcm1OYW1lPzogc3RyaW5nO1xuICAvKipcbiAgICogVGhlIGRlc2NyaXB0aW9uIG9mIHRoZSBhbGFybS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSAgVGhpcyBhbGFybSBkZXRlY3RzIGxvbmcgZHVyYXRpb24gdGltZXMgZm9yIHByb2Nlc3NpbmcgYW4gZXZlbnQgYnkgYSBMYW1iZGEgZnVuY3Rpb24uIExvbmcgZHVyYXRpb25zIG1pZ2h0IGJlIGJlY2F1c2Ugb2YgY2hhbmdlcyBpbiBmdW5jdGlvbiBjb2RlIG1ha2luZyB0aGUgZnVuY3Rpb24gdGFrZSBsb25nZXIgdG8gZXhlY3V0ZSwgb3IgdGhlIGZ1bmN0aW9uJ3MgZGVwZW5kZW5jaWVzIHRha2luZyBsb25nZXIuXG4gICAqL1xuICByZWFkb25seSBhbGFybURlc2NyaXB0aW9uPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIFRoZSBwcm9wZXJ0aWVzIGZvciB0aGUgTGFtYmRhRHVyYXRpb25BbGFybSBjb25zdHJ1Y3QuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTGFtYmRhRHVyYXRpb25BbGFybVByb3BzIGV4dGVuZHMgTGFtYmRhRHVyYXRpb25BbGFybUNvbmZpZyB7XG4gIC8qKlxuICAgKiBUaGUgTGFtYmRhIGZ1bmN0aW9uIHRvIG1vbml0b3IuXG4gICAqL1xuICByZWFkb25seSBsYW1iZGFGdW5jdGlvbjogbGFtYmRhLklGdW5jdGlvbjtcbn1cblxuLyoqXG4gKiBUaGlzIGFsYXJtIGNhbiBkZXRlY3QgYSBsb25nIHJ1bm5pbmcgZHVyYXRpb24gb2YgYVxuICogTGFtYmRhIGZ1bmN0aW9uLiBIaWdoIHJ1bnRpbWUgZHVyYXRpb24gaW5kaWNhdGVzIHRoYXRcbiAqIGEgZnVuY3Rpb24gaXMgdGFraW5nIGEgbG9uZ2VyIHRpbWUgZm9yIGludm9jYXRpb24sIGFuZFxuICogY2FuIGFsc28gaW1wYWN0IHRoZSBjb25jdXJyZW5jeSBjYXBhY2l0eSBvZiBpbnZvY2F0aW9uXG4gKiBpZiBMYW1iZGEgaXMgaGFuZGxpbmcgYSBoaWdoZXIgbnVtYmVyIG9mIGV2ZW50cy4gSXQgaXNcbiAqIGNyaXRpY2FsIHRvIGtub3cgaWYgdGhlIExhbWJkYSBmdW5jdGlvbiBpcyBjb25zdGFudGx5XG4gKiB0YWtpbmcgbG9uZ2VyIGV4ZWN1dGlvbiB0aW1lIHRoYW4gZXhwZWN0ZWQuXG4gKlxuICogVGhlIGFsYXJtIGlzIHRyaWdnZXJlZCB3aGVuIHRoZSBkdXJhdGlvbiBvZiB0aGUgZnVuY3Rpb25cbiAqIGludm9jYXRpb25zIGV4Y2VlZHMgdGhlIHNwZWNpZmllZCB0aHJlc2hvbGQuXG4gKi9cbmV4cG9ydCBjbGFzcyBMYW1iZGFEdXJhdGlvbkFsYXJtIGV4dGVuZHMgY2xvdWR3YXRjaC5BbGFybSB7XG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBMYW1iZGFEdXJhdGlvbkFsYXJtUHJvcHMpIHtcbiAgICBjb25zdCBhbGFybU5hbWUgPSBwcm9wcy5hbGFybU5hbWUgPz8gYCR7cHJvcHMubGFtYmRhRnVuY3Rpb24uZnVuY3Rpb25OYW1lfSAtICR7TGFtYmRhUmVjb21tZW5kZWRBbGFybXNNZXRyaWNzLkRVUkFUSU9OfWA7XG4gICAgY29uc3QgcGVyaW9kID0gcHJvcHMucGVyaW9kID8/IER1cmF0aW9uLm1pbnV0ZXMoMSk7XG4gICAgY29uc3QgZXZhbHVhdGlvblBlcmlvZHMgPSBwcm9wcy5ldmFsdWF0aW9uUGVyaW9kcyA/PyAxNTtcblxuICAgIHZhbGlkYXRlVG90YWxBbGFybVBlcmlvZChwZXJpb2QsIGV2YWx1YXRpb25QZXJpb2RzLCBhbGFybU5hbWUpO1xuXG4gICAgc3VwZXIoc2NvcGUsIGlkLCB7XG4gICAgICBhbGFybU5hbWUsXG4gICAgICBtZXRyaWM6IHByb3BzLmxhbWJkYUZ1bmN0aW9uLm1ldHJpY0R1cmF0aW9uKHtcbiAgICAgICAgcGVyaW9kLFxuICAgICAgfSksXG4gICAgICB0aHJlc2hvbGQ6IHByb3BzLnRocmVzaG9sZCxcbiAgICAgIGV2YWx1YXRpb25QZXJpb2RzLFxuICAgICAgZGF0YXBvaW50c1RvQWxhcm06IHByb3BzLmRhdGFwb2ludHNUb0FsYXJtID8/IDE1LFxuICAgICAgdHJlYXRNaXNzaW5nRGF0YTogcHJvcHMudHJlYXRNaXNzaW5nRGF0YSxcbiAgICAgIGNvbXBhcmlzb25PcGVyYXRvcjogY2xvdWR3YXRjaC5Db21wYXJpc29uT3BlcmF0b3IuR1JFQVRFUl9USEFOX1RIUkVTSE9MRCxcbiAgICAgIGFsYXJtRGVzY3JpcHRpb246IHByb3BzLmFsYXJtRGVzY3JpcHRpb24gPz8gJ1RoaXMgYWxhcm0gZGV0ZWN0cyBsb25nIGR1cmF0aW9uIHRpbWVzIGZvciBwcm9jZXNzaW5nIGFuIGV2ZW50IGJ5IGEgJ1xuICAgICAgKyAnTGFtYmRhIGZ1bmN0aW9uLiBMb25nIGR1cmF0aW9ucyBtaWdodCBiZSBiZWNhdXNlIG9mIGNoYW5nZXMgaW4gZnVuY3Rpb24gY29kZSBtYWtpbmcgdGhlIGZ1bmN0aW9uIHRha2UgbG9uZ2VyIHRvICdcbiAgICAgICsgJ2V4ZWN1dGUsIG9yIHRoZSBmdW5jdGlvblxcJ3MgZGVwZW5kZW5jaWVzIHRha2luZyBsb25nZXIuJyxcbiAgICB9KTtcblxuICAgIGlmIChwcm9wcy5hbGFybUFjdGlvbikgdGhpcy5hZGRBbGFybUFjdGlvbihwcm9wcy5hbGFybUFjdGlvbik7XG4gICAgaWYgKHByb3BzLm9rQWN0aW9uKSB0aGlzLmFkZE9rQWN0aW9uKHByb3BzLm9rQWN0aW9uKTtcbiAgICBpZiAocHJvcHMuaW5zdWZmaWNpZW50RGF0YUFjdGlvbikgdGhpcy5hZGRJbnN1ZmZpY2llbnREYXRhQWN0aW9uKHByb3BzLmluc3VmZmljaWVudERhdGFBY3Rpb24pO1xuICB9XG59XG5cbi8qKlxuICogQ29uZmlndXJhdGlvbiBmb3IgdGhlIENvbmN1cnJlbnRFeGVjdXRpb25zIGFsYXJtLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIExhbWJkYUNvbmN1cnJlbnRFeGVjdXRpb25zQWxhcm1Db25maWcgZXh0ZW5kcyBMYW1iZGFBbGFybUJhc2VDb25maWcge1xuICAvKipcbiAgICogVGhlIHZhbHVlIGFnYWluc3Qgd2hpY2ggdGhlIHNwZWNpZmllZCBzdGF0aWN0aXMgaXMgY29tcGFyZWQuXG4gICAqXG4gICAqIFNldCB0aGUgdGhyZXNob2xkIHRvIGFib3V0IDkwJSBvZiB0aGUgY29uY3VycmVuY3kgcXVvdGEgc2V0XG4gICAqIGZvciB0aGUgYWNjb3VudCBpbiB0aGUgUmVnaW9uLiBCeSBkZWZhdWx0LCB5b3VyIGFjY291bnQgaGFzXG4gICAqIGEgY29uY3VycmVuY3kgcXVvdGEgb2YgMSwwMDAgYWNyb3NzIGFsbCBmdW5jdGlvbnMgaW4gYSBSZWdpb24uXG4gICAqIEhvd2V2ZXIsIHlvdSBjYW4gY2hlY2sgdGhlIHF1b3RhIG9mIHlvdXIgYWNjb3VudCwgYXMgaXQgY2FuXG4gICAqIGJlIGluY3JlYXNlZCBieSBjb250YWN0aW5nIEFXUyBzdXBwb3J0LlxuICAgKlxuICAgKiBAZGVmYXVsdCA5MDBcbiAgICovXG4gIHJlYWRvbmx5IHRocmVzaG9sZD86IG51bWJlcjtcbiAgLyoqXG4gICAqIFRoZSBudW1iZXIgb2YgcGVyaW9kcyBvdmVyIHdoaWNoIGRhdGEgaXMgY29tcGFyZWQgdG8gdGhlIHNwZWNpZmllZCB0aHJlc2hvbGQuXG4gICAqXG4gICAqIEBkZWZhdWx0IDEwXG4gICAqL1xuICByZWFkb25seSBldmFsdWF0aW9uUGVyaW9kcz86IG51bWJlcjtcbiAgLyoqXG4gICAqIFRoZSBudW1iZXIgb2YgZGF0YSBwb2ludHMgdGhhdCBtdXN0IGJlIGJyZWFjaGluZyB0byB0cmlnZ2VyIHRoZSBhbGFybS5cbiAgICpcbiAgICogQGRlZmF1bHQgMTBcbiAgICovXG4gIHJlYWRvbmx5IGRhdGFwb2ludHNUb0FsYXJtPzogbnVtYmVyO1xuICAvKipcbiAgICogVGhlIGFsYXJtIG5hbWUuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gbGFtYmRhRnVuY3Rpb24uZnVuY3Rpb25OYW1lICsgJyAtIENvbmN1cnJlbnRFeGVjdXRpb25zJ1xuICAgKi9cbiAgcmVhZG9ubHkgYWxhcm1OYW1lPzogc3RyaW5nO1xuICAvKipcbiAgICogVGhlIGRlc2NyaXB0aW9uIG9mIHRoZSBhbGFybS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSAgVGhpcyBhbGFybSBoZWxwcyB0byBtb25pdG9yIGlmIHRoZSBjb25jdXJyZW5jeSBvZiB0aGUgZnVuY3Rpb24gaXMgYXBwcm9hY2hpbmcgdGhlIFJlZ2lvbi1sZXZlbFxuICAgKiBjb25jdXJyZW5jeSBsaW1pdCBvZiB5b3VyIGFjY291bnQuIEEgZnVuY3Rpb24gc3RhcnRzIHRvIGJlIHRocm90dGxlZCBpZiBpdCByZWFjaGVzIHRoZSBjb25jdXJyZW5jeSBsaW1pdC5cbiAgICovXG4gIHJlYWRvbmx5IGFsYXJtRGVzY3JpcHRpb24/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogVGhlIHByb3BlcnRpZXMgZm9yIHRoZSBMYW1iZGFDb25jdXJyZW50RXhlY3V0aW9uc0FsYXJtIGNvbnN0cnVjdC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBMYW1iZGFDb25jdXJyZW50RXhlY3V0aW9uc0FsYXJtUHJvcHMgZXh0ZW5kcyBMYW1iZGFDb25jdXJyZW50RXhlY3V0aW9uc0FsYXJtQ29uZmlnIHtcbiAgLyoqXG4gICAqIFRoZSBMYW1iZGEgZnVuY3Rpb24gdG8gbW9uaXRvci5cbiAgICovXG4gIHJlYWRvbmx5IGxhbWJkYUZ1bmN0aW9uOiBsYW1iZGEuSUZ1bmN0aW9uO1xufVxuXG4vKipcbiAqIFRoaXMgYWxhcm0gY2FuIHByb2FjdGl2ZWx5IGRldGVjdCBpZiB0aGUgY29uY3VycmVuY3kgb2YgdGhlXG4gKiBmdW5jdGlvbiBpcyBhcHByb2FjaGluZyB0aGUgUmVnaW9uLWxldmVsIGNvbmN1cnJlbmN5IHF1b3RhXG4gKiBvZiB5b3VyIGFjY291bnQsIHNvIHRoYXQgeW91IGNhbiBhY3Qgb24gaXQuIEEgZnVuY3Rpb24gaXNcbiAqIHRocm90dGxlZCBpZiBpdCByZWFjaGVzIHRoZSBSZWdpb24tbGV2ZWwgY29uY3VycmVuY3kgcXVvdGFcbiAqIG9mIHRoZSBhY2NvdW50LlxuICpcbiAqIFRoZSBhbGFybSBpcyB0cmlnZ2VyZWQgd2hlbiB0aGUgbnVtYmVyIG9mIGNvbmN1cnJlbnQgZXhlY3V0aW9uc1xuICogZXhjZWVkcyB0aGUgc3BlY2lmaWVkIHRocmVzaG9sZC5cbiAqL1xuZXhwb3J0IGNsYXNzIExhbWJkYUNvbmN1cnJlbnRFeGVjdXRpb25zQWxhcm0gZXh0ZW5kcyBjbG91ZHdhdGNoLkFsYXJtIHtcbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IExhbWJkYUNvbmN1cnJlbnRFeGVjdXRpb25zQWxhcm1Qcm9wcykge1xuICAgIGNvbnN0IGFsYXJtTmFtZSA9IHByb3BzLmFsYXJtTmFtZSA/PyBgJHtwcm9wcy5sYW1iZGFGdW5jdGlvbi5mdW5jdGlvbk5hbWV9IC0gJHtMYW1iZGFSZWNvbW1lbmRlZEFsYXJtc01ldHJpY3MuQ09OQ1VSUkVOVF9FWEVDVVRJT05TfWA7XG4gICAgY29uc3QgcGVyaW9kID0gcHJvcHMucGVyaW9kID8/IER1cmF0aW9uLm1pbnV0ZXMoMSk7XG4gICAgY29uc3QgZXZhbHVhdGlvblBlcmlvZHMgPSBwcm9wcy5ldmFsdWF0aW9uUGVyaW9kcyA/PyAxMDtcblxuICAgIHZhbGlkYXRlVG90YWxBbGFybVBlcmlvZChwZXJpb2QsIGV2YWx1YXRpb25QZXJpb2RzLCBhbGFybU5hbWUpO1xuXG4gICAgc3VwZXIoc2NvcGUsIGlkLCB7XG4gICAgICBhbGFybU5hbWUsXG4gICAgICBtZXRyaWM6IG5ldyBjbG91ZHdhdGNoLk1ldHJpYyh7XG4gICAgICAgIG5hbWVzcGFjZTogJ0FXUy9MYW1iZGEnLFxuICAgICAgICBtZXRyaWNOYW1lOiBMYW1iZGFSZWNvbW1lbmRlZEFsYXJtc01ldHJpY3MuQ09OQ1VSUkVOVF9FWEVDVVRJT05TLFxuICAgICAgICBkaW1lbnNpb25zTWFwOiB7XG4gICAgICAgICAgRnVuY3Rpb25OYW1lOiBwcm9wcy5sYW1iZGFGdW5jdGlvbi5mdW5jdGlvbk5hbWUsXG4gICAgICAgIH0sXG4gICAgICAgIHBlcmlvZCxcbiAgICAgICAgc3RhdGlzdGljOiAnTWF4aW11bScsXG4gICAgICB9KSxcbiAgICAgIHRocmVzaG9sZDogcHJvcHMudGhyZXNob2xkID8/IDkwMCxcbiAgICAgIGV2YWx1YXRpb25QZXJpb2RzLFxuICAgICAgZGF0YXBvaW50c1RvQWxhcm06IHByb3BzLmRhdGFwb2ludHNUb0FsYXJtID8/IDEwLFxuICAgICAgdHJlYXRNaXNzaW5nRGF0YTogcHJvcHMudHJlYXRNaXNzaW5nRGF0YSxcbiAgICAgIGNvbXBhcmlzb25PcGVyYXRvcjogY2xvdWR3YXRjaC5Db21wYXJpc29uT3BlcmF0b3IuR1JFQVRFUl9USEFOX1RIUkVTSE9MRCxcbiAgICA