UNPKG

78 kBJavaScriptView Raw
1"use strict";
2var _a, _b;
3Object.defineProperty(exports, "__esModule", { value: true });
4exports.MathExpression = exports.Metric = void 0;
5const jsiiDeprecationWarnings = require("../.warnings.jsii.js");
6const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
7const iam = require("@aws-cdk/aws-iam");
8const cdk = require("@aws-cdk/core");
9const alarm_1 = require("./alarm");
10const metric_util_1 = require("./private/metric-util");
11const statistic_1 = require("./private/statistic");
12/**
13 * A metric emitted by a service
14 *
15 * The metric is a combination of a metric identifier (namespace, name and dimensions)
16 * and an aggregation function (statistic, period and unit).
17 *
18 * It also contains metadata which is used only in graphs, such as color and label.
19 * It makes sense to embed this in here, so that compound constructs can attach
20 * that metadata to metrics they expose.
21 *
22 * This class does not represent a resource, so hence is not a construct. Instead,
23 * Metric is an abstraction that makes it easy to specify metrics for use in both
24 * alarms and graphs.
25 */
26class Metric {
27 constructor(props) {
28 try {
29 jsiiDeprecationWarnings._aws_cdk_aws_cloudwatch_MetricProps(props);
30 }
31 catch (error) {
32 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
33 Error.captureStackTrace(error, Metric);
34 }
35 throw error;
36 }
37 this.period = props.period || cdk.Duration.minutes(5);
38 const periodSec = this.period.toSeconds();
39 if (periodSec !== 1 && periodSec !== 5 && periodSec !== 10 && periodSec !== 30 && periodSec % 60 !== 0) {
40 throw new Error(`'period' must be 1, 5, 10, 30, or a multiple of 60 seconds, received ${periodSec}`);
41 }
42 this.dimensions = this.validateDimensions(props.dimensionsMap ?? props.dimensions);
43 this.namespace = props.namespace;
44 this.metricName = props.metricName;
45 // Try parsing, this will throw if it's not a valid stat
46 this.statistic = statistic_1.normalizeStatistic(props.statistic || 'Average');
47 this.label = props.label;
48 this.color = props.color;
49 this.unit = props.unit;
50 this.account = props.account;
51 this.region = props.region;
52 this.warnings = undefined;
53 }
54 /**
55 * Grant permissions to the given identity to write metrics.
56 *
57 * @param grantee The IAM identity to give permissions to.
58 */
59 static grantPutMetricData(grantee) {
60 return iam.Grant.addToPrincipal({
61 grantee,
62 actions: ['cloudwatch:PutMetricData'],
63 resourceArns: ['*'],
64 });
65 }
66 /**
67 * Return a copy of Metric `with` properties changed.
68 *
69 * All properties except namespace and metricName can be changed.
70 *
71 * @param props The set of properties to change.
72 */
73 with(props) {
74 try {
75 jsiiDeprecationWarnings._aws_cdk_aws_cloudwatch_MetricOptions(props);
76 }
77 catch (error) {
78 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
79 Error.captureStackTrace(error, this.with);
80 }
81 throw error;
82 }
83 // Short-circuit creating a new object if there would be no effective change
84 if ((props.label === undefined || props.label === this.label)
85 && (props.color === undefined || props.color === this.color)
86 && (props.statistic === undefined || props.statistic === this.statistic)
87 && (props.unit === undefined || props.unit === this.unit)
88 && (props.account === undefined || props.account === this.account)
89 && (props.region === undefined || props.region === this.region)
90 // For these we're not going to do deep equality, misses some opportunity for optimization
91 // but that's okay.
92 && (props.dimensions === undefined)
93 && (props.dimensionsMap === undefined)
94 && (props.period === undefined || props.period.toSeconds() === this.period.toSeconds())) {
95 return this;
96 }
97 return new Metric({
98 dimensionsMap: props.dimensionsMap ?? props.dimensions ?? this.dimensions,
99 namespace: this.namespace,
100 metricName: this.metricName,
101 period: ifUndefined(props.period, this.period),
102 statistic: ifUndefined(props.statistic, this.statistic),
103 unit: ifUndefined(props.unit, this.unit),
104 label: ifUndefined(props.label, this.label),
105 color: ifUndefined(props.color, this.color),
106 account: ifUndefined(props.account, this.account),
107 region: ifUndefined(props.region, this.region),
108 });
109 }
110 /**
111 * Attach the metric object to the given construct scope
112 *
113 * Returns a Metric object that uses the account and region from the Stack
114 * the given construct is defined in. If the metric is subsequently used
115 * in a Dashboard or Alarm in a different Stack defined in a different
116 * account or region, the appropriate 'region' and 'account' fields
117 * will be added to it.
118 *
119 * If the scope we attach to is in an environment-agnostic stack,
120 * nothing is done and the same Metric object is returned.
121 */
122 attachTo(scope) {
123 const stack = cdk.Stack.of(scope);
124 return this.with({
125 region: cdk.Token.isUnresolved(stack.region) ? undefined : stack.region,
126 account: cdk.Token.isUnresolved(stack.account) ? undefined : stack.account,
127 });
128 }
129 toMetricConfig() {
130 const dims = this.dimensionsAsList();
131 return {
132 metricStat: {
133 dimensions: dims.length > 0 ? dims : undefined,
134 namespace: this.namespace,
135 metricName: this.metricName,
136 period: this.period,
137 statistic: this.statistic,
138 unitFilter: this.unit,
139 account: this.account,
140 region: this.region,
141 },
142 renderingProperties: {
143 color: this.color,
144 label: this.label,
145 },
146 };
147 }
148 /** @deprecated use toMetricConfig() */
149 toAlarmConfig() {
150 try {
151 jsiiDeprecationWarnings.print("@aws-cdk/aws-cloudwatch.Metric#toAlarmConfig", "use toMetricConfig()");
152 }
153 catch (error) {
154 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
155 Error.captureStackTrace(error, this.toAlarmConfig);
156 }
157 throw error;
158 }
159 const metricConfig = this.toMetricConfig();
160 if (metricConfig.metricStat === undefined) {
161 throw new Error('Using a math expression is not supported here. Pass a \'Metric\' object instead');
162 }
163 const stat = statistic_1.parseStatistic(metricConfig.metricStat.statistic);
164 return {
165 dimensions: metricConfig.metricStat.dimensions,
166 namespace: metricConfig.metricStat.namespace,
167 metricName: metricConfig.metricStat.metricName,
168 period: metricConfig.metricStat.period.toSeconds(),
169 statistic: stat.type === 'simple' ? stat.statistic : undefined,
170 extendedStatistic: stat.type === 'percentile' ? 'p' + stat.percentile : undefined,
171 unit: this.unit,
172 };
173 }
174 /**
175 * @deprecated use toMetricConfig()
176 */
177 toGraphConfig() {
178 try {
179 jsiiDeprecationWarnings.print("@aws-cdk/aws-cloudwatch.Metric#toGraphConfig", "use toMetricConfig()");
180 }
181 catch (error) {
182 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
183 Error.captureStackTrace(error, this.toGraphConfig);
184 }
185 throw error;
186 }
187 const metricConfig = this.toMetricConfig();
188 if (metricConfig.metricStat === undefined) {
189 throw new Error('Using a math expression is not supported here. Pass a \'Metric\' object instead');
190 }
191 return {
192 dimensions: metricConfig.metricStat.dimensions,
193 namespace: metricConfig.metricStat.namespace,
194 metricName: metricConfig.metricStat.metricName,
195 renderingProperties: {
196 period: metricConfig.metricStat.period.toSeconds(),
197 stat: metricConfig.metricStat.statistic,
198 color: asString(metricConfig.renderingProperties?.color),
199 label: asString(metricConfig.renderingProperties?.label),
200 },
201 // deprecated properties for backwards compatibility
202 period: metricConfig.metricStat.period.toSeconds(),
203 statistic: metricConfig.metricStat.statistic,
204 color: asString(metricConfig.renderingProperties?.color),
205 label: asString(metricConfig.renderingProperties?.label),
206 unit: this.unit,
207 };
208 }
209 /**
210 * Make a new Alarm for this metric
211 *
212 * Combines both properties that may adjust the metric (aggregation) as well
213 * as alarm properties.
214 */
215 createAlarm(scope, id, props) {
216 try {
217 jsiiDeprecationWarnings._aws_cdk_aws_cloudwatch_CreateAlarmOptions(props);
218 }
219 catch (error) {
220 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
221 Error.captureStackTrace(error, this.createAlarm);
222 }
223 throw error;
224 }
225 return new alarm_1.Alarm(scope, id, {
226 metric: this.with({
227 statistic: props.statistic,
228 period: props.period,
229 }),
230 alarmName: props.alarmName,
231 alarmDescription: props.alarmDescription,
232 comparisonOperator: props.comparisonOperator,
233 datapointsToAlarm: props.datapointsToAlarm,
234 threshold: props.threshold,
235 evaluationPeriods: props.evaluationPeriods,
236 evaluateLowSampleCountPercentile: props.evaluateLowSampleCountPercentile,
237 treatMissingData: props.treatMissingData,
238 actionsEnabled: props.actionsEnabled,
239 });
240 }
241 toString() {
242 return this.label || this.metricName;
243 }
244 /**
245 * Return the dimensions of this Metric as a list of Dimension.
246 */
247 dimensionsAsList() {
248 const dims = this.dimensions;
249 if (dims === undefined) {
250 return [];
251 }
252 const list = Object.keys(dims).sort().map(key => ({ name: key, value: dims[key] }));
253 return list;
254 }
255 validateDimensions(dims) {
256 if (!dims) {
257 return dims;
258 }
259 var dimsArray = Object.keys(dims);
260 if (dimsArray?.length > 10) {
261 throw new Error(`The maximum number of dimensions is 10, received ${dimsArray.length}`);
262 }
263 dimsArray.map(key => {
264 if (dims[key] === undefined || dims[key] === null) {
265 throw new Error(`Dimension value of '${dims[key]}' is invalid`);
266 }
267 ;
268 if (key.length < 1 || key.length > 255) {
269 throw new Error(`Dimension name must be at least 1 and no more than 255 characters; received ${key}`);
270 }
271 ;
272 if (dims[key].length < 1 || dims[key].length > 255) {
273 throw new Error(`Dimension value must be at least 1 and no more than 255 characters; received ${dims[key]}`);
274 }
275 ;
276 });
277 return dims;
278 }
279}
280exports.Metric = Metric;
281_a = JSII_RTTI_SYMBOL_1;
282Metric[_a] = { fqn: "@aws-cdk/aws-cloudwatch.Metric", version: "1.161.0" };
283function asString(x) {
284 if (x === undefined) {
285 return undefined;
286 }
287 if (typeof x !== 'string') {
288 throw new Error(`Expected string, got ${x}`);
289 }
290 return x;
291}
292/**
293 * A math expression built with metric(s) emitted by a service
294 *
295 * The math expression is a combination of an expression (x+y) and metrics to apply expression on.
296 * It also contains metadata which is used only in graphs, such as color and label.
297 * It makes sense to embed this in here, so that compound constructs can attach
298 * that metadata to metrics they expose.
299 *
300 * MathExpression can also be used for search expressions. In this case,
301 * it also optionally accepts a searchRegion and searchAccount property for cross-environment
302 * search expressions.
303 *
304 * This class does not represent a resource, so hence is not a construct. Instead,
305 * MathExpression is an abstraction that makes it easy to specify metrics for use in both
306 * alarms and graphs.
307 */
308class MathExpression {
309 constructor(props) {
310 try {
311 jsiiDeprecationWarnings._aws_cdk_aws_cloudwatch_MathExpressionProps(props);
312 }
313 catch (error) {
314 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
315 Error.captureStackTrace(error, MathExpression);
316 }
317 throw error;
318 }
319 this.period = props.period || cdk.Duration.minutes(5);
320 this.expression = props.expression;
321 this.usingMetrics = changeAllPeriods(props.usingMetrics ?? {}, this.period);
322 this.label = props.label;
323 this.color = props.color;
324 this.searchAccount = props.searchAccount;
325 this.searchRegion = props.searchRegion;
326 const invalidVariableNames = Object.keys(this.usingMetrics).filter(x => !validVariableName(x));
327 if (invalidVariableNames.length > 0) {
328 throw new Error(`Invalid variable names in expression: ${invalidVariableNames}. Must start with lowercase letter and only contain alphanumerics.`);
329 }
330 this.validateNoIdConflicts();
331 // Check that all IDs used in the expression are also in the `usingMetrics` map. We
332 // can't throw on this anymore since we didn't use to do this validation from the start
333 // and now there will be loads of people who are violating the expected contract, but
334 // we can add warnings.
335 const missingIdentifiers = allIdentifiersInExpression(this.expression).filter(i => !this.usingMetrics[i]);
336 const warnings = [];
337 if (missingIdentifiers.length > 0) {
338 warnings.push(`Math expression '${this.expression}' references unknown identifiers: ${missingIdentifiers.join(', ')}. Please add them to the 'usingMetrics' map.`);
339 }
340 // Also copy warnings from deeper levels so graphs, alarms only have to inspect the top-level objects
341 for (const m of Object.values(this.usingMetrics)) {
342 warnings.push(...m.warnings ?? []);
343 }
344 if (warnings.length > 0) {
345 this.warnings = warnings;
346 }
347 }
348 /**
349 * Return a copy of Metric with properties changed.
350 *
351 * All properties except namespace and metricName can be changed.
352 *
353 * @param props The set of properties to change.
354 */
355 with(props) {
356 try {
357 jsiiDeprecationWarnings._aws_cdk_aws_cloudwatch_MathExpressionOptions(props);
358 }
359 catch (error) {
360 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
361 Error.captureStackTrace(error, this.with);
362 }
363 throw error;
364 }
365 // Short-circuit creating a new object if there would be no effective change
366 if ((props.label === undefined || props.label === this.label)
367 && (props.color === undefined || props.color === this.color)
368 && (props.period === undefined || props.period.toSeconds() === this.period.toSeconds())
369 && (props.searchAccount === undefined || props.searchAccount === this.searchAccount)
370 && (props.searchRegion === undefined || props.searchRegion === this.searchRegion)) {
371 return this;
372 }
373 return new MathExpression({
374 expression: this.expression,
375 usingMetrics: this.usingMetrics,
376 label: ifUndefined(props.label, this.label),
377 color: ifUndefined(props.color, this.color),
378 period: ifUndefined(props.period, this.period),
379 searchAccount: ifUndefined(props.searchAccount, this.searchAccount),
380 searchRegion: ifUndefined(props.searchRegion, this.searchRegion),
381 });
382 }
383 /**
384 * @deprecated use toMetricConfig()
385 */
386 toAlarmConfig() {
387 try {
388 jsiiDeprecationWarnings.print("@aws-cdk/aws-cloudwatch.MathExpression#toAlarmConfig", "use toMetricConfig()");
389 }
390 catch (error) {
391 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
392 Error.captureStackTrace(error, this.toAlarmConfig);
393 }
394 throw error;
395 }
396 throw new Error('Using a math expression is not supported here. Pass a \'Metric\' object instead');
397 }
398 /**
399 * @deprecated use toMetricConfig()
400 */
401 toGraphConfig() {
402 try {
403 jsiiDeprecationWarnings.print("@aws-cdk/aws-cloudwatch.MathExpression#toGraphConfig", "use toMetricConfig()");
404 }
405 catch (error) {
406 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
407 Error.captureStackTrace(error, this.toGraphConfig);
408 }
409 throw error;
410 }
411 throw new Error('Using a math expression is not supported here. Pass a \'Metric\' object instead');
412 }
413 toMetricConfig() {
414 return {
415 mathExpression: {
416 period: this.period.toSeconds(),
417 expression: this.expression,
418 usingMetrics: this.usingMetrics,
419 searchAccount: this.searchAccount,
420 searchRegion: this.searchRegion,
421 },
422 renderingProperties: {
423 label: this.label,
424 color: this.color,
425 },
426 };
427 }
428 /**
429 * Make a new Alarm for this metric
430 *
431 * Combines both properties that may adjust the metric (aggregation) as well
432 * as alarm properties.
433 */
434 createAlarm(scope, id, props) {
435 try {
436 jsiiDeprecationWarnings._aws_cdk_aws_cloudwatch_CreateAlarmOptions(props);
437 }
438 catch (error) {
439 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
440 Error.captureStackTrace(error, this.createAlarm);
441 }
442 throw error;
443 }
444 return new alarm_1.Alarm(scope, id, {
445 metric: this.with({
446 period: props.period,
447 }),
448 alarmName: props.alarmName,
449 alarmDescription: props.alarmDescription,
450 comparisonOperator: props.comparisonOperator,
451 datapointsToAlarm: props.datapointsToAlarm,
452 threshold: props.threshold,
453 evaluationPeriods: props.evaluationPeriods,
454 evaluateLowSampleCountPercentile: props.evaluateLowSampleCountPercentile,
455 treatMissingData: props.treatMissingData,
456 actionsEnabled: props.actionsEnabled,
457 });
458 }
459 toString() {
460 return this.label || this.expression;
461 }
462 validateNoIdConflicts() {
463 const seen = new Map();
464 visit(this);
465 function visit(metric) {
466 metric_util_1.dispatchMetric(metric, {
467 withStat() {
468 // Nothing
469 },
470 withExpression(expr) {
471 for (const [id, subMetric] of Object.entries(expr.usingMetrics)) {
472 const existing = seen.get(id);
473 if (existing && metric_util_1.metricKey(existing) !== metric_util_1.metricKey(subMetric)) {
474 throw new Error(`The ID '${id}' used for two metrics in the expression: '${subMetric}' and '${existing}'. Rename one.`);
475 }
476 seen.set(id, subMetric);
477 visit(subMetric);
478 }
479 },
480 });
481 }
482 }
483}
484exports.MathExpression = MathExpression;
485_b = JSII_RTTI_SYMBOL_1;
486MathExpression[_b] = { fqn: "@aws-cdk/aws-cloudwatch.MathExpression", version: "1.161.0" };
487/**
488 * Pattern for a variable name. Alphanum starting with lowercase.
489 */
490const VARIABLE_PAT = '[a-z][a-zA-Z0-9_]*';
491const VALID_VARIABLE = new RegExp(`^${VARIABLE_PAT}$`);
492const FIND_VARIABLE = new RegExp(VARIABLE_PAT, 'g');
493function validVariableName(x) {
494 return VALID_VARIABLE.test(x);
495}
496/**
497 * Return all variable names used in an expression
498 */
499function allIdentifiersInExpression(x) {
500 return Array.from(matchAll(x, FIND_VARIABLE)).map(m => m[0]);
501}
502function ifUndefined(x, def) {
503 if (x !== undefined) {
504 return x;
505 }
506 return def;
507}
508/**
509 * Change periods of all metrics in the map
510 */
511function changeAllPeriods(metrics, period) {
512 const ret = {};
513 for (const [id, metric] of Object.entries(metrics)) {
514 ret[id] = changePeriod(metric, period);
515 }
516 return ret;
517}
518/**
519 * Return a new metric object which is the same type as the input object, but with the period changed
520 *
521 * Relies on the fact that implementations of `IMetric` are also supposed to have
522 * an implementation of `with` that accepts an argument called `period`. See `IModifiableMetric`.
523 */
524function changePeriod(metric, period) {
525 if (isModifiableMetric(metric)) {
526 return metric.with({ period });
527 }
528 throw new Error(`Metric object should also implement 'with': ${metric}`);
529}
530function isModifiableMetric(m) {
531 return typeof m === 'object' && m !== null && !!m.with;
532}
533// Polyfill for string.matchAll(regexp)
534function matchAll(x, re) {
535 const ret = new Array();
536 let m;
537 while (m = re.exec(x)) {
538 ret.push(m);
539 }
540 return ret;
541}
542//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWV0cmljLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsibWV0cmljLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLHdDQUF3QztBQUN4QyxxQ0FBcUM7QUFFckMsbUNBQXNFO0FBRXRFLHVEQUFrRTtBQUNsRSxtREFBeUU7QUErTnpFOzs7Ozs7Ozs7Ozs7O0dBYUc7QUFDSCxNQUFhLE1BQU07SUF5Q2pCLFlBQVksS0FBa0I7Ozs7OzsrQ0F6Q25CLE1BQU07Ozs7UUEwQ2YsSUFBSSxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUMsTUFBTSxJQUFJLEdBQUcsQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3RELE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDMUMsSUFBSSxTQUFTLEtBQUssQ0FBQyxJQUFJLFNBQVMsS0FBSyxDQUFDLElBQUksU0FBUyxLQUFLLEVBQUUsSUFBSSxTQUFTLEtBQUssRUFBRSxJQUFJLFNBQVMsR0FBRyxFQUFFLEtBQUssQ0FBQyxFQUFFO1lBQ3RHLE1BQU0sSUFBSSxLQUFLLENBQUMsd0VBQXdFLFNBQVMsRUFBRSxDQUFDLENBQUM7U0FDdEc7UUFDRCxJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxLQUFLLENBQUMsYUFBYSxJQUFJLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUNuRixJQUFJLENBQUMsU0FBUyxHQUFHLEtBQUssQ0FBQyxTQUFTLENBQUM7UUFDakMsSUFBSSxDQUFDLFVBQVUsR0FBRyxLQUFLLENBQUMsVUFBVSxDQUFDO1FBQ25DLHdEQUF3RDtRQUN4RCxJQUFJLENBQUMsU0FBUyxHQUFHLDhCQUFrQixDQUFDLEtBQUssQ0FBQyxTQUFTLElBQUksU0FBUyxDQUFDLENBQUM7UUFDbEUsSUFBSSxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDO1FBQ3pCLElBQUksQ0FB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QixDQUFDLE9BQWdDLEVBQUUsTUFBb0I7SUFDOUUsTUFBTSxHQUFHLEdBQTRCLEVBQUUsQ0FBQztJQUN4QyxLQUFLLE1BQU0sQ0FBQyxFQUFFLEVBQUUsTUFBTSxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsRUFBRTtRQUNsRCxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsWUFBWSxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FBQztLQUN4QztJQUNELE9BQU8sR0FBRyxDQUFDO0FBQ2IsQ0FBQztBQUVEOzs7OztHQUtHO0FBQ0gsU0FBUyxZQUFZLENBQUMsTUFBZSxFQUFFLE1BQW9CO0lBQ3pELElBQUksa0JBQWtCLENBQUMsTUFBTSxDQUFDLEVBQUU7UUFDOUIsT0FBTyxNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztLQUNoQztJQUVELE1BQU0sSUFBSSxLQUFLLENBQUMsK0NBQStDLE1BQU0sRUFBRSxDQUFDLENBQUM7QUFDM0UsQ0FBQztBQXdCRCxTQUFTLGtCQUFrQixDQUFDLENBQU07SUFDaEMsT0FBTyxPQUFPLENBQUMsS0FBSyxRQUFRLElBQUksQ0FBQyxLQUFLLElBQUksSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztBQUN6RCxDQUFDO0FBRUQsdUNBQXVDO0FBQ3ZDLFNBQVMsUUFBUSxDQUFDLENBQVMsRUFBRSxFQUFVO0lBQ3JDLE1BQU0sR0FBRyxHQUFHLElBQUksS0FBSyxFQUFvQixDQUFDO0lBQzFDLElBQUksQ0FBeUIsQ0FBQztJQUM5QixPQUFPLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFO1FBQ3JCLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7S0FDYjtJQUNELE9BQU8sR0FBRyxDQUFDO0FBQ2IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGlhbSBmcm9tICdAYXdzLWNkay9hd3MtaWFtJztcbmltcG9ydCAqIGFzIGNkayBmcm9tICdAYXdzLWNkay9jb3JlJztcbmltcG9ydCAqIGFzIGNvbnN0cnVjdHMgZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgeyBBbGFybSwgQ29tcGFyaXNvbk9wZXJhdG9yLCBUcmVhdE1pc3NpbmdEYXRhIH0gZnJvbSAnLi9hbGFybSc7XG5pbXBvcnQgeyBEaW1lbnNpb24sIElNZXRyaWMsIE1ldHJpY0FsYXJtQ29uZmlnLCBNZXRyaWNDb25maWcsIE1ldHJpY0dyYXBoQ29uZmlnLCBVbml0IH0gZnJvbSAnLi9tZXRyaWMtdHlwZXMnO1xuaW1wb3J0IHsgZGlzcGF0Y2hNZXRyaWMsIG1ldHJpY0tleSB9IGZyb20gJy4vcHJpdmF0ZS9tZXRyaWMtdXRpbCc7XG5pbXBvcnQgeyBub3JtYWxpemVTdGF0aXN0aWMsIHBhcnNlU3RhdGlzdGljIH0gZnJvbSAnLi9wcml2YXRlL3N0YXRpc3RpYyc7XG5cbi8vIGtlZXAgdGhpcyBpbXBvcnQgc2VwYXJhdGUgZnJvbSBvdGhlciBpbXBvcnRzIHRvIHJlZHVjZSBjaGFuY2UgZm9yIG1lcmdlIGNvbmZsaWN0cyB3aXRoIHYyLW1haW5cbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1kdXBsaWNhdGUtaW1wb3J0cywgaW1wb3J0L29yZGVyXG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdAYXdzLWNkay9jb3JlJztcblxuZXhwb3J0IHR5cGUgRGltZW5zaW9uSGFzaCA9IHtbZGltOiBzdHJpbmddOiBhbnl9O1xuXG5leHBvcnQgdHlwZSBEaW1lbnNpb25zTWFwID0geyBbZGltOiBzdHJpbmddOiBzdHJpbmcgfTtcblxuLyoqXG4gKiBPcHRpb25zIHNoYXJlZCBieSBtb3N0IG1ldGhvZHMgYWNjZXB0aW5nIG1ldHJpYyBvcHRpb25zXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ29tbW9uTWV0cmljT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBUaGUgcGVyaW9kIG92ZXIgd2hpY2ggdGhlIHNwZWNpZmllZCBzdGF0aXN0aWMgaXMgYXBwbGllZC5cbiAgICpcbiAgICogQGRlZmF1bHQgRHVyYXRpb24ubWludXRlcyg1KVxuICAgKi9cbiAgcmVhZG9ubHkgcGVyaW9kPzogY2RrLkR1cmF0aW9uO1xuXG4gIC8qKlxuICAgKiBXaGF0IGZ1bmN0aW9uIHRvIHVzZSBmb3IgYWdncmVnYXRpbmcuXG4gICAqXG4gICAqIENhbiBiZSBvbmUgb2YgdGhlIGZvbGxvd2luZzpcbiAgICpcbiAgICogLSBcIk1pbmltdW1cIiB8IFwibWluXCJcbiAgICogLSBcIk1heGltdW1cIiB8IFwibWF4XCJcbiAgICogLSBcIkF2ZXJhZ2VcIiB8IFwiYXZnXCJcbiAgICogLSBcIlN1bVwiIHwgXCJzdW1cIlxuICAgKiAtIFwiU2FtcGxlQ291bnQgfCBcIm5cIlxuICAgKiAtIFwicE5OLk5OXCJcbiAgICpcbiAgICogQGRlZmF1bHQgQXZlcmFnZVxuICAgKi9cbiAgcmVhZG9ubHkgc3RhdGlzdGljPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBEaW1lbnNpb25zIG9mIHRoZSBtZXRyaWNcbiAgICpcbiAgICogQGRlZmF1bHQgLSBObyBkaW1lbnNpb25zLlxuICAgKlxuICAgKiBAZGVwcmVjYXRlZCBVc2UgJ2RpbWVuc2lvbnNNYXAnIGluc3RlYWQuXG4gICAqL1xuICByZWFkb25seSBkaW1lbnNpb25zPzogRGltZW5zaW9uSGFzaDtcblxuICAvKipcbiAgICogRGltZW5zaW9ucyBvZiB0aGUgbWV0cmljXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gTm8gZGltZW5zaW9ucy5cbiAgICovXG4gIHJlYWRvbmx5IGRpbWVuc2lvbnNNYXA/OiBEaW1lbnNpb25zTWFwO1xuXG4gIC8qKlxuICAgKiBVbml0IHVzZWQgdG8gZmlsdGVyIHRoZSBtZXRyaWMgc3RyZWFtXG4gICAqXG4gICAqIE9ubHkgcmVmZXIgdG8gZGF0dW1zIGVtaXR0ZWQgdG8gdGhlIG1ldHJpYyBzdHJlYW0gd2l0aCB0aGUgZ2l2ZW4gdW5pdCBhbmRcbiAgICogaWdub3JlIGFsbCBvdGhlcnMuIE9ubHkgdXNlZnVsIHdoZW4gZGF0dW1zIGFyZSBiZWluZyBlbWl0dGVkIHRvIHRoZSBzYW1lXG4gICAqIG1ldHJpYyBzdHJlYW0gdW5kZXIgZGlmZmVyZW50IHVuaXRzLlxuICAgKlxuICAgKiBUaGUgZGVmYXVsdCBpcyB0byB1c2UgYWxsIG1hdHJpYyBkYXR1bXMgaW4gdGhlIHN0cmVhbSwgcmVnYXJkbGVzcyBvZiB1bml0LFxuICAgKiB3aGljaCBpcyByZWNvbW1lbmRlZCBpbiBuZWFybHkgYWxsIGNhc2VzLlxuICAgKlxuICAgKiBDbG91ZFdhdGNoIGRvZXMgbm90IGhvbm9yIHRoaXMgcHJvcGVydHkgZm9yIGdyYXBocy5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBBbGwgbWV0cmljIGRhdHVtcyBpbiB0aGUgZ2l2ZW4gbWV0cmljIHN0cmVhbVxuICAgKi9cbiAgcmVhZG9ubHkgdW5pdD86IFVuaXQ7XG5cbiAgLyoqXG4gICAqIExhYmVsIGZvciB0aGlzIG1ldHJpYyB3aGVuIGFkZGVkIHRvIGEgR3JhcGggaW4gYSBEYXNoYm9hcmRcbiAgICpcbiAgICogWW91IGNhbiB1c2UgW2R5bmFtaWMgbGFiZWxzXShodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQW1hem9uQ2xvdWRXYXRjaC9sYXRlc3QvbW9uaXRvcmluZy9ncmFwaC1keW5hbWljLWxhYmVscy5odG1sKVxuICAgKiB0byBzaG93IHN1bW1hcnkgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGVudGlyZSBkaXNwbGF5ZWQgdGltZSBzZXJpZXNcbiAgICogaW4gdGhlIGxlZ2VuZC4gRm9yIGV4YW1wbGUsIGlmIHlvdSB1c2U6XG4gICAqXG4gICAqIGBgYFxuICAgKiBbbWF4OiAke01BWH1dIE15TWV0cmljXG4gICAqIGBgYFxuICAgKlxuICAgKiBBcyB0aGUgbWV0cmljIGxhYmVsLCB0aGUgbWF4aW11bSB2YWx1ZSBpbiB0aGUgdmlzaWJsZSByYW5nZSB3aWxsXG4gICAqIGJlIHNob3duIG5leHQgdG8gdGhlIHRpbWUgc2VyaWVzIG5hbWUgaW4gdGhlIGdyYXBoJ3MgbGVnZW5kLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5vIGxhYmVsXG4gICAqL1xuICByZWFkb25seSBsYWJlbD86IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIGhleCBjb2xvciBjb2RlLCBwcmVmaXhlZCB3aXRoICcjJyAoZS5nLiAnIzAwZmYwMCcpLCB0byB1c2Ugd2hlbiB0aGlzIG1ldHJpYyBpcyByZW5kZXJlZCBvbiBhIGdyYXBoLlxuICAgKiBUaGUgYENvbG9yYCBjbGFzcyBoYXMgYSBzZXQgb2Ygc3RhbmRhcmQgY29sb3JzIHRoYXQgY2FuIGJlIHVzZWQgaGVyZS5cbiAgICogQGRlZmF1bHQgLSBBdXRvbWF0aWMgY29sb3JcbiAgICovXG4gIHJlYWRvbmx5IGNvbG9yPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBBY2NvdW50IHdoaWNoIHRoaXMgbWV0cmljIGNvbWVzIGZyb20uXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gRGVwbG95bWVudCBhY2NvdW50LlxuICAgKi9cbiAgcmVhZG9ubHkgYWNjb3VudD86IHN0cmluZztcblxuICAvKipcbiAgICogUmVnaW9uIHdoaWNoIHRoaXMgbWV0cmljIGNvbWVzIGZyb20uXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gRGVwbG95bWVudCByZWdpb24uXG4gICAqL1xuICByZWFkb25seSByZWdpb24/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogUHJvcGVydGllcyBmb3IgYSBtZXRyaWNcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBNZXRyaWNQcm9wcyBleHRlbmRzIENvbW1vbk1ldHJpY09wdGlvbnMge1xuICAvKipcbiAgICogTmFtZXNwYWNlIG9mIHRoZSBtZXRyaWMuXG4gICAqL1xuICByZWFkb25seSBuYW1lc3BhY2U6IHN0cmluZztcblxuICAvKipcbiAgICogTmFtZSBvZiB0aGUgbWV0cmljLlxuICAgKi9cbiAgcmVhZG9ubHkgbWV0cmljTmFtZTogc3RyaW5nO1xufVxuXG4vKipcbiAqIFByb3BlcnRpZXMgb2YgYSBtZXRyaWMgdGhhdCBjYW4gYmUgY2hhbmdlZFxuICovXG5leHBvcnQgaW50ZXJmYWNlIE1ldHJpY09wdGlvbnMgZXh0ZW5kcyBDb21tb25NZXRyaWNPcHRpb25zIHtcbn1cblxuLyoqXG4gKiBDb25maWd1cmFibGUgb3B0aW9ucyBmb3IgTWF0aEV4cHJlc3Npb25zXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTWF0aEV4cHJlc3Npb25PcHRpb25zIHtcbiAgLyoqXG4gICAqIExhYmVsIGZvciB0aGlzIGV4cHJlc3Npb24gd2hlbiBhZGRlZCB0byBhIEdyYXBoIGluIGEgRGFzaGJvYXJkXG4gICAqXG4gICAqIElmIHRoaXMgZXhwcmVzc2lvbiBldmFsdWF0ZXMgdG8gbW9yZSB0aGFuIG9uZSB0aW1lIHNlcmllcyAoZm9yXG4gICAqIGV4YW1wbGUsIHRocm91Z2ggdGhlIHVzZSBvZiBgTUVUUklDUygpYCBvciBgU0VBUkNIKClgIGV4cHJlc3Npb25zKSxcbiAgICogZWFjaCB0aW1lIHNlcmllcyB3aWxsIGFwcGVhciBpbiB0aGUgZ3JhcGggdXNpbmcgYSBjb21iaW5hdGlvbiBvZiB0aGVcbiAgICogZXhwcmVzc2lvbiBsYWJlbCBhbmQgdGhlIGluZGl2aWR1YWwgbWV0cmljIGxhYmVsLiBTcGVjaWZ5IHRoZSBlbXB0eVxuICAgKiBzdHJpbmcgKGAnJ2ApIHRvIHN1cHByZXNzIHRoZSBleHByZXNzaW9uIGxhYmVsIGFuZCBvbmx5IGtlZXAgdGhlXG4gICAqIG1ldHJpYyBsYWJlbC5cbiAgICpcbiAgICogWW91IGNhbiB1c2UgW2R5bmFtaWMgbGFiZWxzXShodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQW1hem9uQ2xvdWRXYXRjaC9sYXRlc3QvbW9uaXRvcmluZy9ncmFwaC1keW5hbWljLWxhYmVscy5odG1sKVxuICAgKiB0byBzaG93IHN1bW1hcnkgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGRpc3BsYXllZCB0aW1lIHNlcmllc1xuICAgKiBpbiB0aGUgbGVnZW5kLiBGb3IgZXhhbXBsZSwgaWYgeW91IHVzZTpcbiAgICpcbiAgICogYGBgXG4gICAqIFttYXg6ICR7TUFYfV0gTXlNZXRyaWNcbiAgICogYGBgXG4gICAqXG4gICAqIEFzIHRoZSBtZXRyaWMgbGFiZWwsIHRoZSBtYXhpbXVtIHZhbHVlIGluIHRoZSB2aXNpYmxlIHJhbmdlIHdpbGxcbiAgICogYmUgc2hvd24gbmV4dCB0byB0aGUgdGltZSBzZXJpZXMgbmFtZSBpbiB0aGUgZ3JhcGgncyBsZWdlbmQuIElmIHRoZVxuICAgKiBtYXRoIGV4cHJlc3Npb24gcHJvZHVjZXMgbW9yZSB0aGFuIG9uZSB0aW1lIHNlcmllcywgdGhlIG1heGltdW1cbiAgICogd2lsbCBiZSBzaG93biBmb3IgZWFjaCBpbmRpdmlkdWFsIHRpbWUgc2VyaWVzIHByb2R1Y2UgYnkgdGhpc1xuICAgKiBtYXRoIGV4cHJlc3Npb24uXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gRXhwcmVzc2lvbiB2YWx1ZSBpcyB1c2VkIGFzIGxhYmVsXG4gICAqL1xuICByZWFkb25seSBsYWJlbD86IHN0cmluZztcblxuICAvKipcbiAgICogQ29sb3IgZm9yIHRoaXMgbWV0cmljIHdoZW4gYWRkZWQgdG8gYSBHcmFwaCBpbiBhIERhc2hib2FyZFxuICAgKlxuICAgKiBAZGVmYXVsdCAtIEF1dG9tYXRpYyBjb2xvclxuICAgKi9cbiAgcmVhZG9ubHkgY29sb3I/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBwZXJpb2Qgb3ZlciB3aGljaCB0aGUgZXhwcmVzc2lvbidzIHN0YXRpc3RpY3MgYXJlIGFwcGxpZWQuXG4gICAqXG4gICAqIFRoaXMgcGVyaW9kIG92ZXJyaWRlcyBhbGwgcGVyaW9kcyBpbiB0aGUgbWV0cmljcyB1c2VkIGluIHRoaXNcbiAgICogbWF0aCBleHByZXNzaW9uLlxuICAgKlxuICAgKiBAZGVmYXVsdCBEdXJhdGlvbi5taW51dGVzKDUpXG4gICAqL1xuICByZWFkb25seSBwZXJpb2Q/OiBjZGsuRHVyYXRpb247XG5cbiAgLyoqXG4gICAqIEFjY291bnQgdG8gZXZhbHVhdGUgc2VhcmNoIGV4cHJlc3Npb25zIHdpdGhpbi5cbiAgICpcbiAgICogU3BlY2lmeWluZyBhIHNlYXJjaEFjY291bnQgaGFzIG5vIGVmZmVjdCB0byB0aGUgYWNjb3VudCB1c2VkXG4gICAqIGZvciBtZXRyaWNzIHdpdGhpbiB0aGUgZXhwcmVzc2lvbiAocGFzc2VkIHZpYSB1c2luZ01ldHJpY3MpLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIERlcGxveW1lbnQgYWNjb3VudC5cbiAgICovXG4gIHJlYWRvbmx5IHNlYXJjaEFjY291bnQ/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAgKiBSZWdpb24gdG8gZXZhbHVhdGUgc2VhcmNoIGV4cHJlc3Npb25zIHdpdGhpbi5cbiAgICAqXG4gICAgKiBTcGVjaWZ5aW5nIGEgc2VhcmNoUmVnaW9uIGhhcyBubyBlZmZlY3QgdG8gdGhlIHJlZ2lvbiB1c2VkXG4gICAgKiBmb3IgbWV0cmljcyB3aXRoaW4gdGhlIGV4cHJlc3Npb24gKHBhc3NlZCB2aWEgdXNpbmdNZXRyaWNzKS5cbiAgICAqXG4gICAgKiBAZGVmYXVsdCAtIERlcGxveW1lbnQgcmVnaW9uLlxuICAgICovXG4gIHJlYWRvbmx5IHNlYXJjaFJlZ2lvbj86IHN0cmluZztcbn1cblxuLyoqXG4gKiBQcm9wZXJ0aWVzIGZvciBhIE1hdGhFeHByZXNzaW9uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTWF0aEV4cHJlc3Npb25Qcm9wcyBleHRlbmRzIE1hdGhFeHByZXNzaW9uT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBUaGUgZXhwcmVzc2lvbiBkZWZpbmluZyB0aGUgbWV0cmljLlxuICAgKlxuICAgKiBXaGVuIGFuIGV4cHJlc3Npb24gY29udGFpbnMgYSBTRUFSQ0ggZnVuY3Rpb24sIGl0IGNhbm5vdCBiZSB1c2VkXG4gICAqIHdpdGhpbiBhbiBBbGFybS5cbiAgICovXG4gIHJlYWRvbmx5IGV4cHJlc3Npb246IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIG1ldHJpY3MgdXNlZCBpbiB0aGUgZXhwcmVzc2lvbiwgaW4gYSBtYXAuXG4gICAqXG4gICAqIFRoZSBrZXkgaXMgdGhlIGlkZW50aWZpZXIgdGhhdCByZXByZXNlbnRzIHRoZSBnaXZlbiBtZXRyaWMgaW4gdGhlXG4gICAqIGV4cHJlc3Npb24sIGFuZCB0aGUgdmFsdWUgaXMgdGhlIGFjdHVhbCBNZXRyaWMgb2JqZWN0LlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIEVtcHR5IG1hcC5cbiAgICovXG4gIHJlYWRvbmx5IHVzaW5nTWV0cmljcz86IFJlY29yZDxzdHJpbmcsIElNZXRyaWM+O1xufVxuXG4vKipcbiAqIEEgbWV0cmljIGVtaXR0ZWQgYnkgYSBzZXJ2aWNlXG4gKlxuICogVGhlIG1ldHJpYyBpcyBhIGNvbWJpbmF0aW9uIG9mIGEgbWV0cmljIGlkZW50aWZpZXIgKG5hbWVzcGFjZSwgbmFtZSBhbmQgZGltZW5zaW9ucylcbiAqIGFuZCBhbiBhZ2dyZWdhdGlvbiBmdW5jdGlvbiAoc3RhdGlzdGljLCBwZXJpb2QgYW5kIHVuaXQpLlxuICpcbiAqIEl0IGFsc28gY29udGFpbnMgbWV0YWRhdGEgd2hpY2ggaXMgdXNlZCBvbmx5IGluIGdyYXBocywgc3VjaCBhcyBjb2xvciBhbmQgbGFiZWwuXG4gKiBJdCBtYWtlcyBzZW5zZSB0byBlbWJlZCB0aGlzIGluIGhlcmUsIHNvIHRoYXQgY29tcG91bmQgY29uc3RydWN0cyBjYW4gYXR0YWNoXG4gKiB0aGF0IG1ldGFkYXRhIHRvIG1ldHJpY3MgdGhleSBleHBvc2UuXG4gKlxuICogVGhpcyBjbGFzcyBkb2VzIG5vdCByZXByZXNlbnQgYSByZXNvdXJjZSwgc28gaGVuY2UgaXMgbm90IGEgY29uc3RydWN0LiBJbnN0ZWFkLFxuICogTWV0cmljIGlzIGFuIGFic3RyYWN0aW9uIHRoYXQgbWFrZXMgaXQgZWFzeSB0byBzcGVjaWZ5IG1ldHJpY3MgZm9yIHVzZSBpbiBib3RoXG4gKiBhbGFybXMgYW5kIGdyYXBocy5cbiAqL1xuZXhwb3J0IGNsYXNzIE1ldHJpYyBpbXBsZW1lbnRzIElNZXRyaWMge1xuICAvKipcbiAgICogR3JhbnQgcGVybWlzc2lvbnMgdG8gdGhlIGdpdmVuIGlkZW50aXR5IHRvIHdyaXRlIG1ldHJpY3MuXG4gICAqXG4gICAqIEBwYXJhbSBncmFudGVlIFRoZSBJQU0gaWRlbnRpdHkgdG8gZ2l2ZSBwZXJtaXNzaW9ucyB0by5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgZ3JhbnRQdXRNZXRyaWNEYXRhKGdyYW50ZWU6IGlhbS5JR3JhbnRhYmxlKTogaWFtLkdyYW50IHtcbiAgICByZXR1cm4gaWFtLkdyYW50LmFkZFRvUHJpbmNpcGFsKHtcbiAgICAgIGdyYW50ZWUsXG4gICAgICBhY3Rpb25zOiBbJ2Nsb3Vkd2F0Y2g6UHV0TWV0cmljRGF0YSddLFxuICAgICAgcmVzb3VyY2VBcm5zOiBbJyonXSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKiBEaW1lbnNpb25zIG9mIHRoaXMgbWV0cmljICovXG4gIHB1YmxpYyByZWFkb25seSBkaW1lbnNpb25zPzogRGltZW5zaW9uSGFzaDtcbiAgLyoqIE5hbWVzcGFjZSBvZiB0aGlzIG1ldHJpYyAqL1xuICBwdWJsaWMgcmVhZG9ubHkgbmFtZXNwYWNlOiBzdHJpbmc7XG4gIC8qKiBOYW1lIG9mIHRoaXMgbWV0cmljICovXG4gIHB1YmxpYyByZWFkb25seSBtZXRyaWNOYW1lOiBzdHJpbmc7XG4gIC8qKiBQZXJpb2Qgb2YgdGhpcyBtZXRyaWMgKi9cbiAgcHVibGljIHJlYWRvbmx5IHBlcmlvZDogY2RrLkR1cmF0aW9uO1xuICAvKiogU3RhdGlzdGljIG9mIHRoaXMgbWV0cmljICovXG4gIHB1YmxpYyByZWFkb25seSBzdGF0aXN0aWM6IHN0cmluZztcbiAgLyoqIExhYmVsIGZvciB0aGlzIG1ldHJpYyB3aGVuIGFkZGVkIHRvIGEgR3JhcGggaW4gYSBEYXNoYm9hcmQgKi9cbiAgcHVibGljIHJlYWRvbmx5IGxhYmVsPzogc3RyaW5nO1xuICAvKiogVGhlIGhleCBjb2xvciBjb2RlIHVzZWQgd2hlbiB0aGlzIG1ldHJpYyBpcyByZW5kZXJlZCBvbiBhIGdyYXBoLiAqL1xuICBwdWJsaWMgcmVhZG9ubHkgY29sb3I/OiBzdHJpbmc7XG5cbiAgLyoqIFVuaXQgb2YgdGhlIG1ldHJpYy4gKi9cbiAgcHVibGljIHJlYWRvbmx5IHVuaXQ/OiBVbml0O1xuXG4gIC8qKiBBY2NvdW50IHdoaWNoIHRoaXMgbWV0cmljIGNvbWVzIGZyb20gKi9cbiAgcHVibGljIHJlYWRvbmx5IGFjY291bnQ/OiBzdHJpbmc7XG5cbiAgLyoqIFJlZ2lvbiB3aGljaCB0aGlzIG1ldHJpYyBjb21lcyBmcm9tLiAqL1xuICBwdWJsaWMgcmVhZG9ubHkgcmVnaW9uPzogc3RyaW5nO1xuXG4gIC8qKiBXYXJuaW5ncyBhdHRhY2hlZCB0byB0aGlzIG1ldHJpYy4gKi9cbiAgcHVibGljIHJlYWRvbmx5IHdhcm5pbmdzPzogc3RyaW5nW107XG5cbiAgY29uc3RydWN0b3IocHJvcHM6IE1ldHJpY1Byb3BzKSB7XG4gICAgdGhpcy5wZXJpb2QgPSBwcm9wcy5wZXJpb2QgfHwgY2RrLkR1cmF0aW9uLm1pbnV0ZXMoNSk7XG4gICAgY29uc3QgcGVyaW9kU2VjID0gdGhpcy5wZXJpb2QudG9TZWNvbmRzKCk7XG4gICAgaWYgKHBlcmlvZFNlYyAhPT0gMSAmJiBwZXJpb2RTZWMgIT09IDUgJiYgcGVyaW9kU2VjICE9PSAxMCAmJiBwZXJpb2RTZWMgIT09IDMwICYmIHBlcmlvZFNlYyAlIDYwICE9PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYCdwZXJpb2QnIG11c3QgYmUgMSwgNSwgMTAsIDMwLCBvciBhIG11bHRpcGxlIG9mIDYwIHNlY29uZHMsIHJlY2VpdmVkICR7cGVyaW9kU2VjfWApO1xuICAgIH1cbiAgICB0aGlzLmRpbWVuc2lvbnMgPSB0aGlzLnZhbGlkYXRlRGltZW5zaW9ucyhwcm9wcy5kaW1lbnNpb25zTWFwID8/IHByb3BzLmRpbWVuc2lvbnMpO1xuICAgIHRoaXMubmFtZXNwYWNlID0gcHJvcHMubmFtZXNwYWNlO1xuICAgIHRoaXMubWV0cmljTmFtZSA9IHByb3BzLm1ldHJpY05hbWU7XG4gICAgLy8gVHJ5IHBhcnNpbmcsIHRoaXMgd2lsbCB0aHJvdyBpZiBpdCdzIG5vdCBhIHZhbGlkIHN0YXRcbiAgICB0aGlzLnN0YXRpc3RpYyA9IG5vcm1hbGl6ZVN0YXRpc3RpYyhwcm9wcy5zdGF0aXN0aWMgfHwgJ0F2ZXJhZ2UnKTtcbiAgICB0aGlzLmxhYmVsID0gcHJvcHMubGFiZWw7XG4gICAgdGhpcy5jb2xvciA9IHByb3BzLmNvbG9yO1xuICAgIHRoaXMudW5pdCA9IHByb3BzLnVuaXQ7XG4gICAgdGhpcy5hY2NvdW50ID0gcHJvcHMuYWNjb3VudDtcbiAgICB0aGlzLnJlZ2lvbiA9IHByb3BzLnJlZ2lvbjtcbiAgICB0aGlzLndhcm5pbmdzID0gdW5kZWZpbmVkO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiBhIGNvcHkgb2YgTWV0cmljIGB3aXRoYCBwcm9wZXJ0aWVzIGNoYW5nZWQuXG4gICAqXG4gICAqIEFsbCBwcm9wZXJ0aWVzIGV4Y2VwdCBuYW1lc3BhY2UgYW5kIG1ldHJpY05hbWUgY2FuIGJlIGNoYW5nZWQuXG4gICAqXG4gICAqIEBwYXJhbSBwcm9wcyBUaGUgc2V0IG9mIHByb3BlcnRpZXMgdG8gY2hhbmdlLlxuICAgKi9cbiAgcHVibGljIHdpdGgocHJvcHM6IE1ldHJpY09wdGlvbnMpOiBNZXRyaWMge1xuICAgIC8vIFNob3J0LWNpcmN1aXQgY3JlYXRpbmcgYSBuZXcgb2JqZWN0IGlmIHRoZXJlIHdvdWxkIGJlIG5vIGVmZmVjdGl2ZSBjaGFuZ2VcbiAgICBpZiAoKHByb3BzLmxhYmVsID09PSB1bmRlZmluZWQgfHwgcHJvcHMubGFiZWwgPT09IHRoaXMubGFiZWwpXG4gICAgICAmJiAocHJvcHMuY29sb3IgPT09IHVuZGVmaW5lZCB8fCBwcm9wcy5jb2xvciA9PT0gdGhpcy5jb2xvcilcbiAgICAgICYmIChwcm9wcy5zdGF0aXN0aWMgPT09IHVuZGVmaW5lZCB8fCBwcm9wcy5zdGF0aXN0aWMgPT09IHRoaXMuc3RhdGlzdGljKVxuICAgICAgJiYgKHByb3BzLnVuaXQgPT09IHVuZGVmaW5lZCB8fCBwcm9wcy51bml0ID09PSB0aGlzLnVuaXQpXG4gICAgICAmJiAocHJvcHMuYWNjb3VudCA9PT0gdW5kZWZpbmVkIHx8IHByb3BzLmFjY291bnQgPT09IHRoaXMuYWNjb3VudClcbiAgICAgICYmIChwcm9wcy5yZWdpb24gPT09IHVuZGVmaW5lZCB8fCBwcm9wcy5yZWdpb24gPT09IHRoaXMucmVnaW9uKVxuICAgICAgLy8gRm9yIHRoZXNlIHdlJ3JlIG5vdCBnb2luZyB0byBkbyBkZWVwIGVxdWFsaXR5LCBtaXNzZXMgc29tZSBvcHBvcnR1bml0eSBmb3Igb3B0aW1pemF0aW9uXG4gICAgICAvLyBidXQgdGhhdCdzIG9rYXkuXG4gICAgICAmJiAocHJvcHMuZGltZW5zaW9ucyA9PT0gdW5kZWZpbmVkKVxuICAgICAgJiYgKHByb3BzLmRpbWVuc2lvbnNNYXAgPT09IHVuZGVmaW5lZClcbiAgICAgICYmIChwcm9wcy5wZXJpb2QgPT09IHVuZGVmaW5lZCB8fCBwcm9wcy5wZXJpb2QudG9TZWNvbmRzKCkgPT09IHRoaXMucGVyaW9kLnRvU2Vjb25kcygpKSkge1xuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgcmV0dXJuIG5ldyBNZXRyaWMoe1xuICAgICAgZGltZW5zaW9uc01hcDogcHJvcHMuZGltZW5zaW9uc01hcCA/PyBwcm9wcy5kaW1lbnNpb25zID8/IHRoaXMuZGltZW5zaW9ucyxcbiAgICAgIG5hbWVzcGFjZTogdGhpcy5uYW1lc3BhY2UsXG4gICAgICBtZXRyaWNOYW1lOiB0aGlzLm1ldHJpY05hbWUsXG4gICAgICBwZXJpb2Q6IGlmVW5kZWZpbmVkKHByb3BzLnBlcmlvZCwgdGhpcy5wZXJpb2QpLFxuICAgICAgc3RhdGlzdGljOiBpZlVuZGVmaW5lZChwcm9wcy5zdGF0aXN0aWMsIHRoaXMuc3RhdGlzdGljKSxcbiAgICAgIHVuaXQ6IGlmVW5kZWZpbmVkKHByb3BzLnVuaXQsIHRoaXMudW5pdCksXG4gICAgICBsYWJlbDogaWZVbmRlZmluZWQocHJvcHMubGFiZWwsIHRoaXMubGFiZWwpLFxuICAgICAgY29sb3I6IGlmVW5kZWZpbmVkKHByb3BzLmNvbG9yLCB0aGlzLmNvbG9yKSxcbiAgICAgIGFjY291bnQ6IGlmVW5kZWZpbmVkKHByb3BzLmFjY291bnQsIHRoaXMuYWNjb3VudCksXG4gICAgICByZWdpb246IGlmVW5kZWZpbmVkKHByb3BzLnJlZ2lvbiwgdGhpcy5yZWdpb24pLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEF0dGFjaCB0aGUgbWV0cmljIG9iamVjdCB0byB0aGUgZ2l2ZW4gY29uc3RydWN0IHNjb3BlXG4gICAqXG4gICAqIFJldHVybnMgYSBNZXRyaWMgb2JqZWN0IHRoYXQgdXNlcyB0aGUgYWNjb3VudCBhbmQgcmVnaW9uIGZyb20gdGhlIFN0YWNrXG4gICAqIHRoZSBnaXZlbiBjb25zdHJ1Y3QgaXMgZGVmaW5lZCBpbi4gSWYgdGhlIG1ldHJpYyBpcyBzdWJzZXF1ZW50bHkgdXNlZFxuICAgKiBpbiBhIERhc2hib2FyZCBvciBBbGFybSBpbiBhIGRpZmZlcmVudCBTdGFjayBkZWZpbmVkIGluIGEgZGlmZmVyZW50XG4gICAqIGFjY291bnQgb3IgcmVnaW9uLCB0aGUgYXBwcm9wcmlhdGUgJ3JlZ2lvbicgYW5kICdhY2NvdW50JyBmaWVsZHNcbiAgICogd2lsbCBiZSBhZGRlZCB0byBpdC5cbiAgICpcbiAgICogSWYgdGhlIHNjb3BlIHdlIGF0dGFjaCB0byBpcyBpbiBhbiBlbnZpcm9ubWVudC1hZ25vc3RpYyBzdGFjayxcbiAgICogbm90aGluZyBpcyBkb25lIGFuZCB0aGUgc2FtZSBNZXRyaWMgb2JqZWN0IGlzIHJldHVybmVkLlxuICAgKi9cbiAgcHVibGljIGF0dGFjaFRvKHNjb3BlOiBjb25zdHJ1Y3RzLklDb25zdHJ1Y3QpOiBNZXRyaWMge1xuICAgIGNvbnN0IHN0YWNrID0gY2RrLlN0YWNrLm9mKHNjb3BlKTtcblxuICAgIHJldHVybiB0aGlzLndpdGgoe1xuICAgICAgcmVnaW9uOiBjZGsuVG9rZW4uaXNVbnJlc29sdmVkKHN0YWNrLnJlZ2lvbikgPyB1bmRlZmluZWQgOiBzdGFjay5yZWdpb24sXG4gICAgICBhY2NvdW50OiBjZGsuVG9rZW4uaXNVbnJlc29sdmVkKHN0YWNrLmFjY291bnQpID8gdW5kZWZpbmVkIDogc3RhY2suYWNjb3VudCxcbiAgICB9KTtcbiAgfVxuXG4gIHB1YmxpYyB0b01ldHJpY0NvbmZpZygpOiBNZXRyaWNDb25maWcge1xuICAgIGNvbnN0IGRpbXMgPSB0aGlzLmRpbWVuc2lvbnNBc0xpc3QoKTtcbiAgICByZXR1cm4ge1xuICAgICAgbWV0cmljU3RhdDoge1xuICAgICAgICBkaW1lbnNpb25zOiBkaW1zLmxlbmd0aCA+IDAgPyBkaW1zIDogdW5kZWZpbmVkLFxuICAgICAgICBuYW1lc3BhY2U6IHRoaXMubmFtZXNwYWNlLFxuICAgICAgICBtZXRyaWNOYW1lOiB0aGlzLm1ldHJpY05hbWUsXG4gICAgICAgIHBlcmlvZDogdGhpcy5wZXJpb2QsXG4gICAgICAgIHN0YXRpc3RpYzogdGhpcy5zdGF0aXN0aWMsXG4gICAgICAgIHVuaXRGaWx0ZXI6IHRoaXMudW5pdCxcbiAgICAgICAgYWNjb3VudDogdGhpcy5hY2NvdW50LFxuICAgICAgICByZWdpb246IHRoaXMucmVnaW9uLFxuICAgICAgfSxcbiAgICAgIHJlbmRlcmluZ1Byb3BlcnRpZXM6IHtcbiAgICAgICAgY29sb3I6IHRoaXMuY29sb3IsXG4gICAgICAgIGxhYmVsOiB0aGlzLmxhYmVsLFxuICAgICAgfSxcbiAgICB9O1xuICB9XG5cbiAgLyoqIEBkZXByZWNhdGVkIHVzZSB0b01ldHJpY0NvbmZpZygpICovXG4gIHB1YmxpYyB0b0FsYXJtQ29uZmlnKCk6IE1ldHJpY0FsYXJtQ29uZmlnIHtcbiAgICBjb25zdCBtZXRyaWNDb25maWcgPSB0aGlzLnRvTWV0cmljQ29uZmlnKCk7XG4gICAgaWYgKG1ldHJpY0NvbmZpZy5tZXRyaWNTdGF0ID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignVXNpbmcgYSBtYXRoIGV4cHJlc3Npb24gaXMgbm90IHN1cHBvcnRlZCBoZXJlLiBQYXNzIGEgXFwnTWV0cmljXFwnIG9iamVjdCBpbnN0ZWFkJyk7XG4gICAgfVxuXG4gICAgY29uc3Qgc3RhdCA9IHBhcnNlU3RhdGlzdGljKG1ldHJpY0NvbmZpZy5tZXRyaWNTdGF0LnN0YXRpc3RpYyk7XG4gICAgcmV0dXJuIHtcbiAgICAgIGRpbWVuc2lvbnM6IG1ldHJpY0NvbmZpZy5tZXRyaWNTdGF0LmRpbWVuc2lvbnMsXG4gICAgICBuYW1lc3BhY2U6IG1ldHJpY0NvbmZpZy5tZXRyaWNTdGF0Lm5hbWVzcGFjZSxcbiAgICAgIG1ldHJpY05hbWU6IG1ldHJpY0NvbmZpZy5tZXRyaWNTdGF0Lm1ldHJpY05hbWUsXG4gICAgICBwZXJpb2Q6IG1ldHJpY0NvbmZpZy5tZXRyaWNTdGF0LnBlcmlvZC50b1NlY29uZHMoKSxcbiAgICAgIHN0YXRpc3RpYzogc3RhdC50eXBlID09PSAnc2ltcGxlJyA/IHN0YXQuc3RhdGlzdGljIDogdW5kZWZpbmVkLFxuICAgICAgZXh0ZW5kZWRTdGF0aXN0aWM6IHN0YXQudHlwZSA9PT0gJ3BlcmNlbnRpbGUnID8gJ3AnICsgc3RhdC5wZXJjZW50aWxlIDogdW5kZWZpbmVkLFxuICAgICAgdW5pdDogdGhpcy51bml0LFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogQGRlcHJlY2F0ZWQgdXNlIHRvTWV0cmljQ29uZmlnKClcbiAgICovXG4gIHB1YmxpYyB0b0dyYXBoQ29uZmlnKCk6IE1ldHJpY0dyYXBoQ29uZmlnIHtcbiAgICBjb25zdCBtZXRyaWNDb25maWcgPSB0aGlzLnRvTWV0cmljQ29uZmlnKCk7XG4gICAgaWYgKG1ldHJpY0NvbmZpZy5tZXRyaWNTdGF0ID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignVXNpbmcgYSBtYXRoIGV4cHJlc3Npb24gaXMgbm90IHN1cHBvcnRlZCBoZXJlLiBQYXNzIGEgXFwnTWV0cmljXFwnIG9iamVjdCBpbnN0ZWFkJyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGRpbWVuc2lvbnM6IG1ldHJpY0NvbmZpZy5tZXRyaWNTdGF0LmRpbWVuc2lvbnMsXG4gICAgICBuYW1lc3BhY2U6IG1ldHJpY0NvbmZpZy5tZXRyaWNTdGF0Lm5hbWVzcGFjZSxcbiAgICAgIG1ldHJpY05hbWU6IG1ldHJpY0NvbmZpZy5tZXRyaWNTdGF0Lm1ldHJpY05hbWUsXG4gICAgICByZW5kZXJpbmdQcm9wZXJ0aWVzOiB7XG4gICAgICAgIHBlcmlvZDogbWV0cmljQ29uZmlnLm1ldHJpY1N0YXQucGVyaW9kLnRvU2Vjb25kcygpLFxuICAgICAgICBzdGF0OiBtZXRyaWNDb25maWcubWV0cmljU3RhdC5zdGF0aXN0aWMsXG4gICAgICAgIGNvbG9yOiBhc1N0cmluZyhtZXRyaWNDb25maWcucmVuZGVyaW5nUHJvcGVydGllcz8uY29sb3IpLFxuICAgICAgICBsYWJlbDogYXNTdHJpbmcobWV0cmljQ29uZmlnLnJlbmRlcmluZ1Byb3BlcnRpZXM/LmxhYmVsKSxcbiAgICAgIH0sXG4gICAgICAvLyBkZXByZWNhdGVkIHByb3BlcnRpZXMgZm9yIGJhY2t3YXJkcyBjb21wYXRpYmlsaXR5XG4gICAgICBwZXJpb2Q6IG1ldHJpY0NvbmZpZy5tZXRyaWNTdGF0LnBlcmlvZC50b1NlY29uZHMoKSxcbiAgICAgIHN0YXRpc3RpYzogbWV0cmljQ29uZmlnLm1ldHJpY1N0YXQuc3RhdGlzdGljLFxuICAgICAgY29sb3I6IGFzU3RyaW5nKG1ldHJpY0NvbmZpZy5yZW5kZXJpbmdQcm9wZXJ0aWVzPy5jb2xvciksXG4gICAgICBsYWJlbDogYXNTdHJpbmcobWV0cmljQ29uZmlnLnJlbmRlcmluZ1Byb3BlcnRpZXM/LmxhYmVsKSxcbiAgICAgIHVuaXQ6IHRoaXMudW5pdCxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIE1ha2UgYSBuZXcgQWxhcm0gZm9yIHRoaXMgbWV0cmljXG4gICAqXG4gICAqIENvbWJpbmVzIGJvdGggcHJvcGVydGllcyB0aGF0IG1heSBhZGp1c3QgdGhlIG1ldHJpYyAoYWdncmVnYXRpb24pIGFzIHdlbGxcbiAgICogYXMgYWxhcm0gcHJvcGVydGllcy5cbiAgICovXG4gIHB1YmxpYyBjcmVhdGVBbGFybShzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogQ3JlYXRlQWxhcm1PcHRpb25zKTogQWxhcm0ge1xuICAgIHJldHVybiBuZXcgQWxhcm0oc2NvcGUsIGlkLCB7XG4gICAgICBtZXRyaWM6IHRoaXMud2l0aCh7XG4gICAgICAgIHN0YXRpc3RpYzogcHJvcHMuc3RhdGlzdGljLFxuICAgICAgICBwZXJpb2Q6IHByb3BzLnBlcmlvZCxcbiAgICAgIH0pLFxuICAgICAgYWxhcm1OYW1lOiBwcm9wcy5hbGFybU5hbWUsXG4gICAgICBhbGFybURlc2NyaXB0aW9uOiBwcm9wcy5hbGFybURlc2NyaXB0aW9uLFxuICAgICAgY29tcGFyaXNvbk9wZXJhdG9yOiBwcm9wcy5jb21wYXJpc29uT3BlcmF0b3IsXG4gICAgICBkYXRhcG9pbnRzVG9BbGFybTogcHJvcHMuZGF0YXBvaW50c1RvQWxhcm0sXG4gICAgICB0aHJlc2hvbGQ6IHByb3BzLnRocmVzaG9sZCxcbiAgICAgIGV2YWx1YXRpb25QZXJpb2RzOiBwcm9wcy5ldmFsdWF0aW9uUGVyaW9kcyxcbiAgICAgIGV2YWx1YXRlTG93U2FtcGxlQ291bnRQZXJjZW50aWxlOiBwcm9wcy5ldmFsdWF0ZUxvd1NhbXBsZUNvdW50UGVyY2VudGlsZSxcbiAgICAgIHRyZWF0TWlzc2luZ0RhdGE6IHByb3BzLnRyZWF0TWlzc2luZ0RhdGEsXG4gICAgICBhY3Rpb25zRW5hYmxlZDogcHJvcHMuYWN0aW9uc0VuYWJsZWQsXG4gICAgfSk7XG4gIH1cblxuICBwdWJsaWMgdG9TdHJpbmcoKSB7XG4gICAgcmV0dXJuIHRoaXMubGFiZWwgfHwgdGhpcy5tZXRyaWNOYW1lO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiB0aGUgZGltZW5zaW9ucyBvZiB0aGlzIE1ldHJpYyBhcyBhIGxpc3Qgb2YgRGltZW5zaW9uLlxuICAgKi9cbiAgcHJpdmF0ZSBkaW1lbnNpb25zQXNMaXN0KCk6IERpbWVuc2lvbltdIHtcbiAgICBjb25zdCBkaW1zID0gdGhpcy5kaW1lbnNpb25zO1xuXG4gICAgaWYgKGRpbXMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cblxuICAgIGNvbnN0IGxpc3QgPSBPYmplY3Qua2V5cyhkaW1zKS5zb3J0KCkubWFwKGtleSA9PiAoeyBuYW1lOiBrZXksIHZhbHVlOiBkaW1zW2tleV0gfSkpO1xuXG4gICAgcmV0dXJuIGxpc3Q7XG4gIH1cblxuICBwcml2YXRlIHZhbGlkYXRlRGltZW5zaW9ucyhkaW1zPzogRGltZW5zaW9uSGFzaCk6IERpbWVuc2lvbkhhc2ggfCB1bmRlZmluZWQge1xuICAgIGlmICghZGltcykge1xuICAgICAgcmV0dXJuIGRpbXM7XG4gICAgfVxuXG4gICAgdmFyIGRpbXNBcnJheSA9IE9iamVjdC5rZXlzKGRpbXMpO1xuICAgIGlmIChkaW1zQXJyYXk/Lmxlbmd0aCA+IDEwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFRoZSBtYXhpbXVtIG51bWJlciBvZiBkaW1lbnNpb25zIGlzIDEwLCByZWNlaXZlZCAke2RpbXNBcnJheS5sZW5ndGh9YCk7XG4gICAgfVxuXG4gICAgZGltc0FycmF5Lm1hcChrZXkgPT4ge1xuICAgICAgaWYgKGRpbXNba2V5XSA9PT0gdW5kZWZpbmVkIHx8IGRpbXNba2V5XSA9PT0gbnVsbCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYERpbWVuc2lvbiB2YWx1ZSBvZiAnJHtkaW1zW2tleV19JyBpcyBpbnZhbGlkYCk7XG4gICAgICB9O1xuICAgICAgaWYgKGtleS5sZW5ndGggPCAxIHx8IGtleS5sZW5ndGggPiAyNTUpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBEaW1lbnNpb24gbmFtZSBtdXN0IGJlIGF0IGxlYXN0IDEgYW5kIG5vIG1vcmUgdGhhbiAyNTUgY2hhcmFjdGVyczsgcmVjZWl2ZWQgJHtrZXl9YCk7XG4gICAgICB9O1xuXG4gICAgICBpZiAoZGltc1trZXldLmxlbmd0aCA8IDEgfHwgZGltc1trZXldLmxlbmd0aCA+IDI1NSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYERpbWVuc2lvbiB2YWx1ZSBtdXN0IGJlIGF0IGxlYXN0IDEgYW5kIG5vIG1vcmUgdGhhbiAyNTUgY2hhcmFjdGVyczsgcmVjZWl2ZWQgJHtkaW1zW2tleV19YCk7XG4gICAgICB9O1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIGRpbXM7XG4gIH1cbn1cblxuZnVuY3Rpb24gYXNTdHJpbmcoeD86IHVua25vd24pOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBpZiAoeCA9PT0gdW5kZWZpbmVkKSB7IHJldHVybiB1bmRlZmluZWQ7IH1cbiAgaWYgKHR5cGVvZiB4ICE9PSAnc3RyaW5nJykge1xuICAgIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQgc3RyaW5nLCBnb3QgJHt4fWApO1xuICB9XG4gIHJldHVybiB4O1xufVxuXG4vKipcbiAqIEEgbWF0aCBleHByZXNzaW9uIGJ1aWx0IHdpdGggbWV0cmljKHMpIGVtaXR0ZWQgYnkgYSBzZXJ2aWNlXG4gKlxuICogVGhlIG1hdGggZXhwcmVzc2lvbiBpcyBhIGNvbWJpbmF0aW9uIG9mIGFuIGV4cHJlc3Npb24gKHgreSkgYW5kIG1ldHJpY3MgdG8gYXBwbHkgZXhwcmVzc2lvbiBvbi5cbiAqIEl0IGFsc28gY29udGFpbnMgbWV0YWRhdGEgd2hpY2ggaXMgdXNlZCBvbmx5IGluIGdyYXBocywgc3VjaCBhcyBjb2xvciBhbmQgbGFiZWwuXG4gKiBJdCBtYWtlcyBzZW5zZSB0byBlbWJlZCB0aGlzIGluIGhlcmUsIHNvIHRoYXQgY29tcG91bmQgY29uc3RydWN0cyBjYW4gYXR0YWNoXG4gKiB0aGF0IG1ldGFkYXRhIHRvIG1ldHJpY3MgdGhleSBleHBvc2UuXG4gKlxuICogTWF0aEV4cHJlc3Npb24gY2FuIGFsc28gYmUgdXNlZCBmb3Igc2VhcmNoIGV4cHJlc3Npb25zLiBJbiB0aGlzIGNhc2UsXG4gKiBpdCBhbHNvIG9wdGlvbmFsbHkgYWNjZXB0cyBhIHNlYXJjaFJlZ2lvbiBhbmQgc2VhcmNoQWNjb3VudCBwcm9wZXJ0eSBmb3IgY3Jvc3MtZW52aXJvbm1lbnRcbiAqIHNlYXJjaCBleHByZXNzaW9ucy5cbiAqXG4gKiBUaGlzIGNsYXNzIGRvZXMgbm90IHJlcHJlc2VudCBhIHJlc291cmNlLCBzbyBoZW5jZSBpcyBub3QgYSBjb25zdHJ1Y3QuIEluc3RlYWQsXG4gKiBNYXRoRXhwcmVzc2lvbiBpcyBhbiBhYnN0cmFjdGlvbiB0aGF0IG1ha2VzIGl0IGVhc3kgdG8gc3BlY2lmeSBtZXRyaWNzIGZvciB1c2UgaW4gYm90aFxuICogYWxhcm1zIGFuZCBncmFwaHMuXG4gKi9cbmV4cG9ydCBjbGFzcyBNYXRoRXhwcmVzc2lvbiBpbXBsZW1lbnRzIElNZXRyaWMge1xuICAvKipcbiAgICogVGhlIGV4cHJlc3Npb24gZGVmaW5pbmcgdGhlIG1ldHJpYy5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBleHByZXNzaW9uOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBtZXRyaWNzIHVzZWQgaW4gdGhlIGV4cHJlc3Npb24gYXMgS2V5VmFsdWVQYWlyIDxpZCwgbWV0cmljPi5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSB1c2luZ01ldHJpY3M6IFJlY29yZDxzdHJpbmcsIElNZXRyaWM+O1xuXG4gIC8qKlxuICAgKiBMYWJlbCBmb3IgdGhpcyBtZXRyaWMgd2hlbiBhZGRlZCB0byBhIEdyYXBoLlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGxhYmVsPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgaGV4IGNvbG9yIGNvZGUsIHByZWZpeGVkIHdpdGggJyMnIChlLmcuICcjMDBmZjAwJyksIHRvIHVzZSB3aGVuIHRoaXMgbWV0cmljIGlzIHJlbmRlcmVkIG9uIGEgZ3JhcGguXG4gICAqIFRoZSBgQ29sb3JgIGNsYXNzIGhhcyBhIHNldCBvZiBzdGFuZGFyZCBjb2xvcnMgdGhhdCBjYW4gYmUgdXNlZCBoZXJlLlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGNvbG9yPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBBZ2dyZWdhdGlvbiBwZXJpb2Qgb2YgdGhpcyBtZXRyaWNcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBwZXJpb2Q6IGNkay5EdXJhdGlvbjtcblxuICAvKipcbiAgICogQWNjb3VudCB0byBldmFsdWF0ZSBzZWFyY2ggZXhwcmVzc2lvbnMgd2l0aGluLlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHNlYXJjaEFjY291bnQ/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFJlZ2lvbiB0byBldmFsdWF0ZSBzZWFyY2ggZXhwcmVzc2lvbnMgd2l0aGluLlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHNlYXJjaFJlZ2lvbj86IHN0cmluZztcblxuICAvKipcbiAgICogV2FybmluZ3MgZ2VuZXJhdGVkIGJ5IHRoaXMgbWF0aCBleHByZXNzaW9uXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgd2FybmluZ3M/OiBzdHJpbmdbXTtcblxuICBjb25zdHJ1Y3Rvcihwcm9wczogTWF0aEV4cHJlc3Npb25Qcm9wcykge1xuICAgIHRoaXMucGVyaW9kID0gcHJvcHMucGVyaW9kIHx8IGNkay5EdXJhdGlvbi5taW51dGVzKDUpO1xuICAgIHRoaXMuZXhwcmVzc2lvbiA9IHByb3BzLmV4cHJlc3Npb247XG4gICAgdGhpcy51c2luZ01ldHJpY3MgPSBjaGFuZ2VBbGxQZXJpb2RzKHByb3BzLnVzaW5nTWV0cmljcyA/PyB7fSwgdGhpcy5wZXJpb2QpO1xuICAgIHRoaXMubGFiZWwgPSBwcm9wcy5sYWJlbDtcbiAgICB0aGlzLmNvbG9yID0gcHJvcHMuY29sb3I7XG4gICAgdGhpcy5zZWFyY2hBY2NvdW50ID0gcHJvcHMuc2VhcmNoQWNjb3VudDtcbiAgICB0aGlzLnNlYXJjaFJlZ2lvbiA9IHByb3BzLnNlYXJjaFJlZ2lvbjtcblxuICAgIGNvbnN0IGludmFsaWRWYXJpYWJsZU5hbWVzID0gT2JqZWN0LmtleXModGhpcy51c2luZ01ldHJpY3MpLmZpbHRlcih4ID0+ICF2YWxpZFZhcmlhYmxlTmFtZSh4KSk7XG4gICAgaWYgKGludmFsaWRWYXJpYWJsZU5hbWVzLmxlbmd0aCA+IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCB2YXJpYWJsZSBuYW1lcyBpbiBleHByZXNzaW9uOiAke2ludmFsaWRWYXJpYWJsZU5hbWVzfS4gTXVzdCBzdGFydCB3aXRoIGxvd2VyY2FzZSBsZXR0ZXIgYW5kIG9ubHkgY29udGFpbiBhbHBoYW51bWVyaWNzLmApO1xuICAgIH1cblxuICAgIHRoaXMudmFsaWRhdGVOb0lkQ29uZmxpY3RzKCk7XG5cbiAgICAvLyBDaGVjayB0aGF0IGFsbCBJRHMgdXNlZCBpbiB0aGUgZXhwcmVzc2lvbiBhcmUgYWxzbyBpbiB0aGUgYHVzaW5nTWV0cmljc2AgbWFwLiBXZVxuICAgIC8vIGNhbid0IHRocm93IG9uIHRoaXMgYW55bW9yZSBzaW5jZSB3ZSBkaWRuJ3QgdXNlIHRvIGRvIHRoaXMgdmFsaWRhdGlvbiBmcm9tIHRoZSBzdGFydFxuICAgIC8vIGFuZCBub3cgdGhlcmUgd2lsbCBiZSBsb2FkcyBvZiBwZW9wbGUgd2hvIGFyZSB2aW9sYXRpbmcgdGhlIGV4cGVjdGVkIGNvbnRyYWN0LCBidXRcbiAgICAvLyB3ZSBjYW4gYWRkIHdhcm5pbmdzLlxuICAgIGNvbnN0IG1pc3NpbmdJZGVudGlmaWVycyA9IGFsbElkZW50aWZpZXJzSW5FeHByZXNzaW9uKHRoaXMuZXhwcmVzc2lvbikuZmlsdGVyKGkgPT4gIXRoaXMudXNpbmdNZXRyaWNzW2ldKTtcblxuICAgIGNvbnN0IHdhcm5pbmdzID0gW107XG5cbiAgICBpZiAobWlzc2luZ0lkZW50aWZpZXJzLmxlbmd0aCA+IDApIHtcbiAgICAgIHdhcm5pbmdzLnB1c2goYE1hdGggZXhwcmVzc2lvbiAnJHt0aGlzLmV4cHJlc3Npb259JyByZWZlcmVuY2VzIHVua25vd24gaWRlbnRpZmllcnM6ICR7bWlzc2luZ0lkZW50aWZpZXJzLmpvaW4oJywgJyl9LiBQbGVhc2UgYWRkIHRoZW0gdG8gdGhlICd1c2luZ01ldHJpY3MnIG1hcC5gKTtcbiAgICB9XG5cbiAgICAvLyBBbHNvIGNvcHkgd2FybmluZ3MgZnJvbSBkZWVwZXIgbGV2ZWxzIHNvIGdyYXBocywgYWxhcm1zIG9ubHkgaGF2ZSB0byBpbnNwZWN0IHRoZSB0b3AtbGV2ZWwgb2JqZWN0c1xuICAgIGZvciAoY29uc3QgbSBvZiBPYmplY3QudmFsdWVzKHRoaXMudXNpbmdNZXRyaWNzKSkge1xuICAgICAgd2FybmluZ3MucHVzaCguLi5tLndhcm5pbmdzID8/IFtdKTtcbiAgICB9XG5cbiAgICBpZiAod2FybmluZ3MubGVuZ3RoID4gMCkge1xuICAgICAgdGhpcy53YXJuaW5ncyA9IHdhcm5pbmdzO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gYSBjb3B5IG9mIE1ldHJpYyB3aXRoIHByb3BlcnRpZXMgY2hhbmdlZC5cbiAgICpcbiAgICogQWxsIHByb3BlcnRpZXMgZXhjZXB0IG5hbWVzcGFjZSBhbmQgbWV0cmljTmFtZSBjYW4gYmUgY2hhbmdlZC5cbiAgICpcbiAgICogQHBhcmFtIHByb3BzIFRoZSBzZXQgb2YgcHJvcGVydGllcyB0byBjaGFuZ2UuXG4gICAqL1xuICBwdWJsaWMgd2l0aChwcm9wczogTWF0aEV4cHJlc3Npb25PcHRpb25zKTogTWF0aEV4cHJlc3Npb24ge1xuICAgIC8vIFNob3J0LWNpcmN1aXQgY3JlYXRpbmcgYSBuZXcgb2JqZWN0IGlmIHRoZXJlIHdvdWxkIGJlIG5vIGVmZmVjdGl2ZSBjaGFuZ2VcbiAgICBpZiAoKHByb3BzLmxhYmVsID09PSB1bmRlZmluZWQgfHwgcHJvcHMubGFiZWwgPT09IHRoaXMubGFiZWwpXG4gICAgICAmJiAocHJvcHMuY29sb3IgPT09IHVuZGVmaW5lZCB8fCBwcm9wcy5jb2xvciA9PT0gdGhpcy5jb2xvcilcbiAgICAgICYmIChwcm9wcy5wZXJpb2QgPT09IHVuZGVmaW5lZCB8fCBwcm9wcy5wZXJpb2QudG9TZWNvbmRzKCkgPT09IHRoaXMucGVyaW9kLnRvU2Vjb25kcygpKVxuICAgICAgJiYgKHByb3BzLnNlYXJjaEFjY291bnQgPT09IHVuZGVmaW5lZCB8fCBwcm9wcy5zZWFyY2hBY2NvdW50ID09PSB0aGlzLnNlYXJjaEFjY291bnQpXG4gICAgICAmJiAocHJvcHMuc2VhcmNoUmVnaW9uID09PSB1bmRlZmluZWQgfHwgcHJvcHMuc2VhcmNoUmVnaW9uID09PSB0aGlzLnNlYXJjaFJlZ2lvbikpIHtcbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIHJldHVybiBuZXcgTWF0aEV4cHJlc3Npb24oe1xuICAgICAgZXhwcmVzc2lvbjogdGhpcy5leHByZXNzaW9uLFxuICAgICAgdXNpbmdNZXRyaWNzOiB0aGlzLnVzaW5nTWV0cmljcyxcbiAgICAgIGxhYmVsOiBpZlVuZGVmaW5lZChwcm9wcy5sYWJlbCwgdGhpcy5sYWJlbCksXG4gICAgICBjb2xvcjogaWZVbmRlZmluZWQocHJvcHMuY29sb3IsIHRoaXMuY29sb3IpLFxuICAgICAgcGVyaW9kOiBpZlVuZGVmaW5lZChwcm9wcy5wZXJpb2QsIHRoaXMucGVyaW9kKSxcbiAgICAgIHNlYXJjaEFjY291bnQ6IGlmVW5kZWZpbmVkKHByb3BzLnNlYXJjaEFjY291bnQsIHRoaXMuc2VhcmNoQWNjb3VudCksXG4gICAgICBzZWFyY2hSZWdpb246IGlmVW5kZWZpbmVkKHByb3BzLnNlYXJjaFJlZ2lvbiwgdGhpcy5zZWFyY2hSZWdpb24pLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXByZWNhdGVkIHVzZSB0b01ldHJpY0NvbmZpZygpXG4gICAqL1xuICBwdWJsaWMgdG9BbGFybUNvbmZpZygpOiBNZXRyaWNBbGFybUNvbmZpZyB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdVc2luZyBhIG1hdGggZXhwcmVzc2lvbiBpcyBub3Qgc3VwcG9ydGVkIGhlcmUuIFBhc3MgYSBcXCdNZXRyaWNcXCcgb2JqZWN0IGluc3RlYWQnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVwcmVjYXRlZCB1c2UgdG9NZXRyaWNDb25maWcoKVxuICAgKi9cbiAgcHVibGljIHRvR3JhcGhDb25maWcoKTogTWV0cmljR3JhcGhDb25maWcge1xuICAgIHRocm93IG5ldyBFcnJvcignVXNpbmcgYSBtYXRoIGV4cHJlc3Npb24gaXMgbm90IHN1cHBvcnRlZCBoZXJlLiBQYXNzIGEgXFwnTWV0cmljXFwnIG9iamVjdCBpbnN0ZWFkJyk7XG4gIH1cblxuICBwdWJsaWMgdG9NZXRyaWNDb25maWcoKTogTWV0cmljQ29uZmlnIHtcbiAgICByZXR1cm4ge1xuICAgICAgbWF0aEV4cHJlc3Npb246IHtcbiAgICAgICAgcGVyaW9kOiB0aGlzLnBlcmlvZC50b1NlY29uZHMoKSxcbiAgICAgICAgZXhwcmVzc2lvbjogdGhpcy5leHByZXNzaW9uLFxuICAgICAgICB1c2luZ01ldHJpY3M6IHRoaXMudXNpbmdNZXRyaWNzLFxuICAgICAgICBzZWFyY2hBY2NvdW50OiB0aGlzLnNlYXJjaEFjY291bnQsXG4gICAgICAgIHNlYXJjaFJlZ2lvbjogdGhpcy5zZWFyY2hSZWdpb24sXG4gICAgICB9LFxuICAgICAgcmVuZGVyaW5nUHJvcGVydGllczoge1xuICAgICAgICBsYWJlbDogdGhpcy5sYWJlbCxcbiAgICAgICAgY29sb3I6IHRoaXMuY29sb3IsXG4gICAgICB9LFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogTWFrZSBhIG5ldyBBbGFybSBmb3IgdGhpcyBtZXRyaWNcbiAgICpcbiAgICogQ29tYmluZXMgYm90aCBwcm9wZXJ0aWVzIHRoYXQgbWF5IGFkanVzdCB0aGUgbWV0cmljIChhZ2dyZWdhdGlvbikgYXMgd2VsbFxuICAgKiBhcyBhbGFybSBwcm9wZXJ0aWVzLlxuICAgKi9cbiAgcHVibGljIGNyZWF0ZUFsYXJtKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBDcmVhdGVBbGFybU9wdGlvbnMpOiBBbGFybSB7XG4gICAgcmV0dXJuIG5ldyBBbGFybShzY29wZSwgaWQsIHtcbiAgICAgIG1ldHJpYzogdGhpcy53aXRoKHtcbiAgICAgICAgcGVyaW9kOiBwcm9wcy5wZXJpb2QsXG4gICAgICB9KSxcbiAgICAgIGFsYXJtTmFtZTogcHJvcHMuYWxhcm1OYW1lLFxuICAgICAgYWxhcm1EZXNjcmlwdGlvbjogcHJvcHMuYWxhcm1EZXNjcmlwdGlvbixcbiAgICAgIGNvbXBhcmlzb25PcGVyYXRvcjogcHJvcHMuY29tcGFyaXNvbk9wZXJhdG9yLFxuICAgICAgZGF0YXBvaW50c1RvQWxhcm06IHByb3BzLmRhdGFwb2ludHNUb0FsYXJtLFxuICAgICAgdGhyZXNob2xkOiBwcm9wcy50aHJlc2hvbGQsXG4gICAgICBldmFsdWF0aW9uUGVyaW9kczogcHJvcHMuZXZhbHVhdGlvblBlcmlvZHMsXG4gICAgICBldmFsdWF0ZUxvd1NhbXBsZUNvdW50UGVyY2VudGlsZTogcHJvcHMuZXZhbHVhdGVMb3dTYW1wbGVDb3VudFBlcmNlbnRpbGUsXG4gICAgICB0cmVhdE1pc3NpbmdEYXRhOiBwcm9wcy50cmVhdE1pc3NpbmdEYXRhLFxuICAgICAgYWN0aW9uc0VuYWJsZWQ6IHByb3BzLmFjdGlvbnNFbmFibGVkLFxuICAgIH0pO1xuICB9XG5cbiAgcHVibGljIHRvU3RyaW5nKCkge1xuICAgIHJldHVybiB0aGlzLmxhYmVsIHx8IHRoaXMuZXhwcmVzc2lvbjtcbiAgfVxuXG4gIHByaXZhdGUgdmFsaWRhdGVOb0lkQ29uZmxpY3RzKCkge1xuICAgIGNvbnN0IHNlZW4gPSBuZXcgTWFwPHN0cmluZywgSU1ldHJpYz4oKTtcbiAgICB2aXNpdCh0aGlzKTtcblxuICAgIGZ1bmN0aW9uIHZpc2l0KG1ldHJpYzogSU1ldHJpYykge1xuICAgICAgZGlzcGF0Y2hNZXRyaWMobWV0cmljLCB7XG4gICAgICAgIHdpdGhTdGF0KCkge1xuICAgICAgICAgIC8vIE5vdGhpbmdcbiAgICAgICAgfSxcbiAgICAgICAgd2l0aEV4cHJlc3Npb24oZXhwcikge1xuICAgICAgICAgIGZvciAoY29uc3QgW2lkLCBzdWJNZXRyaWNdIG9mIE9iamVjdC5lbnRyaWVzKGV4cHIudXNpbmdNZXRyaWNzKSkge1xuICAgICAgICAgICAgY29uc3QgZXhpc3RpbmcgPSBzZWVuLmdldChpZCk7XG4gICAgICAgICAgICBpZiAoZXhpc3RpbmcgJiYgbWV0cmljS2V5KGV4aXN0aW5nKSAhPT0gbWV0cmljS2V5KHN1Yk1ldHJpYykpIHtcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBUaGUgSUQgJyR7aWR9JyB1c2VkIGZvciB0d28gbWV0cmljcyBpbiB0aGUgZXhwcmVzc2lvbjogJyR7c3ViTWV0cmljfScgYW5kICcke2V4aXN0aW5nfScuIFJlbmFtZSBvbmUuYCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBzZWVuLnNldChpZCwgc3ViTWV0cmljKTtcbiAgICAgICAgICAgIHZpc2l0KHN1Yk1ldHJpYyk7XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgfSk7XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogUGF0dGVybiBmb3IgYSB2YXJpYWJsZSBuYW1lLiBBbHBoYW51bSBzdGFydGluZyB3aXRoIGxvd2VyY2FzZS5cbiAqL1xuY29uc3QgVkFSSUFCTEVfUEFUID0gJ1thLXpdW2EtekEtWjAtOV9dKic7XG5cbmNvbnN0IFZBTElEX1ZBUklBQkxFID0gbmV3IFJlZ0V4cChgXiR7VkFSSUFCTEVfUEFUfSRgKTtcbmNvbnN0IEZJTkRfVkFSSUFCTEUgPSBuZXcgUmVnRXhwKFZBUklBQkxFX1BBVCwgJ2cnKTtcblxuZnVuY3Rpb24gdmFsaWRWYXJpYWJsZU5hbWUoeDogc3RyaW5nKSB7XG4gIHJldHVybiBWQUxJRF9WQVJJQUJMRS50ZXN0KHgpO1xufVxuXG4vKipcbiAqIFJldHVybiBhbGwgdmFyaWFibGUgbmFtZXMgdXNlZCBpbiBhbiBleHByZXNzaW9uXG4gKi9cbmZ1bmN0aW9uIGFsbElkZW50aWZpZXJzSW5FeHByZXNzaW9uKHg6IHN0cmluZykge1xuICByZXR1cm4gQXJyYXkuZnJvbShtYXRjaEFsbCh4LCBGSU5EX1ZBUklBQkxFKSkubWFwKG0gPT4gbVswXSk7XG59XG5cbi8qKlxuICogUHJvcGVydGllcyBuZWVkZWQgdG8gbWFrZSBhbiBhbGFybSBmcm9tIGEgbWV0cmljXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ3JlYXRlQWxhcm1PcHRpb25zIHtcbiAgLyoqXG4gICAqIFRoZSBwZXJpb2Qgb3ZlciB3aGljaCB0aGUgc3BlY2lmaWVkIHN0YXRpc3RpYyBpcyBhcHBsaWVkLlxuICAgKlxuICAgKiBDYW5ub3QgYmUgdXNlZCB3aXRoIGBNYXRoRXhwcmVzc2lvbmAgb2JqZWN0cy5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBUaGUgcGVyaW9kIGZyb20gdGhlIG1ldHJpY1xuICAgKiBAZGVwcmVjYXRlZCBVc2UgYG1ldHJpYy53aXRoKHsgcGVyaW9kOiAuLi4gfSlgIHRvIGVuY29kZSB0aGUgcGVyaW9kIGludG8gdGhlIE1ldHJpYyBvYmplY3RcbiAgICovXG4gIHJlYWRvbmx5IHBlcmlvZD86IGNkay5EdXJhdGlvbjtcblxuICAvKipcbiAgICogV2hhdCBmdW5jdGlvbiB0byB1c2UgZm9yIGFnZ3JlZ2F0aW5nLlxuICAgKlxuICAgKiBDYW4gYmUgb25lIG9mIHRoZSBmb2xsb3dpbmc6XG4gICAqXG4gICAqIC0gXCJNaW5pbXVtXCIgfCBcIm1pblwiXG4gICAqIC0gXCJNYXhpbXVtXCIgfCBcIm1heFwiXG4gICAqIC0gXCJBdmVyYWdlXCIgfCBcImF2Z1wiXG4gICAqIC0gXCJTdW1cIiB8IFwic3VtXCJcbiAgICogLSBcIlNhbXBsZUNvdW50IHwgXCJuXCJcbiAgICogLSBcInBOTi5OTlwiXG4gICAqXG4gICAqIENhbm5vdCBiZSB1c2VkIHdpdGggYE1hdGhFeHByZXNzaW9uYCBvYmplY3RzLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIFRoZSBzdGF0aXN0aWMgZnJvbSB0aGUgbWV0cmljXG4gICAqIEBkZXByZWNhdGVkIFVzZSBgbWV0cmljLndpdGgoeyBzdGF0aXN0aWM6IC4uLiB9KWAgdG8gZW5jb2RlIHRoZSBwZXJpb2QgaW50byB0aGUgTWV0cmljIG9iamVjdFxuICAgKi9cbiAgcmVhZG9ubHkgc3RhdGlzdGljPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBOYW1lIG9mIHRoZSBhbGFybVxuICAgKlxuICAgKiBAZGVmYXVsdCBBdXRvbWF0aWNhbGx5IGdlbmVyYXRlZCBuYW1lXG4gICAqL1xuICByZWFkb25seSBhbGFybU5hbWU/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIERlc2NyaXB0aW9uIGZvciB0aGUgYWxhcm1cbiAgICpcbiAgICogQGRlZmF1bHQgTm8gZGVzY3JpcHRpb25cbiAgICovXG4gIHJlYWRvbmx5IGFsYXJtRGVzY3JpcHRpb24/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIENvbXBhcmlzb24gdG8gdXNlIHRvIGNoZWNrIGlmIG1ldHJpYyBpcyBicmVhY2hpbmdcbiAgICpcbiAgICogQGRlZmF1bHQgR3JlYXRlclRoYW5PckVxdWFsVG9UaHJlc2hvbGRcbiAgICovXG4gIHJlYWRvbmx5IGNvbXBhcmlzb25PcGVyYXRvcj86IENvbXBhcmlzb25PcGVyYXRvcjtcblxuICAvKipcbiAgICogVGhlIHZhbHVlIGFnYWluc3Qgd2hpY2ggdGhlIHNwZWNpZmllZCBzdGF0aXN0aWMgaXMgY29tcGFyZWQuXG4gICAqL1xuICByZWFkb25seSB0aHJlc2hvbGQ6IG51bWJlcjtcblxuICAvKipcbiAgICogVGhlIG51bWJlciBvZiBwZXJpb2RzIG92ZXIgd2hpY2ggZGF0YSBpcyBjb21wYXJlZCB0byB0aGUgc3BlY2lmaWVkIHRocmVzaG9sZC5cbiAgICovXG4gIHJlYWRvbmx5IGV2YWx1YXRpb25QZXJpb2RzOiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIFNwZWNpZmllcyB3aGV0aGVyIHRvIGV2YWx1YXRlIHRoZSBkYXRhIGFuZCBwb3RlbnRpYWxseSBjaGFuZ2UgdGhlIGFsYXJtIHN0YXRlIGlmIHRoZXJlIGFyZSB0b28gZmV3IGRhdGEgcG9pbnRzIHRvIGJlIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQuXG4gICAqXG4gICAqIFVzZWQgb25seSBmb3IgYWxhcm1zIHRoYXQgYXJlIGJhc2VkIG9uIHBlcmNlbnRpbGVzLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5vdCBjb25maWd1cmVkLlxuICAgKi9cbiAgcmVhZG9ubHkgZXZhbHVhdGVMb3dTYW1wbGVDb3VudFBlcmNlbnRpbGU/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFNldHMgaG93IHRoaXMgYWxhcm0gaXMgdG8gaGFuZGxlIG1pc3NpbmcgZGF0YSBwb2ludHMuXG4gICAqXG4gICAqIEBkZWZhdWx0IFRyZWF0TWlzc2luZ0RhdGEuTWlzc2luZ1xuICAgKi9cbiAgcmVhZG9ubHkgdHJlYXRNaXNzaW5nRGF0YT86IFRyZWF0TWlzc2luZ0RhdGE7XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdGhlIGFjdGlvbnMgZm9yIHRoaXMgYWxhcm0gYXJlIGVuYWJsZWRcbiAgICpcbiAgICogQGRlZmF1bHQgdHJ1ZVxuICAgKi9cbiAgcmVhZG9ubHkgYWN0aW9uc0VuYWJsZWQ/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBUaGUgbnVtYmVyIG9mIGRhdGFwb2ludHMgdGhhdCBtdXN0IGJlIGJyZWFjaGluZyB0byB0cmlnZ2VyIHRoZSBhbGFybS4gVGhpcyBpcyB1c2VkIG9ubHkgaWYgeW91IGFyZSBzZXR0aW5nIGFuIFwiTVxuICAgKiBvdXQgb2YgTlwiIGFsYXJtLiBJbiB0aGF0IGNhc2UsIHRoaXMgdmFsdWUgaXMgdGhlIE0uIEZvciBtb3JlIGluZm9ybWF0aW9uLCBzZWUgRXZhbHVhdGluZyBhbiBBbGFybSBpbiB0aGUgQW1hem9uXG4gICAqIENsb3VkV2F0Y2ggVXNlciBHdWlkZS5cbiAgICpcbiAgICogQGRlZmF1bHQgYGBldmFsdWF0aW9uUGVyaW9kc2BgXG4gICAqXG4gICAqIEBzZWUgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL0FtYXpvbkNsb3VkV2F0Y2gvbGF0ZXN0L21vbml0b3JpbmcvQWxhcm1UaGF0U2VuZHNFbWFpbC5odG1sI2FsYXJtLWV2YWx1YXRpb25cbiAgICovXG4gIHJlYWRvbmx5IGRhdGFwb2ludHNUb0FsYXJtPzogbnVtYmVyO1xufVxuXG5mdW5jdGlvbiBpZlVuZGVmaW5lZDxUPih4OiBUIHwgdW5kZWZpbmVkLCBkZWY6IFQgfCB1bmRlZmluZWQpOiBUIHwgdW5kZWZpbmVkIHtcbiAgaWYgKHggIT09IHVuZGVmaW5lZCkge1xuICAgIHJldHVybiB4O1xuICB9XG4gIHJldHVybiBkZWY7XG59XG5cbi8qKlxuICogQ2hhbmdlIHBlcmlvZHMgb2YgYWxsIG1ldHJpY3MgaW4gdGhlIG1hcFxuICovXG5mdW5jdGlvbiBjaGFuZ2VBbGxQZXJpb2RzKG1ldHJpY3M6IFJlY29yZDxzdHJpbmcsIElNZXRyaWM+LCBwZXJpb2Q6IGNkay5EdXJhdGlvbik6IFJlY29yZDxzdHJpbmcsIElNZXRyaWM+IHtcbiAgY29uc3QgcmV0OiBSZWNvcmQ8c3RyaW5nLCBJTWV0cmljPiA9IHt9O1xuICBmb3IgKGNvbnN0IFtpZCwgbWV0cmljXSBvZiBPYmplY3QuZW50cmllcyhtZXRyaWNzKSkge1xuICAgIHJldFtpZF0gPSBjaGFuZ2VQZXJpb2QobWV0cmljLCBwZXJpb2QpO1xuICB9XG4gIHJldHVybiByZXQ7XG59XG5cbi8qKlxuICogUmV0dXJuIGEgbmV3IG1ldHJpYyBvYmplY3Qgd2hpY2ggaXMgdGhlIHNhbWUgdHlwZSBhcyB0aGUgaW5wdXQgb2JqZWN0LCBidXQgd2l0aCB0aGUgcGVyaW9kIGNoYW5nZWRcbiAqXG4gKiBSZWxpZXMgb24gdGhlIGZhY3QgdGhhdCBpbXBsZW1lbnRhdGlvbnMgb2YgYElNZXRyaWNgIGFyZSBhbHNvIHN1cHBvc2VkIHRvIGhhdmVcbiAqIGFuIGltcGxlbWVudGF0aW9uIG9mIGB3aXRoYCB0aGF0IGFjY2VwdHMgYW4gYXJndW1lbnQgY2FsbGVkIGBwZXJpb2RgLiBTZWUgYElNb2RpZmlhYmxlTWV0cmljYC5cbiAqL1xuZnVuY3Rpb24gY2hhbmdlUGVyaW9kKG1ldHJpYzogSU1ldHJpYywgcGVyaW9kOiBjZGsuRHVyYXRpb24pOiBJTWV0cmljIHtcbiAgaWYgKGlzTW9kaWZpYWJsZU1ldHJpYyhtZXRyaWMpKSB7XG4gICAgcmV0dXJuIG1ldHJpYy53aXRoKHsgcGVyaW9kIH0pO1xuICB9XG5cbiAgdGhyb3cgbmV3IEVycm9yKGBNZXRyaWMgb2JqZWN0IHNob3VsZCBhbHNvIGltcGxlbWVudCAnd2l0aCc6ICR7bWV0cmljfWApO1xufVxuXG4vKipcbiAqIFByaXZhdGUgcHJvdG9jb2wgZm9yIG1ldHJpY3NcbiAqXG4gKiBNZXRyaWMgdHlwZXMgdXNlZCBpbiBhIE1hdGhFeHByZXNzaW9uIG5lZWQgdG8gaW1wbGVtZW50IGF0IGxlYXN0IHRoaXM6XG4gKiBhIGB3aXRoYCBtZXRob2QgdGhhdCB0YWtlcyBhdCBsZWFzdCBhIGBwZXJpb2RgIGFuZCByZXR1cm5zIGEgbW9kaWZpZWQgY29weVxuICogb2YgdGhlIG1ldHJpYyBvYmplY3QuXG4gKlxuICogV2UgcHV0IGl0IGhlcmUgaW5zdGVhZCBvZiBvbiBgSU1ldHJpY2AgYmVjYXVzZSB0aGVyZSBpcyBubyB3YXkgdG8gdHlwZVxuICogaXQgaW4ganNpaSBpbiBhIHdheSB0aGF0IGNvbmNyZXRlIGltcGxlbWVudGF0aW9ucyBgTWV0cmljYCBhbmQgYE1hdGhFeHByZXNzaW9uYFxuICogY2FuIGJlIHN0YXRpY2FsbHkgdHlwYWJsZSBhYm91dCB0aGUgZmllbGRzIHRoYXQgYXJlIGNoYW5nZWFibGU6IGFsbFxuICogYHdpdGhgIG1ldGhvZHMgd291bGQgbmVlZCB0byB0YWtlIHRoZSBzYW1lIGFyZ3VtZW50IHR5cGUsIGJ1dCBub3QgYWxsXG4gKiBjbGFzc2VzIGhhdmUgdGhlIHNhbWUgYHdpdGhgLWFibGUgcHJvcGVydGllcy5cbiAqXG4gKiBUaGlzIGNsYXNzIGV4aXN0cyB0byBwcmV2ZW50IGhhdmluZyB0byB1c2UgYGluc3RhbmNlb2ZgIGluIHRoZSBgY2hhbmdlUGVyaW9kYFxuICogZnVuY3Rpb24sIHNvIHRoYXQgd2UgaGF2ZSBhIHN5c3RlbSB3aGVyZSBpbiBwcmluY2lwbGUgbmV3IGltcGxlbWVudGF0aW9uc1xuICogb2YgYElNZXRyaWNgIGNhbiBiZSBhZGRlZC4gQmVjYXVzZSBpdCB3aWxsIGJlIHJhcmUsIHRoZSBtZWNoYW5pc20gZG9lc24ndCBoYXZlXG4gKiB0byBiZSBleHBvc2VkIHZlcnkgd2VsbCwganVzdCBoYXMgdG8gYmUgcG9zc2libGUuXG4gKi9cbmludGVyZmFjZSBJTW9kaWZpYWJsZU1ldHJpYyB7XG4gIHdpdGgob3B0aW9uczogeyBwZXJpb2Q/OiBjZGsuRHVyYXRpb24gfSk6IElNZXRyaWM7XG59XG5cbmZ1bmN0aW9uIGlzTW9kaWZpYWJsZU1ldHJpYyhtOiBhbnkpOiBtIGlzIElNb2RpZmlhYmxlTWV0cmljIHtcbiAgcmV0dXJuIHR5cGVvZiBtID09PSAnb2JqZWN0JyAmJiBtICE9PSBudWxsICYmICEhbS53aXRoO1xufVxuXG4vLyBQb2x5ZmlsbCBmb3Igc3RyaW5nLm1hdGNoQWxsKHJlZ2V4cClcbmZ1bmN0aW9uIG1hdGNoQWxsKHg6IHN0cmluZywgcmU6IFJlZ0V4cCk6IFJlZ0V4cE1hdGNoQXJyYXlbXSB7XG4gIGNvbnN0IHJldCA9IG5ldyBBcnJheTxSZWdFeHBNYXRjaEFycmF5PigpO1xuICBsZXQgbTogUmVnRXhwRXhlY0FycmF5IHwgbnVsbDtcbiAgd2hpbGUgKG0gPSByZS5leGVjKHgpKSB7XG4gICAgcmV0LnB1c2gobSk7XG4gIH1cbiAgcmV0dXJuIHJldDtcbn1cbiJdfQ==
\No newline at end of file