UNPKG

@aws-cdk/aws-cloudwatch

Version:

The CDK Construct Library for AWS::CloudWatch

542 lines 78 kB
"use strict"; var _a, _b; Object.defineProperty(exports, "__esModule", { value: true }); exports.MathExpression = exports.Metric = void 0; const jsiiDeprecationWarnings = require("../.warnings.jsii.js"); const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); const iam = require("@aws-cdk/aws-iam"); const cdk = require("@aws-cdk/core"); const alarm_1 = require("./alarm"); const metric_util_1 = require("./private/metric-util"); const statistic_1 = require("./private/statistic"); /** * A metric emitted by a service * * The metric is a combination of a metric identifier (namespace, name and dimensions) * and an aggregation function (statistic, period and unit). * * It also contains metadata which is used only in graphs, such as color and label. * It makes sense to embed this in here, so that compound constructs can attach * that metadata to metrics they expose. * * This class does not represent a resource, so hence is not a construct. Instead, * Metric is an abstraction that makes it easy to specify metrics for use in both * alarms and graphs. */ class Metric { constructor(props) { try { jsiiDeprecationWarnings._aws_cdk_aws_cloudwatch_MetricProps(props); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, Metric); } throw error; } this.period = props.period || cdk.Duration.minutes(5); const periodSec = this.period.toSeconds(); if (periodSec !== 1 && periodSec !== 5 && periodSec !== 10 && periodSec !== 30 && periodSec % 60 !== 0) { throw new Error(`'period' must be 1, 5, 10, 30, or a multiple of 60 seconds, received ${periodSec}`); } this.dimensions = this.validateDimensions(props.dimensionsMap ?? props.dimensions); this.namespace = props.namespace; this.metricName = props.metricName; // Try parsing, this will throw if it's not a valid stat this.statistic = statistic_1.normalizeStatistic(props.statistic || 'Average'); this.label = props.label; this.color = props.color; this.unit = props.unit; this.account = props.account; this.region = props.region; this.warnings = undefined; } /** * Grant permissions to the given identity to write metrics. * * @param grantee The IAM identity to give permissions to. */ static grantPutMetricData(grantee) { return iam.Grant.addToPrincipal({ grantee, actions: ['cloudwatch:PutMetricData'], resourceArns: ['*'], }); } /** * Return a copy of Metric `with` properties changed. * * All properties except namespace and metricName can be changed. * * @param props The set of properties to change. */ with(props) { try { jsiiDeprecationWarnings._aws_cdk_aws_cloudwatch_MetricOptions(props); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, this.with); } throw error; } // Short-circuit creating a new object if there would be no effective change if ((props.label === undefined || props.label === this.label) && (props.color === undefined || props.color === this.color) && (props.statistic === undefined || props.statistic === this.statistic) && (props.unit === undefined || props.unit === this.unit) && (props.account === undefined || props.account === this.account) && (props.region === undefined || props.region === this.region) // For these we're not going to do deep equality, misses some opportunity for optimization // but that's okay. && (props.dimensions === undefined) && (props.dimensionsMap === undefined) && (props.period === undefined || props.period.toSeconds() === this.period.toSeconds())) { return this; } return new Metric({ dimensionsMap: props.dimensionsMap ?? props.dimensions ?? this.dimensions, namespace: this.namespace, metricName: this.metricName, period: ifUndefined(props.period, this.period), statistic: ifUndefined(props.statistic, this.statistic), unit: ifUndefined(props.unit, this.unit), label: ifUndefined(props.label, this.label), color: ifUndefined(props.color, this.color), account: ifUndefined(props.account, this.account), region: ifUndefined(props.region, this.region), }); } /** * Attach the metric object to the given construct scope * * Returns a Metric object that uses the account and region from the Stack * the given construct is defined in. If the metric is subsequently used * in a Dashboard or Alarm in a different Stack defined in a different * account or region, the appropriate 'region' and 'account' fields * will be added to it. * * If the scope we attach to is in an environment-agnostic stack, * nothing is done and the same Metric object is returned. */ attachTo(scope) { const stack = cdk.Stack.of(scope); return this.with({ region: cdk.Token.isUnresolved(stack.region) ? undefined : stack.region, account: cdk.Token.isUnresolved(stack.account) ? undefined : stack.account, }); } toMetricConfig() { const dims = this.dimensionsAsList(); return { metricStat: { dimensions: dims.length > 0 ? dims : undefined, namespace: this.namespace, metricName: this.metricName, period: this.period, statistic: this.statistic, unitFilter: this.unit, account: this.account, region: this.region, }, renderingProperties: { color: this.color, label: this.label, }, }; } /** @deprecated use toMetricConfig() */ toAlarmConfig() { try { jsiiDeprecationWarnings.print("@aws-cdk/aws-cloudwatch.Metric#toAlarmConfig", "use toMetricConfig()"); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, this.toAlarmConfig); } throw error; } const metricConfig = this.toMetricConfig(); if (metricConfig.metricStat === undefined) { throw new Error('Using a math expression is not supported here. Pass a \'Metric\' object instead'); } const stat = statistic_1.parseStatistic(metricConfig.metricStat.statistic); return { dimensions: metricConfig.metricStat.dimensions, namespace: metricConfig.metricStat.namespace, metricName: metricConfig.metricStat.metricName, period: metricConfig.metricStat.period.toSeconds(), statistic: stat.type === 'simple' ? stat.statistic : undefined, extendedStatistic: stat.type === 'percentile' ? 'p' + stat.percentile : undefined, unit: this.unit, }; } /** * @deprecated use toMetricConfig() */ toGraphConfig() { try { jsiiDeprecationWarnings.print("@aws-cdk/aws-cloudwatch.Metric#toGraphConfig", "use toMetricConfig()"); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, this.toGraphConfig); } throw error; } const metricConfig = this.toMetricConfig(); if (metricConfig.metricStat === undefined) { throw new Error('Using a math expression is not supported here. Pass a \'Metric\' object instead'); } return { dimensions: metricConfig.metricStat.dimensions, namespace: metricConfig.metricStat.namespace, metricName: metricConfig.metricStat.metricName, renderingProperties: { period: metricConfig.metricStat.period.toSeconds(), stat: metricConfig.metricStat.statistic, color: asString(metricConfig.renderingProperties?.color), label: asString(metricConfig.renderingProperties?.label), }, // deprecated properties for backwards compatibility period: metricConfig.metricStat.period.toSeconds(), statistic: metricConfig.metricStat.statistic, color: asString(metricConfig.renderingProperties?.color), label: asString(metricConfig.renderingProperties?.label), unit: this.unit, }; } /** * Make a new Alarm for this metric * * Combines both properties that may adjust the metric (aggregation) as well * as alarm properties. */ createAlarm(scope, id, props) { try { jsiiDeprecationWarnings._aws_cdk_aws_cloudwatch_CreateAlarmOptions(props); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, this.createAlarm); } throw error; } return new alarm_1.Alarm(scope, id, { metric: this.with({ statistic: props.statistic, period: props.period, }), alarmName: props.alarmName, alarmDescription: props.alarmDescription, comparisonOperator: props.comparisonOperator, datapointsToAlarm: props.datapointsToAlarm, threshold: props.threshold, evaluationPeriods: props.evaluationPeriods, evaluateLowSampleCountPercentile: props.evaluateLowSampleCountPercentile, treatMissingData: props.treatMissingData, actionsEnabled: props.actionsEnabled, }); } toString() { return this.label || this.metricName; } /** * Return the dimensions of this Metric as a list of Dimension. */ dimensionsAsList() { const dims = this.dimensions; if (dims === undefined) { return []; } const list = Object.keys(dims).sort().map(key => ({ name: key, value: dims[key] })); return list; } validateDimensions(dims) { if (!dims) { return dims; } var dimsArray = Object.keys(dims); if (dimsArray?.length > 10) { throw new Error(`The maximum number of dimensions is 10, received ${dimsArray.length}`); } dimsArray.map(key => { if (dims[key] === undefined || dims[key] === null) { throw new Error(`Dimension value of '${dims[key]}' is invalid`); } ; if (key.length < 1 || key.length > 255) { throw new Error(`Dimension name must be at least 1 and no more than 255 characters; received ${key}`); } ; if (dims[key].length < 1 || dims[key].length > 255) { throw new Error(`Dimension value must be at least 1 and no more than 255 characters; received ${dims[key]}`); } ; }); return dims; } } exports.Metric = Metric; _a = JSII_RTTI_SYMBOL_1; Metric[_a] = { fqn: "@aws-cdk/aws-cloudwatch.Metric", version: "1.198.0" }; function asString(x) { if (x === undefined) { return undefined; } if (typeof x !== 'string') { throw new Error(`Expected string, got ${x}`); } return x; } /** * A math expression built with metric(s) emitted by a service * * The math expression is a combination of an expression (x+y) and metrics to apply expression on. * It also contains metadata which is used only in graphs, such as color and label. * It makes sense to embed this in here, so that compound constructs can attach * that metadata to metrics they expose. * * MathExpression can also be used for search expressions. In this case, * it also optionally accepts a searchRegion and searchAccount property for cross-environment * search expressions. * * This class does not represent a resource, so hence is not a construct. Instead, * MathExpression is an abstraction that makes it easy to specify metrics for use in both * alarms and graphs. */ class MathExpression { constructor(props) { try { jsiiDeprecationWarnings._aws_cdk_aws_cloudwatch_MathExpressionProps(props); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, MathExpression); } throw error; } this.period = props.period || cdk.Duration.minutes(5); this.expression = props.expression; this.usingMetrics = changeAllPeriods(props.usingMetrics ?? {}, this.period); this.label = props.label; this.color = props.color; this.searchAccount = props.searchAccount; this.searchRegion = props.searchRegion; const invalidVariableNames = Object.keys(this.usingMetrics).filter(x => !validVariableName(x)); if (invalidVariableNames.length > 0) { throw new Error(`Invalid variable names in expression: ${invalidVariableNames}. Must start with lowercase letter and only contain alphanumerics.`); } this.validateNoIdConflicts(); // Check that all IDs used in the expression are also in the `usingMetrics` map. We // can't throw on this anymore since we didn't use to do this validation from the start // and now there will be loads of people who are violating the expected contract, but // we can add warnings. const missingIdentifiers = allIdentifiersInExpression(this.expression).filter(i => !this.usingMetrics[i]); const warnings = []; if (missingIdentifiers.length > 0) { warnings.push(`Math expression '${this.expression}' references unknown identifiers: ${missingIdentifiers.join(', ')}. Please add them to the 'usingMetrics' map.`); } // Also copy warnings from deeper levels so graphs, alarms only have to inspect the top-level objects for (const m of Object.values(this.usingMetrics)) { warnings.push(...m.warnings ?? []); } if (warnings.length > 0) { this.warnings = warnings; } } /** * Return a copy of Metric with properties changed. * * All properties except namespace and metricName can be changed. * * @param props The set of properties to change. */ with(props) { try { jsiiDeprecationWarnings._aws_cdk_aws_cloudwatch_MathExpressionOptions(props); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, this.with); } throw error; } // Short-circuit creating a new object if there would be no effective change if ((props.label === undefined || props.label === this.label) && (props.color === undefined || props.color === this.color) && (props.period === undefined || props.period.toSeconds() === this.period.toSeconds()) && (props.searchAccount === undefined || props.searchAccount === this.searchAccount) && (props.searchRegion === undefined || props.searchRegion === this.searchRegion)) { return this; } return new MathExpression({ expression: this.expression, usingMetrics: this.usingMetrics, label: ifUndefined(props.label, this.label), color: ifUndefined(props.color, this.color), period: ifUndefined(props.period, this.period), searchAccount: ifUndefined(props.searchAccount, this.searchAccount), searchRegion: ifUndefined(props.searchRegion, this.searchRegion), }); } /** * @deprecated use toMetricConfig() */ toAlarmConfig() { try { jsiiDeprecationWarnings.print("@aws-cdk/aws-cloudwatch.MathExpression#toAlarmConfig", "use toMetricConfig()"); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, this.toAlarmConfig); } throw error; } throw new Error('Using a math expression is not supported here. Pass a \'Metric\' object instead'); } /** * @deprecated use toMetricConfig() */ toGraphConfig() { try { jsiiDeprecationWarnings.print("@aws-cdk/aws-cloudwatch.MathExpression#toGraphConfig", "use toMetricConfig()"); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, this.toGraphConfig); } throw error; } throw new Error('Using a math expression is not supported here. Pass a \'Metric\' object instead'); } toMetricConfig() { return { mathExpression: { period: this.period.toSeconds(), expression: this.expression, usingMetrics: this.usingMetrics, searchAccount: this.searchAccount, searchRegion: this.searchRegion, }, renderingProperties: { label: this.label, color: this.color, }, }; } /** * Make a new Alarm for this metric * * Combines both properties that may adjust the metric (aggregation) as well * as alarm properties. */ createAlarm(scope, id, props) { try { jsiiDeprecationWarnings._aws_cdk_aws_cloudwatch_CreateAlarmOptions(props); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, this.createAlarm); } throw error; } return new alarm_1.Alarm(scope, id, { metric: this.with({ period: props.period, }), alarmName: props.alarmName, alarmDescription: props.alarmDescription, comparisonOperator: props.comparisonOperator, datapointsToAlarm: props.datapointsToAlarm, threshold: props.threshold, evaluationPeriods: props.evaluationPeriods, evaluateLowSampleCountPercentile: props.evaluateLowSampleCountPercentile, treatMissingData: props.treatMissingData, actionsEnabled: props.actionsEnabled, }); } toString() { return this.label || this.expression; } validateNoIdConflicts() { const seen = new Map(); visit(this); function visit(metric) { metric_util_1.dispatchMetric(metric, { withStat() { // Nothing }, withExpression(expr) { for (const [id, subMetric] of Object.entries(expr.usingMetrics)) { const existing = seen.get(id); if (existing && metric_util_1.metricKey(existing) !== metric_util_1.metricKey(subMetric)) { throw new Error(`The ID '${id}' used for two metrics in the expression: '${subMetric}' and '${existing}'. Rename one.`); } seen.set(id, subMetric); visit(subMetric); } }, }); } } } exports.MathExpression = MathExpression; _b = JSII_RTTI_SYMBOL_1; MathExpression[_b] = { fqn: "@aws-cdk/aws-cloudwatch.MathExpression", version: "1.198.0" }; /** * Pattern for a variable name. Alphanum starting with lowercase. */ const VARIABLE_PAT = '[a-z][a-zA-Z0-9_]*'; const VALID_VARIABLE = new RegExp(`^${VARIABLE_PAT}$`); const FIND_VARIABLE = new RegExp(VARIABLE_PAT, 'g'); function validVariableName(x) { return VALID_VARIABLE.test(x); } /** * Return all variable names used in an expression */ function allIdentifiersInExpression(x) { return Array.from(matchAll(x, FIND_VARIABLE)).map(m => m[0]); } function ifUndefined(x, def) { if (x !== undefined) { return x; } return def; } /** * Change periods of all metrics in the map */ function changeAllPeriods(metrics, period) { const ret = {}; for (const [id, metric] of Object.entries(metrics)) { ret[id] = changePeriod(metric, period); } return ret; } /** * Return a new metric object which is the same type as the input object, but with the period changed * * Relies on the fact that implementations of `IMetric` are also supposed to have * an implementation of `with` that accepts an argument called `period`. See `IModifiableMetric`. */ function changePeriod(metric, period) { if (isModifiableMetric(metric)) { return metric.with({ period }); } throw new Error(`Metric object should also implement 'with': ${metric}`); } function isModifiableMetric(m) { return typeof m === 'object' && m !== null && !!m.with; } // Polyfill for string.matchAll(regexp) function matchAll(x, re) { const ret = new Array(); let m; while (m = re.exec(x)) { ret.push(m); } return ret; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWV0cmljLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsibWV0cmljLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLHdDQUF3QztBQUN4QyxxQ0FBcUM7QUFFckMsbUNBQXNFO0FBRXRFLHVEQUFrRTtBQUNsRSxtREFBeUU7QUErTnpFOzs7Ozs7Ozs7Ozs7O0dBYUc7QUFDSCxNQUFhLE1BQU07SUF5Q2pCLFlBQVksS0FBa0I7Ozs7OzsrQ0F6Q25CLE1BQU07Ozs7UUEwQ2YsSUFBSSxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUMsTUFBTSxJQUFJLEdBQUcsQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3RELE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDMUMsSUFBSSxTQUFTLEtBQUssQ0FBQyxJQUFJLFNBQVMsS0FBSyxDQUFDLElBQUksU0FBUyxLQUFLLEVBQUUsSUFBSSxTQUFTLEtBQUssRUFBRSxJQUFJLFNBQVMsR0FBRyxFQUFFLEtBQUssQ0FBQyxFQUFFO1lBQ3RHLE1BQU0sSUFBSSxLQUFLLENBQUMsd0VBQXdFLFNBQVMsRUFBRSxDQUFDLENBQUM7U0FDdEc7UUFDRCxJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxLQUFLLENBQUMsYUFBYSxJQUFJLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUNuRixJQUFJLENBQUMsU0FBUyxHQUFHLEtBQUssQ0FBQyxTQUFTLENBQUM7UUFDakMsSUFBSSxDQUFDLFVBQVUsR0FBRyxLQUFLLENBQUMsVUFBVSxDQUFDO1FBQ25DLHdEQUF3RDtRQUN4RCxJQUFJLENBQUMsU0FBUyxHQUFHLDhCQUFrQixDQUFDLEtBQUssQ0FBQyxTQUFTLElBQUksU0FBUyxDQUFDLENBQUM7UUFDbEUsSUFBSSxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDO1FBQ3pCLElBQUksQ0FB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QixDQUFDLE9BQWdDLEVBQUUsTUFBb0I7SUFDOUUsTUFBTSxHQUFHLEdBQTRCLEVBQUUsQ0FBQztJQUN4QyxLQUFLLE1BQU0sQ0FBQyxFQUFFLEVBQUUsTUFBTSxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsRUFBRTtRQUNsRCxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsWUFBWSxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FBQztLQUN4QztJQUNELE9BQU8sR0FBRyxDQUFDO0FBQ2IsQ0FBQztBQUVEOzs7OztHQUtHO0FBQ0gsU0FBUyxZQUFZLENBQUMsTUFBZSxFQUFFLE1BQW9CO0lBQ3pELElBQUksa0JBQWtCLENBQUMsTUFBTSxDQUFDLEVBQUU7UUFDOUIsT0FBTyxNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztLQUNoQztJQUVELE1BQU0sSUFBSSxLQUFLLENBQUMsK0NBQStDLE1BQU0sRUFBRSxDQUFDLENBQUM7QUFDM0UsQ0FBQztBQXdCRCxTQUFTLGtCQUFrQixDQUFDLENBQU07SUFDaEMsT0FBTyxPQUFPLENBQUMsS0FBSyxRQUFRLElBQUksQ0FBQyxLQUFLLElBQUksSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztBQUN6RCxDQUFDO0FBRUQsdUNBQXVDO0FBQ3ZDLFNBQVMsUUFBUSxDQUFDLENBQVMsRUFBRSxFQUFVO0lBQ3JDLE1BQU0sR0FBRyxHQUFHLElBQUksS0FBSyxFQUFvQixDQUFDO0lBQzFDLElBQUksQ0FBeUIsQ0FBQztJQUM5QixPQUFPLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFO1FBQ3JCLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7S0FDYjtJQUNELE9BQU8sR0FBRyxDQUFDO0FBQ2IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGlhbSBmcm9tICdAYXdzLWNkay9hd3MtaWFtJztcbmltcG9ydCAqIGFzIGNkayBmcm9tICdAYXdzLWNkay9jb3JlJztcbmltcG9ydCAqIGFzIGNvbnN0cnVjdHMgZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgeyBBbGFybSwgQ29tcGFyaXNvbk9wZXJhdG9yLCBUcmVhdE1pc3NpbmdEYXRhIH0gZnJvbSAnLi9hbGFybSc7XG5pbXBvcnQgeyBEaW1lbnNpb24sIElNZXRyaWMsIE1ldHJpY0FsYXJtQ29uZmlnLCBNZXRyaWNDb25maWcsIE1ldHJpY0dyYXBoQ29uZmlnLCBVbml0IH0gZnJvbSAnLi9tZXRyaWMtdHlwZXMnO1xuaW1wb3J0IHsgZGlzcGF0Y2hNZXRyaWMsIG1ldHJpY0tleSB9IGZyb20gJy4vcHJpdmF0ZS9tZXRyaWMtdXRpbCc7XG5pbXBvcnQgeyBub3JtYWxpemVTdGF0aXN0aWMsIHBhcnNlU3RhdGlzdGljIH0gZnJvbSAnLi9wcml2YXRlL3N0YXRpc3RpYyc7XG5cbi8vIGtlZXAgdGhpcyBpbXBvcnQgc2VwYXJhdGUgZnJvbSBvdGhlciBpbXBvcnRzIHRvIHJlZHVjZSBjaGFuY2UgZm9yIG1lcmdlIGNvbmZsaWN0cyB3aXRoIHYyLW1haW5cbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1kdXBsaWNhdGUtaW1wb3J0cywgaW1wb3J0L29yZGVyXG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdAYXdzLWNkay9jb3JlJztcblxuZXhwb3J0IHR5cGUgRGltZW5zaW9uSGFzaCA9IHtbZGltOiBzdHJpbmddOiBhbnl9O1xuXG5leHBvcnQgdHlwZSBEaW1lbnNpb25zTWFwID0geyBbZGltOiBzdHJpbmddOiBzdHJpbmcgfTtcblxuLyoqXG4gKiBPcHRpb25zIHNoYXJlZCBieSBtb3N0IG1ldGhvZHMgYWNjZXB0aW5nIG1ldHJpYyBvcHRpb25zXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ29tbW9uTWV0cmljT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBUaGUgcGVyaW9kIG92ZXIgd2hpY2ggdGhlIHNwZWNpZmllZCBzdGF0aXN0aWMgaXMgYXBwbGllZC5cbiAgICpcbiAgICogQGRlZmF1bHQgRHVyYXRpb24ubWludXRlcyg1KVxuICAgKi9cbiAgcmVhZG9ubHkgcGVyaW9kPzogY2RrLkR1cmF0aW9uO1xuXG4gIC8qKlxuICAgKiBXaGF0IGZ1bmN0aW9uIHRvIHVzZSBmb3IgYWdncmVnYXRpbmcuXG4gICAqXG4gICAqIENhbiBiZSBvbmUgb2YgdGhlIGZvbGxvd2luZzpcbiAgICpcbiAgICogLSBcIk1pbmltdW1cIiB8IFwibWluXCJcbiAgICogLSBcIk1heGltdW1cIiB8IFwibWF4XCJcbiAgICogLSBcIkF2ZXJhZ2VcIiB8IFwiYXZnXCJcbiAgICogLSBcIlN1bVwiIHwgXCJzdW1cIlxuICAgKiAtIFwiU2FtcGxlQ291bnQgfCBcIm5cIlxuICAgKiAtIFwicE5OLk5OXCJcbiAgICpcbiAgICogQGRlZmF1bHQgQXZlcmFnZVxuICAgKi9cbiAgcmVhZG9ubHkgc3RhdGlzdGljPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBEaW1lbnNpb25zIG9mIHRoZSBtZXRyaWNcbiAgICpcbiAgICogQGRlZmF1bHQgLSBObyBkaW1lbnNpb25zLlxuICAgKlxuICAgKiBAZGVwcmVjYXRlZCBVc2UgJ2RpbWVuc2lvbnNNYXAnIGluc3RlYWQuXG4gICAqL1xuICByZWFkb25seSBkaW1lbnNpb25zPzogRGltZW5zaW9uSGFzaDtcblxuICAvKipcbiAgICogRGltZW5zaW9ucyBvZiB0aGUgbWV0cmljXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gTm8gZGltZW5zaW9ucy5cbiAgICovXG4gIHJlYWRvbmx5IGRpbWVuc2lvbnNNYXA/OiBEaW1lbnNpb25zTWFwO1xuXG4gIC8qKlxuICAgKiBVbml0IHVzZWQgdG8gZmlsdGVyIHRoZSBtZXRyaWMgc3RyZWFtXG4gICAqXG4gICAqIE9ubHkgcmVmZXIgdG8gZGF0dW1zIGVtaXR0ZWQgdG8gdGhlIG1ldHJpYyBzdHJlYW0gd2l0aCB0aGUgZ2l2ZW4gdW5pdCBhbmRcbiAgICogaWdub3JlIGFsbCBvdGhlcnMuIE9ubHkgdXNlZnVsIHdoZW4gZGF0dW1zIGFyZSBiZWluZyBlbWl0dGVkIHRvIHRoZSBzYW1lXG4gICAqIG1ldHJpYyBzdHJlYW0gdW5kZXIgZGlmZmVyZW50IHVuaXRzLlxuICAgKlxuICAgKiBUaGUgZGVmYXVsdCBpcyB0byB1c2UgYWxsIG1hdHJpYyBkYXR1bXMgaW4gdGhlIHN0cmVhbSwgcmVnYXJkbGVzcyBvZiB1bml0LFxuICAgKiB3aGljaCBpcyByZWNvbW1lbmRlZCBpbiBuZWFybHkgYWxsIGNhc2VzLlxuICAgKlxuICAgKiBDbG91ZFdhdGNoIGRvZXMgbm90IGhvbm9yIHRoaXMgcHJvcGVydHkgZm9yIGdyYXBocy5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBBbGwgbWV0cmljIGRhdHVtcyBpbiB0aGUgZ2l2ZW4gbWV0cmljIHN0cmVhbVxuICAgKi9cbiAgcmVhZG9ubHkgdW5pdD86IFVuaXQ7XG5cbiAgLyoqXG4gICAqIExhYmVsIGZvciB0aGlzIG1ldHJpYyB3aGVuIGFkZGVkIHRvIGEgR3JhcGggaW4gYSBEYXNoYm9hcmRcbiAgICpcbiAgICogWW91IGNhbiB1c2UgW2R5bmFtaWMgbGFiZWxzXShodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQW1hem9uQ2xvdWRXYXRjaC9sYXRlc3QvbW9uaXRvcmluZy9ncmFwaC1keW5hbWljLWxhYmVscy5odG1sKVxuICAgKiB0byBzaG93IHN1bW1hcnkgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGVudGlyZSBkaXNwbGF5ZWQgdGltZSBzZXJpZXNcbiAgICogaW4gdGhlIGxlZ2VuZC4gRm9yIGV4YW1wbGUsIGlmIHlvdSB1c2U6XG4gICAqXG4gICAqIGBgYFxuICAgKiBbbWF4OiAke01BWH1dIE15TWV0cmljXG4gICAqIGBgYFxuICAgKlxuICAgKiBBcyB0aGUgbWV0cmljIGxhYmVsLCB0aGUgbWF4aW11bSB2YWx1ZSBpbiB0aGUgdmlzaWJsZSByYW5nZSB3aWxsXG4gICAqIGJlIHNob3duIG5leHQgdG8gdGhlIHRpbWUgc2VyaWVzIG5hbWUgaW4gdGhlIGdyYXBoJ3MgbGVnZW5kLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5vIGxhYmVsXG4gICAqL1xuICByZWFkb25seSBsYWJlbD86IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIGhleCBjb2xvciBjb2RlLCBwcmVmaXhlZCB3aXRoICcjJyAoZS5nLiAnIzAwZmYwMCcpLCB0byB1c2Ugd2hlbiB0aGlzIG1ldHJpYyBpcyByZW5kZXJlZCBvbiBhIGdyYXBoLlxuICAgKiBUaGUgYENvbG9yYCBjbGFzcyBoYXMgYSBzZXQgb2Ygc3RhbmRhcmQgY29sb3JzIHRoYXQgY2FuIGJlIHVzZWQgaGVyZS5cbiAgICogQGRlZmF1bHQgLSBBdXRvbWF0aWMgY29sb3JcbiAgICovXG4gIHJlYWRvbmx5IGNvbG9yPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBBY2NvdW50IHdoaWNoIHRoaXMgbWV0cmljIGNvbWVzIGZyb20uXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gRGVwbG95bWVudCBhY2NvdW50LlxuICAgKi9cbiAgcmVhZG9ubHkgYWNjb3VudD86IHN0cmluZztcblxuICAvKipcbiAgICogUmVnaW9uIHdoaWNoIHRoaXMgbWV0cmljIGNvbWVzIGZyb20uXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gRGVwbG95bWVudCByZWdpb24uXG4gICAqL1xuICByZWFkb25seSByZWdpb24/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogUHJvcGVydGllcyBmb3IgYSBtZXRyaWNcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBNZXRyaWNQcm9wcyBleHRlbmRzIENvbW1vbk1ldHJpY09wdGlvbnMge1xuICAvKipcbiAgICogTmFtZXNwYWNlIG9mIHRoZSBtZXRyaWMuXG4gICAqL1xuICByZWFkb25seSBuYW1lc3BhY2U6IHN0cmluZztcblxuICAvKipcbiAgICogTmFtZSBvZiB0aGUgbWV0cmljLlxuICAgKi9cbiAgcmVhZG9ubHkgbWV0cmljTmFtZTogc3RyaW5nO1xufVxuXG4vKipcbiAqIFByb3BlcnRpZXMgb2YgYSBtZXRyaWMgdGhhdCBjYW4gYmUgY2hhbmdlZFxuICovXG5leHBvcnQgaW50ZXJmYWNlIE1ldHJpY09wdGlvbnMgZXh0ZW5kcyBDb21tb25NZXRyaWNPcHRpb25zIHtcbn1cblxuLyoqXG4gKiBDb25maWd1cmFibGUgb3B0aW9ucyBmb3IgTWF0aEV4cHJlc3Npb25zXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTWF0aEV4cHJlc3Npb25PcHRpb25zIHtcbiAgLyoqXG4gICAqIExhYmVsIGZvciB0aGlzIGV4cHJlc3Npb24gd2hlbiBhZGRlZCB0byBhIEdyYXBoIGluIGEgRGFzaGJvYXJkXG4gICAqXG4gICAqIElmIHRoaXMgZXhwcmVzc2lvbiBldmFsdWF0ZXMgdG8gbW9yZSB0aGFuIG9uZSB0aW1lIHNlcmllcyAoZm9yXG4gICAqIGV4YW1wbGUsIHRocm91Z2ggdGhlIHVzZSBvZiBgTUVUUklDUygpYCBvciBgU0VBUkNIKClgIGV4cHJlc3Npb25zKSxcbiAgICogZWFjaCB0aW1lIHNlcmllcyB3aWxsIGFwcGVhciBpbiB0aGUgZ3JhcGggdXNpbmcgYSBjb21iaW5hdGlvbiBvZiB0aGVcbiAgICogZXhwcmVzc2lvbiBsYWJlbCBhbmQgdGhlIGluZGl2aWR1YWwgbWV0cmljIGxhYmVsLiBTcGVjaWZ5IHRoZSBlbXB0eVxuICAgKiBzdHJpbmcgKGAnJ2ApIHRvIHN1cHByZXNzIHRoZSBleHByZXNzaW9uIGxhYmVsIGFuZCBvbmx5IGtlZXAgdGhlXG4gICAqIG1ldHJpYyBsYWJlbC5cbiAgICpcbiAgICogWW91IGNhbiB1c2UgW2R5bmFtaWMgbGFiZWxzXShodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQW1hem9uQ2xvdWRXYXRjaC9sYXRlc3QvbW9uaXRvcmluZy9ncmFwaC1keW5hbWljLWxhYmVscy5odG1sKVxuICAgKiB0byBzaG93IHN1bW1hcnkgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGRpc3BsYXllZCB0aW1lIHNlcmllc1xuICAgKiBpbiB0aGUgbGVnZW5kLiBGb3IgZXhhbXBsZSwgaWYgeW91IHVzZTpcbiAgICpcbiAgICogYGBgXG4gICAqIFttYXg6ICR7TUFYfV0gTXlNZXRyaWNcbiAgICogYGBgXG4gICAqXG4gICAqIEFzIHRoZSBtZXRyaWMgbGFiZWwsIHRoZSBtYXhpbXVtIHZhbHVlIGluIHRoZSB2aXNpYmxlIHJhbmdlIHdpbGxcbiAgICogYmUgc2hvd24gbmV4dCB0byB0aGUgdGltZSBzZXJpZXMgbmFtZSBpbiB0aGUgZ3JhcGgncyBsZWdlbmQuIElmIHRoZVxuICAgKiBtYXRoIGV4cHJlc3Npb24gcHJvZHVjZXMgbW9yZSB0aGFuIG9uZSB0aW1lIHNlcmllcywgdGhlIG1heGltdW1cbiAgICogd2lsbCBiZSBzaG93biBmb3IgZWFjaCBpbmRpdmlkdWFsIHRpbWUgc2VyaWVzIHByb2R1Y2UgYnkgdGhpc1xuICAgKiBtYXRoIGV4cHJlc3Npb24uXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gRXhwcmVzc2lvbiB2YWx1ZSBpcyB1c2VkIGFzIGxhYmVsXG4gICAqL1xuICByZWFkb25seSBsYWJlbD86IHN0cmluZztcblxuICAvKipcbiAgICogQ29sb3IgZm9yIHRoaXMgbWV0cmljIHdoZW4gYWRkZWQgdG8gYSBHcmFwaCBpbiBhIERhc2hib2FyZFxuICAgKlxuICAgKiBAZGVmYXVsdCAtIEF1dG9tYXRpYyBjb2xvclxuICAgKi9cbiAgcmVhZG9ubHkgY29sb3I/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBwZXJpb2Qgb3ZlciB3aGljaCB0aGUgZXhwcmVzc2lvbidzIHN0YXRpc3RpY3MgYXJlIGFwcGxpZWQuXG4gICAqXG4gICAqIFRoaXMgcGVyaW9kIG92ZXJyaWRlcyBhbGwgcGVyaW9kcyBpbiB0aGUgbWV0cmljcyB1c2VkIGluIHRoaXNcbiAgICogbWF0aCBleHByZXNzaW9uLlxuICAgKlxuICAgKiBAZGVmYXVsdCBEdXJhdGlvbi5taW51dGVzKDUpXG4gICAqL1xuICByZWFkb25seSBwZXJpb2Q/OiBjZGsuRHVyYXRpb247XG5cbiAgLyoqXG4gICAqIEFjY291bnQgdG8gZXZhbHVhdGUgc2VhcmNoIGV4cHJlc3Npb25zIHdpdGhpbi5cbiAgICpcbiAgICogU3BlY2lmeWluZyBhIHNlYXJjaEFjY291bnQgaGFzIG5vIGVmZmVjdCB0byB0aGUgYWNjb3VudCB1c2VkXG4gICAqIGZvciBtZXRyaWNzIHdpdGhpbiB0aGUgZXhwcmVzc2lvbiAocGFzc2VkIHZpYSB1c2luZ01ldHJpY3MpLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIERlcGxveW1lbnQgYWNjb3VudC5cbiAgICovXG4gIHJlYWRvbmx5IHNlYXJjaEFjY291bnQ/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAgKiBSZWdpb24gdG8gZXZhbHVhdGUgc2VhcmNoIGV4cHJlc3Npb25zIHdpdGhpbi5cbiAgICAqXG4gICAgKiBTcGVjaWZ5aW5nIGEgc2VhcmNoUmVnaW9uIGhhcyBubyBlZmZlY3QgdG8gdGhlIHJlZ2lvbiB1c2VkXG4gICAgKiBmb3IgbWV0cmljcyB3aXRoaW4gdGhlIGV4cHJlc3Npb24gKHBhc3NlZCB2aWEgdXNpbmdNZXRyaWNzKS5cbiAgICAqXG4gICAgKiBAZGVmYXVsdCAtIERlcGxveW1lbnQgcmVnaW9uLlxuICAgICovXG4gIHJlYWRvbmx5IHNlYXJjaFJlZ2lvbj86IHN0cmluZztcbn1cblxuLyoqXG4gKiBQcm9wZXJ0aWVzIGZvciBhIE1hdGhFeHByZXNzaW9uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTWF0aEV4cHJlc3Npb25Qcm9wcyBleHRlbmRzIE1hdGhFeHByZXNzaW9uT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBUaGUgZXhwcmVzc2lvbiBkZWZpbmluZyB0aGUgbWV0cmljLlxuICAgKlxuICAgKiBXaGVuIGFuIGV4cHJlc3Npb24gY29udGFpbnMgYSBTRUFSQ0ggZnVuY3Rpb24sIGl0IGNhbm5vdCBiZSB1c2VkXG4gICAqIHdpdGhpbiBhbiBBbGFybS5cbiAgICovXG4gIHJlYWRvbmx5IGV4cHJlc3Npb246IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIG1ldHJpY3MgdXNlZCBpbiB0aGUgZXhwcmVzc2lvbiwgaW4gYSBtYXAuXG4gICAqXG4gICAqIFRoZSBrZXkgaXMgdGhlIGlkZW50aWZpZXIgdGhhdCByZXByZXNlbnRzIHRoZSBnaXZlbiBtZXRyaWMgaW4gdGhlXG4gICAqIGV4cHJlc3Npb24sIGFuZCB0aGUgdmFsdWUgaXMgdGhlIGFjdHVhbCBNZXRyaWMgb2JqZWN0LlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIEVtcHR5IG1hcC5cbiAgICovXG4gIHJlYWRvbmx5IHVzaW5nTWV0cmljcz86IFJlY29yZDxzdHJpbmcsIElNZXRyaWM+O1xufVxuXG4vKipcbiAqIEEgbWV0cmljIGVtaXR0ZWQgYnkgYSBzZXJ2aWNlXG4gKlxuICogVGhlIG1ldHJpYyBpcyBhIGNvbWJpbmF0aW9uIG9mIGEgbWV0cmljIGlkZW50aWZpZXIgKG5hbWVzcGFjZSwgbmFtZSBhbmQgZGltZW5zaW9ucylcbiAqIGFuZCBhbiBhZ2dyZWdhdGlvbiBmdW5jdGlvbiAoc3RhdGlzdGljLCBwZXJpb2QgYW5kIHVuaXQpLlxuICpcbiAqIEl0IGFsc28gY29udGFpbnMgbWV0YWRhdGEgd2hpY2ggaXMgdXNlZCBvbmx5IGluIGdyYXBocywgc3VjaCBhcyBjb2xvciBhbmQgbGFiZWwuXG4gKiBJdCBtYWtlcyBzZW5zZSB0byBlbWJlZCB0aGlzIGluIGhlcmUsIHNvIHRoYXQgY29tcG91bmQgY29uc3RydWN0cyBjYW4gYXR0YWNoXG4gKiB0aGF0IG1ldGFkYXRhIHRvIG1ldHJpY3MgdGhleSBleHBvc2UuXG4gKlxuICogVGhpcyBjbGFzcyBkb2VzIG5vdCByZXByZXNlbnQgYSByZXNvdXJjZSwgc28gaGVuY2UgaXMgbm90IGEgY29uc3RydWN0LiBJbnN0ZWFkLFxuICogTWV0cmljIGlzIGFuIGFic3RyYWN0aW9uIHRoYXQgbWFrZXMgaXQgZWFzeSB0byBzcGVjaWZ5IG1ldHJpY3MgZm9yIHVzZSBpbiBib3RoXG4gKiBhbGFybXMgYW5kIGdyYXBocy5cbiAqL1xuZXhwb3J0IGNsYXNzIE1ldHJpYyBpbXBsZW1lbnRzIElNZXRyaWMge1xuICAvKipcbiAgICogR3JhbnQgcGVybWlzc2lvbnMgdG8gdGhlIGdpdmVuIGlkZW50aXR5IHRvIHdyaXRlIG1ldHJpY3MuXG4gICAqXG4gICAqIEBwYXJhbSBncmFudGVlIFRoZSBJQU0gaWRlbnRpdHkgdG8gZ2l2ZSBwZXJtaXNzaW9ucyB0by5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgZ3JhbnRQdXRNZXRyaWNEYXRhKGdyYW50ZWU6IGlhbS5JR3JhbnRhYmxlKTogaWFtLkdyYW50IHtcbiAgICByZXR1cm4gaWFtLkdyYW50LmFkZFRvUHJpbmNpcGFsKHtcbiAgICAgIGdyYW50ZWUsXG4gICAgICBhY3Rpb25zOiBbJ2Nsb3Vkd2F0Y2g6UHV0TWV0cmljRGF0YSddLFxuICAgICAgcmVzb3VyY2VBcm5zOiBbJyonXSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKiBEaW1lbnNpb25zIG9mIHRoaXMgbWV0cmljICovXG4gIHB1YmxpYyByZWFkb25seSBkaW1lbnNpb25zPzogRGltZW5zaW9uSGFzaDtcbiAgLyoqIE5hbWVzcGFjZSBvZiB0aGlzIG1ldHJpYyAqL1xuICBwdWJsaWMgcmVhZG9ubHkgbmFtZXNwYWNlOiBzdHJpbmc7XG4gIC8qKiBOYW1lIG9mIHRoaXMgbWV0cmljICovXG4gIHB1YmxpYyByZWFkb25seSBtZXRyaWNOYW1lOiBzdHJpbmc7XG4gIC8qKiBQZXJpb2Qgb2YgdGhpcyBtZXRyaWMgKi9cbiAgcHVibGljIHJlYWRvbmx5IHBlcmlvZDogY2RrLkR1cmF0aW9uO1xuICAvKiogU3RhdGlzdGljIG9mIHRoaXMgbWV0cmljICovXG4gIHB1YmxpYyByZWFkb25seSBzdGF0aXN0aWM6IHN0cmluZztcbiAgLyoqIExhYmVsIGZvciB0aGlzIG1ldHJpYyB3aGVuIGFkZGVkIHRvIGEgR3JhcGggaW4gYSBEYXNoYm9hcmQgKi9cbiAgcHVibGljIHJlYWRvbmx5IGxhYmVsPzogc3RyaW5nO1xuICAvKiogVGhlIGhleCBjb2xvciBjb2RlIHVzZWQgd2hlbiB0aGlzIG1ldHJpYyBpcyByZW5kZXJlZCBvbiBhIGdyYXBoLiAqL1xuICBwdWJsaWMgcmVhZG9ubHkgY29sb3I/OiBzdHJpbmc7XG5cbiAgLyoqIFVuaXQgb2YgdGhlIG1ldHJpYy4gKi9cbiAgcHVibGljIHJlYWRvbmx5IHVuaXQ/OiBVbml0O1xuXG4gIC8qKiBBY2NvdW50IHdoaWNoIHRoaXMgbWV0cmljIGNvbWVzIGZyb20gKi9cbiAgcHVibGljIHJlYWRvbmx5IGFjY291bnQ/OiBzdHJpbmc7XG5cbiAgLyoqIFJlZ2lvbiB3aGljaCB0aGlzIG1ldHJpYyBjb21lcyBmcm9tLiAqL1xuICBwdWJsaWMgcmVhZG9ubHkgcmVnaW9uPzogc3RyaW5nO1xuXG4gIC8qKiBXYXJuaW5ncyBhdHRhY2hlZCB0byB0aGlzIG1ldHJpYy4gKi9cbiAgcHVibGljIHJlYWRvbmx5IHdhcm5pbmdzPzogc3RyaW5nW107XG5cbiAgY29uc3RydWN0b3IocHJvcHM