UNPKG

@neo-one/monitor

Version:

NEO•ONE monitoring.

449 lines (448 loc) 61.7 kB
"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