@neo-one/monitor
Version:
NEO•ONE monitoring.
449 lines (448 loc) • 61.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const utils_1 = require("@neo-one/utils");
const lodash_1 = tslib_1.__importDefault(require("lodash"));
const ReportHandler_1 = require("./ReportHandler");
const types_1 = require("./types");
const createTracer_1 = require("./createTracer");
const utils_2 = require("./utils");
var LogLevelToLevel;
(function (LogLevelToLevel) {
LogLevelToLevel[LogLevelToLevel["error"] = 0] = "error";
LogLevelToLevel[LogLevelToLevel["warn"] = 1] = "warn";
LogLevelToLevel[LogLevelToLevel["info"] = 2] = "info";
LogLevelToLevel[LogLevelToLevel["verbose"] = 3] = "verbose";
LogLevelToLevel[LogLevelToLevel["debug"] = 4] = "debug";
LogLevelToLevel[LogLevelToLevel["silly"] = 5] = "silly";
})(LogLevelToLevel || (LogLevelToLevel = {}));
class DefaultReference {
constructor(span) {
this.span = span;
}
isValid() {
return !(this.span instanceof MonitorBase) || this.span.hasSpan();
}
getTracerReference(tracer) {
if (!this.isValid()) {
throw new Error('Programming error');
}
const context = this.span instanceof MonitorBase ? this.span.getSpan().span : this.span;
if (context === undefined) {
return undefined;
}
return this.type === 'childOf' ? tracer.childOf(context) : tracer.followsFrom(context);
}
}
class ChildOfReference extends DefaultReference {
constructor() {
super(...arguments);
this.type = 'childOf';
}
}
class FollowsFromReference extends DefaultReference {
constructor() {
super(...arguments);
this.type = 'followsFrom';
}
}
class MonitorBase {
constructor({ service, component, labels = {}, data = {}, logger, spanLogLevel = 'info', tracer = createTracer_1.createTracer(), now, span, reportHandler = new ReportHandler_1.ReportHandler(logger), }) {
this.labels = types_1.KnownLabel;
this.formats = types_1.Format;
this.service = service;
this.component = component;
this.mutableCurrentLabels = labels;
this.mutableData = data;
this.logger = logger;
this.spanLogLevel = spanLogLevel;
this.tracer = tracer;
this.now = now;
this.span = span;
this.reportHandler = reportHandler;
}
nowSeconds() {
return this.now() / 1000;
}
at(component) {
return this.clone({ component });
}
withLabels(labels) {
return this.clone({ mergeLabels: labels });
}
withData(data) {
return this.clone({ mergeData: data });
}
forContext(_ctx) {
return this;
}
forMessage(_ctx) {
return this;
}
log({ name, message, level, metric, error }) {
this.commonLog({ name, message, level, metric, error });
}
captureLog(func, options, cloned = false) {
let { error: errorObj } = options;
if (errorObj !== undefined && typeof errorObj === 'string') {
errorObj = { metric: undefined, message: errorObj, level: 'error' };
}
const errorObjFinal = errorObj;
const log = cloned ? this : this.clone();
const doLog = (error) => log.commonLog({
name: options.name,
message: options.message,
level: options.level,
metric: options.metric,
error: errorObjFinal === undefined
? undefined
: {
metric: errorObjFinal.metric,
message: errorObjFinal.message,
error,
level: errorObjFinal.level,
},
});
try {
const result = func(log);
if (result !== undefined && result.then !== undefined) {
return (result
.then((res) => {
doLog();
return res;
})
.catch((err) => {
doLog(err);
throw err;
}));
}
doLog();
return result;
}
catch (error) {
doLog(error);
throw error;
}
}
logError({ name, message, level, error, metric }) {
let errorLevel = level;
if (errorLevel === undefined) {
errorLevel = 'error';
}
this.commonLog({
name,
message,
level: level === undefined ? 'error' : level,
error: { metric, error, message, level: errorLevel },
});
}
startSpan({ name, level, metric, references = [], trace }) {
let span;
let parent;
const fullLevel = this.getFullLevel(level);
const tracerReferences = references
.concat([this.childOf(this)])
.map((reference) => {
if (reference instanceof DefaultReference && reference.isValid()) {
return reference.getTracerReference(this.tracer);
}
return undefined;
})
.filter(utils_1.utils.notNull);
if (LogLevelToLevel[fullLevel.span] <= LogLevelToLevel[this.spanLogLevel] &&
(trace !== undefined || tracerReferences.length > 0)) {
span = this.tracer.startSpan(name, {
references: tracerReferences,
tags: this.getSpanTags(),
});
parent = this;
}
let currentParent;
if (this.hasSpan()) {
({ parent: currentParent } = this.getSpan());
}
return this.clone({
span: {
metric,
time: this.nowSeconds(),
span,
parent: parent === undefined ? currentParent : parent,
},
});
}
end(error = false) {
const span = this.getSpan();
const { metric } = span;
if (metric !== undefined) {
const value = this.nowSeconds() - span.time;
this.invokeMetric(metric.total, (total) => total.observe(value), (total, labels) => total.observe(labels, value));
if (error) {
this.invokeMetric(metric.error, (errorMetric) => errorMetric.inc(), (errorMetric, labels) => errorMetric.inc(labels));
}
}
const { span: tracerSpan } = span;
if (tracerSpan !== undefined) {
tracerSpan.setTag(this.labels.ERROR, !!error);
tracerSpan.finish();
}
}
captureSpan(func, options) {
const span = this.startSpan({
name: options.name,
level: options.level,
metric: options.metric,
references: options.references,
trace: options.trace,
});
try {
const result = func(span);
if (result !== undefined && result.then !== undefined) {
return (result
.then((res) => {
span.end();
return res;
})
.catch((err) => {
span.end(true);
throw err;
}));
}
span.end();
return result;
}
catch (error) {
span.end(true);
throw error;
}
}
captureSpanLog(func, options) {
const level = this.getFullLevel(options.level);
return this.captureSpan((span) => span.captureLog(func, {
name: options.name,
level: level.log,
message: options.message,
error: typeof options.error === 'object'
? {
level: options.error.level,
message: options.error.message,
}
: options.error,
}, true), {
name: options.name,
level: level.span,
metric: options.metric,
references: options.references,
trace: options.trace,
});
}
childOf(span) {
if (span === undefined) {
return undefined;
}
return new ChildOfReference(span);
}
followsFrom(span) {
if (span === undefined) {
return undefined;
}
return new FollowsFromReference(span);
}
extract(format, carrier) {
return this.tracer.extract(format, carrier);
}
inject(format, carrier) {
const span = this.span;
if (span !== undefined && span.span !== undefined) {
this.tracer.inject(span.span.context(), format, carrier);
}
}
report(report) {
this.reportHandler.report(report);
}
serveMetrics(_port) {
}
close(callback) {
this.closeInternal()
.then(() => {
callback();
})
.catch(() => {
callback();
});
}
setLabels(labels) {
this.setSpanLabels(labels);
this.mutableCurrentLabels = Object.assign({}, this.mutableCurrentLabels, labels);
}
setData(data) {
this.setSpanLabels(data);
this.mutableData = Object.assign({}, this.mutableData, data);
}
hasSpan() {
return this.span !== undefined;
}
getSpan() {
const span = this.span;
if (span === undefined) {
throw new Error('Programming error: Called end on a regular Monitor.');
}
return span;
}
async closeInternal() {
await Promise.all([
new Promise((resolve) => {
this.logger.close(resolve);
}),
new Promise((resolve) => {
this.tracer.close(resolve);
}),
]);
}
invokeMetric(metric, withoutLabels, withLabels) {
const labelNames = metric.getLabelNames();
if (labelNames.length === 0) {
withoutLabels(metric);
}
else {
const labels = metric.getLabelNames().reduce((acc, labelName) => (Object.assign({}, acc, { [labelName]: this.mutableCurrentLabels[labelName] })), {});
withLabels(metric, labels);
}
}
commonLog({ name, message: messageIn, level, metric, error, }) {
const incrementMetric = (maybeMetric) => {
if (maybeMetric !== undefined) {
this.invokeMetric(maybeMetric, (theMetric) => theMetric.inc(), (theMetric, metricLabels) => theMetric.inc(metricLabels));
}
};
let labels = {};
let message = messageIn;
const fullLevel = this.getFullLevel(level);
let logLevel = fullLevel.log;
incrementMetric(metric);
if (error !== undefined) {
const { error: errorObj } = error;
labels = Object.assign({}, labels, { [types_1.KnownLabel.ERROR]: errorObj !== undefined, [types_1.KnownLabel.ERROR_KIND]: `${this.getErrorKind(errorObj)}` });
const errorLevel = error.level === undefined ? 'error' : error.level;
if (errorObj !== undefined) {
incrementMetric(error.metric);
logLevel = errorLevel;
const { message: errorMessage } = error;
if (errorMessage === undefined) {
message = errorMessage;
}
else {
const dot = errorMessage.endsWith('.') ? '' : '.';
message = `${errorMessage}${dot} ${errorObj.message}`;
}
}
}
this.logger.log({
name,
level: logLevel,
message,
labels: utils_2.convertTagLabels(this.getAllRawLabels(labels)),
data: utils_2.convertTagLabels(this.getAllRawData()),
error: error === undefined ? undefined : error.error,
});
if (this.span !== undefined) {
const { span: tracerSpan } = this.span;
if (LogLevelToLevel[fullLevel.span] <= LogLevelToLevel[this.spanLogLevel] && tracerSpan !== undefined) {
let spanLog = Object.assign({ event: name, message }, this.getSpanTags(labels));
if (error !== undefined) {
const { error: errorObj } = error;
if (errorObj !== undefined) {
spanLog = Object.assign({}, spanLog, { [this.labels.ERROR_OBJECT]: errorObj, [this.labels.ERROR_STACK]: errorObj.stack });
}
}
tracerSpan.log(spanLog);
}
}
}
getErrorKind(error) {
if (error === undefined) {
return 'n/a';
}
return error.code === undefined ? error.constructor.name : error.code;
}
getSpanTags(labels = {}) {
let spanLabels = this.getAllRawLabels();
let spanData = this.getAllRawData();
if (this.hasSpan()) {
const { parent } = this.getSpan();
if (parent !== undefined) {
const parentLabels = new Set(Object.keys(parent.labels));
spanLabels = lodash_1.default.omitBy(spanLabels, (_value, label) => parentLabels.has(label));
const parentData = new Set(Object.keys(parent.mutableData));
spanData = lodash_1.default.omitBy(spanData, (_value, label) => parentData.has(label));
}
}
return utils_2.convertTagLabels(Object.assign({}, spanLabels, spanData, labels));
}
getAllRawLabels(labels) {
if (labels === undefined) {
return this.mutableCurrentLabels;
}
return Object.assign({}, this.mutableCurrentLabels, labels, { [this.labels.SERVICE]: this.service, [this.labels.COMPONENT]: this.component });
}
getAllRawData(labels) {
if (labels === undefined) {
return this.mutableData;
}
return Object.assign({}, this.mutableData, labels);
}
setSpanLabels(labels) {
if (this.span !== undefined) {
const { span: tracerSpan } = this.span;
if (tracerSpan !== undefined) {
const tagLabels = utils_2.convertTagLabels(labels);
Object.keys(tagLabels).forEach((key) => {
const value = tagLabels[key];
if (value !== undefined) {
tracerSpan.setTag(key, value);
}
});
}
}
}
getFullLevel(levelIn) {
let level = levelIn;
if (level === undefined) {
level = 'info';
}
if (typeof level === 'string') {
return {
log: level,
span: level,
};
}
return {
log: level.log,
span: level.span === undefined ? level.log : level.span,
};
}
clone(options = {}) {
const { component, mergeLabels, mergeData, span } = options;
let mergedLabels = this.mutableCurrentLabels;
if (mergeLabels !== undefined) {
mergedLabels = Object.assign({}, this.mutableCurrentLabels, mergeLabels);
}
let mergedData = this.mutableData;
if (mergeData !== undefined) {
mergedData = Object.assign({}, this.mutableData, mergeData);
}
return new this.constructor({
service: this.service,
component: component === undefined ? this.component : component,
logger: this.logger,
tracer: this.tracer,
now: this.now,
labels: mergedLabels,
data: mergedData,
span: span === undefined ? this.span : span,
spanLogLevel: this.spanLogLevel,
reportHandler: this.reportHandler,
});
}
}
exports.MonitorBase = MonitorBase;
//# sourceMappingURL=data:application/json;charset=utf8;base64,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SSxDQUFDLE1BQU07WUFDbkIsTUFBTSxFQUFFLElBQUksQ0FBQyxNQUFNO1lBQ25CLEdBQUcsRUFBRSxJQUFJLENBQUMsR0FBRztZQUNiLE1BQU0sRUFBRSxZQUFZO1lBQ3BCLElBQUksRUFBRSxVQUFVO1lBQ2hCLElBQUksRUFBRSxJQUFJLEtBQUssU0FBUyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJO1lBQzNDLFlBQVksRUFBRSxJQUFJLENBQUMsWUFBWTtZQUMvQixhQUFhLEVBQUUsSUFBSSxDQUFDLGFBQWE7U0FDbEMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztDQUNGO0FBdGpCRCxrQ0FzakJDIiwiZmlsZSI6Im5lby1vbmUtbW9uaXRvci9zcmMvTW9uaXRvckJhc2UuanMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmNvbWluZ01lc3NhZ2UgfSBmcm9tICdodHRwJztcbmltcG9ydCB7IENvbnRleHQgfSBmcm9tICdrb2EnO1xuXG5pbXBvcnQgeyB1dGlscyB9IGZyb20gJ0BuZW8tb25lL3V0aWxzJztcbmltcG9ydCBfIGZyb20gJ2xvZGFzaCc7XG5cbmltcG9ydCB7IFJlcG9ydEhhbmRsZXIgfSBmcm9tICcuL1JlcG9ydEhhbmRsZXInO1xuaW1wb3J0IHtcbiAgQ2FwdHVyZUxvZ09wdGlvbnMsXG4gIENhcHR1cmVNb25pdG9yLFxuICBDYXB0dXJlU3BhbkxvZ09wdGlvbnMsXG4gIENhcHR1cmVTcGFuT3B0aW9ucyxcbiAgQ2FycmllcixcbiAgQ291bnRlcixcbiAgRm9ybWF0LFxuICBIaXN0b2dyYW0sXG4gIEtub3duTGFiZWwsXG4gIExhYmVscyxcbiAgTG9nRXJyb3JPcHRpb25zLFxuICBMb2dnZXIsXG4gIExvZ0xldmVsLFxuICBMb2dMZXZlbE9wdGlvbixcbiAgTG9nT3B0aW9ucyxcbiAgTWV0cmljLFxuICBNb25pdG9yLFxuICBSZXBvcnQsXG4gIFNwYW4sXG4gIFNwYW5Db250ZXh0LFxuICBTcGFuT3B0aW9ucyxcbiAgU3VtbWFyeSxcbn0gZnJvbSAnLi90eXBlcyc7XG5cbmltcG9ydCB7IGNyZWF0ZVRyYWNlciB9IGZyb20gJy4vY3JlYXRlVHJhY2VyJztcbmltcG9ydCB7IGNvbnZlcnRUYWdMYWJlbHMgfSBmcm9tICcuL3V0aWxzJztcblxuZXhwb3J0IGludGVyZmFjZSBGdWxsTG9nTGV2ZWxPcHRpb24ge1xuICByZWFkb25seSBsb2c6IExvZ0xldmVsO1xuICByZWFkb25seSBzcGFuOiBMb2dMZXZlbDtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBUcmFjZXJTcGFuIHtcbiAgcmVhZG9ubHkgbG9nOiAoZGF0YTogb2JqZWN0KSA9PiB2b2lkO1xuICByZWFkb25seSBzZXRUYWc6IChuYW1lOiBzdHJpbmcsIHZhbHVlOiBzdHJpbmcgfCBudW1iZXIgfCBib29sZWFuKSA9PiB2b2lkO1xuICByZWFkb25seSBmaW5pc2g6IChmaW5pc2hUaW1lPzogbnVtYmVyKSA9PiB2b2lkO1xuICByZWFkb25seSBjb250ZXh0OiAoKSA9PiBTcGFuQ29udGV4dDtcbn1cbmV4cG9ydCBpbnRlcmZhY2UgVHJhY2VyUmVmZXJlbmNlIHtcbiAgcmVhZG9ubHkgX190cmFjZXI6IHVuZGVmaW5lZDtcbn1cbmV4cG9ydCBpbnRlcmZhY2UgVHJhY2VyU3RhcnRTcGFuT3B0aW9ucyB7XG4gIHJlYWRvbmx5IHJlZmVyZW5jZXM/OiByZWFkb25seSBUcmFjZXJSZWZlcmVuY2VbXTtcbiAgcmVhZG9ubHkgdGFncz86IG9iamVjdDtcbiAgcmVhZG9ubHkgc3RhcnRUaW1lPzogbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFRyYWNlciB7XG4gIHJlYWRvbmx5IHN0YXJ0U3BhbjogKG5hbWU6IHN0cmluZywgb3B0aW9ucz86IFRyYWNlclN0YXJ0U3Bhbk9wdGlvbnMpID0+IFRyYWNlclNwYW47XG4gIHJlYWRvbmx5IGNoaWxkT2Y6IChzcGFuOiBTcGFuQ29udGV4dCB8IFRyYWNlclNwYW4pID0+IFRyYWNlclJlZmVyZW5jZTtcbiAgcmVhZG9ubHkgZm9sbG93c0Zyb206IChzcGFuOiBTcGFuQ29udGV4dCB8IFRyYWNlclNwYW4pID0+IFRyYWNlclJlZmVyZW5jZTtcbiAgcmVhZG9ubHkgZXh0cmFjdDogKGZvcm1hdDogRm9ybWF0LCBjYXJyaWVyOiBDYXJyaWVyKSA9PiBTcGFuQ29udGV4dCB8IHVuZGVmaW5lZDtcbiAgcmVhZG9ubHkgaW5qZWN0OiAoY29udGV4dDogU3BhbkNvbnRleHQsIGZvcm1hdDogRm9ybWF0LCBjYXJyaWVyOiBDYXJyaWVyKSA9PiB2b2lkO1xuICByZWFkb25seSBjbG9zZTogKGNhbGxiYWNrOiAoKSA9PiB2b2lkKSA9PiB2b2lkO1xufVxuXG5leHBvcnQgdHlwZSBOb3cgPSAoKSA9PiBudW1iZXI7XG5cbmV4cG9ydCBpbnRlcmZhY2UgU3BhbkRhdGEge1xuICByZWFkb25seSBtZXRyaWM/OiB7XG4gICAgcmVhZG9ubHkgdG90YWw6IEhpc3RvZ3JhbSB8IFN1bW1hcnk7XG4gICAgcmVhZG9ubHkgZXJyb3I6IENvdW50ZXI7XG4gIH07XG4gIHJlYWRvbmx5IHRpbWU6IG51bWJlcjtcbiAgcmVhZG9ubHkgc3Bhbj86IFRyYWNlclNwYW47XG4gIHJlYWRvbmx5IHBhcmVudD86IE1vbml0b3JCYXNlO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIE1vbml0b3JCYXNlT3B0aW9ucyB7XG4gIHJlYWRvbmx5IHNlcnZpY2U6IHN0cmluZztcbiAgcmVhZG9ubHkgY29tcG9uZW50OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGxhYmVscz86IExhYmVscztcbiAgcmVhZG9ubHkgZGF0YT86IExhYmVscztcbiAgcmVhZG9ubHkgbG9nZ2VyOiBMb2dnZXI7XG4gIHJlYWRvbmx5IHRyYWNlcj86IFRyYWNlcjtcbiAgcmVhZG9ubHkgbm93OiBOb3c7XG4gIHJlYWRvbmx5IHNwYW5Mb2dMZXZlbD86IExvZ0xldmVsO1xuICByZWFkb25seSBzcGFuPzogU3BhbkRhdGEgfCB2b2lkO1xuICByZWFkb25seSByZXBvcnRIYW5kbGVyPzogUmVwb3J0SGFuZGxlcjtcbn1cblxuZW51bSBMb2dMZXZlbFRvTGV2ZWwge1xuICBlcnJvciA9IDAsXG4gIHdhcm4gPSAxLFxuICBpbmZvID0gMixcbiAgdmVyYm9zZSA9IDMsXG4gIGRlYnVnID0gNCxcbiAgc2lsbHkgPSA1LFxufVxuXG50eXBlIFJlZmVyZW5jZVR5cGUgPSAnY2hpbGRPZicgfCAnZm9sbG93c0Zyb20nO1xuXG5hYnN0cmFjdCBjbGFzcyBEZWZhdWx0UmVmZXJlbmNlIHtcbiAgcHJvdGVjdGVkIGFic3RyYWN0IHJlYWRvbmx5IHR5cGU6IFJlZmVyZW5jZVR5cGU7XG4gIHByaXZhdGUgcmVhZG9ubHkgc3BhbjogU3BhbkNvbnRleHQgfCBNb25pdG9yQmFzZTtcblxuICBwdWJsaWMgY29uc3RydWN0b3Ioc3BhbjogU3BhbkNvbnRleHQgfCBNb25pdG9yQmFzZSkge1xuICAgIHRoaXMuc3BhbiA9IHNwYW47XG4gIH1cblxuICBwdWJsaWMgaXNWYWxpZCgpOiBib29sZWFuIHtcbiAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmUgbm8tdXNlLWJlZm9yZS1kZWNsYXJlXG4gICAgcmV0dXJuICEodGhpcy5zcGFuIGluc3RhbmNlb2YgTW9uaXRvckJhc2UpIHx8IHRoaXMuc3Bhbi5oYXNTcGFuKCk7XG4gIH1cblxuICBwdWJsaWMgZ2V0VHJhY2VyUmVmZXJlbmNlKHRyYWNlcjogVHJhY2VyKTogVHJhY2VyUmVmZXJlbmNlIHwgdW5kZWZpbmVkIHtcbiAgICBpZiAoIXRoaXMuaXNWYWxpZCgpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1Byb2dyYW1taW5nIGVycm9yJyk7XG4gICAgfVxuXG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lIG5vLXVzZS1iZWZvcmUtZGVjbGFyZVxuICAgIGNvbnN0IGNvbnRleHQgPSB0aGlzLnNwYW4gaW5zdGFuY2VvZiBNb25pdG9yQmFzZSA/IHRoaXMuc3Bhbi5nZXRTcGFuKCkuc3BhbiA6IHRoaXMuc3BhbjtcblxuICAgIGlmIChjb250ZXh0ID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMudHlwZSA9PT0gJ2NoaWxkT2YnID8gdHJhY2VyLmNoaWxkT2YoY29udGV4dCkgOiB0cmFjZXIuZm9sbG93c0Zyb20oY29udGV4dCk7XG4gIH1cbn1cblxuY2xhc3MgQ2hpbGRPZlJlZmVyZW5jZSBleHRlbmRzIERlZmF1bHRSZWZlcmVuY2Uge1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgdHlwZTogUmVmZXJlbmNlVHlwZSA9ICdjaGlsZE9mJztcbn1cblxuY2xhc3MgRm9sbG93c0Zyb21SZWZlcmVuY2UgZXh0ZW5kcyBEZWZhdWx0UmVmZXJlbmNlIHtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IHR5cGU6IFJlZmVyZW5jZVR5cGUgPSAnZm9sbG93c0Zyb20nO1xufVxuXG5pbnRlcmZhY2UgQ29tbW9uTG9nT3B0aW9ucyB7XG4gIHJlYWRvbmx5IG5hbWU6IHN0cmluZztcbiAgcmVhZG9ubHkgbWVzc2FnZT86IHN0cmluZztcbiAgcmVhZG9ubHkgbGV2ZWw/OiBMb2dMZXZlbDtcblxuICByZWFkb25seSBtZXRyaWM/OiBDb3VudGVyO1xuXG4gIHJlYWRvbmx5IGVycm9yPzoge1xuICAgIHJlYWRvbmx5IG1ldHJpYz86IENvdW50ZXI7XG4gICAgcmVhZG9ubHkgZXJyb3I/OiBFcnJvciB8IHVuZGVmaW5lZDtcbiAgICByZWFkb25seSBtZXNzYWdlPzogc3RyaW5nO1xuICAgIHJlYWRvbmx5IGxldmVsPzogTG9nTGV2ZWw7XG4gIH07XG59XG5cbmV4cG9ydCBjbGFzcyBNb25pdG9yQmFzZSBpbXBsZW1lbnRzIFNwYW4ge1xuICBwdWJsaWMgcmVhZG9ubHkgbGFiZWxzID0gS25vd25MYWJlbDtcbiAgcHVibGljIHJlYWRvbmx5IGZvcm1hdHMgPSBGb3JtYXQ7XG4gIHB1YmxpYyByZWFkb25seSBub3c6IE5vdztcbiAgcHJpdmF0ZSByZWFkb25seSBzZXJ2aWNlOiBzdHJpbmc7XG4gIHByaXZhdGUgcmVhZG9ubHkgY29tcG9uZW50OiBzdHJpbmc7XG4gIHByaXZhdGUgbXV0YWJsZUN1cnJlbnRMYWJlbHM6IExhYmVscztcbiAgcHJpdmF0ZSBtdXRhYmxlRGF0YTogTGFiZWxzO1xuICBwcml2YXRlIHJlYWRvbmx5IGxvZ2dlcjogTG9nZ2VyO1xuICBwcml2YXRlIHJlYWRvbmx5IHNwYW5Mb2dMZXZlbDogTG9nTGV2ZWw7XG4gIHByaXZhdGUgcmVhZG9ubHkgdHJhY2VyOiBUcmFjZXI7XG4gIHByaXZhdGUgcmVhZG9ubHkgc3BhbjogU3BhbkRhdGEgfCB2b2lkO1xuICBwcml2YXRlIHJlYWRvbmx5IHJlcG9ydEhhbmRsZXI6IFJlcG9ydEhhbmRsZXI7XG5cbiAgcHVibGljIGNvbnN0cnVjdG9yKHtcbiAgICBzZXJ2aWNlLFxuICAgIGNvbXBvbmVudCxcbiAgICBsYWJlbHMgPSB7fSxcbiAgICBkYXRhID0ge30sXG4gICAgbG9nZ2VyLFxuICAgIHNwYW5Mb2dMZXZlbCA9ICdpbmZvJyxcbiAgICB0cmFjZXIgPSBjcmVhdGVUcmFjZXIoKSxcbiAgICBub3csXG4gICAgc3BhbixcbiAgICByZXBvcnRIYW5kbGVyID0gbmV3IFJlcG9ydEhhbmRsZXIobG9nZ2VyKSxcbiAgfTogTW9uaXRvckJhc2VPcHRpb25zKSB7XG4gICAgdGhpcy5zZXJ2aWNlID0gc2VydmljZTtcbiAgICB0aGlzLmNvbXBvbmVudCA9IGNvbXBvbmVudDtcbiAgICB0aGlzLm11dGFibGVDdXJyZW50TGFiZWxzID0gbGFiZWxzO1xuICAgIHRoaXMubXV0YWJsZURhdGEgPSBkYXRhO1xuICAgIHRoaXMubG9nZ2VyID0gbG9nZ2VyO1xuICAgIHRoaXMuc3BhbkxvZ0xldmVsID0gc3BhbkxvZ0xldmVsO1xuICAgIHRoaXMudHJhY2VyID0gdHJhY2VyO1xuICAgIHRoaXMubm93ID0gbm93O1xuICAgIHRoaXMuc3BhbiA9IHNwYW47XG4gICAgdGhpcy5yZXBvcnRIYW5kbGVyID0gcmVwb3J0SGFuZGxlcjtcbiAgfVxuXG4gIHB1YmxpYyBub3dTZWNvbmRzKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMubm93KCkgLyAxMDAwO1xuICB9XG5cbiAgcHVibGljIGF0KGNvbXBvbmVudDogc3RyaW5nKTogTW9uaXRvciB7XG4gICAgcmV0dXJuIHRoaXMuY2xvbmUoeyBjb21wb25lbnQgfSk7XG4gIH1cblxuICBwdWJsaWMgd2l0aExhYmVscyhsYWJlbHM6IExhYmVscyk6IE1vbml0b3Ige1xuICAgIHJldHVybiB0aGlzLmNsb25lKHsgbWVyZ2VMYWJlbHM6IGxhYmVscyB9KTtcbiAgfVxuXG4gIHB1YmxpYyB3aXRoRGF0YShkYXRhOiBMYWJlbHMpOiBNb25pdG9yIHtcbiAgICByZXR1cm4gdGhpcy5jbG9uZSh7IG1lcmdlRGF0YTogZGF0YSB9KTtcbiAgfVxuXG4gIHB1YmxpYyBmb3JDb250ZXh0KF9jdHg6IENvbnRleHQpOiBNb25pdG9yIHtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHB1YmxpYyBmb3JNZXNzYWdlKF9jdHg6IEluY29taW5nTWVzc2FnZSk6IE1vbml0b3Ige1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgcHVibGljIGxvZyh7IG5hbWUsIG1lc3NhZ2UsIGxldmVsLCBtZXRyaWMsIGVycm9yIH06IExvZ09wdGlvbnMpOiB2b2lkIHtcbiAgICB0aGlzLmNvbW1vbkxvZyh7IG5hbWUsIG1lc3NhZ2UsIGxldmVsLCBtZXRyaWMsIGVycm9yIH0pO1xuICB9XG5cbiAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lIG5vLWFueVxuICBwdWJsaWMgY2FwdHVyZUxvZyhmdW5jOiAobW9uaXRvcjogQ2FwdHVyZU1vbml0b3IpID0+IGFueSwgb3B0aW9uczogQ2FwdHVyZUxvZ09wdGlvbnMsIGNsb25lZCA9IGZhbHNlKTogYW55IHtcbiAgICBsZXQgeyBlcnJvcjogZXJyb3JPYmogfSA9IG9wdGlvbnM7XG4gICAgaWYgKGVycm9yT2JqICE9PSB1bmRlZmluZWQgJiYgdHlwZW9mIGVycm9yT2JqID09PSAnc3RyaW5nJykge1xuICAgICAgZXJyb3JPYmogPSB7IG1ldHJpYzogdW5kZWZpbmVkLCBtZXNzYWdlOiBlcnJvck9iaiwgbGV2ZWw6ICdlcnJvcicgfTtcbiAgICB9XG4gICAgY29uc3QgZXJyb3JPYmpGaW5hbCA9IGVycm9yT2JqO1xuICAgIGNvbnN0IGxvZyA9IGNsb25lZCA/IHRoaXMgOiB0aGlzLmNsb25lKCk7XG4gICAgY29uc3QgZG9Mb2cgPSAoZXJyb3I/OiBFcnJvciB8IHVuZGVmaW5lZCkgPT5cbiAgICAgIGxvZy5jb21tb25Mb2coe1xuICAgICAgICBuYW1lOiBvcHRpb25zLm5hbWUsXG4gICAgICAgIG1lc3NhZ2U6IG9wdGlvbnMubWVzc2FnZSxcbiAgICAgICAgbGV2ZWw6IG9wdGlvbnMubGV2ZWwsXG4gICAgICAgIG1ldHJpYzogb3B0aW9ucy5tZXRyaWMsXG4gICAgICAgIGVycm9yOlxuICAgICAgICAgIGVycm9yT2JqRmluYWwgPT09IHVuZGVmaW5lZFxuICAgICAgICAgICAgPyB1bmRlZmluZWRcbiAgICAgICAgICAgIDoge1xuICAgICAgICAgICAgICAgIG1ldHJpYzogZXJyb3JPYmpGaW5hbC5tZXRyaWMsXG4gICAgICAgICAgICAgICAgbWVzc2FnZTogZXJyb3JPYmpGaW5hbC5tZXNzYWdlLFxuICAgICAgICAgICAgICAgIGVycm9yLFxuICAgICAgICAgICAgICAgIGxldmVsOiBlcnJvck9iakZpbmFsLmxldmVsLFxuICAgICAgICAgICAgICB9LFxuICAgICAgfSk7XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzdWx0ID0gZnVuYyhsb2cpO1xuXG4gICAgICBpZiAocmVzdWx0ICE9PSB1bmRlZmluZWQgJiYgcmVzdWx0LnRoZW4gIT09IHVuZGVmaW5lZCkge1xuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgIHJlc3VsdFxuICAgICAgICAgICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lIG5vLWFueVxuICAgICAgICAgICAgLnRoZW4oKHJlczogYW55KSA9PiB7XG4gICAgICAgICAgICAgIGRvTG9nKCk7XG5cbiAgICAgICAgICAgICAgcmV0dXJuIHJlcztcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAuY2F0Y2goKGVycjogRXJyb3IpID0+IHtcbiAgICAgICAgICAgICAgZG9Mb2coZXJyKTtcbiAgICAgICAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgICAgICAgfSlcbiAgICAgICAgKTtcbiAgICAgIH1cblxuICAgICAgZG9Mb2coKTtcblxuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgZG9Mb2coZXJyb3IpO1xuICAgICAgdGhyb3cgZXJyb3IgYXMgRXJyb3I7XG4gICAgfVxuICB9XG5cbiAgcHVibGljIGxvZ0Vycm9yKHsgbmFtZSwgbWVzc2FnZSwgbGV2ZWwsIGVycm9yLCBtZXRyaWMgfTogTG9nRXJyb3JPcHRpb25zKTogdm9pZCB7XG4gICAgbGV0IGVycm9yTGV2ZWwgPSBsZXZlbDtcbiAgICBpZiAoZXJyb3JMZXZlbCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICBlcnJvckxldmVsID0gJ2Vycm9yJztcbiAgICB9XG5cbiAgICB0aGlzLmNvbW1vbkxvZyh7XG4gICAgICBuYW1lLFxuICAgICAgbWVzc2FnZSxcbiAgICAgIGxldmVsOiBsZXZlbCA9PT0gdW5kZWZpbmVkID8gJ2Vycm9yJyA6IGxldmVsLFxuICAgICAgZXJyb3I6IHsgbWV0cmljLCBlcnJvciwgbWVzc2FnZSwgbGV2ZWw6IGVycm9yTGV2ZWwgfSxcbiAgICB9KTtcbiAgfVxuXG4gIHB1YmxpYyBzdGFydFNwYW4oeyBuYW1lLCBsZXZlbCwgbWV0cmljLCByZWZlcmVuY2VzID0gW10sIHRyYWNlIH06IFNwYW5PcHRpb25zKTogTW9uaXRvckJhc2Uge1xuICAgIGxldCBzcGFuO1xuICAgIGxldCBwYXJlbnQ7XG5cbiAgICBjb25zdCBmdWxsTGV2ZWwgPSB0aGlzLmdldEZ1bGxMZXZlbChsZXZlbCk7XG4gICAgY29uc3QgdHJhY2VyUmVmZXJlbmNlcyA9IHJlZmVyZW5jZXNcbiAgICAgIC5jb25jYXQoW3RoaXMuY2hpbGRPZih0aGlzKV0pXG4gICAgICAubWFwKChyZWZlcmVuY2UpID0+IHtcbiAgICAgICAgaWYgKHJlZmVyZW5jZSBpbnN0YW5jZW9mIERlZmF1bHRSZWZlcmVuY2UgJiYgcmVmZXJlbmNlLmlzVmFsaWQoKSkge1xuICAgICAgICAgIHJldHVybiByZWZlcmVuY2UuZ2V0VHJhY2VyUmVmZXJlbmNlKHRoaXMudHJhY2VyKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICB9KVxuICAgICAgLmZpbHRlcih1dGlscy5ub3ROdWxsKTtcbiAgICBpZiAoXG4gICAgICBMb2dMZXZlbFRvTGV2ZWxbZnVsbExldmVsLnNwYW5dIDw9IExvZ0xldmVsVG9MZXZlbFt0aGlzLnNwYW5Mb2dMZXZlbF0gJiZcbiAgICAgICh0cmFjZSAhPT0gdW5kZWZpbmVkIHx8IHRyYWNlclJlZmVyZW5jZXMubGVuZ3RoID4gMClcbiAgICApIHtcbiAgICAgIHNwYW4gPSB0aGlzLnRyYWNlci5zdGFydFNwYW4obmFtZSwge1xuICAgICAgICByZWZlcmVuY2VzOiB0cmFjZXJSZWZlcmVuY2VzLFxuICAgICAgICB0YWdzOiB0aGlzLmdldFNwYW5UYWdzKCksXG4gICAgICB9KTtcbiAgICAgIHBhcmVudCA9IHRoaXM7XG4gICAgfVxuXG4gICAgbGV0IGN1cnJlbnRQYXJlbnQ7XG4gICAgaWYgKHRoaXMuaGFzU3BhbigpKSB7XG4gICAgICAoeyBwYXJlbnQ6IGN1cnJlbnRQYXJlbnQgfSA9IHRoaXMuZ2V0U3BhbigpKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5jbG9uZSh7XG4gICAgICBzcGFuOiB7XG4gICAgICAgIG1ldHJpYyxcbiAgICAgICAgdGltZTogdGhpcy5ub3dTZWNvbmRzKCksXG4gICAgICAgIHNwYW4sXG4gICAgICAgIHBhcmVudDogcGFyZW50ID09PSB1bmRlZmluZWQgPyBjdXJyZW50UGFyZW50IDogcGFyZW50LFxuICAgICAgfSxcbiAgICB9KTtcbiAgfVxuXG4gIHB1YmxpYyBlbmQoZXJyb3IgPSBmYWxzZSk6IHZvaWQge1xuICAgIGNvbnN0IHNwYW4gPSB0aGlzLmdldFNwYW4oKTtcbiAgICBjb25zdCB7IG1ldHJpYyB9ID0gc3BhbjtcbiAgICBpZiAobWV0cmljICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGNvbnN0IHZhbHVlID0gdGhpcy5ub3dTZWNvbmRzKCkgLSBzcGFuLnRpbWU7XG4gICAgICB0aGlzLmludm9rZU1ldHJpYyhtZXRyaWMudG90YWwsICh0b3RhbCkgPT4gdG90YWwub2JzZXJ2ZSh2YWx1ZSksICh0b3RhbCwgbGFiZWxzKSA9PiB0b3RhbC5vYnNlcnZlKGxhYmVscywgdmFsdWUpKTtcbiAgICAgIGlmIChlcnJvcikge1xuICAgICAgICB0aGlzLmludm9rZU1ldHJpYyhcbiAgICAgICAgICBtZXRyaWMuZXJyb3IsXG4gICAgICAgICAgKGVycm9yTWV0cmljKSA9PiBlcnJvck1ldHJpYy5pbmMoKSxcbiAgICAgICAgICAoZXJyb3JNZXRyaWMsIGxhYmVscykgPT4gZXJyb3JNZXRyaWMuaW5jKGxhYmVscyksXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgY29uc3QgeyBzcGFuOiB0cmFjZXJTcGFuIH0gPSBzcGFuO1xuICAgIGlmICh0cmFjZXJTcGFuICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHRyYWNlclNwYW4uc2V0VGFnKHRoaXMubGFiZWxzLkVSUk9SLCAhIWVycm9yKTtcbiAgICAgIHRyYWNlclNwYW4uZmluaXNoKCk7XG4gICAgfVxuICB9XG5cbiAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lIG5vLWFueVxuICBwdWJsaWMgY2FwdHVyZVNwYW4oZnVuYzogKHNwYW46IE1vbml0b3JCYXNlKSA9PiBhbnksIG9wdGlvbnM6IENhcHR1cmVTcGFuT3B0aW9ucyk6IGFueSB7XG4gICAgY29uc3Qgc3BhbiA9IHRoaXMuc3RhcnRTcGFuKHtcbiAgICAgIG5hbWU6IG9wdGlvbnMubmFtZSxcbiAgICAgIGxldmVsOiBvcHRpb25zLmxldmVsLFxuICAgICAgbWV0cmljOiBvcHRpb25zLm1ldHJpYyxcbiAgICAgIHJlZmVyZW5jZXM6IG9wdGlvbnMucmVmZXJlbmNlcyxcbiAgICAgIHRyYWNlOiBvcHRpb25zLnRyYWNlLFxuICAgIH0pO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXN1bHQgPSBmdW5jKHNwYW4pO1xuXG4gICAgICBpZiAocmVzdWx0ICE9PSB1bmRlZmluZWQgJiYgcmVzdWx0LnRoZW4gIT09IHVuZGVmaW5lZCkge1xuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgIHJlc3VsdFxuICAgICAgICAgICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lIG5vLWFueVxuICAgICAgICAgICAgLnRoZW4oKHJlczogYW55KSA9PiB7XG4gICAgICAgICAgICAgIHNwYW4uZW5kKCk7XG5cbiAgICAgICAgICAgICAgcmV0dXJuIHJlcztcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAuY2F0Y2goKGVycjogRXJyb3IpID0+IHtcbiAgICAgICAgICAgICAgc3Bhbi5lbmQodHJ1ZSk7XG4gICAgICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIHNwYW4uZW5kKCk7XG5cbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHNwYW4uZW5kKHRydWUpO1xuICAgICAgdGhyb3cgZXJyb3IgYXMgRXJyb3I7XG4gICAgfVxuICB9XG5cbiAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lIG5vLWFueVxuICBwdWJsaWMgY2FwdHVyZVNwYW5Mb2coZnVuYzogKHNwYW46IENhcHR1cmVNb25pdG9yKSA9PiBhbnksIG9wdGlvbnM6IENhcHR1cmVTcGFuTG9nT3B0aW9ucyk6IGFueSB7XG4gICAgY29uc3QgbGV2ZWwgPSB0aGlzLmdldEZ1bGxMZXZlbChvcHRpb25zLmxldmVsKTtcblxuICAgIHJldHVybiB0aGlzLmNhcHR1cmVTcGFuKFxuICAgICAgKHNwYW4pID0+XG4gICAgICAgIHNwYW4uY2FwdHVyZUxvZyhcbiAgICAgICAgICBmdW5jLFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIG5hbWU6IG9wdGlvbnMubmFtZSxcbiAgICAgICAgICAgIGxldmVsOiBsZXZlbC5sb2csXG4gICAgICAgICAgICBtZXNzYWdlOiBvcHRpb25zLm1lc3NhZ2UsXG4gICAgICAgICAgICBlcnJvcjpcbiAgICAgICAgICAgICAgdHlwZW9mIG9wdGlvbnMuZXJyb3IgPT09ICdvYmplY3QnXG4gICAgICAgICAgICAgICAgPyB7XG4gICAgICAgICAgICAgICAgICAgIGxldmVsOiBvcHRpb25zLmVycm9yLmxldmVsLFxuICAgICAgICAgICAgICAgICAgICBtZXNzYWdlOiBvcHRpb25zLmVycm9yLm