sliftutils 1.7.10 → 1.7.11

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.
Files changed (83) hide show
  1. package/examplestorage/exampleserver.ts +0 -2
  2. package/index.d.ts +290 -54
  3. package/misc/dist/environment.ts.cache +3 -3
  4. package/misc/dist/getSecret.ts.cache +139 -0
  5. package/misc/dist/strings.ts.cache +13 -0
  6. package/misc/dist/zip.ts.cache +9 -0
  7. package/misc/getSecret.ts +38 -16
  8. package/misc/https/cloudflareHelpers.d.ts +19 -0
  9. package/misc/https/cloudflareHelpers.ts +69 -0
  10. package/misc/https/dist/certs.ts.cache +115 -179
  11. package/misc/https/dist/cloudflareHelpers.ts.cache +68 -0
  12. package/misc/https/dist/dns.ts.cache +112 -100
  13. package/misc/https/dist/hostServer.ts.cache +130 -0
  14. package/misc/https/dist/httpsCerts.ts.cache +24 -5
  15. package/misc/https/dist/persistentLocalStorage.ts.cache +3 -2
  16. package/misc/https/dns.d.ts +41 -12
  17. package/misc/https/dns.ts +104 -101
  18. package/misc/https/hostServer.d.ts +0 -6
  19. package/misc/https/hostServer.ts +9 -5
  20. package/package.json +2 -2
  21. package/render-utils/dist/observer.tsx.cache +3 -2
  22. package/spec.txt +0 -90
  23. package/storage/ArchivesDisk.d.ts +2 -0
  24. package/storage/ArchivesDisk.ts +7 -3
  25. package/storage/BulkDatabase2/dist/BulkDatabaseBase.ts.cache +1242 -0
  26. package/storage/BulkDatabase2/dist/BulkDatabaseFormat.ts.cache +513 -0
  27. package/storage/BulkDatabase2/dist/BulkDatabaseMerge.ts.cache +352 -0
  28. package/storage/BulkDatabase2/dist/BulkDatabaseReader.ts.cache +306 -0
  29. package/storage/BulkDatabase2/dist/LoadedIndex.ts.cache +435 -0
  30. package/storage/BulkDatabase2/dist/WriteOverlay.ts.cache +58 -0
  31. package/storage/BulkDatabase2/dist/blockCache.ts.cache +179 -0
  32. package/storage/BulkDatabase2/dist/mergeLock.ts.cache +149 -0
  33. package/storage/BulkDatabase2/dist/mergeMarkers.ts.cache +101 -0
  34. package/storage/BulkDatabase2/dist/streamLog.ts.cache +227 -0
  35. package/storage/BulkDatabase2/dist/syncClient.ts.cache +104 -0
  36. package/storage/IArchives.d.ts +47 -15
  37. package/storage/IArchives.ts +86 -31
  38. package/storage/backblaze.d.ts +15 -0
  39. package/storage/backblaze.ts +199 -79
  40. package/storage/dist/ArchivesDisk.ts.cache +373 -0
  41. package/storage/dist/FileFolderAPI.tsx.cache +508 -65
  42. package/storage/dist/IArchives.ts.cache +44 -0
  43. package/storage/dist/IndexedDBFileFolderAPI.ts.cache +8 -2
  44. package/storage/dist/JSONStorage.ts.cache +6 -2
  45. package/storage/dist/PendingManager.tsx.cache +1 -1
  46. package/storage/dist/TransactionStorage.ts.cache +231 -92
  47. package/storage/dist/backblaze.ts.cache +797 -0
  48. package/storage/dist/fileSystemPointer.ts.cache +36 -3
  49. package/storage/dist/remoteFileStorage.ts.cache +495 -0
  50. package/storage/remoteStorage/ArchivesRemote.d.ts +5 -1
  51. package/storage/remoteStorage/ArchivesRemote.ts +28 -8
  52. package/storage/remoteStorage/ArchivesUrl.d.ts +2 -0
  53. package/storage/remoteStorage/ArchivesUrl.ts +16 -4
  54. package/storage/remoteStorage/blobStore.d.ts +52 -3
  55. package/storage/remoteStorage/blobStore.ts +414 -101
  56. package/storage/remoteStorage/createArchives.d.ts +31 -10
  57. package/storage/remoteStorage/createArchives.ts +470 -253
  58. package/storage/remoteStorage/dist/ArchivesRemote.ts.cache +197 -0
  59. package/storage/remoteStorage/dist/ArchivesUrl.ts.cache +85 -0
  60. package/storage/remoteStorage/dist/accessPage.tsx.cache +222 -0
  61. package/storage/remoteStorage/dist/blobStore.ts.cache +837 -0
  62. package/storage/remoteStorage/dist/cliArgs.ts.cache +16 -0
  63. package/storage/remoteStorage/dist/createArchives.ts.cache +610 -0
  64. package/storage/remoteStorage/dist/remoteConfig.ts.cache +206 -0
  65. package/storage/remoteStorage/dist/sourceWrapper.ts.cache +223 -0
  66. package/storage/remoteStorage/dist/storageController.ts.cache +500 -0
  67. package/storage/remoteStorage/dist/storageServer.ts.cache +106 -0
  68. package/storage/remoteStorage/dist/storageServerCli.ts.cache +39 -0
  69. package/storage/remoteStorage/dist/storageServerState.ts.cache +518 -0
  70. package/storage/remoteStorage/remoteConfig.d.ts +8 -0
  71. package/storage/remoteStorage/remoteConfig.ts +105 -5
  72. package/storage/remoteStorage/sourceWrapper.d.ts +41 -0
  73. package/storage/remoteStorage/sourceWrapper.ts +223 -0
  74. package/storage/remoteStorage/spec.md +31 -0
  75. package/storage/remoteStorage/storageController.d.ts +11 -0
  76. package/storage/remoteStorage/storageController.ts +109 -40
  77. package/storage/remoteStorage/storageServer.d.ts +0 -5
  78. package/storage/remoteStorage/storageServer.ts +17 -10
  79. package/storage/remoteStorage/storageServerCli.ts +0 -3
  80. package/storage/remoteStorage/storageServerState.d.ts +7 -1
  81. package/storage/remoteStorage/storageServerState.ts +230 -48
  82. package/testsite/server.ts +0 -2
  83. package/yarn.lock +11 -6
@@ -0,0 +1,518 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule && mod.default) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
6
+ //exports.getLocalArchives = exports.deleteBucketFile = exports.writeBucketFile = exports.assertMutable = exports.getLoadedBucket = exports.setTrustedMachines = exports.getRequests = exports.getTrust = exports.assertWritesAllowed = exports.getWritesRejectedReason = exports.setWritesRejectedReason = exports.getStorageServerConfigOptional = exports.getStorageServerConfig = exports.setStorageServerConfig = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ const FileFolderAPI_1 = require("../FileFolderAPI");
9
+ const TransactionStorage_1 = require("../TransactionStorage");
10
+ const JSONStorage_1 = require("../JSONStorage");
11
+ const ArchivesDisk_1 = require("../ArchivesDisk");
12
+ const blobStore_1 = require("./blobStore");
13
+ const IArchives_1 = require("../IArchives");
14
+ const remoteConfig_1 = require("./remoteConfig");
15
+ const createArchives_1 = require("./createArchives");
16
+ const cliArgs_1 = require("./cliArgs");
17
+ let config;
18
+ function setStorageServerConfig(value) {
19
+ config = value;
20
+ }
21
+ exports.setStorageServerConfig = setStorageServerConfig;
22
+ function getStorageServerConfig() {
23
+ if (!config) {
24
+ throw new Error(`Storage server is not initialized (this API only works on the storage server)`);
25
+ }
26
+ return config;
27
+ }
28
+ exports.getStorageServerConfig = getStorageServerConfig;
29
+ // For self-detection: code that CAN run outside the storage server (createArchives) uses this to
30
+ // check "is this URL our own process?" without throwing.
31
+ function getStorageServerConfigOptional() {
32
+ return config;
33
+ }
34
+ exports.getStorageServerConfigOptional = getStorageServerConfigOptional;
35
+ // When set, all write-path operations (creating files, appending large uploads, creating buckets)
36
+ // throw this message. Reads, findInfo, and deletes still work — so clients can free space. Managed
37
+ // by hostStorageServer's disk-space monitor.
38
+ let writesRejectedReason;
39
+ function setWritesRejectedReason(reason) {
40
+ writesRejectedReason = reason;
41
+ }
42
+ exports.setWritesRejectedReason = setWritesRejectedReason;
43
+ function getWritesRejectedReason() {
44
+ return writesRejectedReason;
45
+ }
46
+ exports.getWritesRejectedReason = getWritesRejectedReason;
47
+ function assertWritesAllowed() {
48
+ if (writesRejectedReason)
49
+ throw new Error(writesRejectedReason);
50
+ }
51
+ exports.assertWritesAllowed = assertWritesAllowed;
52
+ // The system storages (trust, requests) are the same kind of thing — a JSON key/value store under
53
+ // <folder>/system2/<name> — so they share one cache, keyed by name. ("system2" because the layout
54
+ // changed when bucket configs moved into the buckets themselves; old "system"/"buckets" folders
55
+ // are simply ignored.)
56
+ // setTrustedMachines is called by consumers BEFORE starting the server, so when the config isn't
57
+ // set yet we fall back to the same --folder arg the CLI starts the server with.
58
+ function getStorageFolder() {
59
+ let config = getStorageServerConfigOptional();
60
+ if (config)
61
+ return config.folder;
62
+ let folder = (0, cliArgs_1.getArg)("folder");
63
+ if (!folder) {
64
+ throw new Error(`Storage server is not initialized and there is no --folder arg, so the storage folder is unknown`);
65
+ }
66
+ return path_1.default.resolve(folder);
67
+ }
68
+ const systemStorages = new Map();
69
+ function getSystemStorage(name) {
70
+ let storage = systemStorages.get(name);
71
+ if (!storage) {
72
+ storage = (async () => {
73
+ let root = await (0, FileFolderAPI_1.getFileStorageNested2)(getStorageFolder());
74
+ let system = await root.folder.getStorage("system2");
75
+ let transactionName = "storage" + name[0].toUpperCase() + name.slice(1);
76
+ return new JSONStorage_1.JSONStorage(new TransactionStorage_1.TransactionStorage(await system.folder.getStorage(name), transactionName));
77
+ })();
78
+ systemStorages.set(name, storage);
79
+ }
80
+ return storage;
81
+ }
82
+ function getTrust() {
83
+ return getSystemStorage("trust");
84
+ }
85
+ exports.getTrust = getTrust;
86
+ function getRequests() {
87
+ return getSystemStorage("requests");
88
+ }
89
+ exports.getRequests = getRequests;
90
+ /** Makes machineIds the complete trust list for the account: machines not in the list lose access, machines already trusted keep their existing record, and missing ones are added. */
91
+ async function setTrustedMachines(config) {
92
+ let trust = await getTrust();
93
+ let prefix = `${config.account}|`;
94
+ let desired = new Set(config.machineIds);
95
+ for (let key of await trust.getKeys()) {
96
+ if (!key.startsWith(prefix))
97
+ continue;
98
+ let machineId = key.slice(prefix.length);
99
+ if (desired.has(machineId)) {
100
+ desired.delete(machineId);
101
+ continue;
102
+ }
103
+ console.log(`Removing trust for machine ${machineId} on account ${config.account}`);
104
+ await trust.remove(key);
105
+ }
106
+ for (let machineId of desired) {
107
+ console.log(`Adding trust for machine ${machineId} on account ${config.account}`);
108
+ await trust.set(`${prefix}${machineId}`, { account: config.account, machineId, ip: "", time: Date.now() });
109
+ }
110
+ }
111
+ exports.setTrustedMachines = setTrustedMachines;
112
+ const buckets = new Map();
113
+ // setTimeout cannot represent longer delays; more distant window boundaries re-check after this
114
+ const MAX_REBUILD_TIMER_DELAY = 2 ** 31 - 1;
115
+ // Rebuild slightly after the boundary, so the newly-valid entry is unambiguously active
116
+ const REBUILD_BOUNDARY_BUFFER = 1000;
117
+ function getBucketFolder(account, bucketName) {
118
+ return path_1.default.join(getStorageServerConfig().folder, "buckets2", account, bucketName);
119
+ }
120
+ function findSelfIndexes(routing, account, bucketName) {
121
+ let { domain, port } = getStorageServerConfig();
122
+ let indexes = [];
123
+ for (let i = 0; i < routing.sources.length; i++) {
124
+ let source = routing.sources[i];
125
+ if (typeof source === "string" || source.type !== "remote")
126
+ continue;
127
+ let parsed = (0, remoteConfig_1.parseHostedUrl)(source.url);
128
+ if (parsed.address === domain && parsed.port === port && parsed.account === account && parsed.bucketName === bucketName) {
129
+ indexes.push(i);
130
+ }
131
+ }
132
+ return indexes;
133
+ }
134
+ // The entry whose valid window contains the time (among the entries covering the key's route,
135
+ // when one is given - a server can hold different shards with different options). Half-open
136
+ // ([start, end)), so clean breaks resolve unambiguously. Falls back to the nearest window when
137
+ // none contains the time - gaps shouldn't exist, but a write must still resolve to SOME
138
+ // configuration.
139
+ function selectEntryAt(entries, time, route) {
140
+ if (route !== undefined) {
141
+ let covering = entries.filter(x => (0, remoteConfig_1.routeContains)(x.route, route));
142
+ if (covering.length) {
143
+ entries = covering;
144
+ }
145
+ }
146
+ let containing = entries.find(x => x.validWindow[0] <= time && time < x.validWindow[1]);
147
+ if (containing)
148
+ return containing;
149
+ let best;
150
+ let bestDistance = Infinity;
151
+ for (let entry of entries) {
152
+ let distance = Math.min(Math.abs(time - entry.validWindow[0]), Math.abs(time - entry.validWindow[1]));
153
+ if (distance < bestDistance) {
154
+ bestDistance = distance;
155
+ best = entry;
156
+ }
157
+ }
158
+ return best;
159
+ }
160
+ // Bucket options can change over time (multiple self entries with different valid windows), and
161
+ // the structural ones (rawDisk, the downstream list) are baked into the store - so the store is
162
+ // rebuilt shortly after each of our window boundaries passes, making the newly-valid entry apply.
163
+ function scheduleWindowBoundaryRebuild(loaded) {
164
+ var _a, _b;
165
+ let now = Date.now();
166
+ let boundaries = loaded.selfEntries.flatMap(x => x.validWindow).filter(t => t > now);
167
+ if (!boundaries.length)
168
+ return;
169
+ let nextBoundary = Math.min(...boundaries);
170
+ let key = `${loaded.account}/${loaded.bucketName}`;
171
+ let timer = setTimeout(() => {
172
+ void (async () => {
173
+ // A routing change may have already replaced this store; only IT gets a boundary timer
174
+ let current = await buckets.get(key);
175
+ if (current !== loaded)
176
+ return;
177
+ if (Date.now() < nextBoundary) {
178
+ scheduleWindowBoundaryRebuild(loaded);
179
+ return;
180
+ }
181
+ await scheduleRoutingReload(loaded.account, loaded.bucketName, { force: true });
182
+ })();
183
+ }, Math.min(nextBoundary - now + REBUILD_BOUNDARY_BUFFER, MAX_REBUILD_TIMER_DELAY));
184
+ (_b = (_a = timer).unref) === null || _b === void 0 ? void 0 : _b.call(_a);
185
+ }
186
+ function buildBucket(account, bucketName, routing) {
187
+ let folder = getBucketFolder(account, bucketName);
188
+ let selfIndexes = findSelfIndexes(routing, account, bucketName);
189
+ let selfEntries = selfIndexes.map(i => routing.sources[i]);
190
+ let self = selectEntryAt(selfEntries, Date.now());
191
+ let selfIndex = -1;
192
+ if (self) {
193
+ selfIndex = routing.sources.indexOf(self);
194
+ }
195
+ let store;
196
+ if (self === null || self === void 0 ? void 0 : self.rawDisk) {
197
+ store = new ArchivesDisk_1.ArchivesDisk(folder);
198
+ }
199
+ else {
200
+ // Our own disk is the base source; only the routing entries DOWNSTREAM from us (after our
201
+ // currently-valid entry) become synchronization sources. Upstream sources sync from us, so
202
+ // writing to or scanning them would just echo our own data back (and make our availability
203
+ // depend on theirs). A server NOT in the list has been removed from the bucket: it keeps
204
+ // its disk data (the config may re-add it), but stops all synchronization - no one
205
+ // contacts a removed source, and scanning/pushing as if we were still one would fight the
206
+ // real chain. The config-level validWindow rides on each ArchivesSource; the disk source
207
+ // shares our currently-valid entry's window (it holds our copy of the data).
208
+ let ownIndexes = new Set(selfIndexes);
209
+ // Our own disk gets no route filter: everything it holds is ours to index and serve
210
+ let sources = [{
211
+ source: new ArchivesDisk_1.ArchivesDisk(folder),
212
+ validWindow: (self === null || self === void 0 ? void 0 : self.validWindow) || IArchives_1.FULL_VALID_WINDOW,
213
+ }];
214
+ if (selfIndex === -1) {
215
+ console.log(`This server is not in the routing config for bucket ${account}/${bucketName}; keeping its data on disk but no longer synchronizing it`);
216
+ }
217
+ else {
218
+ for (let i = selfIndex + 1; i < routing.sources.length; i++) {
219
+ let source = routing.sources[i];
220
+ if (typeof source === "string" || ownIndexes.has(i))
221
+ continue;
222
+ // Disjoint-shard sources never talk to each other; a partial overlap syncs only
223
+ // the intersection (scans ignore the rest, writes only send matching keys)
224
+ let sharedRoute = (0, remoteConfig_1.routeIntersection)(self === null || self === void 0 ? void 0 : self.route, source.route);
225
+ if (!sharedRoute)
226
+ continue;
227
+ // A bounded-cache server (noFullSync on our own entry) must not full-sync from
228
+ // ANY source, or its disk would fill regardless of the limit
229
+ sources.push({ source: (0, createArchives_1.createApiArchives)(source), validWindow: source.validWindow, route: sharedRoute, noFullSync: source.noFullSync || (self === null || self === void 0 ? void 0 : self.noFullSync) });
230
+ }
231
+ }
232
+ store = new blobStore_1.BlobStore(folder, sources, {
233
+ onIndexChanged: key => {
234
+ // Fires for our own routing writes AND routing files pulled in via synchronization
235
+ // (only ever newer ones, see IArchives.set) — either way, apply the new config
236
+ if (key !== remoteConfig_1.ROUTING_FILE)
237
+ return;
238
+ void scheduleRoutingReload(account, bucketName);
239
+ },
240
+ readerDiskLimit: self === null || self === void 0 ? void 0 : self.readerDiskLimit,
241
+ });
242
+ }
243
+ let loaded = { account, bucketName, routing, routingJSON: JSON.stringify(routing), selfEntries, self, store };
244
+ scheduleWindowBoundaryRebuild(loaded);
245
+ return loaded;
246
+ }
247
+ async function loadBucket(account, bucketName) {
248
+ let data = await new ArchivesDisk_1.ArchivesDisk(getBucketFolder(account, bucketName)).get(remoteConfig_1.ROUTING_FILE);
249
+ if (!data)
250
+ return undefined;
251
+ return buildBucket(account, bucketName, (0, remoteConfig_1.parseRoutingData)(data));
252
+ }
253
+ function getLoadedBucket(account, bucketName) {
254
+ let key = `${account}/${bucketName}`;
255
+ let loaded = buckets.get(key);
256
+ if (!loaded) {
257
+ loaded = loadBucket(account, bucketName);
258
+ buckets.set(key, loaded);
259
+ // Missing buckets are not cached — they can be created at any time (guarding against a
260
+ // concurrent create having already replaced our entry)
261
+ void loaded.then(bucket => {
262
+ if (!bucket && buckets.get(key) === loaded) {
263
+ buckets.delete(key);
264
+ }
265
+ }, () => {
266
+ if (buckets.get(key) === loaded) {
267
+ buckets.delete(key);
268
+ }
269
+ });
270
+ }
271
+ return loaded;
272
+ }
273
+ exports.getLoadedBucket = getLoadedBucket;
274
+ // Routing reloads are serialized per bucket, so concurrent writes/syncs can't rebuild the same
275
+ // store twice in parallel
276
+ const routingReloads = new Map();
277
+ function scheduleRoutingReload(account, bucketName, config) {
278
+ let key = `${account}/${bucketName}`;
279
+ let next = (routingReloads.get(key) || Promise.resolve())
280
+ .then(() => checkRoutingChanged(account, bucketName, config === null || config === void 0 ? void 0 : config.force))
281
+ .catch(e => console.error(`Reloading routing config for bucket ${key} failed:`, e));
282
+ routingReloads.set(key, next);
283
+ return next;
284
+ }
285
+ async function checkRoutingChanged(account, bucketName, force) {
286
+ let key = `${account}/${bucketName}`;
287
+ let loaded = await buckets.get(key);
288
+ if (!loaded)
289
+ return;
290
+ // get() cache-reads the file onto our disk when a remote source holds it, so the bucket still
291
+ // exists after a restart
292
+ let data = await loaded.store.get(remoteConfig_1.ROUTING_FILE);
293
+ if (!data)
294
+ return;
295
+ let routing = (0, remoteConfig_1.parseRoutingData)(data);
296
+ if (!force && JSON.stringify(routing) === loaded.routingJSON)
297
+ return;
298
+ if (force) {
299
+ console.log(`Rebuilding the store for bucket ${key} (a valid window boundary passed)`);
300
+ }
301
+ else {
302
+ console.log(`Routing config changed for bucket ${key}, rebuilding its store`);
303
+ }
304
+ if (loaded.store instanceof blobStore_1.BlobStore) {
305
+ await loaded.store.dispose();
306
+ }
307
+ buckets.set(key, Promise.resolve(buildBucket(account, bucketName, routing)));
308
+ }
309
+ // Per-write options are evaluated at the WRITE's time (and the key's route), not the current
310
+ // config: the write time is stamped exactly once (at the first node that receives the write) and
311
+ // propagates with the data, so every node resolves the same self entry - and the same options.
312
+ function getWriteConfig(bucket, writeTime, route) {
313
+ let self = selectEntryAt(bucket.selfEntries, writeTime, route);
314
+ return { fast: self === null || self === void 0 ? void 0 : self.fast, writeDelay: self === null || self === void 0 ? void 0 : self.writeDelay };
315
+ }
316
+ async function assertMutable(bucket, filePath, writeTime) {
317
+ let self = selectEntryAt(bucket.selfEntries, writeTime, (0, remoteConfig_1.getRoute)(filePath));
318
+ if (!(self === null || self === void 0 ? void 0 : self.immutable))
319
+ return;
320
+ if (await bucket.store.getInfo(filePath)) {
321
+ throw new Error(`Bucket ${bucket.account}/${bucket.bucketName} is immutable (at write time ${writeTime}) and ${JSON.stringify(filePath)} already exists, so it cannot be written to`);
322
+ }
323
+ }
324
+ exports.assertMutable = assertMutable;
325
+ // Routing writes are serialized per bucket, so two concurrent creates can't both build a store
326
+ // (the loser's store would leak with its sync loops running forever)
327
+ const routingWrites = new Map();
328
+ async function writeRoutingConfig(account, bucketName, data, config) {
329
+ let key = `${account}/${bucketName}`;
330
+ // Validates before storing anything, so a bad config can't brick the bucket
331
+ let incoming = (0, remoteConfig_1.parseRoutingData)(data);
332
+ let loaded = await getLoadedBucket(account, bucketName);
333
+ if (!loaded) {
334
+ await new ArchivesDisk_1.ArchivesDisk(getBucketFolder(account, bucketName)).set(remoteConfig_1.ROUTING_FILE, data, { lastModified: config === null || config === void 0 ? void 0 : config.lastModified });
335
+ buckets.set(key, Promise.resolve(buildBucket(account, bucketName, incoming)));
336
+ console.log(`Created bucket ${key}`);
337
+ return;
338
+ }
339
+ // A changed config must carry a higher version than the one currently stored — otherwise two
340
+ // clients with different configs at the same version would keep clobbering each other. Same
341
+ // content at any version is a harmless no-op and is allowed through.
342
+ if (JSON.stringify(incoming) !== loaded.routingJSON && (0, remoteConfig_1.getConfigVersion)(incoming) <= (0, remoteConfig_1.getConfigVersion)(loaded.routing)) {
343
+ throw new Error(`Cannot update routing config for bucket ${key}: the new config differs from the current one but its version (${(0, remoteConfig_1.getConfigVersion)(incoming)}) is not greater than the current version (${(0, remoteConfig_1.getConfigVersion)(loaded.routing)}). Increment the version to update it. Current: ${loaded.routingJSON}. Attempted: ${JSON.stringify(incoming)}`);
344
+ }
345
+ // Routing writes bypass fast mode (the config must apply immediately and survive a crash)
346
+ // and ignore immutable (the routing file must always stay updatable). An older lastModified
347
+ // no-ops inside set, in which case the reload below sees no change.
348
+ await loaded.store.set(remoteConfig_1.ROUTING_FILE, data, { lastModified: config === null || config === void 0 ? void 0 : config.lastModified });
349
+ await scheduleRoutingReload(account, bucketName);
350
+ }
351
+ async function writeBucketFile(account, bucketName, filePath, data, config) {
352
+ assertWritesAllowed();
353
+ if (filePath === remoteConfig_1.ROUTING_FILE) {
354
+ let key = `${account}/${bucketName}`;
355
+ let run = (routingWrites.get(key) || Promise.resolve()).then(() => writeRoutingConfig(account, bucketName, data, config));
356
+ // The chain must survive a failed write, so the stored link swallows the error (the caller
357
+ // still gets it from run)
358
+ routingWrites.set(key, run.then(() => { }, () => { }));
359
+ return await run;
360
+ }
361
+ let loaded = await getLoadedBucket(account, bucketName);
362
+ if (!loaded) {
363
+ throw new Error(`Bucket ${account}/${bucketName} does not exist. Write its routing config to ${JSON.stringify(remoteConfig_1.ROUTING_FILE)} to create it.`);
364
+ }
365
+ // The write time is determined exactly once, HERE at the first node that receives the write;
366
+ // it propagates as lastModified, so every node evaluates the bucket options at the same instant
367
+ let writeTime = (config === null || config === void 0 ? void 0 : config.lastModified) || Date.now();
368
+ // Only freshly-stamped writes are checked: a write with an explicit lastModified is
369
+ // synchronization/backfill (old data legitimately lands on sources whose window has moved on),
370
+ // but a fresh write reaching us outside our windows/routes means the client resolved its
371
+ // target from a stale view - it must re-resolve and retry at the correct source.
372
+ let route = (0, remoteConfig_1.getRoute)(filePath);
373
+ if (!(config === null || config === void 0 ? void 0 : config.lastModified) && loaded.selfEntries.length) {
374
+ let timeValid = loaded.selfEntries.filter(x => writeTime >= x.validWindow[0] - IArchives_1.WRITE_PAST_WINDOW_GRACE && writeTime <= x.validWindow[1] + IArchives_1.WRITE_PAST_WINDOW_GRACE);
375
+ if (!timeValid.length) {
376
+ throw new Error(`${IArchives_1.STORAGE_WRONG_VALID_WINDOW} This server is not a valid write target at ${writeTime} for bucket ${account}/${bucketName} (our valid windows: ${JSON.stringify(loaded.selfEntries.map(x => x.validWindow))}). Re-resolve the currently valid source and retry.`);
377
+ }
378
+ if (!timeValid.some(x => (0, remoteConfig_1.routeContains)(x.route, route))) {
379
+ throw new Error(`${IArchives_1.STORAGE_WRONG_ROUTE} This server does not handle route ${route} (key ${JSON.stringify(filePath)}) for bucket ${account}/${bucketName} (our routes at this time: ${JSON.stringify(timeValid.map(x => x.route || IArchives_1.FULL_ROUTE))}). Re-resolve the source for this key and retry.`);
380
+ }
381
+ }
382
+ await assertMutable(loaded, filePath, writeTime);
383
+ await loaded.store.set(filePath, data, { ...getWriteConfig(loaded, writeTime, route), lastModified: writeTime });
384
+ }
385
+ exports.writeBucketFile = writeBucketFile;
386
+ async function deleteBucketFile(account, bucketName, filePath) {
387
+ if (filePath === remoteConfig_1.ROUTING_FILE) {
388
+ throw new Error(`The routing config ${JSON.stringify(remoteConfig_1.ROUTING_FILE)} cannot be deleted (overwrite it to change the bucket's configuration)`);
389
+ }
390
+ let loaded = await getLoadedBucket(account, bucketName);
391
+ if (!loaded)
392
+ return;
393
+ await loaded.store.del(filePath, getWriteConfig(loaded, Date.now(), (0, remoteConfig_1.getRoute)(filePath)));
394
+ }
395
+ exports.deleteBucketFile = deleteBucketFile;
396
+ // ── local IArchives access ──
397
+ const LARGE_FILE_PART_SIZE = 8 * 1024 * 1024;
398
+ // The in-process IArchives for a bucket hosted by THIS server — used when a RemoteConfig source
399
+ // URL points at ourselves, so we don't talk to ourselves over HTTPS. One singleton per bucket.
400
+ class ArchivesLocalBucket {
401
+ constructor(account, bucketName) {
402
+ this.account = account;
403
+ this.bucketName = bucketName;
404
+ }
405
+ async getBucket() {
406
+ return await getLoadedBucket(this.account, this.bucketName);
407
+ }
408
+ getDebugName() {
409
+ return `localBucket/${this.account}/${this.bucketName}`;
410
+ }
411
+ async get(fileName, config) {
412
+ let result = await this.get2(fileName, config);
413
+ return result && result.data || undefined;
414
+ }
415
+ async get2(fileName, config) {
416
+ let bucket = await this.getBucket();
417
+ if (!bucket)
418
+ return undefined;
419
+ return await bucket.store.get2(fileName, config);
420
+ }
421
+ async set(fileName, data, config) {
422
+ await writeBucketFile(this.account, this.bucketName, fileName, data, config);
423
+ }
424
+ async del(fileName) {
425
+ await deleteBucketFile(this.account, this.bucketName, fileName);
426
+ }
427
+ async setLargeFile(config) {
428
+ assertWritesAllowed();
429
+ let bucket = await this.getBucket();
430
+ if (!bucket) {
431
+ throw new Error(`Bucket ${this.account}/${this.bucketName} does not exist. Write its routing config to ${JSON.stringify(remoteConfig_1.ROUTING_FILE)} to create it.`);
432
+ }
433
+ await assertMutable(bucket, config.path, Date.now());
434
+ let id = await bucket.store.startLargeUpload();
435
+ try {
436
+ while (true) {
437
+ let data = await config.getNextData();
438
+ if (!data)
439
+ break;
440
+ for (let offset = 0; offset < data.length; offset += LARGE_FILE_PART_SIZE) {
441
+ await bucket.store.appendLargeUpload(id, data.subarray(offset, offset + LARGE_FILE_PART_SIZE));
442
+ }
443
+ }
444
+ await bucket.store.finishLargeUpload(id, config.path);
445
+ }
446
+ catch (e) {
447
+ await bucket.store.cancelLargeUpload(id);
448
+ throw e;
449
+ }
450
+ }
451
+ async getInfo(fileName) {
452
+ let bucket = await this.getBucket();
453
+ if (!bucket)
454
+ return undefined;
455
+ return await bucket.store.getInfo(fileName);
456
+ }
457
+ async findInfo(prefix, config) {
458
+ let bucket = await this.getBucket();
459
+ if (!bucket)
460
+ return [];
461
+ return await bucket.store.findInfo(prefix, config);
462
+ }
463
+ async find(prefix, config) {
464
+ return (await this.findInfo(prefix, config)).map(x => x.path);
465
+ }
466
+ async getURL(filePath) {
467
+ let { domain, port } = getStorageServerConfig();
468
+ return (0, remoteConfig_1.buildFileUrl)(`https://${domain}:${port}/file/${encodeURIComponent(this.account)}/${encodeURIComponent(this.bucketName)}`, filePath);
469
+ }
470
+ async getConfig() {
471
+ var _a, _b;
472
+ let bucket = await this.getBucket();
473
+ // Missing buckets say true, matching what they become once created (the default store type)
474
+ let progress = (_b = bucket === null || bucket === void 0 ? void 0 : (_a = bucket.store).getSyncProgress) === null || _b === void 0 ? void 0 : _b.call(_a);
475
+ return {
476
+ supportsChangesAfter: !bucket || !!bucket.store.getChangesAfter,
477
+ remoteConfig: bucket === null || bucket === void 0 ? void 0 : bucket.routing,
478
+ index: progress === null || progress === void 0 ? void 0 : progress.index,
479
+ indexSources: progress === null || progress === void 0 ? void 0 : progress.sources,
480
+ readerDiskLimit: progress === null || progress === void 0 ? void 0 : progress.readerDiskLimit,
481
+ syncing: progress === null || progress === void 0 ? void 0 : progress.syncing,
482
+ };
483
+ }
484
+ async hasWriteAccess() {
485
+ return true;
486
+ }
487
+ async getChangesAfter(time) {
488
+ let bucket = await this.getBucket();
489
+ if (!bucket)
490
+ return [];
491
+ if (!bucket.store.getChangesAfter) {
492
+ throw new Error(`Bucket ${this.account}/${this.bucketName} does not support getChangesAfter (rawDisk buckets have no index)`);
493
+ }
494
+ return await bucket.store.getChangesAfter(time);
495
+ }
496
+ async getSyncStatus() {
497
+ let bucket = await this.getBucket();
498
+ if (!bucket)
499
+ return { allScansComplete: true, indexSize: 0, sources: [] };
500
+ if (!bucket.store.getSyncStatus) {
501
+ throw new Error(`Bucket ${this.account}/${this.bucketName} does not support getSyncStatus (rawDisk buckets have no synchronization)`);
502
+ }
503
+ return await bucket.store.getSyncStatus();
504
+ }
505
+ }
506
+ const localArchives = new Map();
507
+ function getLocalArchives(account, bucketName) {
508
+ let key = `${account}/${bucketName}`;
509
+ let existing = localArchives.get(key);
510
+ if (existing)
511
+ return existing;
512
+ let archives = new ArchivesLocalBucket(account, bucketName);
513
+ localArchives.set(key, archives);
514
+ return archives;
515
+ }
516
+ exports.getLocalArchives = getLocalArchives;
517
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RvcmFnZVNlcnZlclN0YXRlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsic3RvcmFnZVNlcnZlclN0YXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLGdEQUF3QjtBQUN4QixvREFBeUQ7QUFDekQsOERBQTJEO0FBQzNELGdEQUE2QztBQUM3QyxrREFBK0M7QUFDL0MsMkNBQXNEO0FBQ3RELDRDQUlzQjtBQUN0QixpREFBNEo7QUFDNUoscURBQXFEO0FBR3JELHVDQUFtQztBQXdCbkMsSUFBSSxNQUF1QyxDQUFDO0FBQzVDLFNBQWdCLHNCQUFzQixDQUFDLEtBQTBCO0lBQzdELE1BQU0sR0FBRyxLQUFLLENBQUM7QUFDbkIsQ0FBQztBQUZELHdEQUVDO0FBQ0QsU0FBZ0Isc0JBQXNCO0lBQ2xDLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUNWLE1BQU0sSUFBSSxLQUFLLENBQUMsK0VBQStFLENBQUMsQ0FBQztJQUNyRyxDQUFDO0lBQ0QsT0FBTyxNQUFNLENBQUM7QUFDbEIsQ0FBQztBQUxELHdEQUtDO0FBQ0QsaUdBQWlHO0FBQ2pHLHlEQUF5RDtBQUN6RCxTQUFnQiw4QkFBOEI7SUFDMUMsT0FBTyxNQUFNLENBQUM7QUFDbEIsQ0FBQztBQUZELHdFQUVDO0FBRUQsa0dBQWtHO0FBQ2xHLG1HQUFtRztBQUNuRyw2Q0FBNkM7QUFDN0MsSUFBSSxvQkFBd0MsQ0FBQztBQUM3QyxTQUFnQix1QkFBdUIsQ0FBQyxNQUEwQjtJQUM5RCxvQkFBb0IsR0FBRyxNQUFNLENBQUM7QUFDbEMsQ0FBQztBQUZELDBEQUVDO0FBQ0QsU0FBZ0IsdUJBQXVCO0lBQ25DLE9BQU8sb0JBQW9CLENBQUM7QUFDaEMsQ0FBQztBQUZELDBEQUVDO0FBQ0QsU0FBZ0IsbUJBQW1CO0lBQy9CLElBQUksb0JBQW9CO1FBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO0FBQ3BFLENBQUM7QUFGRCxrREFFQztBQUVELGtHQUFr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LENBQUMsU0FBUyxFQUFFLENBQUM7UUFDcEMsSUFBSSxDQUFDLE1BQU07WUFBRSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxDQUFDLEVBQUUsT0FBTyxFQUFFLEVBQUUsRUFBRSxDQUFDO1FBQzFFLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLGFBQWEsRUFBRSxDQUFDO1lBQzlCLE1BQU0sSUFBSSxLQUFLLENBQUMsVUFBVSxJQUFJLENBQUMsT0FBTyxJQUFJLElBQUksQ0FBQyxVQUFVLDJFQUEyRSxDQUFDLENBQUM7UUFDMUksQ0FBQztRQUNELE9BQU8sTUFBTSxNQUFNLENBQUMsS0FBSyxDQUFDLGFBQWEsRUFBRSxDQUFDO0lBQzlDLENBQUM7Q0FDSjtBQUVELE1BQU0sYUFBYSxHQUFHLElBQUksR0FBRyxFQUFxQixDQUFDO0FBQ25ELFNBQWdCLGdCQUFnQixDQUFDLE9BQWUsRUFBRSxVQUFrQjtJQUNoRSxJQUFJLEdBQUcsR0FBRyxHQUFHLE9BQU8sSUFBSSxVQUFVLEVBQUUsQ0FBQztJQUNyQyxJQUFJLFFBQVEsR0FBRyxhQUFhLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3RDLElBQUksUUFBUTtRQUFFLE9BQU8sUUFBUSxDQUFDO0lBQzlCLElBQUksUUFBUSxHQUFHLElBQUksbUJBQW1CLENBQUMsT0FBTyxFQUFFLFVBQVUsQ0FBQyxDQUFDO0lBQzVELGFBQWEsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLFFBQVEsQ0FBQyxDQUFDO0lBQ2pDLE9BQU8sUUFBUSxDQUFDO0FBQ3BCLENBQUM7QUFQRCw0Q0FPQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBwYXRoIGZyb20gXCJwYXRoXCI7XG5pbXBvcnQgeyBnZXRGaWxlU3RvcmFnZU5lc3RlZDIgfSBmcm9tIFwiLi4vRmlsZUZvbGRlckFQSVwiO1xuaW1wb3J0IHsgVHJhbnNhY3Rpb25TdG9yYWdlIH0gZnJvbSBcIi4uL1RyYW5zYWN0aW9uU3RvcmFnZVwiO1xuaW1wb3J0IHsgSlNPTlN0b3JhZ2UgfSBmcm9tIFwiLi4vSlNPTlN0b3JhZ2VcIjtcbmltcG9ydCB7IEFyY2hpdmVzRGlzayB9IGZyb20gXCIuLi9BcmNoaXZlc0Rpc2tcIjtcbmltcG9ydCB7IEJsb2JTdG9yZSwgSUJ1Y2tldFN0b3JlIH0gZnJvbSBcIi4vYmxvYlN0b3JlXCI7XG5pbXBvcnQge1xuICAgIFJlbW90ZUNvbmZpZywgSG9zdGVkQ29uZmlnLCBJQXJjaGl2ZXMsIEFyY2hpdmVzU291cmNlLCBBcmNoaXZlRmlsZUluZm8sIEFyY2hpdmVzQ29uZmlnLFxuICAgIEFyY2hpdmVzU3luY1N0YXR1cywgRlVMTF9WQUxJRF9XSU5ET1csXG4gICAgV1JJVEVfUEFTVF9XSU5ET1dfR1JBQ0UsIFNUT1JBR0VfV1JPTkdfVkFMSURfV0lORE9XLCBTVE9SQUdFX1dST05HX1JPVVRFLCBGVUxMX1JPVVRFLFxufSBmcm9tIFwiLi4vSUFyY2hpdmVzXCI7XG5pbXBvcnQgeyBST1VUSU5HX0ZJTEUsIHBhcnNlUm91dGluZ0RhdGEsIHBhcnNlSG9zdGVkVXJsLCBidWlsZEZpbGVVcmwsIGdldENvbmZpZ1ZlcnNpb24sIGdldFJvdXRlLCByb3V0ZUNvbnRhaW5zLCByb3V0ZUludGVyc2VjdGlvbiB9IGZyb20gXCIuL3JlbW90ZUNvbmZpZ1wiO1xuaW1wb3J0IHsgY3JlYXRlQXBpQXJjaGl2ZXMgfSBmcm9tIFwiLi9jcmVhdGVBcmNoaXZlc1wiO1xuaW1wb3J0IHR5cGUgeyBJU3RvcmFnZSB9IGZyb20gXCIuLi9JU3RvcmFnZVwiO1xuaW1wb3J0IHR5cGUgeyBBY2Nlc3NSZXF1ZXN0LCBUcnVzdFJlY29yZCB9IGZyb20gXCIuL3N0b3JhZ2VDb250cm9sbGVyXCI7XG5pbXBvcnQgeyBnZXRBcmcgfSBmcm9tIFwiLi9jbGlBcmdzXCI7XG5cbi8vIFRoZSBzdG9yYWdlIHNlcnZlcidzIGdsb2JhbCBzZXJ2ZXItc2lkZSBzdGF0ZS4gaG9zdFN0b3JhZ2VTZXJ2ZXIgc2V0cyB0aGUgY29uZmlnIG9uY2UgYXRcbi8vIHN0YXJ0dXA7IGV2ZXJ5dGhpbmcgZWxzZSAoc3lzdGVtIHN0b3JhZ2VzLCBidWNrZXRzKSBpcyBhIGdsb2JhbCBjYWNoZSBjcmVhdGVkIGxhemlseSBvbiBmaXJzdFxuLy8gdXNlLCB0aHJvd2luZyBpZiB0aGUgY29uZmlnIHdhcyBuZXZlciBzZXQuXG4vL1xuLy8gQnVja2V0cyBoYXZlIG5vIHNlcGFyYXRlIHJlZ2lzdHJ5OiBlYWNoIGJ1Y2tldCdzIGNvbmZpZ3VyYXRpb24gKGEgUmVtb3RlQ29uZmlnKSBsaXZlcyBpbnNpZGUgdGhlXG4vLyBidWNrZXQgaXRzZWxmLCBhdCBST1VUSU5HX0ZJTEUuIEEgYnVja2V0IGV4aXN0cyBpZmYgdGhhdCBmaWxlIGV4aXN0cy4gV3JpdGluZyBpdCBjcmVhdGVzIHRoZVxuLy8gYnVja2V0IChidWlsZGluZyBpdHMgc3RvcmUsIHdoaWNoIG1heSBpbW1lZGlhdGVseSBzdGFydCBzeW5jaHJvbml6YXRpb24gc2NhbnMpOyBvdmVyd3JpdGluZyBpdCDigJRcbi8vIGRpcmVjdGx5IG9yIHZpYSBhIGZpbGUgcHVsbGVkIGluIGZyb20gYSBzeW5jaHJvbml6YXRpb24gc291cmNlIOKAlCByZWJ1aWxkcyB0aGUgc3RvcmUgd2l0aCB0aGUgbmV3XG4vLyBzb3VyY2VzIChjYW5jZWxsaW5nIHRoZSBvbGQgc3RvcmUncyBzY2FucykuXG5cbmV4cG9ydCB0eXBlIFN0b3JhZ2VTZXJ2ZXJDb25maWcgPSB7XG4gICAgZG9tYWluOiBzdHJpbmc7XG4gICAgcG9ydDogbnVtYmVyO1xuICAgIHJvb3REb21haW46IHN0cmluZztcbiAgICAvLyB1c2VyQGV4dGVybmFsSXAgb2YgdGhlIHN0b3JhZ2UgbWFjaGluZSwgZm9yIGdlbmVyYXRlZCBzc2ggY29tbWFuZHNcbiAgICBzc2hUYXJnZXQ6IHN0cmluZztcbiAgICAvLyBBYnNvbHV0ZSBjb21tYW5kIHRoYXQgcnVucyB0aGUgZ3JhbnRBY2Nlc3MgQ0xJIG9uIHRoZSBzdG9yYWdlIG1hY2hpbmUgKGFkbWluIGFyZ3MgYXBwZW5kZWQpXG4gICAgc2VydmVyQ29tbWFuZDogc3RyaW5nO1xuICAgIC8vIFRoZSBzZXJ2ZXIncyByb290IHN0b3JhZ2UgZm9sZGVyIChhYnNvbHV0ZSlcbiAgICBmb2xkZXI6IHN0cmluZztcbn07XG5cbmxldCBjb25maWc6IFN0b3JhZ2VTZXJ2ZXJDb25maWcgfCB1bmRlZmluZWQ7XG5leHBvcnQgZnVuY3Rpb24gc2V0U3RvcmFnZVNlcnZlckNvbmZpZyh2YWx1ZTogU3RvcmFnZVNlcnZlckNvbmZpZyk6IHZvaWQge1xuICAgIGNvbmZpZyA9IHZhbHVlO1xufVxuZXhwb3J0IGZ1bmN0aW9uIGdldFN0b3JhZ2VTZXJ2ZXJDb25maWcoKTogU3RvcmFnZVNlcnZlckNvbmZpZyB7XG4gICAgaWYgKCFjb25maWcpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBTdG9yYWdlIHNlcnZlciBpcyBub3QgaW5pdGlhbGl6ZWQgKHRoaXMgQVBJIG9ubHkgd29ya3Mgb24gdGhlIHN0b3JhZ2Ugc2VydmVyKWApO1xuICAgIH1cbiAgICByZXR1cm4gY29uZmlnO1xufVxuLy8gRm9yIHNlbGYtZGV0ZWN0aW9uOiBjb2RlIHRoYXQgQ0FOIHJ1biBvdXRzaWRlIHRoZSBzdG9yYWdlIHNlcnZlciAoY3JlYXRlQXJjaGl2ZXMpIHVzZXMgdGhpcyB0b1xuLy8gY2hlY2sgXCJpcyB0aGlzIFVSTCBvdXIgb3duIHByb2Nlc3M/XCIgd2l0aG91dCB0aHJvd2luZy5cbmV4cG9ydCBmdW5jdGlvbiBnZXRTdG9yYWdlU2VydmVyQ29uZmlnT3B0aW9uYWwoKTogU3RvcmFnZVNlcnZlckNvbmZpZyB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIGNvbmZpZztcbn1cblxuLy8gV2hlbiBzZXQsIGFsbCB3cml0ZS1wYXRoIG9wZXJhdGlvbnMgKGNyZWF0aW5nIGZpbGVzLCBhcHBlbmRpbmcgbGFyZ2UgdXBsb2FkcywgY3JlYXRpbmcgYnVja2V0cylcbi8vIHRocm93IHRoaXMgbWVzc2FnZS4gUmVhZHMsIGZpbmRJbmZvLCBhbmQgZGVsZXRlcyBzdGlsbCB3b3JrIOKAlCBzbyBjbGllbnRzIGNhbiBmcmVlIHNwYWNlLiBNYW5hZ2VkXG4vLyBieSBob3N0U3RvcmFnZVNlcnZlcidzIGRpc2stc3BhY2UgbW9uaXRvci5cbmxldCB3cml0ZXNSZWplY3RlZFJlYXNvbjogc3RyaW5nIHwgdW5kZWZpbmVkO1xuZXhwb3J0IGZ1bmN0aW9uIHNldFdyaXRlc1JlamVjdGVkUmVhc29uKHJlYXNvbjogc3RyaW5nIHwgdW5kZWZpbmVkKTogdm9pZCB7XG4gICAgd3JpdGVzUmVqZWN0ZWRSZWFzb24gPSByZWFzb247XG59XG5leHBvcnQgZnVuY3Rpb24gZ2V0V3JpdGVzUmVqZWN0ZWRSZWFzb24oKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gd3JpdGVzUmVqZWN0ZWRSZWFzb247XG59XG5leHBvcnQgZnVuY3Rpb24gYXNzZXJ0V3JpdGVzQWxsb3dlZCgpOiB2b2lkIHtcbiAgICBpZiAod3JpdGVzUmVqZWN0ZWRSZWFzb24pIHRocm93IG5ldyBFcnJvcih3cml0ZXNSZWplY3RlZFJlYXNvbik7XG59XG5cbi8vIFRoZSBzeXN0ZW0gc3RvcmFnZXMgKHRydXN0LCByZXF1ZXN0cykgYXJlIHRoZSBzYW1lIGtpbmQgb2YgdGhpbmcg4oCUIGEgSlNPTiBrZXkvdmFsdWUgc3RvcmUgdW5kZXJcbi8vIDxmb2xkZXI+L3N5c3RlbTIvPG5hbWU+IOKAlCBzbyB0aGV5IHNoYXJlIG9uZSBjYWNoZSwga2V5ZWQgYnkgbmFtZS4gKFwic3lzdGVtMlwiIGJlY2F1c2UgdGhlIGxheW91dFxuLy8gY2hhbmdlZCB3aGVuIGJ1Y2tldCBjb25maWdzIG1vdmVkIGludG8gdGhlIGJ1Y2tldHMgdGhlbXNlbHZlczsgb2xkIFwic3lzdGVtXCIvXCJidWNrZXRzXCIgZm9sZGVyc1xuLy8gYXJlIHNpbXBseSBpZ25vcmVkLilcbi8vIHNldFRydXN0ZWRNYWNoaW5lcyBpcyBjYWxsZWQgYnkgY29uc3VtZXJzIEJFRk9SRSBzdGFydGluZyB0aGUgc2VydmVyLCBzbyB3aGVuIHRoZSBjb25maWcgaXNuJ3Rcbi8vIHNldCB5ZXQgd2UgZmFsbCBiYWNrIHRvIHRoZSBzYW1lIC0tZm9sZGVyIGFyZyB0aGUgQ0xJIHN0YXJ0cyB0aGUgc2VydmVyIHdpdGguXG5mdW5jdGlvbiBnZXRTdG9yYWdlRm9sZGVyKCk6IHN0cmluZyB7XG4gICAgbGV0IGNvbmZpZyA9IGdldFN0b3JhZ2VTZXJ2ZXJDb25maWdPcHRpb25hbCgpO1xuICAgIGlmIChjb25maWcpIHJldHVybiBjb25maWcuZm9sZGVyO1xuICAgIGxldCBmb2xkZXIgPSBnZXRBcmcoXCJmb2xkZXJcIik7XG4gICAgaWYgKCFmb2xkZXIpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBTdG9yYWdlIHNlcnZlciBpcyBub3QgaW5pdGlhbGl6ZWQgYW5kIHRoZXJlIGlzIG5vIC0tZm9sZGVyIGFyZywgc28gdGhlIHN0b3JhZ2UgZm9sZGVyIGlzIHVua25vd25gKTtcbiAgICB9XG4gICAgcmV0dXJuIHBhdGgucmVzb2x2ZShmb2xkZXIpO1xufVxuXG5jb25zdCBzeXN0ZW1TdG9yYWdlcyA9IG5ldyBNYXA8c3RyaW5nLCBQcm9taXNlPElTdG9yYWdlPHVua25vd24+Pj4oKTtcbmZ1bmN0aW9uIGdldFN5c3RlbVN0b3JhZ2U8VD4obmFtZTogc3RyaW5nKTogUHJvbWlzZTxJU3RvcmFnZTxUPj4ge1xuICAgIGxldCBzdG9yYWdlID0gc3lzdGVtU3RvcmFnZXMuZ2V0KG5hbWUpO1xuICAgIGlmICghc3RvcmFnZSkge1xuICAgICAgICBzdG9yYWdlID0gKGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgIGxldCByb290ID0gYXdhaXQgZ2V0RmlsZVN0b3JhZ2VOZXN0ZWQyKGdldFN0b3JhZ2VGb2xkZXIoKSk7XG4gICAgICAgICAgICBsZXQgc3lzdGVtID0gYXdhaXQgcm9vdC5mb2xkZXIuZ2V0U3RvcmFnZShcInN5c3RlbTJcIik7XG4gICAgICAgICAgICBsZXQgdHJhbnNhY3Rpb25OYW1lID0gXCJzdG9yYWdlXCIgKyBuYW1lWzBdLnRvVXBwZXJDYXNlKCkgKyBuYW1lLnNsaWNlKDEpO1xuICAgICAgICAgICAgcmV0dXJuIG5ldyBKU09OU3RvcmFnZTx1bmtub3duPihuZXcgVHJhbnNhY3Rpb25TdG9yYWdlKGF3YWl0IHN5c3RlbS5mb2xkZXIuZ2V0U3RvcmFnZShuYW1lKSwgdHJhbnNhY3Rpb25OYW1lKSk7XG4gICAgICAgIH0pKCk7XG4gICAgICAgIHN5c3RlbVN0b3JhZ2VzLnNldChuYW1lLCBzdG9yYWdlKTtcbiAgICB9XG4gICAgcmV0dXJuIHN0b3JhZ2UgYXMgUHJvbWlzZTxJU3RvcmFnZTxUPj47XG59XG5leHBvcnQgZnVuY3Rpb24gZ2V0VHJ1c3QoKTogUHJvbWlzZTxJU3RvcmFnZTxUcnVzdFJlY29yZD4+IHtcbiAgICByZXR1cm4gZ2V0U3lzdGVtU3RvcmFnZTxUcnVzdFJlY29yZD4oXCJ0cnVzdFwiKTtcbn1cbmV4cG9ydCBmdW5jdGlvbiBnZXRSZXF1ZXN0cygpOiBQcm9taXNlPElTdG9yYWdlPEFjY2Vzc1JlcXVlc3RbXT4+IHtcbiAgICByZXR1cm4gZ2V0U3lzdGVtU3RvcmFnZTxBY2Nlc3NSZXF1ZXN0W10+KFwicmVxdWVzdHNcIik7XG59XG5cbi8qKiBNYWtlcyBtYWNoaW5lSWRzIHRoZSBjb21wbGV0ZSB0cnVzdCBsaXN0IGZvciB0aGUgYWNjb3VudDogbWFjaGluZXMgbm90IGluIHRoZSBsaXN0IGxvc2UgYWNjZXNzLCBtYWNoaW5lcyBhbHJlYWR5IHRydXN0ZWQga2VlcCB0aGVpciBleGlzdGluZyByZWNvcmQsIGFuZCBtaXNzaW5nIG9uZXMgYXJlIGFkZGVkLiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNldFRydXN0ZWRNYWNoaW5lcyhjb25maWc6IHsgYWNjb3VudDogc3RyaW5nOyBtYWNoaW5lSWRzOiBzdHJpbmdbXSB9KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgbGV0IHRydXN0ID0gYXdhaXQgZ2V0VHJ1c3QoKTtcbiAgICBsZXQgcHJlZml4ID0gYCR7Y29uZmlnLmFjY291bnR9fGA7XG4gICAgbGV0IGRlc2lyZWQgPSBuZXcgU2V0KGNvbmZpZy5tYWNoaW5lSWRzKTtcbiAgICBmb3IgKGxldCBrZXkgb2YgYXdhaXQgdHJ1c3QuZ2V0S2V5cygpKSB7XG4gICAgICAgIGlmICgha2V5LnN0YXJ0c1dpdGgocHJlZml4KSkgY29udGludWU7XG4gICAgICAgIGxldCBtYWNoaW5lSWQgPSBrZXkuc2xpY2UocHJlZml4Lmxlbmd0aCk7XG4gICAgICAgIGlmIChkZXNpcmVkLmhhcyhtYWNoaW5lSWQpKSB7XG4gICAgICAgICAgICBkZXNpcmVkLmRlbGV0ZShtYWNoaW5lSWQpO1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgY29uc29sZS5sb2coYFJlbW92aW5nIHRydXN0IGZvciBtYWNoaW5lICR7bWFjaGluZUlkfSBvbiBhY2NvdW50ICR7Y29uZmlnLmFjY291bnR9YCk7XG4gICAgICAgIGF3YWl0IHRydXN0LnJlbW92ZShrZXkpO1xuICAgIH1cbiAgICBmb3IgKGxldCBtYWNoaW5lSWQgb2YgZGVzaXJlZCkge1xuICAgICAgICBjb25zb2xlLmxvZyhgQWRkaW5nIHRydXN0IGZvciBtYWNoaW5lICR7bWFjaGluZUlkfSBvbiBhY2NvdW50ICR7Y29uZmlnLmFjY291bnR9YCk7XG4gICAgICAgIGF3YWl0IHRydXN0LnNldChgJHtwcmVmaXh9JHttYWNoaW5lSWR9YCwgeyBhY2NvdW50OiBjb25maWcuYWNjb3VudCwgbWFjaGluZUlkLCBpcDogXCJcIiwgdGltZTogRGF0ZS5ub3coKSB9KTtcbiAgICB9XG59XG5cbi8vIOKUgOKUgCBidWNrZXRzIOKUgOKUgFxuXG5leHBvcnQgdHlwZSBMb2FkZWRCdWNrZXQgPSB7XG4gICAgYWNjb3VudDogc3RyaW5nO1xuICAgIGJ1Y2tldE5hbWU6IHN0cmluZztcbiAgICAvLyBUaGUgYnVja2V0J3MgcGFyc2VkIHJvdXRpbmcgY29uZmlnICh0aGUgY29udGVudHMgb2YgUk9VVElOR19GSUxFKVxuICAgIHJvdXRpbmc6IFJlbW90ZUNvbmZpZztcbiAgICAvLyBKU09OIG9mIHJvdXRpbmcsIGZvciBjaGFuZ2UgZGV0ZWN0aW9uXG4gICAgcm91dGluZ0pTT046IHN0cmluZztcbiAgICAvLyBBTEwgb2Ygb3VyIG93biBlbnRyaWVzIGluIHJvdXRpbmcuc291cmNlcyAodGhpcyBidWNrZXQgb24gdGhpcyBzZXJ2ZXIpLiBNb3JlIHRoYW4gb25lIHdoZW5cbiAgICAvLyB0aGUgYnVja2V0J3Mgb3B0aW9ucyBjaGFuZ2Ugb3ZlciB0aW1lIC0gb25lIGVudHJ5IHBlciB2YWxpZCB3aW5kb3cgKGUuZy4gaW1tdXRhYmxlIGRyb3BwZWQsXG4gICAgLy8gb3IgZmFzdCBlbmFibGVkLCBzdGFydGluZyBhdCBhIHNjaGVkdWxlZCBpbnN0YW50KS5cbiAgICBzZWxmRW50cmllczogSG9zdGVkQ29uZmlnW107XG4gICAgLy8gVGhlIGVudHJ5IHZhbGlkIHdoZW4gdGhlIHN0b3JlIHdhcyBidWlsdCAtIHRoZSBzdHJ1Y3R1cmFsIG9wdGlvbnMgKHJhd0Rpc2ssIHdoaWNoIGVudHJpZXNcbiAgICAvLyBhcmUgZG93bnN0cmVhbSkuIFBlci13cml0ZSBvcHRpb25zIChmYXN0L2ltbXV0YWJsZSkgYXJlIGluc3RlYWQgZXZhbHVhdGVkIGF0IGVhY2ggd3JpdGUnc1xuICAgIC8vIHRpbWUsIHNlZSBnZXRXcml0ZUNvbmZpZy9hc3NlcnRNdXRhYmxlLiB1bmRlZmluZWQgd2hlbiB0aGUgY29uZmlnIGRvZXNuJ3QgbWVudGlvbiB1cy5cbiAgICBzZWxmOiBIb3N0ZWRDb25maWcgfCB1bmRlZmluZWQ7XG4gICAgc3RvcmU6IElCdWNrZXRTdG9yZTtcbn07XG5cbmNvbnN0IGJ1Y2tldHMgPSBuZXcgTWFwPHN0cmluZywgUHJvbWlzZTxMb2FkZWRCdWNrZXQgfCB1bmRlZmluZWQ+PigpO1xuXG4vLyBzZXRUaW1lb3V0IGNhbm5vdCByZXByZXNlbnQgbG9uZ2VyIGRlbGF5czsgbW9yZSBkaXN0YW50IHdpbmRvdyBib3VuZGFyaWVzIHJlLWNoZWNrIGFmdGVyIHRoaXNcbmNvbnN0IE1BWF9SRUJVSUxEX1RJTUVSX0RFTEFZID0gMiAqKiAzMSAtIDE7XG4vLyBSZWJ1aWxkIHNsaWdodGx5IGFmdGVyIHRoZSBib3VuZGFyeSwgc28gdGhlIG5ld2x5LXZhbGlkIGVudHJ5IGlzIHVuYW1iaWd1b3VzbHkgYWN0aXZlXG5jb25zdCBSRUJVSUxEX0JPVU5EQVJZX0JVRkZFUiA9IDEwMDA7XG5cbmZ1bmN0aW9uIGdldEJ1Y2tldEZvbGRlcihhY2NvdW50OiBzdHJpbmcsIGJ1Y2tldE5hbWU6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHBhdGguam9pbihnZXRTdG9yYWdlU2VydmVyQ29uZmlnKCkuZm9sZGVyLCBcImJ1Y2tldHMyXCIsIGFjY291bnQsIGJ1Y2tldE5hbWUpO1xufVxuXG5mdW5jdGlvbiBmaW5kU2VsZkluZGV4ZXMocm91dGluZzogUmVtb3RlQ29uZmlnLCBhY2NvdW50OiBzdHJpbmcsIGJ1Y2tldE5hbWU6IHN0cmluZyk6IG51bWJlcltdIHtcbiAgICBsZXQgeyBkb21haW4sIHBvcnQgfSA9IGdldFN0b3JhZ2VTZXJ2ZXJDb25maWcoKTtcbiAgICBsZXQgaW5kZXhlczogbnVtYmVyW10gPSBbXTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHJvdXRpbmcuc291cmNlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICBsZXQgc291cmNlID0gcm91dGluZy5zb3VyY2VzW2ldO1xuICAgICAgICBpZiAodHlwZW9mIHNvdXJjZSA9PT0gXCJzdHJpbmdcIiB8fCBzb3VyY2UudHlwZSAhPT0gXCJyZW1vdGVcIikgY29udGludWU7XG4gICAgICAgIGxldCBwYXJzZWQgPSBwYXJzZUhvc3RlZFVybChzb3VyY2UudXJsKTtcbiAgICAgICAgaWYgKHBhcnNlZC5hZGRyZXNzID09PSBkb21haW4gJiYgcGFyc2VkLnBvcnQgPT09IHBvcnQgJiYgcGFyc2VkLmFjY291bnQgPT09IGFjY291bnQgJiYgcGFyc2VkLmJ1Y2tldE5hbWUgPT09IGJ1Y2tldE5hbWUpIHtcbiAgICAgICAgICAgIGluZGV4ZXMucHVzaChpKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gaW5kZXhlcztcbn1cblxuLy8gVGhlIGVudHJ5IHdob3NlIHZhbGlkIHdpbmRvdyBjb250YWlucyB0aGUgdGltZSAoYW1vbmcgdGhlIGVudHJpZXMgY292ZXJpbmcgdGhlIGtleSdzIHJvdXRlLFxuLy8gd2hlbiBvbmUgaXMgZ2l2ZW4gLSBhIHNlcnZlciBjYW4gaG9sZCBkaWZmZXJlbnQgc2hhcmRzIHdpdGggZGlmZmVyZW50IG9wdGlvbnMpLiBIYWxmLW9wZW5cbi8vIChbc3RhcnQsIGVuZCkpLCBzbyBjbGVhbiBicmVha3MgcmVzb2x2ZSB1bmFtYmlndW91c2x5LiBGYWxscyBiYWNrIHRvIHRoZSBuZWFyZXN0IHdpbmRvdyB3aGVuXG4vLyBub25lIGNvbnRhaW5zIHRoZSB0aW1lIC0gZ2FwcyBzaG91bGRuJ3QgZXhpc3QsIGJ1dCBhIHdyaXRlIG11c3Qgc3RpbGwgcmVzb2x2ZSB0byBTT01FXG4vLyBjb25maWd1cmF0aW9uLlxuZnVuY3Rpb24gc2VsZWN0RW50cnlBdChlbnRyaWVzOiBIb3N0ZWRDb25maWdbXSwgdGltZTogbnVtYmVyLCByb3V0ZT86IG51bWJlcik6IEhvc3RlZENvbmZpZyB8IHVuZGVmaW5lZCB7XG4gICAgaWYgKHJvdXRlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgbGV0IGNvdmVyaW5nID0gZW50cmllcy5maWx0ZXIoeCA9PiByb3V0ZUNvbnRhaW5zKHgucm91dGUsIHJvdXRlKSk7XG4gICAgICAgIGlmIChjb3ZlcmluZy5sZW5ndGgpIHtcbiAgICAgICAgICAgIGVudHJpZXMgPSBjb3ZlcmluZztcbiAgICAgICAgfVxuICAgIH1cbiAgICBsZXQgY29udGFpbmluZyA9IGVudHJpZXMuZmluZCh4ID0+IHgudmFsaWRXaW5kb3dbMF0gPD0gdGltZSAmJiB0aW1lIDwgeC52YWxpZFdpbmRvd1sxXSk7XG4gICAgaWYgKGNvbnRhaW5pbmcpIHJldHVybiBjb250YWluaW5nO1xuICAgIGxldCBiZXN0OiBIb3N0ZWRDb25maWcgfCB1bmRlZmluZWQ7XG4gICAgbGV0IGJlc3REaXN0YW5jZSA9IEluZmluaXR5O1xuICAgIGZvciAobGV0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICAgICAgbGV0IGRpc3RhbmNlID0gTWF0aC5taW4oTWF0aC5hYnModGltZSAtIGVudHJ5LnZhbGlkV2luZG93WzBdKSwgTWF0aC5hYnModGltZSAtIGVudHJ5LnZhbGlkV2luZG93WzFdKSk7XG4gICAgICAgIGlmIChkaXN0YW5jZSA8IGJlc3REaXN0YW5jZSkge1xuICAgICAgICAgICAgYmVzdERpc3RhbmNlID0gZGlzdGFuY2U7XG4gICAgICAgICAgICBiZXN0ID0gZW50cnk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGJlc3Q7XG59XG5cbi8vIEJ1Y2tldCBvcHRpb25zIGNhbiBjaGFuZ2Ugb3ZlciB0aW1lIChtdWx0aXBsZSBzZWxmIGVudHJpZXMgd2l0aCBkaWZmZXJlbnQgdmFsaWQgd2luZG93cyksIGFuZFxuLy8gdGhlIHN0cnVjdHVyYWwgb25lcyAocmF3RGlzaywgdGhlIGRvd25zdHJlYW0gbGlzdCkgYXJlIGJha2VkIGludG8gdGhlIHN0b3JlIC0gc28gdGhlIHN0b3JlIGlzXG4vLyByZWJ1aWx0IHNob3J0bHkgYWZ0ZXIgZWFjaCBvZiBvdXIgd2luZG93IGJvdW5kYXJpZXMgcGFzc2VzLCBtYWtpbmcgdGhlIG5ld2x5LXZhbGlkIGVudHJ5IGFwcGx5LlxuZnVuY3Rpb24gc2NoZWR1bGVXaW5kb3dCb3VuZGFyeVJlYnVpbGQobG9hZGVkOiBMb2FkZWRCdWNrZXQpOiB2b2lkIHtcbiAgICBsZXQgbm93ID0gRGF0ZS5ub3coKTtcbiAgICBsZXQgYm91bmRhcmllcyA9IGxvYWRlZC5zZWxmRW50cmllcy5mbGF0TWFwKHggPT4geC52YWxpZFdpbmRvdykuZmlsdGVyKHQgPT4gdCA+IG5vdyk7XG4gICAgaWYgKCFib3VuZGFyaWVzLmxlbmd0aCkgcmV0dXJuO1xuICAgIGxldCBuZXh0Qm91bmRhcnkgPSBNYXRoLm1pbiguLi5ib3VuZGFyaWVzKTtcbiAgICBsZXQga2V5ID0gYCR7bG9hZGVkLmFjY291bnR9LyR7bG9hZGVkLmJ1Y2tldE5hbWV9YDtcbiAgICBsZXQgdGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgdm9pZCAoYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgLy8gQSByb3V0aW5nIGNoYW5nZSBtYXkgaGF2ZSBhbHJlYWR5IHJlcGxhY2VkIHRoaXMgc3RvcmU7IG9ubHkgSVQgZ2V0cyBhIGJvdW5kYXJ5IHRpbWVyXG4gICAgICAgICAgICBsZXQgY3VycmVudCA9IGF3YWl0IGJ1Y2tldHMuZ2V0KGtleSk7XG4gICAgICAgICAgICBpZiAoY3VycmVudCAhPT0gbG9hZGVkKSByZXR1cm47XG4gICAgICAgICAgICBpZiAoRGF0ZS5ub3coKSA8IG5leHRCb3VuZGFyeSkge1xuICAgICAgICAgICAgICAgIHNjaGVkdWxlV2luZG93Qm91bmRhcnlSZWJ1aWxkKGxvYWRlZCk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYXdhaXQgc2NoZWR1bGVSb3V0aW5nUmVsb2FkKGxvYWRlZC5hY2NvdW50LCBsb2FkZWQuYnVja2V0TmFtZSwgeyBmb3JjZTogdHJ1ZSB9KTtcbiAgICAgICAgfSkoKTtcbiAgICB9LCBNYXRoLm1pbihuZXh0Qm91bmRhcnkgLSBub3cgKyBSRUJVSUxEX0JPVU5EQVJZX0JVRkZFUiwgTUFYX1JFQlVJTERfVElNRVJfREVMQVkpKTtcbiAgICAodGltZXIgYXMgeyB1bnJlZj86ICgpID0+IHZvaWQgfSkudW5yZWY/LigpO1xufVxuXG5mdW5jdGlvbiBidWlsZEJ1Y2tldChhY2NvdW50OiBzdHJpbmcsIGJ1Y2tldE5hbWU6IHN0cmluZywgcm91dGluZzogUmVtb3RlQ29uZmlnKTogTG9hZGVkQnVja2V0IHtcbiAgICBsZXQgZm9sZGVyID0gZ2V0QnVja2V0Rm9sZGVyKGFjY291bnQsIGJ1Y2tldE5hbWUpO1xuICAgIGxldCBzZWxmSW5kZXhlcyA9IGZpbmRTZWxmSW5kZXhlcyhyb3V0aW5nLCBhY2NvdW50LCBidWNrZXROYW1lKTtcbiAgICBsZXQgc2VsZkVudHJpZXMgPSBzZWxmSW5kZXhlcy5tYXAoaSA9PiByb3V0aW5nLnNvdXJjZXNbaV0gYXMgSG9zdGVkQ29uZmlnKTtcbiAgICBsZXQgc2VsZiA9IHNlbGVjdEVudHJ5QXQoc2VsZkVudHJpZXMsIERhdGUubm93KCkpO1xuICAgIGxldCBzZWxmSW5kZXggPSAtMTtcbiAgICBpZiAoc2VsZikge1xuICAgICAgICBzZWxmSW5kZXggPSByb3V0aW5nLnNvdXJjZXMuaW5kZXhPZihzZWxmKTtcbiAgICB9XG4gICAgbGV0IHN0b3JlOiBJQnVja2V0U3RvcmU7XG4gICAgaWYgKHNlbGY/LnJhd0Rpc2spIHtcbiAgICAgICAgc3RvcmUgPSBuZXcgQXJjaGl2ZXNEaXNrKGZvbGRlcik7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgLy8gT3VyIG93biBkaXNrIGlzIHRoZSBiYXNlIHNvdXJjZTsgb25seSB0aGUgcm91dGluZyBlbnRyaWVzIERPV05TVFJFQU0gZnJvbSB1cyAoYWZ0ZXIgb3VyXG4gICAgICAgIC8vIGN1cnJlbnRseS12YWxpZCBlbnRyeSkgYmVjb21lIHN5bmNocm9uaXphdGlvbiBzb3VyY2VzLiBVcHN0cmVhbSBzb3VyY2VzIHN5bmMgZnJvbSB1cywgc29cbiAgICAgICAgLy8gd3JpdGluZyB0byBvciBzY2FubmluZyB0aGVtIHdvdWxkIGp1c3QgZWNobyBvdXIgb3duIGRhdGEgYmFjayAoYW5kIG1ha2Ugb3VyIGF2YWlsYWJpbGl0eVxuICAgICAgICAvLyBkZXBlbmQgb24gdGhlaXJzKS4gQSBzZXJ2ZXIgTk9UIGluIHRoZSBsaXN0IGhhcyBiZWVuIHJlbW92ZWQgZnJvbSB0aGUgYnVja2V0OiBpdCBrZWVwc1xuICAgICAgICAvLyBpdHMgZGlzayBkYXRhICh0aGUgY29uZmlnIG1heSByZS1hZGQgaXQpLCBidXQgc3RvcHMgYWxsIHN5bmNocm9uaXphdGlvbiAtIG5vIG9uZVxuICAgICAgICAvLyBjb250YWN0cyBhIHJlbW92ZWQgc291cmNlLCBhbmQgc2Nhbm5pbmcvcHVzaGluZyBhcyBpZiB3ZSB3ZXJlIHN0aWxsIG9uZSB3b3VsZCBmaWdodCB0aGVcbiAgICAgICAgLy8gcmVhbCBjaGFpbi4gVGhlIGNvbmZpZy1sZXZlbCB2YWxpZFdpbmRvdyByaWRlcyBvbiBlYWNoIEFyY2hpdmVzU291cmNlOyB0aGUgZGlzayBzb3VyY2VcbiAgICAgICAgLy8gc2hhcmVzIG91ciBjdXJyZW50bHktdmFsaWQgZW50cnkncyB3aW5kb3cgKGl0IGhvbGRzIG91ciBjb3B5IG9mIHRoZSBkYXRhKS5cbiAgICAgICAgbGV0IG93bkluZGV4ZXMgPSBuZXcgU2V0KHNlbGZJbmRleGVzKTtcbiAgICAgICAgLy8gT3VyIG93biBkaXNrIGdldHMgbm8gcm91dGUgZmlsdGVyOiBldmVyeXRoaW5nIGl0IGhvbGRzIGlzIG91cnMgdG8gaW5kZXggYW5kIHNlcnZlXG4gICAgICAgIGxldCBzb3VyY2VzOiBBcmNoaXZlc1NvdXJjZVtdID0gW3tcbiAgICAgICAgICAgIHNvdXJjZTogbmV3IEFyY2hpdmVzRGlzayhmb2xkZXIpLFxuICAgICAgICAgICAgdmFsaWRXaW5kb3c6IHNlbGY/LnZhbGlkV2luZG93IHx8IEZVTExfVkFMSURfV0lORE9XLFxuICAgICAgICB9XTtcbiAgICAgICAgaWYgKHNlbGZJbmRleCA9PT0gLTEpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKGBUaGlzIHNlcnZlciBpcyBub3QgaW4gdGhlIHJvdXRpbmcgY29uZmlnIGZvciBidWNrZXQgJHthY2NvdW50fS8ke2J1Y2tldE5hbWV9OyBrZWVwaW5nIGl0cyBkYXRhIG9uIGRpc2sgYnV0IG5vIGxvbmdlciBzeW5jaHJvbml6aW5nIGl0YCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBmb3IgKGxldCBpID0gc2VsZkluZGV4ICsgMTsgaSA8IHJvdXRpbmcuc291cmNlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIGxldCBzb3VyY2UgPSByb3V0aW5nLnNvdXJjZXNbaV07XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBzb3VyY2UgPT09IFwic3RyaW5nXCIgfHwgb3duSW5kZXhlcy5oYXMoaSkpIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgIC8vIERpc2pvaW50LXNoYXJkIHNvdXJjZXMgbmV2ZXIgdGFsayB0byBlYWNoIG90aGVyOyBhIHBhcnRpYWwgb3ZlcmxhcCBzeW5jcyBvbmx5XG4gICAgICAgICAgICAgICAgLy8gdGhlIGludGVyc2VjdGlvbiAoc2NhbnMgaWdub3JlIHRoZSByZXN0LCB3cml0ZXMgb25seSBzZW5kIG1hdGNoaW5nIGtleXMpXG4gICAgICAgICAgICAgICAgbGV0IHNoYXJlZFJvdXRlID0gcm91dGVJbnRlcnNlY3Rpb24oc2VsZj8ucm91dGUsIHNvdXJjZS5yb3V0ZSk7XG4gICAgICAgICAgICAgICAgaWYgKCFzaGFyZWRSb3V0ZSkgY29udGludWU7XG4gICAgICAgICAgICAgICAgLy8gQSBib3VuZGVkLWNhY2hlIHNlcnZlciAobm9GdWxsU3luYyBvbiBvdXIgb3duIGVudHJ5KSBtdXN0IG5vdCBmdWxsLXN5bmMgZnJvbVxuICAgICAgICAgICAgICAgIC8vIEFOWSBzb3VyY2UsIG9yIGl0cyBkaXNrIHdvdWxkIGZpbGwgcmVnYXJkbGVzcyBvZiB0aGUgbGltaXRcbiAgICAgICAgICAgICAgICBzb3VyY2VzLnB1c2goeyBzb3VyY2U6IGNyZWF0ZUFwaUFyY2hpdmVzKHNvdXJjZSksIHZhbGlkV2luZG93OiBzb3VyY2UudmFsaWRXaW5kb3csIHJvdXRlOiBzaGFyZWRSb3V0ZSwgbm9GdWxsU3luYzogc291cmNlLm5vRnVsbFN5bmMgfHwgc2VsZj8ubm9GdWxsU3luYyB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBzdG9yZSA9IG5ldyBCbG9iU3RvcmUoZm9sZGVyLCBzb3VyY2VzLCB7XG4gICAgICAgICAgICBvbkluZGV4Q2hhbmdlZDoga2V5ID0+IHtcbiAgICAgICAgICAgICAgICAvLyBGaXJlcyBmb3Igb3VyIG93biByb3V0aW5nIHdyaXRlcyBBTkQgcm91dGluZyBmaWxlcyBwdWxsZWQgaW4gdmlhIHN5bmNocm9uaXphdGlvblxuICAgICAgICAgICAgICAgIC8vIChvbmx5IGV2ZXIgbmV3ZXIgb25lcywgc2VlIElBcmNoaXZlcy5zZXQpIOKAlCBlaXRoZXIgd2F5LCBhcHBseSB0aGUgbmV3IGNvbmZpZ1xuICAgICAgICAgICAgICAgIGlmIChrZXkgIT09IFJPVVRJTkdfRklMRSkgcmV0dXJuO1xuICAgICAgICAgICAgICAgIHZvaWQgc2NoZWR1bGVSb3V0aW5nUmVsb2FkKGFjY291bnQsIGJ1Y2tldE5hbWUpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHJlYWRlckRpc2tMaW1pdDogc2VsZj8ucmVhZGVyRGlza0xpbWl0LFxuICAgICAgICB9KTtcbiAgICB9XG4gICAgbGV0IGxvYWRlZDogTG9hZGVkQnVja2V0ID0geyBhY2NvdW50LCBidWNrZXROYW1lLCByb3V0aW5nLCByb3V0aW5nSlNPTjogSlNPTi5zdHJpbmdpZnkocm91dGluZyksIHNlbGZFbnRyaWVzLCBzZWxmLCBzdG9yZSB9O1xuICAgIHNjaGVkdWxlV2luZG93Qm91bmRhcnlSZWJ1aWxkKGxvYWRlZCk7XG4gICAgcmV0dXJuIGxvYWRlZDtcbn1cblxuYXN5bmMgZnVuY3Rpb24gbG9hZEJ1Y2tldChhY2NvdW50OiBzdHJpbmcsIGJ1Y2tldE5hbWU6IHN0cmluZyk6IFByb21pc2U8TG9hZGVkQnVja2V0IHwgdW5kZWZpbmVkPiB7XG4gICAgbGV0IGRhdGEgPSBhd2FpdCBuZXcgQXJjaGl2ZXNEaXNrKGdldEJ1Y2tldEZvbGRlcihhY2NvdW50LCBidWNrZXROYW1lKSkuZ2V0KFJPVVRJTkdfRklMRSk7XG4gICAgaWYgKCFkYXRhKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgIHJldHVybiBidWlsZEJ1Y2tldChhY2NvdW50LCBidWNrZXROYW1lLCBwYXJzZVJvdXRpbmdEYXRhKGRhdGEpKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldExvYWRlZEJ1Y2tldChhY2NvdW50OiBzdHJpbmcsIGJ1Y2tldE5hbWU6IHN0cmluZyk6IFByb21pc2U8TG9hZGVkQnVja2V0IHwgdW5kZWZpbmVkPiB7XG4gICAgbGV0IGtleSA9IGAke2FjY291bnR9LyR7YnVja2V0TmFtZX1gO1xuICAgIGxldCBsb2FkZWQgPSBidWNrZXRzLmdldChrZXkpO1xuICAgIGlmICghbG9hZGVkKSB7XG4gICAgICAgIGxvYWRlZCA9IGxvYWRCdWNrZXQoYWNjb3VudCwgYnVja2V0TmFtZSk7XG4gICAgICAgIGJ1Y2tldHMuc2V0KGtleSwgbG9hZGVkKTtcbiAgICAgICAgLy8gTWlzc2luZyBidWNrZXRzIGFyZSBub3QgY2FjaGVkIOKAlCB0aGV5IGNhbiBiZSBjcmVhdGVkIGF0IGFueSB0aW1lIChndWFyZGluZyBhZ2FpbnN0IGFcbiAgICAgICAgLy8gY29uY3VycmVudCBjcmVhdGUgaGF2aW5nIGFscmVhZHkgcmVwbGFjZWQgb3VyIGVudHJ5KVxuICAgICAgICB2b2lkIGxvYWRlZC50aGVuKGJ1Y2tldCA9PiB7XG4gICAgICAgICAgICBpZiAoIWJ1Y2tldCAmJiBidWNrZXRzLmdldChrZXkpID09PSBsb2FkZWQpIHtcbiAgICAgICAgICAgICAgICBidWNrZXRzLmRlbGV0ZShrZXkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LCAoKSA9PiB7XG4gICAgICAgICAgICBpZiAoYnVja2V0cy5nZXQoa2V5KSA9PT0gbG9hZGVkKSB7XG4gICAgICAgICAgICAgICAgYnVja2V0cy5kZWxldGUoa2V5KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuICAgIHJldHVybiBsb2FkZWQ7XG59XG5cbi8vIFJvdXRpbmcgcmVsb2FkcyBhcmUgc2VyaWFsaXplZCBwZXIgYnVja2V0LCBzbyBjb25jdXJyZW50IHdyaXRlcy9zeW5jcyBjYW4ndCByZWJ1aWxkIHRoZSBzYW1lXG4vLyBzdG9yZSB0d2ljZSBpbiBwYXJhbGxlbFxuY29uc3Qgcm91dGluZ1JlbG9hZHMgPSBuZXcgTWFwPHN0cmluZywgUHJvbWlzZTx2b2lkPj4oKTtcbmZ1bmN0aW9uIHNjaGVkdWxlUm91dGluZ1JlbG9hZChhY2NvdW50OiBzdHJpbmcsIGJ1Y2tldE5hbWU6IHN0cmluZywgY29uZmlnPzogeyBmb3JjZT86IGJvb2xlYW4gfSk6IFByb21pc2U8dm9pZD4ge1xuICAgIGxldCBrZXkgPSBgJHthY2NvdW50fS8ke2J1Y2tldE5hbWV9YDtcbiAgICBsZXQgbmV4dCA9IChyb3V0aW5nUmVsb2Fkcy5nZXQoa2V5KSB8fCBQcm9taXNlLnJlc29sdmUoKSlcbiAgICAgICAgLnRoZW4oKCkgPT4gY2hlY2tSb3V0aW5nQ2hhbmdlZChhY2NvdW50LCBidWNrZXROYW1lLCBjb25maWc/LmZvcmNlKSlcbiAgICAgICAgLmNhdGNoKGUgPT4gY29uc29sZS5lcnJvcihgUmVsb2FkaW5nIHJvdXRpbmcgY29uZmlnIGZvciBidWNrZXQgJHtrZXl9IGZhaWxlZDpgLCBlKSk7XG4gICAgcm91dGluZ1JlbG9hZHMuc2V0KGtleSwgbmV4dCk7XG4gICAgcmV0dXJuIG5leHQ7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGNoZWNrUm91dGluZ0NoYW5nZWQoYWNjb3VudDogc3RyaW5nLCBidWNrZXROYW1lOiBzdHJpbmcsIGZvcmNlPzogYm9vbGVhbik6IFByb21pc2U8dm9pZD4ge1xuICAgIGxldCBrZXkgPSBgJHthY2NvdW50fS8ke2J1Y2tldE5hbWV9YDtcbiAgICBsZXQgbG9hZGVkID0gYXdhaXQgYnVja2V0cy5nZXQoa2V5KTtcbiAgICBpZiAoIWxvYWRlZCkgcmV0dXJuO1xuICAgIC8vIGdldCgpIGNhY2hlLXJlYWRzIHRoZSBmaWxlIG9udG8gb3VyIGRpc2sgd2hlbiBhIHJlbW90ZSBzb3VyY2UgaG9sZHMgaXQsIHNvIHRoZSBidWNrZXQgc3RpbGxcbiAgICAvLyBleGlzdHMgYWZ0ZXIgYSByZXN0YXJ0XG4gICAgbGV0IGRhdGEgPSBhd2FpdCBsb2FkZWQuc3RvcmUuZ2V0KFJPVVRJTkdfRklMRSk7XG4gICAgaWYgKCFkYXRhKSByZXR1cm47XG4gICAgbGV0IHJvdXRpbmcgPSBwYXJzZVJvdXRpbmdEYXRhKGRhdGEpO1xuICAgIGlmICghZm9yY2UgJiYgSlNPTi5zdHJpbmdpZnkocm91dGluZykgPT09IGxvYWRlZC5yb3V0aW5nSlNPTikgcmV0dXJuO1xuICAgIGlmIChmb3JjZSkge1xuICAgICAgICBjb25zb2xlLmxvZyhgUmVidWlsZGluZyB0aGUgc3RvcmUgZm9yIGJ1Y2tldCAke2tleX0gKGEgdmFsaWQgd2luZG93IGJvdW5kYXJ5IHBhc3NlZClgKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBjb25zb2xlLmxvZyhgUm91dGluZyBjb25maWcgY2hhbmdlZCBmb3IgYnVja2V0ICR7a2V5fSwgcmVidWlsZGluZyBpdHMgc3RvcmVgKTtcbiAgICB9XG4gICAgaWYgKGxvYWRlZC5zdG9yZSBpbnN0YW5jZW9mIEJsb2JTdG9yZSkge1xuICAgICAgICBhd2FpdCBsb2FkZWQuc3RvcmUuZGlzcG9zZSgpO1xuICAgIH1cbiAgICBidWNrZXRzLnNldChrZXksIFByb21pc2UucmVzb2x2ZShidWlsZEJ1Y2tldChhY2NvdW50LCBidWNrZXROYW1lLCByb3V0aW5nKSkpO1xufVxuXG4vLyBQZXItd3JpdGUgb3B0aW9ucyBhcmUgZXZhbHVhdGVkIGF0IHRoZSBXUklURSdzIHRpbWUgKGFuZCB0aGUga2V5J3Mgcm91dGUpLCBub3QgdGhlIGN1cnJlbnRcbi8vIGNvbmZpZzogdGhlIHdyaXRlIHRpbWUgaXMgc3RhbXBlZCBleGFjdGx5IG9uY2UgKGF0IHRoZSBmaXJzdCBub2RlIHRoYXQgcmVjZWl2ZXMgdGhlIHdyaXRlKSBhbmRcbi8vIHByb3BhZ2F0ZXMgd2l0aCB0aGUgZGF0YSwgc28gZXZlcnkgbm9kZSByZXNvbHZlcyB0aGUgc2FtZSBzZWxmIGVudHJ5IC0gYW5kIHRoZSBzYW1lIG9wdGlvbnMuXG5mdW5jdGlvbiBnZXRXcml0ZUNvbmZpZyhidWNrZXQ6IExvYWRlZEJ1Y2tldCwgd3JpdGVUaW1lOiBudW1iZXIsIHJvdXRlOiBudW1iZXIpOiB7IGZhc3Q/OiBib29sZWFuOyB3cml0ZURlbGF5PzogbnVtYmVyIH0ge1xuICAgIGxldCBzZWxmID0gc2VsZWN0RW50cnlBdChidWNrZXQuc2VsZkVudHJpZXMsIHdyaXRlVGltZSwgcm91dGUpO1xuICAgIHJldHVybiB7IGZhc3Q6IHNlbGY/LmZhc3QsIHdyaXRlRGVsYXk6IHNlbGY/LndyaXRlRGVsYXkgfTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGFzc2VydE11dGFibGUoYnVja2V0OiBMb2FkZWRCdWNrZXQsIGZpbGVQYXRoOiBzdHJpbmcsIHdyaXRlVGltZTogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgbGV0IHNlbGYgPSBzZWxlY3RFbnRyeUF0KGJ1Y2tldC5zZWxmRW50cmllcywgd3JpdGVUaW1lLCBnZXRSb3V0ZShmaWxlUGF0aCkpO1xuICAgIGlmICghc2VsZj8uaW1tdXRhYmxlKSByZXR1cm47XG4gICAgaWYgKGF3YWl0IGJ1Y2tldC5zdG9yZS5nZXRJbmZvKGZpbGVQYXRoKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEJ1Y2tldCAke2J1Y2tldC5hY2NvdW50fS8ke2J1Y2tldC5idWNrZXROYW1lfSBpcyBpbW11dGFibGUgKGF0IHdyaXRlIHRpbWUgJHt3cml0ZVRpbWV9KSBhbmQgJHtKU09OLnN0cmluZ2lmeShmaWxlUGF0aCl9IGFscmVhZHkgZXhpc3RzLCBzbyBpdCBjYW5ub3QgYmUgd3JpdHRlbiB0b2ApO1xuICAgIH1cbn1cblxuLy8gUm91dGluZyB3cml0ZXMgYXJlIHNlcmlhbGl6ZWQgcGVyIGJ1Y2tldCwgc28gdHdvIGNvbmN1cnJlbnQgY3JlYXRlcyBjYW4ndCBib3RoIGJ1aWxkIGEgc3RvcmVcbi8vICh0aGUgbG9zZXIncyBzdG9yZSB3b3VsZCBsZWFrIHdpdGggaXRzIHN5bmMgbG9vcHMgcnVubmluZyBmb3JldmVyKVxuY29uc3Qgcm91dGluZ1dyaXRlcyA9IG5ldyBNYXA8c3RyaW5nLCBQcm9taXNlPHZvaWQ+PigpO1xuXG5hc3luYyBmdW5jdGlvbiB3cml0ZVJvdXRpbmdDb25maWcoYWNjb3VudDogc3RyaW5nLCBidWNrZXROYW1lOiBzdHJpbmcsIGRhdGE6IEJ1ZmZlciwgY29uZmlnPzogeyBsYXN0TW9kaWZpZWQ/OiBudW1iZXIgfSk6IFByb21pc2U8dm9pZD4ge1xuICAgIGxldCBrZXkgPSBgJHthY2NvdW50fS8ke2J1Y2tldE5hbWV9YDtcbiAgICAvLyBWYWxpZGF0ZXMgYmVmb3JlIHN0b3JpbmcgYW55dGhpbmcsIHNvIGEgYmFkIGNvbmZpZyBjYW4ndCBicmljayB0aGUgYnVja2V0XG4gICAgbGV0IGluY29taW5nID0gcGFyc2VSb3V0aW5nRGF0YShkYXRhKTtcbiAgICBsZXQgbG9hZGVkID0gYXdhaXQgZ2V0TG9hZGVkQnVja2V0KGFjY291bnQsIGJ1Y2tldE5hbWUpO1xuICAgIGlmICghbG9hZGVkKSB7XG4gICAgICAgIGF3YWl0IG5ldyBBcmNoaXZlc0Rpc2soZ2V0QnVja2V0Rm9sZGVyKGFjY291bnQsIGJ1Y2tldE5hbWUpKS5zZXQoUk9VVElOR19GSUxFLCBkYXRhLCB7IGxhc3RNb2RpZmllZDogY29uZmlnPy5sYXN0TW9kaWZpZWQgfSk7XG4gICAgICAgIGJ1Y2tldHMuc2V0KGtleSwgUHJvbWlzZS5yZXNvbHZlKGJ1aWxkQnVja2V0KGFjY291bnQsIGJ1Y2tldE5hbWUsIGluY29taW5nKSkpO1xuICAgICAgICBjb25zb2xlLmxvZyhgQ3JlYXRlZCBidWNrZXQgJHtrZXl9YCk7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgLy8gQSBjaGFuZ2VkIGNvbmZpZyBtdXN0IGNhcnJ5IGEgaGlnaGVyIHZlcnNpb24gdGhhbiB0aGUgb25lIGN1cnJlbnRseSBzdG9yZWQg4oCUIG90aGVyd2lzZSB0d29cbiAgICAvLyBjbGllbnRzIHdpdGggZGlmZmVyZW50IGNvbmZpZ3MgYXQgdGhlIHNhbWUgdmVyc2lvbiB3b3VsZCBrZWVwIGNsb2JiZXJpbmcgZWFjaCBvdGhlci4gU2FtZVxuICAgIC8vIGNvbnRlbnQgYXQgYW55IHZlcnNpb24gaXMgYSBoYXJtbGVzcyBuby1vcCBhbmQgaXMgYWxsb3dlZCB0aHJvdWdoLlxuICAgIGlmIChKU09OLnN0cmluZ2lmeShpbmNvbWluZykgIT09IGxvYWRlZC5yb3V0aW5nSlNPTiAmJiBnZXRDb25maWdWZXJzaW9uKGluY29taW5nKSA8PSBnZXRDb25maWdWZXJzaW9uKGxvYWRlZC5yb3V0aW5nKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYENhbm5vdCB1cGRhdGUgcm91dGluZyBjb25maWcgZm9yIGJ1Y2tldCAke2tleX06IHRoZSBuZXcgY29uZmlnIGRpZmZlcnMgZnJvbSB0aGUgY3VycmVudCBvbmUgYnV0IGl0cyB2ZXJzaW9uICgke2dldENvbmZpZ1ZlcnNpb24oaW5jb21pbmcpfSkgaXMgbm90IGdyZWF0ZXIgdGhhbiB0aGUgY3VycmVudCB2ZXJzaW9uICgke2dldENvbmZpZ1ZlcnNpb24obG9hZGVkLnJvdXRpbmcpfSkuIEluY3JlbWVudCB0aGUgdmVyc2lvbiB0byB1cGRhdGUgaXQuIEN1cnJlbnQ6ICR7bG9hZGVkLnJvdXRpbmdKU09OfS4gQXR0ZW1wdGVkOiAke0pTT04uc3RyaW5naWZ5KGluY29taW5nKX1gKTtcbiAgICB9XG4gICAgLy8gUm91dGluZyB3cml0ZXMgYnlwYXNzIGZhc3QgbW9kZSAodGhlIGNvbmZpZyBtdXN0IGFwcGx5IGltbWVkaWF0ZWx5IGFuZCBzdXJ2aXZlIGEgY3Jhc2gpXG4gICAgLy8gYW5kIGlnbm9yZSBpbW11dGFibGUgKHRoZSByb3V0aW5nIGZpbGUgbXVzdCBhbHdheXMgc3RheSB1cGRhdGFibGUpLiBBbiBvbGRlciBsYXN0TW9kaWZpZWRcbiAgICAvLyBuby1vcHMgaW5zaWRlIHNldCwgaW4gd2hpY2ggY2FzZSB0aGUgcmVsb2FkIGJlbG93IHNlZXMgbm8gY2hhbmdlLlxuICAgIGF3YWl0IGxvYWRlZC5zdG9yZS5zZXQoUk9VVElOR19GSUxFLCBkYXRhLCB7IGxhc3RNb2RpZmllZDogY29uZmlnPy5sYXN0TW9kaWZpZWQgfSk7XG4gICAgYXdhaXQgc2NoZWR1bGVSb3V0aW5nUmVsb2FkKGFjY291bnQsIGJ1Y2tldE5hbWUpO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gd3JpdGVCdWNrZXRGaWxlKGFjY291bnQ6IHN0cmluZywgYnVja2V0TmFtZTogc3RyaW5nLCBmaWxlUGF0aDogc3RyaW5nLCBkYXRhOiBCdWZmZXIsIGNvbmZpZz86IHsgbGFzdE1vZGlmaWVkPzogbnVtYmVyIH0pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhc3NlcnRXcml0ZXNBbGxvd2VkKCk7XG4gICAgaWYgKGZpbGVQYXRoID09PSBST1VUSU5HX0ZJTEUpIHtcbiAgICAgICAgbGV0IGtleSA9IGAke2FjY291bnR9LyR7YnVja2V0TmFtZX1gO1xuICAgICAgICBsZXQgcnVuID0gKHJvdXRpbmdXcml0ZXMuZ2V0KGtleSkgfHwgUHJvbWlzZS5yZXNvbHZlKCkpLnRoZW4oKCkgPT4gd3JpdGVSb3V0aW5nQ29uZmlnKGFjY291bnQsIGJ1Y2tldE5hbWUsIGRhdGEsIGNvbmZpZykpO1xuICAgICAgICAvLyBUaGUgY2hhaW4gbXVzdCBzdXJ2aXZlIGEgZmFpbGVkIHdyaXRlLCBzbyB0aGUgc3RvcmVkIGxpbmsgc3dhbGxvd3MgdGhlIGVycm9yICh0aGUgY2FsbGVyXG4gICAgICAgIC8vIHN0aWxsIGdldHMgaXQgZnJvbSBydW4pXG4gICAgICAgIHJvdXRpbmdXcml0ZXMuc2V0KGtleSwgcnVuLnRoZW4oKCkgPT4geyB9LCAoKSA9PiB7IH0pKTtcbiAgICAgICAgcmV0dXJuIGF3YWl0IHJ1bjtcbiAgICB9XG4gICAgbGV0IGxvYWRlZCA9IGF3YWl0IGdldExvYWRlZEJ1Y2tldChhY2NvdW50LCBidWNrZXROYW1lKTtcbiAgICBpZiAoIWxvYWRlZCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEJ1Y2tldCAke2FjY291bnR9LyR7YnVja2V0TmFtZX0gZG9lcyBub3QgZXhpc3QuIFdyaXRlIGl0cyByb3V0aW5nIGNvbmZpZyB0byAke0pTT04uc3RyaW5naWZ5KFJPVVRJTkdfRklMRSl9IHRvIGNyZWF0ZSBpdC5gKTtcbiAgICB9XG4gICAgLy8gVGhlIHdyaXRlIHRpbWUgaXMgZGV0ZXJtaW5lZCBleGFjdGx5IG9uY2UsIEhFUkUgYXQgdGhlIGZpcnN0IG5vZGUgdGhhdCByZWNlaXZlcyB0aGUgd3JpdGU7XG4gICAgLy8gaXQgcHJvcGFnYXRlcyBhcyBsYXN0TW9kaWZpZWQsIHNvIGV2ZXJ5IG5vZGUgZXZhbHVhdGVzIHRoZSBidWNrZXQgb3B0aW9ucyBhdCB0aGUgc2FtZSBpbnN0YW50XG4gICAgbGV0IHdyaXRlVGltZSA9IGNvbmZpZz8ubGFzdE1vZGlmaWVkIHx8IERhdGUubm93KCk7XG4gICAgLy8gT25seSBmcmVzaGx5LXN0YW1wZWQgd3JpdGVzIGFyZSBjaGVja2VkOiBhIHdyaXRlIHdpdGggYW4gZXhwbGljaXQgbGFzdE1vZGlmaWVkIGlzXG4gICAgLy8gc3luY2hyb25pemF0aW9uL2JhY2tmaWxsIChvbGQgZGF0YSBsZWdpdGltYXRlbHkgbGFuZHMgb24gc291cmNlcyB3aG9zZSB3aW5kb3cgaGFzIG1vdmVkIG9uKSxcbiAgICAvLyBidXQgYSBmcmVzaCB3cml0ZSByZWFjaGluZyB1cyBvdXRzaWRlIG91ciB3aW5kb3dzL3JvdXRlcyBtZWFucyB0aGUgY2xpZW50IHJlc29sdmVkIGl0c1xuICAgIC8vIHRhcmdldCBmcm9tIGEgc3RhbGUgdmlldyAtIGl0IG11c3QgcmUtcmVzb2x2ZSBhbmQgcmV0cnkgYXQgdGhlIGNvcnJlY3Qgc291cmNlLlxuICAgIGxldCByb3V0ZSA9IGdldFJvdXRlKGZpbGVQYXRoKTtcbiAgICBpZiAoIWNvbmZpZz8ubGFzdE1vZGlmaWVkICYmIGxvYWRlZC5zZWxmRW50cmllcy5sZW5ndGgpIHtcbiAgICAgICAgbGV0IHRpbWVWYWxpZCA9IGxvYWRlZC5zZWxmRW50cmllcy5maWx0ZXIoeCA9PiB3cml0ZVRpbWUgPj0geC52YWxpZFdpbmRvd1swXSAtIFdSSVRFX1BBU1RfV0lORE9XX0dSQUNFICYmIHdyaXRlVGltZSA8PSB4LnZhbGlkV2luZG93WzFdICsgV1JJVEVfUEFTVF9XSU5ET1dfR1JBQ0UpO1xuICAgICAgICBpZiAoIXRpbWVWYWxpZC5sZW5ndGgpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgJHtTVE9SQUdFX1dST05HX1ZBTElEX1dJTkRPV30gVGhpcyBzZXJ2ZXIgaXMgbm90IGEgdmFsaWQgd3JpdGUgdGFyZ2V0IGF0ICR7d3JpdGVUaW1lfSBmb3IgYnVja2V0ICR7YWNjb3VudH0vJHtidWNrZXROYW1lfSAob3VyIHZhbGlkIHdpbmRvd3M6ICR7SlNPTi5zdHJpbmdpZnkobG9hZGVkLnNlbGZFbnRyaWVzLm1hcCh4ID0+IHgudmFsaWRXaW5kb3cpKX0pLiBSZS1yZXNvbHZlIHRoZSBjdXJyZW50bHkgdmFsaWQgc291cmNlIGFuZCByZXRyeS5gKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXRpbWVWYWxpZC5zb21lKHggPT4gcm91dGVDb250YWlucyh4LnJvdXRlLCByb3V0ZSkpKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYCR7U1RPUkFHRV9XUk9OR19ST1VURX0gVGhpcyBzZXJ2ZXIgZG9lcyBub3QgaGFuZGxlIHJvdXRlICR7cm91dGV9IChrZXkgJHtKU09OLnN0cmluZ2lmeShmaWxlUGF0aCl9KSBmb3IgYnVja2V0ICR7YWNjb3VudH0vJHtidWNrZXROYW1lfSAob3VyIHJvdXRlcyBhdCB0aGlzIHRpbWU6ICR7SlNPTi5zdHJpbmdpZnkodGltZVZhbGlkLm1hcCh4ID0+IHgucm91dGUgfHwgRlVMTF9ST1VURSkpfSkuIFJlLXJlc29sdmUgdGhlIHNvdXJjZSBmb3IgdGhpcyBrZXkgYW5kIHJldHJ5LmApO1xuICAgICAgICB9XG4gICAgfVxuICAgIGF3YWl0IGFzc2VydE11dGFibGUobG9hZGVkLCBmaWxlUGF0aCwgd3JpdGVUaW1lKTtcbiAgICBhd2FpdCBsb2FkZWQuc3RvcmUuc2V0KGZpbGVQYXRoLCBkYXRhLCB7IC4uLmdldFdyaXRlQ29uZmlnKGxvYWRlZCwgd3JpdGVUaW1lLCByb3V0ZSksIGxhc3RNb2RpZmllZDogd3JpdGVUaW1lIH0pO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZGVsZXRlQnVja2V0RmlsZShhY2NvdW50OiBzdHJpbmcsIGJ1Y2tldE5hbWU6IHN0cmluZywgZmlsZVBhdGg6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmIChmaWxlUGF0aCA9PT0gUk9VVElOR19GSUxFKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgVGhlIHJvdXRpbmcgY29uZmlnICR7SlNPTi5zdHJpbmdpZnkoUk9VVElOR19GSUxFKX0gY2Fubm90IGJlIGRlbGV0ZWQgKG92ZXJ3cml0ZSBpdCB0byBjaGFuZ2UgdGhlIGJ1Y2tldCdzIGNvbmZpZ3VyYXRpb24pYCk7XG4gICAgfVxuICAgIGxldCBsb2FkZWQgPSBhd2FpdCBnZXRMb2FkZWRCdWNrZXQoYWNjb3VudCwgYnVja2V0TmFtZSk7XG4gICAgaWYgKCFsb2FkZWQpIHJldHVybjtcbiAgICBhd2FpdCBsb2FkZWQuc3RvcmUuZGVsKGZpbGVQYXRoLCBnZXRXcml0ZUNvbmZpZyhsb2FkZWQsIERhdGUubm93KCksIGdldFJvdXRlKGZpbGVQYXRoKSkpO1xufVxuXG4vLyDilIDilIAgbG9jYWwgSUFyY2hpdmVzIGFjY2VzcyDilIDilIBcblxuY29uc3QgTEFSR0VfRklMRV9QQVJUX1NJWkUgPSA4ICogMTAyNCAqIDEwMjQ7XG5cbi8vIFRoZSBpbi1wcm9jZXNzIElBcmNoaXZlcyBmb3IgYSBidWNrZXQgaG9zdGVkIGJ5IFRISVMgc2VydmVyIOKAlCB1c2VkIHdoZW4gYSBSZW1vdGVDb25maWcgc291cmNlXG4vLyBVUkwgcG9pbnRzIGF0IG91cnNlbHZlcywgc28gd2UgZG9uJ3QgdGFsayB0byBvdXJzZWx2ZXMgb3ZlciBIVFRQUy4gT25lIHNpbmdsZXRvbiBwZXIgYnVja2V0LlxuY2xhc3MgQXJjaGl2ZXNMb2NhbEJ1Y2tldCBpbXBsZW1lbnRzIElBcmNoaXZlcyB7XG4gICAgY29uc3RydWN0b3IocHJpdmF0ZSBhY2NvdW50OiBzdHJpbmcsIHByaXZhdGUgYnVja2V0TmFtZTogc3RyaW5nKSB7IH1cblxuICAgIHByaXZhdGUgYXN5bmMgZ2V0QnVja2V0KCk6IFByb21pc2U8TG9hZGVkQnVja2V0IHwgdW5kZWZpbmVkPiB7XG4gICAgICAgIHJldHVybiBhd2FpdCBnZXRMb2FkZWRCdWNrZXQodGhpcy5hY2NvdW50LCB0aGlzLmJ1Y2tldE5hbWUpO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXREZWJ1Z05hbWUoKSB7XG4gICAgICAgIHJldHVybiBgbG9jYWxCdWNrZXQvJHt0aGlzLmFjY291bnR9LyR7dGhpcy5idWNrZXROYW1lfWA7XG4gICAgfVxuICAgIHB1YmxpYyBhc3luYyBnZXQoZmlsZU5hbWU6IHN0cmluZywgY29uZmlnPzogeyByYW5nZT86IHsgc3RhcnQ6IG51bWJlcjsgZW5kOiBudW1iZXIgfSB9KTogUHJvbWlzZTxCdWZmZXIgfCB1bmRlZmluZWQ+IHtcbiAgICAgICAgbGV0IHJlc3VsdCA9IGF3YWl0IHRoaXMuZ2V0MihmaWxlTmFtZSwgY29uZmlnKTtcbiAgICAgICAgcmV0dXJuIHJlc3VsdCAmJiByZXN1bHQuZGF0YSB8fCB1bmRlZmluZWQ7XG4gICAgfVxuICAgIHB1YmxpYyBhc3luYyBnZXQyKGZpbGVOYW1lOiBzdHJpbmcsIGNvbmZpZz86IHsgcmFuZ2U/OiB7IHN0YXJ0OiBudW1iZXI7IGVuZDogbnVtYmVyIH0gfSk6IFByb21pc2U8eyBkYXRhOiBCdWZmZXI7IHdyaXRlVGltZTogbnVtYmVyOyBzaXplOiBudW1iZXIgfSB8IHVuZGVmaW5lZD4ge1xuICAgICAgICBsZXQgYnVja2V0ID0gYXdhaXQgdGhpcy5nZXRCdWNrZXQoKTtcbiAgICAgICAgaWYgKCFidWNrZXQpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIHJldHVybiBhd2FpdCBidWNrZXQuc3RvcmUuZ2V0MihmaWxlTmFtZSwgY29uZmlnKTtcbiAgICB9XG4gICAgcHVibGljIGFzeW5jIHNldChmaWxlTmFtZTogc3RyaW5nLCBkYXRhOiBCdWZmZXIsIGNvbmZpZz86IHsgbGFzdE1vZGlmaWVkPzogbnVtYmVyIH0pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgYXdhaXQgd3JpdGVCdWNrZXRGaWxlKHRoaXMuYWNjb3VudCwgdGhpcy5idWNrZXROYW1lLCBmaWxlTmFtZSwgZGF0YSwgY29uZmlnKTtcbiAgICB9XG4gICAgcHVibGljIGFzeW5jIGRlbChmaWxlTmFtZTogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IGRlbGV0ZUJ1Y2tldEZpbGUodGhpcy5hY2NvdW50LCB0aGlzLmJ1Y2tldE5hbWUsIGZpbGVOYW1lKTtcbiAgICB9XG4gICAgcHVibGljIGFzeW5jIHNldExhcmdlRmlsZShjb25maWc6IHsgcGF0aDogc3RyaW5nOyBnZXROZXh0RGF0YSgpOiBQcm9taXNlPEJ1ZmZlciB8IHVuZGVmaW5lZD4gfSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhc3NlcnRXcml0ZXNBbGxvd2VkKCk7XG4gICAgICAgIGxldCBidWNrZXQgPSBhd2FpdCB0aGlzLmdldEJ1Y2tldCgpO1xuICAgICAgICBpZiAoIWJ1Y2tldCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBCdWNrZXQgJHt0aGlzLmFjY291bnR9LyR7dGhpcy5idWNrZXROYW1lfSBkb2VzIG5vdCBleGlzdC4gV3JpdGUgaXRzIHJvdXRpbmcgY29uZmlnIHRvICR7SlNPTi5zdHJpbmdpZnkoUk9VVElOR19GSUxFKX0gdG8gY3JlYXRlIGl0LmApO1xuICAgICAgICB9XG4gICAgICAgIGF3YWl0IGFzc2VydE11dGFibGUoYnVja2V0LCBjb25maWcucGF0aCwgRGF0ZS5ub3coKSk7XG4gICAgICAgIGxldCBpZCA9IGF3YWl0IGJ1Y2tldC5zdG9yZS5zdGFydExhcmdlVXBsb2FkKCk7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgICAgICAgICAgIGxldCBkYXRhID0gYXdhaXQgY29uZmlnLmdldE5leHREYXRhKCk7XG4gICAgICAgICAgICAgICAgaWYgKCFkYXRhKSBicmVhaztcbiAgICAgICAgICAgICAgICBmb3IgKGxldCBvZmZzZXQgPSAwOyBvZmZzZXQgPCBkYXRhLmxlbmd0aDsgb2Zmc2V0ICs9IExBUkdFX0ZJTEVfUEFSVF9TSVpFKSB7XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IGJ1Y2tldC5zdG9yZS5hcHBlbmRMYXJnZVVwbG9hZChpZCwgZGF0YS5zdWJhcnJheShvZmZzZXQsIG9mZnNldCArIExBUkdFX0ZJTEVfUEFSVF9TSVpFKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYXdhaXQgYnVja2V0LnN0b3JlLmZpbmlzaExhcmdlVXBsb2FkKGlkLCBjb25maWcucGF0aCk7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGF3YWl0IGJ1Y2tldC5zdG9yZS5jYW5jZWxMYXJnZVVwbG9hZChpZCk7XG4gICAgICAgICAgICB0aHJvdyBlO1xuICAgICAgICB9XG4gICAgfVxuICAgIHB1YmxpYyBhc3luYyBnZXRJbmZvKGZpbGVOYW1lOiBzdHJpbmcpOiBQcm9taXNlPHsgd3JpdGVUaW1lOiBudW1iZXI7IHNpemU6IG51bWJlciB9IHwgdW5kZWZpbmVkPiB7XG4gICAgICAgIGxldCBidWNrZXQgPSBhd2FpdCB0aGlzLmdldEJ1Y2tldCgpO1xuICAgICAgICBpZiAoIWJ1Y2tldCkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgcmV0dXJuIGF3YWl0IGJ1Y2tldC5zdG9yZS5nZXRJbmZvKGZpbGVOYW1lKTtcbiAgICB9XG4gICAgcHVibGljIGFzeW5jIGZpbmRJbmZvKHByZWZpeDogc3RyaW5nLCBjb25maWc/OiB7IHNoYWxsb3c/OiBib29sZWFuOyB0eXBlOiBcImZpbGVzXCIgfCBcImZvbGRlcnNcIiB9KTogUHJvbWlzZTxBcmNoaXZlRmlsZUluZm9bXT4ge1xuICAgICAgICBsZXQgYnVja2V0ID0gYXdhaXQgdGhpcy5nZXRCdWNrZXQoKTtcbiAgICAgICAgaWYgKCFidWNrZXQpIHJldHVybiBbXTtcbiAgICAgICAgcmV0dXJuIGF3YWl0IGJ1Y2tldC5zdG9yZS5maW5kSW5mbyhwcmVmaXgsIGNvbmZpZyk7XG4gICAgfVxuICAgIHB1YmxpYyBhc3luYyBmaW5kKHByZWZpeDogc3RyaW5nLCBjb25maWc/OiB7IHNoYWxsb3c/OiBib29sZWFuOyB0eXBlOiBcImZpbGVzXCIgfCBcImZvbGRlcnNcIiB9KTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICAgICAgICByZXR1cm4gKGF3YWl0IHRoaXMuZmluZEluZm8ocHJlZml4LCBjb25maWcpKS5tYXAoeCA9PiB4LnBhdGgpO1xuICAgIH1cbiAgICBwdWJsaWMgYXN5bmMgZ2V0VVJMKGZpbGVQYXRoOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgICAgICBsZXQgeyBkb21haW4sIHBvcnQgfSA9IGdldFN0b3JhZ2VTZXJ2ZXJDb25maWcoKTtcbiAgICAgICAgcmV0dXJuIGJ1aWxkRmlsZVVybChgaHR0cHM6Ly8ke2RvbWFpbn06JHtwb3J0fS9maWxlLyR7ZW5jb2RlVVJJQ29tcG9uZW50KHRoaXMuYWNjb3VudCl9LyR7ZW5jb2RlVVJJQ29tcG9uZW50KHRoaXMuYnVja2V0TmFtZSl9YCwgZmlsZVBhdGgpO1xuICAgIH1cbiAgICBwdWJsaWMgYXN5bmMgZ2V0Q29uZmlnKCk6IFByb21pc2U8QXJjaGl2ZXNDb25maWc+IHtcbiAgICAgICAgbGV0IGJ1Y2tldCA9IGF3YWl0IHRoaXMuZ2V0QnVja2V0KCk7XG4gICAgICAgIC8vIE1pc3NpbmcgYnVja2V0cyBzYXkgdHJ1ZSwgbWF0Y2hpbmcgd2hhdCB0aGV5IGJlY29tZSBvbmNlIGNyZWF0ZWQgKHRoZSBkZWZhdWx0IHN0b3JlIHR5cGUpXG4gICAgICAgIGxldCBwcm9ncmVzcyA9IGJ1Y2tldD8uc3RvcmUuZ2V0U3luY1Byb2dyZXNzPy4oKTtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHN1cHBvcnRzQ2hhbmdlc0FmdGVyOiAhYnVja2V0IHx8ICEhYnVja2V0LnN0b3JlLmdldENoYW5nZXNBZnRlcixcbiAgICAgICAgICAgIHJlbW90ZUNvbmZpZzogYnVja2V0Py5yb3V0aW5nLFxuICAgICAgICAgICAgaW5kZXg6IHByb2dyZXNzPy5pbmRleCxcbiAgICAgICAgICAgIGluZGV4U291cmNlczogcHJvZ3Jlc3M/LnNvdXJjZXMsXG4gICAgICAgICAgICByZWFkZXJEaXNrTGltaXQ6IHByb2dyZXNzPy5yZWFkZXJEaXNrTGltaXQsXG4gICAgICAgICAgICBzeW5jaW5nOiBwcm9ncmVzcz8uc3luY2luZyxcbiAgICAgICAgfTtcbiAgICB9XG4gICAgcHVibGljIGFzeW5jIGhhc1dyaXRlQWNjZXNzKCk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgcHVibGljIGFzeW5jIGdldENoYW5nZXNBZnRlcih0aW1lOiBudW1iZXIpOiBQcm9taXNlPEFyY2hpdmVGaWxlSW5mb1tdPiB7XG4gICAgICAgIGxldCBidWNrZXQgPSBhd2FpdCB0aGlzLmdldEJ1Y2tldCgpO1xuICAgICAgICBpZiAoIWJ1Y2tldCkgcmV0dXJuIFtdO1xuICAgICAgICBpZiAoIWJ1Y2tldC5zdG9yZS5nZXRDaGFuZ2VzQWZ0ZXIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgQnVja2V0ICR7dGhpcy5hY2NvdW50fS8ke3RoaXMuYnVja2V0TmFtZX0gZG9lcyBub3Qgc3VwcG9ydCBnZXRDaGFuZ2VzQWZ0ZXIgKHJhd0Rpc2sgYnVja2V0cyBoYXZlIG5vIGluZGV4KWApO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBhd2FpdCBidWNrZXQuc3RvcmUuZ2V0Q2hhbmdlc0FmdGVyKHRpbWUpO1xuICAgIH1cbiAgICBwdWJsaWMgYXN5bmMgZ2V0U3luY1N0YXR1cygpOiBQcm9taXNlPEFyY2hpdmVzU3luY1N0YXR1cz4ge1xuICAgICAgICBsZXQgYnVja2V0ID0gYXdhaXQgdGhpcy5nZXRCdWNrZXQoKTtcbiAgICAgICAgaWYgKCFidWNrZXQpIHJldHVybiB7IGFsbFNjYW5zQ29tcGxldGU6IHRydWUsIGluZGV4U2l6ZTogMCwgc291cmNlczogW10gfTtcbiAgICAgICAgaWYgKCFidWNrZXQuc3RvcmUuZ2V0U3luY1N0YXR1cykge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBCdWNrZXQgJHt0aGlzLmFjY291bnR9LyR7dGhpcy5idWNrZXROYW1lfSBkb2VzIG5vdCBzdXBwb3J0IGdldFN5bmNTdGF0dXMgKHJhd0Rpc2sgYnVja2V0cyBoYXZlIG5vIHN5bmNocm9uaXphdGlvbilgKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gYXdhaXQgYnVja2V0LnN0b3JlLmdldFN5bmNTdGF0dXMoKTtcbiAgICB9XG59XG5cbmNvbnN0IGxvY2FsQXJjaGl2ZXMgPSBuZXcgTWFwPHN0cmluZywgSUFyY2hpdmVzPigpO1xuZXhwb3J0IGZ1bmN0aW9uIGdldExvY2FsQXJjaGl2ZXMoYWNjb3VudDogc3RyaW5nLCBidWNrZXROYW1lOiBzdHJpbmcpOiBJQXJjaGl2ZXMge1xuICAgIGxldCBrZXkgPSBgJHthY2NvdW50fS8ke2J1Y2tldE5hbWV9YDtcbiAgICBsZXQgZXhpc3RpbmcgPSBsb2NhbEFyY2hpdmVzLmdldChrZXkpO1xuICAgIGlmIChleGlzdGluZykgcmV0dXJuIGV4aXN0aW5nO1xuICAgIGxldCBhcmNoaXZlcyA9IG5ldyBBcmNoaXZlc0xvY2FsQnVja2V0KGFjY291bnQsIGJ1Y2tldE5hbWUpO1xuICAgIGxvY2FsQXJjaGl2ZXMuc2V0KGtleSwgYXJjaGl2ZXMpO1xuICAgIHJldHVybiBhcmNoaXZlcztcbn1cbiJdfQ==
518
+ /* _JS_SOURCE_HASH = "105df280a7bf3922f7699cdb68eeceac061da15a487b65e6e1652d9fdecf81e2"; */