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,610 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
3
+ //exports.createArchives = exports.ArchivesChain = exports.createApiArchives = void 0;
4
+ module.allowclient = true;
5
+ const misc_1 = require("socket-function/src/misc");
6
+ const IArchives_1 = require("../IArchives");
7
+ const remoteConfig_1 = require("./remoteConfig");
8
+ const ArchivesRemote_1 = require("./ArchivesRemote");
9
+ const backblaze_1 = require("../backblaze");
10
+ const storageServerState_1 = require("./storageServerState");
11
+ const sourceWrapper_1 = require("./sourceWrapper");
12
+ // Turns a RemoteConfig into a usable IArchives (createArchives). Initialization is lazy: on the
13
+ // first call we walk the sources IN ORDER and the first one that answers is authoritative (sources
14
+ // are synchronized copies of the same bucket, so we never consult the rest). Its stored routing
15
+ // config wins over the in-memory one - unless ours has a strictly newer version, in which case we
16
+ // write ours (creating the bucket when no routing exists at all). A failed init (all sources down,
17
+ // or the routing write was rejected) stays failed for callers but retries itself in the background
18
+ // with a ramping delay. Once running, we re-read the routing config every CONFIG_POLL_INTERVAL and
19
+ // rebuild the source list when it changed (reusing wrappers for unchanged sources).
20
+ const CONFIG_POLL_INTERVAL = 5 * 60 * 1000;
21
+ // The direct API IArchives for one source, with no URL-form fallback and no chaining. Used by the
22
+ // storage server for its synchronization sources. Denied calls throw immediately (registering the
23
+ // access request in the background): the sync loops retry-and-log until access is granted, while
24
+ // explicit writes surface the denial (with grant instructions) to the caller instead of hanging.
25
+ function createApiArchives(source) {
26
+ if (source.type === "backblaze") {
27
+ return new backblaze_1.ArchivesBackblaze({ bucketName: (0, remoteConfig_1.parseBackblazeUrl)(source.url).bucketName, public: source.public, immutable: source.immutable });
28
+ }
29
+ let parsed = (0, remoteConfig_1.parseHostedUrl)(source.url);
30
+ let server = (0, misc_1.isNode)() && (0, storageServerState_1.getStorageServerConfigOptional)() || undefined;
31
+ if (server && parsed.address === server.domain && parsed.port === server.port) {
32
+ // This source is a bucket hosted by our own process - use it directly instead of calling
33
+ // ourselves over HTTPS
34
+ return (0, storageServerState_1.getLocalArchives)(parsed.account, parsed.bucketName);
35
+ }
36
+ return new ArchivesRemote_1.ArchivesRemote({ url: source.url, accountName: source.accountName, waitForAccess: false });
37
+ }
38
+ exports.createApiArchives = createApiArchives;
39
+ function configWindowCurrent(config) {
40
+ let now = Date.now();
41
+ let [start, end] = config.validWindow;
42
+ return start - IArchives_1.WRITE_PAST_WINDOW_GRACE <= now && now <= end + IArchives_1.WRITE_PAST_WINDOW_GRACE;
43
+ }
44
+ // Client writes target only the CURRENTLY valid source: a future-window source receives its data
45
+ // through server-side downstream propagation/backfill, never directly from clients
46
+ function configAcceptsWrites(config) {
47
+ return configWindowCurrent(config);
48
+ }
49
+ class ArchivesChain {
50
+ constructor(config) {
51
+ this.initRetryDelay = sourceWrapper_1.RETRY_START_DELAY;
52
+ this.disposed = false;
53
+ this.configured = (0, remoteConfig_1.normalizeRemoteConfig)(config);
54
+ this.activeConfig = this.configured;
55
+ }
56
+ getDebugName() {
57
+ let urls = this.activeConfig.sources.map(x => typeof x === "string" && x || x.url);
58
+ return `chain/${urls.join(",")}`;
59
+ }
60
+ // Lazy init that rethrows its error to every caller, while a background timer resets and
61
+ // retries it with a ramping delay - so a chain that couldn't initialize fixes itself once a
62
+ // source comes back, without any caller having to drive it.
63
+ getState() {
64
+ if (this.disposed) {
65
+ return Promise.reject(new Error(`ArchivesChain ${this.getDebugName()} has been disposed`));
66
+ }
67
+ if (!this.statePromise) {
68
+ let promise = this.init();
69
+ this.statePromise = promise;
70
+ promise.then(() => {
71
+ this.initRetryDelay = sourceWrapper_1.RETRY_START_DELAY;
72
+ }, (e) => {
73
+ var _a, _b, _c;
74
+ if (this.disposed || this.initRetryTimer)
75
+ return;
76
+ console.error(`Storage init failed for ${this.getDebugName()}, retrying in ${Math.round(this.initRetryDelay / 1000)}s. ${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`);
77
+ this.initRetryTimer = setTimeout(() => {
78
+ this.initRetryTimer = undefined;
79
+ if (this.disposed)
80
+ return;
81
+ if (this.statePromise === promise) {
82
+ this.statePromise = undefined;
83
+ }
84
+ this.getState().catch(() => { });
85
+ }, this.initRetryDelay);
86
+ (_c = (_b = this.initRetryTimer).unref) === null || _c === void 0 ? void 0 : _c.call(_b);
87
+ this.initRetryDelay = Math.min(sourceWrapper_1.RETRY_MAX_DELAY, this.initRetryDelay * sourceWrapper_1.RETRY_GROWTH);
88
+ });
89
+ }
90
+ return this.statePromise;
91
+ }
92
+ async init() {
93
+ var _a, _b;
94
+ let configs = this.configured.sources.map(remoteConfig_1.normalizeSource);
95
+ let probeErrors = [];
96
+ let found;
97
+ for (let sourceConfig of configs) {
98
+ let probe = await sourceWrapper_1.SourceWrapper.create(sourceConfig, { background: false });
99
+ try {
100
+ let data = await probe.read(archives => archives.get(remoteConfig_1.ROUTING_FILE));
101
+ found = { probe, existing: data && (0, remoteConfig_1.parseRoutingData)(data) || undefined };
102
+ break;
103
+ }
104
+ catch (e) {
105
+ probeErrors.push(`${sourceConfig.url}: ${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`);
106
+ probe.dispose();
107
+ }
108
+ }
109
+ if (!found) {
110
+ throw new Error(`Cannot initialize storage for ${this.getDebugName()}: no source answered. ${probeErrors.join(" | ")}`);
111
+ }
112
+ let active = this.configured;
113
+ let { probe, existing } = found;
114
+ let needsWrite = true;
115
+ if (existing && (0, remoteConfig_1.getConfigVersion)(existing) >= (0, remoteConfig_1.getConfigVersion)(this.configured)) {
116
+ if ((0, remoteConfig_1.getConfigVersion)(existing) === (0, remoteConfig_1.getConfigVersion)(this.configured) && JSON.stringify(existing) !== JSON.stringify(this.configured)) {
117
+ console.error(`Archives configuration updated without updating the version, for ${probe.config.url}. Updates will be ignored until you increase the version. Using: ${JSON.stringify(existing)}, ignoring: ${JSON.stringify(this.configured)}`);
118
+ }
119
+ active = existing;
120
+ needsWrite = false;
121
+ }
122
+ let sources = await this.buildSources(active);
123
+ if (needsWrite) {
124
+ // We decided to write (ours is newer than the authoritative first-up source's, or no
125
+ // routing exists yet). The write goes to all sources, so now EVERY reachable source's
126
+ // stored routing is read, and the write is refused unless our version is strictly
127
+ // greater than all of them - a source already at (or past) our version means this
128
+ // version number is taken, and writing anyway would leave sources at the same version
129
+ // with different content, each rejecting the other's pushes forever.
130
+ let best;
131
+ let conflictUrl;
132
+ for (let source of sources) {
133
+ let data;
134
+ try {
135
+ data = await source.read(archives => archives.get(remoteConfig_1.ROUTING_FILE));
136
+ }
137
+ catch (_c) {
138
+ // Down sources are still protected by the server-side version guard when the
139
+ // write eventually reaches them
140
+ continue;
141
+ }
142
+ if (!data)
143
+ continue;
144
+ let stored = (0, remoteConfig_1.parseRoutingData)(data);
145
+ if (!best || (0, remoteConfig_1.getConfigVersion)(stored) > (0, remoteConfig_1.getConfigVersion)(best)) {
146
+ best = stored;
147
+ }
148
+ if ((0, remoteConfig_1.getConfigVersion)(stored) === (0, remoteConfig_1.getConfigVersion)(this.configured) && JSON.stringify(stored) !== JSON.stringify(this.configured)) {
149
+ conflictUrl = source.config.url;
150
+ }
151
+ }
152
+ if (best && (0, remoteConfig_1.getConfigVersion)(best) >= (0, remoteConfig_1.getConfigVersion)(this.configured)) {
153
+ if (conflictUrl && (0, remoteConfig_1.getConfigVersion)(best) === (0, remoteConfig_1.getConfigVersion)(this.configured)) {
154
+ console.error(`Archives configuration updated without updating the version, for ${conflictUrl}. Updates will be ignored until you increase the version. Using: ${JSON.stringify(best)}, ignoring: ${JSON.stringify(this.configured)}`);
155
+ }
156
+ active = best;
157
+ needsWrite = false;
158
+ for (let source of sources) {
159
+ source.dispose();
160
+ }
161
+ sources = await this.buildSources(active);
162
+ }
163
+ }
164
+ if (needsWrite) {
165
+ // The update only happens when EVERY source would accept it - a partial update would
166
+ // leave the sources out of sync, and a client without access retrying the write forever
167
+ // would never initialize. Without full access we run on the stored config (when there
168
+ // is one) and log the problem instead.
169
+ let missing = [];
170
+ for (let source of sources) {
171
+ try {
172
+ if (!await source.hasWriteAccess()) {
173
+ missing.push(source.config.url);
174
+ }
175
+ }
176
+ catch (e) {
177
+ missing.push(`${source.config.url} (check failed: ${(_b = e.stack) !== null && _b !== void 0 ? _b : e})`);
178
+ }
179
+ }
180
+ if (missing.length) {
181
+ console.error(`Not writing the storage routing config for ${this.getDebugName()} (version ${(0, remoteConfig_1.getConfigVersion)(this.configured)}): no write access to ${missing.join(", ")}. ${existing && `Running on the stored config (version ${(0, remoteConfig_1.getConfigVersion)(existing)}) instead.` || `No stored config exists, so the bucket cannot be created until write access is granted.`}`);
182
+ if (existing) {
183
+ active = existing;
184
+ for (let source of sources) {
185
+ source.dispose();
186
+ }
187
+ sources = await this.buildSources(active);
188
+ }
189
+ }
190
+ else {
191
+ try {
192
+ // A rejected write fails init, which retries from scratch - re-reading the
193
+ // routing, so losing a create race to another client just adopts their config
194
+ // on the next attempt.
195
+ await probe.write(archives => archives.set(remoteConfig_1.ROUTING_FILE, (0, remoteConfig_1.serializeRemoteConfig)(this.configured)));
196
+ }
197
+ catch (e) {
198
+ for (let source of sources) {
199
+ source.dispose();
200
+ }
201
+ probe.dispose();
202
+ throw e;
203
+ }
204
+ }
205
+ }
206
+ probe.dispose();
207
+ this.activeConfig = active;
208
+ this.startConfigPoll();
209
+ return { config: active, sources };
210
+ }
211
+ async buildSources(config) {
212
+ let sources = [];
213
+ for (let sourceConfig of config.sources.map(remoteConfig_1.normalizeSource)) {
214
+ let source = await sourceWrapper_1.SourceWrapper.create(sourceConfig);
215
+ // Latency (for variable-shard target preference) is tracked from initialization on
216
+ source.startPinging();
217
+ sources.push(source);
218
+ }
219
+ return sources;
220
+ }
221
+ startConfigPoll() {
222
+ var _a, _b;
223
+ if (this.pollTimer || this.disposed)
224
+ return;
225
+ this.pollTimer = setInterval(() => {
226
+ void this.checkForNewConfig().catch((e) => {
227
+ var _a;
228
+ console.error(`Checking for a new storage routing config failed for ${this.getDebugName()}: ${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`);
229
+ });
230
+ }, CONFIG_POLL_INTERVAL);
231
+ (_b = (_a = this.pollTimer).unref) === null || _b === void 0 ? void 0 : _b.call(_a);
232
+ }
233
+ async checkForNewConfig() {
234
+ if (this.disposed || !this.statePromise)
235
+ return;
236
+ let state;
237
+ try {
238
+ state = await this.statePromise;
239
+ }
240
+ catch (_a) {
241
+ // Init is failing; its own retry loop handles that
242
+ return;
243
+ }
244
+ let data = await this.run(state, {}, archives => archives.get(remoteConfig_1.ROUTING_FILE));
245
+ if (!data)
246
+ return;
247
+ let latest = (0, remoteConfig_1.parseRoutingData)(data);
248
+ if (JSON.stringify(latest) === JSON.stringify(state.config))
249
+ return;
250
+ console.log(`Storage routing config changed for ${this.getDebugName()}, rebuilding sources`);
251
+ let oldByConfig = new Map(state.sources.map(source => [JSON.stringify(source.config), source]));
252
+ let sources = [];
253
+ for (let sourceConfig of latest.sources.map(remoteConfig_1.normalizeSource)) {
254
+ let key = JSON.stringify(sourceConfig);
255
+ let old = oldByConfig.get(key);
256
+ if (old) {
257
+ oldByConfig.delete(key);
258
+ sources.push(old);
259
+ }
260
+ else {
261
+ sources.push(await sourceWrapper_1.SourceWrapper.create(sourceConfig));
262
+ }
263
+ }
264
+ // In-flight requests still hold the old wrappers and finish fine; dispose just stops any
265
+ // background reconnect loops
266
+ for (let leftover of oldByConfig.values()) {
267
+ leftover.dispose();
268
+ }
269
+ this.activeConfig = latest;
270
+ this.statePromise = Promise.resolve({ config: latest, sources });
271
+ }
272
+ // Runs a request against the first available source (that covers the key's route, when one is
273
+ // given), moving to the next one ONLY when the source's WebSocket is down (checked directly -
274
+ // never by inspecting the error, which is arbitrary data). An error from a connected source is
275
+ // an application error and throws as-is. A down source gets its background reconnect kicked.
276
+ async run(state, config, run) {
277
+ var _a;
278
+ if (config.write) {
279
+ return await this.runWrite(state, config.route, run);
280
+ }
281
+ let errors = [];
282
+ for (let source of state.sources) {
283
+ if (config.route !== undefined && !(0, remoteConfig_1.routeContains)(source.config.route, config.route))
284
+ continue;
285
+ if (!configWindowCurrent(source.config))
286
+ continue;
287
+ if (!source.isConnected()) {
288
+ source.noteFailure();
289
+ errors.push(`${source.config.url} is not connected`);
290
+ continue;
291
+ }
292
+ try {
293
+ if (config.apiOnly) {
294
+ let api = source.api;
295
+ if (!api) {
296
+ errors.push(`${source.config.url} has URL-only access, which cannot serve this operation`);
297
+ continue;
298
+ }
299
+ return await run(api);
300
+ }
301
+ return await source.read(run);
302
+ }
303
+ catch (e) {
304
+ if (source.isConnected())
305
+ throw e;
306
+ source.noteFailure();
307
+ errors.push(String((_a = e.stack) !== null && _a !== void 0 ? _a : e));
308
+ }
309
+ }
310
+ throw new Error(`All sources failed for ${this.getDebugName()}${config.route !== undefined && ` (route ${config.route})` || ""}: ${errors.join(" | ") || "no sources available"}`);
311
+ }
312
+ // Writes are consistent: they go to the first currently-valid source covering the key's route
313
+ // and NEVER fail over to another node - a client wrongly deciding nodes are down must not
314
+ // scatter its writes across the chain. (Reads fail over freely above: sources are synchronized
315
+ // copies, so reading from any of them is safe.) The one retry is for a window boundary passing
316
+ // (or a route disagreement) mid-write, which re-resolves the target rather than falling back.
317
+ async runWrite(state, route, run) {
318
+ var _a;
319
+ let retriedWrongWindow = false;
320
+ let retriedWrongRoute = false;
321
+ while (true) {
322
+ let target = state.sources.find(x => configAcceptsWrites(x.config) && (route === undefined || (0, remoteConfig_1.routeContains)(x.config.route, route)));
323
+ if (!target) {
324
+ throw new Error(`No source accepts writes for ${this.getDebugName()}${route !== undefined && ` (route ${route})` || ""} (every source is outside its valid window or outside the key's route)`);
325
+ }
326
+ if (!target.isConnected()) {
327
+ target.noteFailure();
328
+ throw new Error(`Cannot write: the write target ${target.config.url} is not connected (writes never fail over to other sources)`);
329
+ }
330
+ try {
331
+ return await target.write(run);
332
+ }
333
+ catch (e) {
334
+ let message = String((_a = e.stack) !== null && _a !== void 0 ? _a : e);
335
+ if (message.includes(IArchives_1.STORAGE_WRONG_VALID_WINDOW) && !retriedWrongWindow) {
336
+ retriedWrongWindow = true;
337
+ continue;
338
+ }
339
+ if (message.includes(IArchives_1.STORAGE_WRONG_ROUTE) && !retriedWrongRoute) {
340
+ retriedWrongRoute = true;
341
+ continue;
342
+ }
343
+ if (!target.isConnected()) {
344
+ target.noteFailure();
345
+ }
346
+ throw e;
347
+ }
348
+ }
349
+ }
350
+ async request(config, run) {
351
+ let state = await this.getState();
352
+ return await this.run(state, config, run);
353
+ }
354
+ // The access-page link (plus our machineId/ip, for the approver to match the request) for the
355
+ // first hosted source that hasn't granted us access. undefined when we have access everywhere
356
+ // we can have it. Also registers the access request server-side.
357
+ async waitingForAccess() {
358
+ let state = await this.getState();
359
+ for (let source of state.sources) {
360
+ if (source.api instanceof ArchivesRemote_1.ArchivesRemote) {
361
+ let waiting = await source.api.waitingForAccess();
362
+ if (waiting)
363
+ return waiting;
364
+ }
365
+ }
366
+ return undefined;
367
+ }
368
+ async get(fileName, config) {
369
+ let result = await this.get2(fileName, config);
370
+ return result && result.data || undefined;
371
+ }
372
+ async get2(fileName, config) {
373
+ return await this.request({ route: (0, remoteConfig_1.getRoute)(fileName) }, archives => archives.get2(fileName, config));
374
+ }
375
+ async getInfo(fileName) {
376
+ return await this.request({ route: (0, remoteConfig_1.getRoute)(fileName) }, archives => archives.getInfo(fileName));
377
+ }
378
+ // A minimal set of connected, currently-valid API sources whose routes cover [0, 1) - listing
379
+ // operations must merge every shard. Greedy sweep: repeatedly take the source that extends
380
+ // coverage the furthest. In practice this is one source (unsharded), or one per shard.
381
+ selectCoveringSources(state) {
382
+ let candidates = state.sources.filter(x => configWindowCurrent(x.config) && x.api && x.isConnected());
383
+ let chosen = [];
384
+ let covered = 0;
385
+ while (covered < 1) {
386
+ let best;
387
+ let bestEnd = covered;
388
+ for (let source of candidates) {
389
+ let [start, end] = source.config.route || IArchives_1.FULL_ROUTE;
390
+ if (start > covered)
391
+ continue;
392
+ if (end > bestEnd) {
393
+ bestEnd = end;
394
+ best = source;
395
+ }
396
+ }
397
+ if (!best) {
398
+ throw new Error(`Cannot cover the full route space for ${this.getDebugName()}: the available sources only cover up to ${covered} (some shards are down or URL-only)`);
399
+ }
400
+ chosen.push(best);
401
+ covered = bestEnd;
402
+ }
403
+ return chosen;
404
+ }
405
+ async runOnApi(source, run) {
406
+ let api = source.api;
407
+ if (!api) {
408
+ throw new Error(`${source.config.url} has URL-only access, which cannot serve this operation`);
409
+ }
410
+ return await run(api);
411
+ }
412
+ async find(prefix, config) {
413
+ return (await this.findInfo(prefix, config)).map(x => x.path);
414
+ }
415
+ async findInfo(prefix, config) {
416
+ let state = await this.getState();
417
+ let covering = this.selectCoveringSources(state);
418
+ let results = await Promise.all(covering.map(source => this.runOnApi(source, archives => archives.findInfo(prefix, config))));
419
+ // Overlapping shards can both report a path; the newest wins
420
+ let byPath = new Map();
421
+ for (let list of results) {
422
+ for (let file of list) {
423
+ let existing = byPath.get(file.path);
424
+ if (!existing || file.createTime > existing.createTime) {
425
+ byPath.set(file.path, file);
426
+ }
427
+ }
428
+ }
429
+ let merged = [...byPath.values()];
430
+ (0, misc_1.sort)(merged, x => x.path);
431
+ return merged;
432
+ }
433
+ async getChangesAfter(time) {
434
+ let state = await this.getState();
435
+ let covering = this.selectCoveringSources(state);
436
+ let results = await Promise.all(covering.map(source => this.runOnApi(source, async (archives) => {
437
+ if (!archives.getChangesAfter) {
438
+ throw new Error(`${archives.getDebugName()} does not support getChangesAfter`);
439
+ }
440
+ return await archives.getChangesAfter(time);
441
+ })));
442
+ let byPath = new Map();
443
+ for (let list of results) {
444
+ for (let file of list) {
445
+ let existing = byPath.get(file.path);
446
+ if (!existing || file.createTime > existing.createTime) {
447
+ byPath.set(file.path, file);
448
+ }
449
+ }
450
+ }
451
+ let merged = [...byPath.values()];
452
+ (0, misc_1.sort)(merged, x => x.path);
453
+ return merged;
454
+ }
455
+ async getSyncStatus() {
456
+ let state = await this.getState();
457
+ let covering = this.selectCoveringSources(state);
458
+ let statuses = await Promise.all(covering.map(source => this.runOnApi(source, async (archives) => {
459
+ if (!archives.getSyncStatus) {
460
+ throw new Error(`${archives.getDebugName()} does not support getSyncStatus`);
461
+ }
462
+ return await archives.getSyncStatus();
463
+ })));
464
+ return {
465
+ allScansComplete: statuses.every(x => x.allScansComplete),
466
+ indexSize: statuses.reduce((sum, x) => sum + x.indexSize, 0),
467
+ sources: statuses.flatMap(x => x.sources),
468
+ };
469
+ }
470
+ async getConfig() {
471
+ let state = await this.getState();
472
+ if (!state.sources.some(x => x.api))
473
+ return { remoteConfig: state.config };
474
+ let config = await this.run(state, { apiOnly: true }, archives => archives.getConfig());
475
+ return { ...config, remoteConfig: state.config };
476
+ }
477
+ /** True only when EVERY write-receiving source would accept our writes (partial write access
478
+ * desynchronizes sources, so it counts as no access). */
479
+ async hasWriteAccess() {
480
+ let state = await this.getState();
481
+ for (let source of state.sources) {
482
+ if (!configAcceptsWrites(source.config))
483
+ continue;
484
+ if (!await source.hasWriteAccess())
485
+ return false;
486
+ }
487
+ return true;
488
+ }
489
+ assertNotBareVariableShard(fileName) {
490
+ if (fileName.includes(IArchives_1.VARIABLE_SHARD) && (0, remoteConfig_1.parseVariableRoute)(fileName) === undefined) {
491
+ throw new Error(`Keys containing VARIABLE_SHARD must be written with setVariableShard, which materializes the shard value and returns the full key. Key: ${JSON.stringify(fileName)}`);
492
+ }
493
+ }
494
+ async set(fileName, data, config) {
495
+ this.assertNotBareVariableShard(fileName);
496
+ await this.request({ write: true, route: (0, remoteConfig_1.getRoute)(fileName) }, archives => archives.set(fileName, data, config));
497
+ }
498
+ async del(fileName) {
499
+ await this.request({ write: true, route: (0, remoteConfig_1.getRoute)(fileName) }, archives => archives.del(fileName));
500
+ }
501
+ /** Writes a key containing the VARIABLE_SHARD sentinel: picks the lowest-latency up write
502
+ * shard, materializes the key with a random value inside that shard's route, writes it, and
503
+ * returns the FULL key actually written (the caller needs it to ever read the value back).
504
+ * Unlike normal writes this CAN move to another shard when the preferred one is down (error +
505
+ * socket down, same rule as reads) - each shard receives a different key, so write
506
+ * consistency is preserved. */
507
+ async setVariableShard(key, data, config) {
508
+ var _a;
509
+ if (!key.includes(IArchives_1.VARIABLE_SHARD)) {
510
+ throw new Error(`Expected the key to contain the VARIABLE_SHARD sentinel, was ${JSON.stringify(key)}`);
511
+ }
512
+ if ((0, remoteConfig_1.parseVariableRoute)(key) !== undefined) {
513
+ throw new Error(`The key already has a materialized shard value; write it with set instead. Key: ${JSON.stringify(key)}`);
514
+ }
515
+ let state = await this.getState();
516
+ // Per-shard write consistency still holds: within a route, only the FIRST source may take
517
+ // writes - latency only picks WHICH shard the key materializes into
518
+ let targetsByRoute = new Map();
519
+ for (let source of state.sources) {
520
+ if (!configAcceptsWrites(source.config))
521
+ continue;
522
+ let routeKey = JSON.stringify(source.config.route || IArchives_1.FULL_ROUTE);
523
+ if (!targetsByRoute.has(routeKey)) {
524
+ targetsByRoute.set(routeKey, source);
525
+ }
526
+ }
527
+ let targets = [...targetsByRoute.values()];
528
+ (0, misc_1.sort)(targets, x => x.getLatency());
529
+ let errors = [];
530
+ for (let target of targets) {
531
+ if (!target.isConnected()) {
532
+ target.noteFailure();
533
+ errors.push(`${target.config.url} is not connected`);
534
+ continue;
535
+ }
536
+ let [start, end] = target.config.route || IArchives_1.FULL_ROUTE;
537
+ let fullKey = key.replace(IArchives_1.VARIABLE_SHARD, IArchives_1.VARIABLE_SHARD + "_" + (start + Math.random() * (end - start)));
538
+ try {
539
+ await target.write(archives => archives.set(fullKey, data, config));
540
+ return fullKey;
541
+ }
542
+ catch (e) {
543
+ // An error alone doesn't justify moving on (it would be an application error); the
544
+ // socket must also be down
545
+ if (target.isConnected())
546
+ throw e;
547
+ target.noteFailure();
548
+ errors.push(String((_a = e.stack) !== null && _a !== void 0 ? _a : e));
549
+ }
550
+ }
551
+ throw new Error(`Every variable-shard write target failed for ${this.getDebugName()}: ${errors.join(" | ") || "no sources accept writes"}`);
552
+ }
553
+ async setLargeFile(config) {
554
+ this.assertNotBareVariableShard(config.path);
555
+ let state = await this.getState();
556
+ // Same consistency rule as runWrite: the first currently-valid source for the route, or nothing
557
+ let route = (0, remoteConfig_1.getRoute)(config.path);
558
+ let target = state.sources.find(x => configAcceptsWrites(x.config) && (0, remoteConfig_1.routeContains)(x.config.route, route));
559
+ if (!target) {
560
+ throw new Error(`No source accepts writes for setLargeFile on ${this.getDebugName()} (route ${route})`);
561
+ }
562
+ if (!target.isConnected()) {
563
+ target.noteFailure();
564
+ throw new Error(`Cannot write: the write target ${target.config.url} is not connected (writes never fail over to other sources)`);
565
+ }
566
+ await target.write(archives => archives.setLargeFile(config));
567
+ }
568
+ async getURL(path) {
569
+ let state = await this.getState();
570
+ let route = (0, remoteConfig_1.getRoute)(path);
571
+ for (let source of state.sources) {
572
+ if (source.config.public === false)
573
+ continue;
574
+ if (!(0, remoteConfig_1.routeContains)(source.config.route, route))
575
+ continue;
576
+ if (source.url)
577
+ return await source.url.getURL(path);
578
+ if (source.api)
579
+ return await source.api.getURL(path);
580
+ }
581
+ throw new Error(`No public source covering route ${route} to build a URL from for ${this.getDebugName()}`);
582
+ }
583
+ dispose() {
584
+ this.disposed = true;
585
+ if (this.pollTimer) {
586
+ clearInterval(this.pollTimer);
587
+ }
588
+ if (this.initRetryTimer) {
589
+ clearTimeout(this.initRetryTimer);
590
+ }
591
+ let statePromise = this.statePromise;
592
+ if (statePromise) {
593
+ void statePromise.then(state => {
594
+ for (let source of state.sources) {
595
+ source.dispose();
596
+ }
597
+ }, () => { });
598
+ }
599
+ }
600
+ }
601
+ exports.ArchivesChain = ArchivesChain;
602
+ // The IArchives for a RemoteConfig (or a single source - a routing URL string works). Fully lazy:
603
+ // nothing is contacted until the first call. Call dispose() when done with it, so its background
604
+ // retry/poll loops stop.
605
+ function createArchives(config) {
606
+ return new ArchivesChain(config);
607
+ }
608
+ exports.createArchives = createArchives;
609
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlQXJjaGl2ZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJjcmVhdGVBcmNoaXZlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxNQUFNLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQztBQUUxQixtREFBd0Q7QUFDeEQsNENBSXNCO0FBQ3RCLGlEQUl3QjtBQUN4QixxREFBa0Q7QUFDbEQsNENBQWlEO0FBQ2pELDZEQUF3RjtBQUN4RixtREFBa0c7QUFFbEcsZ0dBQWdHO0FBQ2hHLG1HQUFtRztBQUNuRyxnR0FBZ0c7QUFDaEcsa0dBQWtHO0FBQ2xHLG1HQUFtRztBQUNuRyxtR0FBbUc7QUFDbkcsbUdBQW1HO0FBQ25HLG9GQUFvRjtBQUVwRixNQUFNLG9CQUFvQixHQUFHLENBQUMsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDO0FBRTNDLGtHQUFrRztBQUNsRyxrR0FBa0c7QUFDbEcsaUdBQWlHO0FBQ2pHLGlHQUFpRztBQUNqRyxTQUFnQixpQkFBaUIsQ0FBQyxNQUFzQztJQUNwRSxJQUFJLE1BQU0sQ0FBQyxJQUFJLEtBQUssV0FBVyxFQUFFLENBQUM7UUFDOUIsT0FBTyxJQUFJLDZCQUFpQixDQUFDLEVBQUUsVUFBVSxFQUFFLElBQUEsZ0NBQWlCLEVBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLFVBQVUsRUFBRSxNQUFNLEVBQUUsTUFBTSxDQUFDLE1BQU0sRUFBRSxTQUFTLEVBQUUsTUFBTSxDQUFDLFNBQVMsRUFBRSxDQUFDLENBQUM7SUFDL0ksQ0FBQztJQUNELElBQUksTUFBTSxHQUFHLElBQUEsNkJBQWMsRUFBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDeEMsSUFBSSxNQUFNLEdBQUcsSUFBQSxhQUFNLEdBQUUsSUFBSSxJQUFBLG1EQUE4QixHQUFFLElBQUksU0FBUyxDQUFDO0lBQ3ZFLElBQUksTUFBTSxJQUFJLE1BQU0sQ0FBQyxPQUFPLEtBQUssTUFBTSxDQUFDLE1BQU0sSUFBSSxNQUFN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LENBQUMsQ0FBQztRQUN0QyxDQUFDO1FBQ0QsSUFBSSxZQUFZLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQztRQUNyQyxJQUFJLFlBQVksRUFBRSxDQUFDO1lBQ2YsS0FBSyxZQUFZLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFO2dCQUMzQixLQUFLLElBQUksTUFBTSxJQUFJLEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQztvQkFDL0IsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUNyQixDQUFDO1lBQ0wsQ0FBQyxFQUFFLEdBQUcsRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQ2xCLENBQUM7SUFDTCxDQUFDO0NBQ0o7QUE1aEJELHNDQTRoQkM7QUFFRCxrR0FBa0c7QUFDbEcsaUdBQWlHO0FBQ2pHLHlCQUF5QjtBQUN6QixTQUFnQixjQUFjLENBQUMsTUFBdUM7SUFDbEUsT0FBTyxJQUFJLGFBQWEsQ0FBQyxNQUFNLENBQUMsQ0FBQztBQUNyQyxDQUFDO0FBRkQsd0NBRUMiLCJzb3VyY2VzQ29udGVudCI6WyJtb2R1bGUuYWxsb3djbGllbnQgPSB0cnVlO1xuXG5pbXBvcnQgeyBpc05vZGUsIHNvcnQgfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy9taXNjXCI7XG5pbXBvcnQge1xuICAgIElBcmNoaXZlcywgUmVtb3RlQ29uZmlnLCBSZW1vdGVDb25maWdCYXNlLCBIb3N0ZWRDb25maWcsIEJhY2tibGF6ZUNvbmZpZyxcbiAgICBBcmNoaXZlRmlsZUluZm8sIEFyY2hpdmVzQ29uZmlnLCBBcmNoaXZlc1N5bmNTdGF0dXMsIFdSSVRFX1BBU1RfV0lORE9XX0dSQUNFLCBTVE9SQUdFX1dST05HX1ZBTElEX1dJTkRPVyxcbiAgICBTVE9SQUdFX1dST05HX1JPVVRFLCBGVUxMX1JPVVRFLCBWQVJJQUJMRV9TSEFSRCxcbn0gZnJvbSBcIi4uL0lBcmNoaXZlc1wiO1xuaW1wb3J0IHtcbiAgICBST1VUSU5HX0ZJTEUsIGdldENvbmZpZ1ZlcnNpb24sIHBhcnNlSG9zdGVkVXJsLCBwYXJzZUJhY2tibGF6ZVVybCxcbiAgICBub3JtYWxpemVSZW1vdGVDb25maWcsIG5vcm1hbGl6ZVNvdXJjZSwgcGFyc2VSb3V0aW5nRGF0YSwgc2VyaWFsaXplUmVtb3RlQ29uZmlnLFxuICAgIGdldFJvdXRlLCByb3V0ZUNvbnRhaW5zLCBwYXJzZVZhcmlhYmxlUm91dGUsXG59IGZyb20gXCIuL3JlbW90ZUNvbmZpZ1wiO1xuaW1wb3J0IHsgQXJjaGl2ZXNSZW1vdGUgfSBmcm9tIFwiLi9BcmNoaXZlc1JlbW90ZVwiO1xuaW1wb3J0IHsgQXJjaGl2ZXNCYWNrYmxhemUgfSBmcm9tIFwiLi4vYmFja2JsYXplXCI7XG5pbXBvcnQgeyBnZXRTdG9yYWdlU2VydmVyQ29uZmlnT3B0aW9uYWwsIGdldExvY2FsQXJjaGl2ZXMgfSBmcm9tIFwiLi9zdG9yYWdlU2VydmVyU3RhdGVcIjtcbmltcG9ydCB7IFNvdXJjZVdyYXBwZXIsIFJFVFJZX1NUQVJUX0RFTEFZLCBSRVRSWV9NQVhfREVMQVksIFJFVFJZX0dST1dUSCB9IGZyb20gXCIuL3NvdXJjZVdyYXBwZXJcIjtcblxuLy8gVHVybnMgYSBSZW1vdGVDb25maWcgaW50byBhIHVzYWJsZSBJQXJjaGl2ZXMgKGNyZWF0ZUFyY2hpdmVzKS4gSW5pdGlhbGl6YXRpb24gaXMgbGF6eTogb24gdGhlXG4vLyBmaXJzdCBjYWxsIHdlIHdhbGsgdGhlIHNvdXJjZXMgSU4gT1JERVIgYW5kIHRoZSBmaXJzdCBvbmUgdGhhdCBhbnN3ZXJzIGlzIGF1dGhvcml0YXRpdmUgKHNvdXJjZXNcbi8vIGFyZSBzeW5jaHJvbml6ZWQgY29waWVzIG9mIHRoZSBzYW1lIGJ1Y2tldCwgc28gd2UgbmV2ZXIgY29uc3VsdCB0aGUgcmVzdCkuIEl0cyBzdG9yZWQgcm91dGluZ1xuLy8gY29uZmlnIHdpbnMgb3ZlciB0aGUgaW4tbWVtb3J5IG9uZSAtIHVubGVzcyBvdXJzIGhhcyBhIHN0cmljdGx5IG5ld2VyIHZlcnNpb24sIGluIHdoaWNoIGNhc2Ugd2Vcbi8vIHdyaXRlIG91cnMgKGNyZWF0aW5nIHRoZSBidWNrZXQgd2hlbiBubyByb3V0aW5nIGV4aXN0cyBhdCBhbGwpLiBBIGZhaWxlZCBpbml0IChhbGwgc291cmNlcyBkb3duLFxuLy8gb3IgdGhlIHJvdXRpbmcgd3JpdGUgd2FzIHJlamVjdGVkKSBzdGF5cyBmYWlsZWQgZm9yIGNhbGxlcnMgYnV0IHJldHJpZXMgaXRzZWxmIGluIHRoZSBiYWNrZ3JvdW5kXG4vLyB3aXRoIGEgcmFtcGluZyBkZWxheS4gT25jZSBydW5uaW5nLCB3ZSByZS1yZWFkIHRoZSByb3V0aW5nIGNvbmZpZyBldmVyeSBDT05GSUdfUE9MTF9JTlRFUlZBTCBhbmRcbi8vIHJlYnVpbGQgdGhlIHNvdXJjZSBsaXN0IHdoZW4gaXQgY2hhbmdlZCAocmV1c2luZyB3cmFwcGVycyBmb3IgdW5jaGFuZ2VkIHNvdXJjZXMpLlxuXG5jb25zdCBDT05GSUdfUE9MTF9JTlRFUlZBTCA9IDUgKiA2MCAqIDEwMDA7XG5cbi8vIFRoZSBkaXJlY3QgQVBJIElBcmNoaXZlcyBmb3Igb25lIHNvdXJjZSwgd2l0aCBubyBVUkwtZm9ybSBmYWxsYmFjayBhbmQgbm8gY2hhaW5pbmcuIFVzZWQgYnkgdGhlXG4vLyBzdG9yYWdlIHNlcnZlciBmb3IgaXRzIHN5bmNocm9uaXphdGlvbiBzb3VyY2VzLiBEZW5pZWQgY2FsbHMgdGhyb3cgaW1tZWRpYXRlbHkgKHJlZ2lzdGVyaW5nIHRoZVxuLy8gYWNjZXNzIHJlcXVlc3QgaW4gdGhlIGJhY2tncm91bmQpOiB0aGUgc3luYyBsb29wcyByZXRyeS1hbmQtbG9nIHVudGlsIGFjY2VzcyBpcyBncmFudGVkLCB3aGlsZVxuLy8gZXhwbGljaXQgd3JpdGVzIHN1cmZhY2UgdGhlIGRlbmlhbCAod2l0aCBncmFudCBpbnN0cnVjdGlvbnMpIHRvIHRoZSBjYWxsZXIgaW5zdGVhZCBvZiBoYW5naW5nLlxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUFwaUFyY2hpdmVzKHNvdXJjZTogSG9zdGVkQ29uZmlnIHwgQmFja2JsYXplQ29uZmlnKTogSUFyY2hpdmVzIHtcbiAgICBpZiAoc291cmNlLnR5cGUgPT09IFwiYmFja2JsYXplXCIpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBBcmNoaXZlc0JhY2tibGF6ZSh7IGJ1Y2tldE5hbWU6IHBhcnNlQmFja2JsYXplVXJsKHNvdXJjZS51cmwpLmJ1Y2tldE5hbWUsIHB1YmxpYzogc291cmNlLnB1YmxpYywgaW1tdXRhYmxlOiBzb3VyY2UuaW1tdXRhYmxlIH0pO1xuICAgIH1cbiAgICBsZXQgcGFyc2VkID0gcGFyc2VIb3N0ZWRVcmwoc291cmNlLnVybCk7XG4gICAgbGV0IHNlcnZlciA9IGlzTm9kZSgpICYmIGdldFN0b3JhZ2VTZXJ2ZXJDb25maWdPcHRpb25hbCgpIHx8IHVuZGVmaW5lZDtcbiAgICBpZiAoc2VydmVyICYmIHBhcnNlZC5hZGRyZXNzID09PSBzZXJ2ZXIuZG9tYWluICYmIHBhcnNlZC5wb3J0ID09PSBzZXJ2ZXIucG9ydCkge1xuICAgICAgICAvLyBUaGlzIHNvdXJjZSBpcyBhIGJ1Y2tldCBob3N0ZWQgYnkgb3VyIG93biBwcm9jZXNzIC0gdXNlIGl0IGRpcmVjdGx5IGluc3RlYWQgb2YgY2FsbGluZ1xuICAgICAgICAvLyBvdXJzZWx2ZXMgb3ZlciBIVFRQU1xuICAgICAgICByZXR1cm4gZ2V0TG9jYWxBcmNoaXZlcyhwYXJzZWQuYWNjb3VudCwgcGFyc2VkLmJ1Y2tldE5hbWUpO1xuICAgIH1cbiAgICByZXR1cm4gbmV3IEFyY2hpdmVzUmVtb3RlKHsgdXJsOiBzb3VyY2UudXJsLCBhY2NvdW50TmFtZTogc291cmNlLmFjY291bnROYW1lLCB3YWl0Rm9yQWNjZXNzOiBmYWxzZSB9KTtcbn1cblxudHlwZSBDaGFpblN0YXRlID0ge1xuICAgIGNvbmZpZzogUmVtb3RlQ29uZmlnO1xuICAgIHNvdXJjZXM6IFNvdXJjZVdyYXBwZXJbXTtcbn07XG5cbmZ1bmN0aW9uIGNvbmZpZ1dpbmRvd0N1cnJlbnQoY29uZmlnOiBIb3N0ZWRDb25maWcgfCBCYWNrYmxhemVDb25maWcpOiBib29sZWFuIHtcbiAgICBsZXQgbm93ID0gRGF0ZS5ub3coKTtcbiAgICBsZXQgW3N0YXJ0LCBlbmRdID0gY29uZmlnLnZhbGlkV2luZG93O1xuICAgIHJldHVybiBzdGFydCAtIFdSSVRFX1BBU1RfV0lORE9XX0dSQUNFIDw9IG5vdyAmJiBub3cgPD0gZW5kICsgV1JJVEVfUEFTVF9XSU5ET1dfR1JBQ0U7XG59XG5cbi8vIENsaWVudCB3cml0ZXMgdGFyZ2V0IG9ubHkgdGhlIENVUlJFTlRMWSB2YWxpZCBzb3VyY2U6IGEgZnV0dXJlLXdpbmRvdyBzb3VyY2UgcmVjZWl2ZXMgaXRzIGRhdGFcbi8vIHRocm91Z2ggc2VydmVyLXNpZGUgZG93bnN0cmVhbSBwcm9wYWdhdGlvbi9iYWNrZmlsbCwgbmV2ZXIgZGlyZWN0bHkgZnJvbSBjbGllbnRzXG5mdW5jdGlvbiBjb25maWdBY2NlcHRzV3JpdGVzKGNvbmZpZzogSG9zdGVkQ29uZmlnIHwgQmFja2JsYXplQ29uZmlnKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIGNvbmZpZ1dpbmRvd0N1cnJlbnQoY29uZmlnKTtcbn1cblxuZXhwb3J0IGNsYXNzIEFyY2hpdmVzQ2hhaW4gaW1wbGVtZW50cyBJQXJjaGl2ZXMge1xuICAgIHByaXZhdGUgY29uZmlndXJlZDogUmVtb3RlQ29uZmlnO1xuICAgIC8vIFRoZSBjb25maWcgd2UgYWN0dWFsbHkgcnVuIG9uICh0aGUgYXV0aG9yaXRhdGl2ZSBzdG9yZWQgb25lIGFmdGVyIGluaXQpXG4gICAgcHJpdmF0ZSBhY3RpdmVDb25maWc6IFJlbW90ZUNvbmZpZztcbiAgICBwcml2YXRlIHN0YXRlUHJvbWlzZTogUHJvbWlzZTxDaGFpblN0YXRlPiB8IHVuZGVmaW5lZDtcbiAgICBwcml2YXRlIGluaXRSZXRyeURlbGF5ID0gUkVUUllfU1RBUlRfREVMQVk7XG4gICAgcHJpdmF0ZSBpbml0UmV0cnlUaW1lcjogUmV0dXJuVHlwZTx0eXBlb2Ygc2V0VGltZW91dD4gfCB1bmRlZmluZWQ7XG4gICAgcHJpdmF0ZSBwb2xsVGltZXI6IFJldHVyblR5cGU8dHlwZW9mIHNldEludGVydmFsPiB8IHVuZGVmaW5lZDtcbiAgICBwcml2YXRlIGRpc3Bvc2VkID0gZmFsc2U7XG5cbiAgICBjb25zdHJ1Y3Rvcihjb25maWc6IFJlbW90ZUNvbmZpZyB8IFJlbW90ZUNvbmZpZ0Jhc2UpIHtcbiAgICAgICAgdGhpcy5jb25maWd1cmVkID0gbm9ybWFsaXplUmVtb3RlQ29uZmlnKGNvbmZpZyk7XG4gICAgICAgIHRoaXMuYWN0aXZlQ29uZmlnID0gdGhpcy5jb25maWd1cmVkO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXREZWJ1Z05hbWUoKSB7XG4gICAgICAgIGxldCB1cmxzID0gdGhpcy5hY3RpdmVDb25maWcuc291cmNlcy5tYXAoeCA9PiB0eXBlb2YgeCA9PT0gXCJzdHJpbmdcIiAmJiB4IHx8ICh4IGFzIEhvc3RlZENvbmZpZyB8IEJhY2tibGF6ZUNvbmZpZykudXJsKTtcbiAgICAgICAgcmV0dXJuIGBjaGFpbi8ke3VybHMuam9pbihcIixcIil9YDtcbiAgICB9XG5cbiAgICAvLyBMYXp5IGluaXQgdGhhdCByZXRocm93cyBpdHMgZXJyb3IgdG8gZXZlcnkgY2FsbGVyLCB3aGlsZSBhIGJhY2tncm91bmQgdGltZXIgcmVzZXRzIGFuZFxuICAgIC8vIHJldHJpZXMgaXQgd2l0aCBhIHJhbXBpbmcgZGVsYXkgLSBzbyBhIGNoYWluIHRoYXQgY291bGRuJ3QgaW5pdGlhbGl6ZSBmaXhlcyBpdHNlbGYgb25jZSBhXG4gICAgLy8gc291cmNlIGNvbWVzIGJhY2ssIHdpdGhvdXQgYW55IGNhbGxlciBoYXZpbmcgdG8gZHJpdmUgaXQuXG4gICAgcHJpdmF0ZSBnZXRTdGF0ZSgpOiBQcm9taXNlPENoYWluU3RhdGU+IHtcbiAgICAgICAgaWYgKHRoaXMuZGlzcG9zZWQpIHtcbiAgICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChuZXcgRXJyb3IoYEFyY2hpdmVzQ2hhaW4gJHt0aGlzLmdldERlYnVnTmFtZSgpfSBoYXMgYmVlbiBkaXNwb3NlZGApKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXRoaXMuc3RhdGVQcm9taXNlKSB7XG4gICAgICAgICAgICBsZXQgcHJvbWlzZSA9IHRoaXMuaW5pdCgpO1xuICAgICAgICAgICAgdGhpcy5zdGF0ZVByb21pc2UgPSBwcm9taXNlO1xuICAgICAgICAgICAgcHJvbWlzZS50aGVuKCgpID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLmluaXRSZXRyeURlbGF5ID0gUkVUUllfU1RBUlRfREVMQVk7XG4gICAgICAgICAgICB9LCAoZTogRXJyb3IpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5kaXNwb3NlZCB8fCB0aGlzLmluaXRSZXRyeVRpbWVyKSByZXR1cm47XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihgU3RvcmFnZSBpbml0IGZhaWxlZCBmb3IgJHt0aGlzLmdldERlYnVnTmFtZSgpfSwgcmV0cnlpbmcgaW4gJHtNYXRoLnJvdW5kKHRoaXMuaW5pdFJldHJ5RGVsYXkgLyAxMDAwKX1zLiAke2Uuc3RhY2sgPz8gZX1gKTtcbiAgICAgICAgICAgICAgICB0aGlzLmluaXRSZXRyeVRpbWVyID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuaW5pdFJldHJ5VGltZXIgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLmRpc3Bvc2VkKSByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLnN0YXRlUHJvbWlzZSA9PT0gcHJvbWlzZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5zdGF0ZVByb21pc2UgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgdGhpcy5nZXRTdGF0ZSgpLmNhdGNoKCgpID0+IHsgfSk7XG4gICAgICAgICAgICAgICAgfSwgdGhpcy5pbml0UmV0cnlEZWxheSk7XG4gICAgICAgICAgICAgICAgKHRoaXMuaW5pdFJldHJ5VGltZXIgYXMgeyB1bnJlZj86ICgpID0+IHZvaWQgfSkudW5yZWY/LigpO1xuICAgICAgICAgICAgICAgIHRoaXMuaW5pdFJldHJ5RGVsYXkgPSBNYXRoLm1pbihSRVRSWV9NQVhfREVMQVksIHRoaXMuaW5pdFJldHJ5RGVsYXkgKiBSRVRSWV9HUk9XVEgpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMuc3RhdGVQcm9taXNlO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgaW5pdCgpOiBQcm9taXNlPENoYWluU3RhdGU+IHtcbiAgICAgICAgbGV0IGNvbmZpZ3MgPSB0aGlzLmNvbmZpZ3VyZWQuc291cmNlcy5tYXAobm9ybWFsaXplU291cmNlKTtcbiAgICAgICAgbGV0IHByb2JlRXJyb3JzOiBzdHJpbmdbXSA9IFtdO1xuICAgICAgICBsZXQgZm91bmQ6IHsgcHJvYmU6IFNvdXJjZVdyYXBwZXI7IGV4aXN0aW5nOiBSZW1vdGVDb25maWcgfCB1bmRlZmluZWQgfSB8IHVuZGVmaW5lZDtcbiAgICAgICAgZm9yIChsZXQgc291cmNlQ29uZmlnIG9mIGNvbmZpZ3MpIHtcbiAgICAgICAgICAgIGxldCBwcm9iZSA9IGF3YWl0IFNvdXJjZVdyYXBwZXIuY3JlYXRlKHNvdXJjZUNvbmZpZywgeyBiYWNrZ3JvdW5kOiBmYWxzZSB9KTtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgbGV0IGRhdGEgPSBhd2FpdCBwcm9iZS5yZWFkKGFyY2hpdmVzID0+IGFyY2hpdmVzLmdldChST1VUSU5HX0ZJTEUpKTtcbiAgICAgICAgICAgICAgICBmb3VuZCA9IHsgcHJvYmUsIGV4aXN0aW5nOiBkYXRhICYmIHBhcnNlUm91dGluZ0RhdGEoZGF0YSkgfHwgdW5kZWZpbmVkIH07XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgcHJvYmVFcnJvcnMucHVzaChgJHtzb3VyY2VDb25maWcudXJsfTogJHsoZSBhcyBFcnJvcikuc3RhY2sgPz8gZX1gKTtcbiAgICAgICAgICAgICAgICBwcm9iZS5kaXNwb3NlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFmb3VuZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBDYW5ub3QgaW5pdGlhbGl6ZSBzdG9yYWdlIGZvciAke3RoaXMuZ2V0RGVidWdOYW1lKCl9OiBubyBzb3VyY2UgYW5zd2VyZWQuICR7cHJvYmVFcnJvcnMuam9pbihcIiB8IFwiKX1gKTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgYWN0aXZlID0gdGhpcy5jb25maWd1cmVkO1xuICAgICAgICBsZXQgeyBwcm9iZSwgZXhpc3RpbmcgfSA9IGZvdW5kO1xuICAgICAgICBsZXQgbmVlZHNXcml0ZSA9IHRydWU7XG4gICAgICAgIGlmIChleGlzdGluZyAmJiBnZXRDb25maWdWZXJzaW9uKGV4aXN0aW5nKSA+PSBnZXRDb25maWdWZXJzaW9uKHRoaXMuY29uZmlndXJlZCkpIHtcbiAgICAgICAgICAgIGlmIChnZXRDb25maWdWZXJzaW9uKGV4aXN0aW5nKSA9PT0gZ2V0Q29uZmlnVmVyc2lvbih0aGlzLmNvbmZpZ3VyZWQpICYmIEpTT04uc3RyaW5naWZ5KGV4aXN0aW5nKSAhPT0gSlNPTi5zdHJpbmdpZnkodGhpcy5jb25maWd1cmVkKSkge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYEFyY2hpdmVzIGNvbmZpZ3VyYXRpb24gdXBkYXRlZCB3aXRob3V0IHVwZGF0aW5nIHRoZSB2ZXJzaW9uLCBmb3IgJHtwcm9iZS5jb25maWcudXJsfS4gVXBkYXRlcyB3aWxsIGJlIGlnbm9yZWQgdW50aWwgeW91IGluY3JlYXNlIHRoZSB2ZXJzaW9uLiBVc2luZzogJHtKU09OLnN0cmluZ2lmeShleGlzdGluZyl9LCBpZ25vcmluZzogJHtKU09OLnN0cmluZ2lmeSh0aGlzLmNvbmZpZ3VyZWQpfWApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYWN0aXZlID0gZXhpc3Rpbmc7XG4gICAgICAgICAgICBuZWVkc1dyaXRlID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IHNvdXJjZXMgPSBhd2FpdCB0aGlzLmJ1aWxkU291cmNlcyhhY3RpdmUpO1xuICAgICAgICBpZiAobmVlZHNXcml0ZSkge1xuICAgICAgICAgICAgLy8gV2UgZGVjaWRlZCB0byB3cml0ZSAob3VycyBpcyBuZXdlciB0aGFuIHRoZSBhdXRob3JpdGF0aXZlIGZpcnN0LXVwIHNvdXJjZSdzLCBvciBub1xuICAgICAgICAgICAgLy8gcm91dGluZyBleGlzdHMgeWV0KS4gVGhlIHdyaXRlIGdvZXMgdG8gYWxsIHNvdXJjZXMsIHNvIG5vdyBFVkVSWSByZWFjaGFibGUgc291cmNlJ3NcbiAgICAgICAgICAgIC8vIHN0b3JlZCByb3V0aW5nIGlzIHJlYWQsIGFuZCB0aGUgd3JpdGUgaXMgcmVmdXNlZCB1bmxlc3Mgb3VyIHZlcnNpb24gaXMgc3RyaWN0bHlcbiAgICAgICAgICAgIC8vIGdyZWF0ZXIgdGhhbiBhbGwgb2YgdGhlbSAtIGEgc291cmNlIGFscmVhZHkgYXQgKG9yIHBhc3QpIG91ciB2ZXJzaW9uIG1lYW5zIHRoaXNcbiAgICAgICAgICAgIC8vIHZlcnNpb24gbnVtYmVyIGlzIHRha2VuLCBhbmQgd3JpdGluZyBhbnl3YXkgd291bGQgbGVhdmUgc291cmNlcyBhdCB0aGUgc2FtZSB2ZXJzaW9uXG4gICAgICAgICAgICAvLyB3aXRoIGRpZmZlcmVudCBjb250ZW50LCBlYWNoIHJlamVjdGluZyB0aGUgb3RoZXIncyBwdXNoZXMgZm9yZXZlci5cbiAgICAgICAgICAgIGxldCBiZXN0OiBSZW1vdGVDb25maWcgfCB1bmRlZmluZWQ7XG4gICAgICAgICAgICBsZXQgY29uZmxpY3RVcmw6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIGZvciAobGV0IHNvdXJjZSBvZiBzb3VyY2VzKSB7XG4gICAgICAgICAgICAgICAgbGV0IGRhdGE6IEJ1ZmZlciB8IHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICBkYXRhID0gYXdhaXQgc291cmNlLnJlYWQoYXJjaGl2ZXMgPT4gYXJjaGl2ZXMuZ2V0KFJPVVRJTkdfRklMRSkpO1xuICAgICAgICAgICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgICAgICAgICAgICAvLyBEb3duIHNvdXJjZXMgYXJlIHN0aWxsIHByb3RlY3RlZCBieSB0aGUgc2VydmVyLXNpZGUgdmVyc2lvbiBndWFyZCB3aGVuIHRoZVxuICAgICAgICAgICAgICAgICAgICAvLyB3cml0ZSBldmVudHVhbGx5IHJlYWNoZXMgdGhlbVxuICAgICAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKCFkYXRhKSBjb250aW51ZTtcbiAgICAgICAgICAgICAgICBsZXQgc3RvcmVkID0gcGFyc2VSb3V0aW5nRGF0YShkYXRhKTtcbiAgICAgICAgICAgICAgICBpZiAoIWJlc3QgfHwgZ2V0Q29uZmlnVmVyc2lvbihzdG9yZWQpID4gZ2V0Q29uZmlnVmVyc2lvbihiZXN0KSkge1xuICAgICAgICAgICAgICAgICAgICBiZXN0ID0gc3RvcmVkO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoZ2V0Q29uZmlnVmVyc2lvbihzdG9yZWQpID09PSBnZXRDb25maWdWZXJzaW9uKHRoaXMuY29uZmlndXJlZCkgJiYgSlNPTi5zdHJpbmdpZnkoc3RvcmVkKSAhPT0gSlNPTi5zdHJpbmdpZnkodGhpcy5jb25maWd1cmVkKSkge1xuICAgICAgICAgICAgICAgICAgICBjb25mbGljdFVybCA9IHNvdXJjZS5jb25maWcudXJsO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChiZXN0ICYmIGdldENvbmZpZ1ZlcnNpb24oYmVzdCkgPj0gZ2V0Q29uZmlnVmVyc2lvbih0aGlzLmNvbmZpZ3VyZWQpKSB7XG4gICAgICAgICAgICAgICAgaWYgKGNvbmZsaWN0VXJsICYmIGdldENvbmZpZ1ZlcnNpb24oYmVzdCkgPT09IGdldENvbmZpZ1ZlcnNpb24odGhpcy5jb25maWd1cmVkKSkge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKGBBcmNoaXZlcyBjb25maWd1cmF0aW9uIHVwZGF0ZWQgd2l0aG91dCB1cGRhdGluZyB0aGUgdmVyc2lvbiwgZm9yICR7Y29uZmxpY3RVcmx9LiBVcGRhdGVzIHdpbGwgYmUgaWdub3JlZCB1bnRpbCB5b3UgaW5jcmVhc2UgdGhlIHZlcnNpb24uIFVzaW5nOiAke0pTT04uc3RyaW5naWZ5KGJlc3QpfSwgaWdub3Jpbmc6ICR7SlNPTi5zdHJpbmdpZnkodGhpcy5jb25maWd1cmVkKX1gKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgYWN0aXZlID0gYmVzdDtcbiAgICAgICAgICAgICAgICBuZWVkc1dyaXRlID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgZm9yIChsZXQgc291cmNlIG9mIHNvdXJjZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgc291cmNlLmRpc3Bvc2UoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgc291cmNlcyA9IGF3YWl0IHRoaXMuYnVpbGRTb3VyY2VzKGFjdGl2ZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG5lZWRzV3JpdGUpIHtcbiAgICAgICAgICAgIC8vIFRoZSB1cGRhdGUgb25seSBoYXBwZW5zIHdoZW4gRVZFUlkgc291cmNlIHdvdWxkIGFjY2VwdCBpdCAtIGEgcGFydGlhbCB1cGRhdGUgd291bGRcbiAgICAgICAgICAgIC8vIGxlYXZlIHRoZSBzb3VyY2VzIG91dCBvZiBzeW5jLCBhbmQgYSBjbGllbnQgd2l0aG91dCBhY2Nlc3MgcmV0cnlpbmcgdGhlIHdyaXRlIGZvcmV2ZXJcbiAgICAgICAgICAgIC8vIHdvdWxkIG5ldmVyIGluaXRpYWxpemUuIFdpdGhvdXQgZnVsbCBhY2Nlc3Mgd2UgcnVuIG9uIHRoZSBzdG9yZWQgY29uZmlnICh3aGVuIHRoZXJlXG4gICAgICAgICAgICAvLyBpcyBvbmUpIGFuZCBsb2cgdGhlIHByb2JsZW0gaW5zdGVhZC5cbiAgICAgICAgICAgIGxldCBtaXNzaW5nOiBzdHJpbmdbXSA9IFtdO1xuICAgICAgICAgICAgZm9yIChsZXQgc291cmNlIG9mIHNvdXJjZXMpIHtcbiAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoIWF3YWl0IHNvdXJjZS5oYXNXcml0ZUFjY2VzcygpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBtaXNzaW5nLnB1c2goc291cmNlLmNvbmZpZy51cmwpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgICAgICBtaXNzaW5nLnB1c2goYCR7c291cmNlLmNvbmZpZy51cmx9IChjaGVjayBmYWlsZWQ6ICR7KGUgYXMgRXJyb3IpLnN0YWNrID8/IGV9KWApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChtaXNzaW5nLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYE5vdCB3cml0aW5nIHRoZSBzdG9yYWdlIHJvdXRpbmcgY29uZmlnIGZvciAke3RoaXMuZ2V0RGVidWdOYW1lKCl9ICh2ZXJzaW9uICR7Z2V0Q29uZmlnVmVyc2lvbih0aGlzLmNvbmZpZ3VyZWQpfSk6IG5vIHdyaXRlIGFjY2VzcyB0byAke21pc3Npbmcuam9pbihcIiwgXCIpfS4gJHtleGlzdGluZyAmJiBgUnVubmluZyBvbiB0aGUgc3RvcmVkIGNvbmZpZyAodmVyc2lvbiAke2dldENvbmZpZ1ZlcnNpb24oZXhpc3RpbmcpfSkgaW5zdGVhZC5gIHx8IGBObyBzdG9yZWQgY29uZmlnIGV4aXN0cywgc28gdGhlIGJ1Y2tldCBjYW5ub3QgYmUgY3JlYXRlZCB1bnRpbCB3cml0ZSBhY2Nlc3MgaXMgZ3JhbnRlZC5gfWApO1xuICAgICAgICAgICAgICAgIGlmIChleGlzdGluZykge1xuICAgICAgICAgICAgICAgICAgICBhY3RpdmUgPSBleGlzdGluZztcbiAgICAgICAgICAgICAgICAgICAgZm9yIChsZXQgc291cmNlIG9mIHNvdXJjZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNvdXJjZS5kaXNwb3NlKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgc291cmNlcyA9IGF3YWl0IHRoaXMuYnVpbGRTb3VyY2VzKGFjdGl2ZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICAvLyBBIHJlamVjdGVkIHdyaXRlIGZhaWxzIGluaXQsIHdoaWNoIHJldHJpZXMgZnJvbSBzY3JhdGNoIC0gcmUtcmVhZGluZyB0aGVcbiAgICAgICAgICAgICAgICAgICAgLy8gcm91dGluZywgc28gbG9zaW5nIGEgY3JlYXRlIHJhY2UgdG8gYW5vdGhlciBjbGllbnQganVzdCBhZG9wdHMgdGhlaXIgY29uZmlnXG4gICAgICAgICAgICAgICAgICAgIC8vIG9uIHRoZSBuZXh0IGF0dGVtcHQuXG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IHByb2JlLndyaXRlKGFyY2hpdmVzID0+IGFyY2hpdmVzLnNldChST1VUSU5HX0ZJTEUsIHNlcmlhbGl6ZVJlbW90ZUNvbmZpZyh0aGlzLmNvbmZpZ3VyZWQpKSk7XG4gICAgICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgICAgICBmb3IgKGxldCBzb3VyY2Ugb2Ygc291cmNlcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgc291cmNlLmRpc3Bvc2UoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBwcm9iZS5kaXNwb3NlKCk7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IGU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHByb2JlLmRpc3Bvc2UoKTtcbiAgICAgICAgdGhpcy5hY3RpdmVDb25maWcgPSBhY3RpdmU7XG4gICAgICAgIHRoaXMuc3RhcnRDb25maWdQb2xsKCk7XG4gICAgICAgIHJldHVybiB7IGNvbmZpZzogYWN0aXZlLCBzb3VyY2VzIH07XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBidWlsZFNvdXJjZXMoY29uZmlnOiBSZW1vdGVDb25maWcpOiBQcm9taXNlPFNvdXJjZVdyYXBwZXJbXT4ge1xuICAgICAgICBsZXQgc291cmNlczogU291cmNlV3JhcHBlcltdID0gW107XG4gICAgICAgIGZvciAobGV0IHNvdXJjZUNvbmZpZyBvZiBjb25maWcuc291cmNlcy5tYXAobm9ybWFsaXplU291cmNlKSkge1xuICAgICAgICAgICAgbGV0IHNvdXJjZSA9IGF3YWl0IFNvdXJjZVdyYXBwZXIuY3JlYXRlKHNvdXJjZUNvbmZpZyk7XG4gICAgICAgICAgICAvLyBMYXRlbmN5IChmb3IgdmFyaWFibGUtc2hhcmQgdGFyZ2V0IHByZWZlcmVuY2UpIGlzIHRyYWNrZWQgZnJvbSBpbml0aWFsaXphdGlvbiBvblxuICAgICAgICAgICAgc291cmNlLnN0YXJ0UGluZ2luZygpO1xuICAgICAgICAgICAgc291cmNlcy5wdXNoKHNvdXJjZSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHNvdXJjZXM7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzdGFydENvbmZpZ1BvbGwoKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLnBvbGxUaW1lciB8fCB0aGlzLmRpc3Bvc2VkKSByZXR1cm47XG4gICAgICAgIHRoaXMucG9sbFRpbWVyID0gc2V0SW50ZXJ2YWwoKCkgPT4ge1xuICAgICAgICAgICAgdm9pZCB0aGlzLmNoZWNrRm9yTmV3Q29uZmlnKCkuY2F0Y2goKGU6IEVycm9yKSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihgQ2hlY2tpbmcgZm9yIGEgbmV3IHN0b3JhZ2Ugcm91dGluZyBjb25maWcgZmFpbGVkIGZvciAke3RoaXMuZ2V0RGVidWdOYW1lKCl9OiAke2Uuc3RhY2sgPz8gZX1gKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9LCBDT05GSUdfUE9MTF9JTlRFUlZBTCk7XG4gICAgICAgICh0aGlzLnBvbGxUaW1lciBhcyB7IHVucmVmPzogKCkgPT4gdm9pZCB9KS51bnJlZj8uKCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBjaGVja0Zvck5ld0NvbmZpZygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgaWYgKHRoaXMuZGlzcG9zZWQgfHwgIXRoaXMuc3RhdGVQcm9taXNlKSByZXR1cm47XG4gICAgICAgIGxldCBzdGF0ZTogQ2hhaW5TdGF0ZTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHN0YXRlID0gYXdhaXQgdGhpcy5zdGF0ZVByb21pc2U7XG4gICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgICAgLy8gSW5pdCBpcyBmYWlsaW5nOyBpdHMgb3duIHJldHJ5IGxvb3AgaGFuZGxlcyB0aGF0XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgbGV0IGRhdGEgPSBhd2FpdCB0aGlzLnJ1bihzdGF0ZSwge30sIGFyY2hpdmVzID0+IGFyY2hpdmVzLmdldChST1VUSU5HX0ZJTEUpKTtcbiAgICAgICAgaWYgKCFkYXRhKSByZXR1cm47XG4gICAgICAgIGxldCBsYXRlc3QgPSBwYXJzZVJvdXRpbmdEYXRhKGRhdGEpO1xuICAgICAgICBpZiAoSlNPTi5zdHJpbmdpZnkobGF0ZXN0KSA9PT0gSlNPTi5zdHJpbmdpZnkoc3RhdGUuY29uZmlnKSkgcmV0dXJuO1xuICAgICAgICBjb25zb2xlLmxvZyhgU3RvcmFnZSByb3V0aW5nIGNvbmZpZyBjaGFuZ2VkIGZvciAke3RoaXMuZ2V0RGVidWdOYW1lKCl9LCByZWJ1aWxkaW5nIHNvdXJjZXNgKTtcbiAgICAgICAgbGV0IG9sZEJ5Q29uZmlnID0gbmV3IE1hcChzdGF0ZS5zb3VyY2VzLm1hcChzb3VyY2UgPT4gW0pTT04uc3RyaW5naWZ5KHNvdXJjZS5jb25maWcpLCBzb3VyY2VdKSk7XG4gICAgICAgIGxldCBzb3VyY2VzOiBTb3VyY2VXcmFwcGVyW10gPSBbXTtcbiAgICAgICAgZm9yIChsZXQgc291cmNlQ29uZmlnIG9mIGxhdGVzdC5zb3VyY2VzLm1hcChub3JtYWxpemVTb3VyY2UpKSB7XG4gICAgICAgICAgICBsZXQga2V5ID0gSlNPTi5zdHJpbmdpZnkoc291cmNlQ29uZmlnKTtcbiAgICAgICAgICAgIGxldCBvbGQgPSBvbGRCeUNvbmZpZy5nZXQoa2V5KTtcbiAgICAgICAgICAgIGlmIChvbGQpIHtcbiAgICAgICAgICAgICAgICBvbGRCeUNvbmZpZy5kZWxldGUoa2V5KTtcbiAgICAgICAgICAgICAgICBzb3VyY2VzLnB1c2gob2xkKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc291cmNlcy5wdXNoKGF3YWl0IFNvdXJjZVdyYXBwZXIuY3JlYXRlKHNvdXJjZUNvbmZpZykpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIC8vIEluLWZsaWdodCByZXF1ZXN0cyBzdGlsbCBob2xkIHRoZSBvbGQgd3JhcHBlcnMgYW5kIGZpbmlzaCBmaW5lOyBkaXNwb3NlIGp1c3Qgc3RvcHMgYW55XG4gICAgICAgIC8vIGJhY2tncm91bmQgcmVjb25uZWN0IGxvb3BzXG4gICAgICAgIGZvciAobGV0IGxlZnRvdmVyIG9mIG9sZEJ5Q29uZmlnLnZhbHVlcygpKSB7XG4gICAgICAgICAgICBsZWZ0b3Zlci5kaXNwb3NlKCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5hY3RpdmVDb25maWcgPSBsYXRlc3Q7XG4gICAgICAgIHRoaXMuc3RhdGVQcm9taXNlID0gUHJvbWlzZS5yZXNvbHZlKHsgY29uZmlnOiBsYXRlc3QsIHNvdXJjZXMgfSk7XG4gICAgfVxuXG4gICAgLy8gUnVucyBhIHJlcXVlc3QgYWdhaW5zdCB0aGUgZmlyc3QgYXZhaWxhYmxlIHNvdXJjZSAodGhhdCBjb3ZlcnMgdGhlIGtleSdzIHJvdXRlLCB3aGVuIG9uZSBpc1xuICAgIC8vIGdpdmVuKSwgbW92aW5nIHRvIHRoZSBuZXh0IG9uZSBPTkxZIHdoZW4gdGhlIHNvdXJjZSdzIFdlYlNvY2tldCBpcyBkb3duIChjaGVja2VkIGRpcmVjdGx5IC1cbiAgICAvLyBuZXZlciBieSBpbnNwZWN0aW5nIHRoZSBlcnJvciwgd2hpY2ggaXMgYXJiaXRyYXJ5IGRhdGEpLiBBbiBlcnJvciBmcm9tIGEgY29ubmVjdGVkIHNvdXJjZSBpc1xuICAgIC8vIGFuIGFwcGxpY2F0aW9uIGVycm9yIGFuZCB0aHJvd3MgYXMtaXMuIEEgZG93biBzb3VyY2UgZ2V0cyBpdHMgYmFja2dyb3VuZCByZWNvbm5lY3Qga2lja2VkLlxuICAgIHByaXZhdGUgYXN5bmMgcnVuPFQ+KHN0YXRlOiBDaGFpblN0YXRlLCBjb25maWc6IHsgYXBpT25seT86IGJvb2xlYW47IHdyaXRlPzogYm9vbGVhbjsgcm91dGU/OiBudW1iZXIgfSwgcnVuOiAoYXJjaGl2ZXM6IElBcmNoaXZlcykgPT4gUHJvbWlzZTxUPik6IFByb21pc2U8VD4ge1xuICAgICAgICBpZiAoY29uZmlnLndyaXRlKSB7XG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5ydW5Xcml0ZShzdGF0ZSwgY29uZmlnLnJvdXRlLCBydW4pO1xuICAgICAgICB9XG4gICAgICAgIGxldCBlcnJvcnM6IHN0cmluZ1tdID0gW107XG4gICAgICAgIGZvciAobGV0IHNvdXJjZSBvZiBzdGF0ZS5zb3VyY2VzKSB7XG4gICAgICAgICAgICBpZiAoY29uZmlnLnJvdXRlICE9PSB1bmRlZmluZWQgJiYgIXJvdXRlQ29udGFpbnMoc291cmNlLmNvbmZpZy5yb3V0ZSwgY29uZmlnLnJvdXRlKSkgY29udGludWU7XG4gICAgICAgICAgICBpZiAoIWNvbmZpZ1dpbmRvd0N1cnJlbnQoc291cmNlLmNvbmZpZykpIGNvbnRpbnVlO1xuICAgICAgICAgICAgaWYgKCFzb3VyY2UuaXNDb25uZWN0ZWQoKSkge1xuICAgICAgICAgICAgICAgIHNvdXJjZS5ub3RlRmFpbHVyZSgpO1xuICAgICAgICAgICAgICAgIGVycm9ycy5wdXNoKGAke3NvdXJjZS5jb25maWcudXJsfSBpcyBub3QgY29ubmVjdGVkYCk7XG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGlmIChjb25maWcuYXBpT25seSkge1xuICAgICAgICAgICAgICAgICAgICBsZXQgYXBpID0gc291cmNlLmFwaTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFhcGkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVycm9ycy5wdXNoKGAke3NvdXJjZS5jb25maWcudXJsfSBoYXMgVVJMLW9ubHkgYWNjZXNzLCB3aGljaCBjYW5ub3Qgc2VydmUgdGhpcyBvcGVyYXRpb25gKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBhd2FpdCBydW4oYXBpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIGF3YWl0IHNvdXJjZS5yZWFkKHJ1bik7XG4gICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgaWYgKHNvdXJjZS5pc0Nvbm5lY3RlZCgpKSB0aHJvdyBlO1xuICAgICAgICAgICAgICAgIHNvdXJjZS5ub3RlRmFpbHVyZSgpO1xuICAgICAgICAgICAgICAgIGVycm9ycy5wdXNoKFN0cmluZygoZSBhcyBFcnJvcikuc3RhY2sgPz8gZSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgQWxsIHNvdXJjZXMgZmFpbGVkIGZvciAke3RoaXMuZ2V0RGVidWdOYW1lKCl9JHtjb25maWcucm91dGUgIT09IHVuZGVmaW5lZCAmJiBgIChyb3V0ZSAke2NvbmZpZy5yb3V0ZX0pYCB8fCBcIlwifTogJHtlcnJvcnMuam9pbihcIiB8IFwiKSB8fCBcIm5vIHNvdXJjZXMgYXZhaWxhYmxlXCJ9YCk7XG4gICAgfVxuXG4gICAgLy8gV3JpdGVzIGFyZSBjb25zaXN0ZW50OiB0aGV5IGdvIHRvIHRoZSBmaXJzdCBjdXJyZW50bHktdmFsaWQgc291cmNlIGNvdmVyaW5nIHRoZSBrZXkncyByb3V0ZVxuICAgIC8vIGFuZCBORVZFUiBmYWlsIG92ZXIgdG8gYW5vdGhlciBub2RlIC0gYSBjbGllbnQgd3JvbmdseSBkZWNpZGluZyBub2RlcyBhcmUgZG93biBtdXN0IG5vdFxuICAgIC8vIHNjYXR0ZXIgaXRzIHdyaXRlcyBhY3Jvc3MgdGhlIGNoYWluLiAoUmVhZHMgZmFpbCBvdmVyIGZyZWVseSBhYm92ZTogc291cmNlcyBhcmUgc3luY2hyb25pemVkXG4gICAgLy8gY29waWVzLCBzbyByZWFkaW5nIGZyb20gYW55IG9mIHRoZW0gaXMgc2FmZS4pIFRoZSBvbmUgcmV0cnkgaXMgZm9yIGEgd2luZG93IGJvdW5kYXJ5IHBhc3NpbmdcbiAgICAvLyAob3IgYSByb3V0ZSBkaXNhZ3JlZW1lbnQpIG1pZC13cml0ZSwgd2hpY2ggcmUtcmVzb2x2ZXMgdGhlIHRhcmdldCByYXRoZXIgdGhhbiBmYWxsaW5nIGJhY2suXG4gICAgcHJpdmF0ZSBhc3luYyBydW5Xcml0ZTxUPihzdGF0ZTogQ2hhaW5TdGF0ZSwgcm91dGU6IG51bWJlciB8IHVuZGVmaW5lZCwgcnVuOiAoYXJjaGl2ZXM6IElBcmNoaXZlcykgPT4gUHJvbWlzZTxUPik6IFByb21pc2U8VD4ge1xuICAgICAgICBsZXQgcmV0cmllZFdyb25nV2luZG93ID0gZmFsc2U7XG4gICAgICAgIGxldCByZXRyaWVkV3JvbmdSb3V0ZSA9IGZhbHNlO1xuICAgICAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgICAgICAgbGV0IHRhcmdldCA9IHN0YXRlLnNvdXJjZXMuZmluZCh4ID0+IGNvbmZpZ0FjY2VwdHNXcml0ZXMoeC5jb25maWcpICYmIChyb3V0ZSA9PT0gdW5kZWZpbmVkIHx8IHJvdXRlQ29udGFpbnMoeC5jb25maWcucm91dGUsIHJvdXRlKSkpO1xuICAgICAgICAgICAgaWYgKCF0YXJnZXQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYE5vIHNvdXJjZSBhY2NlcHRzIHdyaXRlcyBmb3IgJHt0aGlzLmdldERlYnVnTmFtZSgpfSR7cm91dGUgIT09IHVuZGVmaW5lZCAmJiBgIChyb3V0ZSAke3JvdXRlfSlgIHx8IFwiXCJ9IChldmVyeSBzb3VyY2UgaXMgb3V0c2lkZSBpdHMgdmFsaWQgd2luZG93IG9yIG91dHNpZGUgdGhlIGtleSdzIHJvdXRlKWApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCF0YXJnZXQuaXNDb25uZWN0ZWQoKSkge1xuICAgICAgICAgICAgICAgIHRhcmdldC5ub3RlRmFpbHVyZSgpO1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgQ2Fubm90IHdyaXRlOiB0aGUgd3JpdGUgdGFyZ2V0ICR7dGFyZ2V0LmNvbmZpZy51cmx9IGlzIG5vdCBjb25uZWN0ZWQgKHdyaXRlcyBuZXZlciBmYWlsIG92ZXIgdG8gb3RoZXIgc291cmNlcylgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGF3YWl0IHRhcmdldC53cml0ZShydW4pO1xuICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgIGxldCBtZXNzYWdlID0gU3RyaW5nKChlIGFzIEVycm9yKS5zdGFjayA/PyBlKTtcbiAgICAgICAgICAgICAgICBpZiAobWVzc2FnZS5pbmNsdWRlcyhTVE9SQUdFX1dST05HX1ZBTElEX1dJTkRPVykgJiYgIXJldHJpZWRXcm9uZ1dpbmRvdykge1xuICAgICAgICAgICAgICAgICAgICByZXRyaWVkV3JvbmdXaW5kb3cgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKG1lc3NhZ2UuaW5jbHVkZXMoU1RPUkFHRV9XUk9OR19ST1VURSkgJiYgIXJldHJpZWRXcm9uZ1JvdXRlKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHJpZWRXcm9uZ1JvdXRlID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmICghdGFyZ2V0LmlzQ29ubmVjdGVkKCkpIHtcbiAgICAgICAgICAgICAgICAgICAgdGFyZ2V0Lm5vdGVGYWlsdXJlKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRocm93IGU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIHJlcXVlc3Q8VD4oY29uZmlnOiB7IGFwaU9ubHk/OiBib29sZWFuOyB3cml0ZT86IGJvb2xlYW47IHJvdXRlPzogbnVtYmVyIH0sIHJ1bjogKGFyY2hpdmVzOiBJQXJjaGl2ZXMpID0+IFByb21pc2U8VD4pOiBQcm9taXNlPFQ+IHtcbiAgICAgICAgbGV0IHN0YXRlID0gYXdhaXQgdGhpcy5nZXRTdGF0ZSgpO1xuICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5ydW4oc3RhdGUsIGNvbmZpZywgcnVuKTtcbiAgICB9XG5cbiAgICAvLyBUaGUgYWNjZXNzLXBhZ2UgbGluayAocGx1cyBvdXIgbWFjaGluZUlkL2lwLCBmb3IgdGhlIGFwcHJvdmVyIHRvIG1hdGNoIHRoZSByZXF1ZXN0KSBmb3IgdGhlXG4gICAgLy8gZmlyc3QgaG9zdGVkIHNvdXJjZSB0aGF0IGhhc24ndCBncmFudGVkIHVzIGFjY2Vzcy4gdW5kZWZpbmVkIHdoZW4gd2UgaGF2ZSBhY2Nlc3MgZXZlcnl3aGVyZVxuICAgIC8vIHdlIGNhbiBoYXZlIGl0LiBBbHNvIHJlZ2lzdGVycyB0aGUgYWNjZXNzIHJlcXVlc3Qgc2VydmVyLXNpZGUuXG4gICAgcHVibGljIGFzeW5jIHdhaXRpbmdGb3JBY2Nlc3MoKTogUHJvbWlzZTx7IGxpbms6IHN0cmluZzsgbWFjaGluZUlkOiBzdHJpbmc7IGlwOiBzdHJpbmcgfSB8IHVuZGVmaW5lZD4ge1xuICAgICAgICBsZXQgc3RhdGUgPSBhd2FpdCB0aGlzLmdldFN0YXRlKCk7XG4gICAgICAgIGZvciAobGV0IHNvdXJjZSBvZiBzdGF0ZS5zb3VyY2VzKSB7XG4gICAgICAgICAgICBpZiAoc291cmNlLmFwaSBpbnN0YW5jZW9mIEFyY2hpdmVzUmVtb3RlKSB7XG4gICAgICAgICAgICAgICAgbGV0IHdhaXRpbmcgPSBhd2FpdCBzb3VyY2UuYXBpLndhaXRpbmdGb3JBY2Nlc3MoKTtcbiAgICAgICAgICAgICAgICBpZiAod2FpdGluZykgcmV0dXJuIHdhaXRpbmc7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgZ2V0KGZpbGVOYW1lOiBzdHJpbmcsIGNvbmZpZz86IHsgcmFuZ2U/OiB7IHN0YXJ0OiBudW1iZXI7IGVuZDogbnVtYmVyIH0gfSk6IFByb21pc2U8QnVmZmVyIHwgdW5kZWZpbmVkPiB7XG4gICAgICAgIGxldCByZXN1bHQgPSBhd2FpdCB0aGlzLmdldDIoZmlsZU5hbWUsIGNvbmZpZyk7XG4gICAgICAgIHJldHVybiByZXN1bHQgJiYgcmVzdWx0LmRhdGEgfHwgdW5kZWZpbmVkO1xuICAgIH1cbiAgICBwdWJsaWMgYXN5bmMgZ2V0MihmaWxlTmFtZTogc3RyaW5nLCBjb25maWc/OiB7IHJhbmdlPzogeyBzdGFydDogbnVtYmVyOyBlbmQ6IG51bWJlciB9IH0pOiBQcm9taXNlPHsgZGF0YTogQnVmZmVyOyB3cml0ZVRpbWU6IG51bWJlcjsgc2l6ZTogbnVtYmVyIH0gfCB1bmRlZmluZWQ+IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMucmVxdWVzdCh7IHJvdXRlOiBnZXRSb3V0ZShmaWxlTmFtZSkgfSwgYXJjaGl2ZXMgPT4gYXJjaGl2ZXMuZ2V0MihmaWxlTmFtZSwgY29uZmlnKSk7XG4gICAgfVxuICAgIHB1YmxpYyBhc3luYyBnZXRJbmZvKGZpbGVOYW1lOiBzdHJpbmcpOiBQcm9taXNlPHsgd3JpdGVUaW1lOiBudW1iZXI7IHNpemU6IG51bWJlciB9IHwgdW5kZWZpbmVkPiB7XG4gICAgICAgIHJldHVybiBhd2FpdCB0aGlzLnJlcXVlc3QoeyByb3V0ZTogZ2V0Um91dGUoZmlsZU5hbWUpIH0sIGFyY2hpdmVzID0+IGFyY2hpdmVzLmdldEluZm8oZmlsZU5hbWUpKTtcbiAgICB9XG5cbiAgICAvLyBBIG1pbmltYWwgc2V0IG9mIGNvbm5lY3RlZCwgY3VycmVudGx5LXZhbGlkIEFQSSBzb3VyY2VzIHdob3NlIHJvdXRlcyBjb3ZlciBbMCwgMSkgLSBsaXN0aW5nXG4gICAgLy8gb3BlcmF0aW9ucyBtdXN0IG1lcmdlIGV2ZXJ5IHNoYXJkLiBHcmVlZHkgc3dlZXA6IHJlcGVhdGVkbHkgdGFrZSB0aGUgc291cmNlIHRoYXQgZXh0ZW5kc1xuICAgIC8vIGNvdmVyYWdlIHRoZSBmdXJ0aGVzdC4gSW4gcHJhY3RpY2UgdGhpcyBpcyBvbmUgc291cmNlICh1bnNoYXJkZWQpLCBvciBvbmUgcGVyIHNoYXJkLlxuICAgIHByaXZhdGUgc2VsZWN0Q292ZXJpbmdTb3VyY2VzKHN0YXRlOiBDaGFpblN0YXRlKTogU291cmNlV3JhcHBlcltdIHtcbiAgICAgICAgbGV0IGNhbmRpZGF0ZXMgPSBzdGF0ZS5zb3VyY2VzLmZpbHRlcih4ID0+IGNvbmZpZ1dpbmRvd0N1cnJlbnQoeC5jb25maWcpICYmIHguYXBpICYmIHguaXNDb25uZWN0ZWQoKSk7XG4gICAgICAgIGxldCBjaG9zZW46IFNvdXJjZVdyYXBwZXJbXSA9IFtdO1xuICAgICAgICBsZXQgY292ZXJlZCA9IDA7XG4gICAgICAgIHdoaWxlIChjb3ZlcmVkIDwgMSkge1xuICAgICAgICAgICAgbGV0IGJlc3Q6IFNvdXJjZVdyYXBwZXIgfCB1bmRlZmluZWQ7XG4gICAgICAgICAgICBsZXQgYmVzdEVuZCA9IGNvdmVyZWQ7XG4gICAgICAgICAgICBmb3IgKGxldCBzb3VyY2Ugb2YgY2FuZGlkYXRlcykge1xuICAgICAgICAgICAgICAgIGxldCBbc3RhcnQsIGVuZF0gPSBzb3VyY2UuY29uZmlnLnJvdXRlIHx8IEZVTExfUk9VVEU7XG4gICAgICAgICAgICAgICAgaWYgKHN0YXJ0ID4gY292ZXJlZCkgY29udGludWU7XG4gICAgICAgICAgICAgICAgaWYgKGVuZCA+IGJlc3RFbmQpIHtcbiAgICAgICAgICAgICAgICAgICAgYmVzdEVuZCA9IGVuZDtcbiAgICAgICAgICAgICAgICAgICAgYmVzdCA9IHNvdXJjZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIWJlc3QpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYENhbm5vdCBjb3ZlciB0aGUgZnVsbCByb3V0ZSBzcGFjZSBmb3IgJHt0aGlzLmdldERlYnVnTmFtZSgpfTogdGhlIGF2YWlsYWJsZSBzb3VyY2VzIG9ubHkgY292ZXIgdXAgdG8gJHtjb3ZlcmVkfSAoc29tZSBzaGFyZHMgYXJlIGRvd24gb3IgVVJMLW9ubHkpYCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjaG9zZW4ucHVzaChiZXN0KTtcbiAgICAgICAgICAgIGNvdmVyZWQgPSBiZXN0RW5kO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBjaG9zZW47XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBydW5PbkFwaTxUPihzb3VyY2U6IFNvdXJjZVdyYXBwZXIsIHJ1bjogKGFyY2hpdmVzOiBJQXJjaGl2ZXMpID0+IFByb21pc2U8VD4pOiBQcm9taXNlPFQ+IHtcbiAgICAgICAgbGV0IGFwaSA9IHNvdXJjZS5hcGk7XG4gICAgICAgIGlmICghYXBpKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYCR7c291cmNlLmNvbmZpZy51cmx9IGhhcyBVUkwtb25seSBhY2Nlc3MsIHdoaWNoIGNhbm5vdCBzZXJ2ZSB0aGlzIG9wZXJhdGlvbmApO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBhd2FpdCBydW4oYXBpKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgZmluZChwcmVmaXg6IHN0cmluZywgY29uZmlnPzogeyBzaGFsbG93PzogYm9vbGVhbjsgdHlwZTogXCJmaWxlc1wiIHwgXCJmb2xkZXJzXCIgfSk6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgICAgICAgcmV0dXJuIChhd2FpdCB0aGlzLmZpbmRJbmZvKHByZWZpeCwgY29uZmlnKSkubWFwKHggPT4geC5wYXRoKTtcbiAgICB9XG4gICAgcHVibGljIGFzeW5jIGZpbmRJbmZvKHByZWZpeDogc3RyaW5nLCBjb25maWc/OiB7IHNoYWxsb3c/OiBib29sZWFuOyB0eXBlOiBcImZpbGVzXCIgfCBcImZvbGRlcnNcIiB9KTogUHJvbWlzZTxBcmNoaXZlRmlsZUluZm9bXT4ge1xuICAgICAgICBsZXQgc3RhdGUgPSBhd2FpdCB0aGlzLmdldFN0YXRlKCk7XG4gICAgICAgIGxldCBjb3ZlcmluZyA9IHRoaXMuc2VsZWN0Q292ZXJpbmdTb3VyY2VzKHN0YXRlKTtcbiAgICAgICAgbGV0IHJlc3VsdHMgPSBhd2FpdCBQcm9taXNlLmFsbChjb3ZlcmluZy5tYXAoc291cmNlID0+IHRoaXMucnVuT25BcGkoc291cmNlLCBhcmNoaXZlcyA9PiBhcmNoaXZlcy5maW5kSW5mbyhwcmVmaXgsIGNvbmZpZykpKSk7XG4gICAgICAgIC8vIE92ZXJsYXBwaW5nIHNoYXJkcyBjYW4gYm90aCByZXBvcnQgYSBwYXRoOyB0aGUgbmV3ZXN0IHdpbnNcbiAgICAgICAgbGV0IGJ5UGF0aCA9IG5ldyBNYXA8c3RyaW5nLCBBcmNoaXZlRmlsZUluZm8+KCk7XG4gICAgICAgIGZvciAobGV0IGxpc3Qgb2YgcmVzdWx0cykge1xuICAgICAgICAgICAgZm9yIChsZXQgZmlsZSBvZiBsaXN0KSB7XG4gICAgICAgICAgICAgICAgbGV0IGV4aXN0aW5nID0gYnlQYXRoLmdldChmaWxlLnBhdGgpO1xuICAgICAgICAgICAgICAgIGlmICghZXhpc3RpbmcgfHwgZmlsZS5jcmVhdGVUaW1lID4gZXhpc3RpbmcuY3JlYXRlVGltZSkge1xuICAgICAgICAgICAgICAgICAgICBieVBhdGguc2V0KGZpbGUucGF0aCwgZmlsZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGxldCBtZXJnZWQgPSBbLi4uYnlQYXRoLnZhbHVlcygpXTtcbiAgICAgICAgc29ydChtZXJnZWQsIHggPT4geC5wYXRoKTtcbiAgICAgICAgcmV0dXJuIG1lcmdlZDtcbiAgICB9XG4gICAgcHVibGljIGFzeW5jIGdldENoYW5nZXNBZnRlcih0aW1lOiBudW1iZXIpOiBQcm9taXNlPEFyY2hpdmVGaWxlSW5mb1tdPiB7XG4gICAgICAgIGxldCBzdGF0ZSA9IGF3YWl0IHRoaXMuZ2V0U3RhdGUoKTtcbiAgICAgICAgbGV0IGNvdmVyaW5nID0gdGhpcy5zZWxlY3RDb3ZlcmluZ1NvdXJjZXMoc3RhdGUpO1xuICAgICAgICBsZXQgcmVzdWx0cyA9IGF3YWl0IFByb21pc2UuYWxsKGNvdmVyaW5nLm1hcChzb3VyY2UgPT4gdGhpcy5ydW5PbkFwaShzb3VyY2UsIGFzeW5jIGFyY2hpdmVzID0+IHtcbiAgICAgICAgICAgIGlmICghYXJjaGl2ZXMuZ2V0Q2hhbmdlc0FmdGVyKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGAke2FyY2hpdmVzLmdldERlYnVnTmFtZSgpfSBkb2VzIG5vdCBzdXBwb3J0IGdldENoYW5nZXNBZnRlcmApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGF3YWl0IGFyY2hpdmVzLmdldENoYW5nZXNBZnRlcih0aW1lKTtcbiAgICAgICAgfSkpKTtcbiAgICAgICAgbGV0IGJ5UGF0aCA9IG5ldyBNYXA8c3RyaW5nLCBBcmNoaXZlRmlsZUluZm8+KCk7XG4gICAgICAgIGZvciAobGV0IGxpc3Qgb2YgcmVzdWx0cykge1xuICAgICAgICAgICAgZm9yIChsZXQgZmlsZSBvZiBsaXN0KSB7XG4gICAgICAgICAgICAgICAgbGV0IGV4aXN0aW5nID0gYnlQYXRoLmdldChmaWxlLnBhdGgpO1xuICAgICAgICAgICAgICAgIGlmICghZXhpc3RpbmcgfHwgZmlsZS5jcmVhdGVUaW1lID4gZXhpc3RpbmcuY3JlYXRlVGltZSkge1xuICAgICAgICAgICAgICAgICAgICBieVBhdGguc2V0KGZpbGUucGF0aCwgZmlsZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGxldCBtZXJnZWQgPSBbLi4uYnlQYXRoLnZhbHVlcygpXTtcbiAgICAgICAgc29ydChtZXJnZWQsIHggPT4geC5wYXRoKTtcbiAgICAgICAgcmV0dXJuIG1lcmdlZDtcbiAgICB9XG4gICAgcHVibGljIGFzeW5jIGdldFN5bmNTdGF0dXMoKTogUHJvbWlzZTxBcmNoaXZlc1N5bmNTdGF0dXM+IHtcbiAgICAgICAgbGV0IHN0YXRlID0gYXdhaXQgdGhpcy5nZXRTdGF0ZSgpO1xuICAgICAgICBsZXQgY292ZXJpbmcgPSB0aGlzLnNlbGVjdENvdmVyaW5nU291cmNlcyhzdGF0ZSk7XG4gICAgICAgIGxldCBzdGF0dXNlcyA9IGF3YWl0IFByb21pc2UuYWxsKGNvdmVyaW5nLm1hcChzb3VyY2UgPT4gdGhpcy5ydW5PbkFwaShzb3VyY2UsIGFzeW5jIGFyY2hpdmVzID0+IHtcbiAgICAgICAgICAgIGlmICghYXJjaGl2ZXMuZ2V0U3luY1N0YXR1cykge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgJHthcmNoaXZlcy5nZXREZWJ1Z05hbWUoKX0gZG9lcyBub3Qgc3VwcG9ydCBnZXRTeW5jU3RhdHVzYCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgYXJjaGl2ZXMuZ2V0U3luY1N0YXR1cygpO1xuICAgICAgICB9KSkpO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgYWxsU2NhbnNDb21wbGV0ZTogc3RhdHVzZXMuZXZlcnkoeCA9PiB4LmFsbFNjYW5zQ29tcGxldGUpLFxuICAgICAgICAgICAgaW5kZXhTaXplOiBzdGF0dXNlcy5yZWR1Y2UoKHN1bSwgeCkgPT4gc3VtICsgeC5pbmRleFNpemUsIDApLFxuICAgICAgICAgICAgc291cmNlczogc3RhdHVzZXMuZmxhdE1hcCh4ID0+IHguc291cmNlcyksXG4gICAgICAgIH07XG4gICAgfVxuICAgIHB1YmxpYyBhc3luYyBnZXRDb25maWcoKTogUHJvbWlzZTxBcmNoaXZlc0NvbmZpZz4ge1xuICAgICAgICBsZXQgc3RhdGUgPSBhd2FpdCB0aGlzLmdldFN0YXRlKCk7XG4gICAgICAgIGlmICghc3RhdGUuc291cmNlcy5zb21lKHggPT4geC5hcGkpKSByZXR1cm4geyByZW1vdGVDb25maWc6IHN0YXRlLmNvbmZpZyB9O1xuICAgICAgICBsZXQgY29uZmlnID0gYXdhaXQgdGhpcy5ydW4oc3RhdGUsIHsgYXBpT25seTogdHJ1ZSB9LCBhcmNoaXZlcyA9PiBhcmNoaXZlcy5nZXRDb25maWcoKSk7XG4gICAgICAgIHJldHVybiB7IC4uLmNvbmZpZywgcmVtb3RlQ29uZmlnOiBzdGF0ZS5jb25maWcgfTtcbiAgICB9XG4gICAgLyoqIFRydWUgb25seSB3aGVuIEVWRVJZIHdyaXRlLXJlY2VpdmluZyBzb3VyY2Ugd291bGQgYWNjZXB0IG91ciB3cml0ZXMgKHBhcnRpYWwgd3JpdGUgYWNjZXNzXG4gICAgICogIGRlc3luY2hyb25pemVzIHNvdXJjZXMsIHNvIGl0IGNvdW50cyBhcyBubyBhY2Nlc3MpLiAqL1xuICAgIHB1YmxpYyBhc3luYyBoYXNXcml0ZUFjY2VzcygpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICAgICAgbGV0IHN0YXRlID0gYXdhaXQgdGhpcy5nZXRTdGF0ZSgpO1xuICAgICAgICBmb3IgKGxldCBzb3VyY2Ugb2Ygc3RhdGUuc291cmNlcykge1xuICAgICAgICAgICAgaWYgKCFjb25maWdBY2NlcHRzV3JpdGVzKHNvdXJjZS5jb25maWcpKSBjb250aW51ZTtcbiAgICAgICAgICAgIGlmICghYXdhaXQgc291cmNlLmhhc1dyaXRlQWNjZXNzKCkpIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzc2VydE5vdEJhcmVWYXJpYWJsZVNoYXJkKGZpbGVOYW1lOiBzdHJpbmcpOiB2b2lkIHtcbiAgICAgICAgaWYgKGZpbGVOYW1lLmluY2x1ZGVzKFZBUklBQkxFX1NIQVJEKSAmJiBwYXJzZVZhcmlhYmxlUm91dGUoZmlsZU5hbWUpID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgS2V5cyBjb250YWluaW5nIFZBUklBQkxFX1NIQVJEIG11c3QgYmUgd3JpdHRlbiB3aXRoIHNldFZhcmlhYmxlU2hhcmQsIHdoaWNoIG1hdGVyaWFsaXplcyB0aGUgc2hhcmQgdmFsdWUgYW5kIHJldHVybnMgdGhlIGZ1bGwga2V5LiBLZXk6ICR7SlNPTi5zdHJpbmdpZnkoZmlsZU5hbWUpfWApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHNldChmaWxlTmFtZTogc3RyaW5nLCBkYXRhOiBCdWZmZXIsIGNvbmZpZz86IHsgbGFzdE1vZGlmaWVkPzogbnVtYmVyIH0pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgdGhpcy5hc3NlcnROb3RCYXJlVmFyaWFibGVTaGFyZChmaWxlTmFtZSk7XG4gICAgICAgIGF3YWl0IHRoaXMucmVxdWVzdCh7IHdyaXRlOiB0cnVlLCByb3V0ZTogZ2V0Um91dGUoZmlsZU5hbWUpIH0sIGFyY2hpdmVzID0+IGFyY2hpdmVzLnNldChmaWxlTmFtZSwgZGF0YSwgY29uZmlnKSk7XG4gICAgfVxuICAgIHB1YmxpYyBhc3luYyBkZWwoZmlsZU5hbWU6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCB0aGlzLnJlcXVlc3QoeyB3cml0ZTogdHJ1ZSwgcm91dGU6IGdldFJvdXRlKGZpbGVOYW1lKSB9LCBhcmNoaXZlcyA9PiBhcmNoaXZlcy5kZWwoZmlsZU5hbWUpKTtcbiAgICB9XG5cbiAgICAvKiogV3JpdGVzIGEga2V5IGNvbnRhaW5pbmcgdGhlIFZBUklBQkxFX1NIQVJEIHNlbnRpbmVsOiBwaWNrcyB0aGUgbG93ZXN0LWxhdGVuY3kgdXAgd3JpdGVcbiAgICAgKiAgc2hhcmQsIG1hdGVyaWFsaXplcyB0aGUga2V5IHdpdGggYSByYW5kb20gdmFsdWUgaW5zaWRlIHRoYXQgc2hhcmQncyByb3V0ZSwgd3JpdGVzIGl0LCBhbmRcbiAgICAgKiAgcmV0dXJucyB0aGUgRlVMTCBrZXkgYWN0dWFsbHkgd3JpdHRlbiAodGhlIGNhbGxlciBuZWVkcyBpdCB0byBldmVyIHJlYWQgdGhlIHZhbHVlIGJhY2spLlxuICAgICAqICBVbmxpa2Ugbm9ybWFsIHdyaXRlcyB0aGlzIENBTiBtb3ZlIHRvIGFub3RoZXIgc2hhcmQgd2hlbiB0aGUgcHJlZmVycmVkIG9uZSBpcyBkb3duIChlcnJvciArXG4gICAgICogIHNvY2tldCBkb3duLCBzYW1lIHJ1bGUgYXMgcmVhZHMpIC0gZWFjaCBzaGFyZCByZWNlaXZlcyBhIGRpZmZlcmVudCBrZXksIHNvIHdyaXRlXG4gICAgICogIGNvbnNpc3RlbmN5IGlzIHByZXNlcnZlZC4gKi9cbiAgICBwdWJsaWMgYXN5bmMgc2V0VmFyaWFibGVTaGFyZChrZXk6IHN0cmluZywgZGF0YTogQnVmZmVyLCBjb25maWc/OiB7IGxhc3RNb2RpZmllZD86IG51bWJlciB9KTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICAgICAgaWYgKCFrZXkuaW5jbHVkZXMoVkFSSUFCTEVfU0hBUkQpKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEV4cGVjdGVkIHRoZSBrZXkgdG8gY29udGFpbiB0aGUgVkFSSUFCTEVfU0hBUkQgc2VudGluZWwsIHdhcyAke0pTT04uc3RyaW5naWZ5KGtleSl9YCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHBhcnNlVmFyaWFibGVSb3V0ZShrZXkpICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgVGhlIGtleSBhbHJlYWR5IGhhcyBhIG1hdGVyaWFsaXplZCBzaGFyZCB2YWx1ZTsgd3JpdGUgaXQgd2l0aCBzZXQgaW5zdGVhZC4gS2V5OiAke0pTT04uc3RyaW5naWZ5KGtleSl9YCk7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IHN0YXRlID0gYXdhaXQgdGhpcy5nZXRTdGF0ZSgpO1xuICAgICAgICAvLyBQZXItc2hhcmQgd3JpdGUgY29uc2lzdGVuY3kgc3RpbGwgaG9sZHM6IHdpdGhpbiBhIHJvdXRlLCBvbmx5IHRoZSBGSVJTVCBzb3VyY2UgbWF5IHRha2VcbiAgICAgICAgLy8gd3JpdGVzIC0gbGF0ZW5jeSBvbmx5IHBpY2tzIFdISUNIIHNoYXJkIHRoZSBrZXkgbWF0ZXJpYWxpemVzIGludG9cbiAgICAgICAgbGV0IHRhcmdldHNCeVJvdXRlID0gbmV3IE1hcDxzdHJpbmcsIFNvdXJjZVdyYXBwZXI+KCk7XG4gICAgICAgIGZvciAobGV0IHNvdXJjZSBvZiBzdGF0ZS5zb3VyY2VzKSB7XG4gICAgICAgICAgICBpZiAoIWNvbmZpZ0FjY2VwdHNXcml0ZXMoc291cmNlLmNvbmZpZykpIGNvbnRpbnVlO1xuICAgICAgICAgICAgbGV0IHJvdXRlS2V5ID0gSlNPTi5zdHJpbmdpZnkoc291cmNlLmNvbmZpZy5yb3V0ZSB8fCBGVUxMX1JPVVRFKTtcbiAgICAgICAgICAgIGlmICghdGFyZ2V0c0J5Um91dGUuaGFzKHJvdXRlS2V5KSkge1xuICAgICAgICAgICAgICAgIHRhcmdldHNCeVJvdXRlLnNldChyb3V0ZUtleSwgc291cmNlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBsZXQgdGFyZ2V0cyA9IFsuLi50YXJnZXRzQnlSb3V0ZS52YWx1ZXMoKV07XG4gICAgICAgIHNvcnQodGFyZ2V0cywgeCA9PiB4LmdldExhdGVuY3koKSk7XG4gICAgICAgIGxldCBlcnJvcnM6IHN0cmluZ1tdID0gW107XG4gICAgICAgIGZvciAobGV0IHRhcmdldCBvZiB0YXJnZXRzKSB7XG4gICAgICAgICAgICBpZiAoIXRhcmdldC5pc0Nvbm5lY3RlZCgpKSB7XG4gICAgICAgICAgICAgICAgdGFyZ2V0Lm5vdGVGYWlsdXJlKCk7XG4gICAgICAgICAgICAgICAgZXJyb3JzLnB1c2goYCR7dGFyZ2V0LmNvbmZpZy51cmx9IGlzIG5vdCBjb25uZWN0ZWRgKTtcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxldCBbc3RhcnQsIGVuZF0gPSB0YXJnZXQuY29uZmlnLnJvdXRlIHx8IEZVTExfUk9VVEU7XG4gICAgICAgICAgICBsZXQgZnVsbEtleSA9IGtleS5yZXBsYWNlKFZBUklBQkxFX1NIQVJELCBWQVJJQUJMRV9TSEFSRCArIFwiX1wiICsgKHN0YXJ0ICsgTWF0aC5yYW5kb20oKSAqIChlbmQgLSBzdGFydCkpKTtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgdGFyZ2V0LndyaXRlKGFyY2hpdmVzID0+IGFyY2hpdmVzLnNldChmdWxsS2V5LCBkYXRhLCBjb25maWcpKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gZnVsbEtleTtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICAvLyBBbiBlcnJvciBhbG9uZSBkb2Vzbid0IGp1c3RpZnkgbW92aW5nIG9uIChpdCB3b3VsZCBiZSBhbiBhcHBsaWNhdGlvbiBlcnJvcik7IHRoZVxuICAgICAgICAgICAgICAgIC8vIHNvY2tldCBtdXN0IGFsc28gYmUgZG93blxuICAgICAgICAgICAgICAgIGlmICh0YXJnZXQuaXNDb25uZWN0ZWQoKSkgdGhyb3cgZTtcbiAgICAgICAgICAgICAgICB0YXJnZXQubm90ZUZhaWx1cmUoKTtcbiAgICAgICAgICAgICAgICBlcnJvcnMucHVzaChTdHJpbmcoKGUgYXMgRXJyb3IpLnN0YWNrID8/IGUpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEV2ZXJ5IHZhcmlhYmxlLXNoYXJkIHdyaXRlIHRhcmdldCBmYWlsZWQgZm9yICR7dGhpcy5nZXREZWJ1Z05hbWUoKX06ICR7ZXJyb3JzLmpvaW4oXCIgfCBcIikgfHwgXCJubyBzb3VyY2VzIGFjY2VwdCB3cml0ZXNcIn1gKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgc2V0TGFyZ2VGaWxlKGNvbmZpZzogeyBwYXRoOiBzdHJpbmc7IGdldE5leHREYXRhKCk6IFByb21pc2U8QnVmZmVyIHwgdW5kZWZpbmVkPiB9KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRoaXMuYXNzZXJ0Tm90QmFyZVZhcmlhYmxlU2hhcmQoY29uZmlnLnBhdGgpO1xuICAgICAgICBsZXQgc3RhdGUgPSBhd2FpdCB0aGlzLmdldFN0YXRlKCk7XG4gICAgICAgIC8vIFNhbWUgY29uc2lzdGVuY3kgcnVsZSBhcyBydW5Xcml0ZTogdGhlIGZpcnN0IGN1cnJlbnRseS12YWxpZCBzb3VyY2UgZm9yIHRoZSByb3V0ZSwgb3Igbm90aGluZ1xuICAgICAgICBsZXQgcm91dGUgPSBnZXRSb3V0ZShjb25maWcucGF0aCk7XG4gICAgICAgIGxldCB0YXJnZXQgPSBzdGF0ZS5zb3VyY2VzLmZpbmQoeCA9PiBjb25maWdBY2NlcHRzV3JpdGVzKHguY29uZmlnKSAmJiByb3V0ZUNvbnRhaW5zKHguY29uZmlnLnJvdXRlLCByb3V0ZSkpO1xuICAgICAgICBpZiAoIXRhcmdldCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBObyBzb3VyY2UgYWNjZXB0cyB3cml0ZXMgZm9yIHNldExhcmdlRmlsZSBvbiAke3RoaXMuZ2V0RGVidWdOYW1lKCl9IChyb3V0ZSAke3JvdXRlfSlgKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXRhcmdldC5pc0Nvbm5lY3RlZCgpKSB7XG4gICAgICAgICAgICB0YXJnZXQubm90ZUZhaWx1cmUoKTtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgQ2Fubm90IHdyaXRlOiB0aGUgd3JpdGUgdGFyZ2V0ICR7dGFyZ2V0LmNvbmZpZy51cmx9IGlzIG5vdCBjb25uZWN0ZWQgKHdyaXRlcyBuZXZlciBmYWlsIG92ZXIgdG8gb3RoZXIgc291cmNlcylgKTtcbiAgICAgICAgfVxuICAgICAgICBhd2FpdCB0YXJnZXQud3JpdGUoYXJjaGl2ZXMgPT4gYXJjaGl2ZXMuc2V0TGFyZ2VGaWxlKGNvbmZpZykpO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBnZXRVUkwocGF0aDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICAgICAgbGV0IHN0YXRlID0gYXdhaXQgdGhpcy5nZXRTdGF0ZSgpO1xuICAgICAgICBsZXQgcm91dGUgPSBnZXRSb3V0ZShwYXRoKTtcbiAgICAgICAgZm9yIChsZXQgc291cmNlIG9mIHN0YXRlLnNvdXJjZXMpIHtcbiAgICAgICAgICAgIGlmIChzb3VyY2UuY29uZmlnLnB1YmxpYyA9PT0gZmFsc2UpIGNvbnRpbnVlO1xuICAgICAgICAgICAgaWYgKCFyb3V0ZUNvbnRhaW5zKHNvdXJjZS5jb25maWcucm91dGUsIHJvdXRlKSkgY29udGludWU7XG4gICAgICAgICAgICBpZiAoc291cmNlLnVybCkgcmV0dXJuIGF3YWl0IHNvdXJjZS51cmwuZ2V0VVJMKHBhdGgpO1xuICAgICAgICAgICAgaWYgKHNvdXJjZS5hcGkpIHJldHVybiBhd2FpdCBzb3VyY2UuYXBpLmdldFVSTChwYXRoKTtcbiAgICAgICAgfVxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYE5vIHB1YmxpYyBzb3VyY2UgY292ZXJpbmcgcm91dGUgJHtyb3V0ZX0gdG8gYnVpbGQgYSBVUkwgZnJvbSBmb3IgJHt0aGlzLmdldERlYnVnTmFtZSgpfWApO1xuICAgIH1cblxuICAgIHB1YmxpYyBkaXNwb3NlKCk6IHZvaWQge1xuICAgICAgICB0aGlzLmRpc3Bvc2VkID0gdHJ1ZTtcbiAgICAgICAgaWYgKHRoaXMucG9sbFRpbWVyKSB7XG4gICAgICAgICAgICBjbGVhckludGVydmFsKHRoaXMucG9sbFRpbWVyKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5pbml0UmV0cnlUaW1lcikge1xuICAgICAgICAgICAgY2xlYXJUaW1lb3V0KHRoaXMuaW5pdFJldHJ5VGltZXIpO1xuICAgICAgICB9XG4gICAgICAgIGxldCBzdGF0ZVByb21pc2UgPSB0aGlzLnN0YXRlUHJvbWlzZTtcbiAgICAgICAgaWYgKHN0YXRlUHJvbWlzZSkge1xuICAgICAgICAgICAgdm9pZCBzdGF0ZVByb21pc2UudGhlbihzdGF0ZSA9PiB7XG4gICAgICAgICAgICAgICAgZm9yIChsZXQgc291cmNlIG9mIHN0YXRlLnNvdXJjZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgc291cmNlLmRpc3Bvc2UoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LCAoKSA9PiB7IH0pO1xuICAgICAgICB9XG4gICAgfVxufVxuXG4vLyBUaGUgSUFyY2hpdmVzIGZvciBhIFJlbW90ZUNvbmZpZyAob3IgYSBzaW5nbGUgc291cmNlIC0gYSByb3V0aW5nIFVSTCBzdHJpbmcgd29ya3MpLiBGdWxseSBsYXp5OlxuLy8gbm90aGluZyBpcyBjb250YWN0ZWQgdW50aWwgdGhlIGZpcnN0IGNhbGwuIENhbGwgZGlzcG9zZSgpIHdoZW4gZG9uZSB3aXRoIGl0LCBzbyBpdHMgYmFja2dyb3VuZFxuLy8gcmV0cnkvcG9sbCBsb29wcyBzdG9wLlxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUFyY2hpdmVzKGNvbmZpZzogUmVtb3RlQ29uZmlnIHwgUmVtb3RlQ29uZmlnQmFzZSk6IEFyY2hpdmVzQ2hhaW4ge1xuICAgIHJldHVybiBuZXcgQXJjaGl2ZXNDaGFpbihjb25maWcpO1xufVxuIl19
610
+ /* _JS_SOURCE_HASH = "50c50395ddf2ffcc2dd4351bc8b06baf4be9bfc73f82dc2694defa4b5c96e13c"; */