1 | ;
|
2 | /*---------------------------------------------------------
|
3 | * Copyright (C) Microsoft Corporation. All rights reserved.
|
4 | *--------------------------------------------------------*/
|
5 | var __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 | };
|
13 | Object.defineProperty(exports, "__esModule", { value: true });
|
14 | const fs = require("fs");
|
15 | const path = require("path");
|
16 | const mkdirp = require("mkdirp");
|
17 | const debugSession_1 = require("./debugSession");
|
18 | var 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 = {}));
|
26 | class 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 | }
|
96 | exports.Logger = Logger;
|
97 | exports.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 | */
|
102 | class 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 | }
|
205 | function 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 | }
|
217 | class 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 | }
|
225 | exports.LogOutputEvent = LogOutputEvent;
|
226 | function trimLastNewline(str) {
|
227 | return str.replace(/(\n|\r\n)$/, '');
|
228 | }
|
229 | exports.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 |