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