UNPKG

27.2 kBJavaScriptView Raw
1"use strict";
2/*---------------------------------------------------------
3 * Copyright (C) Microsoft Corporation. All rights reserved.
4 *--------------------------------------------------------*/
5var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
6 return new (P || (P = Promise))(function (resolve, reject) {
7 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
8 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
9 function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
10 step((generator = generator.apply(thisArg, _arguments || [])).next());
11 });
12};
13Object.defineProperty(exports, "__esModule", { value: true });
14const fs = require("fs");
15const path = require("path");
16const mkdirp = require("mkdirp");
17const debugSession_1 = require("./debugSession");
18var LogLevel;
19(function (LogLevel) {
20 LogLevel[LogLevel["Verbose"] = 0] = "Verbose";
21 LogLevel[LogLevel["Log"] = 1] = "Log";
22 LogLevel[LogLevel["Warn"] = 2] = "Warn";
23 LogLevel[LogLevel["Error"] = 3] = "Error";
24 LogLevel[LogLevel["Stop"] = 4] = "Stop";
25})(LogLevel = exports.LogLevel || (exports.LogLevel = {}));
26class Logger {
27 constructor() {
28 this._pendingLogQ = [];
29 }
30 log(msg, level = LogLevel.Log) {
31 msg = msg + '\n';
32 this._write(msg, level);
33 }
34 verbose(msg) {
35 this.log(msg, LogLevel.Verbose);
36 }
37 warn(msg) {
38 this.log(msg, LogLevel.Warn);
39 }
40 error(msg) {
41 this.log(msg, LogLevel.Error);
42 }
43 dispose() {
44 if (this._currentLogger) {
45 const disposeP = this._currentLogger.dispose();
46 this._currentLogger = null;
47 return disposeP;
48 }
49 else {
50 return Promise.resolve();
51 }
52 }
53 /**
54 * `log` adds a newline, `write` doesn't
55 */
56 _write(msg, level = LogLevel.Log) {
57 // [null, undefined] => string
58 msg = msg + '';
59 if (this._pendingLogQ) {
60 this._pendingLogQ.push({ msg, level });
61 }
62 else if (this._currentLogger) {
63 this._currentLogger.log(msg, level);
64 }
65 }
66 /**
67 * Set the logger's minimum level to log in the console, and whether to log to the file. Log messages are queued before this is
68 * called the first time, because minLogLevel defaults to Warn.
69 */
70 setup(consoleMinLogLevel, _logFilePath) {
71 const logFilePath = typeof _logFilePath === 'string' ?
72 _logFilePath :
73 (_logFilePath && this._logFilePathFromInit);
74 if (this._currentLogger) {
75 this._currentLogger.setup(consoleMinLogLevel, logFilePath).then(() => {
76 // Now that we have a minimum logLevel, we can clear out the queue of pending messages
77 if (this._pendingLogQ) {
78 const logQ = this._pendingLogQ;
79 this._pendingLogQ = null;
80 logQ.forEach(item => this._write(item.msg, item.level));
81 }
82 });
83 }
84 }
85 init(logCallback, logFilePath, logToConsole) {
86 // Re-init, create new global Logger
87 this._pendingLogQ = this._pendingLogQ || [];
88 this._currentLogger = new InternalLogger(logCallback, logToConsole);
89 this._logFilePathFromInit = logFilePath;
90 // Log the date at the top
91 const d = new Date();
92 const timestamp = d.toLocaleTimeString() + ', ' + d.toLocaleDateString();
93 this.verbose(timestamp);
94 }
95}
96exports.Logger = Logger;
97exports.logger = new Logger();
98/**
99 * Manages logging, whether to console.log, file, or VS Code console.
100 * Encapsulates the state specific to each logging session
101 */
102class InternalLogger {
103 constructor(logCallback, isServer) {
104 /** Dispose and allow exit to continue normally */
105 this.beforeExitCallback = () => this.dispose();
106 this._logCallback = logCallback;
107 this._logToConsole = isServer;
108 this._minLogLevel = LogLevel.Warn;
109 this.disposeCallback = (signal, code) => {
110 this.dispose();
111 // Exit with 128 + value of the signal code.
112 // https://nodejs.org/api/process.html#process_exit_codes
113 code = code || 2; // SIGINT
114 code += 128;
115 process.exit(code);
116 };
117 }
118 setup(consoleMinLogLevel, logFilePath) {
119 return __awaiter(this, void 0, void 0, function* () {
120 this._minLogLevel = consoleMinLogLevel;
121 // Open a log file in the specified location. Overwritten on each run.
122 if (logFilePath) {
123 if (!path.isAbsolute(logFilePath)) {
124 this.log(`logFilePath must be an absolute path: ${logFilePath}`, LogLevel.Error);
125 }
126 else {
127 const handleError = err => this.sendLog(`Error creating log file at path: ${logFilePath}. Error: ${err.toString()}\n`, LogLevel.Error);
128 try {
129 yield mkdirpPromise(path.dirname(logFilePath));
130 this.log(`Verbose logs are written to:\n`, LogLevel.Warn);
131 this.log(logFilePath + '\n', LogLevel.Warn);
132 this._logFileStream = fs.createWriteStream(logFilePath);
133 this.setupShutdownListeners();
134 this._logFileStream.on('error', err => {
135 handleError(err);
136 });
137 }
138 catch (err) {
139 handleError(err);
140 }
141 }
142 }
143 });
144 }
145 setupShutdownListeners() {
146 process.addListener('beforeExit', this.beforeExitCallback);
147 process.addListener('SIGTERM', this.disposeCallback);
148 process.addListener('SIGINT', this.disposeCallback);
149 }
150 removeShutdownListeners() {
151 process.removeListener('beforeExit', this.beforeExitCallback);
152 process.removeListener('SIGTERM', this.disposeCallback);
153 process.removeListener('SIGINT', this.disposeCallback);
154 }
155 dispose() {
156 return new Promise(resolve => {
157 this.removeShutdownListeners();
158 if (this._logFileStream) {
159 this._logFileStream.end(resolve);
160 this._logFileStream = null;
161 }
162 else {
163 resolve();
164 }
165 });
166 }
167 log(msg, level) {
168 if (this._minLogLevel === LogLevel.Stop) {
169 return;
170 }
171 if (level >= this._minLogLevel) {
172 this.sendLog(msg, level);
173 }
174 if (this._logToConsole) {
175 const logFn = level === LogLevel.Error ? console.error :
176 level === LogLevel.Warn ? console.warn :
177 null;
178 if (logFn) {
179 logFn(trimLastNewline(msg));
180 }
181 }
182 // If an error, prepend with '[Error]'
183 if (level === LogLevel.Error) {
184 msg = `[${LogLevel[level]}] ${msg}`;
185 }
186 if (this._logFileStream) {
187 this._logFileStream.write(msg);
188 }
189 }
190 sendLog(msg, level) {
191 // Truncate long messages, they can hang VS Code
192 if (msg.length > 1500) {
193 const endsInNewline = !!msg.match(/(\n|\r\n)$/);
194 msg = msg.substr(0, 1500) + '[...]';
195 if (endsInNewline) {
196 msg = msg + '\n';
197 }
198 }
199 if (this._logCallback) {
200 const event = new LogOutputEvent(msg, level);
201 this._logCallback(event);
202 }
203 }
204}
205function mkdirpPromise(folder) {
206 return new Promise((resolve, reject) => {
207 mkdirp(folder, err => {
208 if (err) {
209 reject(err);
210 }
211 else {
212 resolve();
213 }
214 });
215 });
216}
217class LogOutputEvent extends debugSession_1.OutputEvent {
218 constructor(msg, level) {
219 const category = level === LogLevel.Error ? 'stderr' :
220 level === LogLevel.Warn ? 'console' :
221 'stdout';
222 super(msg, category);
223 }
224}
225exports.LogOutputEvent = LogOutputEvent;
226function trimLastNewline(str) {
227 return str.replace(/(\n|\r\n)$/, '');
228}
229exports.trimLastNewline = trimLastNewline;
230//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9nZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2xvZ2dlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7OzREQUU0RDs7Ozs7Ozs7OztBQUU1RCx5QkFBeUI7QUFDekIsNkJBQTZCO0FBQzdCLGlDQUFpQztBQUNqQyxpREFBMkM7QUFFM0MsSUFBWSxRQU1YO0FBTkQsV0FBWSxRQUFRO0lBQ25CLDZDQUFXLENBQUE7SUFDWCxxQ0FBTyxDQUFBO0lBQ1AsdUNBQVEsQ0FBQTtJQUNSLHlDQUFTLENBQUE7SUFDVCx1Q0FBUSxDQUFBO0FBQ1QsQ0FBQyxFQU5XLFFBQVEsR0FBUixnQkFBUSxLQUFSLGdCQUFRLFFBTW5CO0FBZ0JEO0lBQUE7UUFJUyxpQkFBWSxHQUFlLEVBQUUsQ0FBQztJQTJFdkMsQ0FBQztJQXpFQSxHQUFHLENBQUMsR0FBVyxFQUFFLEtBQUssR0FBRyxRQUFRLENBQUMsR0FBRztRQUNwQyxHQUFHLEdBQUcsR0FBRyxHQUFHLElBQUksQ0FBQztRQUNqQixJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUN6QixDQUFDO0lBRUQsT0FBTyxDQUFDLEdBQVc7UUFDbEIsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ2pDLENBQUM7SUFFRCxJQUFJLENBQUMsR0FBVztRQUNmLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUM5QixDQUFDO0lBRUQsS0FBSyxDQUFDLEdBQVc7UUFDaEIsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQy9CLENBQUM7SUFFRCxPQUFPO1FBQ04sSUFBSSxJQUFJLENBQUMsY0FBYyxFQUFFO1lBQ3hCLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsT0FBTyxFQUFF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RyxJQUFJLENBQUM7YUFDakI7U0FDRDtRQUVELElBQUksSUFBSSxDQUFDLFlBQVksRUFBRTtZQUN0QixNQUFNLEtBQUssR0FBRyxJQUFJLGNBQWMsQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDN0MsSUFBSSxDQUFDLFlBQVksQ0FBQyxLQUFLLENBQUMsQ0FBQztTQUN6QjtJQUNGLENBQUM7Q0FDRDtBQUVELHVCQUF1QixNQUFjO0lBQ3BDLE9BQU8sSUFBSSxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUU7UUFDdEMsTUFBTSxDQUFDLE1BQU0sRUFBRSxHQUFHLENBQUMsRUFBRTtZQUNwQixJQUFJLEdBQUcsRUFBRTtnQkFDUixNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7YUFDWjtpQkFBTTtnQkFDTixPQUFPLEVBQUUsQ0FBQzthQUNWO1FBQ0YsQ0FBQyxDQUFDLENBQUM7SUFDSixDQUFDLENBQUMsQ0FBQztBQUNKLENBQUM7QUFFRCxvQkFBNEIsU0FBUSwwQkFBVztJQUM5QyxZQUFZLEdBQVcsRUFBRSxLQUFlO1FBQ3ZDLE1BQU0sUUFBUSxHQUNiLEtBQUssS0FBSyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUNyQyxLQUFLLEtBQUssUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUM7Z0JBQ3JDLFFBQVEsQ0FBQztRQUNWLEtBQUssQ0FBQyxHQUFHLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDdEIsQ0FBQztDQUNEO0FBUkQsd0NBUUM7QUFFRCx5QkFBZ0MsR0FBVztJQUMxQyxPQUFPLEdBQUcsQ0FBQyxPQUFPLENBQUMsWUFBWSxFQUFFLEVBQUUsQ0FBQyxDQUFDO0FBQ3RDLENBQUM7QUFGRCwwQ0FFQyIsInNvdXJjZXNDb250ZW50IjpbIi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiBDb3B5cmlnaHQgKEMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuXG5pbXBvcnQgKiBhcyBmcyBmcm9tICdmcyc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0ICogYXMgbWtkaXJwIGZyb20gJ21rZGlycCc7XG5pbXBvcnQge091dHB1dEV2ZW50fSBmcm9tICcuL2RlYnVnU2Vzc2lvbic7XG5cbmV4cG9ydCBlbnVtIExvZ0xldmVsIHtcblx0VmVyYm9zZSA9IDAsXG5cdExvZyA9IDEsXG5cdFdhcm4gPSAyLFxuXHRFcnJvciA9IDMsXG5cdFN0b3AgPSA0XG59XG5cbmV4cG9ydCB0eXBlIElMb2dDYWxsYmFjayA9IChvdXRwdXRFdmVudDogT3V0cHV0RXZlbnQpID0+IHZvaWQ7XG5cbmludGVyZmFjZSBJTG9nSXRlbSB7XG5cdG1zZzogc3RyaW5nO1xuXHRsZXZlbDogTG9nTGV2ZWw7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSUxvZ2dlciB7XG5cdGxvZyhtc2c6IHN0cmluZywgbGV2ZWw/OiBMb2dMZXZlbCk6IHZvaWQ7XG5cdHZlcmJvc2UobXNnOiBzdHJpbmcpOiB2b2lkO1xuXHR3YXJuKG1zZzogc3RyaW5nKTogdm9pZDtcblx0ZXJyb3IobXNnOiBzdHJpbmcpOiB2b2lkO1xufVxuXG5leHBvcnQgY2xhc3MgTG9nZ2VyIHtcblx0cHJpdmF0ZSBfbG9nRmlsZVBhdGhGcm9tSW5pdDogc3RyaW5nO1xuXG5cdHByaXZhdGUgX2N1cnJlbnRMb2dnZXI6IEludGVybmFsTG9nZ2VyO1xuXHRwcml2YXRlIF9wZW5kaW5nTG9nUTogSUxvZ0l0ZW1bXSA9IFtdO1xuXG5cdGxvZyhtc2c6IHN0cmluZywgbGV2ZWwgPSBMb2dMZXZlbC5Mb2cpOiB2b2lkIHtcblx0XHRtc2cgPSBtc2cgKyAnXFxuJztcblx0XHR0aGlzLl93cml0ZShtc2csIGxldmVsKTtcblx0fVxuXG5cdHZlcmJvc2UobXNnOiBzdHJpbmcpOiB2b2lkIHtcblx0XHR0aGlzLmxvZyhtc2csIExvZ0xldmVsLlZlcmJvc2UpO1xuXHR9XG5cblx0d2Fybihtc2c6IHN0cmluZyk6IHZvaWQge1xuXHRcdHRoaXMubG9nKG1zZywgTG9nTGV2ZWwuV2Fybik7XG5cdH1cblxuXHRlcnJvcihtc2c6IHN0cmluZyk6IHZvaWQge1xuXHRcdHRoaXMubG9nKG1zZywgTG9nTGV2ZWwuRXJyb3IpO1xuXHR9XG5cblx0ZGlzcG9zZSgpOiBQcm9taXNlPHZvaWQ+IHtcblx0XHRpZiAodGhpcy5fY3VycmVudExvZ2dlcikge1xuXHRcdFx0Y29uc3QgZGlzcG9zZVAgPSB0aGlzLl9jdXJyZW50TG9nZ2VyLmRpc3Bvc2UoKTtcblx0XHRcdHRoaXMuX2N1cnJlbnRMb2dnZXIgPSBudWxsO1xuXHRcdFx0cmV0dXJuIGRpc3Bvc2VQO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRyZXR1cm4gUHJvbWlzZS5yZXNvbHZlKCk7XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIGBsb2dgIGFkZHMgYSBuZXdsaW5lLCBgd3JpdGVgIGRvZXNuJ3Rcblx0ICovXG5cdHByaXZhdGUgX3dyaXRlKG1zZzogc3RyaW5nLCBsZXZlbCA9IExvZ0xldmVsLkxvZyk6IHZvaWQge1xuXHRcdC8vIFtudWxsLCB1bmRlZmluZWRdID0+IHN0cmluZ1xuXHRcdG1zZyA9IG1zZyArICcnO1xuXHRcdGlmICh0aGlzLl9wZW5kaW5nTG9nUSkge1xuXHRcdFx0dGhpcy5fcGVuZGluZ0xvZ1EucHVzaCh7IG1zZywgbGV2ZWwgfSk7XG5cdFx0fSBlbHNlIGlmICh0aGlzLl9jdXJyZW50TG9nZ2VyKSB7XG5cdFx0XHR0aGlzLl9jdXJyZW50TG9nZ2VyLmxvZyhtc2csIGxldmVsKTtcblx0XHR9XG5cdH1cblxuXHQvKipcblx0ICogU2V0IHRoZSBsb2dnZXIncyBtaW5pbXVtIGxldmVsIHRvIGxvZyBpbiB0aGUgY29uc29sZSwgYW5kIHdoZXRoZXIgdG8gbG9nIHRvIHRoZSBmaWxlLiBMb2cgbWVzc2FnZXMgYXJlIHF1ZXVlZCBiZWZvcmUgdGhpcyBpc1xuXHQgKiBjYWxsZWQgdGhlIGZpcnN0IHRpbWUsIGJlY2F1c2UgbWluTG9nTGV2ZWwgZGVmYXVsdHMgdG8gV2Fybi5cblx0ICovXG5cdHNldHVwKGNvbnNvbGVNaW5Mb2dMZXZlbDogTG9nTGV2ZWwsIF9sb2dGaWxlUGF0aD86IHN0cmluZ3xib29sZWFuKTogdm9pZCB7XG5cdFx0Y29uc3QgbG9nRmlsZVBhdGggPSB0eXBlb2YgX2xvZ0ZpbGVQYXRoID09PSAnc3RyaW5nJyA/XG5cdFx0XHRfbG9nRmlsZVBhdGggOlxuXHRcdFx0KF9sb2dGaWxlUGF0aCAmJiB0aGlzLl9sb2dGaWxlUGF0aEZyb21Jbml0KTtcblxuXHRcdGlmICh0aGlzLl9jdXJyZW50TG9nZ2VyKSB7XG5cdFx0XHR0aGlzLl9jdXJyZW50TG9nZ2VyLnNldHVwKGNvbnNvbGVNaW5Mb2dMZXZlbCwgbG9nRmlsZVBhdGgpLnRoZW4oKCkgPT4ge1xuXHRcdFx0XHQvLyBOb3cgdGhhdCB3ZSBoYXZlIGEgbWluaW11bSBsb2dMZXZlbCwgd2UgY2FuIGNsZWFyIG91dCB0aGUgcXVldWUgb2YgcGVuZGluZyBtZXNzYWdlc1xuXHRcdFx0XHRpZiAodGhpcy5fcGVuZGluZ0xvZ1EpIHtcblx0XHRcdFx0XHRjb25zdCBsb2dRID0gdGhpcy5fcGVuZGluZ0xvZ1E7XG5cdFx0XHRcdFx0dGhpcy5fcGVuZGluZ0xvZ1EgPSBudWxsO1xuXHRcdFx0XHRcdGxvZ1EuZm9yRWFjaChpdGVtID0+IHRoaXMuX3dyaXRlKGl0ZW0ubXNnLCBpdGVtLmxldmVsKSk7XG5cdFx0XHRcdH1cblx0XHRcdH0pO1xuXG5cdFx0fVxuXHR9XG5cblx0aW5pdChsb2dDYWxsYmFjazogSUxvZ0NhbGxiYWNrLCBsb2dGaWxlUGF0aD86IHN0cmluZywgbG9nVG9Db25zb2xlPzogYm9vbGVhbik6IHZvaWQge1xuXHRcdC8vIFJlLWluaXQsIGNyZWF0ZSBuZXcgZ2xvYmFsIExvZ2dlclxuXHRcdHRoaXMuX3BlbmRpbmdMb2dRID0gdGhpcy5fcGVuZGluZ0xvZ1EgfHwgW107XG5cdFx0dGhpcy5fY3VycmVudExvZ2dlciA9IG5ldyBJbnRlcm5hbExvZ2dlcihsb2dDYWxsYmFjaywgbG9nVG9Db25zb2xlKTtcblx0XHR0aGlzLl9sb2dGaWxlUGF0aEZyb21Jbml0ID0gbG9nRmlsZVBhdGg7XG5cblx0XHQvLyBMb2cgdGhlIGRhdGUgYXQgdGhlIHRvcFxuXHRcdGNvbnN0IGQgPSBuZXcgRGF0ZSgpO1xuXHRcdGNvbnN0IHRpbWVzdGFtcCA9IGQudG9Mb2NhbGVUaW1lU3RyaW5nKCkgKyAnLCAnICsgZC50b0xvY2FsZURhdGVTdHJpbmcoKTtcblx0XHR0aGlzLnZlcmJvc2UodGltZXN0YW1wKTtcblx0fVxufVxuXG5leHBvcnQgY29uc3QgbG9nZ2VyID0gbmV3IExvZ2dlcigpO1xuXG4vKipcbiAqIE1hbmFnZXMgbG9nZ2luZywgd2hldGhlciB0byBjb25zb2xlLmxvZywgZmlsZSwgb3IgVlMgQ29kZSBjb25zb2xlLlxuICogRW5jYXBzdWxhdGVzIHRoZSBzdGF0ZSBzcGVjaWZpYyB0byBlYWNoIGxvZ2dpbmcgc2Vzc2lvblxuICovXG5jbGFzcyBJbnRlcm5hbExvZ2dlciB7XG5cdHByaXZhdGUgX21pbkxvZ0xldmVsOiBMb2dMZXZlbDtcblx0cHJpdmF0ZSBfbG9nVG9Db25zb2xlOiBib29sZWFuO1xuXG5cdC8qKiBMb2cgaW5mbyB0aGF0IG1lZXRzIG1pbkxvZ0xldmVsIGlzIHNlbnQgdG8gdGhpcyBjYWxsYmFjay4gKi9cblx0cHJpdmF0ZSBfbG9nQ2FsbGJhY2s6IElMb2dDYWxsYmFjaztcblxuXHQvKiogV3JpdGUgc3RlYW0gZm9yIGxvZyBmaWxlICovXG5cdHByaXZhdGUgX2xvZ0ZpbGVTdHJlYW06IGZzLldyaXRlU3RyZWFtO1xuXG5cdC8qKiBEaXNwb3NlIGFuZCBhbGxvdyBleGl0IHRvIGNvbnRpbnVlIG5vcm1hbGx5ICovXG5cdHByaXZhdGUgYmVmb3JlRXhpdENhbGxiYWNrID0gKCkgPT4gdGhpcy5kaXNwb3NlKCk7XG5cblx0LyoqIERpc3Bvc2UgYW5kIGV4aXQgKi9cblx0cHJpdmF0ZSBkaXNwb3NlQ2FsbGJhY2s7XG5cblx0Y29uc3RydWN0b3IobG9nQ2FsbGJhY2s6IElMb2dDYWxsYmFjaywgaXNTZXJ2ZXI/OiBib29sZWFuKSB7XG5cdFx0dGhpcy5fbG9nQ2FsbGJhY2sgPSBsb2dDYWxsYmFjaztcblx0XHR0aGlzLl9sb2dUb0NvbnNvbGUgPSBpc1NlcnZlcjtcblxuXHRcdHRoaXMuX21pbkxvZ0xldmVsID0gTG9nTGV2ZWwuV2FybjtcblxuXHRcdHRoaXMuZGlzcG9zZUNhbGxiYWNrID0gKHNpZ25hbDogc3RyaW5nLCBjb2RlOiBudW1iZXIpID0+IHtcblx0XHRcdHRoaXMuZGlzcG9zZSgpO1xuXG5cdFx0XHQvLyBFeGl0IHdpdGggMTI4ICsgdmFsdWUgb2YgdGhlIHNpZ25hbCBjb2RlLlxuXHRcdFx0Ly8gaHR0cHM6Ly9ub2RlanMub3JnL2FwaS9wcm9jZXNzLmh0bWwjcHJvY2Vzc19leGl0X2NvZGVzXG5cdFx0XHRjb2RlID0gY29kZSB8fCAyOyAvLyBTSUdJTlRcblx0XHRcdGNvZGUgKz0gMTI4O1xuXG5cdFx0XHRwcm9jZXNzLmV4aXQoY29kZSk7XG5cdFx0fTtcblx0fVxuXG5cdHB1YmxpYyBhc3luYyBzZXR1cChjb25zb2xlTWluTG9nTGV2ZWw6IExvZ0xldmVsLCBsb2dGaWxlUGF0aD86IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuXHRcdHRoaXMuX21pbkxvZ0xldmVsID0gY29uc29sZU1pbkxvZ0xldmVsO1xuXG5cdFx0Ly8gT3BlbiBhIGxvZyBmaWxlIGluIHRoZSBzcGVjaWZpZWQgbG9jYXRpb24uIE92ZXJ3cml0dGVuIG9uIGVhY2ggcnVuLlxuXHRcdGlmIChsb2dGaWxlUGF0aCkge1xuXHRcdFx0aWYgKCFwYXRoLmlzQWJzb2x1dGUobG9nRmlsZVBhdGgpKSB7XG5cdFx0XHRcdHRoaXMubG9nKGBsb2dGaWxlUGF0aCBtdXN0IGJlIGFuIGFic29sdXRlIHBhdGg6ICR7bG9nRmlsZVBhdGh9YCwgTG9nTGV2ZWwuRXJyb3IpO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0Y29uc3QgaGFuZGxlRXJyb3IgPSBlcnIgPT4gdGhpcy5zZW5kTG9nKGBFcnJvciBjcmVhdGluZyBsb2cgZmlsZSBhdCBwYXRoOiAke2xvZ0ZpbGVQYXRofS4gRXJyb3I6ICR7ZXJyLnRvU3RyaW5nKCl9XFxuYCwgTG9nTGV2ZWwuRXJyb3IpO1xuXG5cdFx0XHRcdHRyeSB7XG5cdFx0XHRcdFx0YXdhaXQgbWtkaXJwUHJvbWlzZShwYXRoLmRpcm5hbWUobG9nRmlsZVBhdGgpKTtcblx0XHRcdFx0XHR0aGlzLmxvZyhgVmVyYm9zZSBsb2dzIGFyZSB3cml0dGVuIHRvOlxcbmAsIExvZ0xldmVsLldhcm4pO1xuXHRcdFx0XHRcdHRoaXMubG9nKGxvZ0ZpbGVQYXRoICsgJ1xcbicsIExvZ0xldmVsLldhcm4pO1xuXG5cdFx0XHRcdFx0dGhpcy5fbG9nRmlsZVN0cmVhbSA9IGZzLmNyZWF0ZVdyaXRlU3RyZWFtKGxvZ0ZpbGVQYXRoKTtcblx0XHRcdFx0XHR0aGlzLnNldHVwU2h1dGRvd25MaXN0ZW5lcnMoKTtcblx0XHRcdFx0XHR0aGlzLl9sb2dGaWxlU3RyZWFtLm9uKCdlcnJvcicsIGVyciA9PiB7XG5cdFx0XHRcdFx0XHRoYW5kbGVFcnJvcihlcnIpO1xuXHRcdFx0XHRcdH0pO1xuXHRcdFx0XHR9IGNhdGNoIChlcnIpIHtcblx0XHRcdFx0XHRoYW5kbGVFcnJvcihlcnIpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0cHJpdmF0ZSBzZXR1cFNodXRkb3duTGlzdGVuZXJzKCk6IHZvaWQge1xuXHRcdHByb2Nlc3MuYWRkTGlzdGVuZXIoJ2JlZm9yZUV4aXQnLCB0aGlzLmJlZm9yZUV4aXRDYWxsYmFjayk7XG5cdFx0cHJvY2Vzcy5hZGRMaXN0ZW5lcignU0lHVEVSTScsIHRoaXMuZGlzcG9zZUNhbGxiYWNrKTtcblx0XHRwcm9jZXNzLmFkZExpc3RlbmVyKCdTSUdJTlQnLCB0aGlzLmRpc3Bvc2VDYWxsYmFjayk7XG5cdH1cblxuXHRwcml2YXRlIHJlbW92ZVNodXRkb3duTGlzdGVuZXJzKCk6IHZvaWQge1xuXHRcdHByb2Nlc3MucmVtb3ZlTGlzdGVuZXIoJ2JlZm9yZUV4aXQnLCB0aGlzLmJlZm9yZUV4aXRDYWxsYmFjayk7XG5cdFx0cHJvY2Vzcy5yZW1vdmVMaXN0ZW5lcignU0lHVEVSTScsIHRoaXMuZGlzcG9zZUNhbGxiYWNrKTtcblx0XHRwcm9jZXNzLnJlbW92ZUxpc3RlbmVyKCdTSUdJTlQnLCB0aGlzLmRpc3Bvc2VDYWxsYmFjayk7XG5cdH1cblxuXHRwdWJsaWMgZGlzcG9zZSgpOiBQcm9taXNlPHZvaWQ+IHtcblx0XHRyZXR1cm4gbmV3IFByb21pc2UocmVzb2x2ZSA9PiB7XG5cdFx0XHR0aGlzLnJlbW92ZVNodXRkb3duTGlzdGVuZXJzKCk7XG5cdFx0XHRpZiAodGhpcy5fbG9nRmlsZVN0cmVhbSkge1xuXHRcdFx0XHR0aGlzLl9sb2dGaWxlU3RyZWFtLmVuZChyZXNvbHZlKTtcblx0XHRcdFx0dGhpcy5fbG9nRmlsZVN0cmVhbSA9IG51bGw7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRyZXNvbHZlKCk7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdH1cblxuXHRwdWJsaWMgbG9nKG1zZzogc3RyaW5nLCBsZXZlbDogTG9nTGV2ZWwpOiB2b2lkIHtcblx0XHRpZiAodGhpcy5fbWluTG9nTGV2ZWwgPT09IExvZ0xldmVsLlN0b3ApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRpZiAobGV2ZWwgPj0gdGhpcy5fbWluTG9nTGV2ZWwpIHtcblx0XHRcdHRoaXMuc2VuZExvZyhtc2csIGxldmVsKTtcblx0XHR9XG5cblx0XHRpZiAodGhpcy5fbG9nVG9Db25zb2xlKSB7XG5cdFx0XHRjb25zdCBsb2dGbiA9XG5cdFx0XHRcdGxldmVsID09PSBMb2dMZXZlbC5FcnJvciA/IGNvbnNvbGUuZXJyb3IgOlxuXHRcdFx0XHRsZXZlbCA9PT0gTG9nTGV2ZWwuV2FybiA/IGNvbnNvbGUud2FybiA6XG5cdFx0XHRcdG51bGw7XG5cblx0XHRcdGlmIChsb2dGbikge1xuXHRcdFx0XHRsb2dGbih0cmltTGFzdE5ld2xpbmUobXNnKSk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gSWYgYW4gZXJyb3IsIHByZXBlbmQgd2l0aCAnW0Vycm9yXSdcblx0XHRpZiAobGV2ZWwgPT09IExvZ0xldmVsLkVycm9yKSB7XG5cdFx0XHRtc2cgPSBgWyR7TG9nTGV2ZWxbbGV2ZWxdfV0gJHttc2d9YDtcblx0XHR9XG5cblx0XHRpZiAodGhpcy5fbG9nRmlsZVN0cmVhbSkge1xuXHRcdFx0dGhpcy5fbG9nRmlsZVN0cmVhbS53cml0ZShtc2cpO1xuXHRcdH1cblx0fVxuXG5cdHByaXZhdGUgc2VuZExvZyhtc2c6IHN0cmluZywgbGV2ZWw6IExvZ0xldmVsKTogdm9pZCB7XG5cdFx0Ly8gVHJ1bmNhdGUgbG9uZyBtZXNzYWdlcywgdGhleSBjYW4gaGFuZyBWUyBDb2RlXG5cdFx0aWYgKG1zZy5sZW5ndGggPiAxNTAwKSB7XG5cdFx0XHRjb25zdCBlbmRzSW5OZXdsaW5lID0gISFtc2cubWF0Y2goLyhcXG58XFxyXFxuKSQvKTtcblx0XHRcdG1zZyA9IG1zZy5zdWJzdHIoMCwgMTUwMCkgKyAnWy4uLl0nO1xuXHRcdFx0aWYgKGVuZHNJbk5ld2xpbmUpIHtcblx0XHRcdFx0bXNnID0gbXNnICsgJ1xcbic7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWYgKHRoaXMuX2xvZ0NhbGxiYWNrKSB7XG5cdFx0XHRjb25zdCBldmVudCA9IG5ldyBMb2dPdXRwdXRFdmVudChtc2csIGxldmVsKTtcblx0XHRcdHRoaXMuX2xvZ0NhbGxiYWNrKGV2ZW50KTtcblx0XHR9XG5cdH1cbn1cblxuZnVuY3Rpb24gbWtkaXJwUHJvbWlzZShmb2xkZXI6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuXHRyZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuXHRcdG1rZGlycChmb2xkZXIsIGVyciA9PiB7XG5cdFx0XHRpZiAoZXJyKSB7XG5cdFx0XHRcdHJlamVjdChlcnIpO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0cmVzb2x2ZSgpO1xuXHRcdFx0fVxuXHRcdH0pO1xuXHR9KTtcbn1cblxuZXhwb3J0IGNsYXNzIExvZ091dHB1dEV2ZW50IGV4dGVuZHMgT3V0cHV0RXZlbnQge1xuXHRjb25zdHJ1Y3Rvcihtc2c6IHN0cmluZywgbGV2ZWw6IExvZ0xldmVsKSB7XG5cdFx0Y29uc3QgY2F0ZWdvcnkgPVxuXHRcdFx0bGV2ZWwgPT09IExvZ0xldmVsLkVycm9yID8gJ3N0ZGVycicgOlxuXHRcdFx0bGV2ZWwgPT09IExvZ0xldmVsLldhcm4gPyAnY29uc29sZScgOlxuXHRcdFx0J3N0ZG91dCc7XG5cdFx0c3VwZXIobXNnLCBjYXRlZ29yeSk7XG5cdH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHRyaW1MYXN0TmV3bGluZShzdHI6IHN0cmluZyk6IHN0cmluZyB7XG5cdHJldHVybiBzdHIucmVwbGFjZSgvKFxcbnxcXHJcXG4pJC8sICcnKTtcbn1cbiJdfQ==
\No newline at end of file