state-sync-log 0.9.0
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/CHANGELOG.md +5 -0
- package/LICENSE +21 -0
- package/README.md +277 -0
- package/dist/state-sync-log.esm.js +1339 -0
- package/dist/state-sync-log.esm.mjs +1339 -0
- package/dist/state-sync-log.umd.js +1343 -0
- package/dist/types/ClientId.d.ts +1 -0
- package/dist/types/SortedTxEntry.d.ts +44 -0
- package/dist/types/StateCalculator.d.ts +141 -0
- package/dist/types/TxRecord.d.ts +14 -0
- package/dist/types/checkpointUtils.d.ts +15 -0
- package/dist/types/checkpoints.d.ts +62 -0
- package/dist/types/clientState.d.ts +19 -0
- package/dist/types/createStateSyncLog.d.ts +97 -0
- package/dist/types/draft.d.ts +69 -0
- package/dist/types/error.d.ts +4 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/json.d.ts +23 -0
- package/dist/types/operations.d.ts +64 -0
- package/dist/types/reconcile.d.ts +7 -0
- package/dist/types/txLog.d.ts +32 -0
- package/dist/types/txTimestamp.d.ts +27 -0
- package/dist/types/utils.d.ts +23 -0
- package/package.json +94 -0
- package/src/ClientId.ts +1 -0
- package/src/SortedTxEntry.ts +83 -0
- package/src/StateCalculator.ts +407 -0
- package/src/TxRecord.ts +15 -0
- package/src/checkpointUtils.ts +44 -0
- package/src/checkpoints.ts +208 -0
- package/src/clientState.ts +37 -0
- package/src/createStateSyncLog.ts +330 -0
- package/src/draft.ts +288 -0
- package/src/error.ts +12 -0
- package/src/index.ts +8 -0
- package/src/json.ts +25 -0
- package/src/operations.ts +157 -0
- package/src/reconcile.ts +124 -0
- package/src/txLog.ts +208 -0
- package/src/txTimestamp.ts +56 -0
- package/src/utils.ts +55 -0
|
@@ -0,0 +1,1343 @@
|
|
|
1
|
+
(function(global, factory) {
|
|
2
|
+
typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global["state-sync-log"] = {}));
|
|
3
|
+
})(this, (function(exports2) {
|
|
4
|
+
"use strict";var __defProp = Object.defineProperty;
|
|
5
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
7
|
+
|
|
8
|
+
function getFinalizedEpochAndCheckpoint(yCheckpoint) {
|
|
9
|
+
let maxEpoch = -1;
|
|
10
|
+
let best = null;
|
|
11
|
+
let bestTxCount = -1;
|
|
12
|
+
let bestClientId = "";
|
|
13
|
+
for (const [key, cp] of yCheckpoint.entries()) {
|
|
14
|
+
const { epoch, clientId } = parseCheckpointKey(key);
|
|
15
|
+
if (epoch > maxEpoch) {
|
|
16
|
+
maxEpoch = epoch;
|
|
17
|
+
best = cp;
|
|
18
|
+
bestTxCount = cp.txCount;
|
|
19
|
+
bestClientId = clientId;
|
|
20
|
+
} else if (epoch === maxEpoch) {
|
|
21
|
+
if (cp.txCount > bestTxCount || cp.txCount === bestTxCount && clientId < bestClientId) {
|
|
22
|
+
best = cp;
|
|
23
|
+
bestTxCount = cp.txCount;
|
|
24
|
+
bestClientId = clientId;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return { finalizedEpoch: maxEpoch, checkpoint: best };
|
|
29
|
+
}
|
|
30
|
+
class StateSyncLogError extends Error {
|
|
31
|
+
constructor(msg) {
|
|
32
|
+
super(msg);
|
|
33
|
+
Object.setPrototypeOf(this, StateSyncLogError.prototype);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function failure(message) {
|
|
37
|
+
throw new StateSyncLogError(message);
|
|
38
|
+
}
|
|
39
|
+
function checkpointKeyDataToKey(data) {
|
|
40
|
+
return `${data.epoch};${data.txCount};${data.clientId}`;
|
|
41
|
+
}
|
|
42
|
+
function parseCheckpointKey(key) {
|
|
43
|
+
const i1 = key.indexOf(";");
|
|
44
|
+
const i2 = key.indexOf(";", i1 + 1);
|
|
45
|
+
if (i1 === -1 || i2 === -1) {
|
|
46
|
+
failure(`Malformed checkpoint key: ${key}`);
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
epoch: Number.parseInt(key.substring(0, i1), 10),
|
|
50
|
+
txCount: Number.parseInt(key.substring(i1 + 1, i2), 10),
|
|
51
|
+
clientId: key.substring(i2 + 1)
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function createCheckpoint(yTx, yCheckpoint, clientState, activeEpoch, currentState, myClientId) {
|
|
55
|
+
const { checkpoint: prevCP } = getFinalizedEpochAndCheckpoint(yCheckpoint);
|
|
56
|
+
const newWatermarks = prevCP ? { ...prevCP.watermarks } : {};
|
|
57
|
+
const sortedTxs = clientState.stateCalculator.getSortedTxs();
|
|
58
|
+
let endIndex = sortedTxs.length;
|
|
59
|
+
while (endIndex > 0 && sortedTxs[endIndex - 1].txTimestamp.epoch > activeEpoch) {
|
|
60
|
+
endIndex--;
|
|
61
|
+
}
|
|
62
|
+
const activeTxs = sortedTxs.slice(0, endIndex);
|
|
63
|
+
if (activeTxs.length === 0) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
let minWallClock = Number.POSITIVE_INFINITY;
|
|
67
|
+
let txCount = 0;
|
|
68
|
+
for (const entry of activeTxs) {
|
|
69
|
+
const ts = entry.txTimestamp;
|
|
70
|
+
if (ts.wallClock < minWallClock) {
|
|
71
|
+
minWallClock = ts.wallClock;
|
|
72
|
+
}
|
|
73
|
+
const newWm = newWatermarks[ts.clientId] ? { ...newWatermarks[ts.clientId] } : { maxClock: -1, maxWallClock: 0 };
|
|
74
|
+
if (ts.clock > newWm.maxClock) {
|
|
75
|
+
newWm.maxClock = ts.clock;
|
|
76
|
+
newWm.maxWallClock = ts.wallClock;
|
|
77
|
+
}
|
|
78
|
+
newWatermarks[ts.clientId] = newWm;
|
|
79
|
+
txCount++;
|
|
80
|
+
}
|
|
81
|
+
for (const clientId in newWatermarks) {
|
|
82
|
+
if (minWallClock - newWatermarks[clientId].maxWallClock > clientState.retentionWindowMs) {
|
|
83
|
+
delete newWatermarks[clientId];
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const cpKey = checkpointKeyDataToKey({
|
|
87
|
+
epoch: activeEpoch,
|
|
88
|
+
txCount,
|
|
89
|
+
clientId: myClientId
|
|
90
|
+
});
|
|
91
|
+
yCheckpoint.set(cpKey, {
|
|
92
|
+
state: currentState,
|
|
93
|
+
// Responsibility for cloning is moved to the caller if needed
|
|
94
|
+
watermarks: newWatermarks,
|
|
95
|
+
txCount,
|
|
96
|
+
minWallClock
|
|
97
|
+
});
|
|
98
|
+
const keysToDelete = [];
|
|
99
|
+
for (const entry of activeTxs) {
|
|
100
|
+
yTx.delete(entry.txTimestampKey);
|
|
101
|
+
keysToDelete.push(entry.txTimestampKey);
|
|
102
|
+
}
|
|
103
|
+
clientState.stateCalculator.removeTxs(keysToDelete);
|
|
104
|
+
}
|
|
105
|
+
function pruneCheckpoints(yCheckpoint, finalizedEpoch) {
|
|
106
|
+
let canonicalKey = null;
|
|
107
|
+
let bestTxCount = -1;
|
|
108
|
+
for (const [key] of yCheckpoint.entries()) {
|
|
109
|
+
const { epoch, txCount } = parseCheckpointKey(key);
|
|
110
|
+
if (epoch === finalizedEpoch && txCount > bestTxCount) {
|
|
111
|
+
canonicalKey = key;
|
|
112
|
+
bestTxCount = txCount;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
for (const key of yCheckpoint.keys()) {
|
|
116
|
+
if (key !== canonicalKey) {
|
|
117
|
+
yCheckpoint.delete(key);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function getDefaultExportFromCjs(x) {
|
|
122
|
+
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
|
|
123
|
+
}
|
|
124
|
+
var fastDeepEqual;
|
|
125
|
+
var hasRequiredFastDeepEqual;
|
|
126
|
+
function requireFastDeepEqual() {
|
|
127
|
+
if (hasRequiredFastDeepEqual) return fastDeepEqual;
|
|
128
|
+
hasRequiredFastDeepEqual = 1;
|
|
129
|
+
fastDeepEqual = function equal2(a, b) {
|
|
130
|
+
if (a === b) return true;
|
|
131
|
+
if (a && b && typeof a == "object" && typeof b == "object") {
|
|
132
|
+
if (a.constructor !== b.constructor) return false;
|
|
133
|
+
var length, i, keys;
|
|
134
|
+
if (Array.isArray(a)) {
|
|
135
|
+
length = a.length;
|
|
136
|
+
if (length != b.length) return false;
|
|
137
|
+
for (i = length; i-- !== 0; )
|
|
138
|
+
if (!equal2(a[i], b[i])) return false;
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
|
|
142
|
+
if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
|
|
143
|
+
if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
|
|
144
|
+
keys = Object.keys(a);
|
|
145
|
+
length = keys.length;
|
|
146
|
+
if (length !== Object.keys(b).length) return false;
|
|
147
|
+
for (i = length; i-- !== 0; )
|
|
148
|
+
if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
|
|
149
|
+
for (i = length; i-- !== 0; ) {
|
|
150
|
+
var key = keys[i];
|
|
151
|
+
if (!equal2(a[key], b[key])) return false;
|
|
152
|
+
}
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
return a !== a && b !== b;
|
|
156
|
+
};
|
|
157
|
+
return fastDeepEqual;
|
|
158
|
+
}
|
|
159
|
+
var fastDeepEqualExports = requireFastDeepEqual();
|
|
160
|
+
const equal = /* @__PURE__ */ getDefaultExportFromCjs(fastDeepEqualExports);
|
|
161
|
+
const urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
|
|
162
|
+
let nanoid = (size = 21) => {
|
|
163
|
+
let id = "";
|
|
164
|
+
let bytes = crypto.getRandomValues(new Uint8Array(size |= 0));
|
|
165
|
+
while (size--) {
|
|
166
|
+
id += urlAlphabet[bytes[size] & 63];
|
|
167
|
+
}
|
|
168
|
+
return id;
|
|
169
|
+
};
|
|
170
|
+
var rfdc_1;
|
|
171
|
+
var hasRequiredRfdc;
|
|
172
|
+
function requireRfdc() {
|
|
173
|
+
if (hasRequiredRfdc) return rfdc_1;
|
|
174
|
+
hasRequiredRfdc = 1;
|
|
175
|
+
rfdc_1 = rfdc2;
|
|
176
|
+
function copyBuffer(cur) {
|
|
177
|
+
if (cur instanceof Buffer) {
|
|
178
|
+
return Buffer.from(cur);
|
|
179
|
+
}
|
|
180
|
+
return new cur.constructor(cur.buffer.slice(), cur.byteOffset, cur.length);
|
|
181
|
+
}
|
|
182
|
+
function rfdc2(opts) {
|
|
183
|
+
opts = opts || {};
|
|
184
|
+
if (opts.circles) return rfdcCircles(opts);
|
|
185
|
+
const constructorHandlers = /* @__PURE__ */ new Map();
|
|
186
|
+
constructorHandlers.set(Date, (o) => new Date(o));
|
|
187
|
+
constructorHandlers.set(Map, (o, fn) => new Map(cloneArray(Array.from(o), fn)));
|
|
188
|
+
constructorHandlers.set(Set, (o, fn) => new Set(cloneArray(Array.from(o), fn)));
|
|
189
|
+
if (opts.constructorHandlers) {
|
|
190
|
+
for (const handler2 of opts.constructorHandlers) {
|
|
191
|
+
constructorHandlers.set(handler2[0], handler2[1]);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
let handler = null;
|
|
195
|
+
return opts.proto ? cloneProto : clone2;
|
|
196
|
+
function cloneArray(a, fn) {
|
|
197
|
+
const keys = Object.keys(a);
|
|
198
|
+
const a2 = new Array(keys.length);
|
|
199
|
+
for (let i = 0; i < keys.length; i++) {
|
|
200
|
+
const k = keys[i];
|
|
201
|
+
const cur = a[k];
|
|
202
|
+
if (typeof cur !== "object" || cur === null) {
|
|
203
|
+
a2[k] = cur;
|
|
204
|
+
} else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
|
|
205
|
+
a2[k] = handler(cur, fn);
|
|
206
|
+
} else if (ArrayBuffer.isView(cur)) {
|
|
207
|
+
a2[k] = copyBuffer(cur);
|
|
208
|
+
} else {
|
|
209
|
+
a2[k] = fn(cur);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return a2;
|
|
213
|
+
}
|
|
214
|
+
function clone2(o) {
|
|
215
|
+
if (typeof o !== "object" || o === null) return o;
|
|
216
|
+
if (Array.isArray(o)) return cloneArray(o, clone2);
|
|
217
|
+
if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) {
|
|
218
|
+
return handler(o, clone2);
|
|
219
|
+
}
|
|
220
|
+
const o2 = {};
|
|
221
|
+
for (const k in o) {
|
|
222
|
+
if (Object.hasOwnProperty.call(o, k) === false) continue;
|
|
223
|
+
const cur = o[k];
|
|
224
|
+
if (typeof cur !== "object" || cur === null) {
|
|
225
|
+
o2[k] = cur;
|
|
226
|
+
} else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
|
|
227
|
+
o2[k] = handler(cur, clone2);
|
|
228
|
+
} else if (ArrayBuffer.isView(cur)) {
|
|
229
|
+
o2[k] = copyBuffer(cur);
|
|
230
|
+
} else {
|
|
231
|
+
o2[k] = clone2(cur);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return o2;
|
|
235
|
+
}
|
|
236
|
+
function cloneProto(o) {
|
|
237
|
+
if (typeof o !== "object" || o === null) return o;
|
|
238
|
+
if (Array.isArray(o)) return cloneArray(o, cloneProto);
|
|
239
|
+
if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) {
|
|
240
|
+
return handler(o, cloneProto);
|
|
241
|
+
}
|
|
242
|
+
const o2 = {};
|
|
243
|
+
for (const k in o) {
|
|
244
|
+
const cur = o[k];
|
|
245
|
+
if (typeof cur !== "object" || cur === null) {
|
|
246
|
+
o2[k] = cur;
|
|
247
|
+
} else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
|
|
248
|
+
o2[k] = handler(cur, cloneProto);
|
|
249
|
+
} else if (ArrayBuffer.isView(cur)) {
|
|
250
|
+
o2[k] = copyBuffer(cur);
|
|
251
|
+
} else {
|
|
252
|
+
o2[k] = cloneProto(cur);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return o2;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
function rfdcCircles(opts) {
|
|
259
|
+
const refs = [];
|
|
260
|
+
const refsNew = [];
|
|
261
|
+
const constructorHandlers = /* @__PURE__ */ new Map();
|
|
262
|
+
constructorHandlers.set(Date, (o) => new Date(o));
|
|
263
|
+
constructorHandlers.set(Map, (o, fn) => new Map(cloneArray(Array.from(o), fn)));
|
|
264
|
+
constructorHandlers.set(Set, (o, fn) => new Set(cloneArray(Array.from(o), fn)));
|
|
265
|
+
if (opts.constructorHandlers) {
|
|
266
|
+
for (const handler2 of opts.constructorHandlers) {
|
|
267
|
+
constructorHandlers.set(handler2[0], handler2[1]);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
let handler = null;
|
|
271
|
+
return opts.proto ? cloneProto : clone2;
|
|
272
|
+
function cloneArray(a, fn) {
|
|
273
|
+
const keys = Object.keys(a);
|
|
274
|
+
const a2 = new Array(keys.length);
|
|
275
|
+
for (let i = 0; i < keys.length; i++) {
|
|
276
|
+
const k = keys[i];
|
|
277
|
+
const cur = a[k];
|
|
278
|
+
if (typeof cur !== "object" || cur === null) {
|
|
279
|
+
a2[k] = cur;
|
|
280
|
+
} else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
|
|
281
|
+
a2[k] = handler(cur, fn);
|
|
282
|
+
} else if (ArrayBuffer.isView(cur)) {
|
|
283
|
+
a2[k] = copyBuffer(cur);
|
|
284
|
+
} else {
|
|
285
|
+
const index = refs.indexOf(cur);
|
|
286
|
+
if (index !== -1) {
|
|
287
|
+
a2[k] = refsNew[index];
|
|
288
|
+
} else {
|
|
289
|
+
a2[k] = fn(cur);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return a2;
|
|
294
|
+
}
|
|
295
|
+
function clone2(o) {
|
|
296
|
+
if (typeof o !== "object" || o === null) return o;
|
|
297
|
+
if (Array.isArray(o)) return cloneArray(o, clone2);
|
|
298
|
+
if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) {
|
|
299
|
+
return handler(o, clone2);
|
|
300
|
+
}
|
|
301
|
+
const o2 = {};
|
|
302
|
+
refs.push(o);
|
|
303
|
+
refsNew.push(o2);
|
|
304
|
+
for (const k in o) {
|
|
305
|
+
if (Object.hasOwnProperty.call(o, k) === false) continue;
|
|
306
|
+
const cur = o[k];
|
|
307
|
+
if (typeof cur !== "object" || cur === null) {
|
|
308
|
+
o2[k] = cur;
|
|
309
|
+
} else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
|
|
310
|
+
o2[k] = handler(cur, clone2);
|
|
311
|
+
} else if (ArrayBuffer.isView(cur)) {
|
|
312
|
+
o2[k] = copyBuffer(cur);
|
|
313
|
+
} else {
|
|
314
|
+
const i = refs.indexOf(cur);
|
|
315
|
+
if (i !== -1) {
|
|
316
|
+
o2[k] = refsNew[i];
|
|
317
|
+
} else {
|
|
318
|
+
o2[k] = clone2(cur);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
refs.pop();
|
|
323
|
+
refsNew.pop();
|
|
324
|
+
return o2;
|
|
325
|
+
}
|
|
326
|
+
function cloneProto(o) {
|
|
327
|
+
if (typeof o !== "object" || o === null) return o;
|
|
328
|
+
if (Array.isArray(o)) return cloneArray(o, cloneProto);
|
|
329
|
+
if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) {
|
|
330
|
+
return handler(o, cloneProto);
|
|
331
|
+
}
|
|
332
|
+
const o2 = {};
|
|
333
|
+
refs.push(o);
|
|
334
|
+
refsNew.push(o2);
|
|
335
|
+
for (const k in o) {
|
|
336
|
+
const cur = o[k];
|
|
337
|
+
if (typeof cur !== "object" || cur === null) {
|
|
338
|
+
o2[k] = cur;
|
|
339
|
+
} else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
|
|
340
|
+
o2[k] = handler(cur, cloneProto);
|
|
341
|
+
} else if (ArrayBuffer.isView(cur)) {
|
|
342
|
+
o2[k] = copyBuffer(cur);
|
|
343
|
+
} else {
|
|
344
|
+
const i = refs.indexOf(cur);
|
|
345
|
+
if (i !== -1) {
|
|
346
|
+
o2[k] = refsNew[i];
|
|
347
|
+
} else {
|
|
348
|
+
o2[k] = cloneProto(cur);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
refs.pop();
|
|
353
|
+
refsNew.pop();
|
|
354
|
+
return o2;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
return rfdc_1;
|
|
358
|
+
}
|
|
359
|
+
var rfdcExports = requireRfdc();
|
|
360
|
+
const rfdc = /* @__PURE__ */ getDefaultExportFromCjs(rfdcExports);
|
|
361
|
+
const clone = rfdc({ proto: true });
|
|
362
|
+
function deepEqual(a, b) {
|
|
363
|
+
return equal(a, b);
|
|
364
|
+
}
|
|
365
|
+
function generateID() {
|
|
366
|
+
return nanoid();
|
|
367
|
+
}
|
|
368
|
+
function isObject(value) {
|
|
369
|
+
return value !== null && typeof value === "object";
|
|
370
|
+
}
|
|
371
|
+
function deepClone(value) {
|
|
372
|
+
if (value === null || typeof value !== "object") {
|
|
373
|
+
return value;
|
|
374
|
+
}
|
|
375
|
+
return clone(value);
|
|
376
|
+
}
|
|
377
|
+
function lazy(fn) {
|
|
378
|
+
let computed = false;
|
|
379
|
+
let value;
|
|
380
|
+
return () => {
|
|
381
|
+
if (!computed) {
|
|
382
|
+
value = fn();
|
|
383
|
+
computed = true;
|
|
384
|
+
}
|
|
385
|
+
return value;
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
function createDraft(base) {
|
|
389
|
+
return {
|
|
390
|
+
root: base,
|
|
391
|
+
base,
|
|
392
|
+
ownedObjects: /* @__PURE__ */ new Set(),
|
|
393
|
+
isRootOwned: false
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
function shallowClone(obj) {
|
|
397
|
+
if (Array.isArray(obj)) {
|
|
398
|
+
return obj.slice();
|
|
399
|
+
}
|
|
400
|
+
const clone2 = {};
|
|
401
|
+
const keys = Object.keys(obj);
|
|
402
|
+
for (let i = 0; i < keys.length; i++) {
|
|
403
|
+
const key = keys[i];
|
|
404
|
+
clone2[key] = obj[key];
|
|
405
|
+
}
|
|
406
|
+
return clone2;
|
|
407
|
+
}
|
|
408
|
+
function ensureOwned(ctx, parent, key, child) {
|
|
409
|
+
if (ctx.ownedObjects.has(child)) {
|
|
410
|
+
return child;
|
|
411
|
+
}
|
|
412
|
+
const cloned = shallowClone(child);
|
|
413
|
+
parent[key] = cloned;
|
|
414
|
+
ctx.ownedObjects.add(cloned);
|
|
415
|
+
return cloned;
|
|
416
|
+
}
|
|
417
|
+
function ensureOwnedPath(ctx, path) {
|
|
418
|
+
if (!ctx.isRootOwned) {
|
|
419
|
+
ctx.root = shallowClone(ctx.root);
|
|
420
|
+
ctx.ownedObjects.add(ctx.root);
|
|
421
|
+
ctx.isRootOwned = true;
|
|
422
|
+
}
|
|
423
|
+
if (path.length === 0) {
|
|
424
|
+
return ctx.root;
|
|
425
|
+
}
|
|
426
|
+
let current = ctx.root;
|
|
427
|
+
for (let i = 0; i < path.length; i++) {
|
|
428
|
+
const segment = path[i];
|
|
429
|
+
const isArrayIndex = typeof segment === "number";
|
|
430
|
+
if (isArrayIndex) {
|
|
431
|
+
if (!Array.isArray(current)) {
|
|
432
|
+
failure(`Expected array at path segment ${segment}`);
|
|
433
|
+
}
|
|
434
|
+
if (segment < 0 || segment >= current.length) {
|
|
435
|
+
failure(`Index ${segment} out of bounds`);
|
|
436
|
+
}
|
|
437
|
+
} else {
|
|
438
|
+
if (!isObject(current) || Array.isArray(current)) {
|
|
439
|
+
failure(`Expected object at path segment "${segment}"`);
|
|
440
|
+
}
|
|
441
|
+
if (!(segment in current)) {
|
|
442
|
+
failure(`Property "${segment}" does not exist`);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
const child = current[segment];
|
|
446
|
+
if (child === null || typeof child !== "object") {
|
|
447
|
+
failure(`Cannot traverse through primitive at path segment ${segment}`);
|
|
448
|
+
}
|
|
449
|
+
current = ensureOwned(ctx, current, segment, child);
|
|
450
|
+
}
|
|
451
|
+
return current;
|
|
452
|
+
}
|
|
453
|
+
function draftSet(ctx, path, key, value) {
|
|
454
|
+
const container = ensureOwnedPath(ctx, path);
|
|
455
|
+
if (Array.isArray(container)) {
|
|
456
|
+
failure("set requires object container");
|
|
457
|
+
}
|
|
458
|
+
container[key] = value;
|
|
459
|
+
}
|
|
460
|
+
function draftDelete(ctx, path, key) {
|
|
461
|
+
const container = ensureOwnedPath(ctx, path);
|
|
462
|
+
if (Array.isArray(container)) {
|
|
463
|
+
failure("delete requires object container");
|
|
464
|
+
}
|
|
465
|
+
delete container[key];
|
|
466
|
+
}
|
|
467
|
+
function draftSplice(ctx, path, index, deleteCount, inserts) {
|
|
468
|
+
const container = ensureOwnedPath(ctx, path);
|
|
469
|
+
if (!Array.isArray(container)) {
|
|
470
|
+
failure("splice requires array container");
|
|
471
|
+
}
|
|
472
|
+
const safeIndex = Math.min(index, container.length);
|
|
473
|
+
if (inserts.length === 0) {
|
|
474
|
+
container.splice(safeIndex, deleteCount);
|
|
475
|
+
} else if (inserts.length === 1) {
|
|
476
|
+
container.splice(safeIndex, deleteCount, inserts[0]);
|
|
477
|
+
} else {
|
|
478
|
+
container.splice(safeIndex, deleteCount, ...inserts);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
function draftAddToSet(ctx, path, value) {
|
|
482
|
+
const container = ensureOwnedPath(ctx, path);
|
|
483
|
+
if (!Array.isArray(container)) {
|
|
484
|
+
failure("addToSet requires array container");
|
|
485
|
+
}
|
|
486
|
+
if (!container.some((item) => deepEqual(item, value))) {
|
|
487
|
+
container.push(value);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
function draftDeleteFromSet(ctx, path, value) {
|
|
491
|
+
const container = ensureOwnedPath(ctx, path);
|
|
492
|
+
if (!Array.isArray(container)) {
|
|
493
|
+
failure("deleteFromSet requires array container");
|
|
494
|
+
}
|
|
495
|
+
for (let i = container.length - 1; i >= 0; i--) {
|
|
496
|
+
if (deepEqual(container[i], value)) {
|
|
497
|
+
container.splice(i, 1);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
function applyOpToDraft(ctx, op) {
|
|
502
|
+
switch (op.kind) {
|
|
503
|
+
case "set":
|
|
504
|
+
draftSet(ctx, op.path, op.key, op.value);
|
|
505
|
+
break;
|
|
506
|
+
case "delete":
|
|
507
|
+
draftDelete(ctx, op.path, op.key);
|
|
508
|
+
break;
|
|
509
|
+
case "splice":
|
|
510
|
+
draftSplice(ctx, op.path, op.index, op.deleteCount, op.inserts);
|
|
511
|
+
break;
|
|
512
|
+
case "addToSet":
|
|
513
|
+
draftAddToSet(ctx, op.path, op.value);
|
|
514
|
+
break;
|
|
515
|
+
case "deleteFromSet":
|
|
516
|
+
draftDeleteFromSet(ctx, op.path, op.value);
|
|
517
|
+
break;
|
|
518
|
+
default:
|
|
519
|
+
throw failure(`Unknown operation kind: ${op.kind}`);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
function applyTxImmutable(base, tx, validateFn) {
|
|
523
|
+
if (tx.ops.length === 0) return base;
|
|
524
|
+
const ctx = createDraft(base);
|
|
525
|
+
try {
|
|
526
|
+
for (const op of tx.ops) {
|
|
527
|
+
applyOpToDraft(ctx, op);
|
|
528
|
+
}
|
|
529
|
+
if (validateFn && !validateFn(ctx.root)) {
|
|
530
|
+
return base;
|
|
531
|
+
}
|
|
532
|
+
return ctx.root;
|
|
533
|
+
} catch {
|
|
534
|
+
return base;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
function computeReconcileOps(currentState, targetState) {
|
|
538
|
+
const ops = [];
|
|
539
|
+
diffValue(currentState, targetState, [], ops);
|
|
540
|
+
return ops;
|
|
541
|
+
}
|
|
542
|
+
function diffValue(current, target, path, ops) {
|
|
543
|
+
if (current === target) return;
|
|
544
|
+
const currentType = typeof current;
|
|
545
|
+
const targetType = typeof target;
|
|
546
|
+
if (current === null || target === null || currentType !== "object" || targetType !== "object") {
|
|
547
|
+
emitReplace(path, target, ops);
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
const currentIsArray = Array.isArray(current);
|
|
551
|
+
const targetIsArray = Array.isArray(target);
|
|
552
|
+
if (currentIsArray !== targetIsArray) {
|
|
553
|
+
emitReplace(path, target, ops);
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
if (currentIsArray) {
|
|
557
|
+
diffArray(current, target, path, ops);
|
|
558
|
+
} else {
|
|
559
|
+
diffObject(current, target, path, ops);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
function diffObject(current, target, path, ops) {
|
|
563
|
+
for (const key in current) {
|
|
564
|
+
if (Object.hasOwn(current, key) && !Object.hasOwn(target, key)) {
|
|
565
|
+
ops.push({ kind: "delete", path, key });
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
for (const key in target) {
|
|
569
|
+
if (Object.hasOwn(target, key)) {
|
|
570
|
+
const targetVal = target[key];
|
|
571
|
+
if (!Object.hasOwn(current, key)) {
|
|
572
|
+
ops.push({ kind: "set", path, key, value: targetVal });
|
|
573
|
+
} else if (current[key] !== targetVal) {
|
|
574
|
+
diffValue(current[key], targetVal, [...path, key], ops);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
function diffArray(current, target, path, ops) {
|
|
580
|
+
const currentLen = current.length;
|
|
581
|
+
const targetLen = target.length;
|
|
582
|
+
const minLen = currentLen < targetLen ? currentLen : targetLen;
|
|
583
|
+
for (let i = 0; i < minLen; i++) {
|
|
584
|
+
if (current[i] !== target[i]) {
|
|
585
|
+
diffValue(current[i], target[i], [...path, i], ops);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
if (targetLen > currentLen) {
|
|
589
|
+
ops.push({
|
|
590
|
+
kind: "splice",
|
|
591
|
+
path,
|
|
592
|
+
index: currentLen,
|
|
593
|
+
deleteCount: 0,
|
|
594
|
+
inserts: target.slice(currentLen)
|
|
595
|
+
});
|
|
596
|
+
} else if (currentLen > targetLen) {
|
|
597
|
+
ops.push({
|
|
598
|
+
kind: "splice",
|
|
599
|
+
path,
|
|
600
|
+
index: targetLen,
|
|
601
|
+
deleteCount: currentLen - targetLen,
|
|
602
|
+
inserts: []
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
function emitReplace(path, value, ops) {
|
|
607
|
+
if (path.length === 0) {
|
|
608
|
+
failure("StateSyncLog: Cannot replace root state directly via Ops.");
|
|
609
|
+
}
|
|
610
|
+
const parentPath = path.slice(0, -1);
|
|
611
|
+
const keyToCheck = path[path.length - 1];
|
|
612
|
+
if (typeof keyToCheck === "string") {
|
|
613
|
+
ops.push({ kind: "set", path: parentPath, key: keyToCheck, value });
|
|
614
|
+
} else {
|
|
615
|
+
ops.push({
|
|
616
|
+
kind: "splice",
|
|
617
|
+
path: parentPath,
|
|
618
|
+
index: keyToCheck,
|
|
619
|
+
deleteCount: 1,
|
|
620
|
+
inserts: [value]
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
function txTimestampToKey(ts) {
|
|
625
|
+
return `${ts.epoch};${ts.clock};${ts.clientId};${ts.wallClock}`;
|
|
626
|
+
}
|
|
627
|
+
function parseTxTimestampKey(key) {
|
|
628
|
+
const i1 = key.indexOf(";");
|
|
629
|
+
const i2 = key.indexOf(";", i1 + 1);
|
|
630
|
+
const i3 = key.indexOf(";", i2 + 1);
|
|
631
|
+
if (i1 === -1 || i2 === -1 || i3 === -1) {
|
|
632
|
+
failure(`Malformed timestamp key: ${key}`);
|
|
633
|
+
}
|
|
634
|
+
return {
|
|
635
|
+
epoch: Number.parseInt(key.substring(0, i1), 10),
|
|
636
|
+
clock: Number.parseInt(key.substring(i1 + 1, i2), 10),
|
|
637
|
+
clientId: key.substring(i2 + 1, i3),
|
|
638
|
+
wallClock: Number.parseInt(key.substring(i3 + 1), 10)
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
function compareTxTimestamps(a, b) {
|
|
642
|
+
if (a.epoch !== b.epoch) return a.epoch - b.epoch;
|
|
643
|
+
if (a.clock !== b.clock) return a.clock - b.clock;
|
|
644
|
+
if (a.clientId < b.clientId) return -1;
|
|
645
|
+
if (a.clientId > b.clientId) return 1;
|
|
646
|
+
return 0;
|
|
647
|
+
}
|
|
648
|
+
class SortedTxEntry {
|
|
649
|
+
constructor(txTimestampKey, _yTx) {
|
|
650
|
+
__publicField(this, "_txTimestamp");
|
|
651
|
+
__publicField(this, "_originalTxTimestampKey");
|
|
652
|
+
__publicField(this, "_originalTxTimestamp");
|
|
653
|
+
__publicField(this, "_txRecord");
|
|
654
|
+
this.txTimestampKey = txTimestampKey;
|
|
655
|
+
this._yTx = _yTx;
|
|
656
|
+
}
|
|
657
|
+
/**
|
|
658
|
+
* Gets the parsed timestamp, lazily parsing and caching on first access.
|
|
659
|
+
*/
|
|
660
|
+
get txTimestamp() {
|
|
661
|
+
if (!this._txTimestamp) {
|
|
662
|
+
this._txTimestamp = parseTxTimestampKey(this.txTimestampKey);
|
|
663
|
+
}
|
|
664
|
+
return this._txTimestamp;
|
|
665
|
+
}
|
|
666
|
+
/**
|
|
667
|
+
* Gets the original tx timestamp key, lazily and caching on first access.
|
|
668
|
+
*/
|
|
669
|
+
get originalTxTimestampKey() {
|
|
670
|
+
var _a;
|
|
671
|
+
if (this._originalTxTimestampKey === void 0) {
|
|
672
|
+
const tx = this.txRecord;
|
|
673
|
+
this._originalTxTimestampKey = (_a = tx.originalTxKey) != null ? _a : null;
|
|
674
|
+
}
|
|
675
|
+
return this._originalTxTimestampKey;
|
|
676
|
+
}
|
|
677
|
+
/**
|
|
678
|
+
* Gets the parsed original tx timestamp, lazily parsing and caching on first access.
|
|
679
|
+
*/
|
|
680
|
+
get originalTxTimestamp() {
|
|
681
|
+
if (this._originalTxTimestamp === void 0) {
|
|
682
|
+
const key = this.originalTxTimestampKey;
|
|
683
|
+
this._originalTxTimestamp = key ? parseTxTimestampKey(key) : null;
|
|
684
|
+
}
|
|
685
|
+
return this._originalTxTimestamp;
|
|
686
|
+
}
|
|
687
|
+
/**
|
|
688
|
+
* Gets the logical (deduplicated) tx timestamp key.
|
|
689
|
+
* This is the original tx key if it exists, otherwise the physical key.
|
|
690
|
+
*/
|
|
691
|
+
get dedupTxTimestampKey() {
|
|
692
|
+
var _a;
|
|
693
|
+
return (_a = this.originalTxTimestampKey) != null ? _a : this.txTimestampKey;
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
696
|
+
* Gets the logical (deduplicated) parsed tx timestamp.
|
|
697
|
+
* This is the original tx timestamp if it exists, otherwise the physical timestamp.
|
|
698
|
+
*/
|
|
699
|
+
get dedupTxTimestamp() {
|
|
700
|
+
var _a;
|
|
701
|
+
return (_a = this.originalTxTimestamp) != null ? _a : this.txTimestamp;
|
|
702
|
+
}
|
|
703
|
+
/**
|
|
704
|
+
* Gets the tx record, lazily fetching and caching on first access.
|
|
705
|
+
* Returns undefined if the tx doesn't exist.
|
|
706
|
+
*/
|
|
707
|
+
get txRecord() {
|
|
708
|
+
if (!this._txRecord) {
|
|
709
|
+
this._txRecord = this._yTx.get(this.txTimestampKey);
|
|
710
|
+
if (!this._txRecord) {
|
|
711
|
+
throw failure(`SortedTxEntry: TxRecord not found for key ${this.txTimestampKey}`);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
return this._txRecord;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
function isTransactionInCheckpoint(ts, watermarks) {
|
|
718
|
+
const wm = watermarks[ts.clientId];
|
|
719
|
+
if (!wm) return false;
|
|
720
|
+
return ts.clock <= wm.maxClock;
|
|
721
|
+
}
|
|
722
|
+
class StateCalculator {
|
|
723
|
+
constructor(validateFn) {
|
|
724
|
+
/** Sorted tx cache (ALL active/future txs, kept sorted by timestamp) */
|
|
725
|
+
__publicField(this, "sortedTxs", []);
|
|
726
|
+
/** O(1) existence check and lookup */
|
|
727
|
+
__publicField(this, "sortedTxsMap", /* @__PURE__ */ new Map());
|
|
728
|
+
/**
|
|
729
|
+
* Index of the last transaction applied to cachedState.
|
|
730
|
+
* - null: state needs full recalculation from checkpoint
|
|
731
|
+
* - -1: no transactions have been applied yet (state === checkpoint state)
|
|
732
|
+
* - >= 0: transactions up to and including this index have been applied
|
|
733
|
+
*/
|
|
734
|
+
__publicField(this, "lastAppliedIndex", null);
|
|
735
|
+
/** The cached calculated state */
|
|
736
|
+
__publicField(this, "cachedState", null);
|
|
737
|
+
/** The base checkpoint to calculate state from */
|
|
738
|
+
__publicField(this, "baseCheckpoint", null);
|
|
739
|
+
/**
|
|
740
|
+
* Applied dedup keys - tracks which LOGICAL txs have been applied.
|
|
741
|
+
* This is the originalTxKey (or physical key if no original) for each applied tx.
|
|
742
|
+
* Used to properly deduplicate re-emits.
|
|
743
|
+
*/
|
|
744
|
+
__publicField(this, "appliedTxKeys", /* @__PURE__ */ new Set());
|
|
745
|
+
/** Max clock seen from any transaction (for Lamport clock updates) */
|
|
746
|
+
__publicField(this, "maxSeenClock", 0);
|
|
747
|
+
/** Validation function (optional) */
|
|
748
|
+
__publicField(this, "validateFn");
|
|
749
|
+
this.validateFn = validateFn;
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* Sets the base checkpoint. Invalidates cached state if checkpoint changed.
|
|
753
|
+
* @returns true if the checkpoint changed
|
|
754
|
+
*/
|
|
755
|
+
setBaseCheckpoint(checkpoint) {
|
|
756
|
+
if (checkpoint === this.baseCheckpoint) {
|
|
757
|
+
return false;
|
|
758
|
+
}
|
|
759
|
+
this.baseCheckpoint = checkpoint;
|
|
760
|
+
this.invalidate();
|
|
761
|
+
return true;
|
|
762
|
+
}
|
|
763
|
+
/**
|
|
764
|
+
* Gets the current base checkpoint.
|
|
765
|
+
*/
|
|
766
|
+
getBaseCheckpoint() {
|
|
767
|
+
return this.baseCheckpoint;
|
|
768
|
+
}
|
|
769
|
+
/**
|
|
770
|
+
* Clears all transactions and rebuilds from yTx map.
|
|
771
|
+
* This is used when the checkpoint changes and we need a fresh start.
|
|
772
|
+
*/
|
|
773
|
+
rebuildFromYjs(yTx) {
|
|
774
|
+
this.sortedTxs = [];
|
|
775
|
+
this.sortedTxsMap.clear();
|
|
776
|
+
for (const key of yTx.keys()) {
|
|
777
|
+
const entry = new SortedTxEntry(key, yTx);
|
|
778
|
+
this.sortedTxs.push(entry);
|
|
779
|
+
this.sortedTxsMap.set(entry.txTimestampKey, entry);
|
|
780
|
+
if (entry.txTimestamp.clock > this.maxSeenClock) {
|
|
781
|
+
this.maxSeenClock = entry.txTimestamp.clock;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
this.sortedTxs.sort((a, b) => compareTxTimestamps(a.txTimestamp, b.txTimestamp));
|
|
785
|
+
this.invalidate();
|
|
786
|
+
}
|
|
787
|
+
/**
|
|
788
|
+
* Inserts a transaction into the sorted cache.
|
|
789
|
+
* Invalidates cached state if the transaction was inserted before the calculated slice.
|
|
790
|
+
*
|
|
791
|
+
* @returns true if this caused invalidation (out-of-order insert)
|
|
792
|
+
*/
|
|
793
|
+
insertTx(key, yTx) {
|
|
794
|
+
if (this.sortedTxsMap.has(key)) {
|
|
795
|
+
return false;
|
|
796
|
+
}
|
|
797
|
+
const entry = new SortedTxEntry(key, yTx);
|
|
798
|
+
const ts = entry.txTimestamp;
|
|
799
|
+
if (ts.clock > this.maxSeenClock) {
|
|
800
|
+
this.maxSeenClock = ts.clock;
|
|
801
|
+
}
|
|
802
|
+
const sortedTxs = this.sortedTxs;
|
|
803
|
+
let insertIndex = sortedTxs.length;
|
|
804
|
+
for (let i = sortedTxs.length - 1; i >= 0; i--) {
|
|
805
|
+
const existingTs = sortedTxs[i].txTimestamp;
|
|
806
|
+
if (compareTxTimestamps(ts, existingTs) >= 0) {
|
|
807
|
+
insertIndex = i + 1;
|
|
808
|
+
break;
|
|
809
|
+
}
|
|
810
|
+
if (i === 0) {
|
|
811
|
+
insertIndex = 0;
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
sortedTxs.splice(insertIndex, 0, entry);
|
|
815
|
+
this.sortedTxsMap.set(key, entry);
|
|
816
|
+
if (this.lastAppliedIndex !== null && insertIndex <= this.lastAppliedIndex) {
|
|
817
|
+
this.invalidate();
|
|
818
|
+
return true;
|
|
819
|
+
}
|
|
820
|
+
return false;
|
|
821
|
+
}
|
|
822
|
+
/**
|
|
823
|
+
* Removes multiple transactions from the sorted cache.
|
|
824
|
+
* @returns the number of keys that were actually removed
|
|
825
|
+
*/
|
|
826
|
+
removeTxs(keys) {
|
|
827
|
+
if (keys.length === 0) return 0;
|
|
828
|
+
let removedCount = 0;
|
|
829
|
+
let minRemovedIndex = Number.POSITIVE_INFINITY;
|
|
830
|
+
const toDelete = /* @__PURE__ */ new Set();
|
|
831
|
+
for (const key of keys) {
|
|
832
|
+
const entry = this.sortedTxsMap.get(key);
|
|
833
|
+
if (entry) {
|
|
834
|
+
this.sortedTxsMap.delete(key);
|
|
835
|
+
toDelete.add(key);
|
|
836
|
+
const index = this.sortedTxs.indexOf(entry);
|
|
837
|
+
if (index !== -1 && index < minRemovedIndex) {
|
|
838
|
+
minRemovedIndex = index;
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
if (toDelete.size === 0) return 0;
|
|
843
|
+
const sortedTxs = this.sortedTxs;
|
|
844
|
+
let i = 0;
|
|
845
|
+
while (i < sortedTxs.length && toDelete.size > 0) {
|
|
846
|
+
if (toDelete.has(sortedTxs[i].txTimestampKey)) {
|
|
847
|
+
toDelete.delete(sortedTxs[i].txTimestampKey);
|
|
848
|
+
sortedTxs.splice(i, 1);
|
|
849
|
+
removedCount++;
|
|
850
|
+
} else {
|
|
851
|
+
i++;
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
if (this.lastAppliedIndex !== null && minRemovedIndex <= this.lastAppliedIndex) {
|
|
855
|
+
this.invalidate();
|
|
856
|
+
}
|
|
857
|
+
return removedCount;
|
|
858
|
+
}
|
|
859
|
+
/**
|
|
860
|
+
* Checks if a transaction key exists in the cache.
|
|
861
|
+
*/
|
|
862
|
+
hasTx(key) {
|
|
863
|
+
return this.sortedTxsMap.has(key);
|
|
864
|
+
}
|
|
865
|
+
/**
|
|
866
|
+
* Gets a transaction entry by key.
|
|
867
|
+
*/
|
|
868
|
+
getTx(key) {
|
|
869
|
+
return this.sortedTxsMap.get(key);
|
|
870
|
+
}
|
|
871
|
+
/**
|
|
872
|
+
* Gets all sorted transaction entries.
|
|
873
|
+
*/
|
|
874
|
+
getSortedTxs() {
|
|
875
|
+
return this.sortedTxs;
|
|
876
|
+
}
|
|
877
|
+
/**
|
|
878
|
+
* Gets the number of transactions in the cache.
|
|
879
|
+
*/
|
|
880
|
+
get txCount() {
|
|
881
|
+
return this.sortedTxs.length;
|
|
882
|
+
}
|
|
883
|
+
/**
|
|
884
|
+
* Returns true if the state needs full recalculation.
|
|
885
|
+
*/
|
|
886
|
+
needsFullRecalculation() {
|
|
887
|
+
return this.lastAppliedIndex === null;
|
|
888
|
+
}
|
|
889
|
+
/**
|
|
890
|
+
* Invalidates the cached state, forcing a full recalculation on next calculateState().
|
|
891
|
+
* Note: cachedState is kept so computeReconcileOps can diff old vs new state.
|
|
892
|
+
*/
|
|
893
|
+
invalidate() {
|
|
894
|
+
this.lastAppliedIndex = null;
|
|
895
|
+
}
|
|
896
|
+
/**
|
|
897
|
+
* Calculates and returns the current state, along with a lazy getter for ops that changed from the previous state.
|
|
898
|
+
*
|
|
899
|
+
* - If lastAppliedIndex is null: full recalculation from checkpoint
|
|
900
|
+
* - If lastAppliedIndex >= -1: incremental apply from lastAppliedIndex + 1
|
|
901
|
+
*/
|
|
902
|
+
calculateState() {
|
|
903
|
+
var _a, _b, _c, _d;
|
|
904
|
+
const baseState = (_b = (_a = this.baseCheckpoint) == null ? void 0 : _a.state) != null ? _b : {};
|
|
905
|
+
const watermarks = (_d = (_c = this.baseCheckpoint) == null ? void 0 : _c.watermarks) != null ? _d : {};
|
|
906
|
+
const hasWatermarks = Object.keys(watermarks).length > 0;
|
|
907
|
+
if (this.lastAppliedIndex === null) {
|
|
908
|
+
return this.fullRecalculation(baseState, watermarks, hasWatermarks);
|
|
909
|
+
}
|
|
910
|
+
return this.incrementalApply(watermarks, hasWatermarks);
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* Full recalculation of state from the base checkpoint.
|
|
914
|
+
*/
|
|
915
|
+
fullRecalculation(baseState, watermarks, hasWatermarks) {
|
|
916
|
+
var _a;
|
|
917
|
+
const oldState = (_a = this.cachedState) != null ? _a : {};
|
|
918
|
+
this.appliedTxKeys.clear();
|
|
919
|
+
this.lastAppliedIndex = -1;
|
|
920
|
+
this.cachedState = baseState;
|
|
921
|
+
const { state } = this.incrementalApply(watermarks, hasWatermarks, false);
|
|
922
|
+
const getAppliedOps = lazy(() => computeReconcileOps(oldState, state));
|
|
923
|
+
return { state, getAppliedOps };
|
|
924
|
+
}
|
|
925
|
+
/**
|
|
926
|
+
* Incremental apply of transactions from lastAppliedIndex + 1.
|
|
927
|
+
* @param returnOps If true, collects applied transactions (to lazy compute ops). If false, skips collection.
|
|
928
|
+
*/
|
|
929
|
+
incrementalApply(watermarks, hasWatermarks, returnOps = true) {
|
|
930
|
+
let state = this.cachedState;
|
|
931
|
+
const appliedTxs = [];
|
|
932
|
+
const sortedTxs = this.sortedTxs;
|
|
933
|
+
const startIndex = this.lastAppliedIndex + 1;
|
|
934
|
+
for (let i = startIndex; i < sortedTxs.length; i++) {
|
|
935
|
+
const entry = sortedTxs[i];
|
|
936
|
+
const dedupKey = entry.dedupTxTimestampKey;
|
|
937
|
+
if (this.appliedTxKeys.has(dedupKey)) {
|
|
938
|
+
continue;
|
|
939
|
+
}
|
|
940
|
+
if (hasWatermarks) {
|
|
941
|
+
const dedupTs = entry.dedupTxTimestamp;
|
|
942
|
+
if (isTransactionInCheckpoint(dedupTs, watermarks)) {
|
|
943
|
+
this.appliedTxKeys.add(dedupKey);
|
|
944
|
+
continue;
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
const tx = entry.txRecord;
|
|
948
|
+
const newState = applyTxImmutable(state, tx, this.validateFn);
|
|
949
|
+
if (newState !== state) {
|
|
950
|
+
state = newState;
|
|
951
|
+
if (returnOps) {
|
|
952
|
+
appliedTxs.push(tx);
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
this.appliedTxKeys.add(dedupKey);
|
|
956
|
+
this.lastAppliedIndex = i;
|
|
957
|
+
}
|
|
958
|
+
if (sortedTxs.length > 0 && this.lastAppliedIndex < sortedTxs.length - 1) {
|
|
959
|
+
this.lastAppliedIndex = sortedTxs.length - 1;
|
|
960
|
+
}
|
|
961
|
+
this.cachedState = state;
|
|
962
|
+
const getAppliedOps = lazy(() => {
|
|
963
|
+
const ops = [];
|
|
964
|
+
for (const tx of appliedTxs) {
|
|
965
|
+
ops.push(...tx.ops);
|
|
966
|
+
}
|
|
967
|
+
return ops;
|
|
968
|
+
});
|
|
969
|
+
return { state, getAppliedOps };
|
|
970
|
+
}
|
|
971
|
+
/**
|
|
972
|
+
* Gets the max seen clock (for Lamport clock updates).
|
|
973
|
+
*/
|
|
974
|
+
getMaxSeenClock() {
|
|
975
|
+
return this.maxSeenClock;
|
|
976
|
+
}
|
|
977
|
+
/**
|
|
978
|
+
* Gets the current cached state without recalculating.
|
|
979
|
+
* Returns null if state has never been calculated.
|
|
980
|
+
*/
|
|
981
|
+
getCachedState() {
|
|
982
|
+
return this.cachedState;
|
|
983
|
+
}
|
|
984
|
+
/**
|
|
985
|
+
* Gets the last applied timestamp.
|
|
986
|
+
*/
|
|
987
|
+
getLastAppliedTs() {
|
|
988
|
+
var _a, _b;
|
|
989
|
+
if (this.lastAppliedIndex === null || this.lastAppliedIndex < 0) {
|
|
990
|
+
return null;
|
|
991
|
+
}
|
|
992
|
+
return (_b = (_a = this.sortedTxs[this.lastAppliedIndex]) == null ? void 0 : _a.txTimestamp) != null ? _b : null;
|
|
993
|
+
}
|
|
994
|
+
/**
|
|
995
|
+
* Gets the last applied index (for debugging/tracking).
|
|
996
|
+
*/
|
|
997
|
+
getLastAppliedIndex() {
|
|
998
|
+
return this.lastAppliedIndex;
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
function createClientState(validateFn, retentionWindowMs) {
|
|
1002
|
+
return {
|
|
1003
|
+
localClock: 0,
|
|
1004
|
+
cachedFinalizedEpoch: null,
|
|
1005
|
+
// Will be recalculated on first run
|
|
1006
|
+
stateCalculator: new StateCalculator(validateFn),
|
|
1007
|
+
retentionWindowMs
|
|
1008
|
+
};
|
|
1009
|
+
}
|
|
1010
|
+
function appendTx(ops, yTx, activeEpoch, myClientId, clientState, originalKey) {
|
|
1011
|
+
const calc = clientState.stateCalculator;
|
|
1012
|
+
const clock = Math.max(clientState.localClock, calc.getMaxSeenClock()) + 1;
|
|
1013
|
+
clientState.localClock = clock;
|
|
1014
|
+
const ts = {
|
|
1015
|
+
epoch: activeEpoch,
|
|
1016
|
+
clock,
|
|
1017
|
+
clientId: myClientId,
|
|
1018
|
+
wallClock: Date.now()
|
|
1019
|
+
};
|
|
1020
|
+
const key = txTimestampToKey(ts);
|
|
1021
|
+
const record = { ops, originalTxKey: originalKey };
|
|
1022
|
+
yTx.set(key, record);
|
|
1023
|
+
return key;
|
|
1024
|
+
}
|
|
1025
|
+
function syncLog(yTx, myClientId, clientState, finalizedEpoch, baseCP, newKeys) {
|
|
1026
|
+
var _a, _b;
|
|
1027
|
+
const calc = clientState.stateCalculator;
|
|
1028
|
+
const activeEpoch = finalizedEpoch + 1;
|
|
1029
|
+
const watermarks = (_a = baseCP == null ? void 0 : baseCP.watermarks) != null ? _a : {};
|
|
1030
|
+
const referenceTime = (_b = baseCP == null ? void 0 : baseCP.minWallClock) != null ? _b : 0;
|
|
1031
|
+
const shouldPrune = (ts, dedupTs) => {
|
|
1032
|
+
const isAncient = referenceTime - ts.wallClock > clientState.retentionWindowMs;
|
|
1033
|
+
if (isAncient) return true;
|
|
1034
|
+
return isTransactionInCheckpoint(dedupTs, watermarks);
|
|
1035
|
+
};
|
|
1036
|
+
const toDelete = [];
|
|
1037
|
+
const toReEmit = [];
|
|
1038
|
+
const processEntry = (entry) => {
|
|
1039
|
+
if (shouldPrune(entry.txTimestamp, entry.dedupTxTimestamp)) {
|
|
1040
|
+
toDelete.push(entry.txTimestampKey);
|
|
1041
|
+
return false;
|
|
1042
|
+
}
|
|
1043
|
+
if (entry.txTimestamp.epoch <= finalizedEpoch) {
|
|
1044
|
+
toReEmit.push({ originalKey: entry.dedupTxTimestampKey, tx: entry.txRecord });
|
|
1045
|
+
toDelete.push(entry.txTimestampKey);
|
|
1046
|
+
return false;
|
|
1047
|
+
}
|
|
1048
|
+
return true;
|
|
1049
|
+
};
|
|
1050
|
+
for (const entry of calc.getSortedTxs()) {
|
|
1051
|
+
if (processEntry(entry)) {
|
|
1052
|
+
break;
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
const processKeyByTimestampKey = (txTimestampKey) => {
|
|
1056
|
+
if (yTx.has(txTimestampKey)) {
|
|
1057
|
+
processEntry(new SortedTxEntry(txTimestampKey, yTx));
|
|
1058
|
+
}
|
|
1059
|
+
};
|
|
1060
|
+
if (newKeys) {
|
|
1061
|
+
for (const key of newKeys) {
|
|
1062
|
+
processKeyByTimestampKey(key);
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
for (const { originalKey, tx } of toReEmit) {
|
|
1066
|
+
const newKey = appendTx(tx.ops, yTx, activeEpoch, myClientId, clientState, originalKey);
|
|
1067
|
+
calc.insertTx(newKey, yTx);
|
|
1068
|
+
}
|
|
1069
|
+
for (const key of toDelete) {
|
|
1070
|
+
yTx.delete(key);
|
|
1071
|
+
}
|
|
1072
|
+
calc.removeTxs(toDelete);
|
|
1073
|
+
}
|
|
1074
|
+
function updateState(doc, yTx, yCheckpoint, myClientId, clientState, txChanges) {
|
|
1075
|
+
const calc = clientState.stateCalculator;
|
|
1076
|
+
const { finalizedEpoch, checkpoint: baseCP } = getFinalizedEpochAndCheckpoint(yCheckpoint);
|
|
1077
|
+
clientState.cachedFinalizedEpoch = finalizedEpoch;
|
|
1078
|
+
calc.setBaseCheckpoint(baseCP);
|
|
1079
|
+
const needsRebuildSortedCache = calc.getCachedState() === null || !txChanges;
|
|
1080
|
+
if (needsRebuildSortedCache) {
|
|
1081
|
+
calc.rebuildFromYjs(yTx);
|
|
1082
|
+
} else {
|
|
1083
|
+
calc.removeTxs(txChanges.deleted);
|
|
1084
|
+
}
|
|
1085
|
+
doc.transact(() => {
|
|
1086
|
+
syncLog(yTx, myClientId, clientState, finalizedEpoch, baseCP, txChanges == null ? void 0 : txChanges.added);
|
|
1087
|
+
pruneCheckpoints(yCheckpoint, finalizedEpoch);
|
|
1088
|
+
});
|
|
1089
|
+
if (needsRebuildSortedCache) {
|
|
1090
|
+
return calc.calculateState();
|
|
1091
|
+
}
|
|
1092
|
+
for (const key of txChanges.added) {
|
|
1093
|
+
if (yTx.has(key) && !calc.hasTx(key)) {
|
|
1094
|
+
calc.insertTx(key, yTx);
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
return calc.calculateState();
|
|
1098
|
+
}
|
|
1099
|
+
const getSortedTxsSymbol = /* @__PURE__ */ Symbol("getSortedTxs");
|
|
1100
|
+
function createStateSyncLog(options) {
|
|
1101
|
+
const {
|
|
1102
|
+
yDoc,
|
|
1103
|
+
yTxMapName = "state-sync-log-tx",
|
|
1104
|
+
yCheckpointMapName = "state-sync-log-checkpoint",
|
|
1105
|
+
clientId = generateID(),
|
|
1106
|
+
yjsOrigin,
|
|
1107
|
+
validate,
|
|
1108
|
+
retentionWindowMs
|
|
1109
|
+
} = options;
|
|
1110
|
+
if (clientId.includes(";")) {
|
|
1111
|
+
failure(`clientId MUST NOT contain semicolons: ${clientId}`);
|
|
1112
|
+
}
|
|
1113
|
+
const yTx = yDoc.getMap(yTxMapName);
|
|
1114
|
+
const yCheckpoint = yDoc.getMap(yCheckpointMapName);
|
|
1115
|
+
const clientState = createClientState(
|
|
1116
|
+
validate,
|
|
1117
|
+
retentionWindowMs != null ? retentionWindowMs : Number.POSITIVE_INFINITY
|
|
1118
|
+
);
|
|
1119
|
+
const subscribers = /* @__PURE__ */ new Set();
|
|
1120
|
+
const notifySubscribers = (state, getAppliedOps) => {
|
|
1121
|
+
for (const sub of subscribers) {
|
|
1122
|
+
sub(state, getAppliedOps);
|
|
1123
|
+
}
|
|
1124
|
+
};
|
|
1125
|
+
const extractTxChanges = (event) => {
|
|
1126
|
+
const added = [];
|
|
1127
|
+
const deleted = [];
|
|
1128
|
+
for (const [key, change] of event.changes.keys) {
|
|
1129
|
+
if (change.action === "add") {
|
|
1130
|
+
added.push(key);
|
|
1131
|
+
} else if (change.action === "delete") {
|
|
1132
|
+
deleted.push(key);
|
|
1133
|
+
} else if (change.action === "update") {
|
|
1134
|
+
deleted.push(key);
|
|
1135
|
+
added.push(key);
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
return { added, deleted };
|
|
1139
|
+
};
|
|
1140
|
+
const emptyTxChanges = { added: [], deleted: [] };
|
|
1141
|
+
const runUpdate = (txChanges) => {
|
|
1142
|
+
const { state, getAppliedOps } = updateState(
|
|
1143
|
+
yDoc,
|
|
1144
|
+
yTx,
|
|
1145
|
+
yCheckpoint,
|
|
1146
|
+
clientId,
|
|
1147
|
+
clientState,
|
|
1148
|
+
txChanges
|
|
1149
|
+
);
|
|
1150
|
+
notifySubscribers(state, getAppliedOps);
|
|
1151
|
+
};
|
|
1152
|
+
const txObserver = (event, _transaction) => {
|
|
1153
|
+
const txChanges = extractTxChanges(event);
|
|
1154
|
+
runUpdate(txChanges);
|
|
1155
|
+
};
|
|
1156
|
+
const checkpointObserver = (_event, _transaction) => {
|
|
1157
|
+
runUpdate(emptyTxChanges);
|
|
1158
|
+
};
|
|
1159
|
+
yCheckpoint.observe(checkpointObserver);
|
|
1160
|
+
yTx.observe(txObserver);
|
|
1161
|
+
runUpdate(void 0);
|
|
1162
|
+
let disposed = false;
|
|
1163
|
+
const assertNotDisposed = () => {
|
|
1164
|
+
if (disposed) {
|
|
1165
|
+
failure("StateSyncLog has been disposed and cannot be used");
|
|
1166
|
+
}
|
|
1167
|
+
};
|
|
1168
|
+
const getActiveEpochInternal = () => {
|
|
1169
|
+
if (clientState.cachedFinalizedEpoch === null) {
|
|
1170
|
+
failure("cachedFinalizedEpoch is null - this should not happen after initialization");
|
|
1171
|
+
}
|
|
1172
|
+
return clientState.cachedFinalizedEpoch + 1;
|
|
1173
|
+
};
|
|
1174
|
+
return {
|
|
1175
|
+
getState() {
|
|
1176
|
+
var _a;
|
|
1177
|
+
assertNotDisposed();
|
|
1178
|
+
return (_a = clientState.stateCalculator.getCachedState()) != null ? _a : {};
|
|
1179
|
+
},
|
|
1180
|
+
subscribe(callback) {
|
|
1181
|
+
assertNotDisposed();
|
|
1182
|
+
subscribers.add(callback);
|
|
1183
|
+
return () => {
|
|
1184
|
+
subscribers.delete(callback);
|
|
1185
|
+
};
|
|
1186
|
+
},
|
|
1187
|
+
emit(ops) {
|
|
1188
|
+
assertNotDisposed();
|
|
1189
|
+
yDoc.transact(() => {
|
|
1190
|
+
const activeEpoch = getActiveEpochInternal();
|
|
1191
|
+
appendTx(ops, yTx, activeEpoch, clientId, clientState);
|
|
1192
|
+
}, yjsOrigin);
|
|
1193
|
+
},
|
|
1194
|
+
reconcileState(targetState) {
|
|
1195
|
+
var _a;
|
|
1196
|
+
assertNotDisposed();
|
|
1197
|
+
const currentState = (_a = clientState.stateCalculator.getCachedState()) != null ? _a : {};
|
|
1198
|
+
const ops = computeReconcileOps(currentState, targetState);
|
|
1199
|
+
if (ops.length > 0) {
|
|
1200
|
+
this.emit(ops);
|
|
1201
|
+
}
|
|
1202
|
+
},
|
|
1203
|
+
compact() {
|
|
1204
|
+
assertNotDisposed();
|
|
1205
|
+
yDoc.transact(() => {
|
|
1206
|
+
var _a;
|
|
1207
|
+
const activeEpoch = getActiveEpochInternal();
|
|
1208
|
+
const currentState = (_a = clientState.stateCalculator.getCachedState()) != null ? _a : {};
|
|
1209
|
+
createCheckpoint(yTx, yCheckpoint, clientState, activeEpoch, currentState, clientId);
|
|
1210
|
+
}, yjsOrigin);
|
|
1211
|
+
},
|
|
1212
|
+
dispose() {
|
|
1213
|
+
if (disposed) return;
|
|
1214
|
+
disposed = true;
|
|
1215
|
+
yTx.unobserve(txObserver);
|
|
1216
|
+
yCheckpoint.unobserve(checkpointObserver);
|
|
1217
|
+
subscribers.clear();
|
|
1218
|
+
},
|
|
1219
|
+
getActiveEpoch() {
|
|
1220
|
+
assertNotDisposed();
|
|
1221
|
+
return getActiveEpochInternal();
|
|
1222
|
+
},
|
|
1223
|
+
getActiveEpochTxCount() {
|
|
1224
|
+
assertNotDisposed();
|
|
1225
|
+
const activeEpoch = getActiveEpochInternal();
|
|
1226
|
+
let count = 0;
|
|
1227
|
+
for (const entry of clientState.stateCalculator.getSortedTxs()) {
|
|
1228
|
+
const ts = entry.txTimestamp;
|
|
1229
|
+
if (ts.epoch === activeEpoch) {
|
|
1230
|
+
count++;
|
|
1231
|
+
} else if (ts.epoch > activeEpoch) {
|
|
1232
|
+
break;
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
return count;
|
|
1236
|
+
},
|
|
1237
|
+
getActiveEpochStartTime() {
|
|
1238
|
+
assertNotDisposed();
|
|
1239
|
+
const activeEpoch = getActiveEpochInternal();
|
|
1240
|
+
for (const entry of clientState.stateCalculator.getSortedTxs()) {
|
|
1241
|
+
const ts = entry.txTimestamp;
|
|
1242
|
+
if (ts.epoch === activeEpoch) {
|
|
1243
|
+
return ts.wallClock;
|
|
1244
|
+
} else if (ts.epoch > activeEpoch) {
|
|
1245
|
+
break;
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
return void 0;
|
|
1249
|
+
},
|
|
1250
|
+
isLogEmpty() {
|
|
1251
|
+
assertNotDisposed();
|
|
1252
|
+
return yTx.size === 0 && yCheckpoint.size === 0;
|
|
1253
|
+
},
|
|
1254
|
+
[getSortedTxsSymbol]() {
|
|
1255
|
+
assertNotDisposed();
|
|
1256
|
+
return clientState.stateCalculator.getSortedTxs();
|
|
1257
|
+
}
|
|
1258
|
+
};
|
|
1259
|
+
}
|
|
1260
|
+
function resolvePath(state, path) {
|
|
1261
|
+
let current = state;
|
|
1262
|
+
for (const segment of path) {
|
|
1263
|
+
if (typeof segment === "string") {
|
|
1264
|
+
if (!isObject(current) || Array.isArray(current)) {
|
|
1265
|
+
failure(`Expected object at path segment "${segment}"`);
|
|
1266
|
+
}
|
|
1267
|
+
if (!(segment in current)) {
|
|
1268
|
+
failure(`Property "${segment}" does not exist`);
|
|
1269
|
+
}
|
|
1270
|
+
current = current[segment];
|
|
1271
|
+
} else {
|
|
1272
|
+
if (!Array.isArray(current)) {
|
|
1273
|
+
failure(`Expected array at path segment ${segment}`);
|
|
1274
|
+
}
|
|
1275
|
+
if (segment < 0 || segment >= current.length) {
|
|
1276
|
+
failure(`Index ${segment} out of bounds`);
|
|
1277
|
+
}
|
|
1278
|
+
current = current[segment];
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
return current;
|
|
1282
|
+
}
|
|
1283
|
+
function applyOp(state, op, cloneValues) {
|
|
1284
|
+
const container = resolvePath(state, op.path);
|
|
1285
|
+
switch (op.kind) {
|
|
1286
|
+
case "set":
|
|
1287
|
+
if (!isObject(container) || Array.isArray(container)) {
|
|
1288
|
+
failure("set requires object container");
|
|
1289
|
+
}
|
|
1290
|
+
container[op.key] = cloneValues ? deepClone(op.value) : op.value;
|
|
1291
|
+
break;
|
|
1292
|
+
case "delete":
|
|
1293
|
+
if (!isObject(container) || Array.isArray(container)) {
|
|
1294
|
+
failure("delete requires object container");
|
|
1295
|
+
}
|
|
1296
|
+
delete container[op.key];
|
|
1297
|
+
break;
|
|
1298
|
+
case "splice": {
|
|
1299
|
+
if (!Array.isArray(container)) {
|
|
1300
|
+
failure("splice requires array container");
|
|
1301
|
+
}
|
|
1302
|
+
const safeIndex = Math.min(op.index, container.length);
|
|
1303
|
+
container.splice(
|
|
1304
|
+
safeIndex,
|
|
1305
|
+
op.deleteCount,
|
|
1306
|
+
...cloneValues ? op.inserts.map((v) => deepClone(v)) : op.inserts
|
|
1307
|
+
);
|
|
1308
|
+
break;
|
|
1309
|
+
}
|
|
1310
|
+
case "addToSet":
|
|
1311
|
+
if (!Array.isArray(container)) {
|
|
1312
|
+
failure("addToSet requires array container");
|
|
1313
|
+
}
|
|
1314
|
+
if (!container.some((item) => deepEqual(item, op.value))) {
|
|
1315
|
+
container.push(cloneValues ? deepClone(op.value) : op.value);
|
|
1316
|
+
}
|
|
1317
|
+
break;
|
|
1318
|
+
case "deleteFromSet":
|
|
1319
|
+
if (!Array.isArray(container)) {
|
|
1320
|
+
failure("deleteFromSet requires array container");
|
|
1321
|
+
}
|
|
1322
|
+
for (let i = container.length - 1; i >= 0; i--) {
|
|
1323
|
+
if (deepEqual(container[i], op.value)) {
|
|
1324
|
+
container.splice(i, 1);
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
break;
|
|
1328
|
+
default:
|
|
1329
|
+
throw failure(`Unknown operation kind: ${op.kind}`);
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
function applyOps(ops, target, options) {
|
|
1333
|
+
var _a;
|
|
1334
|
+
const cloneValues = (_a = options == null ? void 0 : options.cloneValues) != null ? _a : true;
|
|
1335
|
+
for (const op of ops) {
|
|
1336
|
+
applyOp(target, op, cloneValues);
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
exports2.applyOps = applyOps;
|
|
1340
|
+
exports2.createStateSyncLog = createStateSyncLog;
|
|
1341
|
+
Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
|
|
1342
|
+
}));
|
|
1343
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhdGUtc3luYy1sb2cudW1kLmpzIiwic291cmNlcyI6WyIuLi9zcmMvY2hlY2twb2ludFV0aWxzLnRzIiwiLi4vc3JjL2Vycm9yLnRzIiwiLi4vc3JjL2NoZWNrcG9pbnRzLnRzIiwiLi4vLi4vLi4vbm9kZV9tb2R1bGVzLy5wbnBtL2Zhc3QtZGVlcC1lcXVhbEAzLjEuMy9ub2RlX21vZHVsZXMvZmFzdC1kZWVwLWVxdWFsL2luZGV4LmpzIiwiLi4vLi4vLi4vbm9kZV9tb2R1bGVzLy5wbnBtL25hbm9pZEA1LjEuNi9ub2RlX21vZHVsZXMvbmFub2lkL3VybC1hbHBoYWJldC9pbmRleC5qcyIsIi4uLy4uLy4uL25vZGVfbW9kdWxlcy8ucG5wbS9uYW5vaWRANS4xLjYvbm9kZV9tb2R1bGVzL25hbm9pZC9pbmRleC5icm93c2VyLmpzIiwiLi4vLi4vLi4vbm9kZV9tb2R1bGVzLy5wbnBtL3JmZGNAMS40LjEvbm9kZV9tb2R1bGVzL3JmZGMvaW5kZXguanMiLCIuLi9zcmMvdXRpbHMudHMiLCIuLi9zcmMvZHJhZnQudHMiLCIuLi9zcmMvcmVjb25jaWxlLnRzIiwiLi4vc3JjL3R4VGltZXN0YW1wLnRzIiwiLi4vc3JjL1NvcnRlZFR4RW50cnkudHMiLCIuLi9zcmMvU3RhdGVDYWxjdWxhdG9yLnRzIiwiLi4vc3JjL2NsaWVudFN0YXRlLnRzIiwiLi4vc3JjL3R4TG9nLnRzIiwiLi4vc3JjL2NyZWF0ZVN0YXRlU3luY0xvZy50cyIsIi4uL3NyYy9vcGVyYXRpb25zLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIFkgZnJvbSBcInlqc1wiXG5pbXBvcnQgeyB0eXBlIENoZWNrcG9pbnRSZWNvcmQsIHBhcnNlQ2hlY2twb2ludEtleSB9IGZyb20gXCIuL2NoZWNrcG9pbnRzXCJcblxuLyoqXG4gKiBEZXRlcm1pbmVzIHRoZSBmaW5hbGl6ZWQgZXBvY2ggYW5kIGl0cyBjYW5vbmljYWwgY2hlY2twb2ludCBpbiBhIHNpbmdsZSBwYXNzLlxuICpcbiAqIFBvbGljeSBBOiBUaGUgZmluYWxpemVkIGVwb2NoIGlzIHRoZSBtb3N0IHJlY2VudCBlcG9jaCB3aXRoIGEgY2hlY2twb2ludC5cbiAqIENhbm9uaWNhbCBjaGVja3BvaW50OiBUaGUgY2hlY2twb2ludCB3aXRoIGhpZ2hlc3QgdHhDb3VudCBmb3IgdGhhdCBlcG9jaFxuICogKHRpZS1icmVhazogbG93ZXN0IGNsaWVudElkIGFscGhhYmV0aWNhbGx5KS5cbiAqXG4gKiBSZXR1cm5zIHsgZmluYWxpemVkRXBvY2g6IC0xLCBjaGVja3BvaW50OiBudWxsIH0gaWYgbm8gY2hlY2twb2ludHMgZXhpc3QuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRGaW5hbGl6ZWRFcG9jaEFuZENoZWNrcG9pbnQoeUNoZWNrcG9pbnQ6IFkuTWFwPENoZWNrcG9pbnRSZWNvcmQ+KToge1xuICBmaW5hbGl6ZWRFcG9jaDogbnVtYmVyXG4gIGNoZWNrcG9pbnQ6IENoZWNrcG9pbnRSZWNvcmQgfCBudWxsXG59IHtcbiAgbGV0IG1heEVwb2NoID0gLTFcbiAgbGV0IGJlc3Q6IENoZWNrcG9pbnRSZWNvcmQgfCBudWxsID0gbnVsbFxuICBsZXQgYmVzdFR4Q291bnQgPSAtMVxuICBsZXQgYmVzdENsaWVudElkID0gXCJcIlxuXG4gIGZvciAoY29uc3QgW2tleSwgY3BdIG9mIHlDaGVja3BvaW50LmVudHJpZXMoKSkge1xuICAgIGNvbnN0IHsgZXBvY2gsIGNsaWVudElkIH0gPSBwYXJzZUNoZWNrcG9pbnRLZXkoa2V5KVxuXG4gICAgaWYgKGVwb2NoID4gbWF4RXBvY2gpIHtcbiAgICAgIC8vIE5ldyBoaWdoZXN0IGVwb2NoIC0gcmVzZXQgYmVzdCBjaGVja3BvaW50IHRyYWNraW5nXG4gICAgICBtYXhFcG9jaCA9IGVwb2NoXG4gICAgICBiZXN0ID0gY3BcbiAgICAgIGJlc3RUeENvdW50ID0gY3AudHhDb3VudFxuICAgICAgYmVzdENsaWVudElkID0gY2xpZW50SWRcbiAgICB9IGVsc2UgaWYgKGVwb2NoID09PSBtYXhFcG9jaCkge1xuICAgICAgLy8gU2FtZSBlcG9jaCAtIGNoZWNrIGlmIHRoaXMgaXMgYSBiZXR0ZXIgY2Fub25pY2FsIGNoZWNrcG9pbnRcbiAgICAgIC8vIFByaW1hcnk6IGhpZ2hlciB0eENvdW50IHdpbnNcbiAgICAgIC8vIFNlY29uZGFyeSAodGllLWJyZWFrKTogbG93ZXIgY2xpZW50SWQgKGFscGhhYmV0aWNhbGx5KSB3aW5zXG4gICAgICBpZiAoY3AudHhDb3VudCA+IGJlc3RUeENvdW50IHx8IChjcC50eENvdW50ID09PSBiZXN0VHhDb3VudCAmJiBjbGllbnRJZCA8IGJlc3RDbGllbnRJZCkpIHtcbiAgICAgICAgYmVzdCA9IGNwXG4gICAgICAgIGJlc3RUeENvdW50ID0gY3AudHhDb3VudFxuICAgICAgICBiZXN0Q2xpZW50SWQgPSBjbGllbnRJZFxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB7IGZpbmFsaXplZEVwb2NoOiBtYXhFcG9jaCwgY2hlY2twb2ludDogYmVzdCB9XG59XG4iLCJleHBvcnQgY2xhc3MgU3RhdGVTeW5jTG9nRXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gIGNvbnN0cnVjdG9yKG1zZzogc3RyaW5nKSB7XG4gICAgc3VwZXIobXNnKVxuXG4gICAgLy8gU2V0IHRoZSBwcm90b3R5cGUgZXhwbGljaXRseSBmb3IgYmV0dGVyIGluc3RhbmNlb2Ygc3VwcG9ydFxuICAgIE9iamVjdC5zZXRQcm90b3R5cGVPZih0aGlzLCBTdGF0ZVN5bmNMb2dFcnJvci5wcm90b3R5cGUpXG4gIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGZhaWx1cmUobWVzc2FnZTogc3RyaW5nKTogbmV2ZXIge1xuICB0aHJvdyBuZXcgU3RhdGVTeW5jTG9nRXJyb3IobWVzc2FnZSlcbn1cbiIsImltcG9ydCAqIGFzIFkgZnJvbSBcInlqc1wiXG5pbXBvcnQgeyBDbGllbnRJZCB9IGZyb20gXCIuL0NsaWVudElkXCJcbmltcG9ydCB7IGdldEZpbmFsaXplZEVwb2NoQW5kQ2hlY2twb2ludCB9IGZyb20gXCIuL2NoZWNrcG9pbnRVdGlsc1wiXG5pbXBvcnQgeyBDbGllbnRTdGF0ZSB9IGZyb20gXCIuL2NsaWVudFN0YXRlXCJcbmltcG9ydCB7IGZhaWx1cmUgfSBmcm9tIFwiLi9lcnJvclwiXG5pbXBvcnQgeyBKU09OT2JqZWN0IH0gZnJvbSBcIi4vanNvblwiXG5pbXBvcnQgeyBUeFJlY29yZCB9IGZyb20gXCIuL1R4UmVjb3JkXCJcbmltcG9ydCB7IFR4VGltZXN0YW1wS2V5IH0gZnJvbSBcIi4vdHhUaW1lc3RhbXBcIlxuXG4vKipcbiAqIFdhdGVybWFya2luZyBmb3IgZGVkdXBsaWNhdGlvbiBhbmQgcHJ1bmluZy5cbiAqIC0gbWF4Q2xvY2s6IEFsbCB0eHMgZnJvbSB0aGlzIGNsaWVudCB3aXRoIGNsb2NrIDw9IG1heENsb2NrIGFyZSBGSU5BTElaRUQuXG4gKiAtIG1heFdhbGxDbG9jazogVGhlIGxhc3QgdGltZSB3ZSBzYXcgdGhpcyBjbGllbnQgYWN0aXZlIChmb3IgcHJ1bmluZykuXG4gKi9cbnR5cGUgQ2xpZW50V2F0ZXJtYXJrID0gUmVhZG9ubHk8e1xuICBtYXhDbG9jazogbnVtYmVyXG4gIG1heFdhbGxDbG9jazogbnVtYmVyXG59PlxuXG4vKipcbiAqIFdhdGVybWFya3MgZm9yIGFsbCBjbGllbnRzLlxuICovXG5leHBvcnQgdHlwZSBDbGllbnRXYXRlcm1hcmtzID0gUmVjb3JkPENsaWVudElkLCBDbGllbnRXYXRlcm1hcms+XG5cbi8qKlxuICogQSBzbmFwc2hvdCBvZiB0aGUgc3RhdGUgYXQgdGhlIGVuZCBvZiBhIHNwZWNpZmljIGVwb2NoLlxuICovXG5leHBvcnQgdHlwZSBDaGVja3BvaW50UmVjb3JkID0ge1xuICBzdGF0ZTogSlNPTk9iamVjdCAvLyBUaGUgZG9jdW1lbnQgc3RhdGVcbiAgd2F0ZXJtYXJrczogQ2xpZW50V2F0ZXJtYXJrcyAvLyBEZWR1cC9QcnVuaW5nIGluZm9cbiAgdHhDb3VudDogbnVtYmVyIC8vIFRpZS1icmVha2VyIGZvciBjYW5vbmljYWwgc2VsZWN0aW9uXG4gIG1pbldhbGxDbG9jazogbnVtYmVyIC8vIFJlZmVyZW5jZSB0aW1lIGZvciB0aGlzIGVwb2NoIChkZXRlcm1pbmlzdGljIHBydW5pbmcpXG59XG5cbi8qKlxuICogVW5pcXVlIElEIGZvciBhIGNoZWNrcG9pbnQuXG4gKiBGb3JtYXQ6IGAke2Vwb2NofTske3R4Q291bnR9OyR7Y2xpZW50SWR9YFxuICovXG5leHBvcnQgdHlwZSBDaGVja3BvaW50S2V5ID0gc3RyaW5nXG5cbi8qKlxuICogRGF0YSBleHRyYWN0ZWQgZnJvbSBhIGNoZWNrcG9pbnQga2V5LlxuICovXG5leHBvcnQgdHlwZSBDaGVja3BvaW50S2V5RGF0YSA9IHtcbiAgZXBvY2g6IG51bWJlclxuICB0eENvdW50OiBudW1iZXJcbiAgY2xpZW50SWQ6IENsaWVudElkXG59XG5cbi8qKlxuICogQ29udmVydHMgY2hlY2twb2ludCBrZXkgZGF0YSBjb21wb25lbnRzIHRvIGEga2V5IHN0cmluZy5cbiAqL1xuZnVuY3Rpb24gY2hlY2twb2ludEtleURhdGFUb0tleShkYXRhOiBDaGVja3BvaW50S2V5RGF0YSk6IENoZWNrcG9pbnRLZXkge1xuICByZXR1cm4gYCR7ZGF0YS5lcG9jaH07JHtkYXRhLnR4Q291bnR9OyR7ZGF0YS5jbGllbnRJZH1gXG59XG5cbi8qKlxuICogSGVscGVyIHRvIHBhcnNlIGNoZWNrcG9pbnQga2V5cy5cbiAqIENoZWNrcG9pbnQga2V5cyBoYXZlIGZvcm1hdDogYCR7ZXBvY2h9OyR7dHhDb3VudH07JHtjbGllbnRJZH1gXG4gKiBUaHJvd3MgaWYga2V5IGlzIG1hbGZvcm1lZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlQ2hlY2twb2ludEtleShrZXk6IENoZWNrcG9pbnRLZXkpOiBDaGVja3BvaW50S2V5RGF0YSB7XG4gIGNvbnN0IGkxID0ga2V5LmluZGV4T2YoXCI7XCIpXG4gIGNvbnN0IGkyID0ga2V5LmluZGV4T2YoXCI7XCIsIGkxICsgMSlcblxuICBpZiAoaTEgPT09IC0xIHx8IGkyID09PSAtMSkge1xuICAgIGZhaWx1cmUoYE1hbGZvcm1lZCBjaGVja3BvaW50IGtleTogJHtrZXl9YClcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgZXBvY2g6IE51bWJlci5wYXJzZUludChrZXkuc3Vic3RyaW5nKDAsIGkxKSwgMTApLFxuICAgIHR4Q291bnQ6IE51bWJlci5wYXJzZUludChrZXkuc3Vic3RyaW5nKGkxICsgMSwgaTIpLCAxMCksXG4gICAgY2xpZW50SWQ6IGtleS5zdWJzdHJpbmcoaTIgKyAxKSxcbiAgfVxufVxuXG4vKipcbiAqIENhbGxlZCBwZXJpb2RpY2FsbHkgKGUuZy4gYnkgYSBzZXJ2ZXIgb3IgbGVhZGVyIGNsaWVudCkgdG8gZmluYWxpemUgdGhlIGVwb2NoLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlQ2hlY2twb2ludChcbiAgeVR4OiBZLk1hcDxUeFJlY29yZD4sXG4gIHlDaGVja3BvaW50OiBZLk1hcDxDaGVja3BvaW50UmVjb3JkPixcbiAgY2xpZW50U3RhdGU6IENsaWVudFN0YXRlLFxuICBhY3RpdmVFcG9jaDogbnVtYmVyLFxuICBjdXJyZW50U3RhdGU6IEpTT05PYmplY3QsXG4gIG15Q2xpZW50SWQ6IHN0cmluZ1xuKTogdm9pZCB7XG4gIC8vIDEuIFN0YXJ0IHdpdGggcHJldmlvdXMgd2F0ZXJtYXJrcyAoZnJvbSBmaW5hbGl6ZWQgZXBvY2ggPSBhY3RpdmVFcG9jaCAtIDEpXG4gIGNvbnN0IHsgY2hlY2twb2ludDogcHJldkNQIH0gPSBnZXRGaW5hbGl6ZWRFcG9jaEFuZENoZWNrcG9pbnQoeUNoZWNrcG9pbnQpXG4gIGNvbnN0IG5ld1dhdGVybWFya3MgPSBwcmV2Q1AgPyB7IC4uLnByZXZDUC53YXRlcm1hcmtzIH0gOiB7fVxuXG4gIC8vIEdldCBhY3RpdmUgdHhzIHVzaW5nIGNhY2hlZCBzb3J0ZWQgb3JkZXIgKGZpbHRlciBieSBlcG9jaClcbiAgLy8gRklMVEVSIElTIFJFUVVJUkVEOlxuICAvLyBBbHRob3VnaCB3ZSBhcmUgZmluYWxpemluZyAnYWN0aXZlRXBvY2gnLCBvdGhlciBwZWVycyBtYXkgaGF2ZSBhbHJlYWR5XG4gIC8vIGFkdmFuY2VkIHRvIHRoZSBuZXh0IGVwb2NoIGFuZCBzdGFydGVkIHN5bmNpbmcgdGhvc2UgdHhzLlxuICAvLyBXZSBtdXN0IGVuc3VyZSB0aGlzIGNoZWNrcG9pbnQgT05MWSBjb250YWlucyB0eHMgZnJvbSAnYWN0aXZlRXBvY2gnLlxuICAvLyBVc2luZyBzdGF0ZUNhbGN1bGF0b3IuZ2V0U29ydGVkVHhzIGF2b2lkcyByZWR1bmRhbnQga2V5IHBhcnNpbmcgKHRpbWVzdGFtcHMgYXJlIGNhY2hlZCkuXG4gIC8vXG4gIC8vIE9QVElNSVpBVElPTjogU2luY2Ugc29ydGVkVHhzIGlzIHNvcnRlZCBieSBlcG9jaCAocHJpbWFyeSBrZXkpIGFuZCBwYXN0IGVwb2Noc1xuICAvLyBhcmUgcHJ1bmVkLCB3ZSBvbmx5IG5lZWQgdG8gZmluZCB0aGUgcmlnaHQgYm91bmRhcnkuIEZ1dHVyZSBlcG9jaHMgYXJlIHJhcmUsXG4gIC8vIHNvIGEgc2ltcGxlIGxpbmVhciBzZWFyY2ggZnJvbSB0aGUgcmlnaHQgaXMgZWZmaWNpZW50ICh0eXBpY2FsbHkgMC0xIGl0ZXJhdGlvbnMpLlxuICBjb25zdCBzb3J0ZWRUeHMgPSBjbGllbnRTdGF0ZS5zdGF0ZUNhbGN1bGF0b3IuZ2V0U29ydGVkVHhzKClcblxuICAvLyBGaW5kIGVuZCBib3VuZGFyeSBieSBzZWFyY2hpbmcgZnJvbSByaWdodCAoc2tpcCBhbnkgZnV0dXJlIGVwb2NoIGVudHJpZXMpXG4gIGxldCBlbmRJbmRleCA9IHNvcnRlZFR4cy5sZW5ndGhcbiAgd2hpbGUgKGVuZEluZGV4ID4gMCAmJiBzb3J0ZWRUeHNbZW5kSW5kZXggLSAxXS50eFRpbWVzdGFtcC5lcG9jaCA+IGFjdGl2ZUVwb2NoKSB7XG4gICAgZW5kSW5kZXgtLVxuICB9XG5cbiAgLy8gU2xpY2UgZnJvbSBzdGFydCB0byBlbmRJbmRleCAocGFzdCBlcG9jaHMgYXJlIHBydW5lZCwgc28gdGhlc2UgYXJlIGFsbCBhY3RpdmVFcG9jaClcbiAgY29uc3QgYWN0aXZlVHhzID0gc29ydGVkVHhzLnNsaWNlKDAsIGVuZEluZGV4KVxuXG4gIGlmIChhY3RpdmVUeHMubGVuZ3RoID09PSAwKSB7XG4gICAgcmV0dXJuIC8vIERvIG5vdGhpbmcgaWYgbm8gdHhzIChwcmV2ZW50cyBlbXB0eSBlcG9jaHMpXG4gIH1cblxuICAvLyAyLiBVcGRhdGUgd2F0ZXJtYXJrcyBiYXNlZCBvbiBPQlNFUlZFRCBhY3RpdmUgdHhzIGFuZCBjYWxjdWxhdGUgbWluV2FsbENsb2NrXG4gIC8vIE5PVEU6IFdlIGNhbm5vdCB1c2UgYWN0aXZlVHhzWzBdLnR4VGltZXN0YW1wLndhbGxDbG9jayBmb3IgbWluV2FsbENsb2NrIGJlY2F1c2VcbiAgLy8gdHhzIGFyZSBzb3J0ZWQgYnkgTGFtcG9ydCBjbG9jayAoZXBvY2gg4oaSIGNsb2NrIOKGkiBjbGllbnRJZCksIG5vdCBieSB3YWxsQ2xvY2suXG4gIC8vIEEgY2xpZW50IG1heSBoYXZlIGEgaGlnaCBMYW1wb3J0IGNsb2NrIGJ1dCBlYXJseSB3YWxsQ2xvY2sgZHVlIHRvIGNsb2NrIGRyaWZ0XG4gIC8vIG9yIHJlY2VpdmluZyBtYW55IG1lc3NhZ2VzIGJlZm9yZSBlbWl0dGluZy5cbiAgbGV0IG1pbldhbGxDbG9jayA9IE51bWJlci5QT1NJVElWRV9JTkZJTklUWVxuICBsZXQgdHhDb3VudCA9IDBcbiAgZm9yIChjb25zdCBlbnRyeSBvZiBhY3RpdmVUeHMpIHtcbiAgICBjb25zdCB0cyA9IGVudHJ5LnR4VGltZXN0YW1wXG5cbiAgICAvLyBUcmFjayBtaW4gd2FsbENsb2NrIGZvciBkZXRlcm1pbmlzdGljIHBydW5pbmcgcmVmZXJlbmNlXG4gICAgaWYgKHRzLndhbGxDbG9jayA8IG1pbldhbGxDbG9jaykge1xuICAgICAgbWluV2FsbENsb2NrID0gdHMud2FsbENsb2NrXG4gICAgfVxuXG4gICAgY29uc3QgbmV3V20gPSBuZXdXYXRlcm1hcmtzW3RzLmNsaWVudElkXVxuICAgICAgPyB7IC4uLm5ld1dhdGVybWFya3NbdHMuY2xpZW50SWRdIH1cbiAgICAgIDogeyBtYXhDbG9jazogLTEsIG1heFdhbGxDbG9jazogMCB9XG5cbiAgICBpZiAodHMuY2xvY2sgPiBuZXdXbS5tYXhDbG9jaykge1xuICAgICAgbmV3V20ubWF4Q2xvY2sgPSB0cy5jbG9ja1xuICAgICAgbmV3V20ubWF4V2FsbENsb2NrID0gdHMud2FsbENsb2NrXG4gICAgfVxuICAgIG5ld1dhdGVybWFya3NbdHMuY2xpZW50SWRdID0gbmV3V21cbiAgICB0eENvdW50KytcbiAgfVxuXG4gIC8vIDMuIFBydW5lIEluYWN0aXZlIFdhdGVybWFya3MgKERldGVybWluaXN0aWMpXG4gIC8vIFVzZXMgbWluV2FsbENsb2NrIHNvIGFsbCBjbGllbnRzIGFncmVlIG9uIGV4YWN0bHkgd2hvIHRvIHBydW5lLlxuICBmb3IgKGNvbnN0IGNsaWVudElkIGluIG5ld1dhdGVybWFya3MpIHtcbiAgICBpZiAobWluV2FsbENsb2NrIC0gbmV3V2F0ZXJtYXJrc1tjbGllbnRJZF0ubWF4V2FsbENsb2NrID4gY2xpZW50U3RhdGUucmV0ZW50aW9uV2luZG93TXMpIHtcbiAgICAgIGRlbGV0ZSBuZXdXYXRlcm1hcmtzW2NsaWVudElkXVxuICAgIH1cbiAgfVxuXG4gIC8vIDQuIFNhdmUgQ2hlY2twb2ludFxuICBjb25zdCBjcEtleSA9IGNoZWNrcG9pbnRLZXlEYXRhVG9LZXkoe1xuICAgIGVwb2NoOiBhY3RpdmVFcG9jaCxcbiAgICB0eENvdW50LFxuICAgIGNsaWVudElkOiBteUNsaWVudElkLFxuICB9KVxuICB5Q2hlY2twb2ludC5zZXQoY3BLZXksIHtcbiAgICBzdGF0ZTogY3VycmVudFN0YXRlLCAvLyBSZXNwb25zaWJpbGl0eSBmb3IgY2xvbmluZyBpcyBtb3ZlZCB0byB0aGUgY2FsbGVyIGlmIG5lZWRlZFxuICAgIHdhdGVybWFya3M6IG5ld1dhdGVybWFya3MsXG4gICAgdHhDb3VudCxcbiAgICBtaW5XYWxsQ2xvY2ssXG4gIH0pXG5cbiAgLy8gNS4gRWFybHkgdHggcHJ1bmluZyAoT3B0aW1pemF0aW9uKVxuICAvLyBEZWxldGUgYWxsIHR4cyBmcm9tIHRoZSBub3ctZmluYWxpemVkIGVwb2NoXG4gIC8vIFRoaXMgcmVkdWNlcyBtZW1vcnkgcHJlc3N1cmUgaW5zdGVhZCBvZiB3YWl0aW5nIGZvciBjbGVhbnVwTG9nXG4gIGNvbnN0IGtleXNUb0RlbGV0ZTogVHhUaW1lc3RhbXBLZXlbXSA9IFtdXG4gIGZvciAoY29uc3QgZW50cnkgb2YgYWN0aXZlVHhzKSB7XG4gICAgeVR4LmRlbGV0ZShlbnRyeS50eFRpbWVzdGFtcEtleSlcbiAgICBrZXlzVG9EZWxldGUucHVzaChlbnRyeS50eFRpbWVzdGFtcEtleSlcbiAgfVxuICBjbGllbnRTdGF0ZS5zdGF0ZUNhbGN1bGF0b3IucmVtb3ZlVHhzKGtleXNUb0RlbGV0ZSlcbn1cblxuLyoqXG4gKiBHYXJiYWdlIGNvbGxlY3RzIG9sZCBjaGVja3BvaW50cy5cbiAqIFNob3VsZCBiZSBjYWxsZWQgcGVyaW9kaWNhbGx5IHRvIHByZXZlbnQgdW5ib3VuZGVkIGdyb3d0aCBvZiB5Q2hlY2twb2ludC5cbiAqXG4gKiBLZWVwcyBvbmx5IHRoZSBjYW5vbmljYWwgY2hlY2twb2ludCBmb3IgdGhlIGZpbmFsaXplZCBlcG9jaC5cbiAqIEV2ZXJ5dGhpbmcgZWxzZSBpcyBkZWxldGVkIChvbGQgZXBvY2hzICsgbm9uLWNhbm9uaWNhbCkuXG4gKlxuICogTm90ZTogVGhlIGFjdGl2ZSBlcG9jaCBuZXZlciBoYXMgY2hlY2twb2ludHMgLSBjcmVhdGluZyBhIGNoZWNrcG9pbnRcbiAqIGZvciBhbiBlcG9jaCBpbW1lZGlhdGVseSBtYWtlcyBpdCBmaW5hbGl6ZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwcnVuZUNoZWNrcG9pbnRzKFxuICB5Q2hlY2twb2ludDogWS5NYXA8Q2hlY2twb2ludFJlY29yZD4sXG4gIGZpbmFsaXplZEVwb2NoOiBudW1iZXJcbik6IHZvaWQge1xuICAvLyBGaW5kIHRoZSBjYW5vbmljYWwgY2hlY2twb2ludCBhbmQgaXRzIGtleSBpbiBvbmUgcGFzc1xuICBsZXQgY2Fub25pY2FsS2V5OiBDaGVja3BvaW50S2V5IHwgbnVsbCA9IG51bGxcbiAgbGV0IGJlc3RUeENvdW50ID0gLTFcblxuICBmb3IgKGNvbnN0IFtrZXldIG9mIHlDaGVja3BvaW50LmVudHJpZXMoKSkge1xuICAgIGNvbnN0IHsgZXBvY2gsIHR4Q291bnQgfSA9IHBhcnNlQ2hlY2twb2ludEtleShrZXkpXG4gICAgaWYgKGVwb2NoID09PSBmaW5hbGl6ZWRFcG9jaCAmJiB0eENvdW50ID4gYmVzdFR4Q291bnQpIHtcbiAgICAgIGNhbm9uaWNhbEtleSA9IGtleVxuICAgICAgYmVzdFR4Q291bnQgPSB0eENvdW50XG4gICAgfVxuICB9XG5cbiAgLy8gRGVsZXRlIGV2ZXJ5dGhpbmcgZXhjZXB0IHRoZSBjYW5vbmljYWwgY2hlY2twb2ludFxuICBmb3IgKGNvbnN0IGtleSBvZiB5Q2hlY2twb2ludC5rZXlzKCkpIHtcbiAgICBpZiAoa2V5ICE9PSBjYW5vbmljYWxLZXkpIHtcbiAgICAgIHlDaGVja3BvaW50LmRlbGV0ZShrZXkpXG4gICAgfVxuICB9XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbi8vIGRvIG5vdCBlZGl0IC5qcyBmaWxlcyBkaXJlY3RseSAtIGVkaXQgc3JjL2luZGV4LmpzdFxuXG5cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBlcXVhbChhLCBiKSB7XG4gIGlmIChhID09PSBiKSByZXR1cm4gdHJ1ZTtcblxuICBpZiAoYSAmJiBiICYmIHR5cGVvZiBhID09ICdvYmplY3QnICYmIHR5cGVvZiBiID09ICdvYmplY3QnKSB7XG4gICAgaWYgKGEuY29uc3RydWN0b3IgIT09IGIuY29uc3RydWN0b3IpIHJldHVybiBmYWxzZTtcblxuICAgIHZhciBsZW5ndGgsIGksIGtleXM7XG4gICAgaWYgKEFycmF5LmlzQXJyYXkoYSkpIHtcbiAgICAgIGxlbmd0aCA9IGEubGVuZ3RoO1xuICAgICAgaWYgKGxlbmd0aCAhPSBiLmxlbmd0aCkgcmV0dXJuIGZhbHNlO1xuICAgICAgZm9yIChpID0gbGVuZ3RoOyBpLS0gIT09IDA7KVxuICAgICAgICBpZiAoIWVxdWFsKGFbaV0sIGJbaV0pKSByZXR1cm4gZmFsc2U7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cblxuXG4gICAgaWYgKGEuY29uc3RydWN0b3IgPT09IFJlZ0V4cCkgcmV0dXJuIGEuc291cmNlID09PSBiLnNvdXJjZSAmJiBhLmZsYWdzID09PSBiLmZsYWdzO1xuICAgIGlmIChhLnZhbHVlT2YgIT09IE9iamVjdC5wcm90b3R5cGUudmFsdWVPZikgcmV0dXJuIGEudmFsdWVPZigpID09PSBiLnZhbHVlT2YoKTtcbiAgICBpZiAoYS50b1N0cmluZyAhPT0gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZykgcmV0dXJuIGEudG9TdHJpbmcoKSA9PT0gYi50b1N0cmluZygpO1xuXG4gICAga2V5cyA9IE9iamVjdC5rZXlzKGEpO1xuICAgIGxlbmd0aCA9IGtleXMubGVuZ3RoO1xuICAgIGlmIChsZW5ndGggIT09IE9iamVjdC5rZXlzKGIpLmxlbmd0aCkgcmV0dXJuIGZhbHNlO1xuXG4gICAgZm9yIChpID0gbGVuZ3RoOyBpLS0gIT09IDA7KVxuICAgICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoYiwga2V5c1tpXSkpIHJldHVybiBmYWxzZTtcblxuICAgIGZvciAoaSA9IGxlbmd0aDsgaS0tICE9PSAwOykge1xuICAgICAgdmFyIGtleSA9IGtleXNbaV07XG5cbiAgICAgIGlmICghZXF1YWwoYVtrZXldLCBiW2tleV0pKSByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvLyB0cnVlIGlmIGJvdGggTmFOLCBmYWxzZSBvdGhlcndpc2VcbiAgcmV0dXJuIGEhPT1hICYmIGIhPT1iO1xufTtcbiIsImV4cG9ydCBjb25zdCB1cmxBbHBoYWJldCA9XG4gICd1c2VhbmRvbS0yNlQxOTgzNDBQWDc1cHhKQUNLVkVSWU1JTkRCVVNIV09MRl9HUVpiZmdoamtscXZ3eXpyaWN0J1xuIiwiLyogQHRzLXNlbGYtdHlwZXM9XCIuL2luZGV4LmQudHNcIiAqL1xuaW1wb3J0IHsgdXJsQWxwaGFiZXQgYXMgc2NvcGVkVXJsQWxwaGFiZXQgfSBmcm9tICcuL3VybC1hbHBoYWJldC9pbmRleC5qcydcbmV4cG9ydCB7IHVybEFscGhhYmV0IH0gZnJvbSAnLi91cmwtYWxwaGFiZXQvaW5kZXguanMnXG5leHBvcnQgbGV0IHJhbmRvbSA9IGJ5dGVzID0+IGNyeXB0by5nZXRSYW5kb21WYWx1ZXMobmV3IFVpbnQ4QXJyYXkoYnl0ZXMpKVxuZXhwb3J0IGxldCBjdXN0b21SYW5kb20gPSAoYWxwaGFiZXQsIGRlZmF1bHRTaXplLCBnZXRSYW5kb20pID0+IHtcbiAgbGV0IG1hc2sgPSAoMiA8PCBNYXRoLmxvZzIoYWxwaGFiZXQubGVuZ3RoIC0gMSkpIC0gMVxuICBsZXQgc3RlcCA9IC1+KCgxLjYgKiBtYXNrICogZGVmYXVsdFNpemUpIC8gYWxwaGFiZXQubGVuZ3RoKVxuICByZXR1cm4gKHNpemUgPSBkZWZhdWx0U2l6ZSkgPT4ge1xuICAgIGxldCBpZCA9ICcnXG4gICAgd2hpbGUgKHRydWUpIHtcbiAgICAgIGxldCBieXRlcyA9IGdldFJhbmRvbShzdGVwKVxuICAgICAgbGV0IGogPSBzdGVwIHwgMFxuICAgICAgd2hpbGUgKGotLSkge1xuICAgICAgICBpZCArPSBhbHBoYWJldFtieXRlc1tqXSAmIG1hc2tdIHx8ICcnXG4gICAgICAgIGlmIChpZC5sZW5ndGggPj0gc2l6ZSkgcmV0dXJuIGlkXG4gICAgICB9XG4gICAgfVxuICB9XG59XG5leHBvcnQgbGV0IGN1c3RvbUFscGhhYmV0ID0gKGFscGhhYmV0LCBzaXplID0gMjEpID0+XG4gIGN1c3RvbVJhbmRvbShhbHBoYWJldCwgc2l6ZSB8IDAsIHJhbmRvbSlcbmV4cG9ydCBsZXQgbmFub2lkID0gKHNpemUgPSAyMSkgPT4ge1xuICBsZXQgaWQgPSAnJ1xuICBsZXQgYnl0ZXMgPSBjcnlwdG8uZ2V0UmFuZG9tVmFsdWVzKG5ldyBVaW50OEFycmF5KChzaXplIHw9IDApKSlcbiAgd2hpbGUgKHNpemUtLSkge1xuICAgIGlkICs9IHNjb3BlZFVybEFscGhhYmV0W2J5dGVzW3NpemVdICYgNjNdXG4gIH1cbiAgcmV0dXJuIGlkXG59XG4iLCIndXNlIHN0cmljdCdcbm1vZHVsZS5leHBvcnRzID0gcmZkY1xuXG5mdW5jdGlvbiBjb3B5QnVmZmVyIChjdXIpIHtcbiAgaWYgKGN1ciBpbnN0YW5jZW9mIEJ1ZmZlcikge1xuICAgIHJldHVybiBCdWZmZXIuZnJvbShjdXIpXG4gIH1cblxuICByZXR1cm4gbmV3IGN1ci5jb25zdHJ1Y3RvcihjdXIuYnVmZmVyLnNsaWNlKCksIGN1ci5ieXRlT2Zmc2V0LCBjdXIubGVuZ3RoKVxufVxuXG5mdW5jdGlvbiByZmRjIChvcHRzKSB7XG4gIG9wdHMgPSBvcHRzIHx8IHt9XG4gIGlmIChvcHRzLmNpcmNsZXMpIHJldHVybiByZmRjQ2lyY2xlcyhvcHRzKVxuXG4gIGNvbnN0IGNvbnN0cnVjdG9ySGFuZGxlcnMgPSBuZXcgTWFwKClcbiAgY29uc3RydWN0b3JIYW5kbGVycy5zZXQoRGF0ZSwgKG8pID0+IG5ldyBEYXRlKG8pKVxuICBjb25zdHJ1Y3RvckhhbmRsZXJzLnNldChNYXAsIChvLCBmbikgPT4gbmV3IE1hcChjbG9uZUFycmF5KEFycmF5LmZyb20obyksIGZuKSkpXG4gIGNvbnN0cnVjdG9ySGFuZGxlcnMuc2V0KFNldCwgKG8sIGZuKSA9PiBuZXcgU2V0KGNsb25lQXJyYXkoQXJyYXkuZnJvbShvKSwgZm4pKSlcbiAgaWYgKG9wdHMuY29uc3RydWN0b3JIYW5kbGVycykge1xuICAgIGZvciAoY29uc3QgaGFuZGxlciBvZiBvcHRzLmNvbnN0cnVjdG9ySGFuZGxlcnMpIHtcbiAgICAgIGNvbnN0cnVjdG9ySGFuZGxlcnMuc2V0KGhhbmRsZXJbMF0sIGhhbmRsZXJbMV0pXG4gICAgfVxuICB9XG5cbiAgbGV0IGhhbmRsZXIgPSBudWxsXG5cbiAgcmV0dXJuIG9wdHMucHJvdG8gPyBjbG9uZVByb3RvIDogY2xvbmVcblxuICBmdW5jdGlvbiBjbG9uZUFycmF5IChhLCBmbikge1xuICAgIGNvbnN0IGtleXMgPSBPYmplY3Qua2V5cyhhKVxuICAgIGNvbnN0IGEyID0gbmV3IEFycmF5KGtleXMubGVuZ3RoKVxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwga2V5cy5sZW5ndGg7IGkrKykge1xuICAgICAgY29uc3QgayA9IGtleXNbaV1cbiAgICAgIGNvbnN0IGN1ciA9IGFba11cbiAgICAgIGlmICh0eXBlb2YgY3VyICE9PSAnb2JqZWN0JyB8fCBjdXIgPT09IG51bGwpIHtcbiAgICAgICAgYTJba10gPSBjdXJcbiAgICAgIH0gZWxzZSBpZiAoY3VyLmNvbnN0cnVjdG9yICE9PSBPYmplY3QgJiYgKGhhbmRsZXIgPSBjb25zdHJ1Y3RvckhhbmRsZXJzLmdldChjdXIuY29uc3RydWN0b3IpKSkge1xuICAgICAgICBhMltrXSA9IGhhbmRsZXIoY3VyLCBmbilcbiAgICAgIH0gZWxzZSBpZiAoQXJyYXlCdWZmZXIuaXNWaWV3KGN1cikpIHtcbiAgICAgICAgYTJba10gPSBjb3B5QnVmZmVyKGN1cilcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGEyW2tdID0gZm4oY3VyKVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gYTJcbiAgfVxuXG4gIGZ1bmN0aW9uIGNsb25lIChvKSB7XG4gICAgaWYgKHR5cGVvZiBvICE9PSAnb2JqZWN0JyB8fCBvID09PSBudWxsKSByZXR1cm4gb1xuICAgIGlmIChBcnJheS5pc0FycmF5KG8pKSByZXR1cm4gY2xvbmVBcnJheShvLCBjbG9uZSlcbiAgICBpZiAoby5jb25zdHJ1Y3RvciAhPT0gT2JqZWN0ICYmIChoYW5kbGVyID0gY29uc3RydWN0b3JIYW5kbGVycy5nZXQoby5jb25zdHJ1Y3RvcikpKSB7XG4gICAgICByZXR1cm4gaGFuZGxlcihvLCBjbG9uZSlcbiAgICB9XG4gICAgY29uc3QgbzIgPSB7fVxuICAgIGZvciAoY29uc3QgayBpbiBvKSB7XG4gICAgICBpZiAoT2JqZWN0Lmhhc093blByb3BlcnR5LmNhbGwobywgaykgPT09IGZhbHNlKSBjb250aW51ZVxuICAgICAgY29uc3QgY3VyID0gb1trXVxuICAgICAgaWYgKHR5cGVvZiBjdXIgIT09ICdvYmplY3QnIHx8IGN1ciA9PT0gbnVsbCkge1xuICAgICAgICBvMltrXSA9IGN1clxuICAgICAgfSBlbHNlIGlmIChjdXIuY29uc3RydWN0b3IgIT09IE9iamVjdCAmJiAoaGFuZGxlciA9IGNvbnN0cnVjdG9ySGFuZGxlcnMuZ2V0KGN1ci5jb25zdHJ1Y3RvcikpKSB7XG4gICAgICAgIG8yW2tdID0gaGFuZGxlcihjdXIsIGNsb25lKVxuICAgICAgfSBlbHNlIGlmIChBcnJheUJ1ZmZlci5pc1ZpZXcoY3VyKSkge1xuICAgICAgICBvMltrXSA9IGNvcHlCdWZmZXIoY3VyKVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbzJba10gPSBjbG9uZShjdXIpXG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBvMlxuICB9XG5cbiAgZnVuY3Rpb24gY2xvbmVQcm90byAobykge1xuICAgIGlmICh0eXBlb2YgbyAhPT0gJ29iamVjdCcgfHwgbyA9PT0gbnVsbCkgcmV0dXJuIG9cbiAgICBpZiAoQXJyYXkuaXNBcnJheShvKSkgcmV0dXJuIGNsb25lQXJyYXkobywgY2xvbmVQcm90bylcbiAgICBpZiAoby5jb25zdHJ1Y3RvciAhPT0gT2JqZWN0ICYmIChoYW5kbGVyID0gY29uc3RydWN0b3JIYW5kbGVycy5nZXQoby5jb25zdHJ1Y3RvcikpKSB7XG4gICAgICByZXR1cm4gaGFuZGxlcihvLCBjbG9uZVByb3RvKVxuICAgIH1cbiAgICBjb25zdCBvMiA9IHt9XG4gICAgZm9yIChjb25zdCBrIGluIG8pIHtcbiAgICAgIGNvbnN0IGN1ciA9IG9ba11cbiAgICAgIGlmICh0eXBlb2YgY3VyICE9PSAnb2JqZWN0JyB8fCBjdXIgPT09IG51bGwpIHtcbiAgICAgICAgbzJba10gPSBjdXJcbiAgICAgIH0gZWxzZSBpZiAoY3VyLmNvbnN0cnVjdG9yICE9PSBPYmplY3QgJiYgKGhhbmRsZXIgPSBjb25zdHJ1Y3RvckhhbmRsZXJzLmdldChjdXIuY29uc3RydWN0b3IpKSkge1xuICAgICAgICBvMltrXSA9IGhhbmRsZXIoY3VyLCBjbG9uZVByb3RvKVxuICAgICAgfSBlbHNlIGlmIChBcnJheUJ1ZmZlci5pc1ZpZXcoY3VyKSkge1xuICAgICAgICBvMltrXSA9IGNvcHlCdWZmZXIoY3VyKVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbzJba10gPSBjbG9uZVByb3RvKGN1cilcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIG8yXG4gIH1cbn1cblxuZnVuY3Rpb24gcmZkY0NpcmNsZXMgKG9wdHMpIHtcbiAgY29uc3QgcmVmcyA9IFtdXG4gIGNvbnN0IHJlZnNOZXcgPSBbXVxuXG4gIGNvbnN0IGNvbnN0cnVjdG9ySGFuZGxlcnMgPSBuZXcgTWFwKClcbiAgY29uc3RydWN0b3JIYW5kbGVycy5zZXQoRGF0ZSwgKG8pID0+IG5ldyBEYXRlKG8pKVxuICBjb25zdHJ1Y3RvckhhbmRsZXJzLnNldChNYXAsIChvLCBmbikgPT4gbmV3IE1hcChjbG9uZUFycmF5KEFycmF5LmZyb20obyksIGZuKSkpXG4gIGNvbnN0cnVjdG9ySGFuZGxlcnMuc2V0KFNldCwgKG8sIGZuKSA9PiBuZXcgU2V0KGNsb25lQXJyYXkoQXJyYXkuZnJvbShvKSwgZm4pKSlcbiAgaWYgKG9wdHMuY29uc3RydWN0b3JIYW5kbGVycykge1xuICAgIGZvciAoY29uc3QgaGFuZGxlciBvZiBvcHRzLmNvbnN0cnVjdG9ySGFuZGxlcnMpIHtcbiAgICAgIGNvbnN0cnVjdG9ySGFuZGxlcnMuc2V0KGhhbmRsZXJbMF0sIGhhbmRsZXJbMV0pXG4gICAgfVxuICB9XG5cbiAgbGV0IGhhbmRsZXIgPSBudWxsXG4gIHJldHVybiBvcHRzLnByb3RvID8gY2xvbmVQcm90byA6IGNsb25lXG5cbiAgZnVuY3Rpb24gY2xvbmVBcnJheSAoYSwgZm4pIHtcbiAgICBjb25zdCBrZXlzID0gT2JqZWN0LmtleXMoYSlcbiAgICBjb25zdCBhMiA9IG5ldyBBcnJheShrZXlzLmxlbmd0aClcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGtleXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IGsgPSBrZXlzW2ldXG4gICAgICBjb25zdCBjdXIgPSBhW2tdXG4gICAgICBpZiAodHlwZW9mIGN1ciAhPT0gJ29iamVjdCcgfHwgY3VyID09PSBudWxsKSB7XG4gICAgICAgIGEyW2tdID0gY3VyXG4gICAgICB9IGVsc2UgaWYgKGN1ci5jb25zdHJ1Y3RvciAhPT0gT2JqZWN0ICYmIChoYW5kbGVyID0gY29uc3RydWN0b3JIYW5kbGVycy5nZXQoY3VyLmNvbnN0cnVjdG9yKSkpIHtcbiAgICAgICAgYTJba10gPSBoYW5kbGVyKGN1ciwgZm4pXG4gICAgICB9IGVsc2UgaWYgKEFycmF5QnVmZmVyLmlzVmlldyhjdXIpKSB7XG4gICAgICAgIGEyW2tdID0gY29weUJ1ZmZlcihjdXIpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBpbmRleCA9IHJlZnMuaW5kZXhPZihjdXIpXG4gICAgICAgIGlmIChpbmRleCAhPT0gLTEpIHtcbiAgICAgICAgICBhMltrXSA9IHJlZnNOZXdbaW5kZXhdXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgYTJba10gPSBmbihjdXIpXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGEyXG4gIH1cblxuICBmdW5jdGlvbiBjbG9uZSAobykge1xuICAgIGlmICh0eXBlb2YgbyAhPT0gJ29iamVjdCcgfHwgbyA9PT0gbnVsbCkgcmV0dXJuIG9cbiAgICBpZiAoQXJyYXkuaXNBcnJheShvKSkgcmV0dXJuIGNsb25lQXJyYXkobywgY2xvbmUpXG4gICAgaWYgKG8uY29uc3RydWN0b3IgIT09IE9iamVjdCAmJiAoaGFuZGxlciA9IGNvbnN0cnVjdG9ySGFuZGxlcnMuZ2V0KG8uY29uc3RydWN0b3IpKSkge1xuICAgICAgcmV0dXJuIGhhbmRsZXIobywgY2xvbmUpXG4gICAgfVxuICAgIGNvbnN0IG8yID0ge31cbiAgICByZWZzLnB1c2gobylcbiAgICByZWZzTmV3LnB1c2gobzIpXG4gICAgZm9yIChjb25zdCBrIGluIG8pIHtcbiAgICAgIGlmIChPYmplY3QuaGFzT3duUHJvcGVydHkuY2FsbChvLCBrKSA9PT0gZmFsc2UpIGNvbnRpbnVlXG4gICAgICBjb25zdCBjdXIgPSBvW2tdXG4gICAgICBpZiAodHlwZW9mIGN1ciAhPT0gJ29iamVjdCcgfHwgY3VyID09PSBudWxsKSB7XG4gICAgICAgIG8yW2tdID0gY3VyXG4gICAgICB9IGVsc2UgaWYgKGN1ci5jb25zdHJ1Y3RvciAhPT0gT2JqZWN0ICYmIChoYW5kbGVyID0gY29uc3RydWN0b3JIYW5kbGVycy5nZXQoY3VyLmNvbnN0cnVjdG9yKSkpIHtcbiAgICAgICAgbzJba10gPSBoYW5kbGVyKGN1ciwgY2xvbmUpXG4gICAgICB9IGVsc2UgaWYgKEFycmF5QnVmZmVyLmlzVmlldyhjdXIpKSB7XG4gICAgICAgIG8yW2tdID0gY29weUJ1ZmZlcihjdXIpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBpID0gcmVmcy5pbmRleE9mKGN1cilcbiAgICAgICAgaWYgKGkgIT09IC0xKSB7XG4gICAgICAgICAgbzJba10gPSByZWZzTmV3W2ldXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgbzJba10gPSBjbG9uZShjdXIpXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgcmVmcy5wb3AoKVxuICAgIHJlZnNOZXcucG9wKClcbiAgICByZXR1cm4gbzJcbiAgfVxuXG4gIGZ1bmN0aW9uIGNsb25lUHJvdG8gKG8pIHtcbiAgICBpZiAodHlwZW9mIG8gIT09ICdvYmplY3QnIHx8IG8gPT09IG51bGwpIHJldHVybiBvXG4gICAgaWYgKEFycmF5LmlzQXJyYXkobykpIHJldHVybiBjbG9uZUFycmF5KG8sIGNsb25lUHJvdG8pXG4gICAgaWYgKG8uY29uc3RydWN0b3IgIT09IE9iamVjdCAmJiAoaGFuZGxlciA9IGNvbnN0cnVjdG9ySGFuZGxlcnMuZ2V0KG8uY29uc3RydWN0b3IpKSkge1xuICAgICAgcmV0dXJuIGhhbmRsZXIobywgY2xvbmVQcm90bylcbiAgICB9XG4gICAgY29uc3QgbzIgPSB7fVxuICAgIHJlZnMucHVzaChvKVxuICAgIHJlZnNOZXcucHVzaChvMilcbiAgICBmb3IgKGNvbnN0IGsgaW4gbykge1xuICAgICAgY29uc3QgY3VyID0gb1trXVxuICAgICAgaWYgKHR5cGVvZiBjdXIgIT09ICdvYmplY3QnIHx8IGN1ciA9PT0gbnVsbCkge1xuICAgICAgICBvMltrXSA9IGN1clxuICAgICAgfSBlbHNlIGlmIChjdXIuY29uc3RydWN0b3IgIT09IE9iamVjdCAmJiAoaGFuZGxlciA9IGNvbnN0cnVjdG9ySGFuZGxlcnMuZ2V0KGN1ci5jb25zdHJ1Y3RvcikpKSB7XG4gICAgICAgIG8yW2tdID0gaGFuZGxlcihjdXIsIGNsb25lUHJvdG8pXG4gICAgICB9IGVsc2UgaWYgKEFycmF5QnVmZmVyLmlzVmlldyhjdXIpKSB7XG4gICAgICAgIG8yW2tdID0gY29weUJ1ZmZlcihjdXIpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBpID0gcmVmcy5pbmRleE9mKGN1cilcbiAgICAgICAgaWYgKGkgIT09IC0xKSB7XG4gICAgICAgICAgbzJba10gPSByZWZzTmV3W2ldXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgbzJba10gPSBjbG9uZVByb3RvKGN1cilcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICByZWZzLnBvcCgpXG4gICAgcmVmc05ldy5wb3AoKVxuICAgIHJldHVybiBvMlxuICB9XG59XG4iLCJpbXBvcnQgZXF1YWwgZnJvbSBcImZhc3QtZGVlcC1lcXVhbFwiXG5pbXBvcnQgeyBuYW5vaWQgfSBmcm9tIFwibmFub2lkXCJcbmltcG9ydCByZmRjIGZyb20gXCJyZmRjXCJcbmltcG9ydCB0eXBlIHsgSlNPTlZhbHVlIH0gZnJvbSBcIi4vanNvblwiXG5cbmNvbnN0IGNsb25lID0gcmZkYyh7IHByb3RvOiB0cnVlIH0pXG5cbi8qKlxuICogRGVlcCBlcXVhbGl0eSBjaGVjayBmb3IgSlNPTlZhbHVlcy5cbiAqIFVzZWQgZm9yIGFkZFRvU2V0IC8gZGVsZXRlRnJvbVNldCBvcGVyYXRpb25zLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZGVlcEVxdWFsKGE6IEpTT05WYWx1ZSwgYjogSlNPTlZhbHVlKTogYm9vbGVhbiB7XG4gIHJldHVybiBlcXVhbChhLCBiKVxufVxuXG4vKipcbiAqIEdlbmVyYXRlcyBhIHVuaXF1ZSBJRCB1c2luZyBuYW5vaWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZW5lcmF0ZUlEKCk6IHN0cmluZyB7XG4gIHJldHVybiBuYW5vaWQoKVxufVxuXG4vKipcbiAqIENoZWNrcyBpZiBhIHZhbHVlIGlzIGFuIG9iamVjdCAodHlwZW9mID09PSBcIm9iamVjdFwiICYmICE9PSBudWxsKS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzT2JqZWN0KHZhbHVlOiB1bmtub3duKTogdmFsdWUgaXMgb2JqZWN0IHtcbiAgcmV0dXJuIHZhbHVlICE9PSBudWxsICYmIHR5cGVvZiB2YWx1ZSA9PT0gXCJvYmplY3RcIlxufVxuXG4vKipcbiAqIERlZXAgY2xvbmVzIGEgSlNPTi1zZXJpYWxpemFibGUgdmFsdWUuXG4gKiBPcHRpbWl6ZWQ6IHByaW1pdGl2ZXMgYXJlIHJldHVybmVkIGFzLWlzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZGVlcENsb25lPFQ+KHZhbHVlOiBUKTogVCB7XG4gIC8vIFByaW1pdGl2ZXMgZG9uJ3QgbmVlZCBjbG9uaW5nXG4gIGlmICh2YWx1ZSA9PT0gbnVsbCB8fCB0eXBlb2YgdmFsdWUgIT09IFwib2JqZWN0XCIpIHtcbiAgICByZXR1cm4gdmFsdWVcbiAgfVxuICByZXR1cm4gY2xvbmUodmFsdWUpXG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIGxhenkgbWVtb2l6ZWQgZ2V0dGVyLlxuICovXG5leHBvcnQgZnVuY3Rpb24gbGF6eTxUPihmbjogKCkgPT4gVCk6ICgpID0+IFQge1xuICBsZXQgY29tcHV0ZWQgPSBmYWxzZVxuICBsZXQgdmFsdWU6IFRcbiAgcmV0dXJuICgpID0+IHtcbiAgICBpZiAoIWNvbXB1dGVkKSB7XG4gICAgICB2YWx1ZSA9IGZuKClcbiAgICAgIGNvbXB1dGVkID0gdHJ1ZVxuICAgIH1cbiAgICByZXR1cm4gdmFsdWVcbiAgfVxufVxuIiwiaW1wb3J0IHsgZmFpbHVyZSB9IGZyb20gXCIuL2Vycm9yXCJcbmltcG9ydCB0eXBlIHsgSlNPTk9iamVjdCwgSlNPTlJlY29yZCwgSlNPTlZhbHVlLCBQYXRoIH0gZnJvbSBcIi4vanNvblwiXG5pbXBvcnQgdHlwZSB7IE9wLCBWYWxpZGF0ZUZuIH0gZnJvbSBcIi4vb3BlcmF0aW9uc1wiXG5pbXBvcnQgeyBUeFJlY29yZCB9IGZyb20gXCIuL1R4UmVjb3JkXCJcbmltcG9ydCB7IGRlZXBFcXVhbCwgaXNPYmplY3QgfSBmcm9tIFwiLi91dGlsc1wiXG5cbi8qKlxuICogQSBkcmFmdCBjb250ZXh0IGZvciBjb3B5LW9uLXdyaXRlIGltbXV0YWJsZSB1cGRhdGVzLlxuICpcbiAqIFRoaXMgcHJvdmlkZXMgSW1tZXIvTXV0YXRpdmUtbGlrZSBzZW1hbnRpY3Mgd2l0aG91dCB0aGUgcHJveHkgb3ZlcmhlYWQ6XG4gKiAtIFRoZSBvcmlnaW5hbCBiYXNlIHN0YXRlIGlzIG5ldmVyIG11dGF0ZWRcbiAqIC0gT2JqZWN0cyBhcmUgY2xvbmVkIGxhemlseSBvbiBmaXJzdCBtdXRhdGlvbiAoY29weS1vbi13cml0ZSlcbiAqIC0gT25jZSBhbiBvYmplY3QgaXMgY2xvbmVkIChcIm93bmVkXCIpLCBpdCBjYW4gYmUgbXV0YXRlZCBkaXJlY3RseVxuICogLSBJZiBubyBjaGFuZ2VzIGFyZSBtYWRlLCB0aGUgb3JpZ2luYWwgcmVmZXJlbmNlIGlzIHByZXNlcnZlZCAoc3RydWN0dXJhbCBzaGFyaW5nKVxuICovXG5leHBvcnQgaW50ZXJmYWNlIERyYWZ0Q29udGV4dDxUIGV4dGVuZHMgSlNPTk9iamVjdD4ge1xuICAvKiogVGhlIGN1cnJlbnQgcm9vdCAobWF5IGJlIHRoZSBvcmlnaW5hbCBiYXNlIG9yIGEgY2xvbmVkIHZlcnNpb24pICovXG4gIHJvb3Q6IFRcbiAgLyoqIFRoZSBvcmlnaW5hbCBiYXNlIHN0YXRlIChuZXZlciBtdXRhdGVkKSAqL1xuICBiYXNlOiBUXG4gIC8qKiBTZXQgb2Ygb2JqZWN0cyB0aGF0IGhhdmUgYmVlbiBjbG9uZWQgYW5kIGFyZSBzYWZlIHRvIG11dGF0ZSAqL1xuICBvd25lZE9iamVjdHM6IFdlYWtTZXQ8b2JqZWN0PlxuICAvKiogT3B0aW1pemF0aW9uOiBmYXN0IGNoZWNrIGlmIHJvb3QgaXMgYWxyZWFkeSBvd25lZCAqL1xuICBpc1Jvb3RPd25lZDogYm9vbGVhblxufVxuXG4vKipcbiAqIENyZWF0ZXMgYSBuZXcgZHJhZnQgY29udGV4dCBmcm9tIGEgYmFzZSBzdGF0ZS5cbiAqIFRoZSBiYXNlIHN0YXRlIHdpbGwgbmV2ZXIgYmUgbXV0YXRlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZURyYWZ0PFQgZXh0ZW5kcyBKU09OT2JqZWN0PihiYXNlOiBUKTogRHJhZnRDb250ZXh0PFQ+IHtcbiAgcmV0dXJuIHtcbiAgICByb290OiBiYXNlLFxuICAgIGJhc2UsXG4gICAgb3duZWRPYmplY3RzOiBuZXcgU2V0KCksXG4gICAgaXNSb290T3duZWQ6IGZhbHNlLFxuICB9XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIHRoZSBkcmFmdCB3YXMgbW9kaWZpZWQgKHJvb3QgIT09IGJhc2UpLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNEcmFmdE1vZGlmaWVkPFQgZXh0ZW5kcyBKU09OT2JqZWN0PihjdHg6IERyYWZ0Q29udGV4dDxUPik6IGJvb2xlYW4ge1xuICByZXR1cm4gY3R4LnJvb3QgIT09IGN0eC5iYXNlXG59XG5cbmZ1bmN0aW9uIHNoYWxsb3dDbG9uZTxUIGV4dGVuZHMgb2JqZWN0PihvYmo6IFQpOiBUIHtcbiAgaWYgKEFycmF5LmlzQXJyYXkob2JqKSkge1xuICAgIHJldHVybiBvYmouc2xpY2UoKSBhcyB1bmtub3duIGFzIFRcbiAgfVxuICBjb25zdCBjbG9uZSA9IHt9IGFzIFRcbiAgY29uc3Qga2V5cyA9IE9iamVjdC5rZXlzKG9iailcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBrZXlzLmxlbmd0aDsgaSsrKSB7XG4gICAgY29uc3Qga2V5ID0ga2V5c1tpXVxuICAgIDsoY2xvbmUgYXMgYW55KVtrZXldID0gKG9iaiBhcyBhbnkpW2tleV1cbiAgfVxuICByZXR1cm4gY2xvbmVcbn1cblxuLyoqXG4gKiBFbnN1cmVzIGFuIG9iamVjdCBpcyBvd25lZCAoY2xvbmVkIGlmIG5lY2Vzc2FyeSkgYW5kIHJldHVybnMgdGhlIG93bmVkIHZlcnNpb24uXG4gKiBBbHNvIHVwZGF0ZXMgdGhlIHBhcmVudCB0byBwb2ludCB0byB0aGUgY2xvbmVkIGNoaWxkLlxuICovXG5mdW5jdGlvbiBlbnN1cmVPd25lZDxUIGV4dGVuZHMgSlNPTk9iamVjdD4oXG4gIGN0eDogRHJhZnRDb250ZXh0PFQ+LFxuICBwYXJlbnQ6IEpTT05PYmplY3QsXG4gIGtleTogc3RyaW5nIHwgbnVtYmVyLFxuICBjaGlsZDogSlNPTlJlY29yZCB8IEpTT05WYWx1ZVtdXG4pOiBKU09OUmVjb3JkIHwgSlNPTlZhbHVlW10ge1xuICBpZiAoY3R4Lm93bmVkT2JqZWN0cy5oYXMoY2hpbGQpKSB7XG4gICAgcmV0dXJuIGNoaWxkXG4gIH1cbiAgY29uc3QgY2xvbmVkID0gc2hhbGxvd0Nsb25lKGNoaWxkKVxuICA7KHBhcmVudCBhcyBhbnkpW2tleV0gPSBjbG9uZWRcbiAgY3R4Lm93bmVkT2JqZWN0cy5hZGQoY2xvbmVkKVxuICByZXR1cm4gY2xvbmVkXG59XG5cbi8qKlxuICogRW5zdXJlcyBhbGwgb2JqZWN0cyBhbG9uZyB0aGUgcGF0aCBhcmUgb3duZWQgKGNsb25lZCBpZiBuZWNlc3NhcnkpLlxuICogUmV0dXJucyB0aGUgY29udGFpbmVyIGF0IHRoZSBlbmQgb2YgdGhlIHBhdGguXG4gKiBUaHJvd3MgaWYgdGhlIHBhdGggaXMgaW52YWxpZC5cbiAqL1xuZnVuY3Rpb24gZW5zdXJlT3duZWRQYXRoPFQgZXh0ZW5kcyBKU09OT2JqZWN0PihcbiAgY3R4OiBEcmFmdENvbnRleHQ8VD4sXG4gIHBhdGg6IFBhdGhcbik6IEpTT05SZWNvcmQgfCBKU09OVmFsdWVbXSB7XG4gIC8vIEVuc3VyZSByb290IGlzIG93bmVkIGZpcnN0XG4gIGlmICghY3R4LmlzUm9vdE93bmVkKSB7XG4gICAgY3R4LnJvb3QgPSBzaGFsbG93Q2xvbmUoY3R4LnJvb3QgYXMgdW5rbm93biBhcyBvYmplY3QpIGFzIFRcbiAgICBjdHgub3duZWRPYmplY3RzLmFkZChjdHgucm9vdClcbiAgICBjdHguaXNSb290T3duZWQgPSB0cnVlXG4gIH1cblxuICBpZiAocGF0aC5sZW5ndGggPT09IDApIHtcbiAgICByZXR1cm4gY3R4LnJvb3RcbiAgfVxuXG4gIGxldCBjdXJyZW50OiBKU09OUmVjb3JkIHwgSlNPTlZhbHVlW10gPSBjdHgucm9vdFxuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgcGF0aC5sZW5ndGg7IGkrKykge1xuICAgIGNvbnN0IHNlZ21lbnQgPSBwYXRoW2ldXG4gICAgY29uc3QgaXNBcnJheUluZGV4ID0gdHlwZW9mIHNlZ21lbnQgPT09IFwibnVtYmVyXCJcblxuICAgIC8vIFZhbGlkYXRlIGNvbnRhaW5lciB0eXBlXG4gICAgaWYgKGlzQXJyYXlJbmRleCkge1xuICAgICAgaWYgKCFBcnJheS5pc0FycmF5KGN1cnJlbnQpKSB7XG4gICAgICAgIGZhaWx1cmUoYEV4cGVjdGVkIGFycmF5IGF0IHBhdGggc2VnbWVudCAke3NlZ21lbnR9YClcbiAgICAgIH1cbiAgICAgIGlmIChzZWdtZW50IDwgMCB8fCBzZWdtZW50ID49IGN1cnJlbnQubGVuZ3RoKSB7XG4gICAgICAgIGZhaWx1cmUoYEluZGV4ICR7c2VnbWVudH0gb3V0IG9mIGJvdW5kc2ApXG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGlmICghaXNPYmplY3QoY3VycmVudCkgfHwgQXJyYXkuaXNBcnJheShjdXJyZW50KSkge1xuICAgICAgICBmYWlsdXJlKGBFeHBlY3RlZCBvYmplY3QgYXQgcGF0aCBzZWdtZW50IFwiJHtzZWdtZW50fVwiYClcbiAgICAgIH1cbiAgICAgIGlmICghKHNlZ21lbnQgaW4gY3VycmVudCkpIHtcbiAgICAgICAgZmFpbHVyZShgUHJvcGVydHkgXCIke3NlZ21lbnR9XCIgZG9lcyBub3QgZXhpc3RgKVxuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IGNoaWxkOiBKU09OVmFsdWUgPSAoY3VycmVudCBhcyBhbnkpW3NlZ21lbnRdXG5cbiAgICAvLyBWYWxpZGF0ZSBjaGlsZCBpcyB0cmF2ZXJzYWJsZVxuICAgIGlmIChjaGlsZCA9PT0gbnVsbCB8fCB0eXBlb2YgY2hpbGQgIT09IFwib2JqZWN0XCIpIHtcbiAgICAgIGZhaWx1cmUoYENhbm5vdCB0cmF2ZXJzZSB0aHJvdWdoIHByaW1pdGl2ZSBhdCBwYXRoIHNlZ21lbnQgJHtzZWdtZW50fWApXG4gICAgfVxuXG4gICAgLy8gRW5zdXJlIGNoaWxkIGlzIG93bmVkIGFuZCBjb250aW51ZVxuICAgIGN1cnJlbnQgPSBlbnN1cmVPd25lZChjdHgsIGN1cnJlbnQsIHNlZ21lbnQsIGNoaWxkIGFzIEpTT05SZWNvcmQgfCBKU09OVmFsdWVbXSlcbiAgfVxuXG4gIHJldHVybiBjdXJyZW50XG59XG5cbi8qKlxuICogQXBwbGllcyBhIHNpbmdsZSBcInNldFwiIG9wZXJhdGlvbiB0byB0aGUgZHJhZnQgd2l0aCBjb3B5LW9uLXdyaXRlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZHJhZnRTZXQ8VCBleHRlbmRzIEpTT05PYmplY3Q+KFxuICBjdHg6IERyYWZ0Q29udGV4dDxUPixcbiAgcGF0aDogUGF0aCxcbiAga2V5OiBzdHJpbmcsXG4gIHZhbHVlOiBKU09OVmFsdWVcbik6IHZvaWQge1xuICBjb25zdCBjb250YWluZXIgPSBlbnN1cmVPd25lZFBhdGgoY3R4LCBwYXRoKVxuICBpZiAoQXJyYXkuaXNBcnJheShjb250YWluZXIpKSB7XG4gICAgZmFpbHVyZShcInNldCByZXF1aXJlcyBvYmplY3QgY29udGFpbmVyXCIpXG4gIH1cbiAgOyhjb250YWluZXIgYXMgSlNPTlJlY29yZClba2V5XSA9IHZhbHVlXG59XG5cbi8qKlxuICogQXBwbGllcyBhIHNpbmdsZSBcImRlbGV0ZVwiIG9wZXJhdGlvbiB0byB0aGUgZHJhZnQgd2l0aCBjb3B5LW9uLXdyaXRlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZHJhZnREZWxldGU8VCBleHRlbmRzIEpTT05PYmplY3Q+KFxuICBjdHg6IERyYWZ0Q29udGV4dDxUPixcbiAgcGF0aDogUGF0aCxcbiAga2V5OiBzdHJpbmdcbik6IHZvaWQge1xuICBjb25zdCBjb250YWluZXIgPSBlbnN1cmVPd25lZFBhdGgoY3R4LCBwYXRoKVxuICBpZiAoQXJyYXkuaXNBcnJheShjb250YWluZXIpKSB7XG4gICAgZmFpbHVyZShcImRlbGV0ZSByZXF1aXJlcyBvYmplY3QgY29udGFpbmVyXCIpXG4gIH1cbiAgZGVsZXRlIChjb250YWluZXIgYXMgSlNPTlJlY29yZClba2V5XVxufVxuXG4vKipcbiAqIEFwcGxpZXMgYSBzaW5nbGUgXCJzcGxpY2VcIiBvcGVyYXRpb24gdG8gdGhlIGRyYWZ0IHdpdGggY29weS1vbi13cml0ZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRyYWZ0U3BsaWNlPFQgZXh0ZW5kcyBKU09OT2JqZWN0PihcbiAgY3R4OiBEcmFmdENvbnRleHQ8VD4sXG4gIHBhdGg6IFBhdGgsXG4gIGluZGV4OiBudW1iZXIsXG4gIGRlbGV0ZUNvdW50OiBudW1iZXIsXG4gIGluc2VydHM6IHJlYWRvbmx5IEpTT05WYWx1ZVtdXG4pOiB2b2lkIHtcbiAgY29uc3QgY29udGFpbmVyID0gZW5zdXJlT3duZWRQYXRoKGN0eCwgcGF0aClcbiAgaWYgKCFBcnJheS5pc0FycmF5KGNvbnRhaW5lcikpIHtcbiAgICBmYWlsdXJlKFwic3BsaWNlIHJlcXVpcmVzIGFycmF5IGNvbnRhaW5lclwiKVxuICB9XG4gIGNvbnN0IHNhZmVJbmRleCA9IE1hdGgubWluKGluZGV4LCBjb250YWluZXIubGVuZ3RoKVxuICBpZiAoaW5zZXJ0cy5sZW5ndGggPT09IDApIHtcbiAgICBjb250YWluZXIuc3BsaWNlKHNhZmVJbmRleCwgZGVsZXRlQ291bnQpXG4gIH0gZWxzZSBpZiAoaW5zZXJ0cy5sZW5ndGggPT09IDEpIHtcbiAgICBjb250YWluZXIuc3BsaWNlKHNhZmVJbmRleCwgZGVsZXRlQ291bnQsIGluc2VydHNbMF0pXG4gIH0gZWxzZSB7XG4gICAgY29udGFpbmVyLnNwbGljZShzYWZlSW5kZXgsIGRlbGV0ZUNvdW50LCAuLi5pbnNlcnRzKVxuICB9XG59XG5cbi8qKlxuICogQXBwbGllcyBhIHNpbmdsZSBcImFkZFRvU2V0XCIgb3BlcmF0aW9uIHRvIHRoZSBkcmFmdCB3aXRoIGNvcHktb24td3JpdGUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBkcmFmdEFkZFRvU2V0PFQgZXh0ZW5kcyBKU09OT2JqZWN0PihcbiAgY3R4OiBEcmFmdENvbnRleHQ8VD4sXG4gIHBhdGg6IFBhdGgsXG4gIHZhbHVlOiBKU09OVmFsdWVcbik6IHZvaWQge1xuICBjb25zdCBjb250YWluZXIgPSBlbnN1cmVPd25lZFBhdGgoY3R4LCBwYXRoKVxuICBpZiAoIUFycmF5LmlzQXJyYXkoY29udGFpbmVyKSkge1xuICAgIGZhaWx1cmUoXCJhZGRUb1NldCByZXF1aXJlcyBhcnJheSBjb250YWluZXJcIilcbiAgfVxuICBpZiAoIWNvbnRhaW5lci5zb21lKChpdGVtKSA9PiBkZWVwRXF1YWwoaXRlbSwgdmFsdWUpKSkge1xuICAgIGNvbnRhaW5lci5wdXNoKHZhbHVlKVxuICB9XG59XG5cbi8qKlxuICogQXBwbGllcyBhIHNpbmdsZSBcImRlbGV0ZUZyb21TZXRcIiBvcGVyYXRpb24gdG8gdGhlIGRyYWZ0IHdpdGggY29weS1vbi13cml0ZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRyYWZ0RGVsZXRlRnJvbVNldDxUIGV4dGVuZHMgSlNPTk9iamVjdD4oXG4gIGN0eDogRHJhZnRDb250ZXh0PFQ+LFxuICBwYXRoOiBQYXRoLFxuICB2YWx1ZTogSlNPTlZhbHVlXG4pOiB2b2lkIHtcbiAgY29uc3QgY29udGFpbmVyID0gZW5zdXJlT3duZWRQYXRoKGN0eCwgcGF0aClcbiAgaWYgKCFBcnJheS5pc0FycmF5KGNvbnRhaW5lcikpIHtcbiAgICBmYWlsdXJlKFwiZGVsZXRlRnJvbVNldCByZXF1aXJlcyBhcnJheSBjb250YWluZXJcIilcbiAgfVxuICAvLyBSZW1vdmUgYWxsIG1hdGNoaW5nIGl0ZW1zIChpdGVyYXRlIGJhY2t3YXJkcyB0byBhdm9pZCBpbmRleCBzaGlmdGluZylcbiAgZm9yIChsZXQgaSA9IGNvbnRhaW5lci5sZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xuICAgIGlmIChkZWVwRXF1YWwoY29udGFpbmVyW2ldLCB2YWx1ZSkpIHtcbiAgICAgIGNvbnRhaW5lci5zcGxpY2UoaSwgMSlcbiAgICB9XG4gIH1cbn1cblxuLyoqXG4gKiBBcHBsaWVzIGEgc2luZ2xlIG9wZXJhdGlvbiB0byB0aGUgZHJhZnQgd2l0aCBjb3B5LW9uLXdyaXRlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYXBwbHlPcFRvRHJhZnQ8VCBleHRlbmRzIEpTT05PYmplY3Q+KGN0eDogRHJhZnRDb250ZXh0PFQ+LCBvcDogT3ApOiB2b2lkIHtcbiAgc3dpdGNoIChvcC5raW5kKSB7XG4gICAgY2FzZSBcInNldFwiOlxuICAgICAgZHJhZnRTZXQoY3R4LCBvcC5wYXRoLCBvcC5rZXksIG9wLnZhbHVlKVxuICAgICAgYnJlYWtcbiAgICBjYXNlIFwiZGVsZXRlXCI6XG4gICAgICBkcmFmdERlbGV0ZShjdHgsIG9wLnBhdGgsIG9wLmtleSlcbiAgICAgIGJyZWFrXG4gICAgY2FzZSBcInNwbGljZVwiOlxuICAgICAgZHJhZnRTcGxpY2UoY3R4LCBvcC5wYXRoLCBvcC5pbmRleCwgb3AuZGVsZXRlQ291bnQsIG9wLmluc2VydHMpXG4gICAgICBicmVha1xuICAgIGNhc2UgXCJhZGRUb1NldFwiOlxuICAgICAgZHJhZnRBZGRUb1NldChjdHgsIG9wLnBhdGgsIG9wLnZhbHVlKVxuICAgICAgYnJlYWtcbiAgICBjYXNlIFwiZGVsZXRlRnJvbVNldFwiOlxuICAgICAgZHJhZnREZWxldGVGcm9tU2V0KGN0eCwgb3AucGF0aCwgb3AudmFsdWUpXG4gICAgICBicmVha1xuICAgIGRlZmF1bHQ6XG4gICAgICB0aHJvdyBmYWlsdXJlKGBVbmtub3duIG9wZXJhdGlvbiBraW5kOiAkeyhvcCBhcyBhbnkpLmtpbmR9YClcbiAgfVxufVxuXG4vKipcbiAqIEFwcGxpZXMgYSBzaW5nbGUgdHJhbnNhY3Rpb24gdG8gYSBiYXNlIHN0YXRlIGltbXV0YWJseS5cbiAqXG4gKiBLZXkgYmVuZWZpdHMgb3ZlciBNdXRhdGl2ZS9JbW1lcjpcbiAqIC0gTm8gcHJveHkgb3ZlcmhlYWQgLSBkaXJlY3Qgb2JqZWN0IGFjY2VzcyBhbmQgY29weS1vbi13cml0ZSBjbG9uaW5nXG4gKiAtIFN0cnVjdHVyYWwgc2hhcmluZyAtIHVuY2hhbmdlZCBzdWJ0cmVlcyBrZWVwIHRoZWlyIHJlZmVyZW5jZXNcbiAqIC0gWmVyby1jb3B5IG9uIGZhaWx1cmUgLSBpZiB2YWxpZGF0aW9uIGZhaWxzLCByZXR1cm5zIG9yaWdpbmFsIGJhc2UgdW5jaGFuZ2VkXG4gKlxuICogQHBhcmFtIGJhc2UgLSBUaGUgYmFzZSBzdGF0ZSAobmV2ZXIgbXV0YXRlZClcbiAqIEBwYXJhbSB0eCAtIFRoZSB0cmFuc2FjdGlvbiB0byBhcHBseVxuICogQHBhcmFtIHZhbGlkYXRlRm4gLSBPcHRpb25hbCB2YWxpZGF0aW9uIGZ1bmN0aW9uXG4gKiBAcmV0dXJucyBUaGUgZmluYWwgc3RhdGUgKGlmIHZhbGlkKSBvciB0aGUgb3JpZ2luYWwgYmFzZSAoaWYgaW52YWxpZCBvciBlbXB0eSlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGFwcGx5VHhJbW11dGFibGU8VCBleHRlbmRzIEpTT05PYmplY3Q+KFxuICBiYXNlOiBULFxuICB0eDogUGljazxUeFJlY29yZCwgXCJvcHNcIj4sXG4gIHZhbGlkYXRlRm4/OiBWYWxpZGF0ZUZuPFQ+XG4pOiBUIHtcbiAgaWYgKHR4Lm9wcy5sZW5ndGggPT09IDApIHJldHVybiBiYXNlXG5cbiAgY29uc3QgY3R4ID0gY3JlYXRlRHJhZnQoYmFzZSlcblxuICB0cnkge1xuICAgIGZvciAoY29uc3Qgb3Agb2YgdHgub3BzKSB7XG4gICAgICBhcHBseU9wVG9EcmFmdChjdHgsIG9wKVxuICAgIH1cblxuICAgIGlmICh2YWxpZGF0ZUZuICYmICF2YWxpZGF0ZUZuKGN0eC5yb290KSkge1xuICAgICAgcmV0dXJuIGJhc2VcbiAgICB9XG5cbiAgICByZXR1cm4gY3R4LnJvb3RcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIGJhc2VcbiAgfVxufVxuIiwiaW1wb3J0IHsgZmFpbHVyZSB9IGZyb20gXCIuL2Vycm9yXCJcbmltcG9ydCB7IEpTT05SZWNvcmQsIEpTT05WYWx1ZSwgUGF0aCB9IGZyb20gXCIuL2pzb25cIlxuaW1wb3J0IHsgT3AgfSBmcm9tIFwiLi9vcGVyYXRpb25zXCJcblxuLyoqXG4gKiBSZWNvbmNpbGVzIHRoZSBjdXJyZW50IHN0YXRlIHdpdGggdGhlIHRhcmdldCBzdGF0ZSBieSBjb21wdXRpbmcgYW5kIGVtaXR0aW5nXG4gKiB0aGUgbWluaW1hbCBzZXQgb2Ygb3BlcmF0aW9ucyBuZWVkZWQgdG8gdHJhbnNmb3JtIGN1cnJlbnRTdGF0ZSBpbnRvIHRhcmdldFN0YXRlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY29tcHV0ZVJlY29uY2lsZU9wcyhjdXJyZW50U3RhdGU6IEpTT05WYWx1ZSwgdGFyZ2V0U3RhdGU6IEpTT05WYWx1ZSk6IE9wW10ge1xuICBjb25zdCBvcHM6IE9wW10gPSBbXVxuICBkaWZmVmFsdWUoY3VycmVudFN0YXRlLCB0YXJnZXRTdGF0ZSwgW10sIG9wcylcbiAgcmV0dXJuIG9wc1xufVxuXG5mdW5jdGlvbiBkaWZmVmFsdWUoY3VycmVudDogSlNPTlZhbHVlLCB0YXJnZXQ6IEpTT05WYWx1ZSwgcGF0aDogUGF0aCwgb3BzOiBPcFtdKTogdm9pZCB7XG4gIC8vIDEuIFJlZmVyZW5jZSBlcXVhbGl0eSAoc3RydWN0dXJhbCBzaGFyaW5nKVxuICBpZiAoY3VycmVudCA9PT0gdGFyZ2V0KSByZXR1cm5cblxuICAvLyAyLiBIYW5kbGUgcHJpbWl0aXZlcyBhbmQgbnVsbCBxdWlja2x5XG4gIGNvbnN0IGN1cnJlbnRUeXBlID0gdHlwZW9mIGN1cnJlbnRcbiAgY29uc3QgdGFyZ2V0VHlwZSA9IHR5cGVvZiB0YXJnZXRcblxuICBpZiAoY3VycmVudCA9PT0gbnVsbCB8fCB0YXJnZXQgPT09IG51bGwgfHwgY3VycmVudFR5cGUgIT09IFwib2JqZWN0XCIgfHwgdGFyZ2V0VHlwZSAhPT0gXCJvYmplY3RcIikge1xuICAgIC8vIEF0IGxlYXN0IG9uZSBpcyBwcmltaXRpdmUvbnVsbCwgb3IgdHlwZXMgZG9uJ3QgbWF0Y2hcbiAgICBlbWl0UmVwbGFjZShwYXRoLCB0YXJnZXQsIG9wcylcbiAgICByZXR1cm5cbiAgfVxuXG4gIC8vIEJvdGggYXJlIG9iamVjdHMgKG9iamVjdCBvciBhcnJheSlcbiAgY29uc3QgY3VycmVudElzQXJyYXkgPSBBcnJheS5pc0FycmF5KGN1cnJlbnQpXG4gIGNvbnN0IHRhcmdldElzQXJyYXkgPSBBcnJheS5pc0FycmF5KHRhcmdldClcblxuICBpZiAoY3VycmVudElzQXJyYXkgIT09IHRhcmdldElzQXJyYXkpIHtcbiAgICAvLyBUeXBlIG1pc21hdGNoIChvbmUgYXJyYXksIG9uZSBvYmplY3QpXG4gICAgZW1pdFJlcGxhY2UocGF0aCwgdGFyZ2V0LCBvcHMpXG4gICAgcmV0dXJuXG4gIH1cblxuICBpZiAoY3VycmVudElzQXJyYXkpIHtcbiAgICBkaWZmQXJyYXkoY3VycmVudCwgdGFyZ2V0IGFzIEpTT05WYWx1ZVtdLCBwYXRoLCBvcHMpXG4gIH0gZWxzZSB7XG4gICAgZGlmZk9iamVjdChjdXJyZW50IGFzIEpTT05SZWNvcmQsIHRhcmdldCBhcyBKU09OUmVjb3JkLCBwYXRoLCBvcHMpXG4gIH1cbn1cblxuZnVuY3Rpb24gZGlmZk9iamVjdChjdXJyZW50OiBKU09OUmVjb3JkLCB0YXJnZXQ6IEpTT05SZWNvcmQsIHBhdGg6IFBhdGgsIG9wczogT3BbXSk6IHZvaWQge1xuICAvLyAxLiBEZWxldGUga2V5cyBpbiBjdXJyZW50IGJ1dCBub3QgaW4gdGFyZ2V0XG4gIGZvciAoY29uc3Qga2V5IGluIGN1cnJlbnQpIHtcbiAgICBpZiAoT2JqZWN0Lmhhc093bihjdXJyZW50LCBrZXkpICYmICFPYmplY3QuaGFzT3duKHRhcmdldCwga2V5KSkge1xuICAgICAgb3BzLnB1c2goeyBraW5kOiBcImRlbGV0ZVwiLCBwYXRoLCBrZXkgfSlcbiAgICB9XG4gIH1cblxuICAvLyAyLiBBZGQvVXBkYXRlIGtleXMgaW4gdGFyZ2V0XG4gIGZvciAoY29uc3Qga2V5IGluIHRhcmdldCkge1xuICAgIGlmIChPYmplY3QuaGFzT3duKHRhcmdldCwga2V5KSkge1xuICAgICAgY29uc3QgdGFyZ2V0VmFsID0gdGFyZ2V0W2tleV1cbiAgICAgIGlmICghT2JqZWN0Lmhhc093bihjdXJyZW50LCBrZXkpKSB7XG4gICAgICAgIG9wcy5wdXNoKHsga2luZDogXCJzZXRcIiwgcGF0aCwga2V5LCB2YWx1ZTogdGFyZ2V0VmFsIH0pXG4gICAgICB9IGVsc2UgaWYgKGN1cnJlbnRba2V5XSAhPT0gdGFyZ2V0VmFsKSB7XG4gICAgICAgIC8vIE9ubHkgcmVjdXJzZSBpZiB2YWx1ZXMgZGlmZmVyIChyZWZlcmVuY2UgY2hlY2sgZmlyc3QpXG4gICAgICAgIGRpZmZWYWx1ZShjdXJyZW50W2tleV0sIHRhcmdldFZhbCwgWy4uLnBhdGgsIGtleV0sIG9wcylcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cblxuZnVuY3Rpb24gZGlmZkFycmF5KGN1cnJlbnQ6IEpTT05WYWx1ZVtdLCB0YXJnZXQ6IEpTT05WYWx1ZVtdLCBwYXRoOiBQYXRoLCBvcHM6IE9wW10pOiB2b2lkIHtcbiAgY29uc3QgY3VycmVudExlbiA9IGN1cnJlbnQubGVuZ3RoXG4gIGNvbnN0IHRhcmdldExlbiA9IHRhcmdldC5sZW5ndGhcbiAgY29uc3QgbWluTGVuID0gY3VycmVudExlbiA8IHRhcmdldExlbiA/IGN1cnJlbnRMZW4gOiB0YXJnZXRMZW5cblxuICAvLyBEaWZmIGNvbW1vbiBlbGVtZW50c1xuICBmb3IgKGxldCBpID0gMDsgaSA8IG1pbkxlbjsgaSsrKSB7XG4gICAgaWYgKGN1cnJlbnRbaV0gIT09IHRhcmdldFtpXSkge1xuICAgICAgZGlmZlZhbHVlKGN1cnJlbnRbaV0sIHRhcmdldFtpXSwgWy4uLnBhdGgsIGldLCBvcHMpXG4gICAgfVxuICB9XG5cbiAgLy8gSGFuZGxlIGxlbmd0aCBkaWZmZXJlbmNlXG4gIGlmICh0YXJnZXRMZW4gPiBjdXJyZW50TGVuKSB7XG4gICAgb3BzLnB1c2goe1xuICAgICAga2luZDogXCJzcGxpY2VcIixcbiAgICAgIHBhdGgsXG4gICAgICBpbmRleDogY3VycmVudExlbixcbiAgICAgIGRlbGV0ZUNvdW50OiAwLFxuICAgICAgaW5zZXJ0czogdGFyZ2V0LnNsaWNlKGN1cnJlbnRMZW4pLFxuICAgIH0pXG4gIH0gZWxzZSBpZiAoY3VycmVudExlbiA+IHRhcmdldExlbikge1xuICAgIG9wcy5wdXNoKHtcbiAgICAgIGtpbmQ6IFwic3BsaWNlXCIsXG4gICAgICBwYXRoLFxuICAgICAgaW5kZXg6IHRhcmdldExlbixcbiAgICAgIGRlbGV0ZUNvdW50OiBjdXJyZW50TGVuIC0gdGFyZ2V0TGVuLFxuICAgICAgaW5zZXJ0czogW10sXG4gICAgfSlcbiAgfVxufVxuXG5mdW5jdGlvbiBlbWl0UmVwbGFjZShwYXRoOiBQYXRoLCB2YWx1ZTogSlNPTlZhbHVlLCBvcHM6IE9wW10pOiB2b2lkIHtcbiAgaWYgKHBhdGgubGVuZ3RoID09PSAwKSB7XG4gICAgLy8gQ2Fubm90IHJlcGxhY2Ugcm9vdCBkaXJlY3RseSB2aWEgT3BzICh1bmxlc3Mgd2UgZGVmaW5lIGEgJ3Jvb3QnIG9wLCB3aGljaCB3ZSBkb24ndClcbiAgICAvLyBXZSBleHBlY3Qgcm9vdCB0byBiZSBoYW5kbGVkIGJ5IGRpZmZPYmplY3QgdXN1YWxseS5cbiAgICAvLyBJZiB3ZSBsYW5kIGhlcmUsIGl0IG1lYW5zIHJvb3QgdHlwZXMgbWlzbWF0Y2hlZCAoZS5nLiBPYmogLT4gQXJyYXkpLlxuICAgIGZhaWx1cmUoXCJTdGF0ZVN5bmNMb2c6IENhbm5vdCByZXBsYWNlIHJvb3Qgc3RhdGUgZGlyZWN0bHkgdmlhIE9wcy5cIilcbiAgfVxuXG4gIGNvbnN0IHBhcmVudFBhdGggPSBwYXRoLnNsaWNlKDAsIC0xKVxuICBjb25zdCBrZXlUb0NoZWNrID0gcGF0aFtwYXRoLmxlbmd0aCAtIDFdXG5cbiAgaWYgKHR5cGVvZiBrZXlUb0NoZWNrID09PSBcInN0cmluZ1wiKSB7XG4gICAgLy8gUGFyZW50IGlzIE9iamVjdFxuICAgIG9wcy5wdXNoKHsga2luZDogXCJzZXRcIiwgcGF0aDogcGFyZW50UGF0aCwga2V5OiBrZXlUb0NoZWNrLCB2YWx1ZSB9KVxuICB9IGVsc2Uge1xuICAgIC8vIFBhcmVudCBpcyBBcnJheVxuICAgIG9wcy5wdXNoKHtcbiAgICAgIGtpbmQ6IFwic3BsaWNlXCIsXG4gICAgICBwYXRoOiBwYXJlbnRQYXRoLFxuICAgICAgaW5kZXg6IGtleVRvQ2hlY2ssXG4gICAgICBkZWxldGVDb3VudDogMSxcbiAgICAgIGluc2VydHM6IFt2YWx1ZV0sXG4gICAgfSlcbiAgfVxufVxuIiwiaW1wb3J0IHsgZmFpbHVyZSB9IGZyb20gXCIuL2Vycm9yXCJcblxuLyoqXG4gKiBQYXJzZWQgdHggdGltZXN0YW1wIGNvbXBvbmVudHMuXG4gKi9cbmV4cG9ydCB0eXBlIFR4VGltZXN0YW1wID0ge1xuICBlcG9jaDogbnVtYmVyXG4gIGNsb2NrOiBudW1iZXJcbiAgY2xpZW50SWQ6IHN0cmluZ1xuICB3YWxsQ2xvY2s6IG51bWJlclxufVxuXG4vKipcbiAqIFVuaXF1ZSB0eCBJRCAoQ29tcG9zaXRlIEtleSkuXG4gKi9cbmV4cG9ydCB0eXBlIFR4VGltZXN0YW1wS2V5ID0gc3RyaW5nXG5cbi8qKlxuICogQ29udmVydHMgYSB0aW1lc3RhbXAgb2JqZWN0IHRvIGEgVHJhbnNhY3Rpb25UaW1lc3RhbXBLZXkgc3RyaW5nLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdHhUaW1lc3RhbXBUb0tleSh0czogVHhUaW1lc3RhbXApOiBUeFRpbWVzdGFtcEtleSB7XG4gIHJldHVybiBgJHt0cy5lcG9jaH07JHt0cy5jbG9ja307JHt0cy5jbGllbnRJZH07JHt0cy53YWxsQ2xvY2t9YFxufVxuXG4vKipcbiAqIEhlbHBlciB0byBwYXJzZSB0eCB0aW1lc3RhbXAga2V5cy5cbiAqIFRocm93cyBpZiBrZXkgaXMgbWFsZm9ybWVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VUeFRpbWVzdGFtcEtleShrZXk6IFR4VGltZXN0YW1wS2V5KTogVHhUaW1lc3RhbXAge1xuICBjb25zdCBpMSA9IGtleS5pbmRleE9mKFwiO1wiKVxuICBjb25zdCBpMiA9IGtleS5pbmRleE9mKFwiO1wiLCBpMSArIDEpXG4gIGNvbnN0IGkzID0ga2V5LmluZGV4T2YoXCI7XCIsIGkyICsgMSlcblxuICBpZiAoaTEgPT09IC0xIHx8IGkyID09PSAtMSB8fCBpMyA9PT0gLTEpIHtcbiAgICBmYWlsdXJlKGBNYWxmb3JtZWQgdGltZXN0YW1wIGtleTogJHtrZXl9YClcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgZXBvY2g6IE51bWJlci5wYXJzZUludChrZXkuc3Vic3RyaW5nKDAsIGkxKSwgMTApLFxuICAgIGNsb2NrOiBOdW1iZXIucGFyc2VJbnQoa2V5LnN1YnN0cmluZyhpMSArIDEsIGkyKSwgMTApLFxuICAgIGNsaWVudElkOiBrZXkuc3Vic3RyaW5nKGkyICsgMSwgaTMpLFxuICAgIHdhbGxDbG9jazogTnVtYmVyLnBhcnNlSW50KGtleS5zdWJzdHJpbmcoaTMgKyAxKSwgMTApLFxuICB9XG59XG5cbi8qKlxuICogQ29tcGFyZXMgdHdvIHR4IHRpbWVzdGFtcHMgZm9yIGRldGVybWluaXN0aWMgb3JkZXJpbmcuXG4gKiBTb3J0IG9yZGVyOiBlcG9jaCAoYXNjKSDihpIgY2xvY2sgKGFzYykg4oaSIGNsaWVudElkIChhc2MpXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb21wYXJlVHhUaW1lc3RhbXBzKGE6IFR4VGltZXN0YW1wLCBiOiBUeFRpbWVzdGFtcCk6IG51bWJlciB7XG4gIGlmIChhLmVwb2NoICE9PSBiLmVwb2NoKSByZXR1cm4gYS5lcG9jaCAtIGIuZXBvY2hcbiAgaWYgKGEuY2xvY2sgIT09IGIuY2xvY2spIHJldHVybiBhLmNsb2NrIC0gYi5jbG9ja1xuICBpZiAoYS5jbGllbnRJZCA8IGIuY2xpZW50SWQpIHJldHVybiAtMVxuICBpZiAoYS5jbGllbnRJZCA+IGIuY2xpZW50SWQpIHJldHVybiAxXG4gIHJldHVybiAwXG59XG4iLCJpbXBvcnQgdHlwZSAqIGFzIFkgZnJvbSBcInlqc1wiXG5pbXBvcnQgeyBmYWlsdXJlIH0gZnJvbSBcIi4vZXJyb3JcIlxuaW1wb3J0IHsgVHhSZWNvcmQgfSBmcm9tIFwiLi9UeFJlY29yZFwiXG5pbXBvcnQgeyBwYXJzZVR4VGltZXN0YW1wS2V5LCB0eXBlIFR4VGltZXN0YW1wLCB0eXBlIFR4VGltZXN0YW1wS2V5IH0gZnJvbSBcIi4vdHhUaW1lc3RhbXBcIlxuXG4vKipcbiAqIEEgY2FjaGVkIHR4IGVudHJ5IHdpdGggbGF6eSBwYXJzaW5nIGFuZCBvcHRpb25hbCB0eCBjYWNoaW5nLlxuICogVGhlIHRpbWVzdGFtcCBpcyBwYXJzZWQgb24gZmlyc3QgYWNjZXNzIGFuZCBjYWNoZWQuXG4gKiBUaGUgdHggcmVjb3JkIGNhbiBiZSBmZXRjaGVkIGxhemlseSBhbmQgY2FjaGVkLlxuICovXG5leHBvcnQgY2xhc3MgU29ydGVkVHhFbnRyeSB7XG4gIHByaXZhdGUgX3R4VGltZXN0YW1wPzogVHhUaW1lc3RhbXBcbiAgcHJpdmF0ZSBfb3JpZ2luYWxUeFRpbWVzdGFtcEtleT86IFR4VGltZXN0YW1wS2V5IHwgbnVsbFxuICBwcml2YXRlIF9vcmlnaW5hbFR4VGltZXN0YW1wPzogVHhUaW1lc3RhbXAgfCBudWxsXG4gIHByaXZhdGUgX3R4UmVjb3JkPzogVHhSZWNvcmRcblxuICBjb25zdHJ1Y3RvcihcbiAgICByZWFkb25seSB0eFRpbWVzdGFtcEtleTogVHhUaW1lc3RhbXBLZXksXG4gICAgcHJpdmF0ZSByZWFkb25seSBfeVR4OiBZLk1hcDxUeFJlY29yZD5cbiAgKSB7fVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBwYXJzZWQgdGltZXN0YW1wLCBsYXppbHkgcGFyc2luZyBhbmQgY2FjaGluZyBvbiBmaXJzdCBhY2Nlc3MuXG4gICAqL1xuICBnZXQgdHhUaW1lc3RhbXAoKTogVHhUaW1lc3RhbXAge1xuICAgIGlmICghdGhpcy5fdHhUaW1lc3RhbXApIHtcbiAgICAgIHRoaXMuX3R4VGltZXN0YW1wID0gcGFyc2VUeFRpbWVzdGFtcEtleSh0aGlzLnR4VGltZXN0YW1wS2V5KVxuICAgIH1cbiAgICByZXR1cm4gdGhpcy5fdHhUaW1lc3RhbXBcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBvcmlnaW5hbCB0eCB0aW1lc3RhbXAga2V5LCBsYXppbHkgYW5kIGNhY2hpbmcgb24gZmlyc3QgYWNjZXNzLlxuICAgKi9cbiAgZ2V0IG9yaWdpbmFsVHhUaW1lc3RhbXBLZXkoKTogVHhUaW1lc3RhbXBLZXkgfCBudWxsIHtcbiAgICBpZiAodGhpcy5fb3JpZ2luYWxUeFRpbWVzdGFtcEtleSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICBjb25zdCB0eCA9IHRoaXMudHhSZWNvcmRcbiAgICAgIHRoaXMuX29yaWdpbmFsVHhUaW1lc3RhbXBLZXkgPSB0eC5vcmlnaW5hbFR4S2V5ID8/IG51bGxcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuX29yaWdpbmFsVHhUaW1lc3RhbXBLZXlcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBwYXJzZWQgb3JpZ2luYWwgdHggdGltZXN0YW1wLCBsYXppbHkgcGFyc2luZyBhbmQgY2FjaGluZyBvbiBmaXJzdCBhY2Nlc3MuXG4gICAqL1xuICBnZXQgb3JpZ2luYWxUeFRpbWVzdGFtcCgpOiBUeFRpbWVzdGFtcCB8IG51bGwge1xuICAgIGlmICh0aGlzLl9vcmlnaW5hbFR4VGltZXN0YW1wID09PSB1bmRlZmluZWQpIHtcbiAgICAgIGNvbnN0IGtleSA9IHRoaXMub3JpZ2luYWxUeFRpbWVzdGFtcEtleVxuICAgICAgdGhpcy5fb3JpZ2luYWxUeFRpbWVzdGFtcCA9IGtleSA/IHBhcnNlVHhUaW1lc3RhbXBLZXkoa2V5KSA6IG51bGxcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuX29yaWdpbmFsVHhUaW1lc3RhbXBcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBsb2dpY2FsIChkZWR1cGxpY2F0ZWQpIHR4IHRpbWVzdGFtcCBrZXkuXG4gICAqIFRoaXMgaXMgdGhlIG9yaWdpbmFsIHR4IGtleSBpZiBpdCBleGlzdHMsIG90aGVyd2lzZSB0aGUgcGh5c2ljYWwga2V5LlxuICAgKi9cbiAgZ2V0IGRlZHVwVHhUaW1lc3RhbXBLZXkoKTogVHhUaW1lc3RhbXBLZXkge1xuICAgIHJldHVybiB0aGlzLm9yaWdpbmFsVHhUaW1lc3RhbXBLZXkgPz8gdGhpcy50eFRpbWVzdGFtcEtleVxuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIGxvZ2ljYWwgKGRlZHVwbGljYXRlZCkgcGFyc2VkIHR4IHRpbWVzdGFtcC5cbiAgICogVGhpcyBpcyB0aGUgb3JpZ2luYWwgdHggdGltZXN0YW1wIGlmIGl0IGV4aXN0cywgb3RoZXJ3aXNlIHRoZSBwaHlzaWNhbCB0aW1lc3RhbXAuXG4gICAqL1xuICBnZXQgZGVkdXBUeFRpbWVzdGFtcCgpOiBUeFRpbWVzdGFtcCB7XG4gICAgcmV0dXJuIHRoaXMub3JpZ2luYWxUeFRpbWVzdGFtcCA/PyB0aGlzLnR4VGltZXN0YW1wXG4gIH1cblxuICAvKipcbiAgICogR2V0cyB0aGUgdHggcmVjb3JkLCBsYXppbHkgZmV0Y2hpbmcgYW5kIGNhY2hpbmcgb24gZmlyc3QgYWNjZXNzLlxuICAgKiBSZXR1cm5zIHVuZGVmaW5lZCBpZiB0aGUgdHggZG9lc24ndCBleGlzdC5cbiAgICovXG4gIGdldCB0eFJlY29yZCgpOiBUeFJlY29yZCB7XG4gICAgaWYgKCF0aGlzLl90eFJlY29yZCkge1xuICAgICAgdGhpcy5fdHhSZWNvcmQgPSB0aGlzLl95VHguZ2V0KHRoaXMudHhUaW1lc3RhbXBLZXkpXG4gICAgICBpZiAoIXRoaXMuX3R4UmVjb3JkKSB7XG4gICAgICAgIHRocm93IGZhaWx1cmUoYFNvcnRlZFR4RW50cnk6IFR4UmVjb3JkIG5vdCBmb3VuZCBmb3Iga2V5ICR7dGhpcy50eFRpbWVzdGFtcEtleX1gKVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdGhpcy5fdHhSZWNvcmRcbiAgfVxufVxuIiwiaW1wb3J0IHR5cGUgKiBhcyBZIGZyb20gXCJ5anNcIlxuaW1wb3J0IHsgdHlwZSBDaGVja3BvaW50UmVjb3JkLCB0eXBlIENsaWVudFdhdGVybWFya3MgfSBmcm9tIFwiLi9jaGVja3BvaW50c1wiXG5pbXBvcnQgeyBhcHBseVR4SW1tdXRhYmxlIH0gZnJvbSBcIi4vZHJhZnRcIlxuaW1wb3J0IHsgSlNPTk9iamVjdCB9IGZyb20gXCIuL2pzb25cIlxuaW1wb3J0IHsgT3AsIFZhbGlkYXRlRm4gfSBmcm9tIFwiLi9vcGVyYXRpb25zXCJcbmltcG9ydCB7IGNvbXB1dGVSZWNvbmNpbGVPcHMgfSBmcm9tIFwiLi9yZWNvbmNpbGVcIlxuaW1wb3J0IHsgU29ydGVkVHhFbnRyeSB9IGZyb20gXCIuL1NvcnRlZFR4RW50cnlcIlxuaW1wb3J0IHsgVHhSZWNvcmQgfSBmcm9tIFwiLi9UeFJlY29yZFwiXG5pbXBvcnQgeyBjb21wYXJlVHhUaW1lc3RhbXBzLCB0eXBlIFR4VGltZXN0YW1wLCB0eXBlIFR4VGltZXN0YW1wS2V5IH0gZnJvbSBcIi4vdHhUaW1lc3RhbXBcIlxuaW1wb3J0IHsgbGF6eSB9IGZyb20gXCIuL3V0aWxzXCJcblxuLyoqXG4gKiBDaGVja3MgaWYgYSB0cmFuc2FjdGlvbiBpcyBjb3ZlcmVkIGJ5IHRoZSBjaGVja3BvaW50IHdhdGVybWFya3MuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1RyYW5zYWN0aW9uSW5DaGVja3BvaW50KHRzOiBUeFRpbWVzdGFtcCwgd2F0ZXJtYXJrczogQ2xpZW50V2F0ZXJtYXJrcyk6IGJvb2xlYW4ge1xuICBjb25zdCB3bSA9IHdhdGVybWFya3NbdHMuY2xpZW50SWRdXG4gIGlmICghd20pIHJldHVybiBmYWxzZVxuICByZXR1cm4gdHMuY2xvY2sgPD0gd20ubWF4Q2xvY2tcbn1cblxuLyoqXG4gKiBTdGF0ZUNhbGN1bGF0b3IgZW5jYXBzdWxhdGVzIHRoZSBzb3J0ZWQgdHJhbnNhY3Rpb24gY2FjaGUgYW5kIHN0YXRlIGNhbGN1bGF0aW9uIGxvZ2ljLlxuICpcbiAqIEl0IG1haW50YWluczpcbiAqIC0gQSBzb3J0ZWQgYXJyYXkgb2YgdHJhbnNhY3Rpb24gZW50cmllc1xuICogLSBBIG1hcCBmb3IgTygxKSBsb29rdXBcbiAqIC0gQSB0cmFja2luZyBpbmRleCBpbmRpY2F0aW5nIHVwIHRvIHdoaWNoIHR4IHRoZSBzdGF0ZSBoYXMgYmVlbiBjYWxjdWxhdGVkXG4gKiAtIFRoZSBjYWNoZWQgY2FsY3VsYXRlZCBzdGF0ZVxuICogLSBUaGUgYmFzZSBjaGVja3BvaW50XG4gKlxuICogVGhlIHRyYWNraW5nIGluZGV4IGlzIGludmFsaWRhdGVkIChzZXQgdG8gbnVsbCkgd2hlbjpcbiAqIC0gQSB0cmFuc2FjdGlvbiBpcyBpbnNlcnRlZCBiZWZvcmUgdGhlIGFscmVhZHktY2FsY3VsYXRlZCBzbGljZVxuICogLSBBIHRyYW5zYWN0aW9uIGlzIGRlbGV0ZWQgZnJvbSB0aGUgYWxyZWFkeS1jYWxjdWxhdGVkIHNsaWNlXG4gKiAtIFRoZSBiYXNlIGNoZWNrcG9pbnQgY2hhbmdlc1xuICovXG5leHBvcnQgY2xhc3MgU3RhdGVDYWxjdWxhdG9yIHtcbiAgLyoqIFNvcnRlZCB0eCBjYWNoZSAoQUxMIGFjdGl2ZS9mdXR1cmUgdHhzLCBrZXB0IHNvcnRlZCBieSB0aW1lc3RhbXApICovXG4gIHByaXZhdGUgc29ydGVkVHhzOiBTb3J0ZWRUeEVudHJ5W10gPSBbXVxuXG4gIC8qKiBPKDEpIGV4aXN0ZW5jZSBjaGVjayBhbmQgbG9va3VwICovXG4gIHByaXZhdGUgc29ydGVkVHhzTWFwOiBNYXA8VHhUaW1lc3RhbXBLZXksIFNvcnRlZFR4RW50cnk+ID0gbmV3IE1hcCgpXG5cbiAgLyoqXG4gICAqIEluZGV4IG9mIHRoZSBsYXN0IHRyYW5zYWN0aW9uIGFwcGxpZWQgdG8gY2FjaGVkU3RhdGUuXG4gICAqIC0gbnVsbDogc3RhdGUgbmVlZHMgZnVsbCByZWNhbGN1bGF0aW9uIGZyb20gY2hlY2twb2ludFxuICAgKiAtIC0xOiBubyB0cmFuc2FjdGlvbnMgaGF2ZSBiZWVuIGFwcGxpZWQgeWV0IChzdGF0ZSA9PT0gY2hlY2twb2ludCBzdGF0ZSlcbiAgICogLSA+PSAwOiB0cmFuc2FjdGlvbnMgdXAgdG8gYW5kIGluY2x1ZGluZyB0aGlzIGluZGV4IGhhdmUgYmVlbiBhcHBsaWVkXG4gICAqL1xuICBwcml2YXRlIGxhc3RBcHBsaWVkSW5kZXg6IG51bWJlciB8IG51bGwgPSBudWxsXG5cbiAgLyoqIFRoZSBjYWNoZWQgY2FsY3VsYXRlZCBzdGF0ZSAqL1xuICBwcml2YXRlIGNhY2hlZFN0YXRlOiBKU09OT2JqZWN0IHwgbnVsbCA9IG51bGxcblxuICAvKiogVGhlIGJhc2UgY2hlY2twb2ludCB0byBjYWxjdWxhdGUgc3RhdGUgZnJvbSAqL1xuICBwcml2YXRlIGJhc2VDaGVja3BvaW50OiBDaGVja3BvaW50UmVjb3JkIHwgbnVsbCA9IG51bGxcblxuICAvKipcbiAgICogQXBwbGllZCBkZWR1cCBrZXlzIC0gdHJhY2tzIHdoaWNoIExPR0lDQUwgdHhzIGhhdmUgYmVlbiBhcHBsaWVkLlxuICAgKiBUaGlzIGlzIHRoZSBvcmlnaW5hbFR4S2V5IChvciBwaHlzaWNhbCBrZXkgaWYgbm8gb3JpZ2luYWwpIGZvciBlYWNoIGFwcGxpZWQgdHguXG4gICAqIFVzZWQgdG8gcHJvcGVybHkgZGVkdXBsaWNhdGUgcmUtZW1pdHMuXG4gICAqL1xuICBwcml2YXRlIGFwcGxpZWRUeEtleXM6IFNldDxUeFRpbWVzdGFtcEtleT4gPSBuZXcgU2V0KClcblxuICAvKiogTWF4IGNsb2NrIHNlZW4gZnJvbSBhbnkgdHJhbnNhY3Rpb24gKGZvciBMYW1wb3J0IGNsb2NrIHVwZGF0ZXMpICovXG4gIHByaXZhdGUgbWF4U2VlbkNsb2NrID0gMFxuXG4gIC8qKiBWYWxpZGF0aW9uIGZ1bmN0aW9uIChvcHRpb25hbCkgKi9cbiAgcHJpdmF0ZSB2YWxpZGF0ZUZuPzogVmFsaWRhdGVGbjxKU09OT2JqZWN0PlxuXG4gIGNvbnN0cnVjdG9yKHZhbGlkYXRlRm4/OiBWYWxpZGF0ZUZuPEpTT05PYmplY3Q+KSB7XG4gICAgdGhpcy52YWxpZGF0ZUZuID0gdmFsaWRhdGVGblxuICB9XG5cbiAgLyoqXG4gICAqIFNldHMgdGhlIGJhc2UgY2hlY2twb2ludC4gSW52YWxpZGF0ZXMgY2FjaGVkIHN0YXRlIGlmIGNoZWNrcG9pbnQgY2hhbmdlZC5cbiAgICogQHJldHVybnMgdHJ1ZSBpZiB0aGUgY2hlY2twb2ludCBjaGFuZ2VkXG4gICAqL1xuICBzZXRCYXNlQ2hlY2twb2ludChjaGVja3BvaW50OiBDaGVja3BvaW50UmVjb3JkIHwgbnVsbCk6IGJvb2xlYW4ge1xuICAgIGlmIChjaGVja3BvaW50ID09PSB0aGlzLmJhc2VDaGVja3BvaW50KSB7XG4gICAgICByZXR1cm4gZmFsc2VcbiAgICB9XG5cbiAgICB0aGlzLmJhc2VDaGVja3BvaW50ID0gY2hlY2twb2ludFxuICAgIHRoaXMuaW52YWxpZGF0ZSgpXG4gICAgcmV0dXJuIHRydWVcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBjdXJyZW50IGJhc2UgY2hlY2twb2ludC5cbiAgICovXG4gIGdldEJhc2VDaGVja3BvaW50KCk6IENoZWNrcG9pbnRSZWNvcmQgfCBudWxsIHtcbiAgICByZXR1cm4gdGhpcy5iYXNlQ2hlY2twb2ludFxuICB9XG5cbiAgLyoqXG4gICAqIENsZWFycyBhbGwgdHJhbnNhY3Rpb25zIGFuZCByZWJ1aWxkcyBmcm9tIHlUeCBtYXAuXG4gICAqIFRoaXMgaXMgdXNlZCB3aGVuIHRoZSBjaGVja3BvaW50IGNoYW5nZXMgYW5kIHdlIG5lZWQgYSBmcmVzaCBzdGFydC5cbiAgICovXG4gIHJlYnVpbGRGcm9tWWpzKHlUeDogWS5NYXA8VHhSZWNvcmQ+KTogdm9pZCB7XG4gICAgdGhpcy5zb3J0ZWRUeHMgPSBbXVxuICAgIHRoaXMuc29ydGVkVHhzTWFwLmNsZWFyKClcblxuICAgIC8vIENvbGxlY3QgYWxsIGVudHJpZXMsIGJ1aWxkIHRoZSBtYXAgYW5kIG1heCBjbG9ja1xuICAgIGZvciAoY29uc3Qga2V5IG9mIHlUeC5rZXlzKCkpIHtcbiAgICAgIGNvbnN0IGVudHJ5ID0gbmV3IFNvcnRlZFR4RW50cnkoa2V5LCB5VHgpXG4gICAgICB0aGlzLnNvcnRlZFR4cy5wdXNoKGVudHJ5KVxuXG4gICAgICB0aGlzLnNvcnRlZFR4c01hcC5zZXQoZW50cnkudHhUaW1lc3RhbXBLZXksIGVudHJ5KVxuICAgICAgaWYgKGVudHJ5LnR4VGltZXN0YW1wLmNsb2NrID4gdGhpcy5tYXhTZWVuQ2xvY2spIHtcbiAgICAgICAgdGhpcy5tYXhTZWVuQ2xvY2sgPSBlbnRyeS50eFRpbWVzdGFtcC5jbG9ja1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFNvcnQgb25jZSAtIE8obiBsb2cgbilcbiAgICB0aGlzLnNvcnRlZFR4cy5zb3J0KChhLCBiKSA9PiBjb21wYXJlVHhUaW1lc3RhbXBzKGEudHhUaW1lc3RhbXAsIGIudHhUaW1lc3RhbXApKVxuXG4gICAgLy8gSW52YWxpZGF0ZSBjYWNoZWQgc3RhdGUgc2luY2Ugd2UgcmVidWlsdFxuICAgIHRoaXMuaW52YWxpZGF0ZSgpXG4gIH1cblxuICAvKipcbiAgICogSW5zZXJ0cyBhIHRyYW5zYWN0aW9uIGludG8gdGhlIHNvcnRlZCBjYWNoZS5cbiAgICogSW52YWxpZGF0ZXMgY2FjaGVkIHN0YXRlIGlmIHRoZSB0cmFuc2FjdGlvbiB3YXMgaW5zZXJ0ZWQgYmVmb3JlIHRoZSBjYWxjdWxhdGVkIHNsaWNlLlxuICAgKlxuICAgKiBAcmV0dXJucyB0cnVlIGlmIHRoaXMgY2F1c2VkIGludmFsaWRhdGlvbiAob3V0LW9mLW9yZGVyIGluc2VydClcbiAgICovXG4gIGluc2VydFR4KGtleTogVHhUaW1lc3RhbXBLZXksIHlUeDogWS5NYXA8VHhSZWNvcmQ+KTogYm9vbGVhbiB7XG4gICAgaWYgKHRoaXMuc29ydGVkVHhzTWFwLmhhcyhrZXkpKSB7XG4gICAgICByZXR1cm4gZmFsc2UgLy8gQWxyZWFkeSBleGlzdHNcbiAgICB9XG5cbiAgICBjb25zdCBlbnRyeSA9IG5ldyBTb3J0ZWRUeEVudHJ5KGtleSwgeVR4KVxuICAgIGNvbnN0IHRzID0gZW50cnkudHhUaW1lc3RhbXBcblxuICAgIC8vIFVwZGF0ZSBtYXggc2VlbiBjbG9jayBmb3IgTGFtcG9ydCBjbG9jayBtZWNoYW5pc21cbiAgICBpZiAodHMuY2xvY2sgPiB0aGlzLm1heFNlZW5DbG9jaykge1xuICAgICAgdGhpcy5tYXhTZWVuQ2xvY2sgPSB0cy5jbG9ja1xuICAgIH1cblxuICAgIGNvbnN0IHNvcnRlZFR4cyA9IHRoaXMuc29ydGVkVHhzXG5cbiAgICAvLyBGaW5kIGluc2VydGlvbiBwb3NpdGlvbiAoc2VhcmNoIGZyb20gZW5kIHNpbmNlIG5ldyB0eHMgdHlwaWNhbGx5IGhhdmUgaGlnaGVyIHRpbWVzdGFtcHMpXG4gICAgbGV0IGluc2VydEluZGV4ID0gc29ydGVkVHhzLmxlbmd0aCAvLyBEZWZhdWx0OiBhcHBlbmQgYXQgZW5kXG4gICAgZm9yIChsZXQgaSA9IHNvcnRlZFR4cy5sZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xuICAgICAgY29uc3QgZXhpc3RpbmdUcyA9IHNvcnRlZFR4c1tpXS50eFRpbWVzdGFtcFxuICAgICAgaWYgKGNvbXBhcmVUeFRpbWVzdGFtcHModHMsIGV4aXN0aW5nVHMpID49IDApIHtcbiAgICAgICAgaW5zZXJ0SW5kZXggPSBpICsgMVxuICAgICAgICBicmVha1xuICAgICAgfVxuICAgICAgaWYgKGkgPT09IDApIHtcbiAgICAgICAgaW5zZXJ0SW5kZXggPSAwIC8vIEluc2VydCBhdCBiZWdpbm5pbmdcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBJbnNlcnQgYXQgdGhlIGZvdW5kIHBvc2l0aW9uXG4gICAgc29ydGVkVHhzLnNwbGljZShpbnNlcnRJbmRleCwgMCwgZW50cnkpXG4gICAgdGhpcy5zb3J0ZWRUeHNNYXAuc2V0KGtleSwgZW50cnkpXG5cbiAgICAvLyBDaGVjayBpZiB0aGlzIGludmFsaWRhdGVzIG91ciBjYWNoZWQgc3RhdGVcbiAgICAvLyBJZiB3ZSBpbnNlcnRlZCBiZWZvcmUgb3IgYXQgdGhlIGxhc3QgYXBwbGllZCBpbmRleCwgd2UgbmVlZCB0byByZWNhbGN1bGF0ZVxuICAgIGlmICh0aGlzLmxhc3RBcHBsaWVkSW5kZXggIT09IG51bGwgJiYgaW5zZXJ0SW5kZXggPD0gdGhpcy5sYXN0QXBwbGllZEluZGV4KSB7XG4gICAgICB0aGlzLmludmFsaWRhdGUoKVxuICAgICAgcmV0dXJuIHRydWVcbiAgICB9XG5cbiAgICByZXR1cm4gZmFsc2VcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmVzIG11bHRpcGxlIHRyYW5zYWN0aW9ucyBmcm9tIHRoZSBzb3J0ZWQgY2FjaGUuXG4gICAqIEByZXR1cm5zIHRoZSBudW1iZXIgb2Yga2V5cyB0aGF0IHdlcmUgYWN0dWFsbHkgcmVtb3ZlZFxuICAgKi9cbiAgcmVtb3ZlVHhzKGtleXM6IHJlYWRvbmx5IFR4VGltZXN0YW1wS2V5W10pOiBudW1iZXIge1xuICAgIGlmIChrZXlzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIDBcblxuICAgIGxldCByZW1vdmVkQ291bnQgPSAwXG4gICAgbGV0IG1pblJlbW92ZWRJbmRleCA9IE51bWJlci5QT1NJVElWRV9JTkZJTklUWVxuXG4gICAgLy8gQnVpbGQgc2V0IG9mIGtleXMgdG8gZGVsZXRlIGFuZCB0cmFjayB0aGVpciBpbmRpY2VzXG4gICAgY29uc3QgdG9EZWxldGUgPSBuZXcgU2V0PFR4VGltZXN0YW1wS2V5PigpXG4gICAgZm9yIChjb25zdCBrZXkgb2Yga2V5cykge1xuICAgICAgY29uc3QgZW50cnkgPSB0aGlzLnNvcnRlZFR4c01hcC5nZXQoa2V5KVxuICAgICAgaWYgKGVudHJ5KSB7XG4gICAgICAgIHRoaXMuc29ydGVkVHhzTWFwLmRlbGV0ZShrZXkpXG4gICAgICAgIHRvRGVsZXRlLmFkZChrZXkpXG5cbiAgICAgICAgLy8gRmluZCBpbmRleCBmb3IgaW52YWxpZGF0aW9uIGNoZWNrXG4gICAgICAgIGNvbnN0IGluZGV4ID0gdGhpcy5zb3J0ZWRUeHMuaW5kZXhPZihlbnRyeSlcbiAgICAgICAgaWYgKGluZGV4ICE9PSAtMSAmJiBpbmRleCA8IG1pblJlbW92ZWRJbmRleCkge1xuICAgICAgICAgIG1pblJlbW92ZWRJbmRleCA9IGluZGV4XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAodG9EZWxldGUuc2l6ZSA9PT0gMCkgcmV0dXJuIDBcblxuICAgIC8vIFNpbmdsZSBmb3J3YXJkIHBhc3MgdGhyb3VnaCBzb3J0ZWRUeHMsIHJlbW92aW5nIG1hdGNoaW5nIGVudHJpZXNcbiAgICBjb25zdCBzb3J0ZWRUeHMgPSB0aGlzLnNvcnRlZFR4c1xuICAgIGxldCBpID0gMFxuICAgIHdoaWxlIChpIDwgc29ydGVkVHhzLmxlbmd0aCAmJiB0b0RlbGV0ZS5zaXplID4gMCkge1xuICAgICAgaWYgKHRvRGVsZXRlLmhhcyhzb3J0ZWRUeHNbaV0udHhUaW1lc3RhbXBLZXkpKSB7XG4gICAgICAgIHRvRGVsZXRlLmRlbGV0ZShzb3J0ZWRUeHNbaV0udHhUaW1lc3RhbXBLZXkpXG4gICAgICAgIHNvcnRlZFR4cy5zcGxpY2UoaSwgMSlcbiAgICAgICAgcmVtb3ZlZENvdW50KytcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGkrK1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIENoZWNrIGlmIHRoaXMgaW52YWxpZGF0ZXMgb3VyIGNhY2hlZCBzdGF0ZVxuICAgIGlmICh0aGlzLmxhc3RBcHBsaWVkSW5kZXggIT09IG51bGwgJiYgbWluUmVtb3ZlZEluZGV4IDw9IHRoaXMubGFzdEFwcGxpZWRJbmRleCkge1xuICAgICAgdGhpcy5pbnZhbGlkYXRlKClcbiAgICB9XG5cbiAgICByZXR1cm4gcmVtb3ZlZENvdW50XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIGEgdHJhbnNhY3Rpb24ga2V5IGV4aXN0cyBpbiB0aGUgY2FjaGUuXG4gICAqL1xuICBoYXNUeChrZXk6IFR4VGltZXN0YW1wS2V5KTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuc29ydGVkVHhzTWFwLmhhcyhrZXkpXG4gIH1cblxuICAvKipcbiAgICogR2V0cyBhIHRyYW5zYWN0aW9uIGVudHJ5IGJ5IGtleS5cbiAgICovXG4gIGdldFR4KGtleTogVHhUaW1lc3RhbXBLZXkpOiBTb3J0ZWRUeEVudHJ5IHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5zb3J0ZWRUeHNNYXAuZ2V0KGtleSlcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIGFsbCBzb3J0ZWQgdHJhbnNhY3Rpb24gZW50cmllcy5cbiAgICovXG4gIGdldFNvcnRlZFR4cygpOiByZWFkb25seSBTb3J0ZWRUeEVudHJ5W10ge1xuICAgIHJldHVybiB0aGlzLnNvcnRlZFR4c1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIG51bWJlciBvZiB0cmFuc2FjdGlvbnMgaW4gdGhlIGNhY2hlLlxuICAgKi9cbiAgZ2V0IHR4Q291bnQoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5zb3J0ZWRUeHMubGVuZ3RoXG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0cnVlIGlmIHRoZSBzdGF0ZSBuZWVkcyBmdWxsIHJlY2FsY3VsYXRpb24uXG4gICAqL1xuICBuZWVkc0Z1bGxSZWNhbGN1bGF0aW9uKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmxhc3RBcHBsaWVkSW5kZXggPT09IG51bGxcbiAgfVxuXG4gIC8qKlxuICAgKiBJbnZhbGlkYXRlcyB0aGUgY2FjaGVkIHN0YXRlLCBmb3JjaW5nIGEgZnVsbCByZWNhbGN1bGF0aW9uIG9uIG5leHQgY2FsY3VsYXRlU3RhdGUoKS5cbiAgICogTm90ZTogY2FjaGVkU3RhdGUgaXMga2VwdCBzbyBjb21wdXRlUmVjb25jaWxlT3BzIGNhbiBkaWZmIG9sZCB2cyBuZXcgc3RhdGUuXG4gICAqL1xuICBpbnZhbGlkYXRlKCk6IHZvaWQge1xuICAgIHRoaXMubGFzdEFwcGxpZWRJbmRleCA9IG51bGxcbiAgfVxuXG4gIC8qKlxuICAgKiBDYWxjdWxhdGVzIGFuZCByZXR1cm5zIHRoZSBjdXJyZW50IHN0YXRlLCBhbG9uZyB3aXRoIGEgbGF6eSBnZXR0ZXIgZm9yIG9wcyB0aGF0IGNoYW5nZWQgZnJvbSB0aGUgcHJldmlvdXMgc3RhdGUuXG4gICAqXG4gICAqIC0gSWYgbGFzdEFwcGxpZWRJbmRleCBpcyBudWxsOiBmdWxsIHJlY2FsY3VsYXRpb24gZnJvbSBjaGVja3BvaW50XG4gICAqIC0gSWYgbGFzdEFwcGxpZWRJbmRleCA+PSAtMTogaW5jcmVtZW50YWwgYXBwbHkgZnJvbSBsYXN0QXBwbGllZEluZGV4ICsgMVxuICAgKi9cbiAgY2FsY3VsYXRlU3RhdGUoKTogeyBzdGF0ZTogSlNPTk9iamVjdDsgZ2V0QXBwbGllZE9wczogKCkgPT4gcmVhZG9ubHkgT3BbXSB9IHtcbiAgICBjb25zdCBiYXNlU3RhdGU6IEpTT05PYmplY3QgPSB0aGlzLmJhc2VDaGVja3BvaW50Py5zdGF0ZSA/PyB7fVxuICAgIGNvbnN0IHdhdGVybWFya3MgPSB0aGlzLmJhc2VDaGVja3BvaW50Py53YXRlcm1hcmtzID8/IHt9XG4gICAgY29uc3QgaGFzV2F0ZXJtYXJrcyA9IE9iamVjdC5rZXlzKHdhdGVybWFya3MpLmxlbmd0aCA+IDBcblxuICAgIGlmICh0aGlzLmxhc3RBcHBsaWVkSW5kZXggPT09IG51bGwpIHtcbiAgICAgIC8vIFNMT1cgUEFUSDogRnVsbCByZWNhbGN1bGF0aW9uXG4gICAgICByZXR1cm4gdGhpcy5mdWxsUmVjYWxjdWxhdGlvbihiYXNlU3RhdGUsIHdhdGVybWFya3MsIGhhc1dhdGVybWFya3MpXG4gICAgfVxuXG4gICAgLy8gRkFTVCBQQVRIOiBJbmNyZW1lbnRhbCBhcHBseVxuICAgIHJldHVybiB0aGlzLmluY3JlbWVudGFsQXBwbHkod2F0ZXJtYXJrcywgaGFzV2F0ZXJtYXJrcylcbiAgfVxuXG4gIC8qKlxuICAgKiBGdWxsIHJlY2FsY3VsYXRpb24gb2Ygc3RhdGUgZnJvbSB0aGUgYmFzZSBjaGVja3BvaW50LlxuICAgKi9cbiAgcHJpdmF0ZSBmdWxsUmVjYWxjdWxhdGlvbihcbiAgICBiYXNlU3RhdGU6IEpTT05PYmplY3QsXG4gICAgd2F0ZXJtYXJrczogQ2xpZW50V2F0ZXJtYXJrcyxcbiAgICBoYXNXYXRlcm1hcmtzOiBib29sZWFuXG4gICk6IHsgc3RhdGU6IEpTT05PYmplY3Q7IGdldEFwcGxpZWRPcHM6ICgpID0+IHJlYWRvbmx5IE9wW10gfSB7XG4gICAgY29uc3Qgb2xkU3RhdGUgPSB0aGlzLmNhY2hlZFN0YXRlID8/IHt9XG5cbiAgICAvLyBSZXNldCB0cmFja2luZyBmb3IgZnVsbCByZWNvbXB1dGVcbiAgICB0aGlzLmFwcGxpZWRUeEtleXMuY2xlYXIoKVxuICAgIHRoaXMubGFzdEFwcGxpZWRJbmRleCA9IC0xXG4gICAgdGhpcy5jYWNoZWRTdGF0ZSA9IGJhc2VTdGF0ZVxuXG4gICAgLy8gRGVsZWdhdGUgdG8gaW5jcmVtZW50YWwgYXBwbHkgdG8gcmVwbGF5IGFsbCB0cmFuc2FjdGlvbnNcbiAgICAvLyBXZSBpZ25vcmUgdGhlIHJldHVybmVkIG9wcyBiZWNhdXNlIHRoZXkgcmVwcmVzZW50IHRoZSBvcGVyYXRpb25zIGFwcGxpZWQgZnJvbSB0aGUgYmFzZSBzdGF0ZSxcbiAgICAvLyB3aGVyZWFzIHdlIHdhbnQgdGhlIGRpZmYgZnJvbSB0aGUgKnByZXZpb3VzIGNhY2hlZCBzdGF0ZSouXG4gICAgLy8gV2UgcGFzcyByZXR1cm5PcHM9ZmFsc2UgdG8gYXZvaWQgY29sbGVjdGluZyBvcHMgZHVyaW5nIHJlcGxheS5cbiAgICBjb25zdCB7IHN0YXRlIH0gPSB0aGlzLmluY3JlbWVudGFsQXBwbHkod2F0ZXJtYXJrcywgaGFzV2F0ZXJtYXJrcywgZmFsc2UpXG5cbiAgICAvLyBMYXp5IGxvYWQgdGhlIHJlY29uY2lsaWF0aW9uIG9wcyAoZXhwZW5zaXZlIGRpZmYpXG4gICAgY29uc3QgZ2V0QXBwbGllZE9wcyA9IGxhenkoKCkgPT4gY29tcHV0ZVJlY29uY2lsZU9wcyhvbGRTdGF0ZSwgc3RhdGUpKVxuXG4gICAgcmV0dXJuIHsgc3RhdGUsIGdldEFwcGxpZWRPcHMgfVxuICB9XG5cbiAgLyoqXG4gICAqIEluY3JlbWVudGFsIGFwcGx5IG9mIHRyYW5zYWN0aW9ucyBmcm9tIGxhc3RBcHBsaWVkSW5kZXggKyAxLlxuICAgKiBAcGFyYW0gcmV0dXJuT3BzIElmIHRydWUsIGNvbGxlY3RzIGFwcGxpZWQgdHJhbnNhY3Rpb25zICh0byBsYXp5IGNvbXB1dGUgb3BzKS4gSWYgZmFsc2UsIHNraXBzIGNvbGxlY3Rpb24uXG4gICAqL1xuICBwcml2YXRlIGluY3JlbWVudGFsQXBwbHkoXG4gICAgd2F0ZXJtYXJrczogQ2xpZW50V2F0ZXJtYXJrcyxcbiAgICBoYXNXYXRlcm1hcmtzOiBib29sZWFuLFxuICAgIHJldHVybk9wcyA9IHRydWVcbiAgKTogeyBzdGF0ZTogSlNPTk9iamVjdDsgZ2V0QXBwbGllZE9wczogKCkgPT4gcmVhZG9ubHkgT3BbXSB9IHtcbiAgICBsZXQgc3RhdGUgPSB0aGlzLmNhY2hlZFN0YXRlIGFzIEpTT05PYmplY3RcbiAgICBjb25zdCBhcHBsaWVkVHhzOiBUeFJlY29yZFtdID0gW11cbiAgICBjb25zdCBzb3J0ZWRUeHMgPSB0aGlzLnNvcnRlZFR4c1xuICAgIGNvbnN0IHN0YXJ0SW5kZXggPSB0aGlzLmxhc3RBcHBsaWVkSW5kZXghICsgMVxuXG4gICAgZm9yIChsZXQgaSA9IHN0YXJ0SW5kZXg7IGkgPCBzb3J0ZWRUeHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IGVudHJ5ID0gc29ydGVkVHhzW2ldXG4gICAgICBjb25zdCBkZWR1cEtleSA9IGVudHJ5LmRlZHVwVHhUaW1lc3RhbXBLZXlcblxuICAgICAgLy8gU2tpcCBpZiBhbHJlYWR5IGFwcGxpZWQgKGRlZHVwbGljYXRpb24pXG4gICAgICBpZiAodGhpcy5hcHBsaWVkVHhLZXlzLmhhcyhkZWR1cEtleSkpIHtcbiAgICAgICAgY29udGludWVcbiAgICAgIH1cblxuICAgICAgLy8gU2tpcCBpZiBpbiBjaGVja3BvaW50XG4gICAgICBpZiAoaGFzV2F0ZXJtYXJrcykge1xuICAgICAgICBjb25zdCBkZWR1cFRzID0gZW50cnkuZGVkdXBUeFRpbWVzdGFtcFxuICAgICAgICBpZiAoaXNUcmFuc2FjdGlvbkluQ2hlY2twb2ludChkZWR1cFRzLCB3YXRlcm1hcmtzKSkge1xuICAgICAgICAgIHRoaXMuYXBwbGllZFR4S2V5cy5hZGQoZGVkdXBLZXkpXG4gICAgICAgICAgY29udGludWVcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjb25zdCB0eCA9IGVudHJ5LnR4UmVjb3JkXG5cbiAgICAgIC8vIEFwcGx5IHRyYW5zYWN0aW9uIDEtYnktMSB0byBhdm9pZCBkcmFmdCBjb250ZXh0IHBvbGx1dGlvbiBvbiB2YWxpZGF0aW9uIGZhaWx1cmVcbiAgICAgIGNvbnN0IG5ld1N0YXRlID0gYXBwbHlUeEltbXV0YWJsZShzdGF0ZSwgdHgsIHRoaXMudmFsaWRhdGVGbilcblxuICAgICAgaWYgKG5ld1N0YXRlICE9PSBzdGF0ZSkge1xuICAgICAgICBzdGF0ZSA9IG5ld1N0YXRlXG4gICAgICAgIGlmIChyZXR1cm5PcHMpIHtcbiAgICAgICAgICBhcHBsaWVkVHhzLnB1c2godHgpXG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgdGhpcy5hcHBsaWVkVHhLZXlzLmFkZChkZWR1cEtleSlcbiAgICAgIHRoaXMubGFzdEFwcGxpZWRJbmRleCA9IGlcbiAgICB9XG5cbiAgICAvLyBVcGRhdGUgbGFzdEFwcGxpZWRJbmRleCB0byBlbmQgZXZlbiBpZiBhbGwgdHhzIHdlcmUgc2tpcHBlZFxuICAgIC8vIFRoaXMgZW5zdXJlcyB3ZSBkb24ndCByZS1wcm9jZXNzIHNraXBwZWQgdHhzIG9uIG5leHQgaW5jcmVtZW50YWwgYXBwbHlcbiAgICBpZiAoc29ydGVkVHhzLmxlbmd0aCA+IDAgJiYgdGhpcy5sYXN0QXBwbGllZEluZGV4ISA8IHNvcnRlZFR4cy5sZW5ndGggLSAxKSB7XG4gICAgICB0aGlzLmxhc3RBcHBsaWVkSW5kZXggPSBzb3J0ZWRUeHMubGVuZ3RoIC0gMVxuICAgIH1cblxuICAgIHRoaXMuY2FjaGVkU3RhdGUgPSBzdGF0ZVxuXG4gICAgLy8gTGF6eSBnZXR0ZXIgZm9yIG9wcyAoZmxhdHRlbnMgYXBwbGllZCB0eHMpXG4gICAgY29uc3QgZ2V0QXBwbGllZE9wcyA9IGxhenkoKCkgPT4ge1xuICAgICAgY29uc3Qgb3BzOiBPcFtdID0gW11cbiAgICAgIGZvciAoY29uc3QgdHggb2YgYXBwbGllZFR4cykge1xuICAgICAgICBvcHMucHVzaCguLi50eC5vcHMpXG4gICAgICB9XG4gICAgICByZXR1cm4gb3BzXG4gICAgfSlcblxuICAgIHJldHVybiB7IHN0YXRlLCBnZXRBcHBsaWVkT3BzIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBtYXggc2VlbiBjbG9jayAoZm9yIExhbXBvcnQgY2xvY2sgdXBkYXRlcykuXG4gICAqL1xuICBnZXRNYXhTZWVuQ2xvY2soKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5tYXhTZWVuQ2xvY2tcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBjdXJyZW50IGNhY2hlZCBzdGF0ZSB3aXRob3V0IHJlY2FsY3VsYXRpbmcuXG4gICAqIFJldHVybnMgbnVsbCBpZiBzdGF0ZSBoYXMgbmV2ZXIgYmVlbiBjYWxjdWxhdGVkLlxuICAgKi9cbiAgZ2V0Q2FjaGVkU3RhdGUoKTogSlNPTk9iamVjdCB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLmNhY2hlZFN0YXRlXG4gIH1cblxuICAvKipcbiAgICogR2V0cyB0aGUgbGFzdCBhcHBsaWVkIHRpbWVzdGFtcC5cbiAgICovXG4gIGdldExhc3RBcHBsaWVkVHMoKTogVHhUaW1lc3RhbXAgfCBudWxsIHtcbiAgICBpZiAodGhpcy5sYXN0QXBwbGllZEluZGV4ID09PSBudWxsIHx8IHRoaXMubGFzdEFwcGxpZWRJbmRleCA8IDApIHtcbiAgICAgIHJldHVybiBudWxsXG4gICAgfVxuICAgIHJldHVybiB0aGlzLnNvcnRlZFR4c1t0aGlzLmxhc3RBcHBsaWVkSW5kZXhdPy50eFRpbWVzdGFtcCA/PyBudWxsXG4gIH1cblxuICAvKipcbiAgICogR2V0cyB0aGUgbGFzdCBhcHBsaWVkIGluZGV4IChmb3IgZGVidWdnaW5nL3RyYWNraW5nKS5cbiAgICovXG4gIGdldExhc3RBcHBsaWVkSW5kZXgoKTogbnVtYmVyIHwgbnVsbCB7XG4gICAgcmV0dXJuIHRoaXMubGFzdEFwcGxpZWRJbmRleFxuICB9XG59XG4iLCJpbXBvcnQgeyBKU09OT2JqZWN0IH0gZnJvbSBcIi4vanNvblwiXG5pbXBvcnQgeyBWYWxpZGF0ZUZuIH0gZnJvbSBcIi4vb3BlcmF0aW9uc1wiXG5pbXBvcnQgeyBTdGF0ZUNhbGN1bGF0b3IgfSBmcm9tIFwiLi9TdGF0ZUNhbGN1bGF0b3JcIlxuXG4vKipcbiAqIENsaWVudC1zaWRlIHN0YXRlIGluY2x1ZGluZyBjbG9ja3MgYW5kIGNhbGN1bGF0b3IgZm9yIHN0YXRlIG1hbmFnZW1lbnRcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDbGllbnRTdGF0ZSB7XG4gIC8vIExhbXBvcnQgY2xvY2tzIChtb25vdG9uaWMsIG5ldmVyIHJlc2V0KVxuICBsb2NhbENsb2NrOiBudW1iZXJcblxuICAvLyBDYWNoZWQgZmluYWxpemVkIGVwb2NoIChudWxsID0gbm90IHlldCBpbml0aWFsaXplZCwgcmVjYWxjdWxhdGVkIG9ubHkgd2hlbiBjaGVja3BvaW50IG1hcCBjaGFuZ2VzKVxuICBjYWNoZWRGaW5hbGl6ZWRFcG9jaDogbnVtYmVyIHwgbnVsbFxuXG4gIC8vIFN0YXRlIGNhbGN1bGF0b3IgKG1hbmFnZXMgc29ydGVkIHR4IGNhY2hlLCBzdGF0ZSBjYWxjdWxhdGlvbiwgYW5kIGludmFsaWRhdGlvbilcbiAgc3RhdGVDYWxjdWxhdG9yOiBTdGF0ZUNhbGN1bGF0b3JcblxuICAvKipcbiAgICogVGltZXN0YW1wIHJldGVudGlvbiB3aW5kb3cgaW4gbWlsbGlzZWNvbmRzLlxuICAgKi9cbiAgcmV0ZW50aW9uV2luZG93TXM6IG51bWJlclxufVxuXG4vKipcbiAqIEZhY3RvcnkgdG8gY3JlYXRlIGFuIGluaXRpYWwgQ2xpZW50U3RhdGVcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUNsaWVudFN0YXRlKFxuICB2YWxpZGF0ZUZuOiBWYWxpZGF0ZUZuPEpTT05PYmplY3Q+IHwgdW5kZWZpbmVkLFxuICByZXRlbnRpb25XaW5kb3dNczogbnVtYmVyXG4pOiBDbGllbnRTdGF0ZSB7XG4gIHJldHVybiB7XG4gICAgbG9jYWxDbG9jazogMCxcbiAgICBjYWNoZWRGaW5hbGl6ZWRFcG9jaDogbnVsbCwgLy8gV2lsbCBiZSByZWNhbGN1bGF0ZWQgb24gZmlyc3QgcnVuXG4gICAgc3RhdGVDYWxjdWxhdG9yOiBuZXcgU3RhdGVDYWxjdWxhdG9yKHZhbGlkYXRlRm4pLFxuICAgIHJldGVudGlvbldpbmRvd01zLFxuICB9XG59XG4iLCJpbXBvcnQgKiBhcyBZIGZyb20gXCJ5anNcIlxuaW1wb3J0IHsgdHlwZSBDaGVja3BvaW50UmVjb3JkLCBwcnVuZUNoZWNrcG9pbnRzIH0gZnJvbSBcIi4vY2hlY2twb2ludHNcIlxuaW1wb3J0IHsgZ2V0RmluYWxpemVkRXBvY2hBbmRDaGVja3BvaW50IH0gZnJvbSBcIi4vY2hlY2twb2ludFV0aWxzXCJcbmltcG9ydCB7IENsaWVudFN0YXRlIH0gZnJvbSBcIi4vY2xpZW50U3RhdGVcIlxuaW1wb3J0IHsgSlNPTk9iamVjdCB9IGZyb20gXCIuL2pzb25cIlxuaW1wb3J0IHsgT3AgfSBmcm9tIFwiLi9vcGVyYXRpb25zXCJcbmltcG9ydCB7IFNvcnRlZFR4RW50cnkgfSBmcm9tIFwiLi9Tb3J0ZWRUeEVudHJ5XCJcbmltcG9ydCB7IGlzVHJhbnNhY3Rpb25JbkNoZWNrcG9pbnQgfSBmcm9tIFwiLi9TdGF0ZUNhbGN1bGF0b3JcIlxuaW1wb3J0IHsgVHhSZWNvcmQgfSBmcm9tIFwiLi9UeFJlY29yZFwiXG5pbXBvcnQgeyB0eXBlIFR4VGltZXN0YW1wLCB0eXBlIFR4VGltZXN0YW1wS2V5LCB0eFRpbWVzdGFtcFRvS2V5IH0gZnJvbSBcIi4vdHhUaW1lc3RhbXBcIlxuXG4vKipcbiAqIENoYW5nZXMgdG8gdHJhbnNhY3Rpb24ga2V5cyBmcm9tIGEgWS5ZTWFwRXZlbnQuXG4gKiAtIGFkZGVkOiBrZXlzIHRoYXQgd2VyZSBhZGRlZFxuICogLSBkZWxldGVkOiBrZXlzIHRoYXQgd2VyZSBkZWxldGVkXG4gKi9cbmV4cG9ydCB0eXBlIFR4S2V5Q2hhbmdlcyA9IHtcbiAgYWRkZWQ6IHJlYWRvbmx5IFR4VGltZXN0YW1wS2V5W11cbiAgZGVsZXRlZDogcmVhZG9ubHkgVHhUaW1lc3RhbXBLZXlbXVxufVxuXG4vKipcbiAqIEFwcGVuZHMgYSBuZXcgdHJhbnNhY3Rpb24gdG8gdGhlIGxvZy5cbiAqXG4gKiBAcGFyYW0gb3JpZ2luYWxLZXkgLSBPcHRpb25hbCByZWZlcmVuY2UgdG8gdGhlIG9yaWdpbmFsIHRyYW5zYWN0aW9uIGtleSBmb3IgcmUtZW1pdHMuXG4gKiAgICAgICAgICAgICAgICAgICAgICBVc2VkIGJ5IHN5bmNMb2cgdG8gcHJlc2VydmUgdHJhbnNhY3Rpb25zIG1pc3NlZCBieSBjaGVja3BvaW50cy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGFwcGVuZFR4KFxuICBvcHM6IHJlYWRvbmx5IE9wW10sXG4gIHlUeDogWS5NYXA8VHhSZWNvcmQ+LFxuICBhY3RpdmVFcG9jaDogbnVtYmVyLFxuICBteUNsaWVudElkOiBzdHJpbmcsXG4gIGNsaWVudFN0YXRlOiBDbGllbnRTdGF0ZSxcbiAgb3JpZ2luYWxLZXk/OiBUeFRpbWVzdGFtcEtleVxuKTogVHhUaW1lc3RhbXBLZXkge1xuICBjb25zdCBjYWxjID0gY2xpZW50U3RhdGUuc3RhdGVDYWxjdWxhdG9yXG5cbiAgLy8gMS4gQWR2YW5jZSBsb2dpY2FsIGNsb2NrIChMYW1wb3J0KSBiYXNlZCBvbiBhbGwgc2VlbiB0cmFmZmljXG4gIGNvbnN0IGNsb2NrID0gTWF0aC5tYXgoY2xpZW50U3RhdGUubG9jYWxDbG9jaywgY2FsYy5nZXRNYXhTZWVuQ2xvY2soKSkgKyAxXG4gIGNsaWVudFN0YXRlLmxvY2FsQ2xvY2sgPSBjbG9ja1xuXG4gIC8vIDIuIEdlbmVyYXRlIEtleSB3aXRoIFdhbGxDbG9jayBmb3IgZnV0dXJlIHBydW5pbmcgc2FmZXR5XG4gIGNvbnN0IHRzOiBUeFRpbWVzdGFtcCA9IHtcbiAgICBlcG9jaDogYWN0aXZlRXBvY2gsXG4gICAgY2xvY2ssXG4gICAgY2xpZW50SWQ6IG15Q2xpZW50SWQsXG4gICAgd2FsbENsb2NrOiBEYXRlLm5vdygpLFxuICB9XG4gIGNvbnN0IGtleSA9IHR4VGltZXN0YW1wVG9LZXkodHMpXG5cbiAgLy8gMy4gV3JpdGUgdG8gWWpzIChBdG9taWMpXG4gIGNvbnN0IHJlY29yZDogVHhSZWNvcmQgPSB7IG9wcywgb3JpZ2luYWxUeEtleTogb3JpZ2luYWxLZXkgfVxuICB5VHguc2V0KGtleSwgcmVjb3JkKVxuXG4gIHJldHVybiBrZXlcbn1cblxuLyoqXG4gKiBTeW5jaHJvbml6ZXMgdGhlIHRyYW5zYWN0aW9uIGxvZyB3aXRoIHRoZSBjdXJyZW50IGNoZWNrcG9pbnQuXG4gKiBSZS1lbWl0cyBtaXNzZWQgdHJhbnNhY3Rpb25zIGFuZCBwcnVuZXMgb2xkIG9uZXMuXG4gKlxuICogU2hvdWxkIGJlIGNhbGxlZCBCRUZPUkUgdXBkYXRlU3RhdGUgdG8gZW5zdXJlIGxvZyBpcyBjbGVhbiBhbmQgY29tcGxldGUuXG4gKlxuICogQHJldHVybnMgdHJ1ZSBpZiBhbnkgdHJhbnNhY3Rpb25zIHdlcmUgcmUtZW1pdHRlZCBvciBkZWxldGVkLCB3aGljaCBtYXkgaW52YWxpZGF0ZSBsYXN0QXBwbGllZEluZGV4XG4gKi9cbmZ1bmN0aW9uIHN5bmNMb2coXG4gIHlUeDogWS5NYXA8VHhSZWNvcmQ+LFxuICBteUNsaWVudElkOiBzdHJpbmcsXG4gIGNsaWVudFN0YXRlOiBDbGllbnRTdGF0ZSxcbiAgZmluYWxpemVkRXBvY2g6IG51bWJlcixcbiAgYmFzZUNQOiBDaGVja3BvaW50UmVjb3JkIHwgbnVsbCxcbiAgbmV3S2V5cz86IHJlYWRvbmx5IFR4VGltZXN0YW1wS2V5W10gLy8ga2V5cyBhZGRlZCBpbiB0aGlzIHVwZGF0ZVxuKTogdm9pZCB7XG4gIGNvbnN0IGNhbGMgPSBjbGllbnRTdGF0ZS5zdGF0ZUNhbGN1bGF0b3JcbiAgY29uc3QgYWN0aXZlRXBvY2ggPSBmaW5hbGl6ZWRFcG9jaCArIDFcbiAgY29uc3Qgd2F0ZXJtYXJrcyA9IGJhc2VDUD8ud2F0ZXJtYXJrcyA/PyB7fVxuXG4gIC8vIERldGVybWluaXN0aWMgUmVmZXJlbmNlIFRpbWU6IFVzZSBzdG9yZWQgbWluV2FsbENsb2NrIGlmIGF2YWlsYWJsZSwgb3RoZXJ3aXNlIDAgKG5vdGhpbmcgYW5jaWVudCkuXG4gIGNvbnN0IHJlZmVyZW5jZVRpbWUgPSBiYXNlQ1A/Lm1pbldhbGxDbG9jayA/PyAwXG5cbiAgLy8gSGVscGVyIHRvIGNoZWNrIGlmIGEgdHJhbnNhY3Rpb24gc2hvdWxkIGJlIHBydW5lZFxuICBjb25zdCBzaG91bGRQcnVuZSA9ICh0czogVHhUaW1lc3RhbXAsIGRlZHVwVHM6IFR4VGltZXN0YW1wKTogYm9vbGVhbiA9PiB7XG4gICAgY29uc3QgaXNBbmNpZW50ID0gcmVmZXJlbmNlVGltZSAtIHRzLndhbGxDbG9jayA+IGNsaWVudFN0YXRlLnJldGVudGlvbldpbmRvd01zXG4gICAgaWYgKGlzQW5jaWVudCkgcmV0dXJuIHRydWVcbiAgICByZXR1cm4gaXNUcmFuc2FjdGlvbkluQ2hlY2twb2ludChkZWR1cFRzLCB3YXRlcm1hcmtzKVxuICB9XG5cbiAgY29uc3QgdG9EZWxldGU6IFR4VGltZXN0YW1wS2V5W10gPSBbXVxuICBjb25zdCB0b1JlRW1pdDogQXJyYXk8eyBvcmlnaW5hbEtleTogVHhUaW1lc3RhbXBLZXk7IHR4OiBUeFJlY29yZCB9PiA9IFtdXG5cbiAgLy8gMS4gSGVscGVyIHRvIGRlY2lkZSB3aGF0IHRvIGRvIHdpdGggZWFjaCB0cmFuc2FjdGlvblxuICBjb25zdCBwcm9jZXNzRW50cnkgPSAoZW50cnk6IFNvcnRlZFR4RW50cnkpOiBib29sZWFuID0+IHtcbiAgICBpZiAoc2hvdWxkUHJ1bmUoZW50cnkudHhUaW1lc3RhbXAsIGVudHJ5LmRlZHVwVHhUaW1lc3RhbXApKSB7XG4gICAgICB0b0RlbGV0ZS5wdXNoKGVudHJ5LnR4VGltZXN0YW1wS2V5KVxuICAgICAgcmV0dXJuIGZhbHNlIC8vIGRlbGV0ZWRcbiAgICB9XG5cbiAgICBpZiAoZW50cnkudHhUaW1lc3RhbXAuZXBvY2ggPD0gZmluYWxpemVkRXBvY2gpIHtcbiAgICAgIC8vIE5vdCBpbiBjaGVja3BvaW50IGFuZCBzdGlsbCBmcmVzaCAtIHJlLWVtaXQgaXQgdG8gdGhlIGFjdGl2ZSBlcG9jaFxuICAgICAgdG9SZUVtaXQucHVzaCh7IG9yaWdpbmFsS2V5OiBlbnRyeS5kZWR1cFR4VGltZXN0YW1wS2V5LCB0eDogZW50cnkudHhSZWNvcmQgfSlcbiAgICAgIHRvRGVsZXRlLnB1c2goZW50cnkudHhUaW1lc3RhbXBLZXkpXG4gICAgICByZXR1cm4gZmFsc2UgLy8gcmUtZW1pdHRlZFxuICAgIH1cblxuICAgIHJldHVybiB0cnVlIC8vIGFjdGl2ZS9mcmVzaFxuICB9XG5cbiAgLy8gMi4gU2NhbiBsb2NhbCBjYWNoZSAoc29ydGVkVHhzKSB0byBpZGVudGlmeSBtaXNzaW5nL2FuY2llbnQgdHJhbnNhY3Rpb25zXG4gIGZvciAoY29uc3QgZW50cnkgb2YgY2FsYy5nZXRTb3J0ZWRUeHMoKSkge1xuICAgIGlmIChwcm9jZXNzRW50cnkoZW50cnkpKSB7XG4gICAgICAvLyBPcHRpbWl6YXRpb246IFBoeXNpY2FsIGtleXMgYXJlIHNvcnRlZC4gSWYgd2UgaGl0IHRoZSBhY3RpdmUvZnJlc2ggdGVycml0b3J5LCB3ZSBjYW4gc3RvcC5cbiAgICAgIGJyZWFrXG4gICAgfVxuICB9XG5cbiAgY29uc3QgcHJvY2Vzc0tleUJ5VGltZXN0YW1wS2V5ID0gKHR4VGltZXN0YW1wS2V5OiBUeFRpbWVzdGFtcEtleSk6IHZvaWQgPT4ge1xuICAgIC8vIE9ubHkgcHJvY2VzcyBpZiBpdCBhY3R1YWxseSBleGlzdHMgaW4gWWpzIE1hcFxuICAgIGlmICh5VHguaGFzKHR4VGltZXN0YW1wS2V5KSkge1xuICAgICAgcHJvY2Vzc0VudHJ5KG5ldyBTb3J0ZWRUeEVudHJ5KHR4VGltZXN0YW1wS2V5LCB5VHgpKVxuICAgIH1cbiAgfVxuXG4gIC8vIDMuIFNjYW4gTkVXIGtleXMgZnJvbSBZanMgdG8gaGFuZGxlIGluY29taW5nIHRyYW5zYWN0aW9ucyAoc3luYylcbiAgLy8gQW55IGNsaWVudCBjYW4gcmUtZW1pdCAtIGRlZHVwbGljYXRpb24gdmlhIG9yaWdpbmFsVHhLZXkgaGFuZGxlcyBkdXBsaWNhdGVzLlxuICBpZiAobmV3S2V5cykge1xuICAgIGZvciAoY29uc3Qga2V5IG9mIG5ld0tleXMpIHtcbiAgICAgIHByb2Nlc3NLZXlCeVRpbWVzdGFtcEtleShrZXkpXG4gICAgfVxuICB9XG5cbiAgLy8gNC4gUmUtZW1pdCBtaXNzZWQgdHJhbnNhY3Rpb25zIEJFRk9SRSBwcnVuaW5nXG4gIGZvciAoY29uc3QgeyBvcmlnaW5hbEtleSwgdHggfSBvZiB0b1JlRW1pdCkge1xuICAgIGNvbnN0IG5ld0tleSA9IGFwcGVuZFR4KHR4Lm9wcywgeVR4LCBhY3RpdmVFcG9jaCwgbXlDbGllbnRJZCwgY2xpZW50U3RhdGUsIG9yaWdpbmFsS2V5KVxuICAgIGNhbGMuaW5zZXJ0VHgobmV3S2V5LCB5VHgpXG4gIH1cblxuICAvLyA1LiBQcnVuZSBvbGQvZmluYWxpemVkL3JlZHVuZGFudCB0cmFuc2FjdGlvbnMgZnJvbSBZanMgTWFwXG4gIGZvciAoY29uc3Qga2V5IG9mIHRvRGVsZXRlKSB7XG4gICAgeVR4LmRlbGV0ZShrZXkpXG4gIH1cbiAgY2FsYy5yZW1vdmVUeHModG9EZWxldGUpXG59XG5cbi8qKlxuICogVGhlIHByaW1hcnkgdXBkYXRlIGZ1bmN0aW9uIHRoYXQgbWFpbnRhaW5zIGN1cnJlbnQgc3RhdGUuXG4gKlxuICogQHBhcmFtIHR4Q2hhbmdlcyAtIENoYW5nZXMgZnJvbSBZLllNYXBFdmVudC4gSWYgdW5kZWZpbmVkIChmaXJzdCBydW4pLCBwZXJmb3JtcyBhIGZ1bGwgc2Nhbi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHVwZGF0ZVN0YXRlKFxuICBkb2M6IFkuRG9jLFxuICB5VHg6IFkuTWFwPFR4UmVjb3JkPixcbiAgeUNoZWNrcG9pbnQ6IFkuTWFwPENoZWNrcG9pbnRSZWNvcmQ+LFxuICBteUNsaWVudElkOiBzdHJpbmcsXG4gIGNsaWVudFN0YXRlOiBDbGllbnRTdGF0ZSxcbiAgdHhDaGFuZ2VzOiBUeEtleUNoYW5nZXMgfCB1bmRlZmluZWRcbik6IHsgc3RhdGU6IEpTT05PYmplY3Q7IGdldEFwcGxpZWRPcHM6ICgpID0+IHJlYWRvbmx5IE9wW10gfSB7XG4gIGNvbnN0IGNhbGMgPSBjbGllbnRTdGF0ZS5zdGF0ZUNhbGN1bGF0b3JcblxuICAvLyBBbHdheXMgY2FsY3VsYXRlIGZyZXNoIGZpbmFsaXplZCBlcG9jaCBhbmQgY2hlY2twb2ludCB0byBoYW5kbGUgc3luYyByYWNlIGNvbmRpdGlvbnNcbiAgY29uc3QgeyBmaW5hbGl6ZWRFcG9jaCwgY2hlY2twb2ludDogYmFzZUNQIH0gPSBnZXRGaW5hbGl6ZWRFcG9jaEFuZENoZWNrcG9pbnQoeUNoZWNrcG9pbnQpXG5cbiAgLy8gVXBkYXRlIHJlYWQtY2FjaGVcbiAgY2xpZW50U3RhdGUuY2FjaGVkRmluYWxpemVkRXBvY2ggPSBmaW5hbGl6ZWRFcG9jaFxuXG4gIC8vIFNldCBiYXNlIGNoZWNrcG9pbnQgKHRoaXMgaGFuZGxlcyBpbnZhbGlkYXRpb24gaWYgY2hlY2twb2ludCBjaGFuZ2VkKVxuICBjYWxjLnNldEJhc2VDaGVja3BvaW50KGJhc2VDUClcblxuICAvLyBUcmFjayBpZiB3ZSBuZWVkIHRvIHJlYnVpbGQgc29ydGVkIGNhY2hlIChmaXJzdCBydW4gb3IgbWlzc2luZyBkZWx0YSlcbiAgLy8gT3B0aW1pemF0aW9uOiBXZSBkb24ndCBuZWVkIHRvIHJlYnVpbGQganVzdCBiZWNhdXNlIGNoZWNrcG9pbnQgY2hhbmdlZCxcbiAgLy8gYXMgbG9uZyBhcyB3ZSBoYXZlIHR4Q2hhbmdlcyB0byBrZWVwIGNhY2hlIGluIHN5bmMuXG4gIGNvbnN0IG5lZWRzUmVidWlsZFNvcnRlZENhY2hlID0gY2FsYy5nZXRDYWNoZWRTdGF0ZSgpID09PSBudWxsIHx8ICF0eENoYW5nZXNcblxuICAvLyBSZWJ1aWxkIHNvcnRlZCBjYWNoZSBiZWZvcmUgc3luY0xvZyBpZiBuZWVkZWRcbiAgaWYgKG5lZWRzUmVidWlsZFNvcnRlZENhY2hlKSB7XG4gICAgY2FsYy5yZWJ1aWxkRnJvbVlqcyh5VHgpXG4gIH0gZWxzZSB7XG4gICAgLy8gSWYgbm90IHJlYnVpbGRpbmcsIGltbWVkaWF0ZWx5IHByb2Nlc3MgZGVsZXRpb25zIHRvIGF2b2lkIFwiZ2hvc3RcIiB0cmFuc2FjdGlvbnNcbiAgICAvLyBpbiBzeW5jTG9nIChlLmcuIGF0dGVtcHRpbmcgdG8gYWNjZXNzIGEgdHJhbnNhY3Rpb24gdGhhdCB3YXMganVzdCBkZWxldGVkKS5cbiAgICBjYWxjLnJlbW92ZVR4cyh0eENoYW5nZXMuZGVsZXRlZClcbiAgfVxuXG4gIC8vIFN5bmMgYW5kIHBydW5lIHdpdGhpbiB0cmFuc2FjdGlvblxuICBkb2MudHJhbnNhY3QoKCkgPT4ge1xuICAgIHN5bmNMb2coeVR4LCBteUNsaWVudElkLCBjbGllbnRTdGF0ZSwgZmluYWxpemVkRXBvY2gsIGJhc2VDUCwgdHhDaGFuZ2VzPy5hZGRlZClcblxuICAgIC8vIFNhZmUgdG8gdXNlIGxvY2FsIGZpbmFsaXplZEVwb2NoIGhlcmVcbiAgICBwcnVuZUNoZWNrcG9pbnRzKHlDaGVja3BvaW50LCBmaW5hbGl6ZWRFcG9jaClcbiAgfSlcblxuICBpZiAobmVlZHNSZWJ1aWxkU29ydGVkQ2FjaGUpIHtcbiAgICAvLyBGdWxsIHJlY29tcHV0ZSAoY2FsY3VsYXRvciBoYW5kbGVzIHRoaXMpXG4gICAgcmV0dXJuIGNhbGMuY2FsY3VsYXRlU3RhdGUoKVxuICB9XG5cbiAgLy8gSW5jcmVtZW50YWwgdXBkYXRlIHVzaW5nIG9ubHkgY2hhbmdlZCBrZXlzIChjYWxjdWxhdG9yIGhhbmRsZXMgdGhpcylcbiAgLy8gdHhDaGFuZ2VzIGlzIGd1YXJhbnRlZWQgdG8gZXhpc3QgaGVyZSBzaW5jZSAhdHhDaGFuZ2VzIGltcGxpZXMgbmVlZHNSZWJ1aWxkU29ydGVkQ2FjaGVcblxuICAvLyBVcGRhdGUgc29ydGVkIGNhY2hlIHdpdGggbmV3IGtleXMgZnJvbSB0eENoYW5nZXNcbiAgLy8gVGhpcyBtdXN0IGhhcHBlbiBhZnRlciBzeW5jTG9nIHdoaWNoIG1heSBoYXZlIGRlbGV0ZWQgc29tZSBvZiB0aGVzZSBrZXlzXG4gIGZvciAoY29uc3Qga2V5IG9mIHR4Q2hhbmdlcy5hZGRlZCkge1xuICAgIC8vIENSSVRJQ0FMOiBDaGVjayB5VHguaGFzKGtleSkhIHN5bmNMb2cgbWlnaHQgaGF2ZSBqdXN0IHBydW5lZCBpdC5cbiAgICBpZiAoeVR4LmhhcyhrZXkpICYmICFjYWxjLmhhc1R4KGtleSkpIHtcbiAgICAgIGNhbGMuaW5zZXJ0VHgoa2V5LCB5VHgpXG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIGNhbGMuY2FsY3VsYXRlU3RhdGUoKVxufVxuIiwiaW1wb3J0ICogYXMgWSBmcm9tIFwieWpzXCJcbmltcG9ydCB7IENoZWNrcG9pbnRSZWNvcmQsIGNyZWF0ZUNoZWNrcG9pbnQgfSBmcm9tIFwiLi9jaGVja3BvaW50c1wiXG5pbXBvcnQgeyBjcmVhdGVDbGllbnRTdGF0ZSB9IGZyb20gXCIuL2NsaWVudFN0YXRlXCJcbmltcG9ydCB7IGZhaWx1cmUgfSBmcm9tIFwiLi9lcnJvclwiXG5pbXBvcnQgeyBKU09OT2JqZWN0IH0gZnJvbSBcIi4vanNvblwiXG5cbmltcG9ydCB7IE9wLCBWYWxpZGF0ZUZuIH0gZnJvbSBcIi4vb3BlcmF0aW9uc1wiXG5cbmltcG9ydCB7IGNvbXB1dGVSZWNvbmNpbGVPcHMgfSBmcm9tIFwiLi9yZWNvbmNpbGVcIlxuaW1wb3J0IHsgU29ydGVkVHhFbnRyeSB9IGZyb20gXCIuL1NvcnRlZFR4RW50cnlcIlxuaW1wb3J0IHsgVHhSZWNvcmQgfSBmcm9tIFwiLi9UeFJlY29yZFwiXG5pbXBvcnQgeyBhcHBlbmRUeCwgVHhLZXlDaGFuZ2VzLCB1cGRhdGVTdGF0ZSB9IGZyb20gXCIuL3R4TG9nXCJcbmltcG9ydCB7IFR4VGltZXN0YW1wS2V5IH0gZnJvbSBcIi4vdHhUaW1lc3RhbXBcIlxuaW1wb3J0IHsgZ2VuZXJhdGVJRCB9IGZyb20gXCIuL3V0aWxzXCJcblxuZXhwb3J0IGNvbnN0IGdldFNvcnRlZFR4c1N5bWJvbCA9IFN5bWJvbChcImdldFNvcnRlZFR4c1wiKVxuXG5leHBvcnQgaW50ZXJmYWNlIFN0YXRlU3luY0xvZ09wdGlvbnM8U3RhdGUgZXh0ZW5kcyBKU09OT2JqZWN0PiB7XG4gIC8qKlxuICAgKiBUaGUgWS5qcyBEb2N1bWVudCB0byBiaW5kIHRvLlxuICAgKi9cbiAgeURvYzogWS5Eb2NcblxuICAvKipcbiAgICogTmFtZSBmb3IgdGhlIHR4cyBZLk1hcC5cbiAgICogRGVmYXVsdDogXCJzdGF0ZS1zeW5jLWxvZy10eFwiXG4gICAqL1xuICB5VHhNYXBOYW1lPzogc3RyaW5nXG5cbiAgLyoqXG4gICAqIE5hbWUgZm9yIHRoZSBjaGVja3BvaW50IFkuTWFwLlxuICAgKiBEZWZhdWx0OiBcInN0YXRlLXN5bmMtbG9nLWNoZWNrcG9pbnRcIlxuICAgKi9cbiAgeUNoZWNrcG9pbnRNYXBOYW1lPzogc3RyaW5nXG5cbiAgLyoqXG4gICAqIFVuaXF1ZSBpZGVudGlmaWVyIGZvciB0aGlzIGNsaWVudC5cbiAgICogSWYgb21pdHRlZCwgYSByYW5kb20gVVVJRCAobmFub2lkKSB3aWxsIGJlIGdlbmVyYXRlZC5cbiAgICogTk9URTogSWYgeW91IG5lZWQgdG8gcmVzdW1lIGEgc2Vzc2lvbiAoa2VlcCBsb2NhbCBjbG9jay93YXRlcm1hcmspLCB5b3UgTVVTVCBwcm92aWRlIGEgc3RhYmxlIElELlxuICAgKiBNVVNUIE5PVCBjb250YWluIHNlbWljb2xvbnMuXG4gICAqL1xuICBjbGllbnRJZD86IHN0cmluZ1xuXG4gIC8qKlxuICAgKiBPcmlnaW4gdGFnIGZvciBZLmpzIHR4cyBjcmVhdGVkIGJ5IHRoaXMgbGlicmFyeS5cbiAgICovXG4gIHlqc09yaWdpbj86IHVua25vd25cblxuICAvKipcbiAgICogT3B0aW9uYWwgdmFsaWRhdGlvbiBmdW5jdGlvbi5cbiAgICogUnVucyBhZnRlciBlYWNoIHR4J3Mgb3BzIGFyZSBhcHBsaWVkLlxuICAgKiBJZiBpdCByZXR1cm5zIGZhbHNlLCB0aGUgdHggaXMgcmVqZWN0ZWQgKHN0YXRlIHJldmVydHMpLlxuICAgKiBNVVNUIGJlIGRldGVybWluaXN0aWMgYW5kIGNvbnNpc3RlbnQgYWNyb3NzIGFsbCBjbGllbnRzLlxuICAgKi9cbiAgdmFsaWRhdGU/OiAoc3RhdGU6IFN0YXRlKSA9PiBib29sZWFuXG5cbiAgLyoqXG4gICAqIFRpbWVzdGFtcCByZXRlbnRpb24gd2luZG93IGluIG1pbGxpc2Vjb25kcy5cbiAgICogVHhzIG9sZGVyIHRoYW4gdGhpcyB3aW5kb3cgYXJlIGNvbnNpZGVyZWQgXCJBbmNpZW50XCIgYW5kIHBydW5lZC5cbiAgICpcbiAgICogRGVmYXVsdDogSW5maW5pdHkgKE5vIHBydW5pbmcpLlxuICAgKiBSZWNvbW1lbmRlZDogMTQgZGF5cyAoMTIwOTYwMDAwMCBtcykuXG4gICAqL1xuICByZXRlbnRpb25XaW5kb3dNczogbnVtYmVyIHwgdW5kZWZpbmVkXG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU3RhdGVTeW5jTG9nQ29udHJvbGxlcjxTdGF0ZSBleHRlbmRzIEpTT05PYmplY3Q+IHtcbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIGN1cnJlbnQgc3RhdGUuXG4gICAqL1xuICBnZXRTdGF0ZSgpOiBTdGF0ZVxuXG4gIC8qKlxuICAgKiBTdWJzY3JpYmVzIHRvIHN0YXRlIGNoYW5nZXMuXG4gICAqL1xuICBzdWJzY3JpYmUoY2FsbGJhY2s6IChuZXdTdGF0ZTogU3RhdGUsIGdldEFwcGxpZWRPcHM6ICgpID0+IHJlYWRvbmx5IE9wW10pID0+IHZvaWQpOiAoKSA9PiB2b2lkXG5cbiAgLyoqXG4gICAqIEVtaXRzIGEgbmV3IHR4IChsaXN0IG9mIG9wZXJhdGlvbnMpIHRvIHRoZSBsb2cuXG4gICAqL1xuICBlbWl0KG9wczogT3BbXSk6IHZvaWRcblxuICAvKipcbiAgICogUmVjb25jaWxlcyB0aGUgY3VycmVudCBzdGF0ZSB3aXRoIHRoZSB0YXJnZXQgc3RhdGUuXG4gICAqL1xuICByZWNvbmNpbGVTdGF0ZSh0YXJnZXRTdGF0ZTogU3RhdGUpOiB2b2lkXG5cbiAgLyoqXG4gICAqIE1hbnVhbGx5IHRyaWdnZXJzIGVwb2NoIGNvbXBhY3Rpb24gKENoZWNrcG9pbnRpbmcpLlxuICAgKi9cbiAgY29tcGFjdCgpOiB2b2lkXG5cbiAgLyoqXG4gICAqIENsZWFucyB1cCBvYnNlcnZlcnMgYW5kIHJlbGVhc2VzIG1lbW9yeS5cbiAgICovXG4gIGRpc3Bvc2UoKTogdm9pZFxuXG4gIC8vIC0tLSBPYnNlcnZhYmlsaXR5ICYgU3RhdHMgLS0tXG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIGN1cnJlbnQgYWN0aXZlIGVwb2NoIG51bWJlci5cbiAgICovXG4gIGdldEFjdGl2ZUVwb2NoKCk6IG51bWJlclxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBudW1iZXIgb2YgdHhzIGN1cnJlbnRseSBpbiB0aGUgYWN0aXZlIGVwb2NoLlxuICAgKi9cbiAgZ2V0QWN0aXZlRXBvY2hUeENvdW50KCk6IG51bWJlclxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSB3YWxsQ2xvY2sgdGltZXN0YW1wIG9mIHRoZSBmaXJzdCB0eCBpbiB0aGUgYWN0aXZlIGVwb2NoLlxuICAgKi9cbiAgZ2V0QWN0aXZlRXBvY2hTdGFydFRpbWUoKTogbnVtYmVyIHwgdW5kZWZpbmVkXG5cbiAgLyoqXG4gICAqIFJldHVybnMgdHJ1ZSBpZiB0aGUgbG9nIGlzIGNvbXBsZXRlbHkgZW1wdHkuXG4gICAqL1xuICBpc0xvZ0VtcHR5KCk6IGJvb2xlYW5cblxuICAvKipcbiAgICogSW50ZXJuYWwvVGVzdGluZzogUmV0dXJucyBhbGwgdHhzIGN1cnJlbnRseSBpbiB0aGUgbG9nLCBzb3J0ZWQuXG4gICAqL1xuICBbZ2V0U29ydGVkVHhzU3ltYm9sXSgpOiByZWFkb25seSBTb3J0ZWRUeEVudHJ5W11cbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgU3RhdGVTeW5jTG9nIGNvbnRyb2xsZXIuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVTdGF0ZVN5bmNMb2c8U3RhdGUgZXh0ZW5kcyBKU09OT2JqZWN0PihcbiAgb3B0aW9uczogU3RhdGVTeW5jTG9nT3B0aW9uczxTdGF0ZT5cbik6IFN0YXRlU3luY0xvZ0NvbnRyb2xsZXI8U3RhdGU+IHtcbiAgY29uc3Qge1xuICAgIHlEb2MsXG4gICAgeVR4TWFwTmFtZSA9IFwic3RhdGUtc3luYy1sb2ctdHhcIixcbiAgICB5Q2hlY2twb2ludE1hcE5hbWUgPSBcInN0YXRlLXN5bmMtbG9nLWNoZWNrcG9pbnRcIixcbiAgICBjbGllbnRJZCA9IGdlbmVyYXRlSUQoKSxcbiAgICB5anNPcmlnaW4sXG4gICAgdmFsaWRhdGUsXG4gICAgcmV0ZW50aW9uV2luZG93TXMsXG4gIH0gPSBvcHRpb25zXG5cbiAgaWYgKGNsaWVudElkLmluY2x1ZGVzKFwiO1wiKSkge1xuICAgIGZhaWx1cmUoYGNsaWVudElkIE1VU1QgTk9UIGNvbnRhaW4gc2VtaWNvbG9uczogJHtjbGllbnRJZH1gKVxuICB9XG5cbiAgY29uc3QgeVR4ID0geURvYy5nZXRNYXA8VHhSZWNvcmQ+KHlUeE1hcE5hbWUpXG4gIGNvbnN0IHlDaGVja3BvaW50ID0geURvYy5nZXRNYXA8Q2hlY2twb2ludFJlY29yZD4oeUNoZWNrcG9pbnRNYXBOYW1lKVxuXG4gIC8vIENhc3QgdmFsaWRhdGUgdG8gYmFzaWMgdHlwZSB0byBtYXRjaCBpbnRlcm5hbCBDbGllbnRTdGF0ZVxuICBjb25zdCBjbGllbnRTdGF0ZSA9IGNyZWF0ZUNsaWVudFN0YXRlKFxuICAgIHZhbGlkYXRlIGFzIHVua25vd24gYXMgVmFsaWRhdGVGbjxKU09OT2JqZWN0PixcbiAgICByZXRlbnRpb25XaW5kb3dNcyA/PyBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFlcbiAgKVxuXG4gIC8vIExpc3RlbmVyc1xuICBjb25zdCBzdWJzY3JpYmVycyA9IG5ldyBTZXQ8KHN0YXRlOiBTdGF0ZSwgZ2V0QXBwbGllZE9wczogKCkgPT4gcmVhZG9ubHkgT3BbXSkgPT4gdm9pZD4oKVxuXG4gIGNvbnN0IG5vdGlmeVN1YnNjcmliZXJzID0gKHN0YXRlOiBTdGF0ZSwgZ2V0QXBwbGllZE9wczogKCkgPT4gcmVhZG9ubHkgT3BbXSkgPT4ge1xuICAgIGZvciAoY29uc3Qgc3ViIG9mIHN1YnNjcmliZXJzKSB7XG4gICAgICBzdWIoc3RhdGUsIGdldEFwcGxpZWRPcHMpXG4gICAgfVxuICB9XG5cbiAgLy8gSGVscGVyIHRvIGV4dHJhY3Qga2V5IGNoYW5nZXMgZnJvbSBZTWFwRXZlbnRcbiAgY29uc3QgZXh0cmFjdFR4Q2hhbmdlcyA9IChldmVudDogWS5ZTWFwRXZlbnQ8VHhSZWNvcmQ+KTogVHhLZXlDaGFuZ2VzID0+IHtcbiAgICBjb25zdCBhZGRlZDogVHhUaW1lc3RhbXBLZXlbXSA9IFtdXG4gICAgY29uc3QgZGVsZXRlZDogVHhUaW1lc3RhbXBLZXlbXSA9IFtdXG5cbiAgICBmb3IgKGNvbnN0IFtrZXksIGNoYW5nZV0gb2YgZXZlbnQuY2hhbmdlcy5rZXlzKSB7XG4gICAgICBpZiAoY2hhbmdlLmFjdGlvbiA9PT0gXCJhZGRcIikge1xuICAgICAgICBhZGRlZC5wdXNoKGtleSlcbiAgICAgIH0gZWxzZSBpZiAoY2hhbmdlLmFjdGlvbiA9PT0gXCJkZWxldGVcIikge1xuICAgICAgICBkZWxldGVkLnB1c2goa2V5KVxuICAgICAgfSBlbHNlIGlmIChjaGFuZ2UuYWN0aW9uID09PSBcInVwZGF0ZVwiKSB7XG4gICAgICAgIGRlbGV0ZWQucHVzaChrZXkpXG4gICAgICAgIGFkZGVkLnB1c2goa2V5KVxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB7IGFkZGVkLCBkZWxldGVkIH1cbiAgfVxuXG4gIC8vIEVtcHR5IHR4Q2hhbmdlcyBvYmplY3QgZm9yIGNoZWNrcG9pbnQgb2JzZXJ2ZXIgKG5vIHR4IGtleXMgY2hhbmdlZClcbiAgY29uc3QgZW1wdHlUeENoYW5nZXM6IFR4S2V5Q2hhbmdlcyA9IHsgYWRkZWQ6IFtdLCBkZWxldGVkOiBbXSB9XG5cbiAgLy8gVXBkYXRlIExvZ2ljIHdpdGggaW5jcmVtZW50YWwgY2hhbmdlc1xuICBjb25zdCBydW5VcGRhdGUgPSAodHhDaGFuZ2VzOiBUeEtleUNoYW5nZXMgfCB1bmRlZmluZWQpID0+IHtcbiAgICBjb25zdCB7IHN0YXRlLCBnZXRBcHBsaWVkT3BzIH0gPSB1cGRhdGVTdGF0ZShcbiAgICAgIHlEb2MsXG4gICAgICB5VHgsXG4gICAgICB5Q2hlY2twb2ludCxcbiAgICAgIGNsaWVudElkLFxuICAgICAgY2xpZW50U3RhdGUsXG4gICAgICB0eENoYW5nZXNcbiAgICApXG4gICAgbm90aWZ5U3Vic2NyaWJlcnMoc3RhdGUgYXMgU3RhdGUsIGdldEFwcGxpZWRPcHMpXG4gIH1cblxuICAvLyBUeCBvYnNlcnZlclxuICBjb25zdCB0eE9ic2VydmVyID0gKGV2ZW50OiBZLllNYXBFdmVudDxUeFJlY29yZD4sIF90cmFuc2FjdGlvbjogWS5UcmFuc2FjdGlvbikgPT4ge1xuICAgIGNvbnN0IHR4Q2hhbmdlcyA9IGV4dHJhY3RUeENoYW5nZXMoZXZlbnQpXG4gICAgcnVuVXBkYXRlKHR4Q2hhbmdlcylcbiAgfVxuXG4gIC8vIENoZWNrcG9pbnQgb2JzZXJ2ZXJcbiAgY29uc3QgY2hlY2twb2ludE9ic2VydmVyID0gKFxuICAgIF9ldmVudDogWS5ZTWFwRXZlbnQ8Q2hlY2twb2ludFJlY29yZD4sXG4gICAgX3RyYW5zYWN0aW9uOiBZLlRyYW5zYWN0aW9uXG4gICkgPT4ge1xuICAgIHJ1blVwZGF0ZShlbXB0eVR4Q2hhbmdlcylcbiAgfVxuXG4gIHlDaGVja3BvaW50Lm9ic2VydmUoY2hlY2twb2ludE9ic2VydmVyKVxuICB5VHgub2JzZXJ2ZSh0eE9ic2VydmVyKVxuXG4gIC8vIEluaXRpYWwgcnVuIChmdWxsIHJlY29tcHV0ZSwgdHJlYXQgYXMgY2hlY2twb2ludCBjaGFuZ2UgdG8gaW5pdGlhbGl6ZSBlcG9jaCBjYWNoZSlcbiAgcnVuVXBkYXRlKHVuZGVmaW5lZClcblxuICAvLyBUcmFjayBkaXNwb3NhbCBzdGF0ZVxuICBsZXQgZGlzcG9zZWQgPSBmYWxzZVxuXG4gIGNvbnN0IGFzc2VydE5vdERpc3Bvc2VkID0gKCkgPT4ge1xuICAgIGlmIChkaXNwb3NlZCkge1xuICAgICAgZmFpbHVyZShcIlN0YXRlU3luY0xvZyBoYXMgYmVlbiBkaXNwb3NlZCBhbmQgY2Fubm90IGJlIHVzZWRcIilcbiAgICB9XG4gIH1cblxuICBjb25zdCBnZXRBY3RpdmVFcG9jaEludGVybmFsID0gKCkgPT4ge1xuICAgIGlmIChjbGllbnRTdGF0ZS5jYWNoZWRGaW5hbGl6ZWRFcG9jaCA9PT0gbnVsbCkge1xuICAgICAgZmFpbHVyZShcImNhY2hlZEZpbmFsaXplZEVwb2NoIGlzIG51bGwgLSB0aGlzIHNob3VsZCBub3QgaGFwcGVuIGFmdGVyIGluaXRpYWxpemF0aW9uXCIpXG4gICAgfVxuICAgIHJldHVybiBjbGllbnRTdGF0ZS5jYWNoZWRGaW5hbGl6ZWRFcG9jaCArIDFcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgZ2V0U3RhdGUoKTogU3RhdGUge1xuICAgICAgYXNzZXJ0Tm90RGlzcG9zZWQoKVxuICAgICAgcmV0dXJuIChjbGllbnRTdGF0ZS5zdGF0ZUNhbGN1bGF0b3IuZ2V0Q2FjaGVkU3RhdGUoKSA/PyB7fSkgYXMgU3RhdGVcbiAgICB9LFxuXG4gICAgc3Vic2NyaWJlKGNhbGxiYWNrOiAobmV3U3RhdGU6IFN0YXRlLCBnZXRBcHBsaWVkT3BzOiAoKSA9PiByZWFkb25seSBPcFtdKSA9PiB2b2lkKTogKCkgPT4gdm9pZCB7XG4gICAgICBhc3NlcnROb3REaXNwb3NlZCgpXG4gICAgICBzdWJzY3JpYmVycy5hZGQoY2FsbGJhY2spXG4gICAgICByZXR1cm4gKCkgPT4ge1xuICAgICAgICBzdWJzY3JpYmVycy5kZWxldGUoY2FsbGJhY2spXG4gICAgICB9XG4gICAgfSxcblxuICAgIGVtaXQob3BzOiBPcFtdKTogdm9pZCB7XG4gICAgICBhc3NlcnROb3REaXNwb3NlZCgpXG4gICAgICB5RG9jLnRyYW5zYWN0KCgpID0+IHtcbiAgICAgICAgY29uc3QgYWN0aXZlRXBvY2ggPSBnZXRBY3RpdmVFcG9jaEludGVybmFsKClcbiAgICAgICAgYXBwZW5kVHgob3BzLCB5VHgsIGFjdGl2ZUVwb2NoLCBjbGllbnRJZCwgY2xpZW50U3RhdGUpXG4gICAgICB9LCB5anNPcmlnaW4pXG4gICAgfSxcblxuICAgIHJlY29uY2lsZVN0YXRlKHRhcmdldFN0YXRlOiBTdGF0ZSk6IHZvaWQge1xuICAgICAgYXNzZXJ0Tm90RGlzcG9zZWQoKVxuICAgICAgY29uc3QgY3VycmVudFN0YXRlID0gKGNsaWVudFN0YXRlLnN0YXRlQ2FsY3VsYXRvci5nZXRDYWNoZWRTdGF0ZSgpID8/IHt9KSBhcyBTdGF0ZVxuICAgICAgY29uc3Qgb3BzID0gY29tcHV0ZVJlY29uY2lsZU9wcyhjdXJyZW50U3RhdGUsIHRhcmdldFN0YXRlKVxuICAgICAgaWYgKG9wcy5sZW5ndGggPiAwKSB7XG4gICAgICAgIHRoaXMuZW1pdChvcHMpXG4gICAgICB9XG4gICAgfSxcblxuICAgIGNvbXBhY3QoKTogdm9pZCB7XG4gICAgICBhc3NlcnROb3REaXNwb3NlZCgpXG4gICAgICB5RG9jLnRyYW5zYWN0KCgpID0+IHtcbiAgICAgICAgY29uc3QgYWN0aXZlRXBvY2ggPSBnZXRBY3RpdmVFcG9jaEludGVybmFsKClcbiAgICAgICAgY29uc3QgY3VycmVudFN0YXRlID0gY2xpZW50U3RhdGUuc3RhdGVDYWxjdWxhdG9yLmdldENhY2hlZFN0YXRlKCkgPz8ge31cbiAgICAgICAgY3JlYXRlQ2hlY2twb2ludCh5VHgsIHlDaGVja3BvaW50LCBjbGllbnRTdGF0ZSwgYWN0aXZlRXBvY2gsIGN1cnJlbnRTdGF0ZSwgY2xpZW50SWQpXG4gICAgICB9LCB5anNPcmlnaW4pXG4gICAgfSxcblxuICAgIGRpc3Bvc2UoKTogdm9pZCB7XG4gICAgICBpZiAoZGlzcG9zZWQpIHJldHVybiAvLyBBbHJlYWR5IGRpc3Bvc2VkLCBuby1vcFxuICAgICAgZGlzcG9zZWQgPSB0cnVlXG4gICAgICB5VHgudW5vYnNlcnZlKHR4T2JzZXJ2ZXIpXG4gICAgICB5Q2hlY2twb2ludC51bm9ic2VydmUoY2hlY2twb2ludE9ic2VydmVyKVxuICAgICAgc3Vic2NyaWJlcnMuY2xlYXIoKVxuICAgIH0sXG5cbiAgICBnZXRBY3RpdmVFcG9jaCgpOiBudW1iZXIge1xuICAgICAgYXNzZXJ0Tm90RGlzcG9zZWQoKVxuICAgICAgcmV0dXJuIGdldEFjdGl2ZUVwb2NoSW50ZXJuYWwoKVxuICAgIH0sXG5cbiAgICBnZXRBY3RpdmVFcG9jaFR4Q291bnQoKTogbnVtYmVyIHtcbiAgICAgIGFzc2VydE5vdERpc3Bvc2VkKClcbiAgICAgIGNvbnN0IGFjdGl2ZUVwb2NoID0gZ2V0QWN0aXZlRXBvY2hJbnRlcm5hbCgpXG4gICAgICBsZXQgY291bnQgPSAwXG4gICAgICAvLyBPbmx5IGN1cnJlbnQgb3IgZnV0dXJlIGVwb2NocyBleGlzdCBpbiBzb3J0ZWRUeHMgKHBhc3QgZXBvY2hzIGFyZSBwcnVuZWQgZHVyaW5nIHVwZGF0ZVN0YXRlKS5cbiAgICAgIC8vIEZ1dHVyZSBlcG9jaHMgYXBwZWFyIGlmIHdlIHJlY2VpdmUgdHhzIGJlZm9yZSB0aGUgY29ycmVzcG9uZGluZyBjaGVja3BvaW50LlxuICAgICAgZm9yIChjb25zdCBlbnRyeSBvZiBjbGllbnRTdGF0ZS5zdGF0ZUNhbGN1bGF0b3IuZ2V0U29ydGVkVHhzKCkpIHtcbiAgICAgICAgY29uc3QgdHMgPSBlbnRyeS50eFRpbWVzdGFtcFxuICAgICAgICBpZiAodHMuZXBvY2ggPT09IGFjdGl2ZUVwb2NoKSB7XG4gICAgICAgICAgY291bnQrK1xuICAgICAgICB9IGVsc2UgaWYgKHRzLmVwb2NoID4gYWN0aXZlRXBvY2gpIHtcbiAgICAgICAgICBicmVhayAvLyBPcHRpbWl6YXRpb246IHNvcnRlZCBvcmRlciBtZWFucyB3ZSBjYW4gc3RvcCBlYXJseVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gY291bnRcbiAgICB9LFxuXG4gICAgZ2V0QWN0aXZlRXBvY2hTdGFydFRpbWUoKTogbnVtYmVyIHwgdW5kZWZpbmVkIHtcbiAgICAgIGFzc2VydE5vdERpc3Bvc2VkKClcbiAgICAgIGNvbnN0IGFjdGl2ZUVwb2NoID0gZ2V0QWN0aXZlRXBvY2hJbnRlcm5hbCgpXG4gICAgICAvLyBPbmx5IGN1cnJlbnQgb3IgZnV0dXJlIGVwb2NocyBleGlzdCBpbiBzb3J0ZWRUeHMgKHBhc3QgZXBvY2hzIGFyZSBwcnVuZWQgZHVyaW5nIHVwZGF0ZVN0YXRlKS5cbiAgICAgIGZvciAoY29uc3QgZW50cnkgb2YgY2xpZW50U3RhdGUuc3RhdGVDYWxjdWxhdG9yLmdldFNvcnRlZFR4cygpKSB7XG4gICAgICAgIGNvbnN0IHRzID0gZW50cnkudHhUaW1lc3RhbXBcbiAgICAgICAgaWYgKHRzLmVwb2NoID09PSBhY3RpdmVFcG9jaCkge1xuICAgICAgICAgIHJldHVybiB0cy53YWxsQ2xvY2tcbiAgICAgICAgfSBlbHNlIGlmICh0cy5lcG9jaCA+IGFjdGl2ZUVwb2NoKSB7XG4gICAgICAgICAgYnJlYWsgLy8gT3B0aW1pemF0aW9uOiBzb3J0ZWQgb3JkZXIgbWVhbnMgd2UgY2FuIHN0b3AgZWFybHlcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgcmV0dXJuIHVuZGVmaW5lZFxuICAgIH0sXG5cbiAgICBpc0xvZ0VtcHR5KCk6IGJvb2xlYW4ge1xuICAgICAgYXNzZXJ0Tm90RGlzcG9zZWQoKVxuICAgICAgcmV0dXJuIHlUeC5zaXplID09PSAwICYmIHlDaGVja3BvaW50LnNpemUgPT09IDBcbiAgICB9LFxuXG4gICAgW2dldFNvcnRlZFR4c1N5bWJvbF0oKTogcmVhZG9ubHkgU29ydGVkVHhFbnRyeVtdIHtcbiAgICAgIGFzc2VydE5vdERpc3Bvc2VkKClcbiAgICAgIHJldHVybiBjbGllbnRTdGF0ZS5zdGF0ZUNhbGN1bGF0b3IuZ2V0U29ydGVkVHhzKClcbiAgICB9LFxuICB9XG59XG4iLCJpbXBvcnQgeyBmYWlsdXJlIH0gZnJvbSBcIi4vZXJyb3JcIlxyXG5pbXBvcnQgeyBKU09OT2JqZWN0LCBKU09OVmFsdWUsIFBhdGggfSBmcm9tIFwiLi9qc29uXCJcclxuaW1wb3J0IHsgZGVlcENsb25lLCBkZWVwRXF1YWwsIGlzT2JqZWN0IH0gZnJvbSBcIi4vdXRpbHNcIlxyXG5cclxuLyoqXHJcbiAqIFN1cHBvcnRlZCBvcGVyYXRpb25zLlxyXG4gKiBBcHBsaWVkIHNlcXVlbnRpYWxseSB3aXRoaW4gYSB0eC5cclxuICovXHJcbmV4cG9ydCB0eXBlIE9wID1cclxuICB8IHsga2luZDogXCJzZXRcIjsgcGF0aDogUGF0aDsga2V5OiBzdHJpbmc7IHZhbHVlOiBKU09OVmFsdWUgfVxyXG4gIHwgeyBraW5kOiBcImRlbGV0ZVwiOyBwYXRoOiBQYXRoOyBrZXk6IHN0cmluZyB9XHJcbiAgfCB7IGtpbmQ6IFwic3BsaWNlXCI7IHBhdGg6IFBhdGg7IGluZGV4OiBudW1iZXI7IGRlbGV0ZUNvdW50OiBudW1iZXI7IGluc2VydHM6IEpTT05WYWx1ZVtdIH1cclxuICB8IHsga2luZDogXCJhZGRUb1NldFwiOyBwYXRoOiBQYXRoOyB2YWx1ZTogSlNPTlZhbHVlIH1cclxuICB8IHsga2luZDogXCJkZWxldGVGcm9tU2V0XCI7IHBhdGg6IFBhdGg7IHZhbHVlOiBKU09OVmFsdWUgfVxyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRpb24gZnVuY3Rpb24gdHlwZS5cclxuICpcclxuICogUnVsZXM6XHJcbiAqIC0gVmFsaWRhdGlvbiBNVVNUIGRlcGVuZCBvbmx5IG9uIGNhbmRpZGF0ZVN0YXRlIChhbmQgZGV0ZXJtaW5pc3RpYyBjb2RlKS5cclxuICogLSBWYWxpZGF0aW9uIHJ1bnMgb25jZSBwZXIgdHgsIGFmdGVyIGFsbCBvcHMgYXBwbHkuXHJcbiAqIC0gSWYgdmFsaWRhdGlvbiBmYWlscywgdGhlIHggaXMgcmVqZWN0ZWQgKHN0YXRlIHJldmVydHMgdG8gcHJldmlvdXMpLlxyXG4gKiAtIElmIG5vIHZhbGlkYXRvciBpcyBwcm92aWRlZCwgdmFsaWRhdGlvbiBkZWZhdWx0cyB0byB0cnVlLlxyXG4gKlxyXG4gKiBJTVBPUlRBTlQ6IFZhbGlkYXRpb24gb3V0Y29tZSBpcyAqKmRlcml2ZWQgbG9jYWwgc3RhdGUqKiBhbmQgTVVTVCBOT1QgYmUgcmVwbGljYXRlZC5cclxuICogQWxsIGNsaWVudHMgTVVTVCB1c2UgdGhlIHNhbWUgdmFsaWRhdGlvbiBsb2dpYyB0byBlbnN1cmUgY29uc2lzdGVuY3kuXHJcbiAqL1xyXG5leHBvcnQgdHlwZSBWYWxpZGF0ZUZuPFN0YXRlIGV4dGVuZHMgSlNPTk9iamVjdD4gPSAoY2FuZGlkYXRlU3RhdGU6IFN0YXRlKSA9PiBib29sZWFuXHJcblxyXG4vKipcclxuICogUmVzb2x2ZXMgYSBwYXRoIHdpdGhpbiB0aGUgc3RhdGUuXHJcbiAqIFRocm93cyBpZiBhbnkgc2VnbWVudCBpcyBtaXNzaW5nIG9yIGhhcyB3cm9uZyB0eXBlLlxyXG4gKi9cclxuZnVuY3Rpb24gcmVzb2x2ZVBhdGgoc3RhdGU6IEpTT05PYmplY3QsIHBhdGg6IFBhdGgpOiBKU09OVmFsdWUge1xyXG4gIGxldCBjdXJyZW50OiBKU09OVmFsdWUgPSBzdGF0ZVxyXG4gIGZvciAoY29uc3Qgc2VnbWVudCBvZiBwYXRoKSB7XHJcbiAgICBpZiAodHlwZW9mIHNlZ21lbnQgPT09IFwic3RyaW5nXCIpIHtcclxuICAgICAgaWYgKCFpc09iamVjdChjdXJyZW50KSB8fCBBcnJheS5pc0FycmF5KGN1cnJlbnQpKSB7XHJcbiAgICAgICAgZmFpbHVyZShgRXhwZWN0ZWQgb2JqZWN0IGF0IHBhdGggc2VnbWVudCBcIiR7c2VnbWVudH1cImApXHJcbiAgICAgIH1cclxuICAgICAgaWYgKCEoc2VnbWVudCBpbiBjdXJyZW50KSkge1xyXG4gICAgICAgIGZhaWx1cmUoYFByb3BlcnR5IFwiJHtzZWdtZW50fVwiIGRvZXMgbm90IGV4aXN0YClcclxuICAgICAgfVxyXG4gICAgICBjdXJyZW50ID0gY3VycmVudFtzZWdtZW50XVxyXG4gICAgfSBlbHNlIHtcclxuICAgICAgaWYgKCFBcnJheS5pc0FycmF5KGN1cnJlbnQpKSB7XHJcbiAgICAgICAgZmFpbHVyZShgRXhwZWN0ZWQgYXJyYXkgYXQgcGF0aCBzZWdtZW50ICR7c2VnbWVudH1gKVxyXG4gICAgICB9XHJcbiAgICAgIGlmIChzZWdtZW50IDwgMCB8fCBzZWdtZW50ID49IGN1cnJlbnQubGVuZ3RoKSB7XHJcbiAgICAgICAgZmFpbHVyZShgSW5kZXggJHtzZWdtZW50fSBvdXQgb2YgYm91bmRzYClcclxuICAgICAgfVxyXG4gICAgICBjdXJyZW50ID0gY3VycmVudFtzZWdtZW50XVxyXG4gICAgfVxyXG4gIH1cclxuICByZXR1cm4gY3VycmVudFxyXG59XHJcblxyXG4vKipcclxuICogQXBwbGllcyBhIHNpbmdsZSBvcGVyYXRpb24uXHJcbiAqIChSZWZlcmVuY2UgaW1wbGVtZW50YXRpb24gZm9yIHN0YW5kYXJkIEpTT04tcGF0Y2ggYmVoYXZpb3IpXHJcbiAqL1xyXG5mdW5jdGlvbiBhcHBseU9wKHN0YXRlOiBKU09OT2JqZWN0LCBvcDogT3AsIGNsb25lVmFsdWVzOiBib29sZWFuKTogdm9pZCB7XHJcbiAgLy8gU3BlY2lhbCBjYXNlOiBpZiBwYXRoIGlzIGVtcHR5LCB3ZSBjYW4ndCByZXNvbHZlIFwiY29udGFpbmVyXCIuXHJcbiAgLy8gVGhlIGNhbGxlciBtdXN0IGhhbmRsZSByb290LWxldmVsIHJlcGxhY2VtZW50IGlmIG5lY2Vzc2FyeSwgYnV0XHJcbiAgLy8gc3RhbmRhcmQgT3BzIHVzdWFsbHkgYWN0IE9OIGEgY29udGFpbmVyLlxyXG4gIC8vIEV4Y2VwdGlvbjogaWYgd2UgYWN0IG9uIHJvb3QsIGhhbmRsZSBleHBsaWNpdGx5IG9yIGFzc3VtZSBwYXRoIGxlbmd0aCA+IDAuXHJcbiAgLy8gRm9yIHRoaXMgc3BlYywgT3BzIG1vZGlmeSAqZmllbGRzKiBvciAqaW5kaWNlcyouXHJcbiAgLy8gSWYgcGF0aCBpcyBlbXB0eSwgaXQgbWVhbnMgd2UgYXJlIGFjdGluZyBPTiB0aGUgcm9vdCBvYmplY3QgaXRzZWxmP1xyXG4gIC8vIFRoZSBzcGVjJ3MgXCJzZXRcIiBleGFtcGxlOiBjb250YWluZXJbb3Aua2V5XSA9IG9wLnZhbHVlLlxyXG4gIC8vIFRoaXMgaW1wbGllcyB3ZSByZXNvbHZlIHBhdGggdG8gZ2V0IHRoZSBQQVJFTlQgY29udGFpbmVyLlxyXG5cclxuICBjb25zdCBjb250YWluZXIgPSByZXNvbHZlUGF0aChzdGF0ZSwgb3AucGF0aClcclxuXHJcbiAgc3dpdGNoIChvcC5raW5kKSB7XHJcbiAgICBjYXNlIFwic2V0XCI6XHJcbiAgICAgIGlmICghaXNPYmplY3QoY29udGFpbmVyKSB8fCBBcnJheS5pc0FycmF5KGNvbnRhaW5lcikpIHtcclxuICAgICAgICBmYWlsdXJlKFwic2V0IHJlcXVpcmVzIG9iamVjdCBjb250YWluZXJcIilcclxuICAgICAgfVxyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWV4cGxpY2l0LWFueVxyXG4gICAgICA7KGNvbnRhaW5lciBhcyBhbnkpW29wLmtleV0gPSBjbG9uZVZhbHVlcyA/IGRlZXBDbG9uZShvcC52YWx1ZSkgOiBvcC52YWx1ZVxyXG4gICAgICBicmVha1xyXG5cclxuICAgIGNhc2UgXCJkZWxldGVcIjpcclxuICAgICAgaWYgKCFpc09iamVjdChjb250YWluZXIpIHx8IEFycmF5LmlzQXJyYXkoY29udGFpbmVyKSkge1xyXG4gICAgICAgIGZhaWx1cmUoXCJkZWxldGUgcmVxdWlyZXMgb2JqZWN0IGNvbnRhaW5lclwiKVxyXG4gICAgICB9XHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZXhwbGljaXQtYW55XHJcbiAgICAgIGRlbGV0ZSAoY29udGFpbmVyIGFzIGFueSlbb3Aua2V5XVxyXG4gICAgICBicmVha1xyXG5cclxuICAgIGNhc2UgXCJzcGxpY2VcIjoge1xyXG4gICAgICBpZiAoIUFycmF5LmlzQXJyYXkoY29udGFpbmVyKSkge1xyXG4gICAgICAgIGZhaWx1cmUoXCJzcGxpY2UgcmVxdWlyZXMgYXJyYXkgY29udGFpbmVyXCIpXHJcbiAgICAgIH1cclxuICAgICAgY29uc3Qgc2FmZUluZGV4ID0gTWF0aC5taW4ob3AuaW5kZXgsIGNvbnRhaW5lci5sZW5ndGgpXHJcbiAgICAgIGNvbnRhaW5lci5zcGxpY2UoXHJcbiAgICAgICAgc2FmZUluZGV4LFxyXG4gICAgICAgIG9wLmRlbGV0ZUNvdW50LFxyXG4gICAgICAgIC4uLihjbG9uZVZhbHVlcyA/IG9wLmluc2VydHMubWFwKCh2KSA9PiBkZWVwQ2xvbmUodikpIDogb3AuaW5zZXJ0cylcclxuICAgICAgKVxyXG4gICAgICBicmVha1xyXG4gICAgfVxyXG5cclxuICAgIGNhc2UgXCJhZGRUb1NldFwiOlxyXG4gICAgICBpZiAoIUFycmF5LmlzQXJyYXkoY29udGFpbmVyKSkge1xyXG4gICAgICAgIGZhaWx1cmUoXCJhZGRUb1NldCByZXF1aXJlcyBhcnJheSBjb250YWluZXJcIilcclxuICAgICAgfVxyXG4gICAgICBpZiAoIWNvbnRhaW5lci5zb21lKChpdGVtKSA9PiBkZWVwRXF1YWwoaXRlbSwgb3AudmFsdWUpKSkge1xyXG4gICAgICAgIGNvbnRhaW5lci5wdXNoKGNsb25lVmFsdWVzID8gZGVlcENsb25lKG9wLnZhbHVlKSA6IG9wLnZhbHVlKVxyXG4gICAgICB9XHJcbiAgICAgIGJyZWFrXHJcblxyXG4gICAgY2FzZSBcImRlbGV0ZUZyb21TZXRcIjpcclxuICAgICAgaWYgKCFBcnJheS5pc0FycmF5KGNvbnRhaW5lcikpIHtcclxuICAgICAgICBmYWlsdXJlKFwiZGVsZXRlRnJvbVNldCByZXF1aXJlcyBhcnJheSBjb250YWluZXJcIilcclxuICAgICAgfVxyXG4gICAgICAvLyBSZW1vdmUgYWxsIG1hdGNoaW5nIGl0ZW1zIHVzaW5nIHNwbGljZSAoZnJvbSBlbmQgdG8gYXZvaWQgaW5kZXggc2hpZnRpbmcpXHJcbiAgICAgIGZvciAobGV0IGkgPSBjb250YWluZXIubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pIHtcclxuICAgICAgICBpZiAoZGVlcEVxdWFsKGNvbnRhaW5lcltpXSwgb3AudmFsdWUpKSB7XHJcbiAgICAgICAgICBjb250YWluZXIuc3BsaWNlKGksIDEpXHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIGJyZWFrXHJcblxyXG4gICAgZGVmYXVsdDpcclxuICAgICAgdGhyb3cgZmFpbHVyZShgVW5rbm93biBvcGVyYXRpb24ga2luZDogJHsob3AgYXMgYW55KS5raW5kfWApXHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogT3B0aW9ucyBmb3IgYXBwbHlPcHMuXHJcbiAqL1xyXG5leHBvcnQgaW50ZXJmYWNlIEFwcGx5T3BzT3B0aW9ucyB7XHJcbiAgLyoqXHJcbiAgICogV2hldGhlciB0byBkZWVwIGNsb25lIHZhbHVlcyBiZWZvcmUgaW5zZXJ0aW5nIHRoZW0gaW50byB0aGUgdGFyZ2V0LlxyXG4gICAqIC0gYHRydWVgIChkZWZhdWx0KTogVmFsdWVzIGFyZSBjbG9uZWQgdG8gcHJldmVudCBhbGlhc2luZyBiZXR3ZWVuIHRoZSBvcHMgYW5kIHRhcmdldC5cclxuICAgKiAtIGBmYWxzZWA6IFZhbHVlcyBhcmUgdXNlZCBkaXJlY3RseSBmb3IgYmV0dGVyIHBlcmZvcm1hbmNlLiBPbmx5IHVzZSB0aGlzIGlmIHlvdVxyXG4gICAqICAgZ3VhcmFudGVlIHRoZSBvcCB2YWx1ZXMgd29uJ3QgYmUgbXV0YXRlZCBhZnRlciBhcHBsaWNhdGlvbi5cclxuICAgKi9cclxuICBjbG9uZVZhbHVlcz86IGJvb2xlYW5cclxufVxyXG5cclxuLyoqXHJcbiAqIEFwcGxpZXMgYSBsaXN0IG9mIG9wZXJhdGlvbnMgdG8gYSBtdXRhYmxlIHRhcmdldCBvYmplY3QuXHJcbiAqIFVzZSB0aGlzIHRvIHN5bmNocm9uaXplIGFuIGV4dGVybmFsIG11dGFibGUgc3RhdGUgKGUuZy4sIE1vYlggc3RvcmUpXHJcbiAqIHdpdGggdGhlIG9wZXJhdGlvbnMgcmVjZWl2ZWQgdmlhIHN1YnNjcmliZSgpLlxyXG4gKlxyXG4gKiBAcGFyYW0gb3BzIC0gVGhlIGxpc3Qgb2Ygb3BlcmF0aW9ucyB0byBhcHBseS5cclxuICogQHBhcmFtIHRhcmdldCAtIFRoZSBtdXRhYmxlIG9iamVjdCB0byBtb2RpZnkuXHJcbiAqIEBwYXJhbSBvcHRpb25zIC0gT3B0aW9uYWwgc2V0dGluZ3MgZm9yIGNvbnRyb2xsaW5nIGNsb25pbmcgYmVoYXZpb3IuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gYXBwbHlPcHMob3BzOiByZWFkb25seSBPcFtdLCB0YXJnZXQ6IEpTT05PYmplY3QsIG9wdGlvbnM/OiBBcHBseU9wc09wdGlvbnMpOiB2b2lkIHtcclxuICBjb25zdCBjbG9uZVZhbHVlcyA9IG9wdGlvbnM/LmNsb25lVmFsdWVzID8/IHRydWVcclxuICBmb3IgKGNvbnN0IG9wIG9mIG9wcykge1xyXG4gICAgYXBwbHlPcCh0YXJnZXQsIG9wLCBjbG9uZVZhbHVlcylcclxuICB9XHJcbn1cclxuIl0sIm5hbWVzIjpbImVxdWFsIiwic2NvcGVkVXJsQWxwaGFiZXQiLCJyZmRjIiwiaGFuZGxlciIsImNsb25lIl0sIm1hcHBpbmdzIjoiOzs7Ozs7O0FBWU8sV0FBUywrQkFBK0IsYUFHN0M7QUFDQSxRQUFJLFdBQVc7QUFDZixRQUFJLE9BQWdDO0FBQ3BDLFFBQUksY0FBYztBQUNsQixRQUFJLGVBQWU7QUFFbkIsZUFBVyxDQUFDLEtBQUssRUFBRSxLQUFLLFlBQVksV0FBVztBQUM3QyxZQUFNLEVBQUUsT0FBTyxhQUFhLG1CQUFtQixHQUFHO0FBRWxELFVBQUksUUFBUSxVQUFVO0FBRXBCLG1CQUFXO0FBQ1gsZUFBTztBQUNQLHNCQUFjLEdBQUc7QUFDakIsdUJBQWU7QUFBQSxNQUNqQixXQUFXLFVBQVUsVUFBVTtBQUk3QixZQUFJLEdBQUcsVUFBVSxlQUFnQixHQUFHLFlBQVksZUFBZSxXQUFXLGNBQWU7QUFDdkYsaUJBQU87QUFDUCx3QkFBYyxHQUFHO0FBQ2pCLHlCQUFlO0FBQUEsUUFDakI7QUFBQSxNQUNGO0FBQUEsSUFDRjtBQUVBLFdBQU8sRUFBRSxnQkFBZ0IsVUFBVSxZQUFZLEtBQUE7QUFBQSxFQUNqRDtBQUFBLEVDM0NPLE1BQU0sMEJBQTBCLE1BQU07QUFBQSxJQUMzQyxZQUFZLEtBQWE7QUFDdkIsWUFBTSxHQUFHO0FBR1QsYUFBTyxlQUFlLE1BQU0sa0JBQWtCLFNBQVM7QUFBQSxJQUN6RDtBQUFBLEVBQ0Y7QUFFTyxXQUFTLFFBQVEsU0FBd0I7QUFDOUMsVUFBTSxJQUFJLGtCQUFrQixPQUFPO0FBQUEsRUFDckM7QUN5Q0EsV0FBUyx1QkFBdUIsTUFBd0M7QUFDdEUsV0FBTyxHQUFHLEtBQUssS0FBSyxJQUFJ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QztBQUVFLGtCQUFrQixHQUFHLEdBQUcsSUFBSSxjQUFjLFVBQVUsR0FBRyxLQUFLLElBQUksR0FBRztBQUNyRTtBQUFBLE1BRUYsS0FBSztBQUNILFlBQUksQ0FBQyxTQUFTLFNBQVMsS0FBSyxNQUFNLFFBQVEsU0FBUyxHQUFHO0FBQ3BELGtCQUFRLGtDQUFrQztBQUFBLFFBQzVDO0FBRUEsZUFBUSxVQUFrQixHQUFHLEdBQUc7QUFDaEM7QUFBQSxNQUVGLEtBQUssVUFBVTtBQUNiLFlBQUksQ0FBQyxNQUFNLFFBQVEsU0FBUyxHQUFHO0FBQzdCLGtCQUFRLGlDQUFpQztBQUFBLFFBQzNDO0FBQ0EsY0FBTSxZQUFZLEtBQUssSUFBSSxHQUFHLE9BQU8sVUFBVSxNQUFNO0FBQ3JELGtCQUFVO0FBQUEsVUFDUjtBQUFBLFVBQ0EsR0FBRztBQUFBLFVBQ0gsR0FBSSxjQUFjLEdBQUcsUUFBUSxJQUFJLENBQUMsTUFBTSxVQUFVLENBQUMsQ0FBQyxJQUFJLEdBQUc7QUFBQSxRQUFBO0FBRTdEO0FBQUEsTUFDRjtBQUFBLE1BRUEsS0FBSztBQUNILFlBQUksQ0FBQyxNQUFNLFFBQVEsU0FBUyxHQUFHO0FBQzdCLGtCQUFRLG1DQUFtQztBQUFBLFFBQzdDO0FBQ0EsWUFBSSxDQUFDLFVBQVUsS0FBSyxDQUFDLFNBQVMsVUFBVSxNQUFNLEdBQUcsS0FBSyxDQUFDLEdBQUc7QUFDeEQsb0JBQVUsS0FBSyxjQUFjLFVBQVUsR0FBRyxLQUFLLElBQUksR0FBRyxLQUFLO0FBQUEsUUFDN0Q7QUFDQTtBQUFBLE1BRUYsS0FBSztBQUNILFlBQUksQ0FBQyxNQUFNLFFBQVEsU0FBUyxHQUFHO0FBQzdCLGtCQUFRLHdDQUF3QztBQUFBLFFBQ2xEO0FBRUEsaUJBQVMsSUFBSSxVQUFVLFNBQVMsR0FBRyxLQUFLLEdBQUcsS0FBSztBQUM5QyxjQUFJLFVBQVUsVUFBVSxDQUFDLEdBQUcsR0FBRyxLQUFLLEdBQUc7QUFDckMsc0JBQVUsT0FBTyxHQUFHLENBQUM7QUFBQSxVQUN2QjtBQUFBLFFBQ0Y7QUFDQTtBQUFBLE1BRUY7QUFDRSxjQUFNLFFBQVEsMkJBQTRCLEdBQVcsSUFBSSxFQUFFO0FBQUEsSUFBQTtBQUFBLEVBRWpFO0FBd0JPLFdBQVMsU0FBUyxLQUFvQixRQUFvQixTQUFpQzs7QUFDaEcsVUFBTSxlQUFjLHdDQUFTLGdCQUFULFlBQXdCO0FBQzVDLGVBQVcsTUFBTSxLQUFLO0FBQ3BCLGNBQVEsUUFBUSxJQUFJLFdBQVc7QUFBQSxJQUNqQztBQUFBLEVBQ0Y7Ozs7OyIsInhfZ29vZ2xlX2lnbm9yZUxpc3QiOlszLDQsNSw2XX0=
|