socket-function 1.1.49 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SocketFunction.d.ts +1 -1
- package/SocketFunctionTypes.d.ts +1 -1
- package/dist/SetProcessVariables.ts.cache +9 -0
- package/dist/SocketFunction.ts.cache +467 -0
- package/hot/HotReloadController.d.ts +3 -3
- package/hot/dist/HotReloadController.ts.cache +252 -0
- package/index.d.ts +10 -25
- package/package.json +1 -1
- package/require/CSSShim.d.ts +1 -1
- package/require/RequireController.d.ts +2 -2
- package/require/compileFlags.d.ts +1 -1
- package/require/dist/RequireController.ts.cache +386 -0
- package/require/dist/compileFlags.ts.cache +41 -0
- package/require/dist/extMapper.ts.cache +368 -0
- package/require/dist/require.ts.cache +676 -0
- package/require/require.d.ts +1 -1
- package/src/JSONLACKS/dist/JSONLACKS.ts.cache +469 -0
- package/src/callManager.d.ts +1 -1
- package/src/dist/CallFactory.ts.cache +930 -0
- package/src/dist/Zip.ts.cache +156 -0
- package/src/dist/batching.ts.cache +377 -0
- package/src/dist/bits.ts.cache +121 -0
- package/src/dist/buffers.ts.cache +76 -0
- package/src/dist/caching.ts.cache +302 -0
- package/src/dist/callHTTPHandler.ts.cache +264 -0
- package/src/dist/callManager.ts.cache +159 -0
- package/src/dist/certStore.ts.cache +59 -0
- package/src/dist/createSingleton.ts.cache +62 -0
- package/src/dist/fixLargeNetworkCalls.ts.cache +17 -0
- package/src/dist/forwardPort.ts.cache +222 -0
- package/src/dist/https.ts.cache +141 -0
- package/src/dist/misc.ts.cache +499 -0
- package/src/dist/nodeCache.ts.cache +136 -0
- package/src/dist/nodeProxy.ts.cache +57 -0
- package/src/dist/protocolNegotiation.ts.cache +101 -0
- package/src/dist/tlsParsing.ts.cache +85 -0
- package/src/dist/types.ts.cache +9 -0
- package/src/dist/webSocketServer.ts.cache +365 -0
- package/src/dist/websocketFactory.ts.cache +53 -0
- package/src/formatting/dist/colors.ts.cache +98 -0
- package/src/formatting/dist/format.ts.cache +396 -0
- package/src/formatting/dist/logColors.ts.cache +28 -0
- package/src/lz4/dist/LZ4.ts.cache +53 -0
- package/src/profiling/dist/getOwnTime.ts.cache +100 -0
- package/src/profiling/dist/measure.ts.cache +338 -0
- package/src/profiling/dist/stats.ts.cache +202 -0
- package/src/profiling/dist/statsFormat.ts.cache +45 -0
- package/src/profiling/getOwnTime.ts +7 -1
- package/src/profiling/measure.ts +25 -16
- package/test.ts +11 -5
- package/time/dist/trueTimeShim.ts.cache +656 -0
- package/time/trueTimeShim.d.ts +1 -16
- package/time/trueTimeShim.ts +7 -43
|
@@ -0,0 +1,930 @@
|
|
|
1
|
+
"use strict"; var console = (function shimConsole() { let baseConsole = globalThis.console; if (typeof window !== "undefined") return baseConsole; let name = __filename.replaceAll("\\", "/").split("/").pop(); let dirName = __dirname.replaceAll("\\", "/").split("/").pop(); let context = { __FILE__: __filename, __DIR__: __dirname, __NAME__: name, __DIRNAME__: dirName }; let newConsole = { ...baseConsole }; for (let shim of ["log", "info", "warn", "error"]) { newConsole[shim] = (...args) => { args.push(context); baseConsole[shim](...args); }; } newConsole.__context = context; return newConsole; })(); "use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
|
|
26
|
+
exports.getStats = exports.createCallFactory = exports.harvestCallTimes = exports.getPendingCallCount = exports.harvestFailedCallCount = void 0;
|
|
27
|
+
const callManager_1 = require("./callManager");
|
|
28
|
+
const misc_1 = require("./misc");
|
|
29
|
+
const websocketFactory_1 = require("./websocketFactory");
|
|
30
|
+
const SocketFunction_1 = require("../SocketFunction");
|
|
31
|
+
const nodeCache_1 = require("./nodeCache");
|
|
32
|
+
const caching_1 = require("./caching");
|
|
33
|
+
const logColors_1 = require("./formatting/logColors");
|
|
34
|
+
const fixLargeNetworkCalls_1 = require("./fixLargeNetworkCalls");
|
|
35
|
+
const batching_1 = require("./batching");
|
|
36
|
+
const format_1 = require("./formatting/format");
|
|
37
|
+
const compileFlags_1 = require("../require/compileFlags");
|
|
38
|
+
const measure_1 = require("./profiling/measure");
|
|
39
|
+
const Zip_1 = require("./Zip");
|
|
40
|
+
const protocolNegotiation_1 = require("./protocolNegotiation");
|
|
41
|
+
setImmediate(() => Promise.resolve().then(() => __importStar(require("./lz4/LZ4"))));
|
|
42
|
+
(0, compileFlags_1.setFlag)(require, "pako", "allowclient", true);
|
|
43
|
+
// NOTE: If it is too low, and too many servers disconnect, we can easily spend 100% of our time
|
|
44
|
+
// trying to reconnect.
|
|
45
|
+
// (Or... maybe the delay is just waiting, and we aren't actually overloading the server?)
|
|
46
|
+
const MIN_RETRY_DELAY = 5000;
|
|
47
|
+
const INITIALIZE_STATE_SEQ_NUM = -1;
|
|
48
|
+
let pendingCallCount = 0;
|
|
49
|
+
let harvestableFailedCalls = 0;
|
|
50
|
+
const CALL_TIMES_LIMIT = 1000 * 1000 * 10;
|
|
51
|
+
let harvestableCallTimes = [];
|
|
52
|
+
function harvestFailedCallCount() {
|
|
53
|
+
let count = harvestableFailedCalls;
|
|
54
|
+
harvestableFailedCalls = 0;
|
|
55
|
+
return count;
|
|
56
|
+
}
|
|
57
|
+
exports.harvestFailedCallCount = harvestFailedCallCount;
|
|
58
|
+
function getPendingCallCount() {
|
|
59
|
+
return pendingCallCount;
|
|
60
|
+
}
|
|
61
|
+
exports.getPendingCallCount = getPendingCallCount;
|
|
62
|
+
function harvestCallTimes() {
|
|
63
|
+
let times = harvestableCallTimes;
|
|
64
|
+
harvestableCallTimes = [];
|
|
65
|
+
return times;
|
|
66
|
+
}
|
|
67
|
+
exports.harvestCallTimes = harvestCallTimes;
|
|
68
|
+
(0, batching_1.runInfinitePoll)(misc_1.timeInMinute * 15, () => {
|
|
69
|
+
if (harvestableCallTimes.length > CALL_TIMES_LIMIT) {
|
|
70
|
+
harvestableCallTimes = harvestableCallTimes.slice(-CALL_TIMES_LIMIT);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
async function createCallFactory(webSocketBase,
|
|
74
|
+
// The node id we are connecting to (or that connected to us)
|
|
75
|
+
nodeId,
|
|
76
|
+
// The node id that we were contacted on
|
|
77
|
+
localNodeId = "") {
|
|
78
|
+
let niceConnectionName = nodeId;
|
|
79
|
+
const createWebsocket = (0, websocketFactory_1.createWebsocketFactory)();
|
|
80
|
+
const registerOnce = (0, caching_1.lazy)(() => (0, nodeCache_1.registerNodeClient)(callFactory));
|
|
81
|
+
let canReconnect = !!(0, nodeCache_1.getNodeIdLocation)(nodeId);
|
|
82
|
+
let pendingCalls = new Map();
|
|
83
|
+
// NOTE: It is important to make this as random as possible, to prevent
|
|
84
|
+
// reconnections dues to a process being reset causing seqNum collisions
|
|
85
|
+
// in return calls.
|
|
86
|
+
let nextSeqNum = Date.now() + Math.random();
|
|
87
|
+
// NOTE: I'm not sure if this is needed, I thought it was, but... now I think
|
|
88
|
+
// it probably isn't...
|
|
89
|
+
// if (webSocketBase?.readyState === 1 /* OPEN */ && webSocketBase.ping) {
|
|
90
|
+
// // Heartbeat loop, otherwise onDisconnect is never called.
|
|
91
|
+
// ((async () => {
|
|
92
|
+
// while (webSocketBase?.readyState === 1 /* OPEN */ && webSocketBase.ping) {
|
|
93
|
+
// await delay(1000 * 60);
|
|
94
|
+
// webSocketBase.ping?.();
|
|
95
|
+
// }
|
|
96
|
+
// }))().catch(() => { });
|
|
97
|
+
// }
|
|
98
|
+
let lastConnectionAttempt = 0;
|
|
99
|
+
let callerContext = {
|
|
100
|
+
nodeId,
|
|
101
|
+
localNodeId
|
|
102
|
+
};
|
|
103
|
+
let disconnectCallbacks = new Set();
|
|
104
|
+
function onNextDisconnect(callback) {
|
|
105
|
+
disconnectCallbacks.add(callback);
|
|
106
|
+
}
|
|
107
|
+
let callFactory = {
|
|
108
|
+
nodeId,
|
|
109
|
+
lastClosed: 0,
|
|
110
|
+
connectionId: { nodeId },
|
|
111
|
+
receivedInitializeState: undefined,
|
|
112
|
+
onNextDisconnect,
|
|
113
|
+
disconnect() {
|
|
114
|
+
canReconnect = false;
|
|
115
|
+
callFactory.closedForever = true;
|
|
116
|
+
if (webSocketPromise) {
|
|
117
|
+
webSocketPromise.then(ws => ws.close()).catch(() => { });
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
async performCall(call) {
|
|
121
|
+
var _a;
|
|
122
|
+
let seqNum = nextSeqNum++;
|
|
123
|
+
let fullCall = {
|
|
124
|
+
nodeId,
|
|
125
|
+
isReturn: false,
|
|
126
|
+
args: call.args,
|
|
127
|
+
classGuid: call.classGuid,
|
|
128
|
+
functionName: call.functionName,
|
|
129
|
+
seqNum,
|
|
130
|
+
};
|
|
131
|
+
let data;
|
|
132
|
+
let originalArgs = call.args;
|
|
133
|
+
let time = Date.now();
|
|
134
|
+
let sendStats = {
|
|
135
|
+
uncompressedSize: 0,
|
|
136
|
+
compressedSize: 0,
|
|
137
|
+
};
|
|
138
|
+
try {
|
|
139
|
+
if ((_a = callFactory.receivedInitializeState) === null || _a === void 0 ? void 0 : _a.supportsLZ4) {
|
|
140
|
+
let compressMode = (0, callManager_1.shouldCompressCall)(fullCall);
|
|
141
|
+
// If it's undefined, then we compress it. We basically always want to compress from now on, because LZ4 is so fast.
|
|
142
|
+
if (compressMode !== false) {
|
|
143
|
+
fullCall.args = await compressObjLZ4(fullCall.args, sendStats);
|
|
144
|
+
fullCall.isArgsCompressed = "LZ4";
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
if ((0, callManager_1.shouldCompressCall)(fullCall)) {
|
|
149
|
+
fullCall.args = await compressObj(fullCall.args, sendStats);
|
|
150
|
+
fullCall.isArgsCompressed = "zip";
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
let dataMaybePromise = SocketFunction_1.SocketFunction.WIRE_SERIALIZER.serialize(fullCall);
|
|
154
|
+
if (dataMaybePromise instanceof Promise) {
|
|
155
|
+
data = await dataMaybePromise;
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
data = dataMaybePromise;
|
|
159
|
+
}
|
|
160
|
+
if (!sendStats.compressedSize) {
|
|
161
|
+
let totalSize = 0;
|
|
162
|
+
for (let d of data) {
|
|
163
|
+
totalSize += d.length;
|
|
164
|
+
}
|
|
165
|
+
sendStats.uncompressedSize = totalSize;
|
|
166
|
+
sendStats.compressedSize = totalSize;
|
|
167
|
+
}
|
|
168
|
+
addSendStats(sendStats);
|
|
169
|
+
}
|
|
170
|
+
catch (e) {
|
|
171
|
+
throw new Error(`Error serializing data for call ${call.classGuid}.${call.functionName}\n${e.stack}`);
|
|
172
|
+
}
|
|
173
|
+
time = Date.now() - time;
|
|
174
|
+
let size = data.map(x => x.length).reduce((a, b) => a + b, 0);
|
|
175
|
+
if (time > SocketFunction_1.SocketFunction.WIRE_WARN_TIME) {
|
|
176
|
+
console.log((0, logColors_1.red)(`Slow serialize, took ${(0, format_1.formatTime)(time)} to serialize ${(0, format_1.formatNumber)(size)} bytes. For ${call.classGuid}.${call.functionName}`));
|
|
177
|
+
}
|
|
178
|
+
if (size > SocketFunction_1.SocketFunction.MAX_MESSAGE_SIZE * 1.5) {
|
|
179
|
+
let splitArgIndex = originalArgs.findIndex(fixLargeNetworkCalls_1.isSplitableArray);
|
|
180
|
+
if (splitArgIndex >= 0) {
|
|
181
|
+
console.log((0, logColors_1.yellow)(`Splitting large call due to large args: ${call.classGuid}.${call.functionName}`));
|
|
182
|
+
let SPLIT_GROUPS = 10;
|
|
183
|
+
let splitArg = originalArgs[splitArgIndex];
|
|
184
|
+
let subCalls = (0, misc_1.list)(SPLIT_GROUPS).map(index => {
|
|
185
|
+
let start = Math.floor(index / SPLIT_GROUPS * splitArg.length);
|
|
186
|
+
let end = Math.floor((index + 1) / SPLIT_GROUPS * splitArg.length);
|
|
187
|
+
return splitArg.slice(start, end);
|
|
188
|
+
}).filter(x => x.length > 0);
|
|
189
|
+
let calls = subCalls.map(async (splitList) => {
|
|
190
|
+
let subCall = { ...call };
|
|
191
|
+
subCall.args = subCall.args.slice();
|
|
192
|
+
subCall.args[splitArgIndex] = (0, fixLargeNetworkCalls_1.markArrayAsSplitable)(splitList);
|
|
193
|
+
await callFactory.performCall(subCall);
|
|
194
|
+
});
|
|
195
|
+
await Promise.allSettled(calls);
|
|
196
|
+
await Promise.all(calls);
|
|
197
|
+
// Eh... we COULD return the array of results, but... then the result would sometimes be an array,
|
|
198
|
+
// some times not, so, it is better to return a string which will make it more clear why it sometimes varies.
|
|
199
|
+
return "CALLS_SPLIT_DUE_TO_LARGE_ARGS";
|
|
200
|
+
}
|
|
201
|
+
throw new Error(`Call too large to send (${call.classGuid}.${call.functionName}, size: ${(0, format_1.formatNumber)(size)} > ${(0, format_1.formatNumber)(SocketFunction_1.SocketFunction.MAX_MESSAGE_SIZE)}). If you need to handle very large static data use some external service, such as Backblaze B2 or AWS S3. Or consider fragmenting data at an application level, because sending large data will cause large lag spikes for other clients using this server. Or, if absolutely required, set SocketFunction.MAX_MESSAGE_SIZE to a higher value.`);
|
|
202
|
+
}
|
|
203
|
+
let resultPromise = new Promise((resolve, reject) => {
|
|
204
|
+
let startTime = Date.now();
|
|
205
|
+
pendingCallCount++;
|
|
206
|
+
let callback = (result) => {
|
|
207
|
+
pendingCallCount--;
|
|
208
|
+
pendingCalls.delete(seqNum);
|
|
209
|
+
harvestableCallTimes.push({ start: startTime, end: Date.now(), });
|
|
210
|
+
if (result.error) {
|
|
211
|
+
reject((0, misc_1.convertErrorStackToError)(result.error));
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
resolve(result.result);
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
pendingCalls.set(seqNum, { callback, data, call: fullCall });
|
|
218
|
+
});
|
|
219
|
+
{
|
|
220
|
+
let resultSize = data.map(x => x.length).reduce((a, b) => a + b, 0);
|
|
221
|
+
for (let callback of SocketFunction_1.SocketFunction.trackMessageSizes.upload) {
|
|
222
|
+
callback(resultSize);
|
|
223
|
+
}
|
|
224
|
+
if (SocketFunction_1.SocketFunction.logMessages) {
|
|
225
|
+
let fncHack = "";
|
|
226
|
+
if (call.functionName === "addCall") {
|
|
227
|
+
let arg = originalArgs[0];
|
|
228
|
+
fncHack = `.${arg.DomainName}.${arg.ModuleId}.${arg.FunctionId}`;
|
|
229
|
+
}
|
|
230
|
+
console.log(`SIZE\t${((0, misc_1.formatNumberSuffixed)(resultSize) + `B`).padEnd(4, " ")}\t${(0, format_1.formatNumber)(data.length)} buffers\tREMOTE CALL\t${call.classGuid}.${call.functionName}${fncHack} at ${Date.now()}`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
// If sending OR resultPromise throws, we want to error out. This solves some issues with resultPromise
|
|
234
|
+
// erroring out first, which is before we await it, which makes NodeJS angry (unhandled promise rejection).
|
|
235
|
+
// Also, technically, we could receive the result before we finish sending, in which case, we might
|
|
236
|
+
// as well return it immediately.
|
|
237
|
+
await Promise.race([send(data), resultPromise]);
|
|
238
|
+
return await resultPromise;
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
let webSocketPromise;
|
|
242
|
+
let hasEverConnected = false;
|
|
243
|
+
if (webSocketBase) {
|
|
244
|
+
webSocketPromise = Promise.resolve(webSocketBase);
|
|
245
|
+
await initializeWebsocket(webSocketBase);
|
|
246
|
+
}
|
|
247
|
+
async function initializeWebsocket(newWebSocket, skipCloseHandling = false) {
|
|
248
|
+
registerOnce();
|
|
249
|
+
callFactory.receivedInitializeState = undefined;
|
|
250
|
+
function onClose(error) {
|
|
251
|
+
// We try various connections, and if they fail, we will just try other node IDs until we finally do connect, and then we stick with that nodeId, and when it disconnects we need to handle disconnections normally.
|
|
252
|
+
if (skipCloseHandling && !hasEverConnected) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
callFactory.connectionId = { nodeId };
|
|
256
|
+
callFactory.lastClosed = Date.now();
|
|
257
|
+
callFactory.isConnected = false;
|
|
258
|
+
webSocketPromise = undefined;
|
|
259
|
+
if (!canReconnect) {
|
|
260
|
+
callFactory.closedForever = true;
|
|
261
|
+
}
|
|
262
|
+
for (let [key, call] of pendingCalls) {
|
|
263
|
+
harvestableFailedCalls++;
|
|
264
|
+
pendingCalls.delete(key);
|
|
265
|
+
call.callback({
|
|
266
|
+
isReturn: true,
|
|
267
|
+
result: undefined,
|
|
268
|
+
error: error,
|
|
269
|
+
seqNum: call.call.seqNum,
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
let callbacks = disconnectCallbacks;
|
|
273
|
+
disconnectCallbacks = new Set();
|
|
274
|
+
for (let callback of callbacks) {
|
|
275
|
+
try {
|
|
276
|
+
callback();
|
|
277
|
+
}
|
|
278
|
+
catch (_a) { }
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
newWebSocket.addEventListener("error", e => {
|
|
282
|
+
// NOTE: No more logging, as we throw, so the caller should be logging the
|
|
283
|
+
// error (or swallowing it, if that is what it wants to do).
|
|
284
|
+
//console.log(`Websocket error for ${niceConnectionName}`, e.message);
|
|
285
|
+
onClose(new Error(`Connection error for ${niceConnectionName}: ${e.message}`).stack);
|
|
286
|
+
});
|
|
287
|
+
newWebSocket.addEventListener("close", async () => {
|
|
288
|
+
//console.log(`Websocket closed ${niceConnectionName}`);
|
|
289
|
+
onClose(new Error(`Connection closed to ${niceConnectionName}`).stack);
|
|
290
|
+
});
|
|
291
|
+
newWebSocket.addEventListener("message", onMessage);
|
|
292
|
+
if (newWebSocket.readyState === 0 /* CONNECTING */) {
|
|
293
|
+
await new Promise(resolve => {
|
|
294
|
+
newWebSocket.addEventListener("open", () => {
|
|
295
|
+
if (!SocketFunction_1.SocketFunction.silent) {
|
|
296
|
+
console.log(`Connection established to ${niceConnectionName}`);
|
|
297
|
+
}
|
|
298
|
+
callFactory.isConnected = true;
|
|
299
|
+
hasEverConnected = true;
|
|
300
|
+
resolve();
|
|
301
|
+
});
|
|
302
|
+
newWebSocket.addEventListener("close", () => resolve());
|
|
303
|
+
newWebSocket.addEventListener("error", () => resolve());
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
else if (newWebSocket.readyState === 1 /* OPEN */) {
|
|
307
|
+
callFactory.isConnected = true;
|
|
308
|
+
hasEverConnected = true;
|
|
309
|
+
}
|
|
310
|
+
else {
|
|
311
|
+
onClose(new Error(`Websocket received in closed state`).stack);
|
|
312
|
+
}
|
|
313
|
+
if (callFactory.lastClosed && callFactory.isConnected) {
|
|
314
|
+
console.log(`Successfully reconnected to ${nodeId}, which has been closed for ${(0, format_1.formatTime)(Date.now() - callFactory.lastClosed)}`, { nodeId });
|
|
315
|
+
}
|
|
316
|
+
if (callFactory.isConnected && newWebSocket.protocol) {
|
|
317
|
+
let decoded = (0, protocolNegotiation_1.decodeProtocol)(newWebSocket.protocol);
|
|
318
|
+
if (decoded) {
|
|
319
|
+
callFactory.receivedInitializeState = {
|
|
320
|
+
supportsLZ4: decoded.flags.serverLZ4,
|
|
321
|
+
};
|
|
322
|
+
callFactory.protocolNegotiated = true;
|
|
323
|
+
if (SocketFunction_1.SocketFunction.logMessages) {
|
|
324
|
+
console.log((0, logColors_1.green)(`Negotiated protocol with ${niceConnectionName}: target=${decoded.target}, clientLZ4=${decoded.flags.clientLZ4}, serverLZ4=${decoded.flags.serverLZ4}`));
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
const BASE_LENGTH_OFFSET = 324432461592612;
|
|
330
|
+
let sendInSerial = (0, batching_1.runInSerial)(async (val) => val());
|
|
331
|
+
async function sendRaw(data) {
|
|
332
|
+
if (!webSocketPromise) {
|
|
333
|
+
if (canReconnect) {
|
|
334
|
+
webSocketPromise = tryToReconnect();
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
throw new Error(`Cannot send data to ${niceConnectionName} as the connection has closed`);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
let webSocket = await webSocketPromise;
|
|
341
|
+
await sendInSerial(async () => {
|
|
342
|
+
for (let d of data) {
|
|
343
|
+
if (d.length > 1000 * 1000 * 10) {
|
|
344
|
+
console.log(`Sending large packet ${(0, format_1.formatNumber)(d.length)}B to ${nodeId} at ${Date.now()}`);
|
|
345
|
+
}
|
|
346
|
+
// NOTE: If our latency is 500ms, with 10MB/s, then we need a high water
|
|
347
|
+
// mark of at least 5MB, otherwise our connection is slowed down.
|
|
348
|
+
// - Using the actual high water mark is too difficult, as we receive incoming connections.
|
|
349
|
+
// This is also easier to configure, and we can dynamically change it if we have to.
|
|
350
|
+
// NOTE: In practice we only hit this when sending large Buffers (~30MB), so low values
|
|
351
|
+
// are equivalent to waiting for drain. We want to avoid waiting for drain, so we use a high value.
|
|
352
|
+
const maxWriteBuffer = 128 * 1024 * 1024;
|
|
353
|
+
webSocket.send(d);
|
|
354
|
+
let socket = webSocket._socket;
|
|
355
|
+
if (socket) {
|
|
356
|
+
while (socket.writableLength > maxWriteBuffer) {
|
|
357
|
+
// NOTE: Waiting 1ms probably waits more like 16ms.
|
|
358
|
+
await new Promise(r => setTimeout(r, 1));
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
async function send(data) {
|
|
365
|
+
await sendRaw([
|
|
366
|
+
(data.length + BASE_LENGTH_OFFSET).toString(),
|
|
367
|
+
...data,
|
|
368
|
+
]);
|
|
369
|
+
}
|
|
370
|
+
async function sendWithHeader(data, header) {
|
|
371
|
+
if (data.some(x => x.length > SocketFunction_1.SocketFunction.MAX_MESSAGE_SIZE * 1.5)) {
|
|
372
|
+
if (header.type === "Buffer" || header.type === "Buffer[]") {
|
|
373
|
+
header.bufferLengths = data.map(x => x.length);
|
|
374
|
+
let fitBuffers = [];
|
|
375
|
+
for (let buf of data) {
|
|
376
|
+
if (buf.length > SocketFunction_1.SocketFunction.MAX_MESSAGE_SIZE) {
|
|
377
|
+
let offset = 0;
|
|
378
|
+
while (offset < buf.length) {
|
|
379
|
+
fitBuffers.push(buf.slice(offset, offset + SocketFunction_1.SocketFunction.MAX_MESSAGE_SIZE));
|
|
380
|
+
offset += SocketFunction_1.SocketFunction.MAX_MESSAGE_SIZE;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
fitBuffers.push(buf);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
data = fitBuffers;
|
|
388
|
+
header.bufferCount = fitBuffers.length;
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
throw new Error(`Cannot send large amounts of data unless we are returning Buffer or Buffer[]`);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
// if (totalResultSize > SocketFunction.MAX_MESSAGE_SIZE * 1.5) {
|
|
395
|
+
// Split up Buffer[] if they are too large
|
|
396
|
+
await sendRaw([
|
|
397
|
+
JSON.stringify(header),
|
|
398
|
+
...data,
|
|
399
|
+
]);
|
|
400
|
+
}
|
|
401
|
+
// IMPORTANT! NEVER allow for reconnection of client ids. A lot of code depends on the fact that clients will reconnect with a new client node id when they disconnect!
|
|
402
|
+
async function tryToReconnect() {
|
|
403
|
+
// Don't try to reconnect too often!
|
|
404
|
+
let timeSinceLastAttempt = Date.now() - lastConnectionAttempt;
|
|
405
|
+
if (timeSinceLastAttempt < MIN_RETRY_DELAY) {
|
|
406
|
+
await new Promise(r => setTimeout(r, MIN_RETRY_DELAY - timeSinceLastAttempt));
|
|
407
|
+
}
|
|
408
|
+
lastConnectionAttempt = Date.now();
|
|
409
|
+
// Try alternates, and if any work, use them.
|
|
410
|
+
try {
|
|
411
|
+
let alternates = await SocketFunction_1.SocketFunction.GET_ALTERNATE_NODE_IDS(nodeId);
|
|
412
|
+
if (alternates) {
|
|
413
|
+
for (let alternateNodeId of alternates) {
|
|
414
|
+
let newWebSocket = createWebsocket(alternateNodeId, (0, protocolNegotiation_1.proposeProtocols)((0, misc_1.isNode)() ? nodeId : undefined, { lz4: true }));
|
|
415
|
+
await initializeWebsocket(newWebSocket, true);
|
|
416
|
+
if (callFactory.isConnected) {
|
|
417
|
+
return newWebSocket;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
catch (e) {
|
|
423
|
+
console.error("Error getting alternate node IDs", e);
|
|
424
|
+
}
|
|
425
|
+
let newWebSocket = createWebsocket(nodeId, (0, protocolNegotiation_1.proposeProtocols)(!SocketFunction_1.SocketFunction.isClient() ? nodeId : undefined, { lz4: true }));
|
|
426
|
+
await initializeWebsocket(newWebSocket);
|
|
427
|
+
return newWebSocket;
|
|
428
|
+
}
|
|
429
|
+
let pendingCall;
|
|
430
|
+
async function processPendingCall() {
|
|
431
|
+
var _a, _b;
|
|
432
|
+
if (!pendingCall)
|
|
433
|
+
throw new Error(`No pending call`);
|
|
434
|
+
let currentCall = pendingCall;
|
|
435
|
+
pendingCall = undefined;
|
|
436
|
+
let currentBuffers = currentCall.buffers;
|
|
437
|
+
let call;
|
|
438
|
+
let resultSize;
|
|
439
|
+
let time = Date.now();
|
|
440
|
+
if (currentCall.type === "Buffer" || currentCall.type === "Buffer[]") {
|
|
441
|
+
let result = currentBuffers;
|
|
442
|
+
if (currentCall.bufferLengths) {
|
|
443
|
+
let pendingBuffers = currentBuffers;
|
|
444
|
+
function takeBuffer(len) {
|
|
445
|
+
let lenLeft = len;
|
|
446
|
+
let buffers = [];
|
|
447
|
+
while (lenLeft > 0) {
|
|
448
|
+
let buf = currentBuffers.shift();
|
|
449
|
+
if (!buf) {
|
|
450
|
+
throw new Error(`Not enough buffers received.`);
|
|
451
|
+
}
|
|
452
|
+
if (buf.length > lenLeft) {
|
|
453
|
+
buffers.push(buf.slice(0, lenLeft));
|
|
454
|
+
currentBuffers.unshift(buf.slice(lenLeft));
|
|
455
|
+
break;
|
|
456
|
+
}
|
|
457
|
+
else {
|
|
458
|
+
buffers.push(buf);
|
|
459
|
+
lenLeft -= buf.length;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
if (buffers.length === 1) {
|
|
463
|
+
return buffers[0];
|
|
464
|
+
}
|
|
465
|
+
return Buffer.concat(buffers);
|
|
466
|
+
}
|
|
467
|
+
result = currentCall.bufferLengths.map(takeBuffer);
|
|
468
|
+
if (pendingBuffers.length > 0) {
|
|
469
|
+
throw new Error(`Received too many buffers.`);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
resultSize = result.map(x => x.length).reduce((a, b) => a + b, 0);
|
|
473
|
+
if (currentCall.type === "Buffer") {
|
|
474
|
+
if (result.length === 1) {
|
|
475
|
+
result = result[0];
|
|
476
|
+
}
|
|
477
|
+
else {
|
|
478
|
+
result = Buffer.concat(result);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
call = {
|
|
482
|
+
...currentCall.metadata,
|
|
483
|
+
result,
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
else {
|
|
487
|
+
resultSize = currentBuffers.map(x => x.length).reduce((a, b) => a + b, 0);
|
|
488
|
+
call = await SocketFunction_1.SocketFunction.WIRE_SERIALIZER.deserialize(currentBuffers);
|
|
489
|
+
}
|
|
490
|
+
let parseTime = Date.now() - time;
|
|
491
|
+
for (let callback of SocketFunction_1.SocketFunction.trackMessageSizes.download) {
|
|
492
|
+
callback(resultSize);
|
|
493
|
+
}
|
|
494
|
+
let receiveStats = {
|
|
495
|
+
uncompressedSize: resultSize,
|
|
496
|
+
compressedSize: resultSize,
|
|
497
|
+
};
|
|
498
|
+
let sendStats = {
|
|
499
|
+
uncompressedSize: 0,
|
|
500
|
+
compressedSize: 0,
|
|
501
|
+
};
|
|
502
|
+
if (call.isReturn) {
|
|
503
|
+
// Tolerate the legacy initialize packet from old peers — silently
|
|
504
|
+
// ignore so it doesn't get logged as an unknown call. Our actual
|
|
505
|
+
// initialize state comes from Sec-WebSocket-Protocol negotiation.
|
|
506
|
+
if (call.seqNum === INITIALIZE_STATE_SEQ_NUM) {
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
let callbackObj = pendingCalls.get(call.seqNum);
|
|
510
|
+
if (parseTime > SocketFunction_1.SocketFunction.WIRE_WARN_TIME) {
|
|
511
|
+
console.log((0, logColors_1.red)(`Slow parse, took ${parseTime}ms to parse ${resultSize} bytes, for receiving result of call to ${callbackObj === null || callbackObj === void 0 ? void 0 : callbackObj.call.classGuid}.${callbackObj === null || callbackObj === void 0 ? void 0 : callbackObj.call.functionName}`));
|
|
512
|
+
}
|
|
513
|
+
if (!callbackObj) {
|
|
514
|
+
console.log((0, logColors_1.blue)(`Got return for unknown call ${call.seqNum} (created at time ${new Date(call.seqNum)}), ${nodeId} / ${localNodeId}`));
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
if (SocketFunction_1.SocketFunction.logMessages) {
|
|
518
|
+
let call = callbackObj.call;
|
|
519
|
+
console.log(`SIZE\t${((0, misc_1.formatNumberSuffixed)(resultSize) + "B").padEnd(4, " ")}\t${(0, format_1.formatNumber)(currentBuffers.length)} buffers\tRETURN\t${call.classGuid}.${call.functionName} at ${Date.now()}, (${nodeId} / ${localNodeId})`);
|
|
520
|
+
}
|
|
521
|
+
if (call.isResultCompressed === "LZ4") {
|
|
522
|
+
call.result = await decompressObjLZ4(call.result, receiveStats);
|
|
523
|
+
call.isResultCompressed = undefined;
|
|
524
|
+
}
|
|
525
|
+
else if (call.isResultCompressed === "zip" || call.isResultCompressed === true) {
|
|
526
|
+
call.result = await decompressObj(call.result, receiveStats);
|
|
527
|
+
call.isResultCompressed = undefined;
|
|
528
|
+
}
|
|
529
|
+
callbackObj.callback(call);
|
|
530
|
+
}
|
|
531
|
+
else {
|
|
532
|
+
if (call.isArgsCompressed === "LZ4") {
|
|
533
|
+
call.args = await decompressObjLZ4(call.args, sendStats);
|
|
534
|
+
call.isArgsCompressed = undefined;
|
|
535
|
+
}
|
|
536
|
+
else if (call.isArgsCompressed === "zip" || call.isArgsCompressed === true) {
|
|
537
|
+
call.args = await decompressObj(call.args, sendStats);
|
|
538
|
+
call.isArgsCompressed = undefined;
|
|
539
|
+
}
|
|
540
|
+
if (SocketFunction_1.SocketFunction.logMessages) {
|
|
541
|
+
console.log(`SIZE\t${((0, misc_1.formatNumberSuffixed)(resultSize) + "B").padEnd(4, " ")}\tEVALUATE\t${call.classGuid}.${call.functionName} at ${Date.now()}, (${nodeId} / ${localNodeId})`);
|
|
542
|
+
}
|
|
543
|
+
if (parseTime > SocketFunction_1.SocketFunction.WIRE_WARN_TIME) {
|
|
544
|
+
console.log((0, logColors_1.red)(`Slow parse, took ${parseTime}ms to parse ${resultSize} bytes, for call to ${call.classGuid}.${call.functionName}`));
|
|
545
|
+
}
|
|
546
|
+
let response;
|
|
547
|
+
try {
|
|
548
|
+
SocketFunction_1.SocketFunction.TOTAL_CALLS++;
|
|
549
|
+
let result = await (0, callManager_1.performLocalCall)({ call, caller: callerContext });
|
|
550
|
+
response = {
|
|
551
|
+
isReturn: true,
|
|
552
|
+
result,
|
|
553
|
+
seqNum: call.seqNum,
|
|
554
|
+
};
|
|
555
|
+
if (SocketFunction_1.SocketFunction.logMessages) {
|
|
556
|
+
let timeTaken = Date.now() - time;
|
|
557
|
+
console.log(`DUR\t${((0, format_1.formatTime)(timeTaken)).padEnd(6, " ")}\tFINISH\t${call.classGuid}.${call.functionName} at ${Date.now()}, (${nodeId} / ${localNodeId})`);
|
|
558
|
+
}
|
|
559
|
+
if ((_a = callFactory.receivedInitializeState) === null || _a === void 0 ? void 0 : _a.supportsLZ4) {
|
|
560
|
+
let compressMode = (0, callManager_1.shouldCompressCall)(call);
|
|
561
|
+
if (compressMode !== false) {
|
|
562
|
+
response.result = await compressObjLZ4(response.result, sendStats);
|
|
563
|
+
response.isResultCompressed = "LZ4";
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
else {
|
|
567
|
+
if ((0, callManager_1.shouldCompressCall)(call)) {
|
|
568
|
+
response.result = await compressObj(response.result, sendStats);
|
|
569
|
+
response.isResultCompressed = "zip";
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
catch (e) {
|
|
574
|
+
response = {
|
|
575
|
+
isReturn: true,
|
|
576
|
+
result: undefined,
|
|
577
|
+
seqNum: call.seqNum,
|
|
578
|
+
error: e.stack,
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
{
|
|
582
|
+
let start = time;
|
|
583
|
+
let end = Date.now();
|
|
584
|
+
for (let fnc of SocketFunction_1.SocketFunction.trackMessageSizes.callTimes) {
|
|
585
|
+
fnc({ start, end });
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
let size = 0;
|
|
589
|
+
if (response.result instanceof Buffer) {
|
|
590
|
+
let { result, ...remaining } = response;
|
|
591
|
+
size = result.length;
|
|
592
|
+
await sendWithHeader([result], { type: "Buffer", bufferCount: 1, metadata: remaining });
|
|
593
|
+
}
|
|
594
|
+
else if (Array.isArray(response.result) && response.result.every(x => x instanceof Buffer)) {
|
|
595
|
+
let { result, ...remaining } = response;
|
|
596
|
+
for (let r of result) {
|
|
597
|
+
size += r.length;
|
|
598
|
+
}
|
|
599
|
+
await sendWithHeader(result, { type: "Buffer[]", bufferCount: result.length, metadata: remaining });
|
|
600
|
+
}
|
|
601
|
+
else {
|
|
602
|
+
const LIMIT = ((_b = (0, callManager_1.getCallFlags)(call)) === null || _b === void 0 ? void 0 : _b.responseLimit) || SocketFunction_1.SocketFunction.MAX_MESSAGE_SIZE * 1.5;
|
|
603
|
+
let result = await SocketFunction_1.SocketFunction.WIRE_SERIALIZER.serialize(response);
|
|
604
|
+
let totalResultSize = result.map(x => x.length).reduce((a, b) => a + b, 0);
|
|
605
|
+
if (totalResultSize > LIMIT) {
|
|
606
|
+
response = {
|
|
607
|
+
isReturn: true,
|
|
608
|
+
result: undefined,
|
|
609
|
+
seqNum: call.seqNum,
|
|
610
|
+
error: new Error(`Response too large to send. Return Buffer[] to exceed the limits, or set responseLimit when registering the collection. ${call.classGuid}.${call.functionName}, size: ${(0, format_1.formatNumber)(totalResultSize)} > ${(0, format_1.formatNumber)(SocketFunction_1.SocketFunction.MAX_MESSAGE_SIZE)}. If you need to handle very large static data use some external service, such as Backblaze B2 or AWS S3. Or, if absolutely required, set SocketFunction.MAX_MESSAGE_SIZE to a higher value.`).stack,
|
|
611
|
+
};
|
|
612
|
+
result = await SocketFunction_1.SocketFunction.WIRE_SERIALIZER.serialize(response);
|
|
613
|
+
}
|
|
614
|
+
for (let r of result) {
|
|
615
|
+
size += r.length;
|
|
616
|
+
}
|
|
617
|
+
await send(result);
|
|
618
|
+
}
|
|
619
|
+
// If we have no size, then it's probably uncompressed
|
|
620
|
+
if (!sendStats.compressedSize) {
|
|
621
|
+
sendStats.compressedSize = size;
|
|
622
|
+
sendStats.uncompressedSize = size;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
addSendStats(sendStats);
|
|
626
|
+
addReceiveStats(receiveStats);
|
|
627
|
+
}
|
|
628
|
+
let clientsideSerial = (0, batching_1.runInSerial)(async (val) => val);
|
|
629
|
+
async function onMessage(message) {
|
|
630
|
+
try {
|
|
631
|
+
if (typeof message === "object" && "data" in message) {
|
|
632
|
+
message = message.data;
|
|
633
|
+
}
|
|
634
|
+
// Extra clienside parsing is required
|
|
635
|
+
if (!(0, misc_1.isNode)()) {
|
|
636
|
+
// Immediately start the arrayBuffer conversion. This should be fast, but...
|
|
637
|
+
// maybe we will add more here, and so doing it in parallel might be useful.
|
|
638
|
+
let fixMessageBlob = (async () => {
|
|
639
|
+
if (message instanceof Blob) {
|
|
640
|
+
message = Buffer.from(await message.arrayBuffer());
|
|
641
|
+
}
|
|
642
|
+
})();
|
|
643
|
+
// We need to force the results to be in serial, otherwise strings leapfrog
|
|
644
|
+
// ahead of buffers, which breaks things.
|
|
645
|
+
await clientsideSerial(fixMessageBlob);
|
|
646
|
+
}
|
|
647
|
+
if (typeof message === "string") {
|
|
648
|
+
if (message.startsWith("{")) {
|
|
649
|
+
let obj = JSON.parse(message);
|
|
650
|
+
pendingCall = {
|
|
651
|
+
...obj,
|
|
652
|
+
buffers: [],
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
else {
|
|
656
|
+
let count = parseInt(message);
|
|
657
|
+
if (isNaN(count)) {
|
|
658
|
+
throw new Error(`Invalid message count ${message}`);
|
|
659
|
+
}
|
|
660
|
+
if (count < BASE_LENGTH_OFFSET) {
|
|
661
|
+
throw new Error(`Invalid message count ${message}`);
|
|
662
|
+
}
|
|
663
|
+
count -= BASE_LENGTH_OFFSET;
|
|
664
|
+
if (count > 1000 * 1000) {
|
|
665
|
+
throw new Error(`Invalid message count ${count}`);
|
|
666
|
+
}
|
|
667
|
+
pendingCall = {
|
|
668
|
+
buffers: [],
|
|
669
|
+
bufferCount: count,
|
|
670
|
+
type: "serialized",
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
if ((pendingCall === null || pendingCall === void 0 ? void 0 : pendingCall.bufferCount) === 0) {
|
|
674
|
+
await processPendingCall();
|
|
675
|
+
}
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
678
|
+
if (message instanceof Buffer) {
|
|
679
|
+
if (!pendingCall) {
|
|
680
|
+
throw new Error(`Received data without size ${message.byteLength}B, first 100 bytes: ${message.slice(0, 100).toString("hex")}`);
|
|
681
|
+
}
|
|
682
|
+
let totalSize = message.byteLength + pendingCall.buffers.reduce((a, b) => a + b.length, 0);
|
|
683
|
+
if (totalSize > 1000 * 1000 * 10 || pendingCall.bufferCount > 1000 && (pendingCall.buffers.length % 100 === 0)) {
|
|
684
|
+
if (pendingCall.buffers.length === 0) {
|
|
685
|
+
console.log(`Received large/many packets ${(0, format_1.formatNumber)(totalSize)}B (${pendingCall.buffers.length} / ${pendingCall.bufferCount}) at ${Date.now()}`);
|
|
686
|
+
}
|
|
687
|
+
else {
|
|
688
|
+
let elapsed = Date.now() - (pendingCall.firstReceivedTime || 0);
|
|
689
|
+
console.log(`Received large/many packets ${(0, format_1.formatNumber)(totalSize)}B (${pendingCall.buffers.length} / ${pendingCall.bufferCount}) after ${(0, format_1.formatTime)(elapsed)}`);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
if (pendingCall.buffers.length === 0) {
|
|
693
|
+
pendingCall.firstReceivedTime = Date.now();
|
|
694
|
+
}
|
|
695
|
+
pendingCall.buffers.push(message);
|
|
696
|
+
if (pendingCall.buffers.length !== pendingCall.bufferCount) {
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
await processPendingCall();
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
702
|
+
throw new Error(`Unhandled data type ${typeof message}`);
|
|
703
|
+
}
|
|
704
|
+
catch (e) {
|
|
705
|
+
let err = e.stack || e.message || e;
|
|
706
|
+
// NOTE: I'm looking for all types of errors here (specifically, .send errors), in case
|
|
707
|
+
// there are errors I should be handling.
|
|
708
|
+
if (err.startsWith("Error: Cannot send data to") && err.includes("as the connection has closed")) {
|
|
709
|
+
// This is fine, just ignore it
|
|
710
|
+
}
|
|
711
|
+
else if (err.includes("The requested file could not be read, typically due to permission problems that have occurred after a reference to a file was acquired.")) {
|
|
712
|
+
console.error(`WebSocket data was dropped by the browser due to exceeding the Blob limit. Either you are about to run out of memory, or you hit the much lower Incognito Blob limit. This will likely break the application. To reset the memory you must close all tabs of this site. This is a bug/feature in chrome.`);
|
|
713
|
+
}
|
|
714
|
+
else {
|
|
715
|
+
console.error(e.stack);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
return callFactory;
|
|
720
|
+
}
|
|
721
|
+
exports.createCallFactory = createCallFactory;
|
|
722
|
+
let uncompressedSent = 0;
|
|
723
|
+
let compressedSent = 0;
|
|
724
|
+
let uncompressedReceived = 0;
|
|
725
|
+
let compressedReceived = 0;
|
|
726
|
+
let sendCount = 0;
|
|
727
|
+
let receiveCount = 0;
|
|
728
|
+
function addSendStats(stats) {
|
|
729
|
+
uncompressedSent += stats.uncompressedSize;
|
|
730
|
+
compressedSent += stats.compressedSize;
|
|
731
|
+
sendCount++;
|
|
732
|
+
}
|
|
733
|
+
function addReceiveStats(stats) {
|
|
734
|
+
uncompressedReceived += stats.uncompressedSize;
|
|
735
|
+
compressedReceived += stats.compressedSize;
|
|
736
|
+
receiveCount++;
|
|
737
|
+
}
|
|
738
|
+
function getStats() {
|
|
739
|
+
return {
|
|
740
|
+
uncompressedSent,
|
|
741
|
+
compressedSent,
|
|
742
|
+
uncompressedReceived,
|
|
743
|
+
compressedReceived,
|
|
744
|
+
sendCount,
|
|
745
|
+
receiveCount,
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
exports.getStats = getStats;
|
|
749
|
+
// Register this late as I don't want it to appear before the memory register info, which is use more useful than the network one.
|
|
750
|
+
setImmediate(() => {
|
|
751
|
+
(0, measure_1.registerMeasureInfo)(() => `NET => ${(0, format_1.formatNumber)(compressedSent)}B (${(0, format_1.formatNumber)(uncompressedSent)}B/${(0, format_1.formatNumber)(sendCount)}) / <= ${(0, format_1.formatNumber)(compressedReceived)}B (${(0, format_1.formatNumber)(uncompressedReceived)}B/${(0, format_1.formatNumber)(receiveCount)})`);
|
|
752
|
+
});
|
|
753
|
+
const compressObj = (0, measure_1.measureWrap)(async function wireCallCompress(obj, stats) {
|
|
754
|
+
let buffers = await SocketFunction_1.SocketFunction.WIRE_SERIALIZER.serialize(obj);
|
|
755
|
+
if (buffers.length > 1) {
|
|
756
|
+
throw new Error("Legacy CompressObj only supports single buffer");
|
|
757
|
+
}
|
|
758
|
+
let lengthBuffer = Buffer.from((new Float64Array(buffers.map(x => x.length))).buffer);
|
|
759
|
+
let buffer = Buffer.concat([lengthBuffer, ...buffers]);
|
|
760
|
+
stats.uncompressedSize += buffer.length;
|
|
761
|
+
let result = await Zip_1.Zip.gzip(buffer);
|
|
762
|
+
stats.compressedSize += result.length;
|
|
763
|
+
return result;
|
|
764
|
+
});
|
|
765
|
+
// Assumes the caller already added the obj.length to both the uncompressedSize and compressedSize, and is just looking to update the uncompressedSize to be larger according to the size after we uncompress
|
|
766
|
+
const decompressObj = (0, measure_1.measureWrap)(async function wireCallDecompress(obj, stats) {
|
|
767
|
+
let buffer = await Zip_1.Zip.gunzip(obj);
|
|
768
|
+
stats.uncompressedSize += buffer.length - obj.length;
|
|
769
|
+
let lengthBuffer = buffer.slice(0, 8);
|
|
770
|
+
let lengths = new Float64Array(lengthBuffer.buffer, lengthBuffer.byteOffset, lengthBuffer.byteLength / 8);
|
|
771
|
+
let buffers = [];
|
|
772
|
+
let offset = 8;
|
|
773
|
+
for (let length of lengths) {
|
|
774
|
+
buffers.push(buffer.slice(offset, offset + length));
|
|
775
|
+
offset += length;
|
|
776
|
+
}
|
|
777
|
+
let result = await SocketFunction_1.SocketFunction.WIRE_SERIALIZER.deserialize(buffers);
|
|
778
|
+
return result;
|
|
779
|
+
});
|
|
780
|
+
const compressObjLZ4 = (0, measure_1.measureWrap)(async function wireCallCompressLZ4(obj, stats) {
|
|
781
|
+
const { LZ4 } = await Promise.resolve().then(() => __importStar(require("./lz4/LZ4")));
|
|
782
|
+
let headerParts;
|
|
783
|
+
let dataBuffers;
|
|
784
|
+
if (obj instanceof Buffer) {
|
|
785
|
+
headerParts = [1];
|
|
786
|
+
dataBuffers = [obj];
|
|
787
|
+
}
|
|
788
|
+
else if (Array.isArray(obj) && obj.every((x) => x instanceof Buffer)) {
|
|
789
|
+
let bufferArray = obj;
|
|
790
|
+
const TARGET_SIZE = 50 * 1024 * 1024;
|
|
791
|
+
const MIN_INDIVIDUAL_SIZE = 10 * 1024 * 1024;
|
|
792
|
+
const MAX_UNSPLIT_SIZE = 100 * 1024 * 1024;
|
|
793
|
+
let outputBuffers = [];
|
|
794
|
+
let outputDescriptors = [];
|
|
795
|
+
let currentGroup = [];
|
|
796
|
+
let currentGroupSize = 0;
|
|
797
|
+
function flushCurrentGroup() {
|
|
798
|
+
if (currentGroup.length > 0) {
|
|
799
|
+
outputBuffers.push(Buffer.concat(currentGroup));
|
|
800
|
+
outputDescriptors.push(currentGroup.map(b => b.length));
|
|
801
|
+
currentGroup = [];
|
|
802
|
+
currentGroupSize = 0;
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
for (let buf of bufferArray) {
|
|
806
|
+
if (buf.length >= MIN_INDIVIDUAL_SIZE) {
|
|
807
|
+
flushCurrentGroup();
|
|
808
|
+
if (buf.length > MAX_UNSPLIT_SIZE) {
|
|
809
|
+
let offset = 0;
|
|
810
|
+
while (offset < buf.length) {
|
|
811
|
+
let chunkSize = Math.min(TARGET_SIZE, buf.length - offset);
|
|
812
|
+
outputBuffers.push(buf.slice(offset, offset + chunkSize));
|
|
813
|
+
outputDescriptors.push([chunkSize]);
|
|
814
|
+
offset += chunkSize;
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
else {
|
|
818
|
+
outputBuffers.push(buf);
|
|
819
|
+
outputDescriptors.push([buf.length]);
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
else {
|
|
823
|
+
currentGroup.push(buf);
|
|
824
|
+
currentGroupSize += buf.length;
|
|
825
|
+
if (currentGroupSize >= TARGET_SIZE) {
|
|
826
|
+
flushCurrentGroup();
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
flushCurrentGroup();
|
|
831
|
+
headerParts = [2, outputBuffers.length];
|
|
832
|
+
for (let descriptor of outputDescriptors) {
|
|
833
|
+
headerParts.push(descriptor.length, ...descriptor);
|
|
834
|
+
}
|
|
835
|
+
dataBuffers = outputBuffers;
|
|
836
|
+
}
|
|
837
|
+
else {
|
|
838
|
+
let buffers = await SocketFunction_1.SocketFunction.WIRE_SERIALIZER.serialize(obj);
|
|
839
|
+
headerParts = [3, buffers.length];
|
|
840
|
+
dataBuffers = buffers;
|
|
841
|
+
}
|
|
842
|
+
let headerBuffer = Buffer.from((new Float64Array(headerParts)).buffer);
|
|
843
|
+
let allBuffers = [headerBuffer, ...dataBuffers];
|
|
844
|
+
stats.uncompressedSize += allBuffers.reduce((sum, buf) => sum + buf.length, 0);
|
|
845
|
+
let compressed = [];
|
|
846
|
+
let startTime = Date.now();
|
|
847
|
+
let lastWarnTime = startTime;
|
|
848
|
+
let currentUncompressedSize = 0;
|
|
849
|
+
let currentCompressedSize = 0;
|
|
850
|
+
function logIfSlow(i) {
|
|
851
|
+
let now = Date.now();
|
|
852
|
+
if (now - lastWarnTime > 500) {
|
|
853
|
+
let elapsed = now - startTime;
|
|
854
|
+
console.log(`Slow LZ4 compress (${(0, format_1.formatTime)(elapsed)}: ${i + 1}/${allBuffers.length} buffers, ${(0, format_1.formatNumber)(currentUncompressedSize)}B => ${(0, format_1.formatNumber)(currentCompressedSize)}B`);
|
|
855
|
+
lastWarnTime = now;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
for (let i = 0; i < allBuffers.length; i++) {
|
|
859
|
+
let buf = allBuffers[i];
|
|
860
|
+
currentUncompressedSize += buf.length;
|
|
861
|
+
let compressedBuf = LZ4.compress(buf);
|
|
862
|
+
compressed.push(compressedBuf);
|
|
863
|
+
currentCompressedSize += compressedBuf.length;
|
|
864
|
+
logIfSlow(i);
|
|
865
|
+
}
|
|
866
|
+
logIfSlow(allBuffers.length);
|
|
867
|
+
stats.compressedSize += currentCompressedSize;
|
|
868
|
+
return compressed;
|
|
869
|
+
});
|
|
870
|
+
const decompressObjLZ4 = (0, measure_1.measureWrap)(async function wireCallDecompressLZ4(obj, stats) {
|
|
871
|
+
const { LZ4 } = await Promise.resolve().then(() => __importStar(require("./lz4/LZ4")));
|
|
872
|
+
stats.compressedSize += obj.reduce((sum, buf) => sum + buf.length, 0);
|
|
873
|
+
let decompressed = [];
|
|
874
|
+
let startTime = Date.now();
|
|
875
|
+
let lastWarnTime = startTime;
|
|
876
|
+
let currentCompressedSize = 0;
|
|
877
|
+
let currentUncompressedSize = 0;
|
|
878
|
+
function logIfSlow(i) {
|
|
879
|
+
let now = Date.now();
|
|
880
|
+
if (now - lastWarnTime > 500) {
|
|
881
|
+
let elapsed = now - startTime;
|
|
882
|
+
console.log(`Slow LZ4 decompress (${(0, format_1.formatTime)(elapsed)}): ${i + 1}/${obj.length} buffers, ${(0, format_1.formatNumber)(currentCompressedSize)}B => ${(0, format_1.formatNumber)(currentUncompressedSize)}B`);
|
|
883
|
+
lastWarnTime = now;
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
for (let i = 0; i < obj.length; i++) {
|
|
887
|
+
let buf = obj[i];
|
|
888
|
+
currentCompressedSize += buf.length;
|
|
889
|
+
let decompressedBuf = LZ4.decompress(buf);
|
|
890
|
+
decompressed.push(decompressedBuf);
|
|
891
|
+
currentUncompressedSize += decompressedBuf.length;
|
|
892
|
+
logIfSlow(i);
|
|
893
|
+
}
|
|
894
|
+
logIfSlow(obj.length);
|
|
895
|
+
stats.uncompressedSize += currentUncompressedSize;
|
|
896
|
+
let headerBuffer = decompressed[0];
|
|
897
|
+
let dataBuffers = decompressed.slice(1);
|
|
898
|
+
let typeBuffer = headerBuffer.slice(0, 8);
|
|
899
|
+
let type = new Float64Array(typeBuffer.buffer, typeBuffer.byteOffset, 1)[0];
|
|
900
|
+
if (type === 1) {
|
|
901
|
+
return dataBuffers[0];
|
|
902
|
+
}
|
|
903
|
+
if (type === 2) {
|
|
904
|
+
let headerData = new Float64Array(headerBuffer.buffer, headerBuffer.byteOffset, headerBuffer.byteLength / 8);
|
|
905
|
+
let outputBufferCount = headerData[1];
|
|
906
|
+
let buffers = [];
|
|
907
|
+
let headerIndex = 2;
|
|
908
|
+
for (let i = 0; i < outputBufferCount; i++) {
|
|
909
|
+
let inputBufferCount = headerData[headerIndex++];
|
|
910
|
+
let sizes = [];
|
|
911
|
+
for (let j = 0; j < inputBufferCount; j++) {
|
|
912
|
+
sizes.push(headerData[headerIndex++]);
|
|
913
|
+
}
|
|
914
|
+
let outputBuffer = dataBuffers[i];
|
|
915
|
+
let offset = 0;
|
|
916
|
+
for (let size of sizes) {
|
|
917
|
+
buffers.push(outputBuffer.slice(offset, offset + size));
|
|
918
|
+
offset += size;
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
return buffers;
|
|
922
|
+
}
|
|
923
|
+
if (type === 3) {
|
|
924
|
+
let result = await SocketFunction_1.SocketFunction.WIRE_SERIALIZER.deserialize(dataBuffers);
|
|
925
|
+
return result;
|
|
926
|
+
}
|
|
927
|
+
throw new Error(`Unknown compression type ${type}`);
|
|
928
|
+
});
|
|
929
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ2FsbEZhY3RvcnkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJDYWxsRmFjdG9yeS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUVBLCtDQUFtRjtBQUNuRixpQ0FBOEg7QUFDOUgseURBQTBFO0FBQzFFLHNEQUFtRDtBQUVuRCwyQ0FBcUY7QUFFckYsdUNBQWlDO0FBQ2pDLHNEQUFrRTtBQUNsRSxpRUFBZ0Y7QUFDaEYseUNBQWlFO0FBQ2pFLGdEQUErRDtBQUcvRCwwREFBa0Q7QUFDbEQsaURBQW1GO0FBRW5GLCtCQUE0QjtBQUM1QiwrREFBeUU7QUFDekUsWUFBWSxDQUFDLEdBQUcsRUFBRSxtREFBUSxXQUFXLEdBQUMsQ0FBQyxDQUFDO0FBRXhDLElBQUEsc0JBQU8sRUFBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLGFBQWEsRUFBRSxJQUFJLENBQUMsQ0FBQztBQUU5QyxnR0FBZ0c7QUFDaEcsd0JBQXdCO0FBQ3hCLDJGQUEyRjtBQUMzRixNQUFNLGVBQWUsR0FBRyxJQUFJLENBQUM7QUE2RDdCLE1BQU0sd0JBQXdCLEdBQUcsQ0FBQyxDQUFDLENBQUM7QUFFcEMsSUFBSSxnQkFBZ0IsR0FBRyxDQUFDLENBQUM7QUFDekIsSUFBSSxzQkFBc0IsR0FBRyxDQUFDLENBQUM7QUFDL0IsTUFBTSxnQkFBZ0IsR0FBRyxJQUFJLEdBQUcsSUFBSSxHQUFHLEVBQUUsQ0FBQztBQUMxQyxJQUFJLG9CQUFvQixHQUFzQyxFQUFFLENBQUM7QUFDakUsU0FBZ0Isc0JBQXNCO0lBQ2xDLElBQUksS0FBSyxHQUFHLHNCQUFzQixDQUFDO0lBQ25DLHNCQUFzQixHQUFHLENBQUMsQ0FBQztJQUMzQixPQUFPLEtBQUssQ0FBQztBQUNqQixDQUFDO0FBSkQsd0RBSUM7QUFDRCxTQUFnQixtQkFBbUI7SUFDL0IsT0FBTyxnQkFBZ0IsQ0FBQztBQUM1QixDQUFDO0FBRkQsa0RBRUM7QUFDRCxTQUFnQixnQkFBZ0I7SUFD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QUFDLElBQUksQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRSxNQUFNLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQztnQkFDeEQsTUFBTSxJQUFJLElBQUksQ0FBQztZQUNuQixDQUFDO1FBQ0wsQ0FBQztRQUVELE9BQU8sT0FBTyxDQUFDO0lBQ25CLENBQUM7SUFFRCxJQUFJLElBQUksS0FBSyxDQUFDLEVBQUUsQ0FBQztRQUNiLElBQUksTUFBTSxHQUFHLE1BQU0sK0JBQWMsQ0FBQyxlQUFlLENBQUMsV0FBVyxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQzNFLE9BQU8sTUFBTSxDQUFDO0lBQ2xCLENBQUM7SUFFRCxNQUFNLElBQUksS0FBSyxDQUFDLDRCQUE0QixJQUFJLEVBQUUsQ0FBQyxDQUFDO0FBQ3hELENBQUMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ2FsbGVyQ29udGV4dCwgQ2FsbGVyQ29udGV4dEJhc2UsIENhbGxUeXBlLCBGdWxsQ2FsbFR5cGUgfSBmcm9tIFwiLi4vU29ja2V0RnVuY3Rpb25UeXBlc1wiO1xuaW1wb3J0ICogYXMgd3MgZnJvbSBcIndzXCI7XG5pbXBvcnQgeyBnZXRDYWxsRmxhZ3MsIHBlcmZvcm1Mb2NhbENhbGwsIHNob3VsZENvbXByZXNzQ2FsbCB9IGZyb20gXCIuL2NhbGxNYW5hZ2VyXCI7XG5pbXBvcnQgeyBjb252ZXJ0RXJyb3JTdGFja1RvRXJyb3IsIGZvcm1hdE51bWJlclN1ZmZpeGVkLCBpc0J1ZmZlclR5cGUsIGlzTm9kZSwgbGlzdCwgdGltZUluSG91ciwgdGltZUluTWludXRlIH0gZnJvbSBcIi4vbWlzY1wiO1xuaW1wb3J0IHsgY3JlYXRlV2Vic29ja2V0RmFjdG9yeSwgZ2V0VExTU29ja2V0IH0gZnJvbSBcIi4vd2Vic29ja2V0RmFjdG9yeVwiO1xuaW1wb3J0IHsgU29ja2V0RnVuY3Rpb24gfSBmcm9tIFwiLi4vU29ja2V0RnVuY3Rpb25cIjtcbmltcG9ydCAqIGFzIHRscyBmcm9tIFwidGxzXCI7XG5pbXBvcnQgeyBnZXRDbGllbnROb2RlSWQsIGdldE5vZGVJZExvY2F0aW9uLCByZWdpc3Rlck5vZGVDbGllbnQgfSBmcm9tIFwiLi9ub2RlQ2FjaGVcIjtcbmltcG9ydCBkZWJ1Z2JyZWFrIGZyb20gXCJkZWJ1Z2JyZWFrXCI7XG5pbXBvcnQgeyBsYXp5IH0gZnJvbSBcIi4vY2FjaGluZ1wiO1xuaW1wb3J0IHsgYmx1ZSwgZ3JlZW4sIHJlZCwgeWVsbG93IH0gZnJvbSBcIi4vZm9ybWF0dGluZy9sb2dDb2xvcnNcIjtcbmltcG9ydCB7IGlzU3BsaXRhYmxlQXJyYXksIG1hcmtBcnJheUFzU3BsaXRhYmxlIH0gZnJvbSBcIi4vZml4TGFyZ2VOZXR3b3JrQ2FsbHNcIjtcbmltcG9ydCB7IGRlbGF5LCBydW5JbmZpbml0ZVBvbGwsIHJ1bkluU2VyaWFsIH0gZnJvbSBcIi4vYmF0Y2hpbmdcIjtcbmltcG9ydCB7IGZvcm1hdE51bWJlciwgZm9ybWF0VGltZSB9IGZyb20gXCIuL2Zvcm1hdHRpbmcvZm9ybWF0XCI7XG5pbXBvcnQgemxpYiBmcm9tIFwiemxpYlwiO1xuaW1wb3J0IHBha28gZnJvbSBcInBha29cIjtcbmltcG9ydCB7IHNldEZsYWcgfSBmcm9tIFwiLi4vcmVxdWlyZS9jb21waWxlRmxhZ3NcIjtcbmltcG9ydCB7IG1lYXN1cmVGbmMsIG1lYXN1cmVXcmFwLCByZWdpc3Rlck1lYXN1cmVJbmZvIH0gZnJvbSBcIi4vcHJvZmlsaW5nL21lYXN1cmVcIjtcbmltcG9ydCB7IE1heWJlUHJvbWlzZSB9IGZyb20gXCIuL3R5cGVzXCI7XG5pbXBvcnQgeyBaaXAgfSBmcm9tIFwiLi9aaXBcIjtcbmltcG9ydCB7IGRlY29kZVByb3RvY29sLCBwcm9wb3NlUHJvdG9jb2xzIH0gZnJvbSBcIi4vcHJvdG9jb2xOZWdvdGlhdGlvblwiO1xuc2V0SW1tZWRpYXRlKCgpID0+IGltcG9ydChcIi4vbHo0L0xaNFwiKSk7XG5cbnNldEZsYWcocmVxdWlyZSwgXCJwYWtvXCIsIFwiYWxsb3djbGllbnRcIiwgdHJ1ZSk7XG5cbi8vIE5PVEU6IElmIGl0IGlzIHRvbyBsb3csIGFuZCB0b28gbWFueSBzZXJ2ZXJzIGRpc2Nvbm5lY3QsIHdlIGNhbiBlYXNpbHkgc3BlbmQgMTAwJSBvZiBvdXIgdGltZVxuLy8gIHRyeWluZyB0byByZWNvbm5lY3QuXG4vLyAgKE9yLi4uIG1heWJlIHRoZSBkZWxheSBpcyBqdXN0IHdhaXRpbmcsIGFuZCB3ZSBhcmVuJ3QgYWN0dWFsbHkgb3ZlcmxvYWRpbmcgdGhlIHNlcnZlcj8pXG5jb25zdCBNSU5fUkVUUllfREVMQVkgPSA1MDAwO1xuXG50eXBlIEludGVybmFsQ2FsbFR5cGUgPSBGdWxsQ2FsbFR5cGUgJiB7XG4gICAgc2VxTnVtOiBudW1iZXI7XG4gICAgaXNSZXR1cm46IGZhbHNlO1xuICAgIGlzQXJnc0NvbXByZXNzZWQ/OiBib29sZWFuIHwgXCJMWjRcIiB8IFwiemlwXCI7XG59XG5cbnR5cGUgSW50ZXJuYWxSZXR1cm5UeXBlID0ge1xuICAgIGlzUmV0dXJuOiB0cnVlO1xuICAgIHJlc3VsdDogdW5rbm93bjtcbiAgICBlcnJvcj86IHN0cmluZztcbiAgICBzZXFOdW06IG51bWJlcjtcbiAgICBpc1Jlc3VsdENvbXByZXNzZWQ/OiBib29sZWFuIHwgXCJMWjRcIiB8IFwiemlwXCI7XG59O1xuXG5cbmV4cG9ydCBpbnRlcmZhY2UgQ2FsbEZhY3Rvcnkge1xuICAgIG5vZGVJZDogc3RyaW5nO1xuICAgIHJlYWxOb2RlSWQ/OiBzdHJpbmc7XG4gICAgbGFzdENsb3NlZDogbnVtYmVyO1xuICAgIGNsb3NlZEZvcmV2ZXI/OiBib29sZWFuO1xuICAgIGlzQ29ubmVjdGVkPzogYm9vbGVhbjtcbiAgICByZWNlaXZlZEluaXRpYWxpemVTdGF0ZT86IEluaXRpYWxpemVTdGF0ZTtcbiAgICAvLyBUcnVlIGlmIHRoZSBjb25uZWN0aW9uIHdhcyBlc3RhYmxpc2hlZCB3aXRoIGEgbmVnb3RpYXRlZFxuICAgIC8vIFNlYy1XZWJTb2NrZXQtUHJvdG9jb2wgKHNvIHRoZSBsZWdhY3kgaW5pdGlhbGl6ZSBwYWNrZXQgc2hvdWxkIGJlIHNraXBwZWQpLlxuICAgIHByb3RvY29sTmVnb3RpYXRlZD86IGJvb2xlYW47XG4gICAgLy8gTk9URTogTWF5IG9yIG1heSBub3QgaGF2ZSByZWNvbm5lY3Rpb24gb3IgcmV0cnkgbG9naWMgaW5zaWRlIG9mIHBlcmZvcm1DYWxsLlxuICAgIC8vICBUcmlnZ2VyIHBlcmZvcm1Mb2NhbENhbGwgb24gdGhlIG90aGVyIHNpZGUgb2YgdGhlIGNvbm5lY3Rpb25cbiAgICBwZXJmb3JtQ2FsbChjYWxsOiBDYWxsVHlwZSk6IFByb21pc2U8dW5rbm93bj47XG4gICAgb25OZXh0RGlzY29ubmVjdChjYWxsYmFjazogKCkgPT4gdm9pZCk6IHZvaWQ7XG4gICAgZGlzY29ubmVjdCgpOiB2b2lkO1xuICAgIC8vIElmIHdlIGNoYW5nZSB0aGUgbm9kZSBJRCB3ZSBuZWVkIHRvIHJlY3JlYXRlIHRoaXMgb2JqZWN0LCBlc3NlbnRpYWxseSB0aGlzIG9iamVjdCBzaG91bGQgYmUgaW1tdXRhYmxlLiBJIGZvcmdldCB3aHkgd2Ugd2FudGVkIHRoaXMuIEkgdGhpbmsgaXQncyBiZWNhdXNlIHdlIGRpZG4ndCBrbm93IGZvciBzdXJlIGlmIG5vZGUgSUQgd291bGQgYmUgdW5pcXVlLCBidXQgaXQgd2lsbCBiZS4gXG4gICAgY29ubmVjdGlvbklkOiB7IG5vZGVJZDogc3RyaW5nIH07XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2VuZGVySW50ZXJmYWNlIHtcbiAgICBub2RlSWQ/OiBzdHJpbmc7XG4gICAgLy8gT25seSBzZXQgQUZURVIgXCJvcGVuXCIgKGlmIHNldCBhdCBhbGwsIGFzIGluIHRoZSBicm93c2VyIHdlIGRvbid0IGhhdmUgYWNjZXNzIHRvIHRoZSBzb2NrZXQpLlxuICAgIF9zb2NrZXQ/OiB0bHMuVExTU29ja2V0O1xuICAgIC8vIFRoZSBjaG9zZW4gU2VjLVdlYlNvY2tldC1Qcm90b2NvbCB2YWx1ZSAoc2V0IGFmdGVyIFwib3BlblwiIGJ5IGJvdGggTm9kZSBgd3NgXG4gICAgLy8gYW5kIHRoZSBicm93c2VyIFdlYlNvY2tldCkuIEVtcHR5IHN0cmluZyBtZWFucyBub25lIHdhcyBuZWdvdGlhdGVkLlxuICAgIHByb3RvY29sPzogc3RyaW5nO1xuXG4gICAgc2VuZChkYXRhOiBzdHJpbmcgfCBCdWZmZXIpOiB2b2lkO1xuICAgIGNsb3NlKCk6IHZvaWQ7XG5cbiAgICBhZGRFdmVudExpc3RlbmVyKGV2ZW50OiBcIm9wZW5cIiwgbGlzdGVuZXI6ICgpID0+IHZvaWQpOiB2b2lkO1xuICAgIGFkZEV2ZW50TGlzdGVuZXIoZXZlbnQ6IFwiY2xvc2VcIiwgbGlzdGVuZXI6ICgpID0+IHZvaWQpOiB2b2lkO1xuICAgIGFkZEV2ZW50TGlzdGVuZXIoZXZlbnQ6IFwiZXJyb3JcIiwgbGlzdGVuZXI6IChlcnI6IHsgbWVzc2FnZTogc3RyaW5nIH0pID0+IHZvaWQpOiB2b2lkO1xuICAgIGFkZEV2ZW50TGlzdGVuZXIoZXZlbnQ6IFwibWVzc2FnZVwiLCBsaXN0ZW5lcjogKGRhdGE6IHdzLlJhd0RhdGEgfCB3cy5NZXNzYWdlRXZlbnQgfCBzdHJpbmcpID0+IHZvaWQpOiB2b2lkO1xuXG4gICAgcmVhZHlTdGF0ZTogbnVtYmVyO1xuXG4gICAgcGluZz8oKTogdm9pZDtcbn1cblxudHlwZSBJbml0aWFsaXplU3RhdGUgPSB7XG4gICAgc3VwcG9ydHNMWjQ/OiBib29sZWFuO1xufTtcblxuY29uc3QgSU5JVElBTElaRV9TVEFURV9TRVFfTlVNID0gLTE7XG5cbmxldCBwZW5kaW5nQ2FsbENvdW50ID0gMDtcbmxldCBoYXJ2ZXN0YWJsZUZhaWxlZENhbGxzID0gMDtcbmNvbnN0IENBTExfVElNRVNfTElNSVQgPSAxMDAwICogMTAwMCAqIDEwO1xubGV0IGhhcnZlc3RhYmxlQ2FsbFRpbWVzOiB7IHN0YXJ0OiBudW1iZXI7IGVuZDogbnVtYmVyOyB9W10gPSBbXTtcbmV4cG9ydCBmdW5jdGlvbiBoYXJ2ZXN0RmFpbGVkQ2FsbENvdW50KCkge1xuICAgIGxldCBjb3VudCA9IGhhcnZlc3RhYmxlRmFpbGVkQ2FsbHM7XG4gICAgaGFydmVzdGFibGVGYWlsZWRDYWxscyA9IDA7XG4gICAgcmV0dXJuIGNvdW50O1xufVxuZXhwb3J0IGZ1bmN0aW9uIGdldFBlbmRpbmdDYWxsQ291bnQoKSB7XG4gICAgcmV0dXJuIHBlbmRpbmdDYWxsQ291bnQ7XG59XG5leHBvcnQgZnVuY3Rpb24gaGFydmVzdENhbGxUaW1lcygpIHtcbiAgICBsZXQgdGltZXMgPSBoYXJ2ZXN0YWJsZUNhbGxUaW1lcztcbiAgICBoYXJ2ZXN0YWJsZUNhbGxUaW1lcyA9IFtdO1xuICAgIHJldHVybiB0aW1lcztcbn1cbnJ1bkluZmluaXRlUG9sbCh0aW1lSW5NaW51dGUgKiAxNSwgKCkgPT4ge1xuICAgIGlmIChoYXJ2ZXN0YWJsZUNhbGxUaW1lcy5sZW5ndGggPiBDQUxMX1RJTUVTX0xJTUlUKSB7XG4gICAgICAgIGhhcnZlc3RhYmxlQ2FsbFRpbWVzID0gaGFydmVzdGFibGVDYWxsVGltZXMuc2xpY2UoLUNBTExfVElNRVNfTElNSVQpO1xuICAgIH1cbn0pO1xuXG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGVDYWxsRmFjdG9yeShcbiAgICB3ZWJTb2NrZXRCYXNlOiBTZW5kZXJJbnRlcmZhY2UgfCB1bmRlZmluZWQsXG4gICAgLy8gVGhlIG5vZGUgaWQgd2UgYXJlIGNvbm5lY3RpbmcgdG8gKG9yIHRoYXQgY29ubmVjdGVkIHRvIHVzKVxuICAgIG5vZGVJZDogc3RyaW5nLFxuICAgIC8vIFRoZSBub2RlIGlkIHRoYXQgd2Ugd2VyZSBjb250YWN0ZWQgb25cbiAgICBsb2NhbE5vZGVJZCA9IFwiXCIsXG4pOiBQcm9taXNlPENhbGxGYWN0b3J5PiB7XG4gICAgbGV0IG5pY2VDb25uZWN0aW9uTmFtZSA9IG5vZGVJZDtcblxuICAgIGNvbnN0IGNyZWF0ZVdlYnNvY2tldCA9IGNyZWF0ZVdlYnNvY2tldEZhY3RvcnkoKTtcbiAgICBjb25zdCByZWdpc3Rlck9uY2UgPSBsYXp5KCgpID0+IHJlZ2lzdGVyTm9kZUNsaWVudChjYWxsRmFjdG9yeSkpO1xuXG4gICAgbGV0IGNhblJlY29ubmVjdCA9ICEhZ2V0Tm9kZUlkTG9jYXRpb24obm9kZUlkKTtcblxuICAgIGxldCBwZW5kaW5nQ2FsbHM6IE1hcDxudW1iZXIsIHtcbiAgICAgICAgZGF0YTogQnVmZmVyW107XG4gICAgICAgIGNhbGw6IEludGVybmFsQ2FsbFR5cGU7XG4gICAgICAgIGNhbGxiYWNrOiAocmVzdWx0SlNPTjogSW50ZXJuYWxSZXR1cm5UeXBlKSA9PiB2b2lkO1xuICAgIH0+ID0gbmV3IE1hcCgpO1xuICAgIC8vIE5PVEU6IEl0IGlzIGltcG9ydGFudCB0byBtYWtlIHRoaXMgYXMgcmFuZG9tIGFzIHBvc3NpYmxlLCB0byBwcmV2ZW50XG4gICAgLy8gIHJlY29ubmVjdGlvbnMgZHVlcyB0byBhIHByb2Nlc3MgYmVpbmcgcmVzZXQgY2F1c2luZyBzZXFOdW0gY29sbGlzaW9uc1xuICAgIC8vICBpbiByZXR1cm4gY2FsbHMuXG4gICAgbGV0IG5leHRTZXFOdW0gPSBEYXRlLm5vdygpICsgTWF0aC5yYW5kb20oKTtcblxuICAgIC8vIE5PVEU6IEknbSBub3Qgc3VyZSBpZiB0aGlzIGlzIG5lZWRlZCwgSSB0aG91Z2h0IGl0IHdhcywgYnV0Li4uIG5vdyBJIHRoaW5rXG4gICAgLy8gIGl0IHByb2JhYmx5IGlzbid0Li4uXG4gICAgLy8gaWYgKHdlYlNvY2tldEJhc2U/LnJlYWR5U3RhdGUgPT09IDEgLyogT1BFTiAqLyAmJiB3ZWJTb2NrZXRCYXNlLnBpbmcpIHtcbiAgICAvLyAgICAgLy8gSGVhcnRiZWF0IGxvb3AsIG90aGVyd2lzZSBvbkRpc2Nvbm5lY3QgaXMgbmV2ZXIgY2FsbGVkLlxuICAgIC8vICAgICAoKGFzeW5jICgpID0+IHtcbiAgICAvLyAgICAgICAgIHdoaWxlICh3ZWJTb2NrZXRCYXNlPy5yZWFkeVN0YXRlID09PSAxIC8qIE9QRU4gKi8gJiYgd2ViU29ja2V0QmFzZS5waW5nKSB7XG4gICAgLy8gICAgICAgICAgICAgYXdhaXQgZGVsYXkoMTAwMCAqIDYwKTtcbiAgICAvLyAgICAgICAgICAgICB3ZWJTb2NrZXRCYXNlLnBpbmc/LigpO1xuICAgIC8vICAgICAgICAgfVxuICAgIC8vICAgICB9KSkoKS5jYXRjaCgoKSA9PiB7IH0pO1xuICAgIC8vIH1cblxuICAgIGxldCBsYXN0Q29ubmVjdGlvbkF0dGVtcHQgPSAwO1xuXG4gICAgbGV0IGNhbGxlckNvbnRleHQ6IENhbGxlckNvbnRleHRCYXNlID0ge1xuICAgICAgICBub2RlSWQsXG4gICAgICAgIGxvY2FsTm9kZUlkXG4gICAgfTtcblxuICAgIGxldCBkaXNjb25uZWN0Q2FsbGJhY2tzID0gbmV3IFNldDwoKSA9PiB2b2lkPigpO1xuICAgIGZ1bmN0aW9uIG9uTmV4dERpc2Nvbm5lY3QoY2FsbGJhY2s6ICgpID0+IHZvaWQpOiB2b2lkIHtcbiAgICAgICAgZGlzY29ubmVjdENhbGxiYWNrcy5hZGQoY2FsbGJhY2spO1xuICAgIH1cblxuICAgIGxldCBjYWxsRmFjdG9yeTogQ2FsbEZhY3RvcnkgPSB7XG4gICAgICAgIG5vZGVJZCxcbiAgICAgICAgbGFzdENsb3NlZDogMCxcbiAgICAgICAgY29ubmVjdGlvbklkOiB7IG5vZGVJZCB9LFxuICAgICAgICByZWNlaXZlZEluaXRpYWxpemVTdGF0ZTogdW5kZWZpbmVkLFxuICAgICAgICBvbk5leHREaXNjb25uZWN0LFxuICAgICAgICBkaXNjb25uZWN0KCkge1xuICAgICAgICAgICAgY2FuUmVjb25uZWN0ID0gZmFsc2U7XG4gICAgICAgICAgICBjYWxsRmFjdG9yeS5jbG9zZWRGb3JldmVyID0gdHJ1ZTtcbiAgICAgICAgICAgIGlmICh3ZWJTb2NrZXRQcm9taXNlKSB7XG4gICAgICAgICAgICAgICAgd2ViU29ja2V0UHJvbWlzZS50aGVuKHdzID0+IHdzLmNsb3NlKCkpLmNhdGNoKCgpID0+IHsgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIGFzeW5jIHBlcmZvcm1DYWxsKGNhbGw6IENhbGxUeXBlKSB7XG4gICAgICAgICAgICBsZXQgc2VxTnVtID0gbmV4dFNlcU51bSsrO1xuICAgICAgICAgICAgbGV0IGZ1bGxDYWxsOiBJbnRlcm5hbENhbGxUeXBlID0ge1xuICAgICAgICAgICAgICAgIG5vZGVJZCxcbiAgICAgICAgICAgICAgICBpc1JldHVybjogZmFsc2UsXG4gICAgICAgICAgICAgICAgYXJnczogY2FsbC5hcmdzLFxuICAgICAgICAgICAgICAgIGNsYXNzR3VpZDogY2FsbC5jbGFzc0d1aWQsXG4gICAgICAgICAgICAgICAgZnVuY3Rpb25OYW1lOiBjYWxsLmZ1bmN0aW9uTmFtZSxcbiAgICAgICAgICAgICAgICBzZXFOdW0sXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgbGV0IGRhdGE6IEJ1ZmZlcltdO1xuICAgICAgICAgICAgbGV0IG9yaWdpbmFsQXJncyA9IGNhbGwuYXJncztcbiAgICAgICAgICAgIGxldCB0aW1lID0gRGF0ZS5ub3coKTtcbiAgICAgICAgICAgIGxldCBzZW5kU3RhdHM6IENvbXByZXNzaW9uU3RhdHMgPSB7XG4gICAgICAgICAgICAgICAgdW5jb21wcmVzc2VkU2l6ZTogMCxcbiAgICAgICAgICAgICAgICBjb21wcmVzc2VkU2l6ZTogMCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGlmIChjYWxsRmFjdG9yeS5yZWNlaXZlZEluaXRpYWxpemVTdGF0ZT8uc3VwcG9ydHNMWjQpIHtcbiAgICAgICAgICAgICAgICAgICAgbGV0IGNvbXByZXNzTW9kZSA9IHNob3VsZENvbXByZXNzQ2FsbChmdWxsQ2FsbCk7XG4gICAgICAgICAgICAgICAgICAgIC8vIElmIGl0J3MgdW5kZWZpbmVkLCB0aGVuIHdlIGNvbXByZXNzIGl0LiBXZSBiYXNpY2FsbHkgYWx3YXlzIHdhbnQgdG8gY29tcHJlc3MgZnJvbSBub3cgb24sIGJlY2F1c2UgTFo0IGlzIHNvIGZhc3QuIFxuICAgICAgICAgICAgICAgICAgICBpZiAoY29tcHJlc3NNb2RlICE9PSBmYWxzZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZnVsbENhbGwuYXJncyA9IGF3YWl0IGNvbXByZXNzT2JqTFo0KGZ1bGxDYWxsLmFyZ3MsIHNlbmRTdGF0cykgYXMgYW55O1xuICAgICAgICAgICAgICAgICAgICAgICAgZnVsbENhbGwuaXNBcmdzQ29tcHJlc3NlZCA9IFwiTFo0XCI7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBpZiAoc2hvdWxkQ29tcHJlc3NDYWxsKGZ1bGxDYWxsKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZnVsbENhbGwuYXJncyA9IGF3YWl0IGNvbXByZXNzT2JqKGZ1bGxDYWxsLmFyZ3MsIHNlbmRTdGF0cykgYXMgYW55O1xuICAgICAgICAgICAgICAgICAgICAgICAgZnVsbENhbGwuaXNBcmdzQ29tcHJlc3NlZCA9IFwiemlwXCI7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgbGV0IGRhdGFNYXliZVByb21pc2UgPSBTb2NrZXRGdW5jdGlvbi5XSVJFX1NFUklBTElaRVIuc2VyaWFsaXplKGZ1bGxDYWxsKTtcbiAgICAgICAgICAgICAgICBpZiAoZGF0YU1heWJlUHJvbWlzZSBpbnN0YW5jZW9mIFByb21pc2UpIHtcbiAgICAgICAgICAgICAgICAgICAgZGF0YSA9IGF3YWl0IGRhdGFNYXliZVByb21pc2U7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgZGF0YSA9IGRhdGFNYXliZVByb21pc2U7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmICghc2VuZFN0YXRzLmNvbXByZXNzZWRTaXplKSB7XG4gICAgICAgICAgICAgICAgICAgIGxldCB0b3RhbFNpemUgPSAwO1xuICAgICAgICAgICAgICAgICAgICBmb3IgKGxldCBkIG9mIGRhdGEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRvdGFsU2l6ZSArPSBkLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBzZW5kU3RhdHMudW5jb21wcmVzc2VkU2l6ZSA9IHRvdGFsU2l6ZTtcbiAgICAgICAgICAgICAgICAgICAgc2VuZFN0YXRzLmNvbXByZXNzZWRTaXplID0gdG90YWxTaXplO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBhZGRTZW5kU3RhdHMoc2VuZFN0YXRzKTtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgRXJyb3Igc2VyaWFsaXppbmcgZGF0YSBmb3IgY2FsbCAke2NhbGwuY2xhc3NHdWlkfS4ke2NhbGwuZnVuY3Rpb25OYW1lfVxcbiR7ZS5zdGFja31gKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRpbWUgPSBEYXRlLm5vdygpIC0gdGltZTtcbiAgICAgICAgICAgIGxldCBzaXplID0gZGF0YS5tYXAoeCA9PiB4Lmxlbmd0aCkucmVkdWNlKChhLCBiKSA9PiBhICsgYiwgMCk7XG4gICAgICAgICAgICBpZiAodGltZSA+IFNvY2tldEZ1bmN0aW9uLldJUkVfV0FSTl9USU1FKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2cocmVkKGBTbG93IHNlcmlhbGl6ZSwgdG9vayAke2Zvcm1hdFRpbWUodGltZSl9IHRvIHNlcmlhbGl6ZSAke2Zvcm1hdE51bWJlcihzaXplKX0gYnl0ZXMuIEZvciAke2NhbGwuY2xhc3NHdWlkfS4ke2NhbGwuZnVuY3Rpb25OYW1lfWApKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHNpemUgPiBTb2NrZXRGdW5jdGlvbi5NQVhfTUVTU0FHRV9TSVpFICogMS41KSB7XG4gICAgICAgICAgICAgICAgbGV0IHNwbGl0QXJnSW5kZXggPSBvcmlnaW5hbEFyZ3MuZmluZEluZGV4KGlzU3BsaXRhYmxlQXJyYXkpO1xuICAgICAgICAgICAgICAgIGlmIChzcGxpdEFyZ0luZGV4ID49IDApIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coeWVsbG93KGBTcGxpdHRpbmcgbGFyZ2UgY2FsbCBkdWUgdG8gbGFyZ2UgYXJnczogJHtjYWxsLmNsYXNzR3VpZH0uJHtjYWxsLmZ1bmN0aW9uTmFtZX1gKSk7XG4gICAgICAgICAgICAgICAgICAgIGxldCBTUExJVF9HUk9VUFMgPSAxMDtcbiAgICAgICAgICAgICAgICAgICAgbGV0IHNwbGl0QXJnID0gb3JpZ2luYWxBcmdzW3NwbGl0QXJnSW5kZXhdIGFzIHVua25vd25bXTtcbiAgICAgICAgICAgICAgICAgICAgbGV0IHN1YkNhbGxzID0gbGlzdChTUExJVF9HUk9VUFMpLm1hcChpbmRleCA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBsZXQgc3RhcnQgPSBNYXRoLmZsb29yKGluZGV4IC8gU1BMSVRfR1JPVVBTICogc3BsaXRBcmcubGVuZ3RoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGxldCBlbmQgPSBNYXRoLmZsb29yKChpbmRleCArIDEpIC8gU1BMSVRfR1JPVVBTICogc3BsaXRBcmcubGVuZ3RoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBzcGxpdEFyZy5zbGljZShzdGFydCwgZW5kKTtcbiAgICAgICAgICAgICAgICAgICAgfSkuZmlsdGVyKHggPT4geC5sZW5ndGggPiAwKTtcblxuICAgICAgICAgICAgICAgICAgICBsZXQgY2FsbHMgPSBzdWJDYWxscy5tYXAoYXN5bmMgc3BsaXRMaXN0ID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGxldCBzdWJDYWxsID0geyAuLi5jYWxsIH07XG4gICAgICAgICAgICAgICAgICAgICAgICBzdWJDYWxsLmFyZ3MgPSBzdWJDYWxsLmFyZ3Muc2xpY2UoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHN1YkNhbGwuYXJnc1tzcGxpdEFyZ0luZGV4XSA9IG1hcmtBcnJheUFzU3BsaXRhYmxlKHNwbGl0TGlzdCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCBjYWxsRmFjdG9yeS5wZXJmb3JtQ2FsbChzdWJDYWxsKTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IFByb21pc2UuYWxsU2V0dGxlZChjYWxscyk7XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IFByb21pc2UuYWxsKGNhbGxzKTtcbiAgICAgICAgICAgICAgICAgICAgLy8gRWguLi4gd2UgQ09VTEQgcmV0dXJuIHRoZSBhcnJheSBvZiByZXN1bHRzLCBidXQuLi4gdGhlbiB0aGUgcmVzdWx0IHdvdWxkIHNvbWV0aW1lcyBiZSBhbiBhcnJheSxcbiAgICAgICAgICAgICAgICAgICAgLy8gIHNvbWUgdGltZXMgbm90LCBzbywgaXQgaXMgYmV0dGVyIHRvIHJldHVybiBhIHN0cmluZyB3aGljaCB3aWxsIG1ha2UgaXQgbW9yZSBjbGVhciB3aHkgaXQgc29tZXRpbWVzIHZhcmllcy5cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFwiQ0FMTFNfU1BMSVRfRFVFX1RPX0xBUkdFX0FSR1NcIjtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYENhbGwgdG9vIGxhcmdlIHRvIHNlbmQgKCR7Y2FsbC5jbGFzc0d1aWR9LiR7Y2FsbC5mdW5jdGlvbk5hbWV9LCBzaXplOiAke2Zvcm1hdE51bWJlcihzaXplKX0gPiAke2Zvcm1hdE51bWJlcihTb2NrZXRGdW5jdGlvbi5NQVhfTUVTU0FHRV9TSVpFKX0pLiBJZiB5b3UgbmVlZCB0byBoYW5kbGUgdmVyeSBsYXJnZSBzdGF0aWMgZGF0YSB1c2Ugc29tZSBleHRlcm5hbCBzZXJ2aWNlLCBzdWNoIGFzIEJhY2tibGF6ZSBCMiBvciBBV1MgUzMuIE9yIGNvbnNpZGVyIGZyYWdtZW50aW5nIGRhdGEgYXQgYW4gYXBwbGljYXRpb24gbGV2ZWwsIGJlY2F1c2Ugc2VuZGluZyBsYXJnZSBkYXRhIHdpbGwgY2F1c2UgbGFyZ2UgbGFnIHNwaWtlcyBmb3Igb3RoZXIgY2xpZW50cyB1c2luZyB0aGlzIHNlcnZlci4gT3IsIGlmIGFic29sdXRlbHkgcmVxdWlyZWQsIHNldCBTb2NrZXRGdW5jdGlvbi5NQVhfTUVTU0FHRV9TSVpFIHRvIGEgaGlnaGVyIHZhbHVlLmApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBsZXQgcmVzdWx0UHJvbWlzZSA9IG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICAgICAgICBsZXQgc3RhcnRUaW1lID0gRGF0ZS5ub3coKTtcbiAgICAgICAgICAgICAgICBwZW5kaW5nQ2FsbENvdW50Kys7XG4gICAgICAgICAgICAgICAgbGV0IGNhbGxiYWNrID0gKHJlc3VsdDogSW50ZXJuYWxSZXR1cm5UeXBlKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHBlbmRpbmdDYWxsQ291bnQtLTtcbiAgICAgICAgICAgICAgICAgICAgcGVuZGluZ0NhbGxzLmRlbGV0ZShzZXFOdW0pO1xuICAgICAgICAgICAgICAgICAgICBoYXJ2ZXN0YWJsZUNhbGxUaW1lcy5wdXNoKHsgc3RhcnQ6IHN0YXJ0VGltZSwgZW5kOiBEYXRlLm5vdygpLCB9KTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAocmVzdWx0LmVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZWplY3QoY29udmVydEVycm9yU3RhY2tUb0Vycm9yKHJlc3VsdC5lcnJvcikpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x2ZShyZXN1bHQucmVzdWx0KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgcGVuZGluZ0NhbGxzLnNldChzZXFOdW0sIHsgY2FsbGJhY2ssIGRhdGEsIGNhbGw6IGZ1bGxDYWxsIH0pO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBsZXQgcmVzdWx0U2l6ZSA9IGRhdGEubWFwKHggPT4geC5sZW5ndGgpLnJlZHVjZSgoYSwgYikgPT4gYSArIGIsIDApO1xuICAgICAgICAgICAgICAgIGZvciAobGV0IGNhbGxiYWNrIG9mIFNvY2tldEZ1bmN0aW9uLnRyYWNrTWVzc2FnZVNpemVzLnVwbG9hZCkge1xuICAgICAgICAgICAgICAgICAgICBjYWxsYmFjayhyZXN1bHRTaXplKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKFNvY2tldEZ1bmN0aW9uLmxvZ01lc3NhZ2VzKSB7XG4gICAgICAgICAgICAgICAgICAgIGxldCBmbmNIYWNrID0gXCJcIjtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGNhbGwuZnVuY3Rpb25OYW1lID09PSBcImFkZENhbGxcIikge1xuICAgICAgICAgICAgICAgICAgICAgICAgbGV0IGFyZyA9IG9yaWdpbmFsQXJnc1swXSBhcyBhbnk7XG4gICAgICAgICAgICAgICAgICAgICAgICBmbmNIYWNrID0gYC4ke2FyZy5Eb21haW5OYW1lfS4ke2FyZy5Nb2R1bGVJZH0uJHthcmcuRnVuY3Rpb25JZH1gO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKGBTSVpFXFx0JHsoZm9ybWF0TnVtYmVyU3VmZml4ZWQocmVzdWx0U2l6ZSkgKyBgQmApLnBhZEVuZCg0LCBcIiBcIil9XFx0JHtmb3JtYXROdW1iZXIoZGF0YS5sZW5ndGgpfSBidWZmZXJzXFx0UkVNT1RFIENBTExcXHQke2NhbGwuY2xhc3NHdWlkfS4ke2NhbGwuZnVuY3Rpb25OYW1lfSR7Zm5jSGFja30gYXQgJHtEYXRlLm5vdygpfWApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIElmIHNlbmRpbmcgT1IgcmVzdWx0UHJvbWlzZSB0aHJvd3MsIHdlIHdhbnQgdG8gZXJyb3Igb3V0LiBUaGlzIHNvbHZlcyBzb21lIGlzc3VlcyB3aXRoIHJlc3VsdFByb21pc2VcbiAgICAgICAgICAgIC8vICAgICAgZXJyb3Jpbmcgb3V0IGZpcnN0LCB3aGljaCBpcyBiZWZvcmUgd2UgYXdhaXQgaXQsIHdoaWNoIG1ha2VzIE5vZGVKUyBhbmdyeSAodW5oYW5kbGVkIHByb21pc2UgcmVqZWN0aW9uKS5cbiAgICAgICAgICAgIC8vICAgICAgQWxzbywgdGVjaG5pY2FsbHksIHdlIGNvdWxkIHJlY2VpdmUgdGhlIHJlc3VsdCBiZWZvcmUgd2UgZmluaXNoIHNlbmRpbmcsIGluIHdoaWNoIGNhc2UsIHdlIG1pZ2h0XG4gICAgICAgICAgICAvLyAgICAgIGFzIHdlbGwgcmV0dXJuIGl0IGltbWVkaWF0ZWx5LlxuICAgICAgICAgICAgYXdhaXQgUHJvbWlzZS5yYWNlKFtzZW5kKGRhdGEpLCByZXN1bHRQcm9taXNlXSk7XG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgcmVzdWx0UHJvbWlzZTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBsZXQgd2ViU29ja2V0UHJvbWlzZTogUHJvbWlzZTxTZW5kZXJJbnRlcmZhY2U+IHwgdW5kZWZpbmVkO1xuICAgIGxldCBoYXNFdmVyQ29ubmVjdGVkID0gZmFsc2U7XG4gICAgaWYgKHdlYlNvY2tldEJhc2UpIHtcbiAgICAgICAgd2ViU29ja2V0UHJvbWlzZSA9IFByb21pc2UucmVzb2x2ZSh3ZWJTb2NrZXRCYXNlKTtcbiAgICAgICAgYXdhaXQgaW5pdGlhbGl6ZVdlYnNvY2tldCh3ZWJTb2NrZXRCYXNlKTtcbiAgICB9XG5cbiAgICBhc3luYyBmdW5jdGlvbiBpbml0aWFsaXplV2Vic29ja2V0KG5ld1dlYlNvY2tldDogU2VuZGVySW50ZXJmYWNlLCBza2lwQ2xvc2VIYW5kbGluZyA9IGZhbHNlKSB7XG4gICAgICAgIHJlZ2lzdGVyT25jZSgpO1xuICAgICAgICBjYWxsRmFjdG9yeS5yZWNlaXZlZEluaXRpYWxpemVTdGF0ZSA9IHVuZGVmaW5lZDtcblxuICAgICAgICBmdW5jdGlvbiBvbkNsb3NlKGVycm9yOiBzdHJpbmcpIHtcbiAgICAgICAgICAgIC8vIFdlIHRyeSB2YXJpb3VzIGNvbm5lY3Rpb25zLCBhbmQgaWYgdGhleSBmYWlsLCB3ZSB3aWxsIGp1c3QgdHJ5IG90aGVyIG5vZGUgSURzIHVudGlsIHdlIGZpbmFsbHkgZG8gY29ubmVjdCwgYW5kIHRoZW4gd2Ugc3RpY2sgd2l0aCB0aGF0IG5vZGVJZCwgYW5kIHdoZW4gaXQgZGlzY29ubmVjdHMgd2UgbmVlZCB0byBoYW5kbGUgZGlzY29ubmVjdGlvbnMgbm9ybWFsbHkuXG4gICAgICAgICAgICBpZiAoc2tpcENsb3NlSGFuZGxpbmcgJiYgIWhhc0V2ZXJDb25uZWN0ZWQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNhbGxGYWN0b3J5LmNvbm5lY3Rpb25JZCA9IHsgbm9kZUlkIH07XG4gICAgICAgICAgICBjYWxsRmFjdG9yeS5sYXN0Q2xvc2VkID0gRGF0ZS5ub3coKTtcbiAgICAgICAgICAgIGNhbGxGYWN0b3J5LmlzQ29ubmVjdGVkID0gZmFsc2U7XG4gICAgICAgICAgICB3ZWJTb2NrZXRQcm9taXNlID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgaWYgKCFjYW5SZWNvbm5lY3QpIHtcbiAgICAgICAgICAgICAgICBjYWxsRmFjdG9yeS5jbG9zZWRGb3JldmVyID0gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGZvciAobGV0IFtrZXksIGNhbGxdIG9mIHBlbmRpbmdDYWxscykge1xuICAgICAgICAgICAgICAgIGhhcnZlc3RhYmxlRmFpbGVkQ2FsbHMrKztcbiAgICAgICAgICAgICAgICBwZW5kaW5nQ2FsbHMuZGVsZXRlKGtleSk7XG4gICAgICAgICAgICAgICAgY2FsbC5jYWxsYmFjayh7XG4gICAgICAgICAgICAgICAgICAgIGlzUmV0dXJuOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICByZXN1bHQ6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgICAgICAgZXJyb3I6IGVycm9yLFxuICAgICAgICAgICAgICAgICAgICBzZXFOdW06IGNhbGwuY2FsbC5zZXFOdW0sXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGxldCBjYWxsYmFja3MgPSBkaXNjb25uZWN0Q2FsbGJhY2tzO1xuICAgICAgICAgICAgZGlzY29ubmVjdENhbGxiYWNrcyA9IG5ldyBTZXQoKTtcbiAgICAgICAgICAgIGZvciAobGV0IGNhbGxiYWNrIG9mIGNhbGxiYWNrcykge1xuICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgIGNhbGxiYWNrKCk7XG4gICAgICAgICAgICAgICAgfSBjYXRjaCB7IH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIG5ld1dlYlNvY2tldC5hZGRFdmVudExpc3RlbmVyKFwiZXJyb3JcIiwgZSA9PiB7XG4gICAgICAgICAgICAvLyBOT1RFOiBObyBtb3JlIGxvZ2dpbmcsIGFzIHdlIHRocm93LCBzbyB0aGUgY2FsbGVyIHNob3VsZCBiZSBsb2dnaW5nIHRoZVxuICAgICAgICAgICAgLy8gIGVycm9yIChvciBzd2FsbG93aW5nIGl0LCBpZiB0aGF0IGlzIHdoYXQgaXQgd2FudHMgdG8gZG8pLlxuICAgICAgICAgICAgLy9jb25zb2xlLmxvZyhgV2Vic29ja2V0IGVycm9yIGZvciAke25pY2VDb25uZWN0aW9uTmFtZX1gLCBlLm1lc3NhZ2UpO1xuICAgICAgICAgICAgb25DbG9zZShuZXcgRXJyb3IoYENvbm5lY3Rpb24gZXJyb3IgZm9yICR7bmljZUNvbm5lY3Rpb25OYW1lfTogJHtlLm1lc3NhZ2V9YCkuc3RhY2shKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgbmV3V2ViU29ja2V0LmFkZEV2ZW50TGlzdGVuZXIoXCJjbG9zZVwiLCBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICAvL2NvbnNvbGUubG9nKGBXZWJzb2NrZXQgY2xvc2VkICR7bmljZUNvbm5lY3Rpb25OYW1lfWApO1xuICAgICAgICAgICAgb25DbG9zZShuZXcgRXJyb3IoYENvbm5lY3Rpb24gY2xvc2VkIHRvICR7bmljZUNvbm5lY3Rpb25OYW1lfWApLnN0YWNrISk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIG5ld1dlYlNvY2tldC5hZGRFdmVudExpc3RlbmVyKFwibWVzc2FnZVwiLCBvbk1lc3NhZ2UpO1xuXG5cbiAgICAgICAgaWYgKG5ld1dlYlNvY2tldC5yZWFkeVN0YXRlID09PSAwIC8qIENPTk5FQ1RJTkcgKi8pIHtcbiAgICAgICAgICAgIGF3YWl0IG5ldyBQcm9taXNlPHZvaWQ+KHJlc29sdmUgPT4ge1xuICAgICAgICAgICAgICAgIG5ld1dlYlNvY2tldC5hZGRFdmVudExpc3RlbmVyKFwib3BlblwiLCAoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGlmICghU29ja2V0RnVuY3Rpb24uc2lsZW50KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhgQ29ubmVjdGlvbiBlc3RhYmxpc2hlZCB0byAke25pY2VDb25uZWN0aW9uTmFtZX1gKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBjYWxsRmFjdG9yeS5pc0Nvbm5lY3RlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIGhhc0V2ZXJDb25uZWN0ZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgbmV3V2ViU29ja2V0LmFkZEV2ZW50TGlzdGVuZXIoXCJjbG9zZVwiLCAoKSA9PiByZXNvbHZlKCkpO1xuICAgICAgICAgICAgICAgIG5ld1dlYlNvY2tldC5hZGRFdmVudExpc3RlbmVyKFwiZXJyb3JcIiwgKCkgPT4gcmVzb2x2ZSgpKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2UgaWYgKG5ld1dlYlNvY2tldC5yZWFkeVN0YXRlID09PSAxIC8qIE9QRU4gKi8pIHtcbiAgICAgICAgICAgIGNhbGxGYWN0b3J5LmlzQ29ubmVjdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgIGhhc0V2ZXJDb25uZWN0ZWQgPSB0cnVlO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgb25DbG9zZShuZXcgRXJyb3IoYFdlYnNvY2tldCByZWNlaXZlZCBpbiBjbG9zZWQgc3RhdGVgKS5zdGFjayEpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGNhbGxGYWN0b3J5Lmxhc3RDbG9zZWQgJiYgY2FsbEZhY3RvcnkuaXNDb25uZWN0ZWQpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKGBTdWNjZXNzZnVsbHkgcmVjb25uZWN0ZWQgdG8gJHtub2RlSWR9LCB3aGljaCBoYXMgYmVlbiBjbG9zZWQgZm9yICR7Zm9ybWF0VGltZShEYXRlLm5vdygpIC0gY2FsbEZhY3RvcnkubGFzdENsb3NlZCl9YCwgeyBub2RlSWQgfSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoY2FsbEZhY3RvcnkuaXNDb25uZWN0ZWQgJiYgbmV3V2ViU29ja2V0LnByb3RvY29sKSB7XG4gICAgICAgICAgICBsZXQgZGVjb2RlZCA9IGRlY29kZVByb3RvY29sKG5ld1dlYlNvY2tldC5wcm90b2NvbCk7XG4gICAgICAgICAgICBpZiAoZGVjb2RlZCkge1xuICAgICAgICAgICAgICAgIGNhbGxGYWN0b3J5LnJlY2VpdmVkSW5pdGlhbGl6ZVN0YXRlID0ge1xuICAgICAgICAgICAgICAgICAgICBzdXBwb3J0c0xaNDogZGVjb2RlZC5mbGFncy5zZXJ2ZXJMWjQsXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICBjYWxsRmFjdG9yeS5wcm90b2NvbE5lZ290aWF0ZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgIGlmIChTb2NrZXRGdW5jdGlvbi5sb2dNZXNzYWdlcykge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhncmVlbihgTmVnb3RpYXRlZCBwcm90b2NvbCB3aXRoICR7bmljZUNvbm5lY3Rpb25OYW1lfTogdGFyZ2V0PSR7ZGVjb2RlZC50YXJnZXR9LCBjbGllbnRMWjQ9JHtkZWNvZGVkLmZsYWdzLmNsaWVudExaNH0sIHNlcnZlckxaND0ke2RlY29kZWQuZmxhZ3Muc2VydmVyTFo0fWApKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBCQVNFX0xFTkdUSF9PRkZTRVQgPSAzMjRfNDMyXzQ2MV81OTJfNjEyO1xuICAgIHR5cGUgTWVzc2FnZUhlYWRlciA9IHtcbiAgICAgICAgdHlwZTogXCJzZXJpYWxpemVkXCI7XG4gICAgICAgIGJ1ZmZlckNvdW50OiBudW1iZXI7XG4gICAgfSB8IHtcbiAgICAgICAgdHlwZTogXCJCdWZmZXJbXVwiIHwgXCJCdWZmZXJcIjtcbiAgICAgICAgYnVmZmVyQ291bnQ6IG51bWJlcjtcbiAgICAgICAgYnVmZmVyTGVuZ3Rocz86IG51bWJlcltdO1xuICAgICAgICBtZXRhZGF0YTogT21pdDxJbnRlcm5hbFJldHVyblR5cGUsIFwicmVzdWx0XCI+O1xuICAgIH07XG4gICAgbGV0IHNlbmRJblNlcmlhbCA9IHJ1bkluU2VyaWFsKGFzeW5jICh2YWw6ICgpID0+IFByb21pc2U8dm9pZD4pID0+IHZhbCgpKTtcbiAgICBhc3luYyBmdW5jdGlvbiBzZW5kUmF3KGRhdGE6IChzdHJpbmcgfCBCdWZmZXIpW10pIHtcbiAgICAgICAgaWYgKCF3ZWJTb2NrZXRQcm9taXNlKSB7XG4gICAgICAgICAgICBpZiAoY2FuUmVjb25uZWN0KSB7XG4gICAgICAgICAgICAgICAgd2ViU29ja2V0UHJvbWlzZSA9IHRyeVRvUmVjb25uZWN0KCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgQ2Fubm90IHNlbmQgZGF0YSB0byAke25pY2VDb25uZWN0aW9uTmFtZX0gYXMgdGhlIGNvbm5lY3Rpb24gaGFzIGNsb3NlZGApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGxldCB3ZWJTb2NrZXQgPSBhd2FpdCB3ZWJTb2NrZXRQcm9taXNlO1xuICAgICAgICBhd2FpdCBzZW5kSW5TZXJpYWwoYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgZm9yIChsZXQgZCBvZiBkYXRhKSB7XG4gICAgICAgICAgICAgICAgaWYgKGQubGVuZ3RoID4gMTAwMCAqIDEwMDAgKiAxMCkge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhgU2VuZGluZyBsYXJnZSBwYWNrZXQgJHtmb3JtYXROdW1iZXIoZC5sZW5ndGgpfUIgdG8gJHtub2RlSWR9IGF0ICR7RGF0ZS5ub3coKX1gKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyBOT1RFOiBJZiBvdXIgbGF0ZW5jeSBpcyA1MDBtcywgd2l0aCAxME1CL3MsIHRoZW4gd2UgbmVlZCBhIGhpZ2ggd2F0ZXJcbiAgICAgICAgICAgICAgICAvLyAgbWFyayBvZiBhdCBsZWFzdCA1TUIsIG90aGVyd2lzZSBvdXIgY29ubmVjdGlvbiBpcyBzbG93ZWQgZG93bi5cbiAgICAgICAgICAgICAgICAvLyAgLSBVc2luZyB0aGUgYWN0dWFsIGhpZ2ggd2F0ZXIgbWFyayBpcyB0b28gZGlmZmljdWx0LCBhcyB3ZSByZWNlaXZlIGluY29taW5nIGNvbm5lY3Rpb25zLlxuICAgICAgICAgICAgICAgIC8vICAgICAgVGhpcyBpcyBhbHNvIGVhc2llciB0byBjb25maWd1cmUsIGFuZCB3ZSBjYW4gZHluYW1pY2FsbHkgY2hhbmdlIGl0IGlmIHdlIGhhdmUgdG8uXG4gICAgICAgICAgICAgICAgLy8gTk9URTogSW4gcHJhY3RpY2Ugd2Ugb25seSBoaXQgdGhpcyB3aGVuIHNlbmRpbmcgbGFyZ2UgQnVmZmVycyAofjMwTUIpLCBzbyBsb3cgdmFsdWVzXG4gICAgICAgICAgICAgICAgLy8gIGFyZSBlcXVpdmFsZW50IHRvIHdhaXRpbmcgZm9yIGRyYWluLiBXZSB3YW50IHRvIGF2b2lkIHdhaXRpbmcgZm9yIGRyYWluLCBzbyB3ZSB1c2UgYSBoaWdoIHZhbHVlLlxuICAgICAgICAgICAgICAgIGNvbnN0IG1heFdyaXRlQnVmZmVyID0gMTI4ICogMTAyNCAqIDEwMjQ7XG4gICAgICAgICAgICAgICAgd2ViU29ja2V0LnNlbmQoZCk7XG5cbiAgICAgICAgICAgICAgICBsZXQgc29ja2V0ID0gd2ViU29ja2V0Ll9zb2NrZXQ7XG4gICAgICAgICAgICAgICAgaWYgKHNvY2tldCkge1xuICAgICAgICAgICAgICAgICAgICB3aGlsZSAoc29ja2V0LndyaXRhYmxlTGVuZ3RoID4gbWF4V3JpdGVCdWZmZXIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIE5PVEU6IFdhaXRpbmcgMW1zIHByb2JhYmx5IHdhaXRzIG1vcmUgbGlrZSAxNm1zLlxuICAgICAgICAgICAgICAgICAgICAgICAgYXdhaXQgbmV3IFByb21pc2UociA9PiBzZXRUaW1lb3V0KHIsIDEpKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuICAgIGFzeW5jIGZ1bmN0aW9uIHNlbmQoZGF0YTogQnVmZmVyW10pIHtcbiAgICAgICAgYXdhaXQgc2VuZFJhdyhbXG4gICAgICAgICAgICAoZGF0YS5sZW5ndGggKyBCQVNFX0xFTkdUSF9PRkZTRVQpLnRvU3RyaW5nKCksXG4gICAgICAgICAgICAuLi5kYXRhLFxuICAgICAgICBdKTtcbiAgICB9XG4gICAgYXN5bmMgZnVuY3Rpb24gc2VuZFdpdGhIZWFkZXIoZGF0YTogQnVmZmVyW10sIGhlYWRlcjogTWVzc2FnZUhlYWRlcikge1xuICAgICAgICBpZiAoZGF0YS5zb21lKHggPT4geC5sZW5ndGggPiBTb2NrZXRGdW5jdGlvbi5NQVhfTUVTU0FHRV9TSVpFICogMS41KSkge1xuICAgICAgICAgICAgaWYgKGhlYWRlci50eXBlID09PSBcIkJ1ZmZlclwiIHx8IGhlYWRlci50eXBlID09PSBcIkJ1ZmZlcltdXCIpIHtcbiAgICAgICAgICAgICAgICBoZWFkZXIuYnVmZmVyTGVuZ3RocyA9IGRhdGEubWFwKHggPT4geC5sZW5ndGgpO1xuICAgICAgICAgICAgICAgIGxldCBmaXRCdWZmZXJzOiBCdWZmZXJbXSA9IFtdO1xuICAgICAgICAgICAgICAgIGZvciAobGV0IGJ1ZiBvZiBkYXRhKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChidWYubGVuZ3RoID4gU29ja2V0RnVuY3Rpb24uTUFYX01FU1NBR0VfU0laRSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgbGV0IG9mZnNldCA9IDA7XG4gICAgICAgICAgICAgICAgICAgICAgICB3aGlsZSAob2Zmc2V0IDwgYnVmLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpdEJ1ZmZlcnMucHVzaChidWYuc2xpY2Uob2Zmc2V0LCBvZmZzZXQgKyBTb2NrZXRGdW5jdGlvbi5NQVhfTUVTU0FHRV9TSVpFKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb2Zmc2V0ICs9IFNvY2tldEZ1bmN0aW9uLk1BWF9NRVNTQUdFX1NJWkU7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBmaXRCdWZmZXJzLnB1c2goYnVmKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBkYXRhID0gZml0QnVmZmVycztcbiAgICAgICAgICAgICAgICBoZWFkZXIuYnVmZmVyQ291bnQgPSBmaXRCdWZmZXJzLmxlbmd0aDtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBDYW5ub3Qgc2VuZCBsYXJnZSBhbW91bnRzIG9mIGRhdGEgdW5sZXNzIHdlIGFyZSByZXR1cm5pbmcgQnVmZmVyIG9yIEJ1ZmZlcltdYCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgLy8gaWYgKHRvdGFsUmVzdWx0U2l6ZSA+IFNvY2tldEZ1bmN0aW9uLk1BWF9NRVNTQUdFX1NJWkUgKiAxLjUpIHtcbiAgICAgICAgLy8gU3BsaXQgdXAgQnVmZmVyW10gaWYgdGhleSBhcmUgdG9vIGxhcmdlXG4gICAgICAgIGF3YWl0IHNlbmRSYXcoW1xuICAgICAgICAgICAgSlNPTi5zdHJpbmdpZnkoaGVhZGVyKSxcbiAgICAgICAgICAgIC4uLmRhdGEsXG4gICAgICAgIF0pO1xuICAgIH1cbiAgICAvLyBJTVBPUlRBTlQhIE5FVkVSIGFsbG93IGZvciByZWNvbm5lY3Rpb24gb2YgY2xpZW50IGlkcy4gQSBsb3Qgb2YgY29kZSBkZXBlbmRzIG9uIHRoZSBmYWN0IHRoYXQgY2xpZW50cyB3aWxsIHJlY29ubmVjdCB3aXRoIGEgbmV3IGNsaWVudCBub2RlIGlkIHdoZW4gdGhleSBkaXNjb25uZWN0IVxuICAgIGFzeW5jIGZ1bmN0aW9uIHRyeVRvUmVjb25uZWN0KCk6IFByb21pc2U8U2VuZGVySW50ZXJmYWNlPiB7XG4gICAgICAgIC8vIERvbid0IHRyeSB0byByZWNvbm5lY3QgdG9vIG9mdGVuIVxuICAgICAgICBsZXQgdGltZVNpbmNlTGFzdEF0dGVtcHQgPSBEYXRlLm5vdygpIC0gbGFzdENvbm5lY3Rpb25BdHRlbXB0O1xuICAgICAgICBpZiAodGltZVNpbmNlTGFzdEF0dGVtcHQgPCBNSU5fUkVUUllfREVMQVkpIHtcbiAgICAgICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKHIgPT4gc2V0VGltZW91dChyLCBNSU5fUkVUUllfREVMQVkgLSB0aW1lU2luY2VMYXN0QXR0ZW1wdCkpO1xuICAgICAgICB9XG4gICAgICAgIGxhc3RDb25uZWN0aW9uQXR0ZW1wdCA9IERhdGUubm93KCk7XG5cbiAgICAgICAgLy8gVHJ5IGFsdGVybmF0ZXMsIGFuZCBpZiBhbnkgd29yaywgdXNlIHRoZW0uXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBsZXQgYWx0ZXJuYXRlcyA9IGF3YWl0IFNvY2tldEZ1bmN0aW9uLkdFVF9BTFRFUk5BVEVfTk9ERV9JRFMobm9kZUlkKTtcbiAgICAgICAgICAgIGlmIChhbHRlcm5hdGVzKSB7XG4gICAgICAgICAgICAgICAgZm9yIChsZXQgYWx0ZXJuYXRlTm9kZUlkIG9mIGFsdGVybmF0ZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgbGV0IG5ld1dlYlNvY2tldCA9IGNyZWF0ZVdlYnNvY2tldChhbHRlcm5hdGVOb2RlSWQsIHByb3Bvc2VQcm90b2NvbHMoaXNOb2RlKCkgPyBub2RlSWQgOiB1bmRlZmluZWQsIHsgbHo0OiB0cnVlIH0pKTtcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgaW5pdGlhbGl6ZVdlYnNvY2tldChuZXdXZWJTb2NrZXQsIHRydWUpO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmIChjYWxsRmFjdG9yeS5pc0Nvbm5lY3RlZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5ld1dlYlNvY2tldDtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIkVycm9yIGdldHRpbmcgYWx0ZXJuYXRlIG5vZGUgSURzXCIsIGUpO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IG5ld1dlYlNvY2tldCA9IGNyZWF0ZVdlYnNvY2tldChub2RlSWQsIHByb3Bvc2VQcm90b2NvbHMoIVNvY2tldEZ1bmN0aW9uLmlzQ2xpZW50KCkgPyBub2RlSWQgOiB1bmRlZmluZWQsIHsgbHo0OiB0cnVlIH0pKTtcbiAgICAgICAgYXdhaXQgaW5pdGlhbGl6ZVdlYnNvY2tldChuZXdXZWJTb2NrZXQpO1xuXG4gICAgICAgIHJldHVybiBuZXdXZWJTb2NrZXQ7XG4gICAgfVxuXG4gICAgbGV0IHBlbmRpbmdDYWxsOiBNZXNzYWdlSGVhZGVyICYge1xuICAgICAgICBidWZmZXJzOiBCdWZmZXJbXTtcbiAgICAgICAgZmlyc3RSZWNlaXZlZFRpbWU/OiBudW1iZXI7XG4gICAgfSB8IHVuZGVmaW5lZDtcblxuICAgIGFzeW5jIGZ1bmN0aW9uIHByb2Nlc3NQZW5kaW5nQ2FsbCgpIHtcbiAgICAgICAgaWYgKCFwZW5kaW5nQ2FsbCkgdGhyb3cgbmV3IEVycm9yKGBObyBwZW5kaW5nIGNhbGxgKTtcbiAgICAgICAgbGV0IGN1cnJlbnRDYWxsID0gcGVuZGluZ0NhbGw7XG4gICAgICAgIHBlbmRpbmdDYWxsID0gdW5kZWZpbmVkO1xuICAgICAgICBsZXQgY3VycmVudEJ1ZmZlcnMgPSBjdXJyZW50Q2FsbC5idWZmZXJzO1xuICAgICAgICBsZXQgY2FsbDogSW50ZXJuYWxDYWxsVHlwZSB8IEludGVybmFsUmV0dXJuVHlwZTtcbiAgICAgICAgbGV0IHJlc3VsdFNpemU6IG51bWJlcjtcbiAgICAgICAgbGV0IHRpbWUgPSBEYXRlLm5vdygpO1xuICAgICAgICBpZiAoY3VycmVudENhbGwudHlwZSA9PT0gXCJCdWZmZXJcIiB8fCBjdXJyZW50Q2FsbC50eXBlID09PSBcIkJ1ZmZlcltdXCIpIHtcbiAgICAgICAgICAgIGxldCByZXN1bHQ6IEJ1ZmZlciB8IEJ1ZmZlcltdID0gY3VycmVudEJ1ZmZlcnM7XG4gICAgICAgICAgICBpZiAoY3VycmVudENhbGwuYnVmZmVyTGVuZ3Rocykge1xuICAgICAgICAgICAgICAgIGxldCBwZW5kaW5nQnVmZmVycyA9IGN1cnJlbnRCdWZmZXJzO1xuICAgICAgICAgICAgICAgIGZ1bmN0aW9uIHRha2VCdWZmZXIobGVuOiBudW1iZXIpIHtcbiAgICAgICAgICAgICAgICAgICAgbGV0IGxlbkxlZnQgPSBsZW47XG4gICAgICAgICAgICAgICAgICAgIGxldCBidWZmZXJzOiBCdWZmZXJbXSA9IFtdO1xuICAgICAgICAgICAgICAgICAgICB3aGlsZSAobGVuTGVmdCA+IDApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGxldCBidWYgPSBjdXJyZW50QnVmZmVycy5zaGlmdCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFidWYpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYE5vdCBlbm91Z2ggYnVmZmVycyByZWNlaXZlZC5gKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChidWYubGVuZ3RoID4gbGVuTGVmdCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ1ZmZlcnMucHVzaChidWYuc2xpY2UoMCwgbGVuTGVmdCkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnRCdWZmZXJzLnVuc2hpZnQoYnVmLnNsaWNlKGxlbkxlZnQpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYnVmZmVycy5wdXNoKGJ1Zik7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVuTGVmdCAtPSBidWYubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGlmIChidWZmZXJzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGJ1ZmZlcnNbMF07XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIEJ1ZmZlci5jb25jYXQoYnVmZmVycyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJlc3VsdCA9IGN1cnJlbnRDYWxsLmJ1ZmZlckxlbmd0aHMubWFwKHRha2VCdWZmZXIpO1xuICAgICAgICAgICAgICAgIGlmIChwZW5kaW5nQnVmZmVycy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgUmVjZWl2ZWQgdG9vIG1hbnkgYnVmZmVycy5gKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXN1bHRTaXplID0gcmVzdWx0Lm1hcCh4ID0+IHgubGVuZ3RoKS5yZWR1Y2UoKGEsIGIpID0+IGEgKyBiLCAwKTtcbiAgICAgICAgICAgIGlmIChjdXJyZW50Q2FsbC50eXBlID09PSBcIkJ1ZmZlclwiKSB7XG4gICAgICAgICAgICAgICAgaWYgKHJlc3VsdC5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVzdWx0ID0gcmVzdWx0WzBdO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHJlc3VsdCA9IEJ1ZmZlci5jb25jYXQocmVzdWx0KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYWxsID0ge1xuICAgICAgICAgICAgICAgIC4uLmN1cnJlbnRDYWxsLm1ldGFkYXRhLFxuICAgICAgICAgICAgICAgIHJlc3VsdCxcbiAgICAgICAgICAgIH07XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXN1bHRTaXplID0gY3VycmVudEJ1ZmZlcnMubWFwKHggPT4geC5sZW5ndGgpLnJlZHVjZSgoYSwgYikgPT4gYSArIGIsIDApO1xuICAgICAgICAgICAgY2FsbCA9IGF3YWl0IFNvY2tldEZ1bmN0aW9uLldJUkVfU0VSSUFMSVpFUi5kZXNlcmlhbGl6ZShjdXJyZW50QnVmZmVycykgYXMgSW50ZXJuYWxDYWxsVHlwZSB8IEludGVybmFsUmV0dXJuVHlwZTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgcGFyc2VUaW1lID0gRGF0ZS5ub3coKSAtIHRpbWU7XG4gICAgICAgIGZvciAobGV0IGNhbGxiYWNrIG9mIFNvY2tldEZ1bmN0aW9uLnRyYWNrTWVzc2FnZVNpemVzLmRvd25sb2FkKSB7XG4gICAgICAgICAgICBjYWxsYmFjayhyZXN1bHRTaXplKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCByZWNlaXZlU3RhdHM6IENvbXByZXNzaW9uU3RhdHMgPSB7XG4gICAgICAgICAgICB1bmNvbXByZXNzZWRTaXplOiByZXN1bHRTaXplLFxuICAgICAgICAgICAgY29tcHJlc3NlZFNpemU6IHJlc3VsdFNpemUsXG4gICAgICAgIH07XG4gICAgICAgIGxldCBzZW5kU3RhdHM6IENvbXByZXNzaW9uU3RhdHMgPSB7XG4gICAgICAgICAgICB1bmNvbXByZXNzZWRTaXplOiAwLFxuICAgICAgICAgICAgY29tcHJlc3NlZFNpemU6IDAsXG4gICAgICAgIH07XG5cbiAgICAgICAgaWYgKGNhbGwuaXNSZXR1cm4pIHtcbiAgICAgICAgICAgIC8vIFRvbGVyYXRlIHRoZSBsZWdhY3kgaW5pdGlhbGl6ZSBwYWNrZXQgZnJvbSBvbGQgcGVlcnMg4oCUIHNpbGVudGx5XG4gICAgICAgICAgICAvLyBpZ25vcmUgc28gaXQgZG9lc24ndCBnZXQgbG9nZ2VkIGFzIGFuIHVua25vd24gY2FsbC4gT3VyIGFjdHVhbFxuICAgICAgICAgICAgLy8gaW5pdGlhbGl6ZSBzdGF0ZSBjb21lcyBmcm9tIFNlYy1XZWJTb2NrZXQtUHJvdG9jb2wgbmVnb3RpYXRpb24uXG4gICAgICAgICAgICBpZiAoY2FsbC5zZXFOdW0gPT09IElOSVRJQUxJWkVfU1RBVEVfU0VRX05VTSkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxldCBjYWxsYmFja09iaiA9IHBlbmRpbmdDYWxscy5nZXQoY2FsbC5zZXFOdW0pO1xuICAgICAgICAgICAgaWYgKHBhcnNlVGltZSA+IFNvY2tldEZ1bmN0aW9uLldJUkVfV0FSTl9USU1FKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2cocmVkKGBTbG93IHBhcnNlLCB0b29rICR7cGFyc2VUaW1lfW1zIHRvIHBhcnNlICR7cmVzdWx0U2l6ZX0gYnl0ZXMsIGZvciByZWNlaXZpbmcgcmVzdWx0IG9mIGNhbGwgdG8gJHtjYWxsYmFja09iaj8uY2FsbC5jbGFzc0d1aWR9LiR7Y2FsbGJhY2tPYmo/LmNhbGwuZnVuY3Rpb25OYW1lfWApKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICghY2FsbGJhY2tPYmopIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhibHVlKGBHb3QgcmV0dXJuIGZvciB1bmtub3duIGNhbGwgJHtjYWxsLnNlcU51bX0gKGNyZWF0ZWQgYXQgdGltZSAke25ldyBEYXRlKGNhbGwuc2VxTnVtKX0pLCAke25vZGVJZH0gLyAke2xvY2FsTm9kZUlkfWApKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoU29ja2V0RnVuY3Rpb24ubG9nTWVzc2FnZXMpIHtcbiAgICAgICAgICAgICAgICBsZXQgY2FsbCA9IGNhbGxiYWNrT2JqLmNhbGw7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2coYFNJWkVcXHQkeyhmb3JtYXROdW1iZXJTdWZmaXhlZChyZXN1bHRTaXplKSArIFwiQlwiKS5wYWRFbmQoNCwgXCIgXCIpfVxcdCR7Zm9ybWF0TnVtYmVyKGN1cnJlbnRCdWZmZXJzLmxlbmd0aCl9IGJ1ZmZlcnNcXHRSRVRVUk5cXHQke2NhbGwuY2xhc3NHdWlkfS4ke2NhbGwuZnVuY3Rpb25OYW1lfSBhdCAke0RhdGUubm93KCl9LCAoJHtub2RlSWR9IC8gJHtsb2NhbE5vZGVJZH0pYCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoY2FsbC5pc1Jlc3VsdENvbXByZXNzZWQgPT09IFwiTFo0XCIpIHtcbiAgICAgICAgICAgICAgICBjYWxsLnJlc3VsdCA9IGF3YWl0IGRlY29tcHJlc3NPYmpMWjQoY2FsbC5yZXN1bHQgYXMgQnVmZmVyW10sIHJlY2VpdmVTdGF0cyk7XG4gICAgICAgICAgICAgICAgY2FsbC5pc1Jlc3VsdENvbXByZXNzZWQgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGNhbGwuaXNSZXN1bHRDb21wcmVzc2VkID09PSBcInppcFwiIHx8IGNhbGwuaXNSZXN1bHRDb21wcmVzc2VkID09PSB0cnVlKSB7XG4gICAgICAgICAgICAgICAgY2FsbC5yZXN1bHQgPSBhd2FpdCBkZWNvbXByZXNzT2JqKGNhbGwucmVzdWx0IGFzIEJ1ZmZlciwgcmVjZWl2ZVN0YXRzKTtcbiAgICAgICAgICAgICAgICBjYWxsLmlzUmVzdWx0Q29tcHJlc3NlZCA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhbGxiYWNrT2JqLmNhbGxiYWNrKGNhbGwpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaWYgKGNhbGwuaXNBcmdzQ29tcHJlc3NlZCA9PT0gXCJMWjRcIikge1xuICAgICAgICAgICAgICAgIGNhbGwuYXJncyA9IGF3YWl0IGRlY29tcHJlc3NPYmpMWjQoY2FsbC5hcmdzIGFzIGFueSBhcyBCdWZmZXJbXSwgc2VuZFN0YXRzKSBhcyBhbnk7XG4gICAgICAgICAgICAgICAgY2FsbC5pc0FyZ3NDb21wcmVzc2VkID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChjYWxsLmlzQXJnc0NvbXByZXNzZWQgPT09IFwiemlwXCIgfHwgY2FsbC5pc0FyZ3NDb21wcmVzc2VkID09PSB0cnVlKSB7XG4gICAgICAgICAgICAgICAgY2FsbC5hcmdzID0gYXdhaXQgZGVjb21wcmVzc09iaihjYWxsLmFyZ3MgYXMgYW55IGFzIEJ1ZmZlciwgc2VuZFN0YXRzKSBhcyBhbnk7XG4gICAgICAgICAgICAgICAgY2FsbC5pc0FyZ3NDb21wcmVzc2VkID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKFNvY2tldEZ1bmN0aW9uLmxvZ01lc3NhZ2VzKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2coYFNJWkVcXHQkeyhmb3JtYXROdW1iZXJTdWZmaXhlZChyZXN1bHRTaXplKSArIFwiQlwiKS5wYWRFbmQoNCwgXCIgXCIpfVxcdEVWQUxVQVRFXFx0JHtjYWxsLmNsYXNzR3VpZH0uJHtjYWxsLmZ1bmN0aW9uTmFtZX0gYXQgJHtEYXRlLm5vdygpfSwgKCR7bm9kZUlkfSAvICR7bG9jYWxOb2RlSWR9KWApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHBhcnNlVGltZSA+IFNvY2tldEZ1bmN0aW9uLldJUkVfV0FSTl9USU1FKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2cocmVkKGBTbG93IHBhcnNlLCB0b29rICR7cGFyc2VUaW1lfW1zIHRvIHBhcnNlICR7cmVzdWx0U2l6ZX0gYnl0ZXMsIGZvciBjYWxsIHRvICR7Y2FsbC5jbGFzc0d1aWR9LiR7Y2FsbC5mdW5jdGlvbk5hbWV9YCkpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBsZXQgcmVzcG9uc2U6IEludGVybmFsUmV0dXJuVHlwZTtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgU29ja2V0RnVuY3Rpb24uVE9UQUxfQ0FMTFMrKztcbiAgICAgICAgICAgICAgICBsZXQgcmVzdWx0ID0gYXdhaXQgcGVyZm9ybUxvY2FsQ2FsbCh7IGNhbGwsIGNhbGxlcjogY2FsbGVyQ29udGV4dCB9KTtcbiAgICAgICAgICAgICAgICByZXNwb25zZSA9IHtcbiAgICAgICAgICAgICAgICAgICAgaXNSZXR1cm46IHRydWUsXG4gICAgICAgICAgICAgICAgICAgIHJlc3VsdCxcbiAgICAgICAgICAgICAgICAgICAgc2VxTnVtOiBjYWxsLnNlcU51bSxcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIGlmIChTb2NrZXRGdW5jdGlvbi5sb2dNZXNzYWdlcykge1xuICAgICAgICAgICAgICAgICAgICBsZXQgdGltZVRha2VuID0gRGF0ZS5ub3coKSAtIHRpbWU7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKGBEVVJcXHQkeyhmb3JtYXRUaW1lKHRpbWVUYWtlbikpLnBhZEVuZCg2LCBcIiBcIil9XFx0RklOSVNIXFx0JHtjYWxsLmNsYXNzR3VpZH0uJHtjYWxsLmZ1bmN0aW9uTmFtZX0gYXQgJHtEYXRlLm5vdygpfSwgKCR7bm9kZUlkfSAvICR7bG9jYWxOb2RlSWR9KWApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoY2FsbEZhY3RvcnkucmVjZWl2ZWRJbml0aWFsaXplU3RhdGU/LnN1cHBvcnRzTFo0KSB7XG4gICAgICAgICAgICAgICAgICAgIGxldCBjb21wcmVzc01vZGUgPSBzaG91bGRDb21wcmVzc0NhbGwoY2FsbCk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChjb21wcmVzc01vZGUgIT09IGZhbHNlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXNwb25zZS5yZXN1bHQgPSBhd2FpdCBjb21wcmVzc09iakxaNChyZXNwb25zZS5yZXN1bHQsIHNlbmRTdGF0cyk7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXNwb25zZS5pc1Jlc3VsdENvbXByZXNzZWQgPSBcIkxaNFwiO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHNob3VsZENvbXByZXNzQ2FsbChjYWxsKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVzcG9uc2UucmVzdWx0ID0gYXdhaXQgY29tcHJlc3NPYmoocmVzcG9uc2UucmVzdWx0LCBzZW5kU3RhdHMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVzcG9uc2UuaXNSZXN1bHRDb21wcmVzc2VkID0gXCJ6aXBcIjtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgICAgICAgICAgIHJlc3BvbnNlID0ge1xuICAgICAgICAgICAgICAgICAgICBpc1JldHVybjogdHJ1ZSxcbiAgICAgICAgICAgICAgICAgICAgcmVzdWx0OiB1bmRlZmluZWQsXG4gICAgICAgICAgICAgICAgICAgIHNlcU51bTogY2FsbC5zZXFOdW0sXG4gICAgICAgICAgICAgICAgICAgIGVycm9yOiBlLnN0YWNrLFxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbGV0IHN0YXJ0ID0gdGltZTtcbiAgICAgICAgICAgICAgICBsZXQgZW5kID0gRGF0ZS5ub3coKTtcbiAgICAgICAgICAgICAgICBmb3IgKGxldCBmbmMgb2YgU29ja2V0RnVuY3Rpb24udHJhY2tNZXNzYWdlU2l6ZXMuY2FsbFRpbWVzKSB7XG4gICAgICAgICAgICAgICAgICAgIGZuYyh7IHN0YXJ0LCBlbmQgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBsZXQgc2l6ZSA9IDA7XG5cbiAgICAgICAgICAgIGlmIChyZXNwb25zZS5yZXN1bHQgaW5zdGFuY2VvZiBCdWZmZXIpIHtcbiAgICAgICAgICAgICAgICBsZXQgeyByZXN1bHQsIC4uLnJlbWFpbmluZyB9ID0gcmVzcG9uc2U7XG4gICAgICAgICAgICAgICAgc2l6ZSA9IHJlc3VsdC5sZW5ndGg7XG4gICAgICAgICAgICAgICAgYXdhaXQgc2VuZFdpdGhIZWFkZXIoW3Jlc3VsdF0sIHsgdHlwZTogXCJCdWZmZXJcIiwgYnVmZmVyQ291bnQ6IDEsIG1ldGFkYXRhOiByZW1haW5pbmcgfSk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKEFycmF5LmlzQXJyYXkocmVzcG9uc2UucmVzdWx0KSAmJiByZXNwb25zZS5yZXN1bHQuZXZlcnkoeCA9PiB4IGluc3RhbmNlb2YgQnVmZmVyKSkge1xuICAgICAgICAgICAgICAgIGxldCB7IHJlc3VsdCwgLi4ucmVtYWluaW5nIH0gPSByZXNwb25zZTtcbiAgICAgICAgICAgICAgICBmb3IgKGxldCByIG9mIHJlc3VsdCkge1xuICAgICAgICAgICAgICAgICAgICBzaXplICs9IHIubGVuZ3RoO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBhd2FpdCBzZW5kV2l0aEhlYWRlcihyZXN1bHQsIHsgdHlwZTogXCJCdWZmZXJbXVwiLCBidWZmZXJDb3VudDogcmVzdWx0Lmxlbmd0aCwgbWV0YWRhdGE6IHJlbWFpbmluZyB9KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgY29uc3QgTElNSVQgPSBnZXRDYWxsRmxhZ3MoY2FsbCk/LnJlc3BvbnNlTGltaXQgfHwgU29ja2V0RnVuY3Rpb24uTUFYX01FU1NBR0VfU0laRSAqIDEuNTtcbiAgICAgICAgICAgICAgICBsZXQgcmVzdWx0OiBCdWZmZXJbXSA9IGF3YWl0IFNvY2tldEZ1bmN0aW9uLldJUkVfU0VSSUFMSVpFUi5zZXJpYWxpemUocmVzcG9uc2UpO1xuICAgICAgICAgICAgICAgIGxldCB0b3RhbFJlc3VsdFNpemUgPSByZXN1bHQubWFwKHggPT4geC5sZW5ndGgpLnJlZHVjZSgoYSwgYikgPT4gYSArIGIsIDApO1xuICAgICAgICAgICAgICAgIGlmICh0b3RhbFJlc3VsdFNpemUgPiBMSU1JVCkge1xuICAgICAgICAgICAgICAgICAgICByZXNwb25zZSA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlzUmV0dXJuOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0OiB1bmRlZmluZWQsXG4gICAgICAgICAgICAgICAgICAgICAgICBzZXFOdW06IGNhbGwuc2VxTnVtLFxuICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3I6IG5ldyBFcnJvcihgUmVzcG9uc2UgdG9vIGxhcmdlIHRvIHNlbmQuIFJldHVybiBCdWZmZXJbXSB0byBleGNlZWQgdGhlIGxpbWl0cywgb3Igc2V0IHJlc3BvbnNlTGltaXQgd2hlbiByZWdpc3RlcmluZyB0aGUgY29sbGVjdGlvbi4gJHtjYWxsLmNsYXNzR3VpZH0uJHtjYWxsLmZ1bmN0aW9uTmFtZX0sIHNpemU6ICR7Zm9ybWF0TnVtYmVyKHRvdGFsUmVzdWx0U2l6ZSl9ID4gJHtmb3JtYXROdW1iZXIoU29ja2V0RnVuY3Rpb24uTUFYX01FU1NBR0VfU0laRSl9LiBJZiB5b3UgbmVlZCB0byBoYW5kbGUgdmVyeSBsYXJnZSBzdGF0aWMgZGF0YSB1c2Ugc29tZSBleHRlcm5hbCBzZXJ2aWNlLCBzdWNoIGFzIEJhY2tibGF6ZSBCMiBvciBBV1MgUzMuIE9yLCBpZiBhYnNvbHV0ZWx5IHJlcXVpcmVkLCBzZXQgU29ja2V0RnVuY3Rpb24uTUFYX01FU1NBR0VfU0laRSB0byBhIGhpZ2hlciB2YWx1ZS5gKS5zdGFjayxcbiAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAgICAgcmVzdWx0ID0gYXdhaXQgU29ja2V0RnVuY3Rpb24uV0lSRV9TRVJJQUxJWkVSLnNlcmlhbGl6ZShyZXNwb25zZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGZvciAobGV0IHIgb2YgcmVzdWx0KSB7XG4gICAgICAgICAgICAgICAgICAgIHNpemUgKz0gci5sZW5ndGg7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGF3YWl0IHNlbmQocmVzdWx0KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gSWYgd2UgaGF2ZSBubyBzaXplLCB0aGVuIGl0J3MgcHJvYmFibHkgdW5jb21wcmVzc2VkXG4gICAgICAgICAgICBpZiAoIXNlbmRTdGF0cy5jb21wcmVzc2VkU2l6ZSkge1xuICAgICAgICAgICAgICAgIHNlbmRTdGF0cy5jb21wcmVzc2VkU2l6ZSA9IHNpemU7XG4gICAgICAgICAgICAgICAgc2VuZFN0YXRzLnVuY29tcHJlc3NlZFNpemUgPSBzaXplO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgYWRkU2VuZFN0YXRzKHNlbmRTdGF0cyk7XG4gICAgICAgIGFkZFJlY2VpdmVTdGF0cyhyZWNlaXZlU3RhdHMpO1xuICAgIH1cblxuICAgIGxldCBjbGllbnRzaWRlU2VyaWFsID0gcnVuSW5TZXJpYWwoYXN5bmMgPFQ+KHZhbDogUHJvbWlzZTxUPikgPT4gdmFsKTtcbiAgICBhc3luYyBmdW5jdGlvbiBvbk1lc3NhZ2UobWVzc2FnZTogd3MuUmF3RGF0YSB8IHdzLk1lc3NhZ2VFdmVudCB8IHN0cmluZykge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBtZXNzYWdlID09PSBcIm9iamVjdFwiICYmIFwiZGF0YVwiIGluIG1lc3NhZ2UpIHtcbiAgICAgICAgICAgICAgICBtZXNzYWdlID0gbWVzc2FnZS5kYXRhO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gRXh0cmEgY2xpZW5zaWRlIHBhcnNpbmcgaXMgcmVxdWlyZWRcbiAgICAgICAgICAgIGlmICghaXNOb2RlKCkpIHtcbiAgICAgICAgICAgICAgICAvLyBJbW1lZGlhdGVseSBzdGFydCB0aGUgYXJyYXlCdWZmZXIgY29udmVyc2lvbi4gVGhpcyBzaG91bGQgYmUgZmFzdCwgYnV0Li4uXG4gICAgICAgICAgICAgICAgLy8gIG1heWJlIHdlIHdpbGwgYWRkIG1vcmUgaGVyZSwgYW5kIHNvIGRvaW5nIGl0IGluIHBhcmFsbGVsIG1pZ2h0IGJlIHVzZWZ1bC5cbiAgICAgICAgICAgICAgICBsZXQgZml4TWVzc2FnZUJsb2IgPSAoYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBpZiAobWVzc2FnZSBpbnN0YW5jZW9mIEJsb2IpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBCdWZmZXIuZnJvbShhd2FpdCBtZXNzYWdlLmFycmF5QnVmZmVyKCkpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSkoKTtcbiAgICAgICAgICAgICAgICAvLyBXZSBuZWVkIHRvIGZvcmNlIHRoZSByZXN1bHRzIHRvIGJlIGluIHNlcmlhbCwgb3RoZXJ3aXNlIHN0cmluZ3MgbGVhcGZyb2dcbiAgICAgICAgICAgICAgICAvLyAgYWhlYWQgb2YgYnVmZmVycywgd2hpY2ggYnJlYWtzIHRoaW5ncy5cbiAgICAgICAgICAgICAgICBhd2FpdCBjbGllbnRzaWRlU2VyaWFsKGZpeE1lc3NhZ2VCbG9iKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh0eXBlb2YgbWVzc2FnZSA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgICAgIGlmIChtZXNzYWdlLnN0YXJ0c1dpdGgoXCJ7XCIpKSB7XG4gICAgICAgICAgICAgICAgICAgIGxldCBvYmogPSBKU09OLnBhcnNlKG1lc3NhZ2UpO1xuICAgICAgICAgICAgICAgICAgICBwZW5kaW5nQ2FsbCA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC4uLm9iaixcbiAgICAgICAgICAgICAgICAgICAgICAgIGJ1ZmZlcnM6IFtdLFxuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGxldCBjb3VudCA9IHBhcnNlSW50KG1lc3NhZ2UpO1xuICAgICAgICAgICAgICAgICAgICBpZiAoaXNOYU4oY291bnQpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgbWVzc2FnZSBjb3VudCAke21lc3NhZ2V9YCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgaWYgKGNvdW50IDwgQkFTRV9MRU5HVEhfT0ZGU0VUKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgbWVzc2FnZSBjb3VudCAke21lc3NhZ2V9YCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgY291bnQgLT0gQkFTRV9MRU5HVEhfT0ZGU0VUO1xuICAgICAgICAgICAgICAgICAgICBpZiAoY291bnQgPiAxMDAwICogMTAwMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIG1lc3NhZ2UgY291bnQgJHtjb3VudH1gKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBwZW5kaW5nQ2FsbCA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGJ1ZmZlcnM6IFtdLFxuICAgICAgICAgICAgICAgICAgICAgICAgYnVmZmVyQ291bnQ6IGNvdW50LFxuICAgICAgICAgICAgICAgICAgICAgICAgdHlwZTogXCJzZXJpYWxpemVkXCIsXG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChwZW5kaW5nQ2FsbD8uYnVmZmVyQ291bnQgPT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgcHJvY2Vzc1BlbmRpbmdDYWxsKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChtZXNzYWdlIGluc3RhbmNlb2YgQnVmZmVyKSB7XG4gICAgICAgICAgICAgICAgaWYgKCFwZW5kaW5nQ2FsbCkge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFJlY2VpdmVkIGRhdGEgd2l0aG91dCBzaXplICR7bWVzc2FnZS5ieXRlTGVuZ3RofUIsIGZpcnN0IDEwMCBieXRlczogJHttZXNzYWdlLnNsaWNlKDAsIDEwMCkudG9TdHJpbmcoXCJoZXhcIil9YCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGxldCB0b3RhbFNpemUgPSBtZXNzYWdlLmJ5dGVMZW5ndGggKyBwZW5kaW5nQ2FsbC5idWZmZXJzLnJlZHVjZSgoYSwgYikgPT4gYSArIGIubGVuZ3RoLCAwKTtcbiAgICAgICAgICAgICAgICBpZiAodG90YWxTaXplID4gMTAwMCAqIDEwMDAgKiAxMCB8fCBwZW5kaW5nQ2FsbC5idWZmZXJDb3VudCA+IDEwMDAgJiYgKHBlbmRpbmdDYWxsLmJ1ZmZlcnMubGVuZ3RoICUgMTAwID09PSAwKSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAocGVuZGluZ0NhbGwuYnVmZmVycy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKGBSZWNlaXZlZCBsYXJnZS9tYW55IHBhY2tldHMgJHtmb3JtYXROdW1iZXIodG90YWxTaXplKX1CICgke3BlbmRpbmdDYWxsLmJ1ZmZlcnMubGVuZ3RofSAvICR7cGVuZGluZ0NhbGwuYnVmZmVyQ291bnR9KSBhdCAke0RhdGUubm93KCl9YCk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBsZXQgZWxhcHNlZCA9IERhdGUubm93KCkgLSAocGVuZGluZ0NhbGwuZmlyc3RSZWNlaXZlZFRpbWUgfHwgMCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhgUmVjZWl2ZWQgbGFyZ2UvbWFueSBwYWNrZXRzICR7Zm9ybWF0TnVtYmVyKHRvdGFsU2l6ZSl9QiAoJHtwZW5kaW5nQ2FsbC5idWZmZXJzLmxlbmd0aH0gLyAke3BlbmRpbmdDYWxsLmJ1ZmZlckNvdW50fSkgYWZ0ZXIgJHtmb3JtYXRUaW1lKGVsYXBzZWQpfWApO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChwZW5kaW5nQ2FsbC5idWZmZXJzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgICAgICAgICBwZW5kaW5nQ2FsbC5maXJzdFJlY2VpdmVkVGltZSA9IERhdGUubm93KCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHBlbmRpbmdDYWxsLmJ1ZmZlcnMucHVzaChtZXNzYWdlKTtcbiAgICAgICAgICAgICAgICBpZiAocGVuZGluZ0NhbGwuYnVmZmVycy5sZW5ndGggIT09IHBlbmRpbmdDYWxsLmJ1ZmZlckNvdW50KSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBhd2FpdCBwcm9jZXNzUGVuZGluZ0NhbGwoKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVuaGFuZGxlZCBkYXRhIHR5cGUgJHt0eXBlb2YgbWVzc2FnZX1gKTtcbiAgICAgICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICAgICAgICBsZXQgZXJyID0gZS5zdGFjayB8fCBlLm1lc3NhZ2UgfHwgZTtcbiAgICAgICAgICAgIC8vIE5PVEU6IEknbSBsb29raW5nIGZvciBhbGwgdHlwZXMgb2YgZXJyb3JzIGhlcmUgKHNwZWNpZmljYWxseSwgLnNlbmQgZXJyb3JzKSwgaW4gY2FzZVxuICAgICAgICAgICAgLy8gIHRoZXJlIGFyZSBlcnJvcnMgSSBzaG91bGQgYmUgaGFuZGxpbmcuXG4gICAgICAgICAgICBpZiAoZXJyLnN0YXJ0c1dpdGgoXCJFcnJvcjogQ2Fubm90IHNlbmQgZGF0YSB0b1wiKSAmJiBlcnIuaW5jbHVkZXMoXCJhcyB0aGUgY29ubmVjdGlvbiBoYXMgY2xvc2VkXCIpKSB7XG4gICAgICAgICAgICAgICAgLy8gVGhpcyBpcyBmaW5lLCBqdXN0IGlnbm9yZSBpdFxuICAgICAgICAgICAgfSBlbHNlIGlmIChlcnIuaW5jbHVkZXMoXCJUaGUgcmVxdWVzdGVkIGZpbGUgY291bGQgbm90IGJlIHJlYWQsIHR5cGljYWxseSBkdWUgdG8gcGVybWlzc2lvbiBwcm9ibGVtcyB0aGF0IGhhdmUgb2NjdXJyZWQgYWZ0ZXIgYSByZWZlcmVuY2UgdG8gYSBmaWxlIHdhcyBhY3F1aXJlZC5cIikpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKGBXZWJTb2NrZXQgZGF0YSB3YXMgZHJvcHBlZCBieSB0aGUgYnJvd3NlciBkdWUgdG8gZXhjZWVkaW5nIHRoZSBCbG9iIGxpbWl0LiBFaXRoZXIgeW91IGFyZSBhYm91dCB0byBydW4gb3V0IG9mIG1lbW9yeSwgb3IgeW91IGhpdCB0aGUgbXVjaCBsb3dlciBJbmNvZ25pdG8gQmxvYiBsaW1pdC4gVGhpcyB3aWxsIGxpa2VseSBicmVhayB0aGUgYXBwbGljYXRpb24uIFRvIHJlc2V0IHRoZSBtZW1vcnkgeW91IG11c3QgY2xvc2UgYWxsIHRhYnMgb2YgdGhpcyBzaXRlLiBUaGlzIGlzIGEgYnVnL2ZlYXR1cmUgaW4gY2hyb21lLmApO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKGUuc3RhY2spO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG5cbiAgICByZXR1cm4gY2FsbEZhY3Rvcnk7XG59XG5cblxubGV0IHVuY29tcHJlc3NlZFNlbnQgPSAwO1xubGV0IGNvbXByZXNzZWRTZW50ID0gMDtcbmxldCB1bmNvbXByZXNzZWRSZWNlaXZlZCA9IDA7XG5sZXQgY29tcHJlc3NlZFJlY2VpdmVkID0gMDtcblxubGV0IHNlbmRDb3VudCA9IDA7XG5sZXQgcmVjZWl2ZUNvdW50ID0gMDtcblxuZnVuY3Rpb24gYWRkU2VuZFN0YXRzKHN0YXRzOiBDb21wcmVzc2lvblN0YXRzKSB7XG4gICAgdW5jb21wcmVzc2VkU2VudCArPSBzdGF0cy51bmNvbXByZXNzZWRTaXplO1xuICAgIGNvbXByZXNzZWRTZW50ICs9IHN0YXRzLmNvbXByZXNzZWRTaXplO1xuICAgIHNlbmRDb3VudCsrO1xufVxuZnVuY3Rpb24gYWRkUmVjZWl2ZVN0YXRzKHN0YXRzOiBDb21wcmVzc2lvblN0YXRzKSB7XG4gICAgdW5jb21wcmVzc2VkUmVjZWl2ZWQgKz0gc3RhdHMudW5jb21wcmVzc2VkU2l6ZTtcbiAgICBjb21wcmVzc2VkUmVjZWl2ZWQgKz0gc3RhdHMuY29tcHJlc3NlZFNpemU7XG4gICAgcmVjZWl2ZUNvdW50Kys7XG59XG5leHBvcnQgZnVuY3Rpb24gZ2V0U3RhdHMoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgdW5jb21wcmVzc2VkU2VudCxcbiAgICAgICAgY29tcHJlc3NlZFNlbnQsXG4gICAgICAgIHVuY29tcHJlc3NlZFJlY2VpdmVkLFxuICAgICAgICBjb21wcmVzc2VkUmVjZWl2ZWQsXG4gICAgICAgIHNlbmRDb3VudCxcbiAgICAgICAgcmVjZWl2ZUNvdW50LFxuICAgIH07XG59XG4vLyBSZWdpc3RlciB0aGlzIGxhdGUgYXMgSSBkb24ndCB3YW50IGl0IHRvIGFwcGVhciBiZWZvcmUgdGhlIG1lbW9yeSByZWdpc3RlciBpbmZvLCB3aGljaCBpcyB1c2UgbW9yZSB1c2VmdWwgdGhhbiB0aGUgbmV0d29yayBvbmUuIFxuc2V0SW1tZWRpYXRlKCgpID0+IHtcbiAgICByZWdpc3Rlck1lYXN1cmVJbmZvKCgpID0+IGBORVQgPT4gJHtmb3JtYXROdW1iZXIoY29tcHJlc3NlZFNlbnQpfUIgKCR7Zm9ybWF0TnVtYmVyKHVuY29tcHJlc3NlZFNlbnQpfUIvJHtmb3JtYXROdW1iZXIoc2VuZENvdW50KX0pIC8gPD0gJHtmb3JtYXROdW1iZXIoY29tcHJlc3NlZFJlY2VpdmVkKX1CICgke2Zvcm1hdE51bWJlcih1bmNvbXByZXNzZWRSZWNlaXZlZCl9Qi8ke2Zvcm1hdE51bWJlcihyZWNlaXZlQ291bnQpfSlgKTtcbn0pO1xuXG50eXBlIENvbXByZXNzaW9uU3RhdHMgPSB7XG4gICAgdW5jb21wcmVzc2VkU2l6ZTogbnVtYmVyO1xuICAgIGNvbXByZXNzZWRTaXplOiBudW1iZXI7XG59O1xuXG5jb25zdCBjb21wcmVzc09iaiA9IG1lYXN1cmVXcmFwKGFzeW5jIGZ1bmN0aW9uIHdpcmVDYWxsQ29tcHJlc3Mob2JqOiB1bmtub3duLCBzdGF0czogQ29tcHJlc3Npb25TdGF0cyk6IFByb21pc2U8QnVmZmVyPiB7XG4gICAgbGV0IGJ1ZmZlcnMgPSBhd2FpdCBTb2NrZXRGdW5jdGlvbi5XSVJFX1NFUklBTElaRVIuc2VyaWFsaXplKG9iaik7XG4gICAgaWYgKGJ1ZmZlcnMubGVuZ3RoID4gMSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJMZWdhY3kgQ29tcHJlc3NPYmogb25seSBzdXBwb3J0cyBzaW5nbGUgYnVmZmVyXCIpO1xuICAgIH1cbiAgICBsZXQgbGVuZ3RoQnVmZmVyID0gQnVmZmVyLmZyb20oKG5ldyBGbG9hdDY0QXJyYXkoYnVmZmVycy5tYXAoeCA9PiB4Lmxlbmd0aCkpKS5idWZmZXIpO1xuICAgIGxldCBidWZmZXIgPSBCdWZmZXIuY29uY2F0KFtsZW5ndGhCdWZmZXIsIC4uLmJ1ZmZlcnNdKTtcbiAgICBzdGF0cy51bmNvbXByZXNzZWRTaXplICs9IGJ1ZmZlci5sZW5ndGg7XG4gICAgbGV0IHJlc3VsdCA9IGF3YWl0IFppcC5nemlwKGJ1ZmZlcik7XG4gICAgc3RhdHMuY29tcHJlc3NlZFNpemUgKz0gcmVzdWx0Lmxlbmd0aDtcbiAgICByZXR1cm4gcmVzdWx0O1xufSk7XG4vLyBBc3N1bWVzIHRoZSBjYWxsZXIgYWxyZWFkeSBhZGRlZCB0aGUgb2JqLmxlbmd0aCB0byBib3RoIHRoZSB1bmNvbXByZXNzZWRTaXplIGFuZCBjb21wcmVzc2VkU2l6ZSwgYW5kIGlzIGp1c3QgbG9va2luZyB0byB1cGRhdGUgdGhlIHVuY29tcHJlc3NlZFNpemUgdG8gYmUgbGFyZ2VyIGFjY29yZGluZyB0byB0aGUgc2l6ZSBhZnRlciB3ZSB1bmNvbXByZXNzXG5jb25zdCBkZWNvbXByZXNzT2JqID0gbWVhc3VyZVdyYXAoYXN5bmMgZnVuY3Rpb24gd2lyZUNhbGxEZWNvbXByZXNzKG9iajogQnVmZmVyLCBzdGF0czogQ29tcHJlc3Npb25TdGF0cyk6IFByb21pc2U8dW5rbm93bj4ge1xuICAgIGxldCBidWZmZXIgPSBhd2FpdCBaaXAuZ3VuemlwKG9iaik7XG4gICAgc3RhdHMudW5jb21wcmVzc2VkU2l6ZSArPSBidWZmZXIubGVuZ3RoIC0gb2JqLmxlbmd0aDtcbiAgICBsZXQgbGVuZ3RoQnVmZmVyID0gYnVmZmVyLnNsaWNlKDAsIDgpO1xuICAgIGxldCBsZW5ndGhzID0gbmV3IEZsb2F0NjRBcnJheShsZW5ndGhCdWZmZXIuYnVmZmVyLCBsZW5ndGhCdWZmZXIuYnl0ZU9mZnNldCwgbGVuZ3RoQnVmZmVyLmJ5dGVMZW5ndGggLyA4KTtcbiAgICBsZXQgYnVmZmVyczogQnVmZmVyW10gPSBbXTtcbiAgICBsZXQgb2Zmc2V0ID0gODtcbiAgICBmb3IgKGxldCBsZW5ndGggb2YgbGVuZ3Rocykge1xuICAgICAgICBidWZmZXJzLnB1c2goYnVmZmVyLnNsaWNlKG9mZnNldCwgb2Zmc2V0ICsgbGVuZ3RoKSk7XG4gICAgICAgIG9mZnNldCArPSBsZW5ndGg7XG4gICAgfVxuICAgIGxldCByZXN1bHQgPSBhd2FpdCBTb2NrZXRGdW5jdGlvbi5XSVJFX1NFUklBTElaRVIuZGVzZXJpYWxpemUoYnVmZmVycyk7XG4gICAgcmV0dXJuIHJlc3VsdDtcbn0pO1xuXG5jb25zdCBjb21wcmVzc09iakxaNCA9IG1lYXN1cmVXcmFwKGFzeW5jIGZ1bmN0aW9uIHdpcmVDYWxsQ29tcHJlc3NMWjQob2JqOiB1bmtub3duLCBzdGF0czogQ29tcHJlc3Npb25TdGF0cyk6IFByb21pc2U8QnVmZmVyW10+IHtcbiAgICBjb25zdCB7IExaNCB9ID0gYXdhaXQgaW1wb3J0KFwiLi9sejQvTFo0XCIpO1xuICAgIGxldCBoZWFkZXJQYXJ0czogbnVtYmVyW107XG4gICAgbGV0IGRhdGFCdWZmZXJzOiBCdWZmZXJbXTtcblxuICAgIGlmIChvYmogaW5zdGFuY2VvZiBCdWZmZXIpIHtcbiAgICAgICAgaGVhZGVyUGFydHMgPSBbMV07XG4gICAgICAgIGRhdGFCdWZmZXJzID0gW29ial07XG4gICAgfSBlbHNlIGlmIChBcnJheS5pc0FycmF5KG9iaikgJiYgb2JqLmV2ZXJ5KCh4OiBhbnkpID0+IHggaW5zdGFuY2VvZiBCdWZmZXIpKSB7XG4gICAgICAgIGxldCBidWZmZXJBcnJheSA9IG9iaiBhcyBCdWZmZXJbXTtcbiAgICAgICAgY29uc3QgVEFSR0VUX1NJWkUgPSA1MCAqIDEwMjQgKiAxMDI0O1xuICAgICAgICBjb25zdCBNSU5fSU5ESVZJRFVBTF9TSVpFID0gMTAgKiAxMDI0ICogMTAyNDtcbiAgICAgICAgY29uc3QgTUFYX1VOU1BMSVRfU0laRSA9IDEwMCAqIDEwMjQgKiAxMDI0O1xuXG4gICAgICAgIGxldCBvdXRwdXRCdWZmZXJzOiBCdWZmZXJbXSA9IFtdO1xuICAgICAgICBsZXQgb3V0cHV0RGVzY3JpcHRvcnM6IG51bWJlcltdW10gPSBbXTtcbiAgICAgICAgbGV0IGN1cnJlbnRHcm91cDogQnVmZmVyW10gPSBbXTtcbiAgICAgICAgbGV0IGN1cnJlbnRHcm91cFNpemUgPSAwO1xuXG4gICAgICAgIGZ1bmN0aW9uIGZsdXNoQ3VycmVudEdyb3VwKCkge1xuICAgICAgICAgICAgaWYgKGN1cnJlbnRHcm91cC5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgb3V0cHV0QnVmZmVycy5wdXNoKEJ1ZmZlci5jb25jYXQoY3VycmVudEdyb3VwKSk7XG4gICAgICAgICAgICAgICAgb3V0cHV0RGVzY3JpcHRvcnMucHVzaChjdXJyZW50R3JvdXAubWFwKGIgPT4gYi5sZW5ndGgpKTtcbiAgICAgICAgICAgICAgICBjdXJyZW50R3JvdXAgPSBbXTtcbiAgICAgICAgICAgICAgICBjdXJyZW50R3JvdXBTaXplID0gMDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGZvciAobGV0IGJ1ZiBvZiBidWZmZXJBcnJheSkge1xuICAgICAgICAgICAgaWYgKGJ1Zi5sZW5ndGggPj0gTUlOX0lORElWSURVQUxfU0laRSkge1xuICAgICAgICAgICAgICAgIGZsdXNoQ3VycmVudEdyb3VwKCk7XG5cbiAgICAgICAgICAgICAgICBpZiAoYnVmLmxlbmd0aCA+IE1BWF9VTlNQTElUX1NJWkUpIHtcbiAgICAgICAgICAgICAgICAgICAgbGV0IG9mZnNldCA9IDA7XG4gICAgICAgICAgICAgICAgICAgIHdoaWxlIChvZmZzZXQgPCBidWYubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBsZXQgY2h1bmtTaXplID0gTWF0aC5taW4oVEFSR0VUX1NJWkUsIGJ1Zi5sZW5ndGggLSBvZmZzZXQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgb3V0cHV0QnVmZmVycy5wdXNoKGJ1Zi5zbGljZShvZmZzZXQsIG9mZnNldCArIGNodW5rU2l6ZSkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgb3V0cHV0RGVzY3JpcHRvcnMucHVzaChbY2h1bmtTaXplXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBvZmZzZXQgKz0gY2h1bmtTaXplO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgb3V0cHV0QnVmZmVycy5wdXNoKGJ1Zik7XG4gICAgICAgICAgICAgICAgICAgIG91dHB1dERlc2NyaXB0b3JzLnB1c2goW2J1Zi5sZW5ndGhdKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGN1cnJlbnRHcm91cC5wdXNoKGJ1Zik7XG4gICAgICAgICAgICAgICAgY3VycmVudEdyb3VwU2l6ZSArPSBidWYubGVuZ3RoO1xuXG4gICAgICAgICAgICAgICAgaWYgKGN1cnJlbnRHcm91cFNpemUgPj0gVEFSR0VUX1NJWkUpIHtcbiAgICAgICAgICAgICAgICAgICAgZmx1c2hDdXJyZW50R3JvdXAoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBmbHVzaEN1cnJlbnRHcm91cCgpO1xuXG4gICAgICAgIGhlYWRlclBhcnRzID0gWzIsIG91dHB1dEJ1ZmZlcnMubGVuZ3RoXTtcbiAgICAgICAgZm9yIChsZXQgZGVzY3JpcHRvciBvZiBvdXRwdXREZXNjcmlwdG9ycykge1xuICAgICAgICAgICAgaGVhZGVyUGFydHMucHVzaChkZXNjcmlwdG9yLmxlbmd0aCwgLi4uZGVzY3JpcHRvcik7XG4gICAgICAgIH1cbiAgICAgICAgZGF0YUJ1ZmZlcnMgPSBvdXRwdXRCdWZmZXJzO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGxldCBidWZmZXJzID0gYXdhaXQgU29ja2V0RnVuY3Rpb24uV0lSRV9TRVJJQUxJWkVSLnNlcmlhbGl6ZShvYmopO1xuICAgICAgICBoZWFkZXJQYXJ0cyA9IFszLCBidWZmZXJzLmxlbmd0aF07XG4gICAgICAgIGRhdGFCdWZmZXJzID0gYnVmZmVycztcbiAgICB9XG5cbiAgICBsZXQgaGVhZGVyQnVmZmVyID0gQnVmZmVyLmZyb20oKG5ldyBGbG9hdDY0QXJyYXkoaGVhZGVyUGFydHMpKS5idWZmZXIpO1xuICAgIGxldCBhbGxCdWZmZXJzID0gW2hlYWRlckJ1ZmZlciwgLi4uZGF0YUJ1ZmZlcnNdO1xuXG4gICAgc3RhdHMudW5jb21wcmVzc2VkU2l6ZSArPSBhbGxCdWZmZXJzLnJlZHVjZSgoc3VtLCBidWYpID0+IHN1bSArIGJ1Zi5sZW5ndGgsIDApO1xuXG4gICAgbGV0IGNvbXByZXNzZWQ6IEJ1ZmZlcltdID0gW107XG4gICAgbGV0IHN0YXJ0VGltZSA9IERhdGUubm93KCk7XG4gICAgbGV0IGxhc3RXYXJuVGltZSA9IHN0YXJ0VGltZTtcbiAgICBsZXQgY3VycmVudFVuY29tcHJlc3NlZFNpemUgPSAwO1xuICAgIGxldCBjdXJyZW50Q29tcHJlc3NlZFNpemUgPSAwO1xuXG4gICAgZnVuY3Rpb24gbG9nSWZTbG93KGk6IG51bWJlcikge1xuICAgICAgICBsZXQgbm93ID0gRGF0ZS5ub3coKTtcbiAgICAgICAgaWYgKG5vdyAtIGxhc3RXYXJuVGltZSA+IDUwMCkge1xuICAgICAgICAgICAgbGV0IGVsYXBzZWQgPSBub3cgLSBzdGFydFRpbWU7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgU2xvdyBMWjQgY29tcHJlc3MgKCR7Zm9ybWF0VGltZShlbGFwc2VkKX06ICR7aSArIDF9LyR7YWxsQnVmZmVycy5sZW5ndGh9IGJ1ZmZlcnMsICR7Zm9ybWF0TnVtYmVyKGN1cnJlbnRVbmNvbXByZXNzZWRTaXplKX1CID0+ICR7Zm9ybWF0TnVtYmVyKGN1cnJlbnRDb21wcmVzc2VkU2l6ZSl9QmApO1xuICAgICAgICAgICAgbGFzdFdhcm5UaW1lID0gbm93O1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBhbGxCdWZmZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGxldCBidWYgPSBhbGxCdWZmZXJzW2ldO1xuICAgICAgICBjdXJyZW50VW5jb21wcmVzc2VkU2l6ZSArPSBidWYubGVuZ3RoO1xuICAgICAgICBsZXQgY29tcHJlc3NlZEJ1ZiA9IExaNC5jb21wcmVzcyhidWYpO1xuICAgICAgICBjb21wcmVzc2VkLnB1c2goY29tcHJlc3NlZEJ1Zik7XG4gICAgICAgIGN1cnJlbnRDb21wcmVzc2VkU2l6ZSArPSBjb21wcmVzc2VkQnVmLmxlbmd0aDtcblxuICAgICAgICBsb2dJZlNsb3coaSk7XG4gICAgfVxuICAgIGxvZ0lmU2xvdyhhbGxCdWZmZXJzLmxlbmd0aCk7XG5cbiAgICBzdGF0cy5jb21wcmVzc2VkU2l6ZSArPSBjdXJyZW50Q29tcHJlc3NlZFNpemU7XG5cbiAgICByZXR1cm4gY29tcHJlc3NlZDtcbn0pO1xuXG5jb25zdCBkZWNvbXByZXNzT2JqTFo0ID0gbWVhc3VyZVdyYXAoYXN5bmMgZnVuY3Rpb24gd2lyZUNhbGxEZWNvbXByZXNzTFo0KG9iajogQnVmZmVyW10sIHN0YXRzOiBDb21wcmVzc2lvblN0YXRzKTogUHJvbWlzZTx1bmtub3duPiB7XG5cbiAgICBjb25zdCB7IExaNCB9ID0gYXdhaXQgaW1wb3J0KFwiLi9sejQvTFo0XCIpO1xuICAgIHN0YXRzLmNvbXByZXNzZWRTaXplICs9IG9iai5yZWR1Y2UoKHN1bSwgYnVmKSA9PiBzdW0gKyBidWYubGVuZ3RoLCAwKTtcblxuICAgIGxldCBkZWNvbXByZXNzZWQ6IEJ1ZmZlcltdID0gW107XG4gICAgbGV0IHN0YXJ0VGltZSA9IERhdGUubm93KCk7XG4gICAgbGV0IGxhc3RXYXJuVGltZSA9IHN0YXJ0VGltZTtcbiAgICBsZXQgY3VycmVudENvbXByZXNzZWRTaXplID0gMDtcbiAgICBsZXQgY3VycmVudFVuY29tcHJlc3NlZFNpemUgPSAwO1xuICAgIGZ1bmN0aW9uIGxvZ0lmU2xvdyhpOiBudW1iZXIpIHtcbiAgICAgICAgbGV0IG5vdyA9IERhdGUubm93KCk7XG4gICAgICAgIGlmIChub3cgLSBsYXN0V2FyblRpbWUgPiA1MDApIHtcbiAgICAgICAgICAgIGxldCBlbGFwc2VkID0gbm93IC0gc3RhcnRUaW1lO1xuICAgICAgICAgICAgY29uc29sZS5sb2coYFNsb3cgTFo0IGRlY29tcHJlc3MgKCR7Zm9ybWF0VGltZShlbGFwc2VkKX0pOiAke2kgKyAxfS8ke29iai5sZW5ndGh9IGJ1ZmZlcnMsICR7Zm9ybWF0TnVtYmVyKGN1cnJlbnRDb21wcmVzc2VkU2l6ZSl9QiA9PiAke2Zvcm1hdE51bWJlcihjdXJyZW50VW5jb21wcmVzc2VkU2l6ZSl9QmApO1xuICAgICAgICAgICAgbGFzdFdhcm5UaW1lID0gbm93O1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBvYmoubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgbGV0IGJ1ZiA9IG9ialtpXTtcbiAgICAgICAgY3VycmVudENvbXByZXNzZWRTaXplICs9IGJ1Zi5sZW5ndGg7XG4gICAgICAgIGxldCBkZWNvbXByZXNzZWRCdWYgPSBMWjQuZGVjb21wcmVzcyhidWYpO1xuICAgICAgICBkZWNvbXByZXNzZWQucHVzaChkZWNvbXByZXNzZWRCdWYpO1xuICAgICAgICBjdXJyZW50VW5jb21wcmVzc2VkU2l6ZSArPSBkZWNvbXByZXNzZWRCdWYubGVuZ3RoO1xuXG4gICAgICAgIGxvZ0lmU2xvdyhpKTtcbiAgICB9XG4gICAgbG9nSWZTbG93KG9iai5sZW5ndGgpO1xuXG4gICAgc3RhdHMudW5jb21wcmVzc2VkU2l6ZSArPSBjdXJyZW50VW5jb21wcmVzc2VkU2l6ZTtcblxuICAgIGxldCBoZWFkZXJCdWZmZXIgPSBkZWNvbXByZXNzZWRbMF07XG4gICAgbGV0IGRhdGFCdWZmZXJzID0gZGVjb21wcmVzc2VkLnNsaWNlKDEpO1xuXG4gICAgbGV0IHR5cGVCdWZmZXIgPSBoZWFkZXJCdWZmZXIuc2xpY2UoMCwgOCk7XG4gICAgbGV0IHR5cGUgPSBuZXcgRmxvYXQ2NEFycmF5KHR5cGVCdWZmZXIuYnVmZmVyLCB0eXBlQnVmZmVyLmJ5dGVPZmZzZXQsIDEpWzBdO1xuXG4gICAgaWYgKHR5cGUgPT09IDEpIHtcbiAgICAgICAgcmV0dXJuIGRhdGFCdWZmZXJzWzBdO1xuICAgIH1cblxuICAgIGlmICh0eXBlID09PSAyKSB7XG4gICAgICAgIGxldCBoZWFkZXJEYXRhID0gbmV3IEZsb2F0NjRBcnJheShoZWFkZXJCdWZmZXIuYnVmZmVyLCBoZWFkZXJCdWZmZXIuYnl0ZU9mZnNldCwgaGVhZGVyQnVmZmVyLmJ5dGVMZW5ndGggLyA4KTtcbiAgICAgICAgbGV0IG91dHB1dEJ1ZmZlckNvdW50ID0gaGVhZGVyRGF0YVsxXTtcblxuICAgICAgICBsZXQgYnVmZmVyczogQnVmZmVyW10gPSBbXTtcbiAgICAgICAgbGV0IGhlYWRlckluZGV4ID0gMjtcblxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG91dHB1dEJ1ZmZlckNvdW50OyBpKyspIHtcbiAgICAgICAgICAgIGxldCBpbnB1dEJ1ZmZlckNvdW50ID0gaGVhZGVyRGF0YVtoZWFkZXJJbmRleCsrXTtcbiAgICAgICAgICAgIGxldCBzaXplczogbnVtYmVyW10gPSBbXTtcbiAgICAgICAgICAgIGZvciAobGV0IGogPSAwOyBqIDwgaW5wdXRCdWZmZXJDb3VudDsgaisrKSB7XG4gICAgICAgICAgICAgICAgc2l6ZXMucHVzaChoZWFkZXJEYXRhW2hlYWRlckluZGV4KytdKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgbGV0IG91dHB1dEJ1ZmZlciA9IGRhdGFCdWZmZXJzW2ldO1xuICAgICAgICAgICAgbGV0IG9mZnNldCA9IDA7XG4gICAgICAgICAgICBmb3IgKGxldCBzaXplIG9mIHNpemVzKSB7XG4gICAgICAgICAgICAgICAgYnVmZmVycy5wdXNoKG91dHB1dEJ1ZmZlci5zbGljZShvZmZzZXQsIG9mZnNldCArIHNpemUpKTtcbiAgICAgICAgICAgICAgICBvZmZzZXQgKz0gc2l6ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBidWZmZXJzO1xuICAgIH1cblxuICAgIGlmICh0eXBlID09PSAzKSB7XG4gICAgICAgIGxldCByZXN1bHQgPSBhd2FpdCBTb2NrZXRGdW5jdGlvbi5XSVJFX1NFUklBTElaRVIuZGVzZXJpYWxpemUoZGF0YUJ1ZmZlcnMpO1xuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIHRocm93IG5ldyBFcnJvcihgVW5rbm93biBjb21wcmVzc2lvbiB0eXBlICR7dHlwZX1gKTtcbn0pOyJdfQ==
|
|
930
|
+
/* _JS_SOURCE_HASH = "c820da5d99596a319d37e9cb71d1bd23c38c5f13285953febf1fb51ed2b0b578"; */
|