UNPKG

@ngworker/lumberjack

Version:

Lumberjack is a versatile Angular logging library, specifically designed to be extended and customized

262 lines 31.3 kB
import { inject, Injectable } from '@angular/core'; import { formatLogDriverError } from '../formatting/format-log-driver-error'; import { LumberjackLogFormatter } from '../formatting/lumberjack-log-formatter.service'; import { LumberjackLogDriverLogger } from '../log-drivers/lumberjack-log-driver-logger'; import { lumberjackLogDriverToken } from '../log-drivers/lumberjack-log-driver.token'; import { LumberjackTimeService } from '../time/lumberjack-time.service'; import * as i0 from "@angular/core"; const noReportedLogDriverErrorIndex = -1; /** * Service with programmatic API to pass logs to Lumberjack. Optionally * supports a log payload. * * Lumberjack passes the logs to the registered log drivers based on their * configurations. * * NOTE! Consider extending the `LumberjackLogger` or `ScopedLumberjackLogger` * base classes to set up predefined loggers unless you need a programmatic * API. */ export class LumberjackService { /** * The registered log drivers. */ #drivers = inject(lumberjackLogDriverToken, { optional: true }) ?? []; #driverLogger = inject(LumberjackLogDriverLogger); #logFormatter = inject(LumberjackLogFormatter); #time = inject(LumberjackTimeService); constructor() { this.#drivers = Array.isArray(this.#drivers) ? this.#drivers : [this.#drivers]; } /** * Pass a log to Lumberjack which will be forwarded to the registered log * drivers based on their configurations. * * NOTE! It's recommended to use `LumberjackLogBuilder` to create the log. * * @param lumberjackLog The Lumberjack log. Optionally supports a log payload. */ log(lumberjackLog) { const { log, formattedLog } = this.#logFormatter.formatLog(lumberjackLog); this.#logWithErrorHandling(log, formattedLog, this.#drivers); } /** * Pass a critical log to Lumberjack which will be forwarded to the registered * log drivers based on their configurations. * * @param message Log message, for example describing an event that happened. * @param payload An optional payload to add to the log. * @param scope An optional scope to add to the {@link LumberjackLog}. */ logCritical(message, payload, scope) { this.log({ createdAt: this.#time.getUnixEpochTicks(), level: 'critical', message, payload, scope, }); } /** * Pass an error log to Lumberjack which will be forwarded to the registered * log drivers based on their configurations. * * @param message Log message, for example describing an event that happened. * @param payload An optional payload to add to the log. * @param scope An optional scope to add to the {@link LumberjackLog}. */ logError(message, payload, scope) { this.log({ createdAt: this.#time.getUnixEpochTicks(), level: 'error', message, payload, scope, }); } /** * Pass a warning log to Lumberjack which will be forwarded to the registered * log drivers based on their configurations. * * @param message Log message, for example describing an event that happened. * @param payload An optional payload to add to the log. * @param scope An optional scope to add to the {@link LumberjackLog}. */ logWarning(message, payload, scope) { this.log({ createdAt: this.#time.getUnixEpochTicks(), level: 'warn', message, payload, scope, }); } /** * Pass an info log to Lumberjack which will be forwarded to the registered * log drivers based on their configurations. * * @param message Log message, for example describing an event that happened. * @param payload An optional payload to add to the log. * @param scope An optional scope to add to the {@link LumberjackLog}. */ logInfo(message, payload, scope) { this.log({ createdAt: this.#time.getUnixEpochTicks(), level: 'info', message, payload, scope, }); } /** * Pass a debug log to Lumberjack which will be forwarded to the registered * log drivers based on their configurations. * * @param message Log message, for example describing an event that happened. * @param payload An optional payload to add to the log. * @param scope An optional scope to add to the {@link LumberjackLog}. */ logDebug(message, payload, scope) { this.log({ createdAt: this.#time.getUnixEpochTicks(), level: 'debug', message, payload, scope, }); } /** * Pass a trace log to Lumberjack which will be forwarded to the registered * log drivers based on their configurations. * * @param message Log message, for example describing an event that happened. * @param payload An optional payload to add to the log. * @param scope An optional scope to add to the {@link LumberjackLog}. */ logTrace(message, payload, scope) { this.log({ createdAt: this.#time.getUnixEpochTicks(), level: 'trace', message, payload, scope, }); } /** * Determine whether a log driver is configured to accept a log with the * specified log level. * * @param driver The configured log driver. * @param logLevel The log's log level. */ #canDriveLog(driver, logLevel) { const hasVerboseLogging = driver.config.levels.length === 1 && driver.config.levels[0] === 'verbose'; const acceptsLogLevel = driver.config.levels.includes(logLevel); return hasVerboseLogging || acceptsLogLevel; } /** * Create a log based on the specified log driver error. * * @param driverError The reported log driver error. */ #createDriverErrorLog(driverError) { return { createdAt: this.#time.getUnixEpochTicks(), level: 'error', message: formatLogDriverError(driverError), scope: 'LumberjackLogDriverError', }; } /** * If any stable log drivers are specified, the log driver errors will be * forward to them. Otherwise, they will be output to the browser console. * * @param stableDrivers The log drivers that haven't failed. * @param driverErrors The reported log driver errors. */ #handleDriverErrors(stableDrivers, driverErrors) { if (stableDrivers.length > 0) { this.#logDriverErrorsToStableDrivers(driverErrors, stableDrivers); } else { this.#outputUnhandledDriverErrors(driverErrors); } } /** * Pass the log to all the specified log drivers filtered by their log driver * configuration. If the driver throws an error while handling a log, an error * log with the caught error message will be created and passed to the stable * log drivers. * * @param log The log with an optional log payload. * @param formattedLog The text representation of the specified log. * @param drivers The log drivers. * @param driverErrors The reported log driver errors. * @param driverErrorIndex Index of the reported driver error to handle. */ #logWithErrorHandling(log, formattedLog, drivers, driverErrors = [], driverErrorIndex = noReportedLogDriverErrorIndex) { const stableDrivers = []; drivers .filter((driver) => this.#canDriveLog(driver, log.level)) .forEach((driver) => { try { this.#driverLogger.log(driver, { formattedLog, log }); stableDrivers.push(driver); if (driverErrorIndex !== noReportedLogDriverErrorIndex) { this.#removeHandledError(driverErrorIndex, driverErrors); driverErrorIndex = noReportedLogDriverErrorIndex; } } catch (error) { const caughtDriverError = { error, formattedLog, log, logDriver: driver }; driverErrors = [...driverErrors, caughtDriverError]; } }); this.#handleDriverErrors(stableDrivers, driverErrors); } /** * Pass the log driver errors to the specified stable log drivers. * * @param driverErrors The reported log driver errors. * @param stableDrivers The log drivers that haven't failed. */ #logDriverErrorsToStableDrivers(driverErrors, stableDrivers) { driverErrors.forEach((error, errorIndex) => { const driverErrorLog = this.#createDriverErrorLog(error); this.#logWithErrorHandling(driverErrorLog, driverErrorLog.message, stableDrivers, driverErrors, errorIndex); }); } /** * Output the specified log driver error to the browser console. * * @param driverError The reported log driver error. */ #outputDriverError(driverError) { const errorMessage = formatLogDriverError(driverError); console.error(errorMessage); } /** * Output the unhandled log driver errors to the browser console. * * @param driverErrors The reported log driver errors. */ #outputUnhandledDriverErrors(driverErrors) { driverErrors.forEach((error) => this.#outputDriverError(error)); } /** * Remove the log driver error with the specified index. * * @param driverErrorIndex The index of the log driver error to remove from * the specified log driver errors. * @param driverErrors The reported log driver errors. */ #removeHandledError(driverErrorIndex, driverErrors) { driverErrors.splice(driverErrorIndex, 1); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: LumberjackService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: LumberjackService }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImport: i0, type: LumberjackService, decorators: [{ type: Injectable }], ctorParameters: () => [] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibHVtYmVyamFjay5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvbmd3b3JrZXIvbHVtYmVyamFjay9zcmMvbGliL2xvZ2dpbmcvbHVtYmVyamFjay5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRW5ELE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLHVDQUF1QyxDQUFDO0FBQzdFLE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLGdEQUFnRCxDQUFDO0FBR3hGLE9BQU8sRUFBRSx5QkFBeUIsRUFBRSxNQUFNLDZDQUE2QyxDQUFDO0FBQ3hGLE9BQU8sRUFBRSx3QkFBd0IsRUFBRSxNQUFNLDRDQUE0QyxDQUFDO0FBSXRGLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLGlDQUFpQyxDQUFDOztBQUV4RSxNQUFNLDZCQUE2QixHQUFHLENBQUMsQ0FBQyxDQUFDO0FBRXpDOzs7Ozs7Ozs7O0dBVUc7QUFFSCxNQUFNLE9BQU8saUJBQWlCO0lBQzVCOztPQUVHO0lBQ00sUUFBUSxHQUFHLE1BQU0sQ0FBa0Msd0JBQXdCLEVBQUUsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDdkcsYUFBYSxHQUFHLE1BQU0sQ0FBc0MseUJBQXlCLENBQUMsQ0FBQztJQUN2RixhQUFhLEdBQUcsTUFBTSxDQUFtQyxzQkFBc0IsQ0FBQyxDQUFDO0lBQ2pGLEtBQUssR0FBRyxNQUFNLENBQUMscUJBQXFCLENBQUMsQ0FBQztJQUUvQztRQUNFLElBQUksQ0FBQyxRQUFRLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFFB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TUc7SUFDSCxtQkFBbUIsQ0FBQyxnQkFBd0IsRUFBRSxZQUFrRDtRQUM5RixZQUFZLENBQUMsTUFBTSxDQUFDLGdCQUFnQixFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQzNDLENBQUM7dUdBM1FVLGlCQUFpQjsyR0FBakIsaUJBQWlCOzsyRkFBakIsaUJBQWlCO2tCQUQ3QixVQUFVIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgaW5qZWN0LCBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbmltcG9ydCB7IGZvcm1hdExvZ0RyaXZlckVycm9yIH0gZnJvbSAnLi4vZm9ybWF0dGluZy9mb3JtYXQtbG9nLWRyaXZlci1lcnJvcic7XG5pbXBvcnQgeyBMdW1iZXJqYWNrTG9nRm9ybWF0dGVyIH0gZnJvbSAnLi4vZm9ybWF0dGluZy9sdW1iZXJqYWNrLWxvZy1mb3JtYXR0ZXIuc2VydmljZSc7XG5pbXBvcnQgeyBMdW1iZXJqYWNrTG9nRHJpdmVyIH0gZnJvbSAnLi4vbG9nLWRyaXZlcnMvbHVtYmVyamFjay1sb2ctZHJpdmVyJztcbmltcG9ydCB7IEx1bWJlcmphY2tMb2dEcml2ZXJFcnJvciB9IGZyb20gJy4uL2xvZy1kcml2ZXJzL2x1bWJlcmphY2stbG9nLWRyaXZlci1lcnJvcic7XG5pbXBvcnQgeyBMdW1iZXJqYWNrTG9nRHJpdmVyTG9nZ2VyIH0gZnJvbSAnLi4vbG9nLWRyaXZlcnMvbHVtYmVyamFjay1sb2ctZHJpdmVyLWxvZ2dlcic7XG5pbXBvcnQgeyBsdW1iZXJqYWNrTG9nRHJpdmVyVG9rZW4gfSBmcm9tICcuLi9sb2ctZHJpdmVycy9sdW1iZXJqYWNrLWxvZy1kcml2ZXIudG9rZW4nO1xuaW1wb3J0IHsgTHVtYmVyamFja0xvZ0xldmVsIH0gZnJvbSAnLi4vbG9ncy9sdW1iZXJqYWNrLWxvZy1sZXZlbCc7XG5pbXBvcnQgeyBMdW1iZXJqYWNrTG9nUGF5bG9hZCB9IGZyb20gJy4uL2xvZ3MvbHVtYmVyamFjay1sb2ctcGF5bG9hZCc7XG5pbXBvcnQgeyBMdW1iZXJqYWNrTG9nIH0gZnJvbSAnLi4vbG9ncy9sdW1iZXJqYWNrLmxvZyc7XG5pbXBvcnQgeyBMdW1iZXJqYWNrVGltZVNlcnZpY2UgfSBmcm9tICcuLi90aW1lL2x1bWJlcmphY2stdGltZS5zZXJ2aWNlJztcblxuY29uc3Qgbm9SZXBvcnRlZExvZ0RyaXZlckVycm9ySW5kZXggPSAtMTtcblxuLyoqXG4gKiBTZXJ2aWNlIHdpdGggcHJvZ3JhbW1hdGljIEFQSSB0byBwYXNzIGxvZ3MgdG8gTHVtYmVyamFjay4gT3B0aW9uYWxseVxuICogc3VwcG9ydHMgYSBsb2cgcGF5bG9hZC5cbiAqXG4gKiBMdW1iZXJqYWNrIHBhc3NlcyB0aGUgbG9ncyB0byB0aGUgcmVnaXN0ZXJlZCBsb2cgZHJpdmVycyBiYXNlZCBvbiB0aGVpclxuICogY29uZmlndXJhdGlvbnMuXG4gKlxuICogTk9URSEgQ29uc2lkZXIgZXh0ZW5kaW5nIHRoZSBgTHVtYmVyamFja0xvZ2dlcmAgb3IgYFNjb3BlZEx1bWJlcmphY2tMb2dnZXJgXG4gKiBiYXNlIGNsYXNzZXMgdG8gc2V0IHVwIHByZWRlZmluZWQgbG9nZ2VycyB1bmxlc3MgeW91IG5lZWQgYSBwcm9ncmFtbWF0aWNcbiAqIEFQSS5cbiAqL1xuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIEx1bWJlcmphY2tTZXJ2aWNlPFRQYXlsb2FkIGV4dGVuZHMgTHVtYmVyamFja0xvZ1BheWxvYWQgfCB2b2lkID0gdm9pZD4ge1xuICAvKipcbiAgICogVGhlIHJlZ2lzdGVyZWQgbG9nIGRyaXZlcnMuXG4gICAqL1xuICByZWFkb25seSAjZHJpdmVycyA9IGluamVjdDxMdW1iZXJqYWNrTG9nRHJpdmVyPFRQYXlsb2FkPltdPihsdW1iZXJqYWNrTG9nRHJpdmVyVG9rZW4sIHsgb3B0aW9uYWw6IHRydWUgfSkgPz8gW107XG4gIHJlYWRvbmx5ICNkcml2ZXJMb2dnZXIgPSBpbmplY3Q8THVtYmVyamFja0xvZ0RyaXZlckxvZ2dlcjxUUGF5bG9hZD4+KEx1bWJlcmphY2tMb2dEcml2ZXJMb2dnZXIpO1xuICByZWFkb25seSAjbG9nRm9ybWF0dGVyID0gaW5qZWN0PEx1bWJlcmphY2tMb2dGb3JtYXR0ZXI8VFBheWxvYWQ+PihMdW1iZXJqYWNrTG9nRm9ybWF0dGVyKTtcbiAgcmVhZG9ubHkgI3RpbWUgPSBpbmplY3QoTHVtYmVyamFja1RpbWVTZXJ2aWNlKTtcblxuICBjb25zdHJ1Y3RvcigpIHtcbiAgICB0aGlzLiNkcml2ZXJzID0gQXJyYXkuaXNBcnJheSh0aGlzLiNkcml2ZXJzKSA/IHRoaXMuI2RyaXZlcnMgOiBbdGhpcy4jZHJpdmVyc107XG4gIH1cblxuICAvKipcbiAgICogUGFzcyBhIGxvZyB0byBMdW1iZXJqYWNrIHdoaWNoIHdpbGwgYmUgZm9yd2FyZGVkIHRvIHRoZSByZWdpc3RlcmVkIGxvZ1xuICAgKiBkcml2ZXJzIGJhc2VkIG9uIHRoZWlyIGNvbmZpZ3VyYXRpb25zLlxuICAgKlxuICAgKiBOT1RFISBJdCdzIHJlY29tbWVuZGVkIHRvIHVzZSBgTHVtYmVyamFja0xvZ0J1aWxkZXJgIHRvIGNyZWF0ZSB0aGUgbG9nLlxuICAgKlxuICAgKiBAcGFyYW0gbHVtYmVyamFja0xvZyBUaGUgTHVtYmVyamFjayBsb2cuIE9wdGlvbmFsbHkgc3VwcG9ydHMgYSBsb2cgcGF5bG9hZC5cbiAgICovXG4gIGxvZyhsdW1iZXJqYWNrTG9nOiBMdW1iZXJqYWNrTG9nPFRQYXlsb2FkPik6IHZvaWQge1xuICAgIGNvbnN0IHsgbG9nLCBmb3JtYXR0ZWRMb2cgfSA9IHRoaXMuI2xvZ0Zvcm1hdHRlci5mb3JtYXRMb2cobHVtYmVyamFja0xvZyk7XG5cbiAgICB0aGlzLiNsb2dXaXRoRXJyb3JIYW5kbGluZyhsb2csIGZvcm1hdHRlZExvZywgdGhpcy4jZHJpdmVycyk7XG4gIH1cblxuICAvKipcbiAgICogUGFzcyBhIGNyaXRpY2FsIGxvZyB0byBMdW1iZXJqYWNrIHdoaWNoIHdpbGwgYmUgZm9yd2FyZGVkIHRvIHRoZSByZWdpc3RlcmVkXG4gICAqIGxvZyBkcml2ZXJzIGJhc2VkIG9uIHRoZWlyIGNvbmZpZ3VyYXRpb25zLlxuICAgKlxuICAgKiBAcGFyYW0gbWVzc2FnZSBMb2cgbWVzc2FnZSwgZm9yIGV4YW1wbGUgZGVzY3JpYmluZyBhbiBldmVudCB0aGF0IGhhcHBlbmVkLlxuICAgKiBAcGFyYW0gcGF5bG9hZCBBbiBvcHRpb25hbCBwYXlsb2FkIHRvIGFkZCB0byB0aGUgbG9nLlxuICAgKiBAcGFyYW0gc2NvcGUgQW4gb3B0aW9uYWwgc2NvcGUgdG8gYWRkIHRvIHRoZSB7QGxpbmsgTHVtYmVyamFja0xvZ30uXG4gICAqL1xuICBsb2dDcml0aWNhbChtZXNzYWdlOiBzdHJpbmcsIHBheWxvYWQ/OiBUUGF5bG9hZCwgc2NvcGU/OiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmxvZyh7XG4gICAgICBjcmVhdGVkQXQ6IHRoaXMuI3RpbWUuZ2V0VW5peEVwb2NoVGlja3MoKSxcbiAgICAgIGxldmVsOiAnY3JpdGljYWwnLFxuICAgICAgbWVzc2FnZSxcbiAgICAgIHBheWxvYWQsXG4gICAgICBzY29wZSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQYXNzIGFuIGVycm9yIGxvZyB0byBMdW1iZXJqYWNrIHdoaWNoIHdpbGwgYmUgZm9yd2FyZGVkIHRvIHRoZSByZWdpc3RlcmVkXG4gICAqIGxvZyBkcml2ZXJzIGJhc2VkIG9uIHRoZWlyIGNvbmZpZ3VyYXRpb25zLlxuICAgKlxuICAgKiBAcGFyYW0gbWVzc2FnZSBMb2cgbWVzc2FnZSwgZm9yIGV4YW1wbGUgZGVzY3JpYmluZyBhbiBldmVudCB0aGF0IGhhcHBlbmVkLlxuICAgKiBAcGFyYW0gcGF5bG9hZCBBbiBvcHRpb25hbCBwYXlsb2FkIHRvIGFkZCB0byB0aGUgbG9nLlxuICAgKiBAcGFyYW0gc2NvcGUgQW4gb3B0aW9uYWwgc2NvcGUgdG8gYWRkIHRvIHRoZSB7QGxpbmsgTHVtYmVyamFja0xvZ30uXG4gICAqL1xuICBsb2dFcnJvcihtZXNzYWdlOiBzdHJpbmcsIHBheWxvYWQ/OiBUUGF5bG9hZCwgc2NvcGU/OiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmxvZyh7XG4gICAgICBjcmVhdGVkQXQ6IHRoaXMuI3RpbWUuZ2V0VW5peEVwb2NoVGlja3MoKSxcbiAgICAgIGxldmVsOiAnZXJyb3InLFxuICAgICAgbWVzc2FnZSxcbiAgICAgIHBheWxvYWQsXG4gICAgICBzY29wZSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQYXNzIGEgd2FybmluZyBsb2cgdG8gTHVtYmVyamFjayB3aGljaCB3aWxsIGJlIGZvcndhcmRlZCB0byB0aGUgcmVnaXN0ZXJlZFxuICAgKiBsb2cgZHJpdmVycyBiYXNlZCBvbiB0aGVpciBjb25maWd1cmF0aW9ucy5cbiAgICpcbiAgICogQHBhcmFtIG1lc3NhZ2UgTG9nIG1lc3NhZ2UsIGZvciBleGFtcGxlIGRlc2NyaWJpbmcgYW4gZXZlbnQgdGhhdCBoYXBwZW5lZC5cbiAgICogQHBhcmFtIHBheWxvYWQgQW4gb3B0aW9uYWwgcGF5bG9hZCB0byBhZGQgdG8gdGhlIGxvZy5cbiAgICogQHBhcmFtIHNjb3BlIEFuIG9wdGlvbmFsIHNjb3BlIHRvIGFkZCB0byB0aGUge0BsaW5rIEx1bWJlcmphY2tMb2d9LlxuICAgKi9cbiAgbG9nV2FybmluZyhtZXNzYWdlOiBzdHJpbmcsIHBheWxvYWQ/OiBUUGF5bG9hZCwgc2NvcGU/OiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmxvZyh7XG4gICAgICBjcmVhdGVkQXQ6IHRoaXMuI3RpbWUuZ2V0VW5peEVwb2NoVGlja3MoKSxcbiAgICAgIGxldmVsOiAnd2FybicsXG4gICAgICBtZXNzYWdlLFxuICAgICAgcGF5bG9hZCxcbiAgICAgIHNjb3BlLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFBhc3MgYW4gaW5mbyBsb2cgdG8gTHVtYmVyamFjayB3aGljaCB3aWxsIGJlIGZvcndhcmRlZCB0byB0aGUgcmVnaXN0ZXJlZFxuICAgKiBsb2cgZHJpdmVycyBiYXNlZCBvbiB0aGVpciBjb25maWd1cmF0aW9ucy5cbiAgICpcbiAgICogQHBhcmFtIG1lc3NhZ2UgTG9nIG1lc3NhZ2UsIGZvciBleGFtcGxlIGRlc2NyaWJpbmcgYW4gZXZlbnQgdGhhdCBoYXBwZW5lZC5cbiAgICogQHBhcmFtIHBheWxvYWQgQW4gb3B0aW9uYWwgcGF5bG9hZCB0byBhZGQgdG8gdGhlIGxvZy5cbiAgICogQHBhcmFtIHNjb3BlIEFuIG9wdGlvbmFsIHNjb3BlIHRvIGFkZCB0byB0aGUge0BsaW5rIEx1bWJlcmphY2tMb2d9LlxuICAgKi9cbiAgbG9nSW5mbyhtZXNzYWdlOiBzdHJpbmcsIHBheWxvYWQ/OiBUUGF5bG9hZCwgc2NvcGU/OiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmxvZyh7XG4gICAgICBjcmVhdGVkQXQ6IHRoaXMuI3RpbWUuZ2V0VW5peEVwb2NoVGlja3MoKSxcbiAgICAgIGxldmVsOiAnaW5mbycsXG4gICAgICBtZXNzYWdlLFxuICAgICAgcGF5bG9hZCxcbiAgICAgIHNjb3BlLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFBhc3MgYSBkZWJ1ZyBsb2cgdG8gTHVtYmVyamFjayB3aGljaCB3aWxsIGJlIGZvcndhcmRlZCB0byB0aGUgcmVnaXN0ZXJlZFxuICAgKiBsb2cgZHJpdmVycyBiYXNlZCBvbiB0aGVpciBjb25maWd1cmF0aW9ucy5cbiAgICpcbiAgICogQHBhcmFtIG1lc3NhZ2UgTG9nIG1lc3NhZ2UsIGZvciBleGFtcGxlIGRlc2NyaWJpbmcgYW4gZXZlbnQgdGhhdCBoYXBwZW5lZC5cbiAgICogQHBhcmFtIHBheWxvYWQgQW4gb3B0aW9uYWwgcGF5bG9hZCB0byBhZGQgdG8gdGhlIGxvZy5cbiAgICogQHBhcmFtIHNjb3BlIEFuIG9wdGlvbmFsIHNjb3BlIHRvIGFkZCB0byB0aGUge0BsaW5rIEx1bWJlcmphY2tMb2d9LlxuICAgKi9cbiAgbG9nRGVidWcobWVzc2FnZTogc3RyaW5nLCBwYXlsb2FkPzogVFBheWxvYWQsIHNjb3BlPzogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5sb2coe1xuICAgICAgY3JlYXRlZEF0OiB0aGlzLiN0aW1lLmdldFVuaXhFcG9jaFRpY2tzKCksXG4gICAgICBsZXZlbDogJ2RlYnVnJyxcbiAgICAgIG1lc3NhZ2UsXG4gICAgICBwYXlsb2FkLFxuICAgICAgc2NvcGUsXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogUGFzcyBhIHRyYWNlIGxvZyB0byBMdW1iZXJqYWNrIHdoaWNoIHdpbGwgYmUgZm9yd2FyZGVkIHRvIHRoZSByZWdpc3RlcmVkXG4gICAqIGxvZyBkcml2ZXJzIGJhc2VkIG9uIHRoZWlyIGNvbmZpZ3VyYXRpb25zLlxuICAgKlxuICAgKiBAcGFyYW0gbWVzc2FnZSBMb2cgbWVzc2FnZSwgZm9yIGV4YW1wbGUgZGVzY3JpYmluZyBhbiBldmVudCB0aGF0IGhhcHBlbmVkLlxuICAgKiBAcGFyYW0gcGF5bG9hZCBBbiBvcHRpb25hbCBwYXlsb2FkIHRvIGFkZCB0byB0aGUgbG9nLlxuICAgKiBAcGFyYW0gc2NvcGUgQW4gb3B0aW9uYWwgc2NvcGUgdG8gYWRkIHRvIHRoZSB7QGxpbmsgTHVtYmVyamFja0xvZ30uXG4gICAqL1xuICBsb2dUcmFjZShtZXNzYWdlOiBzdHJpbmcsIHBheWxvYWQ/OiBUUGF5bG9hZCwgc2NvcGU/OiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmxvZyh7XG4gICAgICBjcmVhdGVkQXQ6IHRoaXMuI3RpbWUuZ2V0VW5peEVwb2NoVGlja3MoKSxcbiAgICAgIGxldmVsOiAndHJhY2UnLFxuICAgICAgbWVzc2FnZSxcbiAgICAgIHBheWxvYWQsXG4gICAgICBzY29wZSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZXRlcm1pbmUgd2hldGhlciBhIGxvZyBkcml2ZXIgaXMgY29uZmlndXJlZCB0byBhY2NlcHQgYSBsb2cgd2l0aCB0aGVcbiAgICogc3BlY2lmaWVkIGxvZyBsZXZlbC5cbiAgICpcbiAgICogQHBhcmFtIGRyaXZlciBUaGUgY29uZmlndXJlZCBsb2cgZHJpdmVyLlxuICAgKiBAcGFyYW0gbG9nTGV2ZWwgVGhlIGxvZydzIGxvZyBsZXZlbC5cbiAgICovXG4gICNjYW5Ecml2ZUxvZyhkcml2ZXI6IEx1bWJlcmphY2tMb2dEcml2ZXI8VFBheWxvYWQ+LCBsb2dMZXZlbDogTHVtYmVyamFja0xvZ0xldmVsKTogYm9vbGVhbiB7XG4gICAgY29uc3QgaGFzVmVyYm9zZUxvZ2dpbmcgPSBkcml2ZXIuY29uZmlnLmxldmVscy5sZW5ndGggPT09IDEgJiYgZHJpdmVyLmNvbmZpZy5sZXZlbHNbMF0gPT09ICd2ZXJib3NlJztcbiAgICBjb25zdCBhY2NlcHRzTG9nTGV2ZWwgPSAoZHJpdmVyLmNvbmZpZy5sZXZlbHMgYXMgTHVtYmVyamFja0xvZ0xldmVsW10pLmluY2x1ZGVzKGxvZ0xldmVsKTtcblxuICAgIHJldHVybiBoYXNWZXJib3NlTG9nZ2luZyB8fCBhY2NlcHRzTG9nTGV2ZWw7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlIGEgbG9nIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgbG9nIGRyaXZlciBlcnJvci5cbiAgICpcbiAgICogQHBhcmFtIGRyaXZlckVycm9yIFRoZSByZXBvcnRlZCBsb2cgZHJpdmVyIGVycm9yLlxuICAgKi9cbiAgI2NyZWF0ZURyaXZlckVycm9yTG9nKGRyaXZlckVycm9yOiBMdW1iZXJqYWNrTG9nRHJpdmVyRXJyb3I8VFBheWxvYWQ+KTogTHVtYmVyamFja0xvZzxUUGF5bG9hZD4ge1xuICAgIHJldHVybiB7XG4gICAgICBjcmVhdGVkQXQ6IHRoaXMuI3RpbWUuZ2V0VW5peEVwb2NoVGlja3MoKSxcbiAgICAgIGxldmVsOiAnZXJyb3InLFxuICAgICAgbWVzc2FnZTogZm9ybWF0TG9nRHJpdmVyRXJyb3IoZHJpdmVyRXJyb3IpLFxuICAgICAgc2NvcGU6ICdMdW1iZXJqYWNrTG9nRHJpdmVyRXJyb3InLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogSWYgYW55IHN0YWJsZSBsb2cgZHJpdmVycyBhcmUgc3BlY2lmaWVkLCB0aGUgbG9nIGRyaXZlciBlcnJvcnMgd2lsbCBiZVxuICAgKiBmb3J3YXJkIHRvIHRoZW0uIE90aGVyd2lzZSwgdGhleSB3aWxsIGJlIG91dHB1dCB0byB0aGUgYnJvd3NlciBjb25zb2xlLlxuICAgKlxuICAgKiBAcGFyYW0gc3RhYmxlRHJpdmVycyBUaGUgbG9nIGRyaXZlcnMgdGhhdCBoYXZlbid0IGZhaWxlZC5cbiAgICogQHBhcmFtIGRyaXZlckVycm9ycyBUaGUgcmVwb3J0ZWQgbG9nIGRyaXZlciBlcnJvcnMuXG4gICAqL1xuICAjaGFuZGxlRHJpdmVyRXJyb3JzKFxuICAgIHN0YWJsZURyaXZlcnM6IEx1bWJlcmphY2tMb2dEcml2ZXI8VFBheWxvYWQ+W10sXG4gICAgZHJpdmVyRXJyb3JzOiBMdW1iZXJqYWNrTG9nRHJpdmVyRXJyb3I8VFBheWxvYWQ+W11cbiAgKSB7XG4gICAgaWYgKHN0YWJsZURyaXZlcnMubGVuZ3RoID4gMCkge1xuICAgICAgdGhpcy4jbG9nRHJpdmVyRXJyb3JzVG9TdGFibGVEcml2ZXJzKGRyaXZlckVycm9ycywgc3RhYmxlRHJpdmVycyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuI291dHB1dFVuaGFuZGxlZERyaXZlckVycm9ycyhkcml2ZXJFcnJvcnMpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBQYXNzIHRoZSBsb2cgdG8gYWxsIHRoZSBzcGVjaWZpZWQgbG9nIGRyaXZlcnMgZmlsdGVyZWQgYnkgdGhlaXIgbG9nIGRyaXZlclxuICAgKiBjb25maWd1cmF0aW9uLiBJZiB0aGUgZHJpdmVyIHRocm93cyBhbiBlcnJvciB3aGlsZSBoYW5kbGluZyBhIGxvZywgYW4gZXJyb3JcbiAgICogbG9nIHdpdGggdGhlIGNhdWdodCBlcnJvciBtZXNzYWdlIHdpbGwgYmUgY3JlYXRlZCBhbmQgcGFzc2VkIHRvIHRoZSBzdGFibGVcbiAgICogbG9nIGRyaXZlcnMuXG4gICAqXG4gICAqIEBwYXJhbSBsb2cgVGhlIGxvZyB3aXRoIGFuIG9wdGlvbmFsIGxvZyBwYXlsb2FkLlxuICAgKiBAcGFyYW0gZm9ybWF0dGVkTG9nIFRoZSB0ZXh0IHJlcHJlc2VudGF0aW9uIG9mIHRoZSBzcGVjaWZpZWQgbG9nLlxuICAgKiBAcGFyYW0gZHJpdmVycyBUaGUgbG9nIGRyaXZlcnMuXG4gICAqIEBwYXJhbSBkcml2ZXJFcnJvcnMgVGhlIHJlcG9ydGVkIGxvZyBkcml2ZXIgZXJyb3JzLlxuICAgKiBAcGFyYW0gZHJpdmVyRXJyb3JJbmRleCBJbmRleCBvZiB0aGUgcmVwb3J0ZWQgZHJpdmVyIGVycm9yIHRvIGhhbmRsZS5cbiAgICovXG4gICNsb2dXaXRoRXJyb3JIYW5kbGluZyhcbiAgICBsb2c6IEx1bWJlcmphY2tMb2c8VFBheWxvYWQ+LFxuICAgIGZvcm1hdHRlZExvZzogc3RyaW5nLFxuICAgIGRyaXZlcnM6IEx1bWJlcmphY2tMb2dEcml2ZXI8VFBheWxvYWQ+W10sXG4gICAgZHJpdmVyRXJyb3JzOiBMdW1iZXJqYWNrTG9nRHJpdmVyRXJyb3I8VFBheWxvYWQ+W10gPSBbXSxcbiAgICBkcml2ZXJFcnJvckluZGV4ID0gbm9SZXBvcnRlZExvZ0RyaXZlckVycm9ySW5kZXhcbiAgKTogdm9pZCB7XG4gICAgY29uc3Qgc3RhYmxlRHJpdmVyczogTHVtYmVyamFja0xvZ0RyaXZlcjxUUGF5bG9hZD5bXSA9IFtdO1xuXG4gICAgZHJpdmVyc1xuICAgICAgLmZpbHRlcigoZHJpdmVyKSA9PiB0aGlzLiNjYW5Ecml2ZUxvZyhkcml2ZXIsIGxvZy5sZXZlbCkpXG4gICAgICAuZm9yRWFjaCgoZHJpdmVyKSA9PiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgdGhpcy4jZHJpdmVyTG9nZ2VyLmxvZyhkcml2ZXIsIHsgZm9ybWF0dGVkTG9nLCBsb2cgfSk7XG4gICAgICAgICAgc3RhYmxlRHJpdmVycy5wdXNoKGRyaXZlcik7XG5cbiAgICAgICAgICBpZiAoZHJpdmVyRXJyb3JJbmRleCAhPT0gbm9SZXBvcnRlZExvZ0RyaXZlckVycm9ySW5kZXgpIHtcbiAgICAgICAgICAgIHRoaXMuI3JlbW92ZUhhbmRsZWRFcnJvcihkcml2ZXJFcnJvckluZGV4LCBkcml2ZXJFcnJvcnMpO1xuICAgICAgICAgICAgZHJpdmVyRXJyb3JJbmRleCA9IG5vUmVwb3J0ZWRMb2dEcml2ZXJFcnJvckluZGV4O1xuICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICBjb25zdCBjYXVnaHREcml2ZXJFcnJvcjogTHVtYmVyamFja0xvZ0RyaXZlckVycm9yPFRQYXlsb2FkPiA9IHsgZXJyb3IsIGZvcm1hdHRlZExvZywgbG9nLCBsb2dEcml2ZXI6IGRyaXZlciB9O1xuICAgICAgICAgIGRyaXZlckVycm9ycyA9IFsuLi5kcml2ZXJFcnJvcnMsIGNhdWdodERyaXZlckVycm9yXTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgdGhpcy4jaGFuZGxlRHJpdmVyRXJyb3JzKHN0YWJsZURyaXZlcnMsIGRyaXZlckVycm9ycyk7XG4gIH1cblxuICAvKipcbiAgICogUGFzcyB0aGUgbG9nIGRyaXZlciBlcnJvcnMgdG8gdGhlIHNwZWNpZmllZCBzdGFibGUgbG9nIGRyaXZlcnMuXG4gICAqXG4gICAqIEBwYXJhbSBkcml2ZXJFcnJvcnMgVGhlIHJlcG9ydGVkIGxvZyBkcml2ZXIgZXJyb3JzLlxuICAgKiBAcGFyYW0gc3RhYmxlRHJpdmVycyBUaGUgbG9nIGRyaXZlcnMgdGhhdCBoYXZlbid0IGZhaWxlZC5cbiAgICovXG4gICNsb2dEcml2ZXJFcnJvcnNUb1N0YWJsZURyaXZlcnMoXG4gICAgZHJpdmVyRXJyb3JzOiBMdW1iZXJqYWNrTG9nRHJpdmVyRXJyb3I8VFBheWxvYWQ+W10sXG4gICAgc3RhYmxlRHJpdmVyczogTHVtYmVyamFja0xvZ0RyaXZlcjxUUGF5bG9hZD5bXVxuICApIHtcbiAgICBkcml2ZXJFcnJvcnMuZm9yRWFjaCgoZXJyb3IsIGVycm9ySW5kZXgpID0+IHtcbiAgICAgIGNvbnN0IGRyaXZlckVycm9yTG9nID0gdGhpcy4jY3JlYXRlRHJpdmVyRXJyb3JMb2coZXJyb3IpO1xuXG4gICAgICB0aGlzLiNsb2dXaXRoRXJyb3JIYW5kbGluZyhkcml2ZXJFcnJvckxvZywgZHJpdmVyRXJyb3JMb2cubWVzc2FnZSwgc3RhYmxlRHJpdmVycywgZHJpdmVyRXJyb3JzLCBlcnJvckluZGV4KTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBPdXRwdXQgdGhlIHNwZWNpZmllZCBsb2cgZHJpdmVyIGVycm9yIHRvIHRoZSBicm93c2VyIGNvbnNvbGUuXG4gICAqXG4gICAqIEBwYXJhbSBkcml2ZXJFcnJvciBUaGUgcmVwb3J0ZWQgbG9nIGRyaXZlciBlcnJvci5cbiAgICovXG4gICNvdXRwdXREcml2ZXJFcnJvcihkcml2ZXJFcnJvcjogTHVtYmVyamFja0xvZ0RyaXZlckVycm9yPFRQYXlsb2FkPik6IHZvaWQge1xuICAgIGNvbnN0IGVycm9yTWVzc2FnZSA9IGZvcm1hdExvZ0RyaXZlckVycm9yKGRyaXZlckVycm9yKTtcblxuICAgIGNvbnNvbGUuZXJyb3IoZXJyb3JNZXNzYWdlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBPdXRwdXQgdGhlIHVuaGFuZGxlZCBsb2cgZHJpdmVyIGVycm9ycyB0byB0aGUgYnJvd3NlciBjb25zb2xlLlxuICAgKlxuICAgKiBAcGFyYW0gZHJpdmVyRXJyb3JzIFRoZSByZXBvcnRlZCBsb2cgZHJpdmVyIGVycm9ycy5cbiAgICovXG4gICNvdXRwdXRVbmhhbmRsZWREcml2ZXJFcnJvcnMoZHJpdmVyRXJyb3JzOiBMdW1iZXJqYWNrTG9nRHJpdmVyRXJyb3I8VFBheWxvYWQ+W10pIHtcbiAgICBkcml2ZXJFcnJvcnMuZm9yRWFjaCgoZXJyb3IpID0+IHRoaXMuI291dHB1dERyaXZlckVycm9yKGVycm9yKSk7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlIHRoZSBsb2cgZHJpdmVyIGVycm9yIHdpdGggdGhlIHNwZWNpZmllZCBpbmRleC5cbiAgICpcbiAgICogQHBhcmFtIGRyaXZlckVycm9ySW5kZXggVGhlIGluZGV4IG9mIHRoZSBsb2cgZHJpdmVyIGVycm9yIHRvIHJlbW92ZSBmcm9tXG4gICAqICAgdGhlIHNwZWNpZmllZCBsb2cgZHJpdmVyIGVycm9ycy5cbiAgICogQHBhcmFtIGRyaXZlckVycm9ycyBUaGUgcmVwb3J0ZWQgbG9nIGRyaXZlciBlcnJvcnMuXG4gICAqL1xuICAjcmVtb3ZlSGFuZGxlZEVycm9yKGRyaXZlckVycm9ySW5kZXg6IG51bWJlciwgZHJpdmVyRXJyb3JzOiBMdW1iZXJqYWNrTG9nRHJpdmVyRXJyb3I8VFBheWxvYWQ+W10pIHtcbiAgICBkcml2ZXJFcnJvcnMuc3BsaWNlKGRyaXZlckVycm9ySW5kZXgsIDEpO1xuICB9XG59XG4iXX0=