UNPKG

56.1 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.Wrapper = exports.WrapperOptionDefaults = exports.createErrorResponse = exports.filename = exports.isGenerator = void 0;
4const childProcess = require("child_process");
5const process = require("process");
6const proctor = require("process-doctor");
7const util_1 = require("util");
8const serialize_1 = require("./serialize");
9const throttle_1 = require("./throttle");
10const error_1 = require("./error");
11const p = (val) => util_1.inspect(val, { compact: true, breakLength: Infinity });
12const isGenerator = (fn) => fn instanceof function* () { }.constructor ||
13 fn instanceof async function* () { }.constructor;
14exports.isGenerator = isGenerator;
15exports.filename = module.filename;
16function createErrorResponse(err, { call, startTime, logUrl, executionId }) {
17 return {
18 kind: "promise",
19 type: "reject",
20 value: serialize_1.serializeReturnValue(call.name, err, false),
21 isErrorObject: typeof err === "object" && err instanceof Error,
22 callId: call.callId,
23 remoteExecutionStartTime: startTime,
24 remoteExecutionEndTime: Date.now(),
25 logUrl,
26 executionId
27 };
28}
29exports.createErrorResponse = createErrorResponse;
30exports.WrapperOptionDefaults = {
31 wrapperLog: console.log,
32 childProcess: true,
33 childProcessMemoryLimitMb: 0,
34 childProcessTimeoutMs: 0,
35 childProcessEnvironment: {},
36 childDir: ".",
37 wrapperVerbose: false,
38 validateSerialization: true
39};
40const oomPattern = /Allocation failed - JavaScript heap out of memory/;
41const FAAST_CHILD_ENV = "FAAST_CHILD";
42class Wrapper {
43 constructor(fModule, options = {}) {
44 this.executing = false;
45 this.verbose = false;
46 this.funcs = {};
47 this.logLines = (msg) => {
48 let lines = msg.split("\n");
49 if (lines[lines.length - 1] === "") {
50 lines = lines.slice(0, lines.length - 1);
51 }
52 for (const line of lines) {
53 this.log(`[${this.childPid}]: ${line}`);
54 }
55 };
56 this.options = { ...exports.WrapperOptionDefaults, ...options };
57 this.log = this.options.wrapperLog;
58 this.verbose = this.options.wrapperVerbose;
59 this.funcs = fModule;
60 this.queue = new throttle_1.AsyncIterableQueue();
61 /* istanbul ignore if */
62 if (process.env[FAAST_CHILD_ENV]) {
63 this.options.childProcess = false;
64 this.log(`faast: started child process for module wrapper.`);
65 process.on("message", async (cc) => {
66 const startTime = Date.now();
67 try {
68 await this.execute({ ...cc, startTime }, {
69 onMessage: async (msg) => {
70 this.log(`Received message ${msg.kind}`);
71 process.send({ done: false, value: msg });
72 }
73 });
74 this.log(`Done with this.execute()`);
75 }
76 catch (err) {
77 this.log(err);
78 }
79 finally {
80 process.send({ done: true });
81 }
82 });
83 }
84 else {
85 if (!process.env.FAAST_SILENT) {
86 this.log(`faast: successful cold start.`);
87 }
88 }
89 }
90 lookupFunction(request) {
91 const { name, args } = request;
92 if (!name) {
93 throw new Error("Invalid function call request: no name");
94 }
95 const func = this.funcs[name];
96 if (!func) {
97 throw new Error(`Function named "${name}" not found`);
98 }
99 if (!args) {
100 throw new Error("Invalid arguments to function call");
101 }
102 return func;
103 }
104 stopCpuMonitoring() {
105 this.monitoringTimer && clearInterval(this.monitoringTimer);
106 this.monitoringTimer = undefined;
107 }
108 startCpuMonitoring(pid, callId) {
109 if (this.monitoringTimer) {
110 this.stopCpuMonitoring();
111 }
112 this.monitoringTimer = cpuMonitor(pid, 1000, (err, result) => {
113 if (err) {
114 this.log(`cpu monitor error: ${err}`);
115 }
116 if (result) {
117 this.queue.push({ kind: "cpumetrics", callId, metrics: result });
118 }
119 });
120 }
121 stop() {
122 this.stopCpuMonitoring();
123 if (this.child) {
124 this.log(`Stopping child process.`);
125 this.child.stdout.removeListener("data", this.logLines);
126 this.child.stderr.removeListener("data", this.logLines);
127 this.child.disconnect();
128 this.child.kill();
129 this.child = undefined;
130 this.executing = false;
131 }
132 }
133 async execute(callingContext, { errorCallback, onMessage, measureCpuUsage }) {
134 const processError = (err) => err instanceof Error && errorCallback ? errorCallback(err) : err;
135 try {
136 /* istanbul ignore if */
137 if (this.executing) {
138 this.log(`faast: warning: module wrapper execute is not re-entrant`);
139 throw new Error(`faast: module wrapper is not re-entrant`);
140 }
141 this.executing = true;
142 const { call, startTime, logUrl, executionId, instanceId } = callingContext;
143 const detail = { logUrl, executionId, instanceId };
144 const { callId } = call;
145 this.log(`calling: ${call.name}`);
146 this.log(` args: ${call.args}`);
147 this.log(` callId: ${callId}`);
148 // let startedMessageTimer: NodeJS.Timeout | undefined = setTimeout(
149 // () => messageCallback({ kind: "functionstarted", callId }),
150 // 2 * 1000
151 // );
152 // TODO: Add this code after the execute returns or yields its first value...
153 // if (startedMessageTimer) {
154 // clearTimeout(startedMessageTimer);
155 // startedMessageTimer = undefined;
156 // }
157 const memoryUsage = process.memoryUsage();
158 const memInfo = p(memoryUsage);
159 if (this.options.childProcess) {
160 if (!this.child) {
161 this.child = this.setupChildProcess();
162 }
163 this.verbose &&
164 this.log(`faast: invoking '${call.name}' in child process, memory: ${memInfo}`);
165 this.child.send(callingContext, err => {
166 /* istanbul ignore if */
167 if (err) {
168 this.log(`child send error: rejecting with ${err}`);
169 this.queue.push(Promise.reject(err));
170 }
171 });
172 if (measureCpuUsage) {
173 this.verbose &&
174 this.log(`Starting CPU monitor for pid ${this.child.pid}`);
175 // XXX CPU Monitoring not enabled for now.
176 // this.startCpuMonitoring(this.child.pid, callId);
177 }
178 let timer;
179 const timeout = this.options.childProcessTimeoutMs;
180 if (timeout) {
181 this.verbose && this.log(`Setting timeout: ${timeout}`);
182 timer = setTimeout(() => {
183 const error = new error_1.FaastError({
184 name: error_1.FaastErrorNames.ETIMEOUT,
185 info: { ...detail, functionName: call.name }
186 }, `Request exceeded timeout of ${timeout}ms`);
187 this.queue.push(Promise.reject(error));
188 this.stop();
189 }, timeout);
190 }
191 this.verbose && this.log(`awaiting async dequeue`);
192 try {
193 const promises = [];
194 for await (const result of this.queue) {
195 this.verbose && this.log(`Dequeuing ${p(result)}`);
196 if (result.kind === "promise" || result.kind === "iterator") {
197 result.logUrl = logUrl;
198 }
199 promises.push(onMessage(result));
200 }
201 await Promise.all(promises);
202 }
203 finally {
204 this.verbose && this.log(`Finalizing queue`);
205 this.stopCpuMonitoring();
206 timer && clearTimeout(timer);
207 this.queue.clear();
208 }
209 }
210 else {
211 this.verbose &&
212 this.log(`faast: Invoking '${call.name}', memory: ${memInfo}`);
213 const func = this.lookupFunction(call);
214 if (!func) {
215 throw new Error(`faast module wrapper: could not find function '${call.name}'`);
216 }
217 const args = serialize_1.deserialize(call.args);
218 let value;
219 try {
220 value = await func.apply(undefined, args);
221 this.verbose && this.log(`Finished call function`);
222 }
223 catch (err) {
224 this.log(`Function ${call.name} threw error: ${err}`);
225 throw err;
226 }
227 this.verbose &&
228 this.log(`returned value: ${p(value)}, type: ${typeof value}`);
229 const validate = this.options.validateSerialization;
230 const context = { type: "fulfill", callId, ...detail };
231 // Check for iterable.
232 if (value !== null && value !== undefined) {
233 if (exports.isGenerator(func)) {
234 let next = await value.next();
235 let sequence = 0;
236 while (true) {
237 this.verbose && this.log(`next: ${p(next)}`);
238 let result = {
239 ...context,
240 kind: "iterator",
241 value: serialize_1.serializeReturnValue(call.name, [next], validate),
242 sequence
243 };
244 if (next.done) {
245 result.remoteExecutionStartTime = startTime;
246 result.remoteExecutionEndTime = Date.now();
247 result.memoryUsage = memoryUsage;
248 }
249 await onMessage(result);
250 if (next.done) {
251 return;
252 }
253 sequence++;
254 next = await value.next();
255 }
256 }
257 }
258 await onMessage({
259 ...context,
260 kind: "promise",
261 value: serialize_1.serializeReturnValue(call.name, [value], validate),
262 remoteExecutionStartTime: startTime,
263 remoteExecutionEndTime: Date.now(),
264 memoryUsage
265 });
266 }
267 }
268 catch (err) {
269 this.log(`faast: wrapped function exception or promise rejection: ${err}`);
270 const response = createErrorResponse(processError(err), callingContext);
271 this.log(`Error response: ${util_1.inspect(response)}`);
272 await onMessage(response);
273 }
274 finally {
275 this.verbose && this.log(`Exiting execute`);
276 this.executing = false;
277 }
278 }
279 setupChildProcess() {
280 this.verbose && this.log(`faast: creating child process`);
281 let execArgv = process.execArgv.slice();
282 if (this.options.childProcessMemoryLimitMb) {
283 /* istanbul ignore next */
284 execArgv = process.execArgv.filter(arg => !arg.match(/^--max-old-space-size/) && !arg.match(/^--inspect/));
285 execArgv.push(`--max-old-space-size=${this.options.childProcessMemoryLimitMb}`);
286 }
287 const { childProcessEnvironment } = this.options;
288 const env = {
289 ...process.env,
290 ...childProcessEnvironment,
291 [FAAST_CHILD_ENV]: "true"
292 };
293 this.verbose && this.log(`Env: ${JSON.stringify(env)}`);
294 const forkOptions = {
295 silent: true,
296 env,
297 cwd: this.options.childDir,
298 execArgv
299 };
300 const child = childProcess.fork("./index.js", [], forkOptions);
301 this.childPid = child.pid;
302 child.stdout.setEncoding("utf8");
303 child.stderr.setEncoding("utf8");
304 let oom;
305 const detectOom = (chunk) => {
306 if (oomPattern.test(chunk)) {
307 oom = chunk;
308 }
309 };
310 child.stdout.on("data", this.logLines);
311 child.stderr.on("data", this.logLines);
312 child.stderr.on("data", detectOom);
313 child.on("message", (message) => {
314 this.verbose && this.log(`child message: resolving with ${p(message)}`);
315 if (message.done) {
316 this.queue.done();
317 }
318 else {
319 this.queue.push(message.value);
320 }
321 });
322 /* istanbul ignore next */
323 child.on("error", err => {
324 this.verbose && this.log(`child error: rejecting with ${err}`);
325 this.child = undefined;
326 this.queue.push(Promise.reject(err));
327 });
328 child.on("exit", (code, signal) => {
329 this.verbose && this.log(`child exit: code: ${code}, signal: ${signal}`);
330 this.child = undefined;
331 if (code) {
332 this.queue.push(Promise.reject(new Error(`Exited with error code ${code}`)));
333 }
334 else if (signal !== null && signal !== "SIGTERM") {
335 let errorMessage = `Aborted with signal ${signal}`;
336 if (signal === "SIGABRT" && oom) {
337 errorMessage += ` (${oom})`;
338 oom = undefined;
339 }
340 this.queue.push(Promise.reject(new Error(errorMessage)));
341 }
342 else {
343 this.verbose && this.log(`child exiting normally`);
344 }
345 });
346 return child;
347 }
348}
349exports.Wrapper = Wrapper;
350function cpuMonitor(pid, interval, callback) {
351 const start = Date.now();
352 const timer = setInterval(() => proctor.lookup(pid, (err, result) => {
353 if (err) {
354 callback(err);
355 return;
356 }
357 const { stime, utime } = result;
358 callback(err, result && {
359 stime: stime * 10,
360 utime: utime * 10,
361 elapsed: Date.now() - start
362 });
363 }), interval);
364 return timer;
365}
366//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid3JhcHBlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy93cmFwcGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDhDQUE4QztBQUM5QyxtQ0FBbUM7QUFDbkMsMENBQTBDO0FBQzFDLCtCQUErQjtBQUUvQiwyQ0FBZ0U7QUFDaEUseUNBQWdEO0FBRWhELG1DQUFzRDtBQUV0RCxNQUFNLENBQUMsR0FBRyxDQUFDLEdBQVEsRUFBRSxFQUFFLENBQUMsY0FBTyxDQUFDLEdBQUcsRUFBRSxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsV0FBVyxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7QUFFeEUsTUFBTSxXQUFXLEdBQUcsQ0FBQyxFQUFZLEVBQUUsRUFBRSxDQUN4QyxFQUFFLFlBQVksUUFBUSxDQUFDLE1BQUssQ0FBQyxDQUFDLFdBQVc7SUFDekMsRUFBRSxZQUFZLEtBQUssU0FBUyxDQUFDLE1BQUssQ0FBQyxDQUFDLFdBQVcsQ0FBQztBQUZ2QyxRQUFBLFdBQVcsZUFFNEI7QUFFdkMsUUFBQSxRQUFRLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQztBQWtDeEMsU0FBZ0IsbUJBQW1CLENBQy9CLEdBQVEsRUFDUixFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLFdBQVcsRUFBa0I7SUFFeEQsT0FBTztRQUNILElBQUksRUFBRSxTQUFTO1FBQ2YsSUFBSSxFQUFFLFFBQVE7UUFDZCxLQUFLLEVBQUUsZ0NBQW9CLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxHQUFHLEVBQUUsS0FBSyxDQUFDO1FBQ2xELGFBQWEsRUFBRSxPQUFPLEdBQUcsS0FBSyxRQUFRLElBQUksR0FBRyxZQUFZLEtBQUs7UUFDOUQsTUFBTSxFQUFFLElBQUksQ0FBQyxNQUFNO1FBQ25CLHdCQUF3QixFQUFFLFNBQVM7UUFDbkMsc0JBQXNCLEVBQUUsSUFBSSxDQUFDLEdBQUcsRUFBRTtRQUNsQyxNQUFNO1FBQ04sV0FBVztLQUNk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IFwiY2hpbGRfcHJvY2Vzc1wiO1xuaW1wb3J0ICogYXMgcHJvY2VzcyBmcm9tIFwicHJvY2Vzc1wiO1xuaW1wb3J0ICogYXMgcHJvY3RvciBmcm9tIFwicHJvY2Vzcy1kb2N0b3JcIjtcbmltcG9ydCB7IGluc3BlY3QgfSBmcm9tIFwidXRpbFwiO1xuaW1wb3J0IHsgSXRlcmF0b3JSZXNwb25zZU1lc3NhZ2UsIE1lc3NhZ2UsIFByb21pc2VSZXNwb25zZU1lc3NhZ2UgfSBmcm9tIFwiLi9wcm92aWRlclwiO1xuaW1wb3J0IHsgZGVzZXJpYWxpemUsIHNlcmlhbGl6ZVJldHVyblZhbHVlIH0gZnJvbSBcIi4vc2VyaWFsaXplXCI7XG5pbXBvcnQgeyBBc3luY0l0ZXJhYmxlUXVldWUgfSBmcm9tIFwiLi90aHJvdHRsZVwiO1xuaW1wb3J0IHsgQW55RnVuY3Rpb24gfSBmcm9tIFwiLi90eXBlc1wiO1xuaW1wb3J0IHsgRmFhc3RFcnJvciwgRmFhc3RFcnJvck5hbWVzIH0gZnJvbSBcIi4vZXJyb3JcIjtcblxuY29uc3QgcCA9ICh2YWw6IGFueSkgPT4gaW5zcGVjdCh2YWwsIHsgY29tcGFjdDogdHJ1ZSwgYnJlYWtMZW5ndGg6IEluZmluaXR5IH0pO1xuXG5leHBvcnQgY29uc3QgaXNHZW5lcmF0b3IgPSAoZm46IEZ1bmN0aW9uKSA9PlxuICAgIGZuIGluc3RhbmNlb2YgZnVuY3Rpb24qICgpIHt9LmNvbnN0cnVjdG9yIHx8XG4gICAgZm4gaW5zdGFuY2VvZiBhc3luYyBmdW5jdGlvbiogKCkge30uY29uc3RydWN0b3I7XG5cbmV4cG9ydCBjb25zdCBmaWxlbmFtZSA9IG1vZHVsZS5maWxlbmFtZTtcblxuZXhwb3J0IGludGVyZmFjZSBDYWxsSWQge1xuICAgIGNhbGxJZDogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFRyYW1wb2xpbmUge1xuICAgIHRyYW1wb2xpbmU6IEFueUZ1bmN0aW9uO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFRyYW1wb2xpbmVGYWN0b3J5IHtcbiAgICBmaWxlbmFtZTogc3RyaW5nO1xuICAgIG1ha2VUcmFtcG9saW5lOiAod3JhcHBlcjogV3JhcHBlcikgPT4gVHJhbXBvbGluZTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBGdW5jdGlvbkNhbGwgZXh0ZW5kcyBDYWxsSWQge1xuICAgIGFyZ3M6IHN0cmluZztcbiAgICBtb2R1bGVQYXRoOiBzdHJpbmc7XG4gICAgbmFtZTogc3RyaW5nO1xuICAgIFJlc3BvbnNlUXVldWVJZDogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIENhbGxpbmdDb250ZXh0IHtcbiAgICBjYWxsOiBGdW5jdGlvbkNhbGw7XG4gICAgc3RhcnRUaW1lOiBudW1iZXI7XG4gICAgbG9nVXJsPzogc3RyaW5nO1xuICAgIGV4ZWN1dGlvbklkPzogc3RyaW5nO1xuICAgIGluc3RhbmNlSWQ/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTW9kdWxlVHlwZSB7XG4gICAgW25hbWU6IHN0cmluZ106IGFueTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUVycm9yUmVzcG9uc2UoXG4gICAgZXJyOiBhbnksXG4gICAgeyBjYWxsLCBzdGFydFRpbWUsIGxvZ1VybCwgZXhlY3V0aW9uSWQgfTogQ2FsbGluZ0NvbnRleHRcbik6IFByb21pc2VSZXNwb25zZU1lc3NhZ2Uge1xuICAgIHJldHVybiB7XG4gICAgICAgIGtpbmQ6IFwicHJvbWlzZVwiLFxuICAgICAgICB0eXBlOiBcInJlamVjdFwiLFxuICAgICAgICB2YWx1ZTogc2VyaWFsaXplUmV0dXJuVmFsdWUoY2FsbC5uYW1lLCBlcnIsIGZhbHNlKSxcbiAgICAgICAgaXNFcnJvck9iamVjdDogdHlwZW9mIGVyciA9PT0gXCJvYmplY3RcIiAmJiBlcnIgaW5zdGFuY2VvZiBFcnJvcixcbiAgICAgICAgY2FsbElkOiBjYWxsLmNhbGxJZCxcbiAgICAgICAgcmVtb3RlRXhlY3V0aW9uU3RhcnRUaW1lOiBzdGFydFRpbWUsXG4gICAgICAgIHJlbW90ZUV4ZWN1dGlvbkVuZFRpbWU6IERhdGUubm93KCksXG4gICAgICAgIGxvZ1VybCxcbiAgICAgICAgZXhlY3V0aW9uSWRcbiAgICB9O1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFdyYXBwZXJPcHRpb25zIHtcbiAgICAvKipcbiAgICAgKiBMb2dnaW5nIGZ1bmN0aW9uIGZvciBjb25zb2xlLmxvZy93YXJuL2Vycm9yIG91dHB1dC4gT25seSBhdmFpbGFibGUgaW5cbiAgICAgKiBjaGlsZCBwcm9jZXNzIG1vZGUuIFRoaXMgaXMgbWFpbmx5IHVzZWZ1bCBmb3IgZGVidWdnaW5nIHRoZSBcImxvY2FsXCJcbiAgICAgKiBtb2RlIHdoaWNoIHJ1bnMgY29kZSBsb2NhbGx5LiBJbiByZWFsIGNsb3VkcyB0aGUgbG9ncyB3aWxsIGVuZCB1cCBpbiB0aGVcbiAgICAgKiBjbG91ZCBsb2dnaW5nIHNlcnZpY2UgKGUuZy4gQ2xvdWR3YXRjaCBMb2dzLCBvciBHb29nbGUgU3RhY2tkcml2ZXIgbG9ncykuXG4gICAgICogRGVmYXVsdHMgdG8gY29uc29sZS5sb2cuXG4gICAgICovXG4gICAgd3JhcHBlckxvZz86IChtc2c6IHN0cmluZykgPT4gdm9pZDtcbiAgICBjaGlsZFByb2Nlc3M/OiBib29sZWFuO1xuICAgIGNoaWxkUHJvY2Vzc01lbW9yeUxpbWl0TWI/OiBudW1iZXI7XG4gICAgY2hpbGRQcm9jZXNzVGltZW91dE1zPzogbnVtYmVyO1xuICAgIGNoaWxkUHJvY2Vzc0Vudmlyb25tZW50PzogeyBba2V5OiBzdHJpbmddOiBzdHJpbmcgfTtcbiAgICBjaGlsZERpcj86IHN0cmluZztcbiAgICB3cmFwcGVyVmVyYm9zZT86IGJvb2xlYW47XG4gICAgdmFsaWRhdGVTZXJpYWxpemF0aW9uPzogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGNvbnN0IFdyYXBwZXJPcHRpb25EZWZhdWx0czogUmVxdWlyZWQ8V3JhcHBlck9wdGlvbnM+ID0ge1xuICAgIHdyYXBwZXJMb2c6IGNvbnNvbGUubG9nLFxuICAgIGNoaWxkUHJvY2VzczogdHJ1ZSxcbiAgICBjaGlsZFByb2Nlc3NNZW1vcnlMaW1pdE1iOiAwLFxuICAgIGNoaWxkUHJvY2Vzc1RpbWVvdXRNczogMCxcbiAgICBjaGlsZFByb2Nlc3NFbnZpcm9ubWVudDoge30sXG4gICAgY2hpbGREaXI6IFwiLlwiLFxuICAgIHdyYXBwZXJWZXJib3NlOiBmYWxzZSxcbiAgICB2YWxpZGF0ZVNlcmlhbGl6YXRpb246IHRydWVcbn07XG5cbnR5cGUgRXJyb3JDYWxsYmFjayA9IChlcnI6IEVycm9yKSA9PiBFcnJvcjtcbnR5cGUgTWVzc2FnZUNhbGxiYWNrID0gKG1zZzogTWVzc2FnZSkgPT4gUHJvbWlzZTx2b2lkPjtcblxuZXhwb3J0IGludGVyZmFjZSBXcmFwcGVyRXhlY3V0ZU9wdGlvbnMge1xuICAgIGVycm9yQ2FsbGJhY2s/OiBFcnJvckNhbGxiYWNrO1xuICAgIG9uTWVzc2FnZTogTWVzc2FnZUNhbGxiYWNrO1xuICAgIG1lYXN1cmVDcHVVc2FnZT86IGJvb2xlYW47XG59XG5cbmNvbnN0IG9vbVBhdHRlcm4gPSAvQWxsb2NhdGlvbiBmYWlsZWQgLSBKYXZhU2NyaXB0IGhlYXAgb3V0IG9mIG1lbW9yeS87XG5cbmNvbnN0IEZBQVNUX0NISUxEX0VOViA9IFwiRkFBU1RfQ0hJTERcIjtcblxuZXhwb3J0IGNsYXNzIFdyYXBwZXIge1xuICAgIGV4ZWN1dGluZyA9IGZhbHNlO1xuICAgIHByb3RlY3RlZCB2ZXJib3NlID0gZmFsc2U7XG4gICAgcHJvdGVjdGVkIGZ1bmNzOiBNb2R1bGVUeXBlID0ge307XG4gICAgcHJvdGVjdGVkIGNoaWxkPzogY2hpbGRQcm9jZXNzLkNoaWxkUHJvY2VzcztcbiAgICBwcm90ZWN0ZWQgY2hpbGRQaWQ/OiBudW1iZXI7XG4gICAgcHJvdGVjdGVkIGxvZzogKG1zZzogc3RyaW5nKSA9PiB2b2lkO1xuICAgIHByb3RlY3RlZCBxdWV1ZTogQXN5bmNJdGVyYWJsZVF1ZXVlPE1lc3NhZ2U+O1xuICAgIHJlYWRvbmx5IG9wdGlvbnM6IFJlcXVpcmVkPFdyYXBwZXJPcHRpb25zPjtcbiAgICBwcm90ZWN0ZWQgbW9uaXRvcmluZ1RpbWVyPzogTm9kZUpTLlRpbWVyO1xuXG4gICAgY29uc3RydWN0b3IoZk1vZHVsZTogTW9kdWxlVHlwZSwgb3B0aW9uczogV3JhcHBlck9wdGlvbnMgPSB7fSkge1xuICAgICAgICB0aGlzLm9wdGlvbnMgPSB7IC4uLldyYXBwZXJPcHRpb25EZWZhdWx0cywgLi4ub3B0aW9ucyB9O1xuICAgICAgICB0aGlzLmxvZyA9IHRoaXMub3B0aW9ucy53cmFwcGVyTG9nO1xuICAgICAgICB0aGlzLnZlcmJvc2UgPSB0aGlzLm9wdGlvbnMud3JhcHBlclZlcmJvc2U7XG4gICAgICAgIHRoaXMuZnVuY3MgPSBmTW9kdWxlO1xuICAgICAgICB0aGlzLnF1ZXVlID0gbmV3IEFzeW5jSXRlcmFibGVRdWV1ZSgpO1xuXG4gICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBpZiAgKi9cbiAgICAgICAgaWYgKHByb2Nlc3MuZW52W0ZBQVNUX0NISUxEX0VOVl0pIHtcbiAgICAgICAgICAgIHRoaXMub3B0aW9ucy5jaGlsZFByb2Nlc3MgPSBmYWxzZTtcbiAgICAgICAgICAgIHRoaXMubG9nKGBmYWFzdDogc3RhcnRlZCBjaGlsZCBwcm9jZXNzIGZvciBtb2R1bGUgd3JhcHBlci5gKTtcbiAgICAgICAgICAgIHByb2Nlc3Mub24oXCJtZXNzYWdlXCIsIGFzeW5jIChjYzogQ2FsbGluZ0NvbnRleHQpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBzdGFydFRpbWUgPSBEYXRlLm5vdygpO1xuICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMuZXhlY3V0ZShcbiAgICAgICAgICAgICAgICAgICAgICAgIHsgLi4uY2MsIHN0YXJ0VGltZSB9LFxuICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9uTWVzc2FnZTogYXN5bmMgbXNnID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2coYFJlY2VpdmVkIG1lc3NhZ2UgJHttc2cua2luZH1gKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvY2Vzcy5zZW5kISh7IGRvbmU6IGZhbHNlLCB2YWx1ZTogbXNnIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2coYERvbmUgd2l0aCB0aGlzLmV4ZWN1dGUoKWApO1xuICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmxvZyhlcnIpO1xuICAgICAgICAgICAgICAgIH0gZmluYWxseSB7XG4gICAgICAgICAgICAgICAgICAgIHByb2Nlc3Muc2VuZCEoeyBkb25lOiB0cnVlIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaWYgKCFwcm9jZXNzLmVudi5GQUFTVF9TSUxFTlQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmxvZyhgZmFhc3Q6IHN1Y2Nlc3NmdWwgY29sZCBzdGFydC5gKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByb3RlY3RlZCBsb29rdXBGdW5jdGlvbihyZXF1ZXN0OiBvYmplY3QpOiBBbnlGdW5jdGlvbiB7XG4gICAgICAgIGNvbnN0IHsgbmFtZSwgYXJncyB9ID0gcmVxdWVzdCBhcyBGdW5jdGlvbkNhbGw7XG4gICAgICAgIGlmICghbmFtZSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBmdW5jdGlvbiBjYWxsIHJlcXVlc3Q6IG5vIG5hbWVcIik7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBmdW5jID0gdGhpcy5mdW5jc1tuYW1lXTtcbiAgICAgICAgaWYgKCFmdW5jKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEZ1bmN0aW9uIG5hbWVkIFwiJHtuYW1lfVwiIG5vdCBmb3VuZGApO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFhcmdzKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIGFyZ3VtZW50cyB0byBmdW5jdGlvbiBjYWxsXCIpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmdW5jO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBzdG9wQ3B1TW9uaXRvcmluZygpIHtcbiAgICAgICAgdGhpcy5tb25pdG9yaW5nVGltZXIgJiYgY2xlYXJJbnRlcnZhbCh0aGlzLm1vbml0b3JpbmdUaW1lcik7XG4gICAgICAgIHRoaXMubW9uaXRvcmluZ1RpbWVyID0gdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBzdGFydENwdU1vbml0b3JpbmcocGlkOiBudW1iZXIsIGNhbGxJZDogc3RyaW5nKSB7XG4gICAgICAgIGlmICh0aGlzLm1vbml0b3JpbmdUaW1lcikge1xuICAgICAgICAgICAgdGhpcy5zdG9wQ3B1TW9uaXRvcmluZygpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMubW9uaXRvcmluZ1RpbWVyID0gY3B1TW9uaXRvcihwaWQsIDEwMDAsIChlcnIsIHJlc3VsdCkgPT4ge1xuICAgICAgICAgICAgaWYgKGVycikge1xuICAgICAgICAgICAgICAgIHRoaXMubG9nKGBjcHUgbW9uaXRvciBlcnJvcjogJHtlcnJ9YCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAocmVzdWx0KSB7XG4gICAgICAgICAgICAgICAgdGhpcy5xdWV1ZS5wdXNoKHsga2luZDogXCJjcHVtZXRyaWNzXCIsIGNhbGxJZCwgbWV0cmljczogcmVzdWx0IH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBzdG9wKCkge1xuICAgICAgICB0aGlzLnN0b3BDcHVNb25pdG9yaW5nKCk7XG4gICAgICAgIGlmICh0aGlzLmNoaWxkKSB7XG4gICAgICAgICAgICB0aGlzLmxvZyhgU3RvcHBpbmcgY2hpbGQgcHJvY2Vzcy5gKTtcbiAgICAgICAgICAgIHRoaXMuY2hpbGQuc3Rkb3V0IS5yZW1vdmVMaXN0ZW5lcihcImRhdGFcIiwgdGhpcy5sb2dMaW5lcyk7XG4gICAgICAgICAgICB0aGlzLmNoaWxkLnN0ZGVyciEucmVtb3ZlTGlzdGVuZXIoXCJkYXRhXCIsIHRoaXMubG9nTGluZXMpO1xuICAgICAgICAgICAgdGhpcy5jaGlsZCEuZGlzY29ubmVjdCgpO1xuICAgICAgICAgICAgdGhpcy5jaGlsZCEua2lsbCgpO1xuICAgICAgICAgICAgdGhpcy5jaGlsZCA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIHRoaXMuZXhlY3V0aW5nID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBhc3luYyBleGVjdXRlKFxuICAgICAgICBjYWxsaW5nQ29udGV4dDogQ2FsbGluZ0NvbnRleHQsXG4gICAgICAgIHsgZXJyb3JDYWxsYmFjaywgb25NZXNzYWdlLCBtZWFzdXJlQ3B1VXNhZ2UgfTogV3JhcHBlckV4ZWN1dGVPcHRpb25zXG4gICAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGNvbnN0IHByb2Nlc3NFcnJvciA9IChlcnI6IGFueSkgPT5cbiAgICAgICAgICAgIGVyciBpbnN0YW5jZW9mIEVycm9yICYmIGVycm9yQ2FsbGJhY2sgPyBlcnJvckNhbGxiYWNrKGVycikgOiBlcnI7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgaWYgICovXG4gICAgICAgICAgICBpZiAodGhpcy5leGVjdXRpbmcpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmxvZyhgZmFhc3Q6IHdhcm5pbmc6IG1vZHVsZSB3cmFwcGVyIGV4ZWN1dGUgaXMgbm90IHJlLWVudHJhbnRgKTtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYGZhYXN0OiBtb2R1bGUgd3JhcHBlciBpcyBub3QgcmUtZW50cmFudGApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5leGVjdXRpbmcgPSB0cnVlO1xuICAgICAgICAgICAgY29uc3QgeyBjYWxsLCBzdGFydFRpbWUsIGxvZ1VybCwgZXhlY3V0aW9uSWQsIGluc3RhbmNlSWQgfSA9IGNhbGxpbmdDb250ZXh0O1xuICAgICAgICAgICAgY29uc3QgZGV0YWlsID0geyBsb2dVcmwsIGV4ZWN1dGlvbklkLCBpbnN0YW5jZUlkIH07XG4gICAgICAgICAgICBjb25zdCB7IGNhbGxJZCB9ID0gY2FsbDtcbiAgICAgICAgICAgIHRoaXMubG9nKGBjYWxsaW5nOiAke2NhbGwubmFtZX1gKTtcbiAgICAgICAgICAgIHRoaXMubG9nKGAgICBhcmdzOiAke2NhbGwuYXJnc31gKTtcbiAgICAgICAgICAgIHRoaXMubG9nKGAgICBjYWxsSWQ6ICR7Y2FsbElkfWApO1xuICAgICAgICAgICAgLy8gbGV0IHN0YXJ0ZWRNZXNzYWdlVGltZXI6IE5vZGVKUy5UaW1lb3V0IHwgdW5kZWZpbmVkID0gc2V0VGltZW91dChcbiAgICAgICAgICAgIC8vICAgICAoKSA9PiBtZXNzYWdlQ2FsbGJhY2soeyBraW5kOiBcImZ1bmN0aW9uc3RhcnRlZFwiLCBjYWxsSWQgfSksXG4gICAgICAgICAgICAvLyAgICAgMiAqIDEwMDBcbiAgICAgICAgICAgIC8vICk7XG5cbiAgICAgICAgICAgIC8vIFRPRE86IEFkZCB0aGlzIGNvZGUgYWZ0ZXIgdGhlIGV4ZWN1dGUgcmV0dXJucyBvciB5aWVsZHMgaXRzIGZpcnN0IHZhbHVlLi4uXG4gICAgICAgICAgICAvLyBpZiAoc3RhcnRlZE1lc3NhZ2VUaW1lcikge1xuICAgICAgICAgICAgLy8gICAgIGNsZWFyVGltZW91dChzdGFydGVkTWVzc2FnZVRpbWVyKTtcbiAgICAgICAgICAgIC8vICAgICBzdGFydGVkTWVzc2FnZVRpbWVyID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgLy8gfVxuXG4gICAgICAgICAgICBjb25zdCBtZW1vcnlVc2FnZSA9IHByb2Nlc3MubWVtb3J5VXNhZ2UoKTtcbiAgICAgICAgICAgIGNvbnN0IG1lbUluZm8gPSBwKG1lbW9yeVVzYWdlKTtcbiAgICAgICAgICAgIGlmICh0aGlzLm9wdGlvbnMuY2hpbGRQcm9jZXNzKSB7XG4gICAgICAgICAgICAgICAgaWYgKCF0aGlzLmNoaWxkKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY2hpbGQgPSB0aGlzLnNldHVwQ2hpbGRQcm9jZXNzKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRoaXMudmVyYm9zZSAmJlxuICAgICAgICAgICAgICAgICAgICB0aGlzLmxvZyhcbiAgICAgICAgICAgICAgICAgICAgICAgIGBmYWFzdDogaW52b2tpbmcgJyR7Y2FsbC5uYW1lfScgaW4gY2hpbGQgcHJvY2VzcywgbWVtb3J5OiAke21lbUluZm99YFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIHRoaXMuY2hpbGQuc2VuZChjYWxsaW5nQ29udGV4dCwgZXJyID0+IHtcbiAgICAgICAgICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIGlmICAqL1xuICAgICAgICAgICAgICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmxvZyhgY2hpbGQgc2VuZCBlcnJvcjogcmVqZWN0aW5nIHdpdGggJHtlcnJ9YCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnF1ZXVlLnB1c2goUHJvbWlzZS5yZWplY3QoZXJyKSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICBpZiAobWVhc3VyZUNwdVVzYWdlKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMudmVyYm9zZSAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2coYFN0YXJ0aW5nIENQVSBtb25pdG9yIGZvciBwaWQgJHt0aGlzLmNoaWxkLnBpZH1gKTtcbiAgICAgICAgICAgICAgICAgICAgLy8gWFhYIENQVSBNb25pdG9yaW5nIG5vdCBlbmFibGVkIGZvciBub3cuXG4gICAgICAgICAgICAgICAgICAgIC8vIHRoaXMuc3RhcnRDcHVNb25pdG9yaW5nKHRoaXMuY2hpbGQucGlkLCBjYWxsSWQpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGxldCB0aW1lcjtcbiAgICAgICAgICAgICAgICBjb25zdCB0aW1lb3V0ID0gdGhpcy5vcHRpb25zLmNoaWxkUHJvY2Vzc1RpbWVvdXRNcztcbiAgICAgICAgICAgICAgICBpZiAodGltZW91dCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnZlcmJvc2UgJiYgdGhpcy5sb2coYFNldHRpbmcgdGltZW91dDogJHt0aW1lb3V0fWApO1xuICAgICAgICAgICAgICAgICAgICB0aW1lciA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgZXJyb3IgPSBuZXcgRmFhc3RFcnJvcihcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWU6IEZhYXN0RXJyb3JOYW1lcy5FVElNRU9VVCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mbzogeyAuLi5kZXRhaWwsIGZ1bmN0aW9uTmFtZTogY2FsbC5uYW1lIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBSZXF1ZXN0IGV4Y2VlZGVkIHRpbWVvdXQgb2YgJHt0aW1lb3V0fW1zYFxuICAgICAgICAgICAgICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5xdWV1ZS5wdXNoKFByb21pc2UucmVqZWN0KGVycm9yKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnN0b3AoKTtcbiAgICAgICAgICAgICAgICAgICAgfSwgdGltZW91dCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRoaXMudmVyYm9zZSAmJiB0aGlzLmxvZyhgYXdhaXRpbmcgYXN5bmMgZGVxdWV1ZWApO1xuICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHByb21pc2VzID0gW107XG4gICAgICAgICAgICAgICAgICAgIGZvciBhd2FpdCAoY29uc3QgcmVzdWx0IG9mIHRoaXMucXVldWUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMudmVyYm9zZSAmJiB0aGlzLmxvZyhgRGVxdWV1aW5nICR7cChyZXN1bHQpfWApO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHJlc3VsdC5raW5kID09PSBcInByb21pc2VcIiB8fCByZXN1bHQua2luZCA9PT0gXCJpdGVyYXRvclwiKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0LmxvZ1VybCA9IGxvZ1VybDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIHByb21pc2VzLnB1c2gob25NZXNzYWdlKHJlc3VsdCkpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IFByb21pc2UuYWxsKHByb21pc2VzKTtcbiAgICAgICAgICAgICAgICB9IGZpbmFsbHkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnZlcmJvc2UgJiYgdGhpcy5sb2coYEZpbmFsaXppbmcgcXVldWVgKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zdG9wQ3B1TW9uaXRvcmluZygpO1xuICAgICAgICAgICAgICAgICAgICB0aW1lciAmJiBjbGVhclRpbWVvdXQodGltZXIpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnF1ZXVlLmNsZWFyKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLnZlcmJvc2UgJiZcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2coYGZhYXN0OiBJbnZva2luZyAnJHtjYWxsLm5hbWV9JywgbWVtb3J5OiAke21lbUluZm99YCk7XG4gICAgICAgICAgICAgICAgY29uc3QgZnVuYyA9IHRoaXMubG9va3VwRnVuY3Rpb24oY2FsbCk7XG4gICAgICAgICAgICAgICAgaWYgKCFmdW5jKSB7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgICAgICAgICAgICAgIGBmYWFzdCBtb2R1bGUgd3JhcHBlcjogY291bGQgbm90IGZpbmQgZnVuY3Rpb24gJyR7Y2FsbC5uYW1lfSdgXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNvbnN0IGFyZ3MgPSBkZXNlcmlhbGl6ZShjYWxsLmFyZ3MpO1xuICAgICAgICAgICAgICAgIGxldCB2YWx1ZTtcbiAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IGF3YWl0IGZ1bmMuYXBwbHkodW5kZWZpbmVkLCBhcmdzKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy52ZXJib3NlICYmIHRoaXMubG9nKGBGaW5pc2hlZCBjYWxsIGZ1bmN0aW9uYCk7XG4gICAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMubG9nKGBGdW5jdGlvbiAke2NhbGwubmFtZX0gdGhyZXcgZXJyb3I6ICR7ZXJyfWApO1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRoaXMudmVyYm9zZSAmJlxuICAgICAgICAgICAgICAgICAgICB0aGlzLmxvZyhgcmV0dXJuZWQgdmFsdWU6ICR7cCh2YWx1ZSl9LCB0eXBlOiAke3R5cGVvZiB2YWx1ZX1gKTtcblxuICAgICAgICAgICAgICAgIGNvbnN0IHZhbGlkYXRlID0gdGhpcy5vcHRpb25zLnZhbGlkYXRlU2VyaWFsaXphdGlvbjtcbiAgICAgICAgICAgICAgICBjb25zdCBjb250ZXh0ID0geyB0eXBlOiBcImZ1bGZpbGxcIiwgY2FsbElkLCAuLi5kZXRhaWwgfSBhcyBjb25zdDtcbiAgICAgICAgICAgICAgICAvLyBDaGVjayBmb3IgaXRlcmFibGUuXG5cbiAgICAgICAgICAgICAgICBpZiAodmFsdWUgIT09IG51bGwgJiYgdmFsdWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoaXNHZW5lcmF0b3IoZnVuYykpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGxldCBuZXh0ID0gYXdhaXQgdmFsdWUubmV4dCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgbGV0IHNlcXVlbmNlID0gMDtcbiAgICAgICAgICAgICAgICAgICAgICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy52ZXJib3NlICYmIHRoaXMubG9nKGBuZXh0OiAke3AobmV4dCl9YCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV0IHJlc3VsdDogSXRlcmF0b3JSZXNwb25zZU1lc3NhZ2UgPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4uLmNvbnRleHQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtpbmQ6IFwiaXRlcmF0b3JcIixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU6IHNlcmlhbGl6ZVJldHVyblZhbHVlKGNhbGwubmFtZSwgW25leHRdLCB2YWxpZGF0ZSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcXVlbmNlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBhcyBjb25zdDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAobmV4dC5kb25lKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdC5yZW1vdGVFeGVjdXRpb25TdGFydFRpbWUgPSBzdGFydFRpbWU7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdC5yZW1vdGVFeGVjdXRpb25FbmRUaW1lID0gRGF0ZS5ub3coKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0Lm1lbW9yeVVzYWdlID0gbWVtb3J5VXNhZ2U7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IG9uTWVzc2FnZShyZXN1bHQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChuZXh0LmRvbmUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXF1ZW5jZSsrO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5leHQgPSBhd2FpdCB2YWx1ZS5uZXh0KCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBhd2FpdCBvbk1lc3NhZ2Uoe1xuICAgICAgICAgICAgICAgICAgICAuLi5jb250ZXh0LFxuICAgICAgICAgICAgICAgICAgICBraW5kOiBcInByb21pc2VcIixcbiAgICAgICAgICAgICAgICAgICAgdmFsdWU6IHNlcmlhbGl6ZVJldHVyblZhbHVlKGNhbGwubmFtZSwgW3ZhbHVlXSwgdmFsaWRhdGUpLFxuICAgICAgICAgICAgICAgICAgICByZW1vdGVFeGVjdXRpb25TdGFydFRpbWU6IHN0YXJ0VGltZSxcbiAgICAgICAgICAgICAgICAgICAgcmVtb3RlRXhlY3V0aW9uRW5kVGltZTogRGF0ZS5ub3coKSxcbiAgICAgICAgICAgICAgICAgICAgbWVtb3J5VXNhZ2VcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICB0aGlzLmxvZyhgZmFhc3Q6IHdyYXBwZWQgZnVuY3Rpb24gZXhjZXB0aW9uIG9yIHByb21pc2UgcmVqZWN0aW9uOiAke2Vycn1gKTtcbiAgICAgICAgICAgIGNvbnN0IHJlc3BvbnNlID0gY3JlYXRlRXJyb3JSZXNwb25zZShwcm9jZXNzRXJyb3IoZXJyKSwgY2FsbGluZ0NvbnRleHQpO1xuICAgICAgICAgICAgdGhpcy5sb2coYEVycm9yIHJlc3BvbnNlOiAke2luc3BlY3QocmVzcG9uc2UpfWApO1xuICAgICAgICAgICAgYXdhaXQgb25NZXNzYWdlKHJlc3BvbnNlKTtcbiAgICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgICAgIHRoaXMudmVyYm9zZSAmJiB0aGlzLmxvZyhgRXhpdGluZyBleGVjdXRlYCk7XG4gICAgICAgICAgICB0aGlzLmV4ZWN1dGluZyA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIGxvZ0xpbmVzID0gKG1zZzogc3RyaW5nKSA9PiB7XG4gICAgICAgIGxldCBsaW5lcyA9IG1zZy5zcGxpdChcIlxcblwiKTtcbiAgICAgICAgaWYgKGxpbmVzW2xpbmVzLmxlbmd0aCAtIDFdID09PSBcIlwiKSB7XG4gICAgICAgICAgICBsaW5lcyA9IGxpbmVzLnNsaWNlKDAsIGxpbmVzLmxlbmd0aCAtIDEpO1xuICAgICAgICB9XG4gICAgICAgIGZvciAoY29uc3QgbGluZSBvZiBsaW5lcykge1xuICAgICAgICAgICAgdGhpcy5sb2coYFske3RoaXMuY2hpbGRQaWR9XTogJHtsaW5lfWApO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHByb3RlY3RlZCBzZXR1cENoaWxkUHJvY2VzcygpIHtcbiAgICAgICAgdGhpcy52ZXJib3NlICYmIHRoaXMubG9nKGBmYWFzdDogY3JlYXRpbmcgY2hpbGQgcHJvY2Vzc2ApO1xuXG4gICAgICAgIGxldCBleGVjQXJndiA9IHByb2Nlc3MuZXhlY0FyZ3Yuc2xpY2UoKTtcbiAgICAgICAgaWYgKHRoaXMub3B0aW9ucy5jaGlsZFByb2Nlc3NNZW1vcnlMaW1pdE1iKSB7XG4gICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAgKi9cbiAgICAgICAgICAgIGV4ZWNBcmd2ID0gcHJvY2Vzcy5leGVjQXJndi5maWx0ZXIoXG4gICAgICAgICAgICAgICAgYXJnID0+ICFhcmcubWF0Y2goL14tLW1heC1vbGQtc3BhY2Utc2l6ZS8pICYmICFhcmcubWF0Y2goL14tLWluc3BlY3QvKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGV4ZWNBcmd2LnB1c2goXG4gICAgICAgICAgICAgICAgYC0tbWF4LW9sZC1zcGFjZS1zaXplPSR7dGhpcy5vcHRpb25zLmNoaWxkUHJvY2Vzc01lbW9yeUxpbWl0TWJ9YFxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHsgY2hpbGRQcm9jZXNzRW52aXJvbm1lbnQgfSA9IHRoaXMub3B0aW9ucztcbiAgICAgICAgY29uc3QgZW52ID0ge1xuICAgICAgICAgICAgLi4ucHJvY2Vzcy5lbnYsXG4gICAgICAgICAgICAuLi5jaGlsZFByb2Nlc3NFbnZpcm9ubWVudCxcbiAgICAgICAgICAgIFtGQUFTVF9DSElMRF9FTlZdOiBcInRydWVcIlxuICAgICAgICB9O1xuICAgICAgICB0aGlzLnZlcmJvc2UgJiYgdGhpcy5sb2coYEVudjogJHtKU09OLnN0cmluZ2lmeShlbnYpfWApO1xuICAgICAgICBjb25zdCBmb3JrT3B0aW9uczogY2hpbGRQcm9jZXNzLkZvcmtPcHRpb25zID0ge1xuICAgICAgICAgICAgc2lsZW50OiB0cnVlLCAvLyByZWRpcmVjdHMgc3Rkb3V0IGFuZCBzdGRlcnIgdG8gSVBDLlxuICAgICAgICAgICAgZW52LFxuICAgICAgICAgICAgY3dkOiB0aGlzLm9wdGlvbnMuY2hpbGREaXIsXG4gICAgICAgICAgICBleGVjQXJndlxuICAgICAgICB9O1xuXG4gICAgICAgIGNvbnN0IGNoaWxkID0gY2hpbGRQcm9jZXNzLmZvcmsoXCIuL2luZGV4LmpzXCIsIFtdLCBmb3JrT3B0aW9ucyk7XG4gICAgICAgIHRoaXMuY2hpbGRQaWQgPSBjaGlsZC5waWQ7XG5cbiAgICAgICAgY2hpbGQuc3Rkb3V0IS5zZXRFbmNvZGluZyhcInV0ZjhcIik7XG4gICAgICAgIGNoaWxkLnN0ZGVyciEuc2V0RW5jb2RpbmcoXCJ1dGY4XCIpO1xuXG4gICAgICAgIGxldCBvb206IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgICAgICAgY29uc3QgZGV0ZWN0T29tID0gKGNodW5rOiBzdHJpbmcpID0+IHtcbiAgICAgICAgICAgIGlmIChvb21QYXR0ZXJuLnRlc3QoY2h1bmspKSB7XG4gICAgICAgICAgICAgICAgb29tID0gY2h1bms7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICAgIGNoaWxkLnN0ZG91dCEub24oXCJkYXRhXCIsIHRoaXMubG9nTGluZXMpO1xuICAgICAgICBjaGlsZC5zdGRlcnIhLm9uKFwiZGF0YVwiLCB0aGlzLmxvZ0xpbmVzKTtcbiAgICAgICAgY2hpbGQuc3RkZXJyIS5vbihcImRhdGFcIiwgZGV0ZWN0T29tKTtcbiAgICAgICAgY2hpbGQub24oXCJtZXNzYWdlXCIsIChtZXNzYWdlOiBJdGVyYXRvclJlc3VsdDxNZXNzYWdlPikgPT4ge1xuICAgICAgICAgICAgdGhpcy52ZXJib3NlICYmIHRoaXMubG9nKGBjaGlsZCBtZXNzYWdlOiByZXNvbHZpbmcgd2l0aCAke3AobWVzc2FnZSl9YCk7XG4gICAgICAgICAgICBpZiAobWVzc2FnZS5kb25lKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5xdWV1ZS5kb25lKCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMucXVldWUucHVzaChtZXNzYWdlLnZhbHVlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICAqL1xuICAgICAgICBjaGlsZC5vbihcImVycm9yXCIsIGVyciA9PiB7XG4gICAgICAgICAgICB0aGlzLnZlcmJvc2UgJiYgdGhpcy5sb2coYGNoaWxkIGVycm9yOiByZWplY3Rpbmcgd2l0aCAke2Vycn1gKTtcbiAgICAgICAgICAgIHRoaXMuY2hpbGQgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICB0aGlzLnF1ZXVlLnB1c2goUHJvbWlzZS5yZWplY3QoZXJyKSk7XG4gICAgICAgIH0pO1xuICAgICAgICBjaGlsZC5vbihcImV4aXRcIiwgKGNvZGUsIHNpZ25hbCkgPT4ge1xuICAgICAgICAgICAgdGhpcy52ZXJib3NlICYmIHRoaXMubG9nKGBjaGlsZCBleGl0OiBjb2RlOiAke2NvZGV9LCBzaWduYWw6ICR7c2lnbmFsfWApO1xuICAgICAgICAgICAgdGhpcy5jaGlsZCA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIGlmIChjb2RlKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5xdWV1ZS5wdXNoKFxuICAgICAgICAgICAgICAgICAgICBQcm9taXNlLnJlamVjdChuZXcgRXJyb3IoYEV4aXRlZCB3aXRoIGVycm9yIGNvZGUgJHtjb2RlfWApKVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKHNpZ25hbCAhPT0gbnVsbCAmJiBzaWduYWwgIT09IFwiU0lHVEVSTVwiKSB7XG4gICAgICAgICAgICAgICAgbGV0IGVycm9yTWVzc2FnZSA9IGBBYm9ydGVkIHdpdGggc2lnbmFsICR7c2lnbmFsfWA7XG4gICAgICAgICAgICAgICAgaWYgKHNpZ25hbCA9PT0gXCJTSUdBQlJUXCIgJiYgb29tKSB7XG4gICAgICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZSArPSBgICgke29vbX0pYDtcbiAgICAgICAgICAgICAgICAgICAgb29tID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB0aGlzLnF1ZXVlLnB1c2goUHJvbWlzZS5yZWplY3QobmV3IEVycm9yKGVycm9yTWVzc2FnZSkpKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy52ZXJib3NlICYmIHRoaXMubG9nKGBjaGlsZCBleGl0aW5nIG5vcm1hbGx5YCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gY2hpbGQ7XG4gICAgfVxufVxuXG5leHBvcnQgaW50ZXJmYWNlIENwdU1lYXN1cmVtZW50IHtcbiAgICBzdGltZTogbnVtYmVyO1xuICAgIHV0aW1lOiBudW1iZXI7XG4gICAgZWxhcHNlZDogbnVtYmVyO1xufVxuXG5mdW5jdGlvbiBjcHVNb25pdG9yKFxuICAgIHBpZDogbnVtYmVyLFxuICAgIGludGVydmFsOiBudW1iZXIsXG4gICAgY2FsbGJhY2s6IChlcnI/OiBFcnJvciwgcmVzdWx0PzogQ3B1TWVhc3VyZW1lbnQpID0+IHZvaWRcbikge1xuICAgIGNvbnN0IHN0YXJ0ID0gRGF0ZS5ub3coKTtcbiAgICBjb25zdCB0aW1lciA9IHNldEludGVydmFsKFxuICAgICAgICAoKSA9PlxuICAgICAgICAgICAgcHJvY3Rvci5sb29rdXAocGlkLCAoZXJyLCByZXN1bHQpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgICAgICAgICAgIGNhbGxiYWNrKGVycik7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgY29uc3QgeyBzdGltZSwgdXRpbWUgfSA9IHJlc3VsdDtcbiAgICAgICAgICAgICAgICBjYWxsYmFjayhcbiAgICAgICAgICAgICAgICAgICAgZXJyLFxuICAgICAgICAgICAgICAgICAgICByZXN1bHQgJiYge1xuICAgICAgICAgICAgICAgICAgICAgICAgc3RpbWU6IHN0aW1lICogMTAsXG4gICAgICAgICAgICAgICAgICAgICAgICB1dGltZTogdXRpbWUgKiAxMCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsYXBzZWQ6IERhdGUubm93KCkgLSBzdGFydFxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH0pLFxuICAgICAgICBpbnRlcnZhbFxuICAgICk7XG4gICAgcmV0dXJuIHRpbWVyO1xufVxuIl19
\No newline at end of file