UNPKG

21.7 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.MetricSet = exports.allMetricsGraphJson = void 0;
4const drop_empty_object_at_the_end_of_an_array_token_1 = require("./drop-empty-object-at-the-end-of-an-array-token");
5const env_tokens_1 = require("./env-tokens");
6const metric_util_1 = require("./metric-util");
7const object_1 = require("./object");
8/**
9 * Return the JSON structure which represents these metrics in a graph.
10 *
11 * Depending on the metric type (stat or expression), one `Metric` object
12 * can render to multiple time series.
13 *
14 * - Top-level metrics will be rendered visibly, additionally added metrics will
15 * be rendered invisibly.
16 * - IDs used in math expressions need to be either globally unique, or refer to the same
17 * metric object.
18 *
19 * This will be called by GraphWidget, no need for clients to call this.
20 */
21function allMetricsGraphJson(left, right) {
22 // Add metrics to a set which will automatically expand them recursively,
23 // making sure to retain conflicting the visible one on conflicting metrics objects.
24 const mset = new MetricSet();
25 mset.addTopLevel('left', ...left);
26 mset.addTopLevel('right', ...right);
27 // Render all metrics from the set.
28 return mset.entries.map(entry => new drop_empty_object_at_the_end_of_an_array_token_1.DropEmptyObjectAtTheEndOfAnArray(metricGraphJson(entry.metric, entry.tag, entry.id)));
29}
30exports.allMetricsGraphJson = allMetricsGraphJson;
31function metricGraphJson(metric, yAxis, id) {
32 const config = metric.toMetricConfig();
33 const ret = [];
34 const options = { ...config.renderingProperties };
35 metric_util_1.dispatchMetric(metric, {
36 withStat(stat) {
37 ret.push(stat.namespace, stat.metricName);
38 // Dimensions
39 for (const dim of (stat.dimensions || [])) {
40 ret.push(dim.name, dim.value);
41 }
42 // Metric attributes that are rendered to graph options
43 if (stat.account) {
44 options.accountId = env_tokens_1.accountIfDifferentFromStack(stat.account);
45 }
46 if (stat.region) {
47 options.region = env_tokens_1.regionIfDifferentFromStack(stat.region);
48 }
49 if (stat.period && stat.period.toSeconds() !== 300) {
50 options.period = stat.period.toSeconds();
51 }
52 if (stat.statistic && stat.statistic !== 'Average') {
53 options.stat = stat.statistic;
54 }
55 },
56 withExpression(expr) {
57 options.expression = expr.expression;
58 if (expr.searchAccount) {
59 options.accountId = env_tokens_1.accountIfDifferentFromStack(expr.searchAccount);
60 }
61 if (expr.searchRegion) {
62 options.region = env_tokens_1.regionIfDifferentFromStack(expr.searchRegion);
63 }
64 if (expr.period && expr.period !== 300) {
65 options.period = expr.period;
66 }
67 },
68 });
69 // Options
70 if (!yAxis) {
71 options.visible = false;
72 }
73 if (yAxis !== 'left') {
74 options.yAxis = yAxis;
75 }
76 if (id) {
77 options.id = id;
78 }
79 if (options.visible !== false && options.expression && !options.label) {
80 // Label may be '' or undefined.
81 //
82 // If undefined, we'll render the expression as the label, to suppress
83 // the default behavior of CW where it would render the metric
84 // id as label, which we (inelegantly) generate to be something like "metric_alias0".
85 //
86 // For array expressions (returning more than 1 TS) users may sometimes want to
87 // suppress the label completely. For those cases, we'll accept the empty string,
88 // and not render a label at all.
89 options.label = options.label === '' ? undefined : metric.toString();
90 }
91 const renderedOpts = object_1.dropUndefined(options);
92 if (Object.keys(renderedOpts).length !== 0) {
93 ret.push(renderedOpts);
94 }
95 return ret;
96}
97/**
98 * Contain a set of metrics, expanding math expressions
99 *
100 * "Primary" metrics (added via a top-level call) can be tagged with an additional value.
101 */
102class MetricSet {
103 constructor() {
104 this.metrics = new Array();
105 this.metricById = new Map();
106 this.metricByKey = new Map();
107 }
108 /**
109 * Add the given set of metrics to this set
110 */
111 addTopLevel(tag, ...metrics) {
112 for (const metric of metrics) {
113 this.addOne(metric, tag);
114 }
115 }
116 /**
117 * Access all the accumulated timeseries entries
118 */
119 get entries() {
120 return this.metrics;
121 }
122 /**
123 * Add a metric into the set
124 *
125 * The id may not be the same as a previous metric added, unless it's the same metric.
126 *
127 * It can be made visible, in which case the new "metric" object replaces the old
128 * one (and the new ones "renderingPropertieS" will be honored instead of the old
129 * one's).
130 */
131 addOne(metric, tag, id) {
132 const key = metric_util_1.metricKey(metric);
133 let existingEntry;
134 // Try lookup existing by id if we have one
135 if (id) {
136 existingEntry = this.metricById.get(id);
137 if (existingEntry && metric_util_1.metricKey(existingEntry.metric) !== key) {
138 throw new Error(`Cannot have two different metrics share the same id ('${id}') in one Alarm or Graph. Rename one of them.`);
139 }
140 }
141 if (!existingEntry) {
142 // Try lookup by metric if we didn't find one by id
143 existingEntry = this.metricByKey.get(key);
144 // If the one we found already has an id, it must be different from the id
145 // we're trying to add and we want to add a new metric. Pretend we didn't
146 // find one.
147 if (existingEntry?.id && id) {
148 existingEntry = undefined;
149 }
150 }
151 // Create a new entry if we didn't find one so far
152 let entry;
153 if (existingEntry) {
154 entry = existingEntry;
155 }
156 else {
157 entry = { metric };
158 this.metrics.push(entry);
159 this.metricByKey.set(key, entry);
160 }
161 // If it didn't have an id but now we do, add one
162 if (!entry.id && id) {
163 entry.id = id;
164 this.metricById.set(id, entry);
165 }
166 // If it didn't have a tag but now we do, add one
167 if (!entry.tag && tag) {
168 entry.tag = tag;
169 }
170 // Recurse and add children
171 const conf = metric.toMetricConfig();
172 if (conf.mathExpression) {
173 for (const [subId, subMetric] of Object.entries(conf.mathExpression.usingMetrics)) {
174 this.addOne(subMetric, undefined, subId);
175 }
176 }
177 }
178}
179exports.MetricSet = MetricSet;
180//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVuZGVyaW5nLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsicmVuZGVyaW5nLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUNBLHFIQUFvRztBQUNwRyw2Q0FBdUY7QUFDdkYsK0NBQTBEO0FBQzFELHFDQUF5QztBQUV6Qzs7Ozs7Ozs7Ozs7O0dBWUc7QUFDSCxTQUFnQixtQkFBbUIsQ0FBQyxJQUFlLEVBQUUsS0FBZ0I7SUFDbkUseUVBQXlFO0lBQ3pFLG9GQUFvRjtJQUNwRixNQUFNLElBQUksR0FBRyxJQUFJLFNBQVMsRUFBVSxDQUFDO0lBQ3JDLElBQUksQ0FBQyxXQUFXLENBQUMsTUFBTSxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFDbEMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLEVBQUUsR0FBRyxLQUFLLENBQUMsQ0FBQztJQUVwQyxtQ0FBbUM7SUFDbkMsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksaUZBQWdDLENBQUMsZUFBZSxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUUsS0FBSyxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQzdILENBQUM7QUFURCxrREFTQztBQUVELFNBQVMsZUFBZSxDQUFDLE1BQWUsRUFBRSxLQUFjLEVBQUUsRUFBVztJQUNuRSxNQUFNLE1BQU0sR0FBRyxNQUFNLENBQUMsY0FBYyxFQUFFLENBQUM7SUFFdkMsTUFBTSxHQUFHLEdBQVUsRUFBRSxDQUFDO0lBQ3RCLE1BQU0sT0FBTyxHQUFRLEVBQUUsR0FBRyxNQUFNLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztJQUV2RCw0QkFBYyxDQUFDLE1BQU0sRUFBRTtRQUNyQixRQUFRLENBQUMsSUFBSTtZQUNYLEdBQUcsQ0FBQyxJQUFJLENBQ04sSUFBSSxDQUFDLFNBQVMsRUFDZCxJQUFJLENBQUMsVUFBVSxDQUNoQixDQUFDO1lBRUYsYUFB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YUFBYSxFQUFFO1lBQ2pCLEtBQUssR0FBRyxhQUFhLENBQUM7U0FDdkI7YUFBTTtZQUNMLEtBQUssR0FBRyxFQUFFLE1BQU0sRUFBRSxDQUFDO1lBQ25CLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ3pCLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsQ0FBQztTQUNsQztRQUVELGlEQUFpRDtRQUNqRCxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsSUFBSSxFQUFFLEVBQUU7WUFDbkIsS0FBSyxDQUFDLEVBQUUsR0FBRyxFQUFFLENBQUM7WUFDZCxJQUFJLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsS0FBSyxDQUFDLENBQUM7U0FDaEM7UUFFRCxpREFBaUQ7UUFDakQsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLElBQUksR0FBRyxFQUFFO1lBQ3JCLEtBQUssQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDO1NBQ2pCO1FBRUQsMkJBQTJCO1FBQzNCLE1BQU0sSUFBSSxHQUFHLE1BQU0sQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUNyQyxJQUFJLElBQUksQ0FBQyxjQUFjLEVBQUU7WUFDdkIsS0FBSyxNQUFNLENBQUMsS0FBSyxFQUFFLFNBQVMsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxZQUFZLENBQUMsRUFBRTtnQkFDakYsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsU0FBUyxFQUFFLEtBQUssQ0FBQyxDQUFDO2FBQzFDO1NBQ0Y7S0FDRjtDQUNGO0FBbEZELDhCQWtGQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IElNZXRyaWMgfSBmcm9tICcuLi9tZXRyaWMtdHlwZXMnO1xuaW1wb3J0IHsgRHJvcEVtcHR5T2JqZWN0QXRUaGVFbmRPZkFuQXJyYXkgfSBmcm9tICcuL2Ryb3AtZW1wdHktb2JqZWN0LWF0LXRoZS1lbmQtb2YtYW4tYXJyYXktdG9rZW4nO1xuaW1wb3J0IHsgYWNjb3VudElmRGlmZmVyZW50RnJvbVN0YWNrLCByZWdpb25JZkRpZmZlcmVudEZyb21TdGFjayB9IGZyb20gJy4vZW52LXRva2Vucyc7XG5pbXBvcnQgeyBkaXNwYXRjaE1ldHJpYywgbWV0cmljS2V5IH0gZnJvbSAnLi9tZXRyaWMtdXRpbCc7XG5pbXBvcnQgeyBkcm9wVW5kZWZpbmVkIH0gZnJvbSAnLi9vYmplY3QnO1xuXG4vKipcbiAqIFJldHVybiB0aGUgSlNPTiBzdHJ1Y3R1cmUgd2hpY2ggcmVwcmVzZW50cyB0aGVzZSBtZXRyaWNzIGluIGEgZ3JhcGguXG4gKlxuICogRGVwZW5kaW5nIG9uIHRoZSBtZXRyaWMgdHlwZSAoc3RhdCBvciBleHByZXNzaW9uKSwgb25lIGBNZXRyaWNgIG9iamVjdFxuICogY2FuIHJlbmRlciB0byBtdWx0aXBsZSB0aW1lIHNlcmllcy5cbiAqXG4gKiAtIFRvcC1sZXZlbCBtZXRyaWNzIHdpbGwgYmUgcmVuZGVyZWQgdmlzaWJseSwgYWRkaXRpb25hbGx5IGFkZGVkIG1ldHJpY3Mgd2lsbFxuICogICBiZSByZW5kZXJlZCBpbnZpc2libHkuXG4gKiAtIElEcyB1c2VkIGluIG1hdGggZXhwcmVzc2lvbnMgbmVlZCB0byBiZSBlaXRoZXIgZ2xvYmFsbHkgdW5pcXVlLCBvciByZWZlciB0byB0aGUgc2FtZVxuICogICBtZXRyaWMgb2JqZWN0LlxuICpcbiAqIFRoaXMgd2lsbCBiZSBjYWxsZWQgYnkgR3JhcGhXaWRnZXQsIG5vIG5lZWQgZm9yIGNsaWVudHMgdG8gY2FsbCB0aGlzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYWxsTWV0cmljc0dyYXBoSnNvbihsZWZ0OiBJTWV0cmljW10sIHJpZ2h0OiBJTWV0cmljW10pOiBhbnlbXSB7XG4gIC8vIEFkZCBtZXRyaWNzIHRvIGEgc2V0IHdoaWNoIHdpbGwgYXV0b21hdGljYWxseSBleHBhbmQgdGhlbSByZWN1cnNpdmVseSxcbiAgLy8gbWFraW5nIHN1cmUgdG8gcmV0YWluIGNvbmZsaWN0aW5nIHRoZSB2aXNpYmxlIG9uZSBvbiBjb25mbGljdGluZyBtZXRyaWNzIG9iamVjdHMuXG4gIGNvbnN0IG1zZXQgPSBuZXcgTWV0cmljU2V0PHN0cmluZz4oKTtcbiAgbXNldC5hZGRUb3BMZXZlbCgnbGVmdCcsIC4uLmxlZnQpO1xuICBtc2V0LmFkZFRvcExldmVsKCdyaWdodCcsIC4uLnJpZ2h0KTtcblxuICAvLyBSZW5kZXIgYWxsIG1ldHJpY3MgZnJvbSB0aGUgc2V0LlxuICByZXR1cm4gbXNldC5lbnRyaWVzLm1hcChlbnRyeSA9PiBuZXcgRHJvcEVtcHR5T2JqZWN0QXRUaGVFbmRPZkFuQXJyYXkobWV0cmljR3JhcGhKc29uKGVudHJ5Lm1ldHJpYywgZW50cnkudGFnLCBlbnRyeS5pZCkpKTtcbn1cblxuZnVuY3Rpb24gbWV0cmljR3JhcGhKc29uKG1ldHJpYzogSU1ldHJpYywgeUF4aXM/OiBzdHJpbmcsIGlkPzogc3RyaW5nKSB7XG4gIGNvbnN0IGNvbmZpZyA9IG1ldHJpYy50b01ldHJpY0NvbmZpZygpO1xuXG4gIGNvbnN0IHJldDogYW55W10gPSBbXTtcbiAgY29uc3Qgb3B0aW9uczogYW55ID0geyAuLi5jb25maWcucmVuZGVyaW5nUHJvcGVydGllcyB9O1xuXG4gIGRpc3BhdGNoTWV0cmljKG1ldHJpYywge1xuICAgIHdpdGhTdGF0KHN0YXQpIHtcbiAgICAgIHJldC5wdXNoKFxuICAgICAgICBzdGF0Lm5hbWVzcGFjZSxcbiAgICAgICAgc3RhdC5tZXRyaWNOYW1lLFxuICAgICAgKTtcblxuICAgICAgLy8gRGltZW5zaW9uc1xuICAgICAgZm9yIChjb25zdCBkaW0gb2YgKHN0YXQuZGltZW5zaW9ucyB8fCBbXSkpIHtcbiAgICAgICAgcmV0LnB1c2goZGltLm5hbWUsIGRpbS52YWx1ZSk7XG4gICAgICB9XG5cbiAgICAgIC8vIE1ldHJpYyBhdHRyaWJ1dGVzIHRoYXQgYXJlIHJlbmRlcmVkIHRvIGdyYXBoIG9wdGlvbnNcbiAgICAgIGlmIChzdGF0LmFjY291bnQpIHsgb3B0aW9ucy5hY2NvdW50SWQgPSBhY2NvdW50SWZEaWZmZXJlbnRGcm9tU3RhY2soc3RhdC5hY2NvdW50KTsgfVxuICAgICAgaWYgKHN0YXQucmVnaW9uKSB7IG9wdGlvbnMucmVnaW9uID0gcmVnaW9uSWZEaWZmZXJlbnRGcm9tU3RhY2soc3RhdC5yZWdpb24pOyB9XG4gICAgICBpZiAoc3RhdC5wZXJpb2QgJiYgc3RhdC5wZXJpb2QudG9TZWNvbmRzKCkgIT09IDMwMCkgeyBvcHRpb25zLnBlcmlvZCA9IHN0YXQucGVyaW9kLnRvU2Vjb25kcygpOyB9XG4gICAgICBpZiAoc3RhdC5zdGF0aXN0aWMgJiYgc3RhdC5zdGF0aXN0aWMgIT09ICdBdmVyYWdlJykgeyBvcHRpb25zLnN0YXQgPSBzdGF0LnN0YXRpc3RpYzsgfVxuICAgIH0sXG5cbiAgICB3aXRoRXhwcmVzc2lvbihleHByKSB7XG4gICAgICBvcHRpb25zLmV4cHJlc3Npb24gPSBleHByLmV4cHJlc3Npb247XG4gICAgICBpZiAoZXhwci5zZWFyY2hBY2NvdW50KSB7IG9wdGlvbnMuYWNjb3VudElkID0gYWNjb3VudElmRGlmZmVyZW50RnJvbVN0YWNrKGV4cHIuc2VhcmNoQWNjb3VudCk7IH1cbiAgICAgIGlmIChleHByLnNlYXJjaFJlZ2lvbikgeyBvcHRpb25zLnJlZ2lvbiA9IHJlZ2lvbklmRGlmZmVyZW50RnJvbVN0YWNrKGV4cHIuc2VhcmNoUmVnaW9uKTsgfVxuICAgICAgaWYgKGV4cHIucGVyaW9kICYmIGV4cHIucGVyaW9kICE9PSAzMDApIHsgb3B0aW9ucy5wZXJpb2QgPSBleHByLnBlcmlvZDsgfVxuICAgIH0sXG4gIH0pO1xuXG4gIC8vIE9wdGlvbnNcbiAgaWYgKCF5QXhpcykgeyBvcHRpb25zLnZpc2libGUgPSBmYWxzZTsgfVxuICBpZiAoeUF4aXMgIT09ICdsZWZ0JykgeyBvcHRpb25zLnlBeGlzID0geUF4aXM7IH1cbiAgaWYgKGlkKSB7IG9wdGlvbnMuaWQgPSBpZDsgfVxuXG4gIGlmIChvcHRpb25zLnZpc2libGUgIT09IGZhbHNlICYmIG9wdGlvbnMuZXhwcmVzc2lvbiAmJiAhb3B0aW9ucy5sYWJlbCkge1xuICAgIC8vIExhYmVsIG1heSBiZSAnJyBvciB1bmRlZmluZWQuXG4gICAgLy9cbiAgICAvLyBJZiB1bmRlZmluZWQsIHdlJ2xsIHJlbmRlciB0aGUgZXhwcmVzc2lvbiBhcyB0aGUgbGFiZWwsIHRvIHN1cHByZXNzXG4gICAgLy8gdGhlIGRlZmF1bHQgYmVoYXZpb3Igb2YgQ1cgd2hlcmUgaXQgd291bGQgcmVuZGVyIHRoZSBtZXRyaWNcbiAgICAvLyBpZCBhcyBsYWJlbCwgd2hpY2ggd2UgKGluZWxlZ2FudGx5KSBnZW5lcmF0ZSB0byBiZSBzb21ldGhpbmcgbGlrZSBcIm1ldHJpY19hbGlhczBcIi5cbiAgICAvL1xuICAgIC8vIEZvciBhcnJheSBleHByZXNzaW9ucyAocmV0dXJuaW5nIG1vcmUgdGhhbiAxIFRTKSB1c2VycyBtYXkgc29tZXRpbWVzIHdhbnQgdG9cbiAgICAvLyBzdXBwcmVzcyB0aGUgbGFiZWwgY29tcGxldGVseS4gRm9yIHRob3NlIGNhc2VzLCB3ZSdsbCBhY2NlcHQgdGhlIGVtcHR5IHN0cmluZyxcbiAgICAvLyBhbmQgbm90IHJlbmRlciBhIGxhYmVsIGF0IGFsbC5cbiAgICBvcHRpb25zLmxhYmVsID0gb3B0aW9ucy5sYWJlbCA9PT0gJycgPyB1bmRlZmluZWQgOiBtZXRyaWMudG9TdHJpbmcoKTtcbiAgfVxuXG4gIGNvbnN0IHJlbmRlcmVkT3B0cyA9IGRyb3BVbmRlZmluZWQob3B0aW9ucyk7XG5cbiAgaWYgKE9iamVjdC5rZXlzKHJlbmRlcmVkT3B0cykubGVuZ3RoICE9PSAwKSB7XG4gICAgcmV0LnB1c2gocmVuZGVyZWRPcHRzKTtcbiAgfVxuICByZXR1cm4gcmV0O1xufVxuXG4vKipcbiAqIEEgc2luZ2xlIG1ldHJpYyBpbiBhIE1ldHJpY1NldFxuICovXG5leHBvcnQgaW50ZXJmYWNlIE1ldHJpY0VudHJ5PEE+IHtcbiAgLyoqXG4gICAqIFRoZSBtZXRyaWMgb2JqZWN0XG4gICAqL1xuICByZWFkb25seSBtZXRyaWM6IElNZXRyaWM7XG5cbiAgLyoqXG4gICAqIFRoZSB0YWcsIGFkZGVkIGlmIHRoZSBvYmplY3QgaXMgYSBwcmltYXJ5IG1ldHJpY1xuICAgKi9cbiAgdGFnPzogQTtcblxuICAvKipcbiAgICogSUQgZm9yIHRoaXMgbWV0cmljIG9iamVjdFxuICAgKi9cbiAgaWQ/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogQ29udGFpbiBhIHNldCBvZiBtZXRyaWNzLCBleHBhbmRpbmcgbWF0aCBleHByZXNzaW9uc1xuICpcbiAqIFwiUHJpbWFyeVwiIG1ldHJpY3MgKGFkZGVkIHZpYSBhIHRvcC1sZXZlbCBjYWxsKSBjYW4gYmUgdGFnZ2VkIHdpdGggYW4gYWRkaXRpb25hbCB2YWx1ZS5cbiAqL1xuZXhwb3J0IGNsYXNzIE1ldHJpY1NldDxBPiB7XG4gIHByaXZhdGUgcmVhZG9ubHkgbWV0cmljcyA9IG5ldyBBcnJheTxNZXRyaWNFbnRyeTxBPj4oKTtcbiAgcHJpdmF0ZSByZWFkb25seSBtZXRyaWNCeUlkID0gbmV3IE1hcDxzdHJpbmcsIE1ldHJpY0VudHJ5PEE+PigpO1xuICBwcml2YXRlIHJlYWRvbmx5IG1ldHJpY0J5S2V5ID0gbmV3IE1hcDxzdHJpbmcsIE1ldHJpY0VudHJ5PEE+PigpO1xuXG4gIC8qKlxuICAgKiBBZGQgdGhlIGdpdmVuIHNldCBvZiBtZXRyaWNzIHRvIHRoaXMgc2V0XG4gICAqL1xuICBwdWJsaWMgYWRkVG9wTGV2ZWwodGFnOiBBLCAuLi5tZXRyaWNzOiBJTWV0cmljW10pIHtcbiAgICBmb3IgKGNvbnN0IG1ldHJpYyBvZiBtZXRyaWNzKSB7XG4gICAgICB0aGlzLmFkZE9uZShtZXRyaWMsIHRhZyk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEFjY2VzcyBhbGwgdGhlIGFjY3VtdWxhdGVkIHRpbWVzZXJpZXMgZW50cmllc1xuICAgKi9cbiAgcHVibGljIGdldCBlbnRyaWVzKCk6IFJlYWRvbmx5QXJyYXk8TWV0cmljRW50cnk8QT4+IHtcbiAgICByZXR1cm4gdGhpcy5tZXRyaWNzO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZCBhIG1ldHJpYyBpbnRvIHRoZSBzZXRcbiAgICpcbiAgICogVGhlIGlkIG1heSBub3QgYmUgdGhlIHNhbWUgYXMgYSBwcmV2aW91cyBtZXRyaWMgYWRkZWQsIHVubGVzcyBpdCdzIHRoZSBzYW1lIG1ldHJpYy5cbiAgICpcbiAgICogSXQgY2FuIGJlIG1hZGUgdmlzaWJsZSwgaW4gd2hpY2ggY2FzZSB0aGUgbmV3IFwibWV0cmljXCIgb2JqZWN0IHJlcGxhY2VzIHRoZSBvbGRcbiAgICogb25lIChhbmQgdGhlIG5ldyBvbmVzIFwicmVuZGVyaW5nUHJvcGVydGllU1wiIHdpbGwgYmUgaG9ub3JlZCBpbnN0ZWFkIG9mIHRoZSBvbGRcbiAgICogb25lJ3MpLlxuICAgKi9cbiAgcHJpdmF0ZSBhZGRPbmUobWV0cmljOiBJTWV0cmljLCB0YWc/OiBBLCBpZD86IHN0cmluZykge1xuICAgIGNvbnN0IGtleSA9IG1ldHJpY0tleShtZXRyaWMpO1xuXG4gICAgbGV0IGV4aXN0aW5nRW50cnk6IE1ldHJpY0VudHJ5PEE+IHwgdW5kZWZpbmVkO1xuXG4gICAgLy8gVHJ5IGxvb2t1cCBleGlzdGluZyBieSBpZCBpZiB3ZSBoYXZlIG9uZVxuICAgIGlmIChpZCkge1xuICAgICAgZXhpc3RpbmdFbnRyeSA9IHRoaXMubWV0cmljQnlJZC5nZXQoaWQpO1xuICAgICAgaWYgKGV4aXN0aW5nRW50cnkgJiYgbWV0cmljS2V5KGV4aXN0aW5nRW50cnkubWV0cmljKSAhPT0ga2V5KSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgQ2Fubm90IGhhdmUgdHdvIGRpZmZlcmVudCBtZXRyaWNzIHNoYXJlIHRoZSBzYW1lIGlkICgnJHtpZH0nKSBpbiBvbmUgQWxhcm0gb3IgR3JhcGguIFJlbmFtZSBvbmUgb2YgdGhlbS5gKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoIWV4aXN0aW5nRW50cnkpIHtcbiAgICAgIC8vIFRyeSBsb29rdXAgYnkgbWV0cmljIGlmIHdlIGRpZG4ndCBmaW5kIG9uZSBieSBpZFxuICAgICAgZXhpc3RpbmdFbnRyeSA9IHRoaXMubWV0cmljQnlLZXkuZ2V0KGtleSk7XG5cbiAgICAgIC8vIElmIHRoZSBvbmUgd2UgZm91bmQgYWxyZWFkeSBoYXMgYW4gaWQsIGl0IG11c3QgYmUgZGlmZmVyZW50IGZyb20gdGhlIGlkXG4gICAgICAvLyB3ZSdyZSB0cnlpbmcgdG8gYWRkIGFuZCB3ZSB3YW50IHRvIGFkZCBhIG5ldyBtZXRyaWMuIFByZXRlbmQgd2UgZGlkbid0XG4gICAgICAvLyBmaW5kIG9uZS5cbiAgICAgIGlmIChleGlzdGluZ0VudHJ5Py5pZCAmJiBpZCkgeyBleGlzdGluZ0VudHJ5ID0gdW5kZWZpbmVkOyB9XG4gICAgfVxuXG4gICAgLy8gQ3JlYXRlIGEgbmV3IGVudHJ5IGlmIHdlIGRpZG4ndCBmaW5kIG9uZSBzbyBmYXJcbiAgICBsZXQgZW50cnk7XG4gICAgaWYgKGV4aXN0aW5nRW50cnkpIHtcbiAgICAgIGVudHJ5ID0gZXhpc3RpbmdFbnRyeTtcbiAgICB9IGVsc2Uge1xuICAgICAgZW50cnkgPSB7IG1ldHJpYyB9O1xuICAgICAgdGhpcy5tZXRyaWNzLnB1c2goZW50cnkpO1xuICAgICAgdGhpcy5tZXRyaWNCeUtleS5zZXQoa2V5LCBlbnRyeSk7XG4gICAgfVxuXG4gICAgLy8gSWYgaXQgZGlkbid0IGhhdmUgYW4gaWQgYnV0IG5vdyB3ZSBkbywgYWRkIG9uZVxuICAgIGlmICghZW50cnkuaWQgJiYgaWQpIHtcbiAgICAgIGVudHJ5LmlkID0gaWQ7XG4gICAgICB0aGlzLm1ldHJpY0J5SWQuc2V0KGlkLCBlbnRyeSk7XG4gICAgfVxuXG4gICAgLy8gSWYgaXQgZGlkbid0IGhhdmUgYSB0YWcgYnV0IG5vdyB3ZSBkbywgYWRkIG9uZVxuICAgIGlmICghZW50cnkudGFnICYmIHRhZykge1xuICAgICAgZW50cnkudGFnID0gdGFnO1xuICAgIH1cblxuICAgIC8vIFJlY3Vyc2UgYW5kIGFkZCBjaGlsZHJlblxuICAgIGNvbnN0IGNvbmYgPSBtZXRyaWMudG9NZXRyaWNDb25maWcoKTtcbiAgICBpZiAoY29uZi5tYXRoRXhwcmVzc2lvbikge1xuICAgICAgZm9yIChjb25zdCBbc3ViSWQsIHN1Yk1ldHJpY10gb2YgT2JqZWN0LmVudHJpZXMoY29uZi5tYXRoRXhwcmVzc2lvbi51c2luZ01ldHJpY3MpKSB7XG4gICAgICAgIHRoaXMuYWRkT25lKHN1Yk1ldHJpYywgdW5kZWZpbmVkLCBzdWJJZCk7XG4gICAgICB9XG4gICAgfVxuICB9XG59XG4iXX0=
\No newline at end of file