cdk-monitoring-constructs
Version:
[](https://badge.fury.io/js/cdk-monitoring-constructs) [](https://m
342 lines • 54.1 kB
JavaScript
"use strict";
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.MetricFactory = exports.DefaultMetricPeriod = void 0;
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
const aws_cdk_lib_1 = require("aws-cdk-lib");
const aws_cloudwatch_1 = require("aws-cdk-lib/aws-cloudwatch");
const AnomalyDetectionMathExpression_1 = require("./AnomalyDetectionMathExpression");
const MetricStatistic_1 = require("./MetricStatistic");
const RateComputationMethod_1 = require("./RateComputationMethod");
/**
* The most common default metric period used at Amazon is currently 5 minutes.
*/
exports.DefaultMetricPeriod = aws_cdk_lib_1.Duration.minutes(5);
class MetricFactory {
constructor(scope, props) {
this.globalDefaults = props?.globalDefaults ?? {};
this.scope = scope;
}
/**
* Factory method that creates a metric. The metric properties will already be updated to comply with the global defaults.
*
* @param metricName metric name
* @param statistic aggregation statistic to use
* @param label metric label; if undefined, metric name is used by CloudWatch
* @param dimensionsMap additional dimensions to be added
* @param color metric color; if undefined, uses a CloudWatch provided color (preferred)
* @param namespace specify a custom namespace; if undefined, uses the global default
* @param period specify a custom period; if undefined, uses the global default
* @param region specify a custom region; if undefined, uses the global default
* @param account specify a custom account; if undefined, uses the global default
*/
createMetric(metricName, statistic, label, dimensionsMap, color, namespace, period, region, account) {
return new aws_cloudwatch_1.Metric({
statistic,
metricName,
label,
color,
dimensionsMap: dimensionsMap
? this.removeUndefinedEntries(dimensionsMap)
: undefined,
namespace: this.getNamespaceWithFallback(namespace),
period: period ?? this.globalDefaults.period ?? exports.DefaultMetricPeriod,
region: this.resolveRegion(region ?? this.globalDefaults.region),
account: this.resolveAccount(account ?? this.globalDefaults.account),
});
}
/**
* Factory method that creates a metric math expression. The metric properties will already be updated to comply with the global defaults.
*
* @param expression CloudWatch metric math expression (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/using-metric-math.html)
* @param usingMetrics map of metrics, where keys are expression IDs (used in the expression) and values are metrics
* @param label metric label (required, as there is no reasonable default)
* @param color metric color; if undefined, uses a CloudWatch provided color (preferred)
* @param period specify a custom period; if undefined, uses the global default
* @param region -- Deprecated: Use createSearchMetric if doing cross region search
* @param account -- Deprecated: Use createSearchMetric if doing cross region search
*/
createMetricMath(expression, usingMetrics, label, color, period, region, account) {
if (region || account) {
console.warn("'region' and 'account' inputs are ignored, please use 'createSearchMetric'");
}
return new aws_cloudwatch_1.MathExpression({
label,
color,
expression,
usingMetrics,
period: period ?? this.globalDefaults.period ?? exports.DefaultMetricPeriod,
});
}
/**
* Factory method that creates a metric search query. The metric properties will already be updated to comply with the global defaults.
* If you want to match "any value" of a specific dimension, please use `undefined` value representation in your consumer language.
* (For example, `undefined as any as string` in TypeScript, due to JSII typing quirks.)
*
* @param query metric search query (the same as the search query prompt in CloudWatch AWS Console), it might also be empty
* @param dimensionsMap dimensions, further narrowing the search results; use `undefined` if you want to represent "any value" (in TS: `undefined as any as string`)
* @param statistic aggregation statistic to use
* @param namespace specify a custom namespace; if undefined, uses the global default
* @param label specify custom label for search metrics; default is " " as it cannot be empty string
* @param period specify a custom period; if undefined, uses the global default
* @param region specify a custom region; if undefined, uses the global default
* @param account specify a custom account; if undefined, uses the global default
*/
createMetricSearch(query, dimensionsMap, statistic, namespace, label, period, region, account) {
const finalPeriod = period ?? this.globalDefaults.period ?? exports.DefaultMetricPeriod;
const searchNamespace = this.getNamespaceWithFallback(namespace);
const namespacesWithQuotations = searchNamespace
.split(",")
.map((namespace) => `"${namespace.trim()}"`);
const keysWithQuotations = Object.keys(dimensionsMap).map((key) => `"${key}"`);
const namespacePlusDimensionKeys = [
...namespacesWithQuotations,
...keysWithQuotations,
].join(",");
const metricSchema = `{${namespacePlusDimensionKeys}}`;
const dimensionKeysAndValues = Object.entries(this.removeUndefinedEntries(dimensionsMap))
.map(([key, value]) => `"${key}"="${value}"`)
.join(" ");
const expression = `SEARCH('${metricSchema} ${dimensionKeysAndValues} ${query}', '${statistic}', ${finalPeriod.toSeconds()})`;
return new aws_cloudwatch_1.MathExpression({
expression,
// see https://github.com/aws/aws-cdk/issues/7237
usingMetrics: {},
// cannot be an empty string and undefined is no good either
label: label ?? " ",
period: finalPeriod,
searchRegion: this.resolveRegion(region ?? this.globalDefaults.region),
searchAccount: this.resolveAccount(account ?? this.globalDefaults.account),
});
}
/**
* Factory method that creates anomaly detection on a metric.
* Anomaly occurs whenever a metric value falls outside of a precomputed range of predicted values.
* The detection does not need any setup. The model will start learning automatically and should be ready in a few minutes.
* Usually, the anomaly detection is paired with an alarm.
* @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Anomaly_Detection.html
*
* @param metric metric to detect anomaly detection of
* @param stdev standard deviation, basically the tolerance / band thickness
* @param label metric label (required, as there is no reasonable default)
* @param color metric color; if undefined, uses a CloudWatch provided color (preferred)
* @param expressionId expression ID of the metric; uses `m1` if undefined
* @param period specify a custom period; if undefined, uses the global default
* @param region specify a custom region; if undefined, uses the global default
* @param account specify a custom account; if undefined, uses the global default
*/
createMetricAnomalyDetection(metric, stdev, label, color, expressionId, period, region, account) {
const finalExpressionId = expressionId ?? "m1";
const usingMetrics = {};
usingMetrics[finalExpressionId] = metric;
return new AnomalyDetectionMathExpression_1.AnomalyDetectionMathExpression({
label,
color,
usingMetrics,
expression: `ANOMALY_DETECTION_BAND(${finalExpressionId},${stdev})`,
period: period ?? this.globalDefaults.period ?? exports.DefaultMetricPeriod,
searchRegion: this.resolveRegion(region ?? this.globalDefaults.region),
searchAccount: this.resolveAccount(account ?? this.globalDefaults.account),
});
}
/**
* Adapts properties of a foreign metric (metric created outside of this metric factory) to comply with the global defaults.
* Might modify namespace and metric period.
*
* @param metric metric to be adapted
*/
adaptMetric(metric) {
if (this.globalDefaults.region) {
metric = metric.with({ region: this.globalDefaults.region });
}
if (this.globalDefaults.account) {
metric = metric.with({ account: this.globalDefaults.account });
}
return metric.with({
period: this.globalDefaults.period ?? exports.DefaultMetricPeriod,
});
}
/**
* Adapts properties of a foreign metric (metric created outside of this metric factory) to comply with the global defaults.
* Might modify namespace. Preserves metric period.
*
* @param metric metric to be adapted
*/
adaptMetricPreservingPeriod(metric) {
return metric;
}
/**
* Creates a metric math expression that multiplies the given metric by given coefficient.
* Does nothing if the multiplier is one. Preserves the metric period.
*
* @param metric metric to multiply
* @param multiplier multiplier (must be > 1)
* @param label expression label
* @param expressionId expression ID of the metric; uses `m1` if undefined
*/
multiplyMetric(metric, multiplier, label, expressionId) {
if (multiplier == 1) {
return metric;
}
else if (multiplier < 1) {
throw new Error("Multiplier must be greater than one.");
}
else {
const finalExpressionId = expressionId ?? "m1";
const usingMetrics = {};
usingMetrics[finalExpressionId] = metric;
return this.createMetricMath(`${finalExpressionId} * ${multiplier}`, usingMetrics, label, metric.color, metric.period);
}
}
/**
* Creates a metric math expression that divides the given metric by given coefficient.
* Does nothing if the divisor is one. Preserves the metric period.
*
* @param metric metric to multiply
* @param divisor divisor (must be > 1)
* @param label expression label
* @param expressionId expression ID of the metric; uses `m1` if undefined
*/
divideMetric(metric, divisor, label, expressionId) {
if (divisor == 1) {
return metric;
}
else if (divisor < 1) {
throw new Error("Divisor must be greater than one.");
}
else {
const finalExpressionId = expressionId ?? "m1";
const usingMetrics = {};
usingMetrics[finalExpressionId] = metric;
return this.createMetricMath(`${finalExpressionId} / ${divisor}`, usingMetrics, label, metric.color, metric.period);
}
}
/**
* Creates a metric math expression that computes a rate from a regular metric.
* For example, it allows you to compute rate per second (TPS), per minute, or just an average of your transactions.
*
* @param metric metric to calculate the rate from
* @param method rate computation method
* @param addStatsToLabel add detailed statistics (min, max, average) to the label
* @param expressionId expression ID of the metric; uses `m1` if undefined
* @param fillWithZeroes if TRUE, the final metric will be zero-filled (0 on no data); false if undefined
*/
toRate(metric, method, addStatsToLabel, expressionId, fillWithZeroes) {
const finalExpressionId = expressionId ?? "m1";
const labelPrefix = metric.label ?? "Rate";
const statsInLabel = [];
if (addStatsToLabel ?? false) {
statsInLabel.push("min: ${MIN}");
statsInLabel.push("max: ${MAX}");
if (method !== RateComputationMethod_1.RateComputationMethod.AVERAGE) {
// only add average if do not have it already
statsInLabel.push("avg: ${AVG}");
}
}
const finalExpressionIdZeroed = fillWithZeroes ?? false
? `FILL(${finalExpressionId},0)`
: finalExpressionId;
const labelAppendix = statsInLabel.length > 0 ? ` (${statsInLabel.join(", ")})` : "";
switch (method) {
case RateComputationMethod_1.RateComputationMethod.AVERAGE:
const avgLabel = `${labelPrefix} (avg)${labelAppendix}`;
const avgMetric = metric.with({
label: avgLabel,
statistic: MetricStatistic_1.MetricStatistic.AVERAGE,
});
if (fillWithZeroes ?? false) {
return this.createMetricMath(finalExpressionIdZeroed, { [finalExpressionId]: avgMetric }, avgLabel, avgMetric.color, avgMetric.period);
}
return avgMetric;
case RateComputationMethod_1.RateComputationMethod.PER_SECOND:
let perSecondLabel = `${labelPrefix}/s${labelAppendix}`;
if (labelPrefix === "Requests" ||
labelPrefix === "Invocations" ||
labelPrefix === "Transactions") {
// currently, kept as "TPS" to reduce number of snapshot changes
perSecondLabel = `TPS${labelAppendix}`;
}
return this.createMetricMath(`${finalExpressionIdZeroed} / PERIOD(${finalExpressionId})`, { [finalExpressionId]: metric }, perSecondLabel, metric.color, metric.period);
case RateComputationMethod_1.RateComputationMethod.PER_MINUTE:
return this.createMetricMath(`(60 * ${finalExpressionIdZeroed}) / PERIOD(${finalExpressionId})`, { [finalExpressionId]: metric }, `${labelPrefix}/m${labelAppendix}`, metric.color, metric.period);
case RateComputationMethod_1.RateComputationMethod.PER_HOUR:
return this.createMetricMath(`(3600 * ${finalExpressionIdZeroed}) / PERIOD(${finalExpressionId})`, { [finalExpressionId]: metric }, `${labelPrefix}/h${labelAppendix}`, metric.color, metric.period);
case RateComputationMethod_1.RateComputationMethod.PER_DAY:
return this.createMetricMath(`(86400 * ${finalExpressionIdZeroed}) / PERIOD(${finalExpressionId})`, { [finalExpressionId]: metric }, `${labelPrefix}/d${labelAppendix}`, metric.color, metric.period);
}
}
/**
* Returns the given namespace (if defined) or the global namespace as a fallback.
* If there is no namespace to fallback to (neither the custom or the default one), it will fail.
* @param value custom namespace
*/
getNamespaceWithFallback(value) {
const namespace = value ?? this.globalDefaults.namespace;
if (!namespace) {
throw new Error("There is no custom namespace defined. Please specify it in your factory defaults.");
}
return namespace;
}
/**
* Helper method that helps to sanitize the given expression ID and removes all invalid characters.
* Valid expression ID regexp is the following: ^[a-z][a-zA-Z0-9_]*$
* As this is just to validate a suffix and not the whole ID, we do not have to verify the first lower case letter.
* @param expressionId expression ID to sanitize
*/
sanitizeMetricExpressionIdSuffix(expressionId) {
return expressionId.replace(/[^0-9a-z_]/gi, "");
}
/**
* Merges the given additional dimensions to the given target dimension hash.
* All existing dimensions with the same key are replaced.
* @param target target dimension hash to update
* @param additionalDimensions additional dimensions
*/
addAdditionalDimensions(target, additionalDimensions) {
// Add additional dimensions in the search query
Object.keys(additionalDimensions).forEach((key) => {
target[key] = additionalDimensions[key];
});
}
/**
* Removes all entries from the given dimension hash that contain an undefined value.
* @param dimensionsMap dimensions map to update
*/
removeUndefinedEntries(dimensionsMap) {
const copy = {};
Object.entries(dimensionsMap)
.filter(([_, value]) => value !== undefined)
.forEach(([key, value]) => (copy[key] = value));
return copy;
}
/**
* Attempts to get the account from the metric if it differs from the scope.
*/
resolveAccount(metricAccount) {
if (!this.scope) {
return metricAccount;
}
const { account } = aws_cdk_lib_1.Stack.of(this.scope);
if (metricAccount !== account) {
return metricAccount;
}
return;
}
/**
* Attempts to get the region from the metric if it differs from the scope.
*/
resolveRegion(metricRegion) {
if (!this.scope) {
return metricRegion;
}
const { region } = aws_cdk_lib_1.Stack.of(this.scope);
if (metricRegion !== region) {
return metricRegion;
}
return;
}
}
exports.MetricFactory = MetricFactory;
_a = JSII_RTTI_SYMBOL_1;
MetricFactory[_a] = { fqn: "cdk-monitoring-constructs.MetricFactory", version: "10.0.0" };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWV0cmljRmFjdG9yeS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIk1ldHJpY0ZhY3RvcnkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSw2Q0FBOEM7QUFDOUMsK0RBS29DO0FBR3BDLHFGQUFrRjtBQUVsRix1REFBb0Q7QUFFcEQsbUVBQWdFO0FBRWhFOztHQUVHO0FBQ1UsUUFBQSxtQkFBbUIsR0FBRyxzQkFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQztBQXlCdkQsTUFBYSxhQUFhO0lBSXhCLFlBQVksS0FBZ0IsRUFBRSxLQUEwQjtRQUN0RCxJQUFJLENBQUMsY0FBYyxHQUFHLEtBQUssRUFBRSxjQUFjLElBQUksRUFBRSxDQUFDO1FBQ2xELElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO0lBQ3JCLENBQUM7SUFFRDs7Ozs7Ozs7Ozs7O09BWUc7SUFDSCxZQUFZLENBQ1YsVUFBa0IsRUFDbEIsU0FBMEIsRUFDMUIsS0FBYyxFQUNkLGFBQTZCLEVBQzdCLEtBQWMsRUFDZCxTQUFrQixFQUNsQixNQUFpQixFQUNqQixNQUFlLEVBQ2YsT0FBZ0I7UUFFaEIsT0FBTyxJQUFJLHVCQUFNLENBQUM7WUFDaEIsU0FBUztZQUNULFVBQVU7WUFDVixLQUFLO1lBQ0wsS0FBSztZQUNMLGFBQWEsRUFBRSxhQUFhO2dCQUMxQixDQUFDLENBQUMsSUFBSSxDQUFDLHNCQUFzQixDQUFDLGFBQWEsQ0FBQztnQkFDNUMsQ0FBQyxDQUFDLFNBQVM7WUFDYixTQUFTLEVBQUUsSUFBSSxDQUFDLHdCQUF3QixDQUFDLFNBQVMsQ0FBQztZQUNuRCxNQUFNLEVBQUUsTUFBTSxJQUFJLElBQUksQ0FBQyxjQUFjLENBQUMsTUFBTSxJQUFJLDJCQUFtQjtZQUNuRSxNQUFNLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxNQUFNLElBQUksSUFBSSxDQUFDLGNBQWMsQ0FBQyxNQUFNLENBQUM7WUFDaEUsT0FBTyxFQUFFLElBQUksQ0FBQyxj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UUFDdEIsQ0FBQztRQUVELE1BQU0sRUFBRSxNQUFNLEVBQUUsR0FBRyxtQkFBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDeEMsSUFBSSxZQUFZLEtBQUssTUFBTSxFQUFFLENBQUM7WUFDNUIsT0FBTyxZQUFZLENBQUM7UUFDdEIsQ0FBQztRQUVELE9BQU87SUFDVCxDQUFDOztBQXBkSCxzQ0FxZEMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBEdXJhdGlvbiwgU3RhY2sgfSBmcm9tIFwiYXdzLWNkay1saWJcIjtcbmltcG9ydCB7XG4gIERpbWVuc2lvbnNNYXAsXG4gIElNZXRyaWMsXG4gIE1hdGhFeHByZXNzaW9uLFxuICBNZXRyaWMsXG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtY2xvdWR3YXRjaFwiO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSBcImNvbnN0cnVjdHNcIjtcblxuaW1wb3J0IHsgQW5vbWFseURldGVjdGlvbk1hdGhFeHByZXNzaW9uIH0gZnJvbSBcIi4vQW5vbWFseURldGVjdGlvbk1hdGhFeHByZXNzaW9uXCI7XG5pbXBvcnQgeyBCYXNlTWV0cmljRmFjdG9yeVByb3BzIH0gZnJvbSBcIi4vQmFzZU1ldHJpY0ZhY3RvcnlcIjtcbmltcG9ydCB7IE1ldHJpY1N0YXRpc3RpYyB9IGZyb20gXCIuL01ldHJpY1N0YXRpc3RpY1wiO1xuaW1wb3J0IHsgTWV0cmljV2l0aEFsYXJtU3VwcG9ydCB9IGZyb20gXCIuL01ldHJpY1dpdGhBbGFybVN1cHBvcnRcIjtcbmltcG9ydCB7IFJhdGVDb21wdXRhdGlvbk1ldGhvZCB9IGZyb20gXCIuL1JhdGVDb21wdXRhdGlvbk1ldGhvZFwiO1xuXG4vKipcbiAqIFRoZSBtb3N0IGNvbW1vbiBkZWZhdWx0IG1ldHJpYyBwZXJpb2QgdXNlZCBhdCBBbWF6b24gaXMgY3VycmVudGx5IDUgbWludXRlcy5cbiAqL1xuZXhwb3J0IGNvbnN0IERlZmF1bHRNZXRyaWNQZXJpb2QgPSBEdXJhdGlvbi5taW51dGVzKDUpO1xuXG4vKipcbiAqIFRoZXNlIGFyZSB0aGUgZ2xvYmFscyB1c2VkIGZvciBlYWNoIG1ldHJpYywgdW5sZXNzIHRoZXJlIGlzIHNvbWUga2luZCBvZiBvdmVycmlkZS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBNZXRyaWNGYWN0b3J5RGVmYXVsdHMgZXh0ZW5kcyBCYXNlTWV0cmljRmFjdG9yeVByb3BzIHtcbiAgLyoqXG4gICAqIEVhY2ggbWV0cmljIGV4aXN0cyBpbiBhIG5hbWVzcGFjZS4gQVdTIFNlcnZpY2VzIGhhdmUgdGhlaXIgb3duIG5hbWVzcGFjZSwgYnV0IGhlcmUgeW91IGNhbiBzcGVjaWZ5IHlvdXIgY3VzdG9tIG9uZS5cbiAgICovXG4gIHJlYWRvbmx5IG5hbWVzcGFjZT86IHN0cmluZztcblxuICAvKipcbiAgICogTWV0cmljIHBlcmlvZC4gRGVmYXVsdCB2YWx1ZSBpcyB1c2VkIGlmIG5vdCBkZWZpbmVkLlxuICAgKiBAZGVmYXVsdCAtIERlZmF1bHRNZXRyaWNQZXJpb2RcbiAgICovXG4gIHJlYWRvbmx5IHBlcmlvZD86IER1cmF0aW9uO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIE1ldHJpY0ZhY3RvcnlQcm9wcyB7XG4gIC8qKlxuICAgKiBBbGxvd3MgeW91IHRvIHNwZWNpZnkgdGhlIGdsb2JhbCBkZWZhdWx0cywgd2hpY2ggY2FuIGJlIG92ZXJyaWRkZW4gaW4gdGhlIGluZGl2aWR1YWwgbWV0cmljcyBvciBhbGFybXMuXG4gICAqL1xuICByZWFkb25seSBnbG9iYWxEZWZhdWx0cz86IE1ldHJpY0ZhY3RvcnlEZWZhdWx0cztcbn1cblxuZXhwb3J0IGNsYXNzIE1ldHJpY0ZhY3Rvcnkge1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgZ2xvYmFsRGVmYXVsdHM6IE1ldHJpY0ZhY3RvcnlEZWZhdWx0cztcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IHNjb3BlOiBDb25zdHJ1Y3QgfCB1bmRlZmluZWQ7XG5cbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgcHJvcHM/OiBNZXRyaWNGYWN0b3J5UHJvcHMpIHtcbiAgICB0aGlzLmdsb2JhbERlZmF1bHRzID0gcHJvcHM/Lmdsb2JhbERlZmF1bHRzID8/IHt9O1xuICAgIHRoaXMuc2NvcGUgPSBzY29wZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGYWN0b3J5IG1ldGhvZCB0aGF0IGNyZWF0ZXMgYSBtZXRyaWMuIFRoZSBtZXRyaWMgcHJvcGVydGllcyB3aWxsIGFscmVhZHkgYmUgdXBkYXRlZCB0byBjb21wbHkgd2l0aCB0aGUgZ2xvYmFsIGRlZmF1bHRzLlxuICAgKlxuICAgKiBAcGFyYW0gbWV0cmljTmFtZSBtZXRyaWMgbmFtZVxuICAgKiBAcGFyYW0gc3RhdGlzdGljIGFnZ3JlZ2F0aW9uIHN0YXRpc3RpYyB0byB1c2VcbiAgICogQHBhcmFtIGxhYmVsIG1ldHJpYyBsYWJlbDsgaWYgdW5kZWZpbmVkLCBtZXRyaWMgbmFtZSBpcyB1c2VkIGJ5IENsb3VkV2F0Y2hcbiAgICogQHBhcmFtIGRpbWVuc2lvbnNNYXAgYWRkaXRpb25hbCBkaW1lbnNpb25zIHRvIGJlIGFkZGVkXG4gICAqIEBwYXJhbSBjb2xvciBtZXRyaWMgY29sb3I7IGlmIHVuZGVmaW5lZCwgdXNlcyBhIENsb3VkV2F0Y2ggcHJvdmlkZWQgY29sb3IgKHByZWZlcnJlZClcbiAgICogQHBhcmFtIG5hbWVzcGFjZSBzcGVjaWZ5IGEgY3VzdG9tIG5hbWVzcGFjZTsgaWYgdW5kZWZpbmVkLCB1c2VzIHRoZSBnbG9iYWwgZGVmYXVsdFxuICAgKiBAcGFyYW0gcGVyaW9kIHNwZWNpZnkgYSBjdXN0b20gcGVyaW9kOyBpZiB1bmRlZmluZWQsIHVzZXMgdGhlIGdsb2JhbCBkZWZhdWx0XG4gICAqIEBwYXJhbSByZWdpb24gc3BlY2lmeSBhIGN1c3RvbSByZWdpb247IGlmIHVuZGVmaW5lZCwgdXNlcyB0aGUgZ2xvYmFsIGRlZmF1bHRcbiAgICogQHBhcmFtIGFjY291bnQgc3BlY2lmeSBhIGN1c3RvbSBhY2NvdW50OyBpZiB1bmRlZmluZWQsIHVzZXMgdGhlIGdsb2JhbCBkZWZhdWx0XG4gICAqL1xuICBjcmVhdGVNZXRyaWMoXG4gICAgbWV0cmljTmFtZTogc3RyaW5nLFxuICAgIHN0YXRpc3RpYzogTWV0cmljU3RhdGlzdGljLFxuICAgIGxhYmVsPzogc3RyaW5nLFxuICAgIGRpbWVuc2lvbnNNYXA/OiBEaW1lbnNpb25zTWFwLFxuICAgIGNvbG9yPzogc3RyaW5nLFxuICAgIG5hbWVzcGFjZT86IHN0cmluZyxcbiAgICBwZXJpb2Q/OiBEdXJhdGlvbixcbiAgICByZWdpb24/OiBzdHJpbmcsXG4gICAgYWNjb3VudD86IHN0cmluZyxcbiAgKTogTWV0cmljV2l0aEFsYXJtU3VwcG9ydCB7XG4gICAgcmV0dXJuIG5ldyBNZXRyaWMoe1xuICAgICAgc3RhdGlzdGljLFxuICAgICAgbWV0cmljTmFtZSxcbiAgICAgIGxhYmVsLFxuICAgICAgY29sb3IsXG4gICAgICBkaW1lbnNpb25zTWFwOiBkaW1lbnNpb25zTWFwXG4gICAgICAgID8gdGhpcy5yZW1vdmVVbmRlZmluZWRFbnRyaWVzKGRpbWVuc2lvbnNNYXApXG4gICAgICAgIDogdW5kZWZpbmVkLFxuICAgICAgbmFtZXNwYWNlOiB0aGlzLmdldE5hbWVzcGFjZVdpdGhGYWxsYmFjayhuYW1lc3BhY2UpLFxuICAgICAgcGVyaW9kOiBwZXJpb2QgPz8gdGhpcy5nbG9iYWxEZWZhdWx0cy5wZXJpb2QgPz8gRGVmYXVsdE1ldHJpY1BlcmlvZCxcbiAgICAgIHJlZ2lvbjogdGhpcy5yZXNvbHZlUmVnaW9uKHJlZ2lvbiA/PyB0aGlzLmdsb2JhbERlZmF1bHRzLnJlZ2lvbiksXG4gICAgICBhY2NvdW50OiB0aGlzLnJlc29sdmVBY2NvdW50KGFjY291bnQgPz8gdGhpcy5nbG9iYWxEZWZhdWx0cy5hY2NvdW50KSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGYWN0b3J5IG1ldGhvZCB0aGF0IGNyZWF0ZXMgYSBtZXRyaWMgbWF0aCBleHByZXNzaW9uLiBUaGUgbWV0cmljIHByb3BlcnRpZXMgd2lsbCBhbHJlYWR5IGJlIHVwZGF0ZWQgdG8gY29tcGx5IHdpdGggdGhlIGdsb2JhbCBkZWZhdWx0cy5cbiAgICpcbiAgICogQHBhcmFtIGV4cHJlc3Npb24gQ2xvdWRXYXRjaCBtZXRyaWMgbWF0aCBleHByZXNzaW9uIChodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQW1hem9uQ2xvdWRXYXRjaC9sYXRlc3QvbW9uaXRvcmluZy91c2luZy1tZXRyaWMtbWF0aC5odG1sKVxuICAgKiBAcGFyYW0gdXNpbmdNZXRyaWNzIG1hcCBvZiBtZXRyaWNzLCB3aGVyZSBrZXlzIGFyZSBleHByZXNzaW9uIElEcyAodXNlZCBpbiB0aGUgZXhwcmVzc2lvbikgYW5kIHZhbHVlcyBhcmUgbWV0cmljc1xuICAgKiBAcGFyYW0gbGFiZWwgbWV0cmljIGxhYmVsIChyZXF1aXJlZCwgYXMgdGhlcmUgaXMgbm8gcmVhc29uYWJsZSBkZWZhdWx0KVxuICAgKiBAcGFyYW0gY29sb3IgbWV0cmljIGNvbG9yOyBpZiB1bmRlZmluZWQsIHVzZXMgYSBDbG91ZFdhdGNoIHByb3ZpZGVkIGNvbG9yIChwcmVmZXJyZWQpXG4gICAqIEBwYXJhbSBwZXJpb2Qgc3BlY2lmeSBhIGN1c3RvbSBwZXJpb2Q7IGlmIHVuZGVmaW5lZCwgdXNlcyB0aGUgZ2xvYmFsIGRlZmF1bHRcbiAgICogQHBhcmFtIHJlZ2lvbiAtLSBEZXByZWNhdGVkOiBVc2UgY3JlYXRlU2VhcmNoTWV0cmljIGlmIGRvaW5nIGNyb3NzIHJlZ2lvbiBzZWFyY2hcbiAgICogQHBhcmFtIGFjY291bnQgLS0gRGVwcmVjYXRlZDogVXNlIGNyZWF0ZVNlYXJjaE1ldHJpYyBpZiBkb2luZyBjcm9zcyByZWdpb24gc2VhcmNoXG4gICAqL1xuICBjcmVhdGVNZXRyaWNNYXRoKFxuICAgIGV4cHJlc3Npb246IHN0cmluZyxcbiAgICB1c2luZ01ldHJpY3M6IFJlY29yZDxzdHJpbmcsIElNZXRyaWM+LFxuICAgIGxhYmVsOiBzdHJpbmcsXG4gICAgY29sb3I/OiBzdHJpbmcsXG4gICAgcGVyaW9kPzogRHVyYXRpb24sXG4gICAgcmVnaW9uPzogc3RyaW5nLFxuICAgIGFjY291bnQ/OiBzdHJpbmcsXG4gICk6IE1ldHJpY1dpdGhBbGFybVN1cHBvcnQge1xuICAgIGlmIChyZWdpb24gfHwgYWNjb3VudCkge1xuICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICBcIidyZWdpb24nIGFuZCAnYWNjb3VudCcgaW5wdXRzIGFyZSBpZ25vcmVkLCBwbGVhc2UgdXNlICdjcmVhdGVTZWFyY2hNZXRyaWMnXCIsXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gbmV3IE1hdGhFeHByZXNzaW9uKHtcbiAgICAgIGxhYmVsLFxuICAgICAgY29sb3IsXG4gICAgICBleHByZXNzaW9uLFxuICAgICAgdXNpbmdNZXRyaWNzLFxuICAgICAgcGVyaW9kOiBwZXJpb2QgPz8gdGhpcy5nbG9iYWxEZWZhdWx0cy5wZXJpb2QgPz8gRGVmYXVsdE1ldHJpY1BlcmlvZCxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGYWN0b3J5IG1ldGhvZCB0aGF0IGNyZWF0ZXMgYSBtZXRyaWMgc2VhcmNoIHF1ZXJ5LiBUaGUgbWV0cmljIHByb3BlcnRpZXMgd2lsbCBhbHJlYWR5IGJlIHVwZGF0ZWQgdG8gY29tcGx5IHdpdGggdGhlIGdsb2JhbCBkZWZhdWx0cy5cbiAgICogSWYgeW91IHdhbnQgdG8gbWF0Y2ggXCJhbnkgdmFsdWVcIiBvZiBhIHNwZWNpZmljIGRpbWVuc2lvbiwgcGxlYXNlIHVzZSBgdW5kZWZpbmVkYCB2YWx1ZSByZXByZXNlbnRhdGlvbiBpbiB5b3VyIGNvbnN1bWVyIGxhbmd1YWdlLlxuICAgKiAoRm9yIGV4YW1wbGUsIGB1bmRlZmluZWQgYXMgYW55IGFzIHN0cmluZ2AgaW4gVHlwZVNjcmlwdCwgZHVlIHRvIEpTSUkgdHlwaW5nIHF1aXJrcy4pXG4gICAqXG4gICAqIEBwYXJhbSBxdWVyeSBtZXRyaWMgc2VhcmNoIHF1ZXJ5ICh0aGUgc2FtZSBhcyB0aGUgc2VhcmNoIHF1ZXJ5IHByb21wdCBpbiBDbG91ZFdhdGNoIEFXUyBDb25zb2xlKSwgaXQgbWlnaHQgYWxzbyBiZSBlbXB0eVxuICAgKiBAcGFyYW0gZGltZW5zaW9uc01hcCBkaW1lbnNpb25zLCBmdXJ0aGVyIG5hcnJvd2luZyB0aGUgc2VhcmNoIHJlc3VsdHM7IHVzZSBgdW5kZWZpbmVkYCBpZiB5b3Ugd2FudCB0byByZXByZXNlbnQgXCJhbnkgdmFsdWVcIiAoaW4gVFM6IGB1bmRlZmluZWQgYXMgYW55IGFzIHN0cmluZ2ApXG4gICAqIEBwYXJhbSBzdGF0aXN0aWMgYWdncmVnYXRpb24gc3RhdGlzdGljIHRvIHVzZVxuICAgKiBAcGFyYW0gbmFtZXNwYWNlIHNwZWNpZnkgYSBjdXN0b20gbmFtZXNwYWNlOyBpZiB1bmRlZmluZWQsIHVzZXMgdGhlIGdsb2JhbCBkZWZhdWx0XG4gICAqIEBwYXJhbSBsYWJlbCBzcGVjaWZ5IGN1c3RvbSBsYWJlbCBmb3Igc2VhcmNoIG1ldHJpY3M7IGRlZmF1bHQgaXMgXCIgXCIgYXMgaXQgY2Fubm90IGJlIGVtcHR5IHN0cmluZ1xuICAgKiBAcGFyYW0gcGVyaW9kIHNwZWNpZnkgYSBjdXN0b20gcGVyaW9kOyBpZiB1bmRlZmluZWQsIHVzZXMgdGhlIGdsb2JhbCBkZWZhdWx0XG4gICAqIEBwYXJhbSByZWdpb24gc3BlY2lmeSBhIGN1c3RvbSByZWdpb247IGlmIHVuZGVmaW5lZCwgdXNlcyB0aGUgZ2xvYmFsIGRlZmF1bHRcbiAgICogQHBhcmFtIGFjY291bnQgc3BlY2lmeSBhIGN1c3RvbSBhY2NvdW50OyBpZiB1bmRlZmluZWQsIHVzZXMgdGhlIGdsb2JhbCBkZWZhdWx0XG4gICAqL1xuICBjcmVhdGVNZXRyaWNTZWFyY2goXG4gICAgcXVlcnk6IHN0cmluZyxcbiAgICBkaW1lbnNpb25zTWFwOiBEaW1lbnNpb25zTWFwLFxuICAgIHN0YXRpc3RpYzogTWV0cmljU3RhdGlzdGljLFxuICAgIG5hbWVzcGFjZT86IHN0cmluZyxcbiAgICBsYWJlbD86IHN0cmluZyxcbiAgICBwZXJpb2Q/OiBEdXJhdGlvbixcbiAgICByZWdpb24/OiBzdHJpbmcsXG4gICAgYWNjb3VudD86IHN0cmluZyxcbiAgKTogTWF0aEV4cHJlc3Npb24ge1xuICAgIGNvbnN0IGZpbmFsUGVyaW9kID1cbiAgICAgIHBlcmlvZCA/PyB0aGlzLmdsb2JhbERlZmF1bHRzLnBlcmlvZCA/PyBEZWZhdWx0TWV0cmljUGVyaW9kO1xuICAgIGNvbnN0IHNlYXJjaE5hbWVzcGFjZSA9IHRoaXMuZ2V0TmFtZXNwYWNlV2l0aEZhbGxiYWNrKG5hbWVzcGFjZSk7XG4gICAgY29uc3QgbmFtZXNwYWNlc1dpdGhRdW90YXRpb25zID0gc2VhcmNoTmFtZXNwYWNlXG4gICAgICAuc3BsaXQoXCIsXCIpXG4gICAgICAubWFwKChuYW1lc3BhY2UpID0+IGBcIiR7bmFtZXNwYWNlLnRyaW0oKX1cImApO1xuICAgIGNvbnN0IGtleXNXaXRoUXVvdGF0aW9ucyA9IE9iamVjdC5rZXlzKGRpbWVuc2lvbnNNYXApLm1hcChcbiAgICAgIChrZXkpID0+IGBcIiR7a2V5fVwiYCxcbiAgICApO1xuICAgIGNvbnN0IG5hbWVzcGFjZVBsdXNEaW1lbnNpb25LZXlzID0gW1xuICAgICAgLi4ubmFtZXNwYWNlc1dpdGhRdW90YXRpb25zLFxuICAgICAgLi4ua2V5c1dpdGhRdW90YXRpb25zLFxuICAgIF0uam9pbihcIixcIik7XG4gICAgY29uc3QgbWV0cmljU2NoZW1hID0gYHske25hbWVzcGFjZVBsdXNEaW1lbnNpb25LZXlzfX1gO1xuXG4gICAgY29uc3QgZGltZW5zaW9uS2V5c0FuZFZhbHVlcyA9IE9iamVjdC5lbnRyaWVzKFxuICAgICAgdGhpcy5yZW1vdmVVbmRlZmluZWRFbnRyaWVzKGRpbWVuc2lvbnNNYXApLFxuICAgIClcbiAgICAgIC5tYXAoKFtrZXksIHZhbHVlXSkgPT4gYFwiJHtrZXl9XCI9XCIke3ZhbHVlfVwiYClcbiAgICAgIC5qb2luKFwiIFwiKTtcblxuICAgIGNvbnN0IGV4cHJlc3Npb24gPSBgU0VBUkNIKCcke21ldHJpY1NjaGVtYX0gJHtkaW1lbnNpb25LZXlzQW5kVmFsdWVzfSAke3F1ZXJ5fScsICcke3N0YXRpc3RpY30nLCAke2ZpbmFsUGVyaW9kLnRvU2Vjb25kcygpfSlgO1xuXG4gICAgcmV0dXJuIG5ldyBNYXRoRXhwcmVzc2lvbih7XG4gICAgICBleHByZXNzaW9uLFxuICAgICAgLy8gc2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9hd3MvYXdzLWNkay9pc3N1ZXMvNzIzN1xuICAgICAgdXNpbmdNZXRyaWNzOiB7fSxcbiAgICAgIC8vIGNhbm5vdCBiZSBhbiBlbXB0eSBzdHJpbmcgYW5kIHVuZGVmaW5lZCBpcyBubyBnb29kIGVpdGhlclxuICAgICAgbGFiZWw6IGxhYmVsID8/IFwiIFwiLFxuICAgICAgcGVyaW9kOiBmaW5hbFBlcmlvZCxcbiAgICAgIHNlYXJjaFJlZ2lvbjogdGhpcy5yZXNvbHZlUmVnaW9uKHJlZ2lvbiA/PyB0aGlzLmdsb2JhbERlZmF1bHRzLnJlZ2lvbiksXG4gICAgICBzZWFyY2hBY2NvdW50OiB0aGlzLnJlc29sdmVBY2NvdW50KFxuICAgICAgICBhY2NvdW50ID8/IHRoaXMuZ2xvYmFsRGVmYXVsdHMuYWNjb3VudCxcbiAgICAgICksXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogRmFjdG9yeSBtZXRob2QgdGhhdCBjcmVhdGVzIGFub21hbHkgZGV0ZWN0aW9uIG9uIGEgbWV0cmljLlxuICAgKiBBbm9tYWx5IG9jY3VycyB3aGVuZXZlciBhIG1ldHJpYyB2YWx1ZSBmYWxscyBvdXRzaWRlIG9mIGEgcHJlY29tcHV0ZWQgcmFuZ2Ugb2YgcHJlZGljdGVkIHZhbHVlcy5cbiAgICogVGhlIGRldGVjdGlvbiBkb2VzIG5vdCBuZWVkIGFueSBzZXR1cC4gVGhlIG1vZGVsIHdpbGwgc3RhcnQgbGVhcm5pbmcgYXV0b21hdGljYWxseSBhbmQgc2hvdWxkIGJlIHJlYWR5IGluIGEgZmV3IG1pbnV0ZXMuXG4gICAqIFVzdWFsbHksIHRoZSBhbm9tYWx5IGRldGVjdGlvbiBpcyBwYWlyZWQgd2l0aCBhbiBhbGFybS5cbiAgICogQHNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQW1hem9uQ2xvdWRXYXRjaC9sYXRlc3QvbW9uaXRvcmluZy9DbG91ZFdhdGNoX0Fub21hbHlfRGV0ZWN0aW9uLmh0bWxcbiAgICpcbiAgICogQHBhcmFtIG1ldHJpYyBtZXRyaWMgdG8gZGV0ZWN0IGFub21hbHkgZGV0ZWN0aW9uIG9mXG4gICAqIEBwYXJhbSBzdGRldiBzdGFuZGFyZCBkZXZpYXRpb24sIGJhc2ljYWxseSB0aGUgdG9sZXJhbmNlIC8gYmFuZCB0aGlja25lc3NcbiAgICogQHBhcmFtIGxhYmVsIG1ldHJpYyBsYWJlbCAocmVxdWlyZWQsIGFzIHRoZXJlIGlzIG5vIHJlYXNvbmFibGUgZGVmYXVsdClcbiAgICogQHBhcmFtIGNvbG9yIG1ldHJpYyBjb2xvcjsgaWYgdW5kZWZpbmVkLCB1c2VzIGEgQ2xvdWRXYXRjaCBwcm92aWRlZCBjb2xvciAocHJlZmVycmVkKVxuICAgKiBAcGFyYW0gZXhwcmVzc2lvbklkIGV4cHJlc3Npb24gSUQgb2YgdGhlIG1ldHJpYzsgdXNlcyBgbTFgIGlmIHVuZGVmaW5lZFxuICAgKiBAcGFyYW0gcGVyaW9kIHNwZWNpZnkgYSBjdXN0b20gcGVyaW9kOyBpZiB1bmRlZmluZWQsIHVzZXMgdGhlIGdsb2JhbCBkZWZhdWx0XG4gICAqIEBwYXJhbSByZWdpb24gc3BlY2lmeSBhIGN1c3RvbSByZWdpb247IGlmIHVuZGVmaW5lZCwgdXNlcyB0aGUgZ2xvYmFsIGRlZmF1bHRcbiAgICogQHBhcmFtIGFjY291bnQgc3BlY2lmeSBhIGN1c3RvbSBhY2NvdW50OyBpZiB1bmRlZmluZWQsIHVzZXMgdGhlIGdsb2JhbCBkZWZhdWx0XG4gICAqL1xuICBjcmVhdGVNZXRyaWNBbm9tYWx5RGV0ZWN0aW9uKFxuICAgIG1ldHJpYzogSU1ldHJpYyxcbiAgICBzdGRldjogbnVtYmVyLFxuICAgIGxhYmVsOiBzdHJpbmcsXG4gICAgY29sb3I/OiBzdHJpbmcsXG4gICAgZXhwcmVzc2lvbklkPzogc3RyaW5nLFxuICAgIHBlcmlvZD86IER1cmF0aW9uLFxuICAgIHJlZ2lvbj86IHN0cmluZyxcbiAgICBhY2NvdW50Pzogc3RyaW5nLFxuICApOiBNZXRyaWNXaXRoQWxhcm1TdXBwb3J0IHtcbiAgICBjb25zdCBmaW5hbEV4cHJlc3Npb25JZCA9IGV4cHJlc3Npb25JZCA/PyBcIm0xXCI7XG4gICAgY29uc3QgdXNpbmdNZXRyaWNzOiBSZWNvcmQ8c3RyaW5nLCBJTWV0cmljPiA9IHt9O1xuICAgIHVzaW5nTWV0cmljc1tmaW5hbEV4cHJlc3Npb25JZF0gPSBtZXRyaWM7XG4gICAgcmV0dXJuIG5ldyBBbm9tYWx5RGV0ZWN0aW9uTWF0aEV4cHJlc3Npb24oe1xuICAgICAgbGFiZWwsXG4gICAgICBjb2xvcixcbiAgICAgIHVzaW5nTWV0cmljcyxcbiAgICAgIGV4cHJlc3Npb246IGBBTk9NQUxZX0RFVEVDVElPTl9CQU5EKCR7ZmluYWxFeHByZXNzaW9uSWR9LCR7c3RkZXZ9KWAsXG4gICAgICBwZXJpb2Q6IHBlcmlvZCA/PyB0aGlzLmdsb2JhbERlZmF1bHRzLnBlcmlvZCA/PyBEZWZhdWx0TWV0cmljUGVyaW9kLFxuICAgICAgc2VhcmNoUmVnaW9uOiB0aGlzLnJlc29sdmVSZWdpb24ocmVnaW9uID8/IHRoaXMuZ2xvYmFsRGVmYXVsdHMucmVnaW9uKSxcbiAgICAgIHNlYXJjaEFjY291bnQ6IHRoaXMucmVzb2x2ZUFjY291bnQoXG4gICAgICAgIGFjY291bnQgPz8gdGhpcy5nbG9iYWxEZWZhdWx0cy5hY2NvdW50LFxuICAgICAgKSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGFwdHMgcHJvcGVydGllcyBvZiBhIGZvcmVpZ24gbWV0cmljIChtZXRyaWMgY3JlYXRlZCBvdXRzaWRlIG9mIHRoaXMgbWV0cmljIGZhY3RvcnkpIHRvIGNvbXBseSB3aXRoIHRoZSBnbG9iYWwgZGVmYXVsdHMuXG4gICAqIE1pZ2h0IG1vZGlmeSBuYW1lc3BhY2UgYW5kIG1ldHJpYyBwZXJpb2QuXG4gICAqXG4gICAqIEBwYXJhbSBtZXRyaWMgbWV0cmljIHRvIGJlIGFkYXB0ZWRcbiAgICovXG4gIGFkYXB0TWV0cmljKG1ldHJpYzogTWV0cmljV2l0aEFsYXJtU3VwcG9ydCk6IE1ldHJpY1dpdGhBbGFybVN1cHBvcnQge1xuICAgIGlmICh0aGlzLmdsb2JhbERlZmF1bHRzLnJlZ2lvbikge1xuICAgICAgbWV0cmljID0gbWV0cmljLndpdGgoeyByZWdpb246IHRoaXMuZ2xvYmFsRGVmYXVsdHMucmVnaW9uIH0pO1xuICAgIH1cblxuICAgIGlmICh0aGlzLmdsb2JhbERlZmF1bHRzLmFjY291bnQpIHtcbiAgICAgIG1ldHJpYyA9IG1ldHJpYy53aXRoKHsgYWNjb3VudDogdGhpcy5nbG9iYWxEZWZhdWx0cy5hY2NvdW50IH0pO1xuICAgIH1cblxuICAgIHJldHVybiBtZXRyaWMud2l0aCh7XG4gICAgICBwZXJpb2Q6IHRoaXMuZ2xvYmFsRGVmYXVsdHMucGVyaW9kID8/IERlZmF1bHRNZXRyaWNQZXJpb2QsXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQWRhcHRzIHByb3BlcnRpZXMgb2YgYSBmb3JlaWduIG1ldHJpYyAobWV0cmljIGNyZWF0ZWQgb3V0c2lkZSBvZiB0aGlzIG1ldHJpYyBmYWN0b3J5KSB0byBjb21wbHkgd2l0aCB0aGUgZ2xvYmFsIGRlZmF1bHRzLlxuICAgKiBNaWdodCBtb2RpZnkgbmFtZXNwYWNlLiBQcmVzZXJ2ZXMgbWV0cmljIHBlcmlvZC5cbiAgICpcbiAgICogQHBhcmFtIG1ldHJpYyBtZXRyaWMgdG8gYmUgYWRhcHRlZFxuICAgKi9cbiAgYWRhcHRNZXRyaWNQcmVzZXJ2aW5nUGVyaW9kKFxuICAgIG1ldHJpYzogTWV0cmljV2l0aEFsYXJtU3VwcG9ydCxcbiAgKTogTWV0cmljV2l0aEFsYXJtU3VwcG9ydCB7XG4gICAgcmV0dXJuIG1ldHJpYztcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgbWV0cmljIG1hdGggZXhwcmVzc2lvbiB0aGF0IG11bHRpcGxpZXMgdGhlIGdpdmVuIG1ldHJpYyBieSBnaXZlbiBjb2VmZmljaWVudC5cbiAgICogRG9lcyBub3RoaW5nIGlmIHRoZSBtdWx0aXBsaWVyIGlzIG9uZS4gUHJlc2VydmVzIHRoZSBtZXRyaWMgcGVyaW9kLlxuICAgKlxuICAgKiBAcGFyYW0gbWV0cmljIG1ldHJpYyB0byBtdWx0aXBseVxuICAgKiBAcGFyYW0gbXVsdGlwbGllciBtdWx0aXBsaWVyIChtdXN0IGJlID4gMSlcbiAgICogQHBhcmFtIGxhYmVsIGV4cHJlc3Npb24gbGFiZWxcbiAgICogQHBhcmFtIGV4cHJlc3Npb25JZCBleHByZXNzaW9uIElEIG9mIHRoZSBtZXRyaWM7IHVzZXMgYG0xYCBpZiB1bmRlZmluZWRcbiAgICovXG4gIG11bHRpcGx5TWV0cmljKFxuICAgIG1ldHJpYzogTWV0cmljV2l0aEFsYXJtU3VwcG9ydCxcbiAgICBtdWx0aXBsaWVyOiBudW1iZXIsXG4gICAgbGFiZWw6IHN0cmluZyxcbiAgICBleHByZXNzaW9uSWQ/OiBzdHJpbmcsXG4gICk6IE1ldHJpY1dpdGhBbGFybVN1cHBvcnQge1xuICAgIGlmIChtdWx0aXBsaWVyID09IDEpIHtcbiAgICAgIHJldHVybiBtZXRyaWM7XG4gICAgfSBlbHNlIGlmIChtdWx0aXBsaWVyIDwgMSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTXVsdGlwbGllciBtdXN0IGJlIGdyZWF0ZXIgdGhhbiBvbmUuXCIpO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBmaW5hbEV4cHJlc3Npb25JZCA9IGV4cHJlc3Npb25JZCA/PyBcIm0xXCI7XG4gICAgICBjb25zdCB1c2luZ01ldHJpY3M6IFJlY29yZDxzdHJpbmcsIElNZXRyaWM+ID0ge307XG4gICAgICB1c2luZ01ldHJpY3NbZmluYWxFeHByZXNzaW9uSWRdID0gbWV0cmljO1xuICAgICAgcmV0dXJuIHRoaXMuY3JlYXRlTWV0cmljTWF0aChcbiAgICAgICAgYCR7ZmluYWxFeHByZXNzaW9uSWR9ICogJHttdWx0aXBsaWVyfWAsXG4gICAgICAgIHVzaW5nTWV0cmljcyxcbiAgICAgICAgbGFiZWwsXG4gICAgICAgIG1ldHJpYy5jb2xvcixcbiAgICAgICAgbWV0cmljLnBlcmlvZCxcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBtZXRyaWMgbWF0aCBleHByZXNzaW9uIHRoYXQgZGl2aWRlcyB0aGUgZ2l2ZW4gbWV0cmljIGJ5IGdpdmVuIGNvZWZmaWNpZW50LlxuICAgKiBEb2VzIG5vdGhpbmcgaWYgdGhlIGRpdmlzb3IgaXMgb25lLiBQcmVzZXJ2ZXMgdGhlIG1ldHJpYyBwZXJpb2QuXG4gICAqXG4gICAqIEBwYXJhbSBtZXRyaWMgbWV0cmljIHRvIG11bHRpcGx5XG4gICAqIEBwYXJhbSBkaXZpc29yIGRpdmlzb3IgKG11c3QgYmUgPiAxKVxuICAgKiBAcGFyYW0gbGFiZWwgZXhwcmVzc2lvbiBsYWJlbFxuICAgKiBAcGFyYW0gZXhwcmVzc2lvbklkIGV4cHJlc3Npb24gSUQgb2YgdGhlIG1ldHJpYzsgdXNlcyBgbTFgIGlmIHVuZGVmaW5lZFxuICAgKi9cbiAgZGl2aWRlTWV0cmljKFxuICAgIG1ldHJpYzogTWV0cmljV2l0aEFsYXJtU3VwcG9ydCxcbiAgICBkaXZpc29yOiBudW1iZXIsXG4gICAgbGFiZWw6IHN0cmluZyxcbiAgICBleHByZXNzaW9uSWQ/OiBzdHJpbmcsXG4gICk6IE1ldHJpY1dpdGhBbGFybVN1cHBvcnQge1xuICAgIGlmIChkaXZpc29yID09IDEpIHtcbiAgICAgIHJldHVybiBtZXRyaWM7XG4gICAgfSBlbHNlIGlmIChkaXZpc29yIDwgMSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiRGl2aXNvciBtdXN0IGJlIGdyZWF0ZXIgdGhhbiBvbmUuXCIpO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBmaW5hbEV4cHJlc3Npb25JZCA9IGV4cHJlc3Npb25JZCA/PyBcIm0xXCI7XG4gICAgICBjb25zdCB1c2luZ01ldHJpY3M6IFJlY29yZDxzdHJpbmcsIElNZXRyaWM+ID0ge307XG4gICAgICB1c2luZ01ldHJpY3NbZmluYWxFeHByZXNzaW9uSWRdID0gbWV0cmljO1xuICAgICAgcmV0dXJuIHRoaXMuY3JlYXRlTWV0cmljTWF0aChcbiAgICAgICAgYCR7ZmluYWxFeHByZXNzaW9uSWR9IC8gJHtkaXZpc29yfWAsXG4gICAgICAgIHVzaW5nTWV0cmljcyxcbiAgICAgICAgbGFiZWwsXG4gICAgICAgIG1ldHJpYy5jb2xvcixcbiAgICAgICAgbWV0cmljLnBlcmlvZCxcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBtZXRyaWMgbWF0aCBleHByZXNzaW9uIHRoYXQgY29tcHV0ZXMgYSByYXRlIGZyb20gYSByZWd1bGFyIG1ldHJpYy5cbiAgICogRm9yIGV4YW1wbGUsIGl0IGFsbG93cyB5b3UgdG8gY29tcHV0ZSByYXRlIHBlciBzZWNvbmQgKFRQUyksIHBlciBtaW51dGUsIG9yIGp1c3QgYW4gYXZlcmFnZSBvZiB5b3VyIHRyYW5zYWN0aW9ucy5cbiAgICpcbiAgICogQHBhcmFtIG1ldHJpYyBtZXRyaWMgdG8gY2FsY3VsYXRlIHRoZSByYXRlIGZyb21cbiAgICogQHBhcmFtIG1ldGhvZCByYXRlIGNvbXB1dGF0aW9uIG1ldGhvZFxuICAgKiBAcGFyYW0gYWRkU3RhdHNUb0xhYmVsIGFkZCBkZXRhaWxlZCBzdGF0aXN0aWNzIChtaW4sIG1heCwgYXZlcmFnZSkgdG8gdGhlIGxhYmVsXG4gICAqIEBwYXJhbSBleHByZXNzaW9uSWQgZXhwcmVzc2lvbiBJRCBvZiB0aGUgbWV0cmljOyB1c2VzIGBtMWAgaWYgdW5kZWZpbmVkXG4gICAqIEBwYXJhbSBmaWxsV2l0aFplcm9lcyBpZiBUUlVFLCB0aGUgZmluYWwgbWV0cmljIHdpbGwgYmUgemVyby1maWxsZWQgKDAgb24gbm8gZGF0YSk7IGZhbHNlIGlmIHVuZGVmaW5lZFxuICAgKi9cbiAgdG9SYXRlKFxuICAgIG1ldHJpYzogTWV0cmljV2l0aEFsYXJtU3VwcG9ydCxcbiAgICBtZXRob2Q6IFJhdGVDb21wdXRhdGlvbk1ldGhvZCxcbiAgICBhZGRTdGF0c1RvTGFiZWw/OiBib29sZWFuLFxuICAgIGV4cHJlc3Npb25JZD86IHN0cmluZyxcbiAgICBmaWxsV2l0aFplcm9lcz86IGJvb2xlYW4sXG4gICk6IE1ldHJpY1dpdGhBbGFybVN1cHBvcnQge1xuICAgIGNvbnN0IGZpbmFsRXhwcmVzc2lvbklkID0gZXhwcmVzc2lvbklkID8/IFwibTFcIjtcbiAgICBjb25zdCBsYWJlbFByZWZpeCA9IG1ldHJpYy5sYWJlbCA/PyBcIlJhdGVcIjtcblxuICAgIGNvbnN0IHN0YXRzSW5MYWJlbDogc3RyaW5nW10gPSBbXTtcbiAgICBpZiAoYWRkU3RhdHNUb0xhYmVsID8/IGZhbHNlKSB7XG4gICAgICBzdGF0c0luTGFiZWwucHVzaChcIm1pbjogJHtNSU59XCIpO1xuICAgICAgc3RhdHNJbkxhYmVsLnB1c2goXCJtYXg6ICR7TUFYfVwiKTtcbiAgICAgIGlmIChtZXRob2QgIT09IFJhdGVDb21wdXRhdGlvbk1ldGhvZC5BVkVSQUdFKSB7XG4gICAgICAgIC8vIG9ubHkgYWRkIGF2ZXJhZ2UgaWYgZG8gbm90IGhhdmUgaXQgYWxyZWFkeVxuICAgICAgICBzdGF0c0luTGFiZWwucHVzaChcImF2ZzogJHtBVkd9XCIpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IGZpbmFsRXhwcmVzc2lvbklkWmVyb2VkID1cbiAgICAgIGZpbGxXaXRoWmVyb2VzID8/IGZhbHNlXG4gICAgICAgID8gYEZJTEwoJHtmaW5hbEV4cHJlc3Npb25JZH0sMClgXG4gICAgICAgIDogZmluYWxFeHByZXNzaW9uSWQ7XG4gICAgY29uc3QgbGFiZWxBcHBlbmRpeCA9XG4gICAgICBzdGF0c0luTGFiZWwubGVuZ3RoID4gMCA/IGAgKCR7c3RhdHNJbkxhYmVsLmpvaW4oXCIsIFwiKX0pYCA6IFwiXCI7XG5cbiAgICBzd2l0Y2ggKG1ldGhvZCkge1xuICAgICAgY2FzZSBSYXRlQ29tcHV0YXRpb25NZXRob2QuQVZFUkFHRTpcbiAgICAgICAgY29uc3QgYXZnTGFiZWwgPSBgJHtsYWJlbFByZWZpeH0gKGF2Zykke2xhYmVsQXBwZW5kaXh9YDtcbiAgICAgICAgY29uc3QgYXZnTWV0cmljID0gbWV0cmljLndpdGgoe1xuICAgICAgICAgIGxhYmVsOiBhdmdMYWJlbCxcbiAgICAgICAgICBzdGF0aXN0aWM6IE1ldHJpY1N0YXRpc3RpYy5BVkVSQUdFLFxuICAgICAgICB9KTtcbiAgICAgICAgaWYgKGZpbGxXaXRoWmVyb2VzID8/IGZhbHNlKSB7XG4gICAgICAgICAgcmV0dXJuIHRoaXMuY3JlYXRlTWV0cmljTWF0aChcbiAgICAgICAgICAgIGZpbmFsRXhwcmVzc2lvbklkWmVyb2VkLFxuICAgICAgICAgICAgeyBbZmluYWxFeHByZXNzaW9uSWRdOiBhdmdNZXRyaWMgfSxcbiAgICAgICAgICAgIGF2Z0xhYmVsLFxuICAgICAgICAgICAgYXZnTWV0cmljLmNvbG9yLFxuICAgICAgICAgICAgYXZnTWV0cmljLnBlcmlvZCxcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBhdmdNZXRyaWM7XG4gICAgICBjYXNlIFJhdGVDb21wdXRhdGlvbk1ldGhvZC5QRVJfU0VDT05EOlxuICAgICAgICBsZXQgcGVyU2Vjb25kTGFiZWwgPSBgJHtsYWJlbFByZWZpeH0vcyR7bGFiZWxBcHBlbmRpeH1gO1xuICAgICAgICBpZiAoXG4gICAgICAgICAgbGFiZWxQcmVmaXggPT09IFwiUmVxdWVzdHNcIiB8fFxuICAgICAgICAgIGxhYmVsUHJlZml4ID09PSBcIkludm9jYXRpb25zXCIgfHxcbiAgICAgICAgICBsYWJlbFByZWZpeCA9PT0gXCJUcmFuc2FjdGlvbnNcIlxuICAgICAgICApIHtcbiAgICAgICAgICAvLyBjdXJyZW50bHksIGtlcHQgYXMgXCJUUFNcIiB0byByZWR1Y2UgbnVtYmVyIG9mIHNuYXBzaG90IGNoYW5nZXNcbiAgICAgICAgICBwZXJTZWNvbmRMYWJlbCA9IGBUUFMke2xhYmVsQXBwZW5kaXh9YDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5jcmVhdGVNZXRyaWNNYXRoKFxuICAgICAgICAgIGAke2ZpbmFsRXhwcmVzc2lvbklkWmVyb2VkfSAvIFBFUklPRCgke2ZpbmFsRXhwcmVzc2lvbklkfSlgLFxuICAgICAgICAgIHsgW2ZpbmFsRXhwcmVzc2lvbklkXTogbWV0cmljIH0sXG4gICAgICAgICAgcGVyU2Vjb25kTGFiZWwsXG4gICAgICAgICAgbWV0cmljLmNvbG9yLFxuICAgICAgICAgIG1ldHJpYy5wZXJpb2QsXG4gICAgICAgICk7XG4gICAgICBjYXNlIFJhdGVDb21wdXRhdGlvbk1ldGhvZC5QRVJfTUlOVVRFOlxuICAgICAgICByZXR1cm4gdGhpcy5jcmVhdGVNZXRyaWNNYXRoKFxuICAgICAgICAgIGAoNjAgKiAke2ZpbmFsRXhwcmVzc2lvbklkWmVyb2VkfSkgLyBQRVJJT0QoJHtmaW5hbEV4cHJlc3Npb25JZH0pYCxcbiAgICAgICAgICB7IFtmaW5hbEV4cHJlc3Npb25JZF06IG1ldHJpYyB9LFxuICAgICAgICAgIGAke2xhYmVsUHJlZml4fS9tJHtsYWJlbEFwcGVuZGl4fWAsXG4gICAgICAgICAgbWV0cmljLmNvbG9yLFxuICAgICAgICAgIG1ldHJpYy5wZXJpb2QsXG4gICAgICAgICk7XG4gICAgICBjYXNlIFJhdGVDb21wdXRhdGlvbk1ldGhvZC5QRVJfSE9VUjpcbiAgICAgICAgcmV0dXJuIHRoaXMuY3JlYXRlTWV0cmljTWF0aChcbiAgICAgICAgICBgKDM2MDAgKiAke2ZpbmFsRXhwcmVzc2lvbklkWmVyb2VkfSkgLyBQRVJJT0QoJHtmaW5hbEV4cHJlc3Npb25JZH0pYCxcbiAgICAgICAgICB7IFtmaW5hbEV4cHJlc3Npb25JZF06IG1ldHJpYyB9LFxuICAgICAgICAgIGAke2xhYmVsUHJlZml4fS9oJHtsYWJlbEFwcGVuZGl4fWAsXG4gICAgICAgICAgbWV0cmljLmNvbG9yLFxuICAgICAgICAgIG1ldHJpYy5wZXJpb2QsXG4gICAgICAgICk7XG4gICAgICBjYXNlIFJhdGVDb2