UNPKG

20 kBJavaScriptView Raw
1"use strict";
2var __importDefault = (this && this.__importDefault) || function (mod) {
3 return (mod && mod.__esModule) ? mod : { "default": mod };
4};
5Object.defineProperty(exports, "__esModule", { value: true });
6const assert_1 = __importDefault(require("assert"));
7const chrome_remote_interface_1 = __importDefault(require("chrome-remote-interface"));
8const istanbulize_1 = require("istanbulize");
9const node_inspector_server_1 = require("node-inspector-server");
10async function spawnInspected(file, args, options) {
11 const processCovs = [];
12 const srv = await node_inspector_server_1.InspectorServer.open();
13 return new Promise((resolve, reject) => {
14 srv
15 .subscribe(async (ev) => {
16 try {
17 // if (ev.rootProcess !== undefined && options.onRootProcess !== undefined) {
18 // options.onRootProcess(ev.rootProcess);
19 // }
20 // const args: ReadonlyArray<string> = ["--inspect=0", ...ev.args];
21 // const proxy: ChildProcessProxy = ev.proxySpawn(args);
22 // const debuggerPort: number = await getDebuggerPort(proxy);
23 const processCov = await getCoverage(ev.url, options.filter, options.timeout);
24 processCovs.push(processCov);
25 }
26 catch (err) {
27 reject(err);
28 }
29 }, reject, () => resolve(processCovs));
30 const child = srv.spawn(file, args, options);
31 if (options.onRootProcess !== undefined) {
32 options.onRootProcess(child);
33 }
34 child.on("close", () => {
35 srv.closeSync();
36 });
37 });
38}
39exports.spawnInspected = spawnInspected;
40async function getCoverage(url, filter, timeout) {
41 return new Promise(async (resolve, reject) => {
42 const timeoutId = timeout !== undefined ? setTimeout(onTimeout, timeout) : undefined;
43 let session;
44 let mainExecutionContextId;
45 const scriptIdToMeta = new Map();
46 let state = "WaitingForMainContext"; // TODO: enum
47 try {
48 session = await chrome_remote_interface_1.default({ target: url });
49 session.once("Runtime.executionContextCreated", onMainContextCreation);
50 session.on("Runtime.executionContextDestroyed", onContextDestruction);
51 session.on("Debugger.scriptParsed", onScriptParsed);
52 await session.Profiler.enable();
53 await session.Profiler.startPreciseCoverage({ callCount: true, detailed: true });
54 await session.Debugger.enable();
55 await session.Runtime.enable();
56 await session.Runtime.runIfWaitingForDebugger();
57 }
58 catch (err) {
59 removeListeners();
60 reject(err);
61 }
62 function onMainContextCreation(ev) {
63 assert_1.default(state === "WaitingForMainContext");
64 mainExecutionContextId = ev.context.id;
65 state = "WaitingForMainContextDestruction";
66 }
67 function onScriptParsed(ev) {
68 const collect = filter !== undefined ? filter(ev) : true;
69 if (collect) {
70 let sourceType = istanbulize_1.SourceType.Script;
71 if (ev.isModule !== undefined) {
72 sourceType = ev.isModule ? istanbulize_1.SourceType.Module : istanbulize_1.SourceType.Script;
73 }
74 let sourceMapUrl;
75 if (ev.sourceMapURL !== undefined && ev.sourceMapURL !== "") {
76 sourceMapUrl = ev.sourceMapURL;
77 }
78 scriptIdToMeta.set(ev.scriptId, {
79 sourceType,
80 sourceMapUrl,
81 });
82 }
83 }
84 async function onContextDestruction(ev) {
85 assert_1.default(state === "WaitingForMainContextDestruction");
86 if (ev.executionContextId !== mainExecutionContextId) {
87 return;
88 }
89 state = "WaitingForCoverage";
90 try {
91 // await session.Profiler.stopPreciseCoverage();
92 await session.HeapProfiler.collectGarbage();
93 const { result: scriptCovs } = await session.Profiler.takePreciseCoverage();
94 const result = [];
95 for (const scriptCov of scriptCovs) {
96 const meta = scriptIdToMeta.get(scriptCov.scriptId);
97 if (meta === undefined) {
98 // `undefined` means that the script was filtered out.
99 continue;
100 }
101 const { scriptSource } = await session.Debugger.getScriptSource({ scriptId: scriptCov.scriptId });
102 result.push(Object.assign(Object.assign(Object.assign({}, scriptCov), { sourceText: scriptSource }), meta));
103 }
104 resolve({ result });
105 }
106 catch (err) {
107 reject(err);
108 }
109 finally {
110 removeListeners();
111 }
112 }
113 function onTimeout() {
114 removeListeners();
115 reject(new Error("Unable to get V8 coverage (timeout)"));
116 }
117 function removeListeners() {
118 if (session === undefined) {
119 // Failure before the session is created
120 return;
121 }
122 session.removeListener("Runtime.executionContextCreated", onMainContextCreation);
123 session.removeListener("Runtime.executionContextDestroyed", onContextDestruction);
124 session.removeListener("Runtime.scriptParsed", onScriptParsed);
125 if (timeoutId !== undefined) {
126 clearTimeout(timeoutId);
127 }
128 session.close();
129 }
130 });
131}
132
133//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIl9zcmMvc3Bhd24taW5zcGVjdGVkLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQ0Esb0RBQTRCO0FBRTVCLHNGQUEwQztBQUcxQyw2Q0FBeUM7QUFDekMsaUVBQXlFO0FBd0JsRSxLQUFLLFVBQVUsY0FBYyxDQUNsQyxJQUFZLEVBQ1osSUFBMkIsRUFDM0IsT0FBOEI7SUFFOUIsTUFBTSxXQUFXLEdBQXFCLEVBQUUsQ0FBQztJQUV6QyxNQUFNLEdBQUcsR0FBb0IsTUFBTSx1Q0FBZSxDQUFDLElBQUksRUFBRSxDQUFDO0lBRTFELE9BQU8sSUFBSSxPQUFPLENBQW1CLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO1FBQ3ZELEdBQUc7YUFDQSxTQUFTLENBQ1IsS0FBSyxFQUFFLEVBQW1CLEVBQUUsRUFBRTtZQUM1QixJQUFJO2dCQUNGLDZFQUE2RTtnQkFDN0UsMkNBQTJDO2dCQUMzQyxJQUFJO2dCQUNKLG1FQUFtRTtnQkFDbkUsd0RBQXdEO2dCQUN4RCw2REFBNkQ7Z0JBQzdELE1BQU0sVUFBVSxHQUFtQixNQUFNLFdBQVcsQ0FBQyxFQUFFLENBQUMsR0FBRyxFQUFFLE9BQU8sQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDO2dCQUM5RixXQUFXLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO2FBQzlCO1lBQUMsT0FBTyxHQUFHLEVBQUU7Z0JBQ1osTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO2FBQ2I7UUFDSCxDQUFDLEVBQ0QsTUFBTSxFQUNOLEdBQUcsRUFBRSxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FDM0IsQ0FBQztRQUVKLE1BQU0sS0FBSyxHQUFvQixHQUFHLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxJQUFJLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDOUQsSUFBSSxPQUFPLENBQUMsYUFBYSxLQUFLLFNBQVMsRUFBRTtZQUN2QyxPQUFPLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FB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bkI7UUFDSCxDQUFDO1FBRUQsU0FBUyxTQUFTO1lBQ2hCLGVBQWUsRUFBRSxDQUFDO1lBQ2xCLE1BQU0sQ0FBQyxJQUFJLEtBQUssQ0FBQyxxQ0FBcUMsQ0FBQyxDQUFDLENBQUM7UUFDM0QsQ0FBQztRQUVELFNBQVMsZUFBZTtZQUN0QixJQUFJLE9BQU8sS0FBSyxTQUFTLEVBQUU7Z0JBQ3pCLHdDQUF3QztnQkFDeEMsT0FBTzthQUNSO1lBRUEsT0FBc0MsQ0FBQyxjQUFjLENBQUMsaUNBQWlDLEVBQUUscUJBQXFCLENBQUMsQ0FBQztZQUNoSCxPQUFzQyxDQUFDLGNBQWMsQ0FBQyxtQ0FBbUMsRUFBRSxvQkFBb0IsQ0FBQyxDQUFDO1lBQ2pILE9BQXNDLENBQUMsY0FBYyxDQUFDLHNCQUFzQixFQUFFLGNBQWMsQ0FBQyxDQUFDO1lBQy9GLElBQUksU0FBUyxLQUFLLFNBQVMsRUFBRTtnQkFDM0IsWUFBWSxDQUFDLFNBQVMsQ0FBQyxDQUFDO2FBQ3pCO1lBQ0EsT0FBZSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQzNCLENBQUM7SUFDSCxDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMiLCJmaWxlIjoic3Bhd24taW5zcGVjdGVkLmpzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgUHJvY2Vzc0NvdiwgU2NyaXB0Q292IH0gZnJvbSBcIkBjODgvdjgtY292ZXJhZ2VcIjtcbmltcG9ydCBhc3NlcnQgZnJvbSBcImFzc2VydFwiO1xuaW1wb3J0IGNwIGZyb20gXCJjaGlsZF9wcm9jZXNzXCI7XG5pbXBvcnQgY3JpIGZyb20gXCJjaHJvbWUtcmVtb3RlLWludGVyZmFjZVwiO1xuaW1wb3J0IFByb3RvY29sIGZyb20gXCJkZXZ0b29scy1wcm90b2NvbFwiO1xuaW1wb3J0IGV2ZW50cyBmcm9tIFwiZXZlbnRzXCI7XG5pbXBvcnQgeyBTb3VyY2VUeXBlIH0gZnJvbSBcImlzdGFuYnVsaXplXCI7XG5pbXBvcnQgeyBJbnNwZWN0b3JDbGllbnQsIEluc3BlY3RvclNlcnZlciB9IGZyb20gXCJub2RlLWluc3BlY3Rvci1zZXJ2ZXJcIjtcbmltcG9ydCB7IENvdmVyYWdlRmlsdGVyIH0gZnJvbSBcIi4vZmlsdGVyXCI7XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2NyaXB0TWV0YSB7XG4gIHNvdXJjZVRleHQ6IHN0cmluZztcbiAgc291cmNlVHlwZTogU291cmNlVHlwZTtcbiAgc291cmNlTWFwVXJsPzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJpY2hTY3JpcHRDb3YgZXh0ZW5kcyBTY3JpcHRDb3YsIFNjcmlwdE1ldGEge1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJpY2hQcm9jZXNzQ292IGV4dGVuZHMgUHJvY2Vzc0NvdiB7XG4gIHJlc3VsdDogUmljaFNjcmlwdENvdltdO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFNwYXduSW5zcGVjdGVkT3B0aW9ucyBleHRlbmRzIGNwLlNwYXduT3B0aW9ucyB7XG4gIGZpbHRlcj86IENvdmVyYWdlRmlsdGVyO1xuXG4gIHRpbWVvdXQ/OiBudW1iZXI7XG5cbiAgb25Sb290UHJvY2Vzcz8ocHJvY2VzczogY3AuQ2hpbGRQcm9jZXNzKTogYW55O1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc3Bhd25JbnNwZWN0ZWQoXG4gIGZpbGU6IHN0cmluZyxcbiAgYXJnczogUmVhZG9ubHlBcnJheTxzdHJpbmc+LFxuICBvcHRpb25zOiBTcGF3bkluc3BlY3RlZE9wdGlvbnMsXG4pOiBQcm9taXNlPFJpY2hQcm9jZXNzQ292W10+IHtcbiAgY29uc3QgcHJvY2Vzc0NvdnM6IFJpY2hQcm9jZXNzQ292W10gPSBbXTtcblxuICBjb25zdCBzcnY6IEluc3BlY3RvclNlcnZlciA9IGF3YWl0IEluc3BlY3RvclNlcnZlci5vcGVuKCk7XG5cbiAgcmV0dXJuIG5ldyBQcm9taXNlPFJpY2hQcm9jZXNzQ292W10+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICBzcnZcbiAgICAgIC5zdWJzY3JpYmUoXG4gICAgICAgIGFzeW5jIChldjogSW5zcGVjdG9yQ2xpZW50KSA9PiB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIC8vIGlmIChldi5yb290UHJvY2VzcyAhPT0gdW5kZWZpbmVkICYmIG9wdGlvbnMub25Sb290UHJvY2VzcyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAvLyAgIG9wdGlvbnMub25Sb290UHJvY2Vzcyhldi5yb290UHJvY2Vzcyk7XG4gICAgICAgICAgICAvLyB9XG4gICAgICAgICAgICAvLyBjb25zdCBhcmdzOiBSZWFkb25seUFycmF5PHN0cmluZz4gPSBbXCItLWluc3BlY3Q9MFwiLCAuLi5ldi5hcmdzXTtcbiAgICAgICAgICAgIC8vIGNvbnN0IHByb3h5OiBDaGlsZFByb2Nlc3NQcm94eSA9IGV2LnByb3h5U3Bhd24oYXJncyk7XG4gICAgICAgICAgICAvLyBjb25zdCBkZWJ1Z2dlclBvcnQ6IG51bWJlciA9IGF3YWl0IGdldERlYnVnZ2VyUG9ydChwcm94eSk7XG4gICAgICAgICAgICBjb25zdCBwcm9jZXNzQ292OiBSaWNoUHJvY2Vzc0NvdiA9IGF3YWl0IGdldENvdmVyYWdlKGV2LnVybCwgb3B0aW9ucy5maWx0ZXIsIG9wdGlvbnMudGltZW91dCk7XG4gICAgICAgICAgICBwcm9jZXNzQ292cy5wdXNoKHByb2Nlc3NDb3YpO1xuICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgcmVqZWN0KGVycik7XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICByZWplY3QsXG4gICAgICAgICgpID0+IHJlc29sdmUocHJvY2Vzc0NvdnMpLFxuICAgICAgKTtcblxuICAgIGNvbnN0IGNoaWxkOiBjcC5DaGlsZFByb2Nlc3MgPSBzcnYuc3Bhd24oZmlsZSwgYXJncywgb3B0aW9ucyk7XG4gICAgaWYgKG9wdGlvbnMub25Sb290UHJvY2VzcyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBvcHRpb25zLm9uUm9vdFByb2Nlc3MoY2hpbGQpO1xuICAgIH1cblxuICAgIGNoaWxkLm9uKFwiY2xvc2VcIiwgKCkgPT4ge1xuICAgICAgc3J2LmNsb3NlU3luYygpO1xuICAgIH0pO1xuICB9KTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZ2V0Q292ZXJhZ2UodXJsOiBzdHJpbmcsIGZpbHRlcj86IENvdmVyYWdlRmlsdGVyLCB0aW1lb3V0PzogbnVtYmVyKTogUHJvbWlzZTxSaWNoUHJvY2Vzc0Nvdj4ge1xuICByZXR1cm4gbmV3IFByb21pc2U8UmljaFByb2Nlc3NDb3Y+KGFzeW5jIChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICBjb25zdCB0aW1lb3V0SWQ6IE5vZGVKUy5UaW1lciB8IHVuZGVmaW5lZCA9IHRpbWVvdXQgIT09IHVuZGVmaW5lZCA/IHNldFRpbWVvdXQob25UaW1lb3V0LCB0aW1lb3V0KSA6IHVuZGVmaW5lZDtcbiAgICBsZXQgc2Vzc2lvbjogYW55O1xuICAgIGxldCBtYWluRXhlY3V0aW9uQ29udGV4dElkOiBQcm90b2NvbC5SdW50aW1lLkV4ZWN1dGlvbkNvbnRleHRJZCB8IHVuZGVmaW5lZDtcbiAgICBjb25zdCBzY3JpcHRJZFRvTWV0YTogTWFwPFByb3RvY29sLlJ1bnRpbWUuU2NyaXB0SWQsIFBhcnRpYWw8U2NyaXB0TWV0YT4+ID0gbmV3IE1hcCgpO1xuICAgIGxldCBzdGF0ZTogc3RyaW5nID0gXCJXYWl0aW5nRm9yTWFpbkNvbnRleHRcIjsgLy8gVE9ETzogZW51bVxuICAgIHRyeSB7XG4gICAgICBzZXNzaW9uID0gYXdhaXQgY3JpKHt0YXJnZXQ6IHVybH0pO1xuICAgICAgKHNlc3Npb24gYXMgYW55IGFzIGV2ZW50cy5FdmVudEVtaXR0ZXIpLm9uY2UoXCJSdW50aW1lLmV4ZWN1dGlvbkNvbnRleHRDcmVhdGVkXCIsIG9uTWFpbkNvbnRleHRDcmVhdGlvbik7XG4gICAgICAoc2Vzc2lvbiBhcyBhbnkgYXMgZXZlbnRzLkV2ZW50RW1pdHRlcikub24oXCJSdW50aW1lLmV4ZWN1dGlvbkNvbnRleHREZXN0cm95ZWRcIiwgb25Db250ZXh0RGVzdHJ1Y3Rpb24pO1xuICAgICAgKHNlc3Npb24gYXMgYW55IGFzIGV2ZW50cy5FdmVudEVtaXR0ZXIpLm9uKFwiRGVidWdnZXIuc2NyaXB0UGFyc2VkXCIsIG9uU2NyaXB0UGFyc2VkKTtcblxuICAgICAgYXdhaXQgc2Vzc2lvbi5Qcm9maWxlci5lbmFibGUoKTtcbiAgICAgIGF3YWl0IHNlc3Npb24uUHJvZmlsZXIuc3RhcnRQcmVjaXNlQ292ZXJhZ2Uoe2NhbGxDb3VudDogdHJ1ZSwgZGV0YWlsZWQ6IHRydWV9KTtcbiAgICAgIGF3YWl0IHNlc3Npb24uRGVidWdnZXIuZW5hYmxlKCk7XG4gICAgICBhd2FpdCBzZXNzaW9uLlJ1bnRpbWUuZW5hYmxlKCk7XG4gICAgICBhd2FpdCBzZXNzaW9uLlJ1bnRpbWUucnVuSWZXYWl0aW5nRm9yRGVidWdnZXIoKTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIHJlbW92ZUxpc3RlbmVycygpO1xuICAgICAgcmVqZWN0KGVycik7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gb25NYWluQ29udGV4dENyZWF0aW9uKGV2OiBQcm90b2NvbC5SdW50aW1lLkV4ZWN1dGlvbkNvbnRleHRDcmVhdGVkRXZlbnQpIHtcbiAgICAgIGFzc2VydChzdGF0ZSA9PT0gXCJXYWl0aW5nRm9yTWFpbkNvbnRleHRcIik7XG4gICAgICBtYWluRXhlY3V0aW9uQ29udGV4dElkID0gZXYuY29udGV4dC5pZDtcbiAgICAgIHN0YXRlID0gXCJXYWl0aW5nRm9yTWFpbkNvbnRleHREZXN0cnVjdGlvblwiO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIG9uU2NyaXB0UGFyc2VkKGV2OiBQcm90b2NvbC5EZWJ1Z2dlci5TY3JpcHRQYXJzZWRFdmVudCkge1xuICAgICAgY29uc3QgY29sbGVjdDogYm9vbGVhbiA9IGZpbHRlciAhPT0gdW5kZWZpbmVkID8gZmlsdGVyKGV2KSA6IHRydWU7XG4gICAgICBpZiAoY29sbGVjdCkge1xuICAgICAgICBsZXQgc291cmNlVHlwZTogU291cmNlVHlwZSA9IFNvdXJjZVR5cGUuU2NyaXB0O1xuICAgICAgICBpZiAoZXYuaXNNb2R1bGUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIHNvdXJjZVR5cGUgPSBldi5pc01vZHVsZSA/IFNvdXJjZVR5cGUuTW9kdWxlIDogU291cmNlVHlwZS5TY3JpcHQ7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IHNvdXJjZU1hcFVybDogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgICAgICBpZiAoZXYuc291cmNlTWFwVVJMICE9PSB1bmRlZmluZWQgJiYgZXYuc291cmNlTWFwVVJMICE9PSBcIlwiKSB7XG4gICAgICAgICAgc291cmNlTWFwVXJsID0gZXYuc291cmNlTWFwVVJMO1xuICAgICAgICB9XG4gICAgICAgIHNjcmlwdElkVG9NZXRhLnNldChcbiAgICAgICAgICBldi5zY3JpcHRJZCxcbiAgICAgICAgICB7XG4gICAgICAgICAgICBzb3VyY2VUeXBlLFxuICAgICAgICAgICAgc291cmNlTWFwVXJsLFxuICAgICAgICAgIH0sXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgYXN5bmMgZnVuY3Rpb24gb25Db250ZXh0RGVzdHJ1Y3Rpb24oZXY6IFByb3RvY29sLlJ1bnRpbWUuRXhlY3V0aW9uQ29udGV4dERlc3Ryb3llZEV2ZW50KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICBhc3NlcnQoc3RhdGUgPT09IFwiV2FpdGluZ0Zvck1haW5Db250ZXh0RGVzdHJ1Y3Rpb25cIik7XG4gICAgICBpZiAoZXYuZXhlY3V0aW9uQ29udGV4dElkICE9PSBtYWluRXhlY3V0aW9uQ29udGV4dElkKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHN0YXRlID0gXCJXYWl0aW5nRm9yQ292ZXJhZ2VcIjtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgLy8gYXdhaXQgc2Vzc2lvbi5Qcm9maWxlci5zdG9wUHJlY2lzZUNvdmVyYWdlKCk7XG4gICAgICAgIGF3YWl0IHNlc3Npb24uSGVhcFByb2ZpbGVyLmNvbGxlY3RHYXJiYWdlKCk7XG4gICAgICAgIGNvbnN0IHtyZXN1bHQ6IHNjcmlwdENvdnN9ID0gYXdhaXQgc2Vzc2lvbi5Qcm9maWxlci50YWtlUHJlY2lzZUNvdmVyYWdlKCk7XG4gICAgICAgIGNvbnN0IHJlc3VsdDogUmljaFNjcmlwdENvdltdID0gW107XG4gICAgICAgIGZvciAoY29uc3Qgc2NyaXB0Q292IG9mIHNjcmlwdENvdnMpIHtcbiAgICAgICAgICBjb25zdCBtZXRhOiBQYXJ0aWFsPFNjcmlwdE1ldGE+IHwgdW5kZWZpbmVkID0gc2NyaXB0SWRUb01ldGEuZ2V0KHNjcmlwdENvdi5zY3JpcHRJZCk7XG4gICAgICAgICAgaWYgKG1ldGEgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgLy8gYHVuZGVmaW5lZGAgbWVhbnMgdGhhdCB0aGUgc2NyaXB0IHdhcyBmaWx0ZXJlZCBvdXQuXG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICB9XG4gICAgICAgICAgY29uc3Qge3NjcmlwdFNvdXJjZX0gPSBhd2FpdCBzZXNzaW9uLkRlYnVnZ2VyLmdldFNjcmlwdFNvdXJjZSh7c2NyaXB0SWQ6IHNjcmlwdENvdi5zY3JpcHRJZH0pO1xuICAgICAgICAgIHJlc3VsdC5wdXNoKHtcbiAgICAgICAgICAgIC4uLnNjcmlwdENvdixcbiAgICAgICAgICAgIHNvdXJjZVRleHQ6IHNjcmlwdFNvdXJjZSxcbiAgICAgICAgICAgIC4uLm1ldGEsXG4gICAgICAgICAgfSBhcyBSaWNoU2NyaXB0Q292KTtcbiAgICAgICAgfVxuICAgICAgICByZXNvbHZlKHtyZXN1bHR9KTtcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICByZWplY3QoZXJyKTtcbiAgICAgIH0gZmluYWxseSB7XG4gICAgICAgIHJlbW92ZUxpc3RlbmVycygpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIG9uVGltZW91dCgpOiB2b2lkIHtcbiAgICAgIHJlbW92ZUxpc3RlbmVycygpO1xuICAgICAgcmVqZWN0KG5ldyBFcnJvcihcIlVuYWJsZSB0byBnZXQgVjggY292ZXJhZ2UgKHRpbWVvdXQpXCIpKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiByZW1vdmVMaXN0ZW5lcnMoKTogdm9pZCB7XG4gICAgICBpZiAoc2Vzc2lvbiA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIC8vIEZhaWx1cmUgYmVmb3JlIHRoZSBzZXNzaW9uIGlzIGNyZWF0ZWRcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICAoc2Vzc2lvbiBhcyBhbnkgYXMgZXZlbnRzLkV2ZW50RW1pdHRlcikucmVtb3ZlTGlzdGVuZXIoXCJSdW50aW1lLmV4ZWN1dGlvbkNvbnRleHRDcmVhdGVkXCIsIG9uTWFpbkNvbnRleHRDcmVhdGlvbik7XG4gICAgICAoc2Vzc2lvbiBhcyBhbnkgYXMgZXZlbnRzLkV2ZW50RW1pdHRlcikucmVtb3ZlTGlzdGVuZXIoXCJSdW50aW1lLmV4ZWN1dGlvbkNvbnRleHREZXN0cm95ZWRcIiwgb25Db250ZXh0RGVzdHJ1Y3Rpb24pO1xuICAgICAgKHNlc3Npb24gYXMgYW55IGFzIGV2ZW50cy5FdmVudEVtaXR0ZXIpLnJlbW92ZUxpc3RlbmVyKFwiUnVudGltZS5zY3JpcHRQYXJzZWRcIiwgb25TY3JpcHRQYXJzZWQpO1xuICAgICAgaWYgKHRpbWVvdXRJZCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGNsZWFyVGltZW91dCh0aW1lb3V0SWQpO1xuICAgICAgfVxuICAgICAgKHNlc3Npb24gYXMgYW55KS5jbG9zZSgpO1xuICAgIH1cbiAgfSk7XG59XG4iXSwic291cmNlUm9vdCI6IiJ9