sliftutils 1.7.9 → 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 (92) hide show
  1. package/bin/storageserver.js +4 -0
  2. package/{teststorage → examplestorage}/browser.tsx +18 -22
  3. package/{teststorage/server.ts → examplestorage/exampleserver.ts} +4 -6
  4. package/index.d.ts +770 -84
  5. package/misc/dist/environment.ts.cache +3 -3
  6. package/misc/dist/getSecret.ts.cache +139 -0
  7. package/misc/dist/strings.ts.cache +13 -0
  8. package/misc/dist/zip.ts.cache +9 -0
  9. package/misc/getSecret.ts +38 -16
  10. package/misc/https/cloudflareHelpers.d.ts +19 -0
  11. package/misc/https/cloudflareHelpers.ts +69 -0
  12. package/misc/https/dist/certs.ts.cache +115 -179
  13. package/misc/https/dist/cloudflareHelpers.ts.cache +68 -0
  14. package/misc/https/dist/dns.ts.cache +112 -100
  15. package/misc/https/dist/hostServer.ts.cache +130 -0
  16. package/misc/https/dist/httpsCerts.ts.cache +24 -5
  17. package/misc/https/dist/persistentLocalStorage.ts.cache +3 -2
  18. package/misc/https/dns.d.ts +41 -8
  19. package/misc/https/dns.ts +104 -106
  20. package/misc/https/hostServer.d.ts +0 -3
  21. package/misc/https/hostServer.ts +12 -8
  22. package/package.json +3 -2
  23. package/render-utils/dist/observer.tsx.cache +3 -2
  24. package/spec.txt +0 -55
  25. package/storage/ArchivesDisk.d.ts +67 -0
  26. package/storage/ArchivesDisk.ts +369 -0
  27. package/storage/BulkDatabase2/dist/BulkDatabaseBase.ts.cache +1242 -0
  28. package/storage/BulkDatabase2/dist/BulkDatabaseFormat.ts.cache +513 -0
  29. package/storage/BulkDatabase2/dist/BulkDatabaseMerge.ts.cache +352 -0
  30. package/storage/BulkDatabase2/dist/BulkDatabaseReader.ts.cache +306 -0
  31. package/storage/BulkDatabase2/dist/LoadedIndex.ts.cache +435 -0
  32. package/storage/BulkDatabase2/dist/WriteOverlay.ts.cache +58 -0
  33. package/storage/BulkDatabase2/dist/blockCache.ts.cache +179 -0
  34. package/storage/BulkDatabase2/dist/mergeLock.ts.cache +149 -0
  35. package/storage/BulkDatabase2/dist/mergeMarkers.ts.cache +101 -0
  36. package/storage/BulkDatabase2/dist/streamLog.ts.cache +227 -0
  37. package/storage/BulkDatabase2/dist/syncClient.ts.cache +104 -0
  38. package/storage/IArchives.d.ts +127 -1
  39. package/storage/IArchives.ts +201 -1
  40. package/storage/backblaze.d.ts +29 -2
  41. package/storage/backblaze.ts +214 -78
  42. package/storage/dist/ArchivesDisk.ts.cache +373 -0
  43. package/storage/dist/FileFolderAPI.tsx.cache +508 -65
  44. package/storage/dist/IArchives.ts.cache +44 -0
  45. package/storage/dist/IndexedDBFileFolderAPI.ts.cache +8 -2
  46. package/storage/dist/JSONStorage.ts.cache +6 -2
  47. package/storage/dist/PendingManager.tsx.cache +1 -1
  48. package/storage/dist/TransactionStorage.ts.cache +231 -92
  49. package/storage/dist/backblaze.ts.cache +797 -0
  50. package/storage/dist/fileSystemPointer.ts.cache +36 -3
  51. package/storage/dist/remoteFileStorage.ts.cache +495 -0
  52. package/storage/remoteStorage/ArchivesRemote.d.ts +34 -18
  53. package/storage/remoteStorage/ArchivesRemote.ts +85 -65
  54. package/storage/remoteStorage/ArchivesUrl.d.ts +48 -0
  55. package/storage/remoteStorage/ArchivesUrl.ts +86 -0
  56. package/storage/remoteStorage/accessPage.tsx +111 -28
  57. package/storage/remoteStorage/blobStore.d.ts +128 -25
  58. package/storage/remoteStorage/blobStore.ts +757 -290
  59. package/storage/remoteStorage/cliArgs.d.ts +1 -0
  60. package/storage/remoteStorage/cliArgs.ts +9 -0
  61. package/storage/remoteStorage/createArchives.d.ts +85 -0
  62. package/storage/remoteStorage/createArchives.ts +612 -0
  63. package/storage/remoteStorage/dist/ArchivesRemote.ts.cache +197 -0
  64. package/storage/remoteStorage/dist/ArchivesUrl.ts.cache +85 -0
  65. package/storage/remoteStorage/dist/accessPage.tsx.cache +222 -0
  66. package/storage/remoteStorage/dist/blobStore.ts.cache +837 -0
  67. package/storage/remoteStorage/dist/cliArgs.ts.cache +16 -0
  68. package/storage/remoteStorage/dist/createArchives.ts.cache +610 -0
  69. package/storage/remoteStorage/dist/remoteConfig.ts.cache +206 -0
  70. package/storage/remoteStorage/dist/sourceWrapper.ts.cache +223 -0
  71. package/storage/remoteStorage/dist/storageController.ts.cache +500 -0
  72. package/storage/remoteStorage/dist/storageServer.ts.cache +106 -0
  73. package/storage/remoteStorage/dist/storageServerCli.ts.cache +39 -0
  74. package/storage/remoteStorage/dist/storageServerState.ts.cache +518 -0
  75. package/storage/remoteStorage/grantAccess.js +4 -0
  76. package/storage/remoteStorage/grantAccessCli.d.ts +1 -0
  77. package/storage/remoteStorage/grantAccessCli.ts +27 -0
  78. package/storage/remoteStorage/remoteConfig.d.ts +29 -0
  79. package/storage/remoteStorage/remoteConfig.ts +194 -0
  80. package/storage/remoteStorage/sourceWrapper.d.ts +41 -0
  81. package/storage/remoteStorage/sourceWrapper.ts +223 -0
  82. package/storage/remoteStorage/spec.md +31 -0
  83. package/storage/remoteStorage/storageController.d.ts +30 -27
  84. package/storage/remoteStorage/storageController.ts +297 -159
  85. package/storage/remoteStorage/storageServer.d.ts +6 -0
  86. package/storage/remoteStorage/storageServer.ts +88 -94
  87. package/storage/remoteStorage/storageServerCli.d.ts +1 -0
  88. package/storage/remoteStorage/storageServerCli.ts +38 -0
  89. package/storage/remoteStorage/storageServerState.d.ts +43 -0
  90. package/storage/remoteStorage/storageServerState.ts +540 -0
  91. package/testsite/server.ts +0 -2
  92. package/yarn.lock +11 -6
@@ -0,0 +1,500 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
3
+ //exports.RemoteStorageController = exports.STORAGE_ACCESS_DENIED = exports.STORAGE_NOT_AUTHENTICATED = exports.STORAGE_AUTH_PURPOSE = exports.REMOTE_STORAGE_CLASS_GUID = void 0;
4
+ module.allowclient = true;
5
+ const SocketFunction_1 = require("socket-function/SocketFunction");
6
+ const nodeCache_1 = require("socket-function/src/nodeCache");
7
+ const callHTTPHandler_1 = require("socket-function/src/callHTTPHandler");
8
+ const callManager_1 = require("socket-function/src/callManager");
9
+ const RequireController_1 = require("socket-function/require/RequireController");
10
+ const misc_1 = require("socket-function/src/misc");
11
+ const certs_1 = require("../../misc/https/certs");
12
+ const IArchives_1 = require("../IArchives");
13
+ const remoteConfig_1 = require("./remoteConfig");
14
+ const storageServerState_1 = require("./storageServerState");
15
+ // The remote storage server's API. Authentication uses certs.ts machine identities: a client
16
+ // proves it owns its machine key by signing a timestamped token (bound to this server, so tokens
17
+ // can't be replayed elsewhere), and the server then trusts that connection as that machineId.
18
+ // Access to an account is granted to specific machineIds, via a command line command run on the
19
+ // storage machine (see storageServer.ts).
20
+ //
21
+ // There is no bucket-creation API: a bucket exists iff its routing config (ROUTING_FILE) exists,
22
+ // and writing that file creates or reconfigures the bucket (see storageServerState.ts). Reads of
23
+ // nonexistent buckets return undefined / empty, same as reads of nonexistent files.
24
+ exports.REMOTE_STORAGE_CLASS_GUID = "RemoteStorageController-b7e42a91";
25
+ exports.STORAGE_AUTH_PURPOSE = "remoteStorage-auth-1";
26
+ // Error markers, so clients can identify these failures inside error messages
27
+ exports.STORAGE_NOT_AUTHENTICATED = "REMOTE_STORAGE_NOT_AUTHENTICATED_cf2f7b1e";
28
+ exports.STORAGE_ACCESS_DENIED = "REMOTE_STORAGE_ACCESS_DENIED_9d81a4c0";
29
+ const AUTH_TIME_WINDOW = misc_1.timeInMinute * 10;
30
+ const MAX_SESSIONS = 100 * 1000;
31
+ const MAX_REQUESTS_PER_IP = 50;
32
+ // callerNodeId -> authenticated machineId. Connections are long-lived websockets, so a session
33
+ // lasts until the connection drops (clients re-authenticate on reconnect).
34
+ const sessions = new Map();
35
+ const CONTENT_TYPES = {
36
+ html: "text/html", js: "text/javascript", css: "text/css", json: "application/json",
37
+ txt: "text/plain", png: "image/png", jpg: "image/jpeg", jpeg: "image/jpeg", gif: "image/gif",
38
+ svg: "image/svg+xml", webp: "image/webp", mp4: "video/mp4", webm: "video/webm",
39
+ mp3: "audio/mpeg", wav: "audio/wav", pdf: "application/pdf",
40
+ };
41
+ function assertValidName(value, kind) {
42
+ if (!/^[\w-]{1,64}$/.test(value)) {
43
+ throw new Error(`Invalid ${kind} ${JSON.stringify(value)}, expected 1-64 characters of letters/numbers/underscore/dash`);
44
+ }
45
+ }
46
+ function assertValidPath(path) {
47
+ if (Buffer.from(path, "utf8").length > 1000) {
48
+ throw new Error(`Path too long: ${path.length} characters > 1000. Path: ${path.slice(0, 200)}`);
49
+ }
50
+ if (!path || path.startsWith("/") || path.endsWith("/") || path.includes("//") || path.includes("\\") || path.includes("\x00")) {
51
+ throw new Error(`Invalid path ${JSON.stringify(path.slice(0, 200))}, paths cannot be empty, start or end with /, or contain //, backslashes, or null characters`);
52
+ }
53
+ // Paths are one-to-one with files on disk, so . and .. segments would escape the store folder
54
+ if (path.split("/").some(part => part === "." || part === "..")) {
55
+ throw new Error(`Invalid path ${JSON.stringify(path.slice(0, 200))}, paths cannot contain . or .. segments`);
56
+ }
57
+ }
58
+ function getCallerMachineId() {
59
+ let caller = SocketFunction_1.SocketFunction.getCaller();
60
+ let machineId = sessions.get(caller.nodeId);
61
+ if (!machineId) {
62
+ throw new Error(`${exports.STORAGE_NOT_AUTHENTICATED} Call authenticate first (connection ${caller.nodeId})`);
63
+ }
64
+ return machineId;
65
+ }
66
+ function getCallerIP() {
67
+ return (0, nodeCache_1.getNodeIdIP)(SocketFunction_1.SocketFunction.getCaller().nodeId);
68
+ }
69
+ function isAdmin(machineId) {
70
+ return machineId === (0, certs_1.getOwnMachineId)((0, storageServerState_1.getStorageServerConfig)().rootDomain);
71
+ }
72
+ function requireAdmin() {
73
+ let machineId = getCallerMachineId();
74
+ if (!isAdmin(machineId)) {
75
+ throw new Error(`${exports.STORAGE_ACCESS_DENIED} Admin commands must be run from the storage machine itself (caller machine ${machineId})`);
76
+ }
77
+ return machineId;
78
+ }
79
+ async function requireAccess(account) {
80
+ assertValidName(account, "account");
81
+ let machineId = getCallerMachineId();
82
+ if (isAdmin(machineId))
83
+ return machineId;
84
+ let trust = await (0, storageServerState_1.getTrust)();
85
+ let trusted = await trust.get(`${account}|${machineId}`);
86
+ if (!trusted) {
87
+ let { domain, port } = (0, storageServerState_1.getStorageServerConfig)();
88
+ throw new Error(`${exports.STORAGE_ACCESS_DENIED} Machine ${machineId} has no access to account ${JSON.stringify(account)}. Visit https://${domain}:${port}/${account} for access instructions.`);
89
+ }
90
+ return machineId;
91
+ }
92
+ // A single command, runnable from anywhere, that sshes into the storage machine and runs the
93
+ // grantAccess CLI there
94
+ function getGrantAccessCommand(requestId) {
95
+ let { sshTarget, serverCommand } = (0, storageServerState_1.getStorageServerConfig)();
96
+ return `ssh ${sshTarget} '${serverCommand} --requestId ${requestId}'`;
97
+ }
98
+ async function getBucket(account, bucketName) {
99
+ assertValidName(account, "account");
100
+ assertValidName(bucketName, "bucket name");
101
+ return await (0, storageServerState_1.getLoadedBucket)(account, bucketName);
102
+ }
103
+ class RemoteStorageControllerBase {
104
+ // Latency measurement (see SourceWrapper's pinging); no auth, it measures the transport
105
+ async ping() { }
106
+ // Proves the caller owns the machine key for the machineId in its certificate. The signature
107
+ // must be fresh and bound to this server, so it cannot be replayed to (or from) other servers.
108
+ async authenticate(token) {
109
+ let { domain, port } = (0, storageServerState_1.getStorageServerConfig)();
110
+ let caller = SocketFunction_1.SocketFunction.getCaller();
111
+ if (Math.abs(Date.now() - token.time) > AUTH_TIME_WINDOW) {
112
+ throw new Error(`Auth token time is too far from the server time (token ${token.time}, server ${Date.now()}, allowed drift ${AUTH_TIME_WINDOW}ms)`);
113
+ }
114
+ (0, certs_1.verify)(token.certPem, token.signature, {
115
+ purpose: exports.STORAGE_AUTH_PURPOSE,
116
+ time: token.time,
117
+ server: `${domain}:${port}`,
118
+ });
119
+ let machineId = (0, certs_1.getCommonName)(token.certPem).split(".")[0];
120
+ if (!(0, certs_1.verifyMachineIdForPublicKey)({ machineId, publicKey: (0, certs_1.getPublicIdentifier)(token.certPem) })) {
121
+ throw new Error(`Certificate common name ${JSON.stringify((0, certs_1.getCommonName)(token.certPem))} does not match its public key`);
122
+ }
123
+ sessions.set(caller.nodeId, machineId);
124
+ while (sessions.size > MAX_SESSIONS) {
125
+ let oldest = sessions.keys().next().value;
126
+ if (oldest === undefined)
127
+ break;
128
+ sessions.delete(oldest);
129
+ }
130
+ return { machineId, ip: getCallerIP() };
131
+ }
132
+ // Records that the calling machine wants access to an account. Requests are kept per requesting
133
+ // IP, so the storage machine's admin can list them with --listAccess <ip> and grant one.
134
+ async requestAccess(account) {
135
+ assertValidName(account, "account");
136
+ let machineId = getCallerMachineId();
137
+ let ip = getCallerIP();
138
+ let requestsStorage = await (0, storageServerState_1.getRequests)();
139
+ let requests = await requestsStorage.get(ip) || [];
140
+ let existing = requests.find(x => x.account === account && x.machineId === machineId);
141
+ if (existing) {
142
+ existing.time = Date.now();
143
+ }
144
+ else {
145
+ existing = {
146
+ requestId: Math.random().toString(36).slice(2, 10),
147
+ account,
148
+ machineId,
149
+ ip,
150
+ time: Date.now(),
151
+ };
152
+ requests.push(existing);
153
+ }
154
+ while (requests.length > MAX_REQUESTS_PER_IP)
155
+ requests.shift();
156
+ await requestsStorage.set(ip, requests);
157
+ return { machineId, ip, requestId: existing.requestId, grantAccessCommand: getGrantAccessCommand(existing.requestId) };
158
+ }
159
+ async getAccessState(account) {
160
+ assertValidName(account, "account");
161
+ let machineId = getCallerMachineId();
162
+ let ip = getCallerIP();
163
+ let trust = await (0, storageServerState_1.getTrust)();
164
+ let hasAccess = isAdmin(machineId) || !!await trust.get(`${account}|${machineId}`);
165
+ let result = { machineId, ip, hasAccess };
166
+ if (!hasAccess) {
167
+ let requests = await (0, storageServerState_1.getRequests)();
168
+ let ownRequest = (await requests.get(ip) || []).find(x => x.account === account && x.machineId === machineId);
169
+ if (ownRequest) {
170
+ result.grantAccessCommand = getGrantAccessCommand(ownRequest.requestId);
171
+ }
172
+ return result;
173
+ }
174
+ let trustedMachines = [];
175
+ for (let key of await trust.getKeys()) {
176
+ if (!key.startsWith(`${account}|`))
177
+ continue;
178
+ let record = await trust.get(key);
179
+ if (record)
180
+ trustedMachines.push(record);
181
+ }
182
+ result.trustedMachines = trustedMachines;
183
+ return result;
184
+ }
185
+ // Callable by any machine that has access to `account`. Returns pending access requests for the
186
+ // account that come from EXACTLY `ip`. Callers must type in an IP explicitly — the server never
187
+ // volunteers a list of requesting IPs, so a trusted user can't accidentally approve a random
188
+ // request from a machine they didn't mean to trust.
189
+ async listRequestsForIP(account, ip) {
190
+ let requests = await (0, storageServerState_1.getRequests)();
191
+ return (await requests.get(ip) || []).filter(x => x.account === account);
192
+ }
193
+ // Callable by any machine that has access to the request's account (or by the storage-machine
194
+ // admin). Grants the requested access; the caller must supply the specific requestId, which they
195
+ // only get by explicitly looking up requests for a specific IP.
196
+ async grantAccess(requestId) {
197
+ // Must capture in the synchronous phase — SocketFunction.getCaller() only works before any await.
198
+ let callerMachineId = getCallerMachineId();
199
+ let trust = await (0, storageServerState_1.getTrust)();
200
+ let requests = await (0, storageServerState_1.getRequests)();
201
+ for (let ip of await requests.getKeys()) {
202
+ for (let request of await requests.get(ip) || []) {
203
+ if (request.requestId !== requestId)
204
+ continue;
205
+ if (!isAdmin(callerMachineId) && !await trust.get(`${request.account}|${callerMachineId}`)) {
206
+ throw new Error(`${exports.STORAGE_ACCESS_DENIED} Machine ${callerMachineId} has no access to account ${JSON.stringify(request.account)}`);
207
+ }
208
+ let record = {
209
+ account: request.account,
210
+ machineId: request.machineId,
211
+ ip: request.ip,
212
+ time: Date.now(),
213
+ };
214
+ await trust.set(`${request.account}|${request.machineId}`, record);
215
+ return record;
216
+ }
217
+ }
218
+ throw new Error(`No access request found with id ${JSON.stringify(requestId)}. It may have already been granted or expired.`);
219
+ }
220
+ // Admin (must be run from the storage machine itself, which shares the server's machineId).
221
+ // Only returns requests for the given IP, so you cannot accidentally grant a request from an
222
+ // IP you didn't explicitly type in.
223
+ async adminListRequests(ip) {
224
+ let requests = await (0, storageServerState_1.getRequests)();
225
+ return await requests.get(ip) || [];
226
+ }
227
+ async adminGrantAccess(requestId) {
228
+ let trust = await (0, storageServerState_1.getTrust)();
229
+ let requests = await (0, storageServerState_1.getRequests)();
230
+ for (let ip of await requests.getKeys()) {
231
+ for (let request of await requests.get(ip) || []) {
232
+ if (request.requestId !== requestId)
233
+ continue;
234
+ let record = {
235
+ account: request.account,
236
+ machineId: request.machineId,
237
+ ip: request.ip,
238
+ time: Date.now(),
239
+ };
240
+ await trust.set(`${request.account}|${request.machineId}`, record);
241
+ return record;
242
+ }
243
+ }
244
+ throw new Error(`No access request found with id ${JSON.stringify(requestId)}. It may have already been granted or expired.`);
245
+ }
246
+ async get(account, bucketName, path, range) {
247
+ let result = await this.get2(account, bucketName, path, range);
248
+ return result && result.data || undefined;
249
+ }
250
+ async get2(account, bucketName, path, range) {
251
+ assertValidPath(path);
252
+ let bucket = await getBucket(account, bucketName);
253
+ if (!bucket)
254
+ return undefined;
255
+ return await bucket.store.get2(path, { range });
256
+ }
257
+ async set(account, bucketName, path, data, lastModified) {
258
+ assertValidName(bucketName, "bucket name");
259
+ assertValidPath(path);
260
+ // Handles bucket creation (writes of ROUTING_FILE), reconfiguration, fast mode, and
261
+ // immutability — see storageServerState.ts
262
+ await (0, storageServerState_1.writeBucketFile)(account, bucketName, path, Buffer.from(data), { lastModified });
263
+ }
264
+ async del(account, bucketName, path) {
265
+ assertValidName(bucketName, "bucket name");
266
+ assertValidPath(path);
267
+ await (0, storageServerState_1.deleteBucketFile)(account, bucketName, path);
268
+ }
269
+ async getInfo(account, bucketName, path) {
270
+ assertValidPath(path);
271
+ let bucket = await getBucket(account, bucketName);
272
+ if (!bucket)
273
+ return undefined;
274
+ return await bucket.store.getInfo(path);
275
+ }
276
+ async findInfo(account, bucketName, prefix, config) {
277
+ let bucket = await getBucket(account, bucketName);
278
+ if (!bucket)
279
+ return [];
280
+ return await bucket.store.findInfo(prefix, config);
281
+ }
282
+ // Fast (served from the store's BulkDatabase2 index, not a scan) — see IArchives.getChangesAfter
283
+ async getChangesAfter(account, bucketName, time) {
284
+ let bucket = await getBucket(account, bucketName);
285
+ if (!bucket)
286
+ return [];
287
+ if (!bucket.store.getChangesAfter) {
288
+ throw new Error(`Bucket ${account}/${bucketName} does not support getChangesAfter (rawDisk buckets have no index)`);
289
+ }
290
+ return await bucket.store.getChangesAfter(time);
291
+ }
292
+ async getArchivesConfig(account, bucketName) {
293
+ var _a, _b;
294
+ let bucket = await getBucket(account, bucketName);
295
+ // Missing buckets say true, matching what they become once created (the default store type)
296
+ let progress = (_b = bucket === null || bucket === void 0 ? void 0 : (_a = bucket.store).getSyncProgress) === null || _b === void 0 ? void 0 : _b.call(_a);
297
+ return {
298
+ supportsChangesAfter: !bucket || !!bucket.store.getChangesAfter,
299
+ remoteConfig: bucket === null || bucket === void 0 ? void 0 : bucket.routing,
300
+ index: progress === null || progress === void 0 ? void 0 : progress.index,
301
+ indexSources: progress === null || progress === void 0 ? void 0 : progress.sources,
302
+ readerDiskLimit: progress === null || progress === void 0 ? void 0 : progress.readerDiskLimit,
303
+ syncing: progress === null || progress === void 0 ? void 0 : progress.syncing,
304
+ };
305
+ }
306
+ /** Walks the whole index for exact totals (overall and per holding source) - more expensive
307
+ * than the maintained counters that getArchivesConfig returns, but immune to counter drift. */
308
+ async getIndexInfo(account, bucketName) {
309
+ let bucket = await getBucket(account, bucketName);
310
+ if (!bucket || !bucket.store.computeIndexTotals)
311
+ return undefined;
312
+ return await bucket.store.computeIndexTotals();
313
+ }
314
+ async getSyncStatus(account, bucketName) {
315
+ let bucket = await getBucket(account, bucketName);
316
+ if (!bucket)
317
+ return { allScansComplete: true, indexSize: 0, sources: [] };
318
+ if (!bucket.store.getSyncStatus) {
319
+ throw new Error(`Bucket ${account}/${bucketName} does not support getSyncStatus (rawDisk buckets have no synchronization)`);
320
+ }
321
+ return await bucket.store.getSyncStatus();
322
+ }
323
+ async startLargeFile(account, bucketName, path) {
324
+ (0, storageServerState_1.assertWritesAllowed)();
325
+ // Validates now, so the upload doesn't fail at the end
326
+ assertValidPath(path);
327
+ let bucket = await getBucket(account, bucketName);
328
+ if (!bucket) {
329
+ throw new Error(`Bucket ${account}/${bucketName} does not exist. Write its routing config to ${JSON.stringify(remoteConfig_1.ROUTING_FILE)} to create it.`);
330
+ }
331
+ await (0, storageServerState_1.assertMutable)(bucket, path, Date.now());
332
+ let id = await bucket.store.startLargeUpload();
333
+ largeUploadInfo.set(id, { account, bucketName, path });
334
+ return id;
335
+ }
336
+ async uploadPart(uploadId, data) {
337
+ (0, storageServerState_1.assertWritesAllowed)();
338
+ let info = largeUploadInfo.get(uploadId);
339
+ if (!info)
340
+ throw new Error(`Unknown large upload ${uploadId}`);
341
+ let bucket = await getBucket(info.account, info.bucketName);
342
+ if (!bucket)
343
+ throw new Error(`Bucket ${info.account}/${info.bucketName} no longer exists`);
344
+ await bucket.store.appendLargeUpload(uploadId, Buffer.from(data));
345
+ }
346
+ async finishLargeFile(uploadId) {
347
+ (0, storageServerState_1.assertWritesAllowed)();
348
+ let info = largeUploadInfo.get(uploadId);
349
+ if (!info)
350
+ throw new Error(`Unknown large upload ${uploadId}`);
351
+ largeUploadInfo.delete(uploadId);
352
+ let bucket = await getBucket(info.account, info.bucketName);
353
+ if (!bucket)
354
+ throw new Error(`Bucket ${info.account}/${info.bucketName} no longer exists`);
355
+ await bucket.store.finishLargeUpload(uploadId, info.path);
356
+ }
357
+ async cancelLargeFile(uploadId) {
358
+ let info = largeUploadInfo.get(uploadId);
359
+ if (!info)
360
+ return;
361
+ largeUploadInfo.delete(uploadId);
362
+ let bucket = await getBucket(info.account, info.bucketName);
363
+ if (!bucket)
364
+ return;
365
+ await bucket.store.cancelLargeUpload(uploadId);
366
+ }
367
+ // The server's single default HTTP route. /file/<account>/<bucketName>/<path> serves files from
368
+ // public buckets over plain GETs (see IArchives.getURL); every other path serves the access
369
+ // page (via RequireController.requireHTML — the path is the account name, see accessPage.tsx).
370
+ async httpEntry(config) {
371
+ var _a, _b;
372
+ // Both are keyed by the current call and must be captured synchronously, before any await
373
+ let caller = SocketFunction_1.SocketFunction.getCaller();
374
+ let request = (0, callHTTPHandler_1.getCurrentHTTPRequest)();
375
+ let pathname = new URL((request === null || request === void 0 ? void 0 : request.url) || "/", "https://localhost").pathname;
376
+ if (!pathname.startsWith("/file/")) {
377
+ return await (0, callManager_1.performLocalCall)({
378
+ caller,
379
+ call: { nodeId: caller.nodeId, classGuid: RequireController_1.RequireController._classGuid, functionName: "requireHTML", args: [config] },
380
+ });
381
+ }
382
+ let parts = pathname.split("/").filter(x => x).map(decodeURIComponent);
383
+ let account = parts[1];
384
+ let bucketName = parts[2];
385
+ let filePath = parts.slice(3).join("/");
386
+ if (!account || !bucketName || !filePath) {
387
+ return (0, callHTTPHandler_1.setHTTPResultHeaders)(Buffer.from(""), { status: "404" });
388
+ }
389
+ assertValidName(account, "account");
390
+ assertValidName(bucketName, "bucket name");
391
+ assertValidPath(filePath);
392
+ let bucket = await (0, storageServerState_1.getLoadedBucket)(account, bucketName);
393
+ if (!bucket) {
394
+ return (0, callHTTPHandler_1.setHTTPResultHeaders)(Buffer.from(""), { status: "404" });
395
+ }
396
+ if (!((_a = bucket.self) === null || _a === void 0 ? void 0 : _a.public)) {
397
+ throw new Error(`Bucket ${account}/${bucketName} is not public, so its files cannot be read over plain URLs`);
398
+ }
399
+ // The index answers existence + write time + size without touching any data, so
400
+ // If-Modified-Since and range validation cost nothing
401
+ let info = await bucket.store.getInfo(filePath);
402
+ if (!info || !info.size) {
403
+ return (0, callHTTPHandler_1.setHTTPResultHeaders)(Buffer.from(""), { status: "404" });
404
+ }
405
+ let ext = filePath.split(".").pop() || "";
406
+ let headers = {
407
+ "Content-Type": CONTENT_TYPES[ext.toLowerCase()] || "application/octet-stream",
408
+ "Last-Modified": new Date(info.writeTime).toUTCString(),
409
+ "Accept-Ranges": "bytes",
410
+ };
411
+ if ((_b = bucket.self) === null || _b === void 0 ? void 0 : _b.immutable) {
412
+ headers["Cache-Control"] = `max-age=${IArchives_1.IMMUTABLE_CACHE_TIME / 1000}`;
413
+ }
414
+ let ifModifiedSince = request === null || request === void 0 ? void 0 : request.headers["if-modified-since"];
415
+ if (typeof ifModifiedSince === "string") {
416
+ let since = new Date(ifModifiedSince).getTime();
417
+ // Last-Modified is served at 1 second resolution, so compare at that resolution
418
+ if (since && Math.floor(info.writeTime / 1000) * 1000 <= since) {
419
+ return (0, callHTTPHandler_1.setHTTPResultHeaders)(Buffer.from(""), { ...headers, status: "304" });
420
+ }
421
+ }
422
+ let range;
423
+ let rangeHeader = request === null || request === void 0 ? void 0 : request.headers["range"];
424
+ if (typeof rangeHeader === "string") {
425
+ // Single-range form only (bytes=start-end / start- / -suffix); anything else serves the full file
426
+ let match = /^bytes=(\d*)-(\d*)$/.exec(rangeHeader.trim());
427
+ if (match && (match[1] || match[2])) {
428
+ let start;
429
+ let endInclusive = info.size - 1;
430
+ if (!match[1]) {
431
+ start = Math.max(0, info.size - +match[2]);
432
+ }
433
+ else {
434
+ start = +match[1];
435
+ if (match[2]) {
436
+ endInclusive = Math.min(+match[2], info.size - 1);
437
+ }
438
+ }
439
+ if (start >= info.size || start > endInclusive) {
440
+ return (0, callHTTPHandler_1.setHTTPResultHeaders)(Buffer.from(""), { ...headers, "Content-Range": `bytes */${info.size}`, status: "416" });
441
+ }
442
+ range = { start, end: endInclusive + 1 };
443
+ }
444
+ }
445
+ let result = await bucket.store.get2(filePath, { range });
446
+ if (!result) {
447
+ return (0, callHTTPHandler_1.setHTTPResultHeaders)(Buffer.from(""), { status: "404" });
448
+ }
449
+ if (range) {
450
+ return (0, callHTTPHandler_1.setHTTPResultHeaders)(result.data, { ...headers, "Content-Range": `bytes ${range.start}-${range.end - 1}/${info.size}`, status: "206" });
451
+ }
452
+ return (0, callHTTPHandler_1.setHTTPResultHeaders)(result.data, headers);
453
+ }
454
+ }
455
+ const largeUploadInfo = new Map();
456
+ // Access checks run as hooks on the register shape below, keyed off the call's arguments, so the
457
+ // method bodies don't each repeat them
458
+ const accountAccess = async (context) => {
459
+ await requireAccess(String(context.call.args[0]));
460
+ };
461
+ const uploadAccess = async (context) => {
462
+ let info = largeUploadInfo.get(String(context.call.args[0]));
463
+ // Unknown upload ids are handled by the methods themselves (throw / no-op)
464
+ if (!info)
465
+ return;
466
+ await requireAccess(info.account);
467
+ };
468
+ const adminAccess = async () => {
469
+ requireAdmin();
470
+ };
471
+ exports.RemoteStorageController = SocketFunction_1.SocketFunction.register(exports.REMOTE_STORAGE_CLASS_GUID, new RemoteStorageControllerBase(), () => ({
472
+ ping: {},
473
+ authenticate: {},
474
+ requestAccess: {},
475
+ getAccessState: {},
476
+ listRequestsForIP: { hooks: [accountAccess] },
477
+ grantAccess: {},
478
+ adminListRequests: { hooks: [adminAccess] },
479
+ adminGrantAccess: { hooks: [adminAccess] },
480
+ get: { hooks: [accountAccess] },
481
+ get2: { hooks: [accountAccess] },
482
+ set: { hooks: [accountAccess] },
483
+ del: { hooks: [accountAccess] },
484
+ getInfo: { hooks: [accountAccess] },
485
+ findInfo: { hooks: [accountAccess] },
486
+ getChangesAfter: { hooks: [accountAccess] },
487
+ getArchivesConfig: { hooks: [accountAccess] },
488
+ getIndexInfo: { hooks: [accountAccess] },
489
+ getSyncStatus: { hooks: [accountAccess] },
490
+ startLargeFile: { hooks: [accountAccess] },
491
+ uploadPart: { hooks: [uploadAccess] },
492
+ finishLargeFile: { hooks: [uploadAccess] },
493
+ cancelLargeFile: { hooks: [uploadAccess] },
494
+ httpEntry: {},
495
+ }), () => ({
496
+ noClientHooks: true,
497
+ noDefaultHooks: true,
498
+ }));
499
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RvcmFnZUNvbnRyb2xsZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzdG9yYWdlQ29udHJvbGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxNQUFNLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQztBQUUxQixtRUFBZ0U7QUFFaEUsNkRBQTREO0FBQzVELHlFQUFrRztBQUNsRyxpRUFBbUU7QUFDbkUsaUZBQThFO0FBQzlFLG1EQUF3RDtBQUN4RCxrREFBa0k7QUFDbEksNENBQXlHO0FBQ3pHLGlEQUE4QztBQUM5Qyw2REFHOEI7QUFFOUIsNkZBQTZGO0FBQzdGLGlHQUFpRztBQUNqRyw4RkFBOEY7QUFDOUYsZ0dBQWdHO0FBQ2hHLDBDQUEwQztBQUMxQyxFQUFFO0FBQ0YsaUdBQWlHO0FBQ2pHLGlHQUFpRztBQUNqRyxvRkFBb0Y7QUFFdkUsUUFBQSx5QkFBeUIsR0FBRyxrQ0FBa0MsQ0FBQztBQUMvRCxRQUFBLG9CQUFvQixHQUFHLHNCQUFzQixDQUFDO0FBQzNELDhFQUE4RTtBQUNqRSxRQUFBLHlCQUF5QixHQUFHLDJDQUEyQyxDQUFDO0FBQ3hFLFFBQUEscUJBQXFCLEdBQUcsdUNBQXVDLENBQUM7QUFFN0UsTUFBTSxnQkFBZ0IsR0FBRyxtQkFBWSxHQUFHLEVBQUUsQ0FBQztBQUMzQyxNQUFNLFlBQVksR0FBRyxHQUFHLEdBQUcsSUFBSSxDQUFDO0FBQ2hDLE1BQU0sbUJBQW1CLEdBQUcsRUFBRSxDQUFDO0FBa0MvQiwrRkFBK0Y7QUFDL0YsMkVBQTJFO0FBQzNFLE1BQU0sUUFBUSxHQUFHLElBQUksR0FBRyxFQUFrQixDQUFDO0FBRTNDLE1BQU0sYUFBYSxHQUE4QjtJQUM3QyxJQUFJLEVBQUUsV0FBVyxFQUFFLEVBQUUsRUFBRSxpQkFBaUIsRUFBRSxHQUFHLEVBQUUsVUFBVSxFQUFFLElBQUksRUFBRSxrQkFBa0I7SUFDbkYsR0FBRyxFQUFFLFlBQVksRUFBRSxHQUFHLEVBQUUsV0FBVyxFQUFFLEdBQUcsRUFB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Q0FBQyxFQUFFO0lBQzNDLGlCQUFpQixFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsYUFBYSxDQUFDLEVBQUU7SUFDN0MsWUFBWSxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsYUFBYSxDQUFDLEVBQUU7SUFDeEMsYUFBYSxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsYUFBYSxDQUFDLEVBQUU7SUFDekMsY0FBYyxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsYUFBYSxDQUFDLEVBQUU7SUFDMUMsVUFBVSxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsWUFBWSxDQUFDLEVBQUU7SUFDckMsZUFBZSxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsWUFBWSxDQUFDLEVBQUU7SUFDMUMsZUFBZSxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsWUFBWSxDQUFDLEVBQUU7SUFDMUMsU0FBUyxFQUFFLEVBQUU7Q0FDaEIsQ0FBQyxFQUNGLEdBQUcsRUFBRSxDQUFDLENBQUM7SUFDSCxhQUFhLEVBQUUsSUFBSTtJQUNuQixjQUFjLEVBQUUsSUFBSTtDQUN2QixDQUFDLENBQ0wsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIm1vZHVsZS5hbGxvd2NsaWVudCA9IHRydWU7XG5cbmltcG9ydCB7IFNvY2tldEZ1bmN0aW9uIH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9Tb2NrZXRGdW5jdGlvblwiO1xuaW1wb3J0IHsgU29ja2V0RnVuY3Rpb25Ib29rIH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9Tb2NrZXRGdW5jdGlvblR5cGVzXCI7XG5pbXBvcnQgeyBnZXROb2RlSWRJUCB9IGZyb20gXCJzb2NrZXQtZnVuY3Rpb24vc3JjL25vZGVDYWNoZVwiO1xuaW1wb3J0IHsgc2V0SFRUUFJlc3VsdEhlYWRlcnMsIGdldEN1cnJlbnRIVFRQUmVxdWVzdCB9IGZyb20gXCJzb2NrZXQtZnVuY3Rpb24vc3JjL2NhbGxIVFRQSGFuZGxlclwiO1xuaW1wb3J0IHsgcGVyZm9ybUxvY2FsQ2FsbCB9IGZyb20gXCJzb2NrZXQtZnVuY3Rpb24vc3JjL2NhbGxNYW5hZ2VyXCI7XG5pbXBvcnQgeyBSZXF1aXJlQ29udHJvbGxlciB9IGZyb20gXCJzb2NrZXQtZnVuY3Rpb24vcmVxdWlyZS9SZXF1aXJlQ29udHJvbGxlclwiO1xuaW1wb3J0IHsgdGltZUluTWludXRlIH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9zcmMvbWlzY1wiO1xuaW1wb3J0IHsgZ2V0Q29tbW9uTmFtZSwgZ2V0UHVibGljSWRlbnRpZmllciwgZ2V0T3duTWFjaGluZUlkLCB2ZXJpZnksIHZlcmlmeU1hY2hpbmVJZEZvclB1YmxpY0tleSB9IGZyb20gXCIuLi8uLi9taXNjL2h0dHBzL2NlcnRzXCI7XG5pbXBvcnQgeyBBcmNoaXZlRmlsZUluZm8sIEFyY2hpdmVzQ29uZmlnLCBBcmNoaXZlc1N5bmNTdGF0dXMsIElNTVVUQUJMRV9DQUNIRV9USU1FIH0gZnJvbSBcIi4uL0lBcmNoaXZlc1wiO1xuaW1wb3J0IHsgUk9VVElOR19GSUxFIH0gZnJvbSBcIi4vcmVtb3RlQ29uZmlnXCI7XG5pbXBvcnQge1xuICAgIGdldFN0b3JhZ2VTZXJ2ZXJDb25maWcsIGdldFRydXN0LCBnZXRSZXF1ZXN0cywgZ2V0TG9hZGVkQnVja2V0LCB3cml0ZUJ1Y2tldEZpbGUsXG4gICAgZGVsZXRlQnVja2V0RmlsZSwgYXNzZXJ0V3JpdGVzQWxsb3dlZCwgYXNzZXJ0TXV0YWJsZSwgTG9hZGVkQnVja2V0LFxufSBmcm9tIFwiLi9zdG9yYWdlU2VydmVyU3RhdGVcIjtcblxuLy8gVGhlIHJlbW90ZSBzdG9yYWdlIHNlcnZlcidzIEFQSS4gQXV0aGVudGljYXRpb24gdXNlcyBjZXJ0cy50cyBtYWNoaW5lIGlkZW50aXRpZXM6IGEgY2xpZW50XG4vLyBwcm92ZXMgaXQgb3ducyBpdHMgbWFjaGluZSBrZXkgYnkgc2lnbmluZyBhIHRpbWVzdGFtcGVkIHRva2VuIChib3VuZCB0byB0aGlzIHNlcnZlciwgc28gdG9rZW5zXG4vLyBjYW4ndCBiZSByZXBsYXllZCBlbHNld2hlcmUpLCBhbmQgdGhlIHNlcnZlciB0aGVuIHRydXN0cyB0aGF0IGNvbm5lY3Rpb24gYXMgdGhhdCBtYWNoaW5lSWQuXG4vLyBBY2Nlc3MgdG8gYW4gYWNjb3VudCBpcyBncmFudGVkIHRvIHNwZWNpZmljIG1hY2hpbmVJZHMsIHZpYSBhIGNvbW1hbmQgbGluZSBjb21tYW5kIHJ1biBvbiB0aGVcbi8vIHN0b3JhZ2UgbWFjaGluZSAoc2VlIHN0b3JhZ2VTZXJ2ZXIudHMpLlxuLy9cbi8vIFRoZXJlIGlzIG5vIGJ1Y2tldC1jcmVhdGlvbiBBUEk6IGEgYnVja2V0IGV4aXN0cyBpZmYgaXRzIHJvdXRpbmcgY29uZmlnIChST1VUSU5HX0ZJTEUpIGV4aXN0cyxcbi8vIGFuZCB3cml0aW5nIHRoYXQgZmlsZSBjcmVhdGVzIG9yIHJlY29uZmlndXJlcyB0aGUgYnVja2V0IChzZWUgc3RvcmFnZVNlcnZlclN0YXRlLnRzKS4gUmVhZHMgb2Zcbi8vIG5vbmV4aXN0ZW50IGJ1Y2tldHMgcmV0dXJuIHVuZGVmaW5lZCAvIGVtcHR5LCBzYW1lIGFzIHJlYWRzIG9mIG5vbmV4aXN0ZW50IGZpbGVzLlxuXG5leHBvcnQgY29uc3QgUkVNT1RFX1NUT1JBR0VfQ0xBU1NfR1VJRCA9IFwiUmVtb3RlU3RvcmFnZUNvbnRyb2xsZXItYjdlNDJhOTFcIjtcbmV4cG9ydCBjb25zdCBTVE9SQUdFX0FVVEhfUFVSUE9TRSA9IFwicmVtb3RlU3RvcmFnZS1hdXRoLTFcIjtcbi8vIEVycm9yIG1hcmtlcnMsIHNvIGNsaWVudHMgY2FuIGlkZW50aWZ5IHRoZXNlIGZhaWx1cmVzIGluc2lkZSBlcnJvciBtZXNzYWdlc1xuZXhwb3J0IGNvbnN0IFNUT1JBR0VfTk9UX0FVVEhFTlRJQ0FURUQgPSBcIlJFTU9URV9TVE9SQUdFX05PVF9BVVRIRU5USUNBVEVEX2NmMmY3YjFlXCI7XG5leHBvcnQgY29uc3QgU1RPUkFHRV9BQ0NFU1NfREVOSUVEID0gXCJSRU1PVEVfU1RPUkFHRV9BQ0NFU1NfREVOSUVEXzlkODFhNGMwXCI7XG5cbmNvbnN0IEFVVEhfVElNRV9XSU5ET1cgPSB0aW1lSW5NaW51dGUgKiAxMDtcbmNvbnN0IE1BWF9TRVNTSU9OUyA9IDEwMCAqIDEwMDA7XG5jb25zdCBNQVhfUkVRVUVTVFNfUEVSX0lQID0gNTA7XG5cbmV4cG9ydCB0eXBlIEF1dGhUb2tlbiA9IHtcbiAgICBjZXJ0UGVtOiBzdHJpbmc7XG4gICAgdGltZTogbnVtYmVyO1xuICAgIHNpZ25hdHVyZTogc3RyaW5nO1xufTtcbmV4cG9ydCB0eXBlIEFjY2Vzc1JlcXVlc3QgPSB7XG4gICAgcmVxdWVzdElkOiBzdHJpbmc7XG4gICAgYWNjb3VudDogc3RyaW5nO1xuICAgIG1hY2hpbmVJZDogc3RyaW5nO1xuICAgIGlwOiBzdHJpbmc7XG4gICAgdGltZTogbnVtYmVyO1xufTtcbmV4cG9ydCB0eXBlIFRydXN0UmVjb3JkID0ge1xuICAgIGFjY291bnQ6IHN0cmluZztcbiAgICBtYWNoaW5lSWQ6IHN0cmluZztcbiAgICBpcDogc3RyaW5nO1xuICAgIHRpbWU6IG51bWJlcjtcbn07XG5leHBvcnQgdHlwZSBBY2Nlc3NTdGF0ZSA9IHtcbiAgICBtYWNoaW5lSWQ6IHN0cmluZztcbiAgICBpcDogc3RyaW5nO1xuICAgIGhhc0FjY2VzczogYm9vbGVhbjtcbiAgICAvLyBBIHNpbmdsZSBzc2ggY29tbWFuZCwgcnVubmFibGUgZnJvbSBhbnl3aGVyZSwgdGhhdCBydW5zIHRoZSBncmFudEFjY2VzcyBDTEkgb24gdGhlIHN0b3JhZ2VcbiAgICAvLyBtYWNoaW5lIHRvIGdyYW50IHRoZSBjYWxsZXIncyBvd24gcGVuZGluZyByZXF1ZXN0LiBPbmx5IHNldCB3aGVuIHRoZSBjYWxsZXIgaGFzIGEgcGVuZGluZ1xuICAgIC8vIHJlcXVlc3QgKHNvIGFuIGFscmVhZHktdHJ1c3RlZCBjYWxsZXIgaGFzIG5vIG5lZWQgZm9yIGl0KS5cbiAgICBncmFudEFjY2Vzc0NvbW1hbmQ/OiBzdHJpbmc7XG4gICAgLy8gT25seSB0aGUgbWFjaGluZXMgdGhhdCBBTFJFQURZIGhhdmUgYWNjZXNzLiBQZW5kaW5nIHJlcXVlc3RzIGFyZSBORVZFUiBsaXN0ZWQgaGVyZSDigJQgc2hvd2luZ1xuICAgIC8vIHRoZW0gd291bGQgbGV0IGEgdHJ1c3RlZCB1c2VyIGFjY2lkZW50YWxseSBhcHByb3ZlIGEgcmFuZG9tIHJlcXVlc3QuIENhbGxlcnMgc2VlIHBlbmRpbmdcbiAgICAvLyByZXF1ZXN0cyBvbmx5IGJ5IGV4cGxpY2l0bHkgdHlwaW5nIGFuIElQIGludG8gbGlzdFJlcXVlc3RzRm9ySVAuXG4gICAgdHJ1c3RlZE1hY2hpbmVzPzogVHJ1c3RSZWNvcmRbXTtcbn07XG5cbi8vIGNhbGxlck5vZGVJZCAtPiBhdXRoZW50aWNhdGVkIG1hY2hpbmVJZC4gQ29ubmVjdGlvbnMgYXJlIGxvbmctbGl2ZWQgd2Vic29ja2V0cywgc28gYSBzZXNzaW9uXG4vLyBsYXN0cyB1bnRpbCB0aGUgY29ubmVjdGlvbiBkcm9wcyAoY2xpZW50cyByZS1hdXRoZW50aWNhdGUgb24gcmVjb25uZWN0KS5cbmNvbnN0IHNlc3Npb25zID0gbmV3IE1hcDxzdHJpbmcsIHN0cmluZz4oKTtcblxuY29uc3QgQ09OVEVOVF9UWVBFUzogeyBbZXh0OiBzdHJpbmddOiBzdHJpbmcgfSA9IHtcbiAgICBodG1sOiBcInRleHQvaHRtbFwiLCBqczogXCJ0ZXh0L2phdmFzY3JpcHRcIiwgY3NzOiBcInRleHQvY3NzXCIsIGpzb246IFwiYXBwbGljYXRpb24vanNvblwiLFxuICAgIHR4dDogXCJ0ZXh0L3BsYWluXCIsIHBuZzogXCJpbWFnZS9wbmdcIiwganBnOiBcImltYWdlL2pwZWdcIiwganBlZzogXCJpbWFnZS9qcGVnXCIsIGdpZjogXCJpbWFnZS9naWZcIixcbiAgICBzdmc6IFwiaW1hZ2Uvc3ZnK3htbFwiLCB3ZWJwOiBcImltYWdlL3dlYnBcIiwgbXA0OiBcInZpZGVvL21wNFwiLCB3ZWJtOiBcInZpZGVvL3dlYm1cIixcbiAgICBtcDM6IFwiYXVkaW8vbXBlZ1wiLCB3YXY6IFwiYXVkaW8vd2F2XCIsIHBkZjogXCJhcHBsaWNhdGlvbi9wZGZcIixcbn07XG5cbmZ1bmN0aW9uIGFzc2VydFZhbGlkTmFtZSh2YWx1ZTogc3RyaW5nLCBraW5kOiBzdHJpbmcpIHtcbiAgICBpZiAoIS9eW1xcdy1dezEsNjR9JC8udGVzdCh2YWx1ZSkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkICR7a2luZH0gJHtKU09OLnN0cmluZ2lmeSh2YWx1ZSl9LCBleHBlY3RlZCAxLTY0IGNoYXJhY3RlcnMgb2YgbGV0dGVycy9udW1iZXJzL3VuZGVyc2NvcmUvZGFzaGApO1xuICAgIH1cbn1cbmZ1bmN0aW9uIGFzc2VydFZhbGlkUGF0aChwYXRoOiBzdHJpbmcpIHtcbiAgICBpZiAoQnVmZmVyLmZyb20ocGF0aCwgXCJ1dGY4XCIpLmxlbmd0aCA+IDEwMDApIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBQYXRoIHRvbyBsb25nOiAke3BhdGgubGVuZ3RofSBjaGFyYWN0ZXJzID4gMTAwMC4gUGF0aDogJHtwYXRoLnNsaWNlKDAsIDIwMCl9YCk7XG4gICAgfVxuICAgIGlmICghcGF0aCB8fCBwYXRoLnN0YXJ0c1dpdGgoXCIvXCIpIHx8IHBhdGguZW5kc1dpdGgoXCIvXCIpIHx8IHBhdGguaW5jbHVkZXMoXCIvL1wiKSB8fCBwYXRoLmluY2x1ZGVzKFwiXFxcXFwiKSB8fCBwYXRoLmluY2x1ZGVzKFwiXFx4MDBcIikpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHBhdGggJHtKU09OLnN0cmluZ2lmeShwYXRoLnNsaWNlKDAsIDIwMCkpfSwgcGF0aHMgY2Fubm90IGJlIGVtcHR5LCBzdGFydCBvciBlbmQgd2l0aCAvLCBvciBjb250YWluIC8vLCBiYWNrc2xhc2hlcywgb3IgbnVsbCBjaGFyYWN0ZXJzYCk7XG4gICAgfVxuICAgIC8vIFBhdGhzIGFyZSBvbmUtdG8tb25lIHdpdGggZmlsZXMgb24gZGlzaywgc28gLiBhbmQgLi4gc2VnbWVudHMgd291bGQgZXNjYXBlIHRoZSBzdG9yZSBmb2xkZXJcbiAgICBpZiAocGF0aC5zcGxpdChcIi9cIikuc29tZShwYXJ0ID0+IHBhcnQgPT09IFwiLlwiIHx8IHBhcnQgPT09IFwiLi5cIikpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHBhdGggJHtKU09OLnN0cmluZ2lmeShwYXRoLnNsaWNlKDAsIDIwMCkpfSwgcGF0aHMgY2Fubm90IGNvbnRhaW4gLiBvciAuLiBzZWdtZW50c2ApO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gZ2V0Q2FsbGVyTWFjaGluZUlkKCk6IHN0cmluZyB7XG4gICAgbGV0IGNhbGxlciA9IFNvY2tldEZ1bmN0aW9uLmdldENhbGxlcigpO1xuICAgIGxldCBtYWNoaW5lSWQgPSBzZXNzaW9ucy5nZXQoY2FsbGVyLm5vZGVJZCk7XG4gICAgaWYgKCFtYWNoaW5lSWQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGAke1NUT1JBR0VfTk9UX0FVVEhFTlRJQ0FURUR9IENhbGwgYXV0aGVudGljYXRlIGZpcnN0IChjb25uZWN0aW9uICR7Y2FsbGVyLm5vZGVJZH0pYCk7XG4gICAgfVxuICAgIHJldHVybiBtYWNoaW5lSWQ7XG59XG5mdW5jdGlvbiBnZXRDYWxsZXJJUCgpOiBzdHJpbmcge1xuICAgIHJldHVybiBnZXROb2RlSWRJUChTb2NrZXRGdW5jdGlvbi5nZXRDYWxsZXIoKS5ub2RlSWQpO1xufVxuZnVuY3Rpb24gaXNBZG1pbihtYWNoaW5lSWQ6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiBtYWNoaW5lSWQgPT09IGdldE93bk1hY2hpbmVJZChnZXRTdG9yYWdlU2VydmVyQ29uZmlnKCkucm9vdERvbWFpbik7XG59XG5mdW5jdGlvbiByZXF1aXJlQWRtaW4oKTogc3RyaW5nIHtcbiAgICBsZXQgbWFjaGluZUlkID0gZ2V0Q2FsbGVyTWFjaGluZUlkKCk7XG4gICAgaWYgKCFpc0FkbWluKG1hY2hpbmVJZCkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGAke1NUT1JBR0VfQUNDRVNTX0RFTklFRH0gQWRtaW4gY29tbWFuZHMgbXVzdCBiZSBydW4gZnJvbSB0aGUgc3RvcmFnZSBtYWNoaW5lIGl0c2VsZiAoY2FsbGVyIG1hY2hpbmUgJHttYWNoaW5lSWR9KWApO1xuICAgIH1cbiAgICByZXR1cm4gbWFjaGluZUlkO1xufVxuYXN5bmMgZnVuY3Rpb24gcmVxdWlyZUFjY2VzcyhhY2NvdW50OiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGFzc2VydFZhbGlkTmFtZShhY2NvdW50LCBcImFjY291bnRcIik7XG4gICAgbGV0IG1hY2hpbmVJZCA9IGdldENhbGxlck1hY2hpbmVJZCgpO1xuICAgIGlmIChpc0FkbWluKG1hY2hpbmVJZCkpIHJldHVybiBtYWNoaW5lSWQ7XG4gICAgbGV0IHRydXN0ID0gYXdhaXQgZ2V0VHJ1c3QoKTtcbiAgICBsZXQgdHJ1c3RlZCA9IGF3YWl0IHRydXN0LmdldChgJHthY2NvdW50fXwke21hY2hpbmVJZH1gKTtcbiAgICBpZiAoIXRydXN0ZWQpIHtcbiAgICAgICAgbGV0IHsgZG9tYWluLCBwb3J0IH0gPSBnZXRTdG9yYWdlU2VydmVyQ29uZmlnKCk7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgJHtTVE9SQUdFX0FDQ0VTU19ERU5JRUR9IE1hY2hpbmUgJHttYWNoaW5lSWR9IGhhcyBubyBhY2Nlc3MgdG8gYWNjb3VudCAke0pTT04uc3RyaW5naWZ5KGFjY291bnQpfS4gVmlzaXQgaHR0cHM6Ly8ke2RvbWFpbn06JHtwb3J0fS8ke2FjY291bnR9IGZvciBhY2Nlc3MgaW5zdHJ1Y3Rpb25zLmApO1xuICAgIH1cbiAgICByZXR1cm4gbWFjaGluZUlkO1xufVxuXG4vLyBBIHNpbmdsZSBjb21tYW5kLCBydW5uYWJsZSBmcm9tIGFueXdoZXJlLCB0aGF0IHNzaGVzIGludG8gdGhlIHN0b3JhZ2UgbWFjaGluZSBhbmQgcnVucyB0aGVcbi8vIGdyYW50QWNjZXNzIENMSSB0aGVyZVxuZnVuY3Rpb24gZ2V0R3JhbnRBY2Nlc3NDb21tYW5kKHJlcXVlc3RJZDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBsZXQgeyBzc2hUYXJnZXQsIHNlcnZlckNvbW1hbmQgfSA9IGdldFN0b3JhZ2VTZXJ2ZXJDb25maWcoKTtcbiAgICByZXR1cm4gYHNzaCAke3NzaFRhcmdldH0gJyR7c2VydmVyQ29tbWFuZH0gLS1yZXF1ZXN0SWQgJHtyZXF1ZXN0SWR9J2A7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdldEJ1Y2tldChhY2NvdW50OiBzdHJpbmcsIGJ1Y2tldE5hbWU6IHN0cmluZyk6IFByb21pc2U8TG9hZGVkQnVja2V0IHwgdW5kZWZpbmVkPiB7XG4gICAgYXNzZXJ0VmFsaWROYW1lKGFjY291bnQsIFwiYWNjb3VudFwiKTtcbiAgICBhc3NlcnRWYWxpZE5hbWUoYnVja2V0TmFtZSwgXCJidWNrZXQgbmFtZVwiKTtcbiAgICByZXR1cm4gYXdhaXQgZ2V0TG9hZGVkQnVja2V0KGFjY291bnQsIGJ1Y2tldE5hbWUpO1xufVxuXG5jbGFzcyBSZW1vdGVTdG9yYWdlQ29udHJvbGxlckJhc2Uge1xuICAgIC8vIExhdGVuY3kgbWVhc3VyZW1lbnQgKHNlZSBTb3VyY2VXcmFwcGVyJ3MgcGluZ2luZyk7IG5vIGF1dGgsIGl0IG1lYXN1cmVzIHRoZSB0cmFuc3BvcnRcbiAgICBhc3luYyBwaW5nKCk6IFByb21pc2U8dm9pZD4geyB9XG5cbiAgICAvLyBQcm92ZXMgdGhlIGNhbGxlciBvd25zIHRoZSBtYWNoaW5lIGtleSBmb3IgdGhlIG1hY2hpbmVJZCBpbiBpdHMgY2VydGlmaWNhdGUuIFRoZSBzaWduYXR1cmVcbiAgICAvLyBtdXN0IGJlIGZyZXNoIGFuZCBib3VuZCB0byB0aGlzIHNlcnZlciwgc28gaXQgY2Fubm90IGJlIHJlcGxheWVkIHRvIChvciBmcm9tKSBvdGhlciBzZXJ2ZXJzLlxuICAgIGFzeW5jIGF1dGhlbnRpY2F0ZSh0b2tlbjogQXV0aFRva2VuKTogUHJvbWlzZTx7IG1hY2hpbmVJZDogc3RyaW5nOyBpcDogc3RyaW5nIH0+IHtcbiAgICAgICAgbGV0IHsgZG9tYWluLCBwb3J0IH0gPSBnZXRTdG9yYWdlU2VydmVyQ29uZmlnKCk7XG4gICAgICAgIGxldCBjYWxsZXIgPSBTb2NrZXRGdW5jdGlvbi5nZXRDYWxsZXIoKTtcbiAgICAgICAgaWYgKE1hdGguYWJzKERhdGUubm93KCkgLSB0b2tlbi50aW1lKSA+IEFVVEhfVElNRV9XSU5ET1cpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgQXV0aCB0b2tlbiB0aW1lIGlzIHRvbyBmYXIgZnJvbSB0aGUgc2VydmVyIHRpbWUgKHRva2VuICR7dG9rZW4udGltZX0sIHNlcnZlciAke0RhdGUubm93KCl9LCBhbGxvd2VkIGRyaWZ0ICR7QVVUSF9USU1FX1dJTkRPV31tcylgKTtcbiAgICAgICAgfVxuICAgICAgICB2ZXJpZnkodG9rZW4uY2VydFBlbSwgdG9rZW4uc2lnbmF0dXJlLCB7XG4gICAgICAgICAgICBwdXJwb3NlOiBTVE9SQUdFX0FVVEhfUFVSUE9TRSxcbiAgICAgICAgICAgIHRpbWU6IHRva2VuLnRpbWUsXG4gICAgICAgICAgICBzZXJ2ZXI6IGAke2RvbWFpbn06JHtwb3J0fWAsXG4gICAgICAgIH0pO1xuICAgICAgICBsZXQgbWFjaGluZUlkID0gZ2V0Q29tbW9uTmFtZSh0b2tlbi5jZXJ0UGVtKS5zcGxpdChcIi5cIilbMF07XG4gICAgICAgIGlmICghdmVyaWZ5TWFjaGluZUlkRm9yUHVibGljS2V5KHsgbWFjaGluZUlkLCBwdWJsaWNLZXk6IGdldFB1YmxpY0lkZW50aWZpZXIodG9rZW4uY2VydFBlbSkgfSkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgQ2VydGlmaWNhdGUgY29tbW9uIG5hbWUgJHtKU09OLnN0cmluZ2lmeShnZXRDb21tb25OYW1lKHRva2VuLmNlcnRQZW0pKX0gZG9lcyBub3QgbWF0Y2ggaXRzIHB1YmxpYyBrZXlgKTtcbiAgICAgICAgfVxuICAgICAgICBzZXNzaW9ucy5zZXQoY2FsbGVyLm5vZGVJZCwgbWFjaGluZUlkKTtcbiAgICAgICAgd2hpbGUgKHNlc3Npb25zLnNpemUgPiBNQVhfU0VTU0lPTlMpIHtcbiAgICAgICAgICAgIGxldCBvbGRlc3QgPSBzZXNzaW9ucy5rZXlzKCkubmV4dCgpLnZhbHVlO1xuICAgICAgICAgICAgaWYgKG9sZGVzdCA9PT0gdW5kZWZpbmVkKSBicmVhaztcbiAgICAgICAgICAgIHNlc3Npb25zLmRlbGV0ZShvbGRlc3QpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB7IG1hY2hpbmVJZCwgaXA6IGdldENhbGxlcklQKCkgfTtcbiAgICB9XG5cbiAgICAvLyBSZWNvcmRzIHRoYXQgdGhlIGNhbGxpbmcgbWFjaGluZSB3YW50cyBhY2Nlc3MgdG8gYW4gYWNjb3VudC4gUmVxdWVzdHMgYXJlIGtlcHQgcGVyIHJlcXVlc3RpbmdcbiAgICAvLyBJUCwgc28gdGhlIHN0b3JhZ2UgbWFjaGluZSdzIGFkbWluIGNhbiBsaXN0IHRoZW0gd2l0aCAtLWxpc3RBY2Nlc3MgPGlwPiBhbmQgZ3JhbnQgb25lLlxuICAgIGFzeW5jIHJlcXVlc3RBY2Nlc3MoYWNjb3VudDogc3RyaW5nKTogUHJvbWlzZTx7IG1hY2hpbmVJZDogc3RyaW5nOyBpcDogc3RyaW5nOyByZXF1ZXN0SWQ6IHN0cmluZzsgZ3JhbnRBY2Nlc3NDb21tYW5kOiBzdHJpbmcgfT4ge1xuICAgICAgICBhc3NlcnRWYWxpZE5hbWUoYWNjb3VudCwgXCJhY2NvdW50XCIpO1xuICAgICAgICBsZXQgbWFjaGluZUlkID0gZ2V0Q2FsbGVyTWFjaGluZUlkKCk7XG4gICAgICAgIGxldCBpcCA9IGdldENhbGxlcklQKCk7XG4gICAgICAgIGxldCByZXF1ZXN0c1N0b3JhZ2UgPSBhd2FpdCBnZXRSZXF1ZXN0cygpO1xuICAgICAgICBsZXQgcmVxdWVzdHMgPSBhd2FpdCByZXF1ZXN0c1N0b3JhZ2UuZ2V0KGlwKSB8fCBbXTtcbiAgICAgICAgbGV0IGV4aXN0aW5nID0gcmVxdWVzdHMuZmluZCh4ID0+IHguYWNjb3VudCA9PT0gYWNjb3VudCAmJiB4Lm1hY2hpbmVJZCA9PT0gbWFjaGluZUlkKTtcbiAgICAgICAgaWYgKGV4aXN0aW5nKSB7XG4gICAgICAgICAgICBleGlzdGluZy50aW1lID0gRGF0ZS5ub3coKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGV4aXN0aW5nID0ge1xuICAgICAgICAgICAgICAgIHJlcXVlc3RJZDogTWF0aC5yYW5kb20oKS50b1N0cmluZygzNikuc2xpY2UoMiwgMTApLFxuICAgICAgICAgICAgICAgIGFjY291bnQsXG4gICAgICAgICAgICAgICAgbWFjaGluZUlkLFxuICAgICAgICAgICAgICAgIGlwLFxuICAgICAgICAgICAgICAgIHRpbWU6IERhdGUubm93KCksXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgcmVxdWVzdHMucHVzaChleGlzdGluZyk7XG4gICAgICAgIH1cbiAgICAgICAgd2hpbGUgKHJlcXVlc3RzLmxlbmd0aCA+IE1BWF9SRVFVRVNUU19QRVJfSVApIHJlcXVlc3RzLnNoaWZ0KCk7XG4gICAgICAgIGF3YWl0IHJlcXVlc3RzU3RvcmFnZS5zZXQoaXAsIHJlcXVlc3RzKTtcbiAgICAgICAgcmV0dXJuIHsgbWFjaGluZUlkLCBpcCwgcmVxdWVzdElkOiBleGlzdGluZy5yZXF1ZXN0SWQsIGdyYW50QWNjZXNzQ29tbWFuZDogZ2V0R3JhbnRBY2Nlc3NDb21tYW5kKGV4aXN0aW5nLnJlcXVlc3RJZCkgfTtcbiAgICB9XG5cbiAgICBhc3luYyBnZXRBY2Nlc3NTdGF0ZShhY2NvdW50OiBzdHJpbmcpOiBQcm9taXNlPEFjY2Vzc1N0YXRlPiB7XG4gICAgICAgIGFzc2VydFZhbGlkTmFtZShhY2NvdW50LCBcImFjY291bnRcIik7XG4gICAgICAgIGxldCBtYWNoaW5lSWQgPSBnZXRDYWxsZXJNYWNoaW5lSWQoKTtcbiAgICAgICAgbGV0IGlwID0gZ2V0Q2FsbGVySVAoKTtcbiAgICAgICAgbGV0IHRydXN0ID0gYXdhaXQgZ2V0VHJ1c3QoKTtcbiAgICAgICAgbGV0IGhhc0FjY2VzcyA9IGlzQWRtaW4obWFjaGluZUlkKSB8fCAhIWF3YWl0IHRydXN0LmdldChgJHthY2NvdW50fXwke21hY2hpbmVJZH1gKTtcbiAgICAgICAgbGV0IHJlc3VsdDogQWNjZXNzU3RhdGUgPSB7IG1hY2hpbmVJZCwgaXAsIGhhc0FjY2VzcyB9O1xuICAgICAgICBpZiAoIWhhc0FjY2Vzcykge1xuICAgICAgICAgICAgbGV0IHJlcXVlc3RzID0gYXdhaXQgZ2V0UmVxdWVzdHMoKTtcbiAgICAgICAgICAgIGxldCBvd25SZXF1ZXN0ID0gKGF3YWl0IHJlcXVlc3RzLmdldChpcCkgfHwgW10pLmZpbmQoeCA9PiB4LmFjY291bnQgPT09IGFjY291bnQgJiYgeC5tYWNoaW5lSWQgPT09IG1hY2hpbmVJZCk7XG4gICAgICAgICAgICBpZiAob3duUmVxdWVzdCkge1xuICAgICAgICAgICAgICAgIHJlc3VsdC5ncmFudEFjY2Vzc0NvbW1hbmQgPSBnZXRHcmFudEFjY2Vzc0NvbW1hbmQob3duUmVxdWVzdC5yZXF1ZXN0SWQpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCB0cnVzdGVkTWFjaGluZXM6IFRydXN0UmVjb3JkW10gPSBbXTtcbiAgICAgICAgZm9yIChsZXQga2V5IG9mIGF3YWl0IHRydXN0LmdldEtleXMoKSkge1xuICAgICAgICAgICAgaWYgKCFrZXkuc3RhcnRzV2l0aChgJHthY2NvdW50fXxgKSkgY29udGludWU7XG4gICAgICAgICAgICBsZXQgcmVjb3JkID0gYXdhaXQgdHJ1c3QuZ2V0KGtleSk7XG4gICAgICAgICAgICBpZiAocmVjb3JkKSB0cnVzdGVkTWFjaGluZXMucHVzaChyZWNvcmQpO1xuICAgICAgICB9XG4gICAgICAgIHJlc3VsdC50cnVzdGVkTWFjaGluZXMgPSB0cnVzdGVkTWFjaGluZXM7XG4gICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgLy8gQ2FsbGFibGUgYnkgYW55IG1hY2hpbmUgdGhhdCBoYXMgYWNjZXNzIHRvIGBhY2NvdW50YC4gUmV0dXJucyBwZW5kaW5nIGFjY2VzcyByZXF1ZXN0cyBmb3IgdGhlXG4gICAgLy8gYWNjb3VudCB0aGF0IGNvbWUgZnJvbSBFWEFDVExZIGBpcGAuIENhbGxlcnMgbXVzdCB0eXBlIGluIGFuIElQIGV4cGxpY2l0bHkg4oCUIHRoZSBzZXJ2ZXIgbmV2ZXJcbiAgICAvLyB2b2x1bnRlZXJzIGEgbGlzdCBvZiByZXF1ZXN0aW5nIElQcywgc28gYSB0cnVzdGVkIHVzZXIgY2FuJ3QgYWNjaWRlbnRhbGx5IGFwcHJvdmUgYSByYW5kb21cbiAgICAvLyByZXF1ZXN0IGZyb20gYSBtYWNoaW5lIHRoZXkgZGlkbid0IG1lYW4gdG8gdHJ1c3QuXG4gICAgYXN5bmMgbGlzdFJlcXVlc3RzRm9ySVAoYWNjb3VudDogc3RyaW5nLCBpcDogc3RyaW5nKTogUHJvbWlzZTxBY2Nlc3NSZXF1ZXN0W10+IHtcbiAgICAgICAgbGV0IHJlcXVlc3RzID0gYXdhaXQgZ2V0UmVxdWVzdHMoKTtcbiAgICAgICAgcmV0dXJuIChhd2FpdCByZXF1ZXN0cy5nZXQoaXApIHx8IFtdKS5maWx0ZXIoeCA9PiB4LmFjY291bnQgPT09IGFjY291bnQpO1xuICAgIH1cblxuICAgIC8vIENhbGxhYmxlIGJ5IGFueSBtYWNoaW5lIHRoYXQgaGFzIGFjY2VzcyB0byB0aGUgcmVxdWVzdCdzIGFjY291bnQgKG9yIGJ5IHRoZSBzdG9yYWdlLW1hY2hpbmVcbiAgICAvLyBhZG1pbikuIEdyYW50cyB0aGUgcmVxdWVzdGVkIGFjY2VzczsgdGhlIGNhbGxlciBtdXN0IHN1cHBseSB0aGUgc3BlY2lmaWMgcmVxdWVzdElkLCB3aGljaCB0aGV5XG4gICAgLy8gb25seSBnZXQgYnkgZXhwbGljaXRseSBsb29raW5nIHVwIHJlcXVlc3RzIGZvciBhIHNwZWNpZmljIElQLlxuICAgIGFzeW5jIGdyYW50QWNjZXNzKHJlcXVlc3RJZDogc3RyaW5nKTogUHJvbWlzZTxUcnVzdFJlY29yZD4ge1xuICAgICAgICAvLyBNdXN0IGNhcHR1cmUgaW4gdGhlIHN5bmNocm9ub3VzIHBoYXNlIOKAlCBTb2NrZXRGdW5jdGlvbi5nZXRDYWxsZXIoKSBvbmx5IHdvcmtzIGJlZm9yZSBhbnkgYXdhaXQuXG4gICAgICAgIGxldCBjYWxsZXJNYWNoaW5lSWQgPSBnZXRDYWxsZXJNYWNoaW5lSWQoKTtcbiAgICAgICAgbGV0IHRydXN0ID0gYXdhaXQgZ2V0VHJ1c3QoKTtcbiAgICAgICAgbGV0IHJlcXVlc3RzID0gYXdhaXQgZ2V0UmVxdWVzdHMoKTtcbiAgICAgICAgZm9yIChsZXQgaXAgb2YgYXdhaXQgcmVxdWVzdHMuZ2V0S2V5cygpKSB7XG4gICAgICAgICAgICBmb3IgKGxldCByZXF1ZXN0IG9mIGF3YWl0IHJlcXVlc3RzLmdldChpcCkgfHwgW10pIHtcbiAgICAgICAgICAgICAgICBpZiAocmVxdWVzdC5yZXF1ZXN0SWQgIT09IHJlcXVlc3RJZCkgY29udGludWU7XG4gICAgICAgICAgICAgICAgaWYgKCFpc0FkbWluKGNhbGxlck1hY2hpbmVJZCkgJiYgIWF3YWl0IHRydXN0LmdldChgJHtyZXF1ZXN0LmFjY291bnR9fCR7Y2FsbGVyTWFjaGluZUlkfWApKSB7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgJHtTVE9SQUdFX0FDQ0VTU19ERU5JRUR9IE1hY2hpbmUgJHtjYWxsZXJNYWNoaW5lSWR9IGhhcyBubyBhY2Nlc3MgdG8gYWNjb3VudCAke0pTT04uc3RyaW5naWZ5KHJlcXVlc3QuYWNjb3VudCl9YCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGxldCByZWNvcmQ6IFRydXN0UmVjb3JkID0ge1xuICAgICAgICAgICAgICAgICAgICBhY2NvdW50OiByZXF1ZXN0LmFjY291bnQsXG4gICAgICAgICAgICAgICAgICAgIG1hY2hpbmVJZDogcmVxdWVzdC5tYWNoaW5lSWQsXG4gICAgICAgICAgICAgICAgICAgIGlwOiByZXF1ZXN0LmlwLFxuICAgICAgICAgICAgICAgICAgICB0aW1lOiBEYXRlLm5vdygpLFxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgYXdhaXQgdHJ1c3Quc2V0KGAke3JlcXVlc3QuYWNjb3VudH18JHtyZXF1ZXN0Lm1hY2hpbmVJZH1gLCByZWNvcmQpO1xuICAgICAgICAgICAgICAgIHJldHVybiByZWNvcmQ7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBObyBhY2Nlc3MgcmVxdWVzdCBmb3VuZCB3aXRoIGlkICR7SlNPTi5zdHJpbmdpZnkocmVxdWVzdElkKX0uIEl0IG1heSBoYXZlIGFscmVhZHkgYmVlbiBncmFudGVkIG9yIGV4cGlyZWQuYCk7XG4gICAgfVxuXG4gICAgLy8gQWRtaW4gKG11c3QgYmUgcnVuIGZyb20gdGhlIHN0b3JhZ2UgbWFjaGluZSBpdHNlbGYsIHdoaWNoIHNoYXJlcyB0aGUgc2VydmVyJ3MgbWFjaGluZUlkKS5cbiAgICAvLyBPbmx5IHJldHVybnMgcmVxdWVzdHMgZm9yIHRoZSBnaXZlbiBJUCwgc28geW91IGNhbm5vdCBhY2NpZGVudGFsbHkgZ3JhbnQgYSByZXF1ZXN0IGZyb20gYW5cbiAgICAvLyBJUCB5b3UgZGlkbid0IGV4cGxpY2l0bHkgdHlwZSBpbi5cbiAgICBhc3luYyBhZG1pbkxpc3RSZXF1ZXN0cyhpcDogc3RyaW5nKTogUHJvbWlzZTxBY2Nlc3NSZXF1ZXN0W10+IHtcbiAgICAgICAgbGV0IHJlcXVlc3RzID0gYXdhaXQgZ2V0UmVxdWVzdHMoKTtcbiAgICAgICAgcmV0dXJuIGF3YWl0IHJlcXVlc3RzLmdldChpcCkgfHwgW107XG4gICAgfVxuICAgIGFzeW5jIGFkbWluR3JhbnRBY2Nlc3MocmVxdWVzdElkOiBzdHJpbmcpOiBQcm9taXNlPFRydXN0UmVjb3JkPiB7XG4gICAgICAgIGxldCB0cnVzdCA9IGF3YWl0IGdldFRydXN0KCk7XG4gICAgICAgIGxldCByZXF1ZXN0cyA9IGF3YWl0IGdldFJlcXVlc3RzKCk7XG4gICAgICAgIGZvciAobGV0IGlwIG9mIGF3YWl0IHJlcXVlc3RzLmdldEtleXMoKSkge1xuICAgICAgICAgICAgZm9yIChsZXQgcmVxdWVzdCBvZiBhd2FpdCByZXF1ZXN0cy5nZXQoaXApIHx8IFtdKSB7XG4gICAgICAgICAgICAgICAgaWYgKHJlcXVlc3QucmVxdWVzdElkICE9PSByZXF1ZXN0SWQpIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgIGxldCByZWNvcmQ6IFRydXN0UmVjb3JkID0ge1xuICAgICAgICAgICAgICAgICAgICBhY2NvdW50OiByZXF1ZXN0LmFjY291bnQsXG4gICAgICAgICAgICAgICAgICAgIG1hY2hpbmVJZDogcmVxdWVzdC5tYWNoaW5lSWQsXG4gICAgICAgICAgICAgICAgICAgIGlwOiByZXF1ZXN0LmlwLFxuICAgICAgICAgICAgICAgICAgICB0aW1lOiBEYXRlLm5vdygpLFxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgYXdhaXQgdHJ1c3Quc2V0KGAke3JlcXVlc3QuYWNjb3VudH18JHtyZXF1ZXN0Lm1hY2hpbmVJZH1gLCByZWNvcmQpO1xuICAgICAgICAgICAgICAgIHJldHVybiByZWNvcmQ7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBObyBhY2Nlc3MgcmVxdWVzdCBmb3VuZCB3aXRoIGlkICR7SlNPTi5zdHJpbmdpZnkocmVxdWVzdElkKX0uIEl0IG1heSBoYXZlIGFscmVhZHkgYmVlbiBncmFudGVkIG9yIGV4cGlyZWQuYCk7XG4gICAgfVxuXG4gICAgYXN5bmMgZ2V0KGFjY291bnQ6IHN0cmluZywgYnVja2V0TmFtZTogc3RyaW5nLCBwYXRoOiBzdHJpbmcsIHJhbmdlPzogeyBzdGFydDogbnVtYmVyOyBlbmQ6IG51bWJlciB9KTogUHJvbWlzZTxCdWZmZXIgfCB1bmRlZmluZWQ+IHtcbiAgICAgICAgbGV0IHJlc3VsdCA9IGF3YWl0IHRoaXMuZ2V0MihhY2NvdW50LCBidWNrZXROYW1lLCBwYXRoLCByYW5nZSk7XG4gICAgICAgIHJldHVybiByZXN1bHQgJiYgcmVzdWx0LmRhdGEgfHwgdW5kZWZpbmVkO1xuICAgIH1cbiAgICBhc3luYyBnZXQyKGFjY291bnQ6IHN0cmluZywgYnVja2V0TmFtZTogc3RyaW5nLCBwYXRoOiBzdHJpbmcsIHJhbmdlPzogeyBzdGFydDogbnVtYmVyOyBlbmQ6IG51bWJlciB9KTogUHJvbWlzZTx7IGRhdGE6IEJ1ZmZlcjsgd3JpdGVUaW1lOiBudW1iZXI7IHNpemU6IG51bWJlciB9IHwgdW5kZWZpbmVkPiB7XG4gICAgICAgIGFzc2VydFZhbGlkUGF0aChwYXRoKTtcbiAgICAgICAgbGV0IGJ1Y2tldCA9IGF3YWl0IGdldEJ1Y2tldChhY2NvdW50LCBidWNrZXROYW1lKTtcbiAgICAgICAgaWYgKCFidWNrZXQpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIHJldHVybiBhd2FpdCBidWNrZXQuc3RvcmUuZ2V0MihwYXRoLCB7IHJhbmdlIH0pO1xuICAgIH1cbiAgICBhc3luYyBzZXQoYWNjb3VudDogc3RyaW5nLCBidWNrZXROYW1lOiBzdHJpbmcsIHBhdGg6IHN0cmluZywgZGF0YTogQnVmZmVyLCBsYXN0TW9kaWZpZWQ/OiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgYXNzZXJ0VmFsaWROYW1lKGJ1Y2tldE5hbWUsIFwiYnVja2V0IG5hbWVcIik7XG4gICAgICAgIGFzc2VydFZhbGlkUGF0aChwYXRoKTtcbiAgICAgICAgLy8gSGFuZGxlcyBidWNrZXQgY3JlYXRpb24gKHdyaXRlcyBvZiBST1VUSU5HX0ZJTEUpLCByZWNvbmZpZ3VyYXRpb24sIGZhc3QgbW9kZSwgYW5kXG4gICAgICAgIC8vIGltbXV0YWJpbGl0eSDigJQgc2VlIHN0b3JhZ2VTZXJ2ZXJTdGF0ZS50c1xuICAgICAgICBhd2FpdCB3cml0ZUJ1Y2tldEZpbGUoYWNjb3VudCwgYnVja2V0TmFtZSwgcGF0aCwgQnVmZmVyLmZyb20oZGF0YSksIHsgbGFzdE1vZGlmaWVkIH0pO1xuICAgIH1cbiAgICBhc3luYyBkZWwoYWNjb3VudDogc3RyaW5nLCBidWNrZXROYW1lOiBzdHJpbmcsIHBhdGg6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhc3NlcnRWYWxpZE5hbWUoYnVja2V0TmFtZSwgXCJidWNrZXQgbmFtZVwiKTtcbiAgICAgICAgYXNzZXJ0VmFsaWRQYXRoKHBhdGgpO1xuICAgICAgICBhd2FpdCBkZWxldGVCdWNrZXRGaWxlKGFjY291bnQsIGJ1Y2tldE5hbWUsIHBhdGgpO1xuICAgIH1cbiAgICBhc3luYyBnZXRJbmZvKGFjY291bnQ6IHN0cmluZywgYnVja2V0TmFtZTogc3RyaW5nLCBwYXRoOiBzdHJpbmcpOiBQcm9taXNlPHsgd3JpdGVUaW1lOiBudW1iZXI7IHNpemU6IG51bWJlciB9IHwgdW5kZWZpbmVkPiB7XG4gICAgICAgIGFzc2VydFZhbGlkUGF0aChwYXRoKTtcbiAgICAgICAgbGV0IGJ1Y2tldCA9IGF3YWl0IGdldEJ1Y2tldChhY2NvdW50LCBidWNrZXROYW1lKTtcbiAgICAgICAgaWYgKCFidWNrZXQpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIHJldHVybiBhd2FpdCBidWNrZXQuc3RvcmUuZ2V0SW5mbyhwYXRoKTtcbiAgICB9XG4gICAgYXN5bmMgZmluZEluZm8oYWNjb3VudDogc3RyaW5nLCBidWNrZXROYW1lOiBzdHJpbmcsIHByZWZpeDogc3RyaW5nLCBjb25maWc/OiB7IHNoYWxsb3c/OiBib29sZWFuOyB0eXBlPzogXCJmaWxlc1wiIHwgXCJmb2xkZXJzXCIgfSk6IFByb21pc2U8QXJjaGl2ZUZpbGVJbmZvW10+IHtcbiAgICAgICAgbGV0IGJ1Y2tldCA9IGF3YWl0IGdldEJ1Y2tldChhY2NvdW50LCBidWNrZXROYW1lKTtcbiAgICAgICAgaWYgKCFidWNrZXQpIHJldHVybiBbXTtcbiAgICAgICAgcmV0dXJuIGF3YWl0IGJ1Y2tldC5zdG9yZS5maW5kSW5mbyhwcmVmaXgsIGNvbmZpZyk7XG4gICAgfVxuICAgIC8vIEZhc3QgKHNlcnZlZCBmcm9tIHRoZSBzdG9yZSdzIEJ1bGtEYXRhYmFzZTIgaW5kZXgsIG5vdCBhIHNjYW4pIOKAlCBzZWUgSUFyY2hpdmVzLmdldENoYW5nZXNBZnRlclxuICAgIGFzeW5jIGdldENoYW5nZXNBZnRlcihhY2NvdW50OiBzdHJpbmcsIGJ1Y2tldE5hbWU6IHN0cmluZywgdGltZTogbnVtYmVyKTogUHJvbWlzZTxBcmNoaXZlRmlsZUluZm9bXT4ge1xuICAgICAgICBsZXQgYnVja2V0ID0gYXdhaXQgZ2V0QnVja2V0KGFjY291bnQsIGJ1Y2tldE5hbWUpO1xuICAgICAgICBpZiAoIWJ1Y2tldCkgcmV0dXJuIFtdO1xuICAgICAgICBpZiAoIWJ1Y2tldC5zdG9yZS5nZXRDaGFuZ2VzQWZ0ZXIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgQnVja2V0ICR7YWNjb3VudH0vJHtidWNrZXROYW1lfSBkb2VzIG5vdCBzdXBwb3J0IGdldENoYW5nZXNBZnRlciAocmF3RGlzayBidWNrZXRzIGhhdmUgbm8gaW5kZXgpYCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGF3YWl0IGJ1Y2tldC5zdG9yZS5nZXRDaGFuZ2VzQWZ0ZXIodGltZSk7XG4gICAgfVxuICAgIGFzeW5jIGdldEFyY2hpdmVzQ29uZmlnKGFjY291bnQ6IHN0cmluZywgYnVja2V0TmFtZTogc3RyaW5nKTogUHJvbWlzZTxBcmNoaXZlc0NvbmZpZz4ge1xuICAgICAgICBsZXQgYnVja2V0ID0gYXdhaXQgZ2V0QnVja2V0KGFjY291bnQsIGJ1Y2tldE5hbWUpO1xuICAgICAgICAvLyBNaXNzaW5nIGJ1Y2tldHMgc2F5IHRydWUsIG1hdGNoaW5nIHdoYXQgdGhleSBiZWNvbWUgb25jZSBjcmVhdGVkICh0aGUgZGVmYXVsdCBzdG9yZSB0eXBlKVxuICAgICAgICBsZXQgcHJvZ3Jlc3MgPSBidWNrZXQ/LnN0b3JlLmdldFN5bmNQcm9ncmVzcz8uKCk7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzdXBwb3J0c0NoYW5nZXNBZnRlcjogIWJ1Y2tldCB8fCAhIWJ1Y2tldC5zdG9yZS5nZXRDaGFuZ2VzQWZ0ZXIsXG4gICAgICAgICAgICByZW1vdGVDb25maWc6IGJ1Y2tldD8ucm91dGluZyxcbiAgICAgICAgICAgIGluZGV4OiBwcm9ncmVzcz8uaW5kZXgsXG4gICAgICAgICAgICBpbmRleFNvdXJjZXM6IHByb2dyZXNzPy5zb3VyY2VzLFxuICAgICAgICAgICAgcmVhZGVyRGlza0xpbWl0OiBwcm9ncmVzcz8ucmVhZGVyRGlza0xpbWl0LFxuICAgICAgICAgICAgc3luY2luZzogcHJvZ3Jlc3M/LnN5bmNpbmcsXG4gICAgICAgIH07XG4gICAgfVxuICAgIC8qKiBXYWxrcyB0aGUgd2hvbGUgaW5kZXggZm9yIGV4YWN0IHRvdGFscyAob3ZlcmFsbCBhbmQgcGVyIGhvbGRpbmcgc291cmNlKSAtIG1vcmUgZXhwZW5zaXZlXG4gICAgICogIHRoYW4gdGhlIG1haW50YWluZWQgY291bnRlcnMgdGhhdCBnZXRBcmNoaXZlc0NvbmZpZyByZXR1cm5zLCBidXQgaW1tdW5lIHRvIGNvdW50ZXIgZHJpZnQuICovXG4gICAgYXN5bmMgZ2V0SW5kZXhJbmZvKGFjY291bnQ6IHN0cmluZywgYnVja2V0TmFtZTogc3RyaW5nKTogUHJvbWlzZTx7IGZpbGVDb3VudDogbnVtYmVyOyBieXRlQ291bnQ6IG51bWJlcjsgc291cmNlczogeyBkZWJ1Z05hbWU6IHN0cmluZzsgZmlsZUNvdW50OiBudW1iZXI7IGJ5dGVDb3VudDogbnVtYmVyIH1bXSB9IHwgdW5kZWZpbmVkPiB7XG4gICAgICAgIGxldCBidWNrZXQgPSBhd2FpdCBnZXRCdWNrZXQoYWNjb3VudCwgYnVja2V0TmFtZSk7XG4gICAgICAgIGlmICghYnVja2V0IHx8ICFidWNrZXQuc3RvcmUuY29tcHV0ZUluZGV4VG90YWxzKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICByZXR1cm4gYXdhaXQgYnVja2V0LnN0b3JlLmNvbXB1dGVJbmRleFRvdGFscygpO1xuICAgIH1cbiAgICBhc3luYyBnZXRTeW5jU3RhdHVzKGFjY291bnQ6IHN0cmluZywgYnVja2V0TmFtZTogc3RyaW5nKTogUHJvbWlzZTxBcmNoaXZlc1N5bmNTdGF0dXM+IHtcbiAgICAgICAgbGV0IGJ1Y2tldCA9IGF3YWl0IGdldEJ1Y2tldChhY2NvdW50LCBidWNrZXROYW1lKTtcbiAgICAgICAgaWYgKCFidWNrZXQpIHJldHVybiB7IGFsbFNjYW5zQ29tcGxldGU6IHRydWUsIGluZGV4U2l6ZTogMCwgc291cmNlczogW10gfTtcbiAgICAgICAgaWYgKCFidWNrZXQuc3RvcmUuZ2V0U3luY1N0YXR1cykge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBCdWNrZXQgJHthY2NvdW50fS8ke2J1Y2tldE5hbWV9IGRvZXMgbm90IHN1cHBvcnQgZ2V0U3luY1N0YXR1cyAocmF3RGlzayBidWNrZXRzIGhhdmUgbm8gc3luY2hyb25pemF0aW9uKWApO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBhd2FpdCBidWNrZXQuc3RvcmUuZ2V0U3luY1N0YXR1cygpO1xuICAgIH1cblxuICAgIGFzeW5jIHN0YXJ0TGFyZ2VGaWxlKGFjY291bnQ6IHN0cmluZywgYnVja2V0TmFtZTogc3RyaW5nLCBwYXRoOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgICAgICBhc3NlcnRXcml0ZXNBbGxvd2VkKCk7XG4gICAgICAgIC8vIFZhbGlkYXRlcyBub3csIHNvIHRoZSB1cGxvYWQgZG9lc24ndCBmYWlsIGF0IHRoZSBlbmRcbiAgICAgICAgYXNzZXJ0VmFsaWRQYXRoKHBhdGgpO1xuICAgICAgICBsZXQgYnVja2V0ID0gYXdhaXQgZ2V0QnVja2V0KGFjY291bnQsIGJ1Y2tldE5hbWUpO1xuICAgICAgICBpZiAoIWJ1Y2tldCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBCdWNrZXQgJHthY2NvdW50fS8ke2J1Y2tldE5hbWV9IGRvZXMgbm90IGV4aXN0LiBXcml0ZSBpdHMgcm91dGluZyBjb25maWcgdG8gJHtKU09OLnN0cmluZ2lmeShST1VUSU5HX0ZJTEUpfSB0byBjcmVhdGUgaXQuYCk7XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgYXNzZXJ0TXV0YWJsZShidWNrZXQsIHBhdGgsIERhdGUubm93KCkpO1xuICAgICAgICBsZXQgaWQgPSBhd2FpdCBidWNrZXQuc3RvcmUuc3RhcnRMYXJnZVVwbG9hZCgpO1xuICAgICAgICBsYXJnZVVwbG9hZEluZm8uc2V0KGlkLCB7IGFjY291bnQsIGJ1Y2tldE5hbWUsIHBhdGggfSk7XG4gICAgICAgIHJldHVybiBpZDtcbiAgICB9XG4gICAgYXN5bmMgdXBsb2FkUGFydCh1cGxvYWRJZDogc3RyaW5nLCBkYXRhOiBCdWZmZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgYXNzZXJ0V3JpdGVzQWxsb3dlZCgpO1xuICAgICAgICBsZXQgaW5mbyA9IGxhcmdlVXBsb2FkSW5mby5nZXQodXBsb2FkSWQpO1xuICAgICAgICBpZiAoIWluZm8pIHRocm93IG5ldyBFcnJvcihgVW5rbm93biBsYXJnZSB1cGxvYWQgJHt1cGxvYWRJZH1gKTtcbiAgICAgICAgbGV0IGJ1Y2tldCA9IGF3YWl0IGdldEJ1Y2tldChpbmZvLmFjY291bnQsIGluZm8uYnVja2V0TmFtZSk7XG4gICAgICAgIGlmICghYnVja2V0KSB0aHJvdyBuZXcgRXJyb3IoYEJ1Y2tldCAke2luZm8uYWNjb3VudH0vJHtpbmZvLmJ1Y2tldE5hbWV9IG5vIGxvbmdlciBleGlzdHNgKTtcbiAgICAgICAgYXdhaXQgYnVja2V0LnN0b3JlLmFwcGVuZExhcmdlVXBsb2FkKHVwbG9hZElkLCBCdWZmZXIuZnJvbShkYXRhKSk7XG4gICAgfVxuICAgIGFzeW5jIGZpbmlzaExhcmdlRmlsZSh1cGxvYWRJZDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGFzc2VydFdyaXRlc0FsbG93ZWQoKTtcbiAgICAgICAgbGV0IGluZm8gPSBsYXJnZVVwbG9hZEluZm8uZ2V0KHVwbG9hZElkKTtcbiAgICAgICAgaWYgKCFpbmZvKSB0aHJvdyBuZXcgRXJyb3IoYFVua25vd24gbGFyZ2UgdXBsb2FkICR7dXBsb2FkSWR9YCk7XG4gICAgICAgIGxhcmdlVXBsb2FkSW5mby5kZWxldGUodXBsb2FkSWQpO1xuICAgICAgICBsZXQgYnVja2V0ID0gYXdhaXQgZ2V0QnVja2V0KGluZm8uYWNjb3VudCwgaW5mby5idWNrZXROYW1lKTtcbiAgICAgICAgaWYgKCFidWNrZXQpIHRocm93IG5ldyBFcnJvcihgQnVja2V0ICR7aW5mby5hY2NvdW50fS8ke2luZm8uYnVja2V0TmFtZX0gbm8gbG9uZ2VyIGV4aXN0c2ApO1xuICAgICAgICBhd2FpdCBidWNrZXQuc3RvcmUuZmluaXNoTGFyZ2VVcGxvYWQodXBsb2FkSWQsIGluZm8ucGF0aCk7XG4gICAgfVxuICAgIGFzeW5jIGNhbmNlbExhcmdlRmlsZSh1cGxvYWRJZDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGxldCBpbmZvID0gbGFyZ2VVcGxvYWRJbmZvLmdldCh1cGxvYWRJZCk7XG4gICAgICAgIGlmICghaW5mbykgcmV0dXJuO1xuICAgICAgICBsYXJnZVVwbG9hZEluZm8uZGVsZXRlKHVwbG9hZElkKTtcbiAgICAgICAgbGV0IGJ1Y2tldCA9IGF3YWl0IGdldEJ1Y2tldChpbmZvLmFjY291bnQsIGluZm8uYnVja2V0TmFtZSk7XG4gICAgICAgIGlmICghYnVja2V0KSByZXR1cm47XG4gICAgICAgIGF3YWl0IGJ1Y2tldC5zdG9yZS5jYW5jZWxMYXJnZVVwbG9hZCh1cGxvYWRJZCk7XG4gICAgfVxuXG4gICAgLy8gVGhlIHNlcnZlcidzIHNpbmdsZSBkZWZhdWx0IEhUVFAgcm91dGUuIC9maWxlLzxhY2NvdW50Pi88YnVja2V0TmFtZT4vPHBhdGg+IHNlcnZlcyBmaWxlcyBmcm9tXG4gICAgLy8gcHVibGljIGJ1Y2tldHMgb3ZlciBwbGFpbiBHRVRzIChzZWUgSUFyY2hpdmVzLmdldFVSTCk7IGV2ZXJ5IG90aGVyIHBhdGggc2VydmVzIHRoZSBhY2Nlc3NcbiAgICAvLyBwYWdlICh2aWEgUmVxdWlyZUNvbnRyb2xsZXIucmVxdWlyZUhUTUwg4oCUIHRoZSBwYXRoIGlzIHRoZSBhY2NvdW50IG5hbWUsIHNlZSBhY2Nlc3NQYWdlLnRzeCkuXG4gICAgYXN5bmMgaHR0cEVudHJ5KGNvbmZpZz86IHsgcmVxdWlyZUNhbGxzPzogc3RyaW5nW107IGNhY2hlVGltZT86IG51bWJlciB9KTogUHJvbWlzZTxCdWZmZXI+IHtcbiAgICAgICAgLy8gQm90aCBhcmUga2V5ZWQgYnkgdGhlIGN1cnJlbnQgY2FsbCBhbmQgbXVzdCBiZSBjYXB0dXJlZCBzeW5jaHJvbm91c2x5LCBiZWZvcmUgYW55IGF3YWl0XG4gICAgICAgIGxldCBjYWxsZXIgPSBTb2NrZXRGdW5jdGlvbi5nZXRDYWxsZXIoKTtcbiAgICAgICAgbGV0IHJlcXVlc3QgPSBnZXRDdXJyZW50SFRUUFJlcXVlc3QoKTtcbiAgICAgICAgbGV0IHBhdGhuYW1lID0gbmV3IFVSTChyZXF1ZXN0Py51cmwgfHwgXCIvXCIsIFwiaHR0cHM6Ly9sb2NhbGhvc3RcIikucGF0aG5hbWU7XG4gICAgICAgIGlmICghcGF0aG5hbWUuc3RhcnRzV2l0aChcIi9maWxlL1wiKSkge1xuICAgICAgICAgICAgcmV0dXJuIGF3YWl0IHBlcmZvcm1Mb2NhbENhbGwoe1xuICAgICAgICAgICAgICAgIGNhbGxlcixcbiAgICAgICAgICAgICAgICBjYWxsOiB7IG5vZGVJZDogY2FsbGVyLm5vZGVJZCwgY2xhc3NHdWlkOiBSZXF1aXJlQ29udHJvbGxlci5fY2xhc3NHdWlkLCBmdW5jdGlvbk5hbWU6IFwicmVxdWlyZUhUTUxcIiwgYXJnczogW2NvbmZpZ10gfSxcbiAgICAgICAgICAgIH0pIGFzIEJ1ZmZlcjtcbiAgICAgICAgfVxuICAgICAgICBsZXQgcGFydHMgPSBwYXRobmFtZS5zcGxpdChcIi9cIikuZmlsdGVyKHggPT4geCkubWFwKGRlY29kZVVSSUNvbXBvbmVudCk7XG4gICAgICAgIGxldCBhY2NvdW50ID0gcGFydHNbMV07XG4gICAgICAgIGxldCBidWNrZXROYW1lID0gcGFydHNbMl07XG4gICAgICAgIGxldCBmaWxlUGF0aCA9IHBhcnRzLnNsaWNlKDMpLmpvaW4oXCIvXCIpO1xuICAgICAgICBpZiAoIWFjY291bnQgfHwgIWJ1Y2tldE5hbWUgfHwgIWZpbGVQYXRoKSB7XG4gICAgICAgICAgICByZXR1cm4gc2V0SFRUUFJlc3VsdEhlYWRlcnMoQnVmZmVyLmZyb20oXCJcIiksIHsgc3RhdHVzOiBcIjQwNFwiIH0pO1xuICAgICAgICB9XG4gICAgICAgIGFzc2VydFZhbGlkTmFtZShhY2NvdW50LCBcImFjY291bnRcIik7XG4gICAgICAgIGFzc2VydFZhbGlkTmFtZShidWNrZXROYW1lLCBcImJ1Y2tldCBuYW1lXCIpO1xuICAgICAgICBhc3NlcnRWYWxpZFBhdGgoZmlsZVBhdGgpO1xuICAgICAgICBsZXQgYnVja2V0ID0gYXdhaXQgZ2V0TG9hZGVkQnVja2V0KGFjY291bnQsIGJ1Y2tldE5hbWUpO1xuICAgICAgICBpZiAoIWJ1Y2tldCkge1xuICAgICAgICAgICAgcmV0dXJuIHNldEhUVFBSZXN1bHRIZWFkZXJzKEJ1ZmZlci5mcm9tKFwiXCIpLCB7IHN0YXR1czogXCI0MDRcIiB9KTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIWJ1Y2tldC5zZWxmPy5wdWJsaWMpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgQnVja2V0ICR7YWNjb3VudH0vJHtidWNrZXROYW1lfSBpcyBub3QgcHVibGljLCBzbyBpdHMgZmlsZXMgY2Fubm90IGJlIHJlYWQgb3ZlciBwbGFpbiBVUkxzYCk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gVGhlIGluZGV4IGFuc3dlcnMgZXhpc3RlbmNlICsgd3JpdGUgdGltZSArIHNpemUgd2l0aG91dCB0b3VjaGluZyBhbnkgZGF0YSwgc29cbiAgICAgICAgLy8gSWYtTW9kaWZpZWQtU2luY2UgYW5kIHJhbmdlIHZhbGlkYXRpb24gY29zdCBub3RoaW5nXG4gICAgICAgIGxldCBpbmZvID0gYXdhaXQgYnVja2V0LnN0b3JlLmdldEluZm8oZmlsZVBhdGgpO1xuICAgICAgICBpZiAoIWluZm8gfHwgIWluZm8uc2l6ZSkge1xuICAgICAgICAgICAgcmV0dXJuIHNldEhUVFBSZXN1bHRIZWFkZXJzKEJ1ZmZlci5mcm9tKFwiXCIpLCB7IHN0YXR1czogXCI0MDRcIiB9KTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgZXh0ID0gZmlsZVBhdGguc3BsaXQoXCIuXCIpLnBvcCgpIHx8IFwiXCI7XG4gICAgICAgIGxldCBoZWFkZXJzOiB7IFtoZWFkZXI6IHN0cmluZ106IHN0cmluZyB9ID0ge1xuICAgICAgICAgICAgXCJDb250ZW50LVR5cGVcIjogQ09OVEVOVF9UWVBFU1tleHQudG9Mb3dlckNhc2UoKV0gfHwgXCJhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW1cIixcbiAgICAgICAgICAgIFwiTGFzdC1Nb2RpZmllZFwiOiBuZXcgRGF0ZShpbmZvLndyaXRlVGltZSkudG9VVENTdHJpbmcoKSxcbiAgICAgICAgICAgIFwiQWNjZXB0LVJhbmdlc1wiOiBcImJ5dGVzXCIsXG4gICAgICAgIH07XG4gICAgICAgIGlmIChidWNrZXQuc2VsZj8uaW1tdXRhYmxlKSB7XG4gICAgICAgICAgICBoZWFkZXJzW1wiQ2FjaGUtQ29udHJvbFwiXSA9IGBtYXgtYWdlPSR7SU1NVVRBQkxFX0NBQ0hFX1RJTUUgLyAxMDAwfWA7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IGlmTW9kaWZpZWRTaW5jZSA9IHJlcXVlc3Q/LmhlYWRlcnNbXCJpZi1tb2RpZmllZC1zaW5jZVwiXTtcbiAgICAgICAgaWYgKHR5cGVvZiBpZk1vZGlmaWVkU2luY2UgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgICAgIGxldCBzaW5jZSA9IG5ldyBEYXRlKGlmTW9kaWZpZWRTaW5jZSkuZ2V0VGltZSgpO1xuICAgICAgICAgICAgLy8gTGFzdC1Nb2RpZmllZCBpcyBzZXJ2ZWQgYXQgMSBzZWNvbmQgcmVzb2x1dGlvbiwgc28gY29tcGFyZSBhdCB0aGF0IHJlc29sdXRpb25cbiAgICAgICAgICAgIGlmIChzaW5jZSAmJiBNYXRoLmZsb29yKGluZm8ud3JpdGVUaW1lIC8gMTAwMCkgKiAxMDAwIDw9IHNpbmNlKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHNldEhUVFBSZXN1bHRIZWFkZXJzKEJ1ZmZlci5mcm9tKFwiXCIpLCB7IC4uLmhlYWRlcnMsIHN0YXR1czogXCIzMDRcIiB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBsZXQgcmFuZ2U6IHsgc3RhcnQ6IG51bWJlcjsgZW5kOiBudW1iZXIgfSB8IHVuZGVmaW5lZDtcbiAgICAgICAgbGV0IHJhbmdlSGVhZGVyID0gcmVxdWVzdD8uaGVhZGVyc1tcInJhbmdlXCJdO1xuICAgICAgICBpZiAodHlwZW9mIHJhbmdlSGVhZGVyID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgICAvLyBTaW5nbGUtcmFuZ2UgZm9ybSBvbmx5IChieXRlcz1zdGFydC1lbmQgLyBzdGFydC0gLyAtc3VmZml4KTsgYW55dGhpbmcgZWxzZSBzZXJ2ZXMgdGhlIGZ1bGwgZmlsZVxuICAgICAgICAgICAgbGV0IG1hdGNoID0gL15ieXRlcz0oXFxkKiktKFxcZCopJC8uZXhlYyhyYW5nZUhlYWRlci50cmltKCkpO1xuICAgICAgICAgICAgaWYgKG1hdGNoICYmIChtYXRjaFsxXSB8fCBtYXRjaFsyXSkpIHtcbiAgICAgICAgICAgICAgICBsZXQgc3RhcnQ6IG51bWJlcjtcbiAgICAgICAgICAgICAgICBsZXQgZW5kSW5jbHVzaXZlID0gaW5mby5zaXplIC0gMTtcbiAgICAgICAgICAgICAgICBpZiAoIW1hdGNoWzFdKSB7XG4gICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gTWF0aC5tYXgoMCwgaW5mby5zaXplIC0gK21hdGNoWzJdKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBzdGFydCA9ICttYXRjaFsxXTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKG1hdGNoWzJdKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBlbmRJbmNsdXNpdmUgPSBNYXRoLm1pbigrbWF0Y2hbMl0sIGluZm8uc2l6ZSAtIDEpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChzdGFydCA+PSBpbmZvLnNpemUgfHwgc3RhcnQgPiBlbmRJbmNsdXNpdmUpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHNldEhUVFBSZXN1bHRIZWFkZXJzKEJ1ZmZlci5mcm9tKFwiXCIpLCB7IC4uLmhlYWRlcnMsIFwiQ29udGVudC1SYW5nZVwiOiBgYnl0ZXMgKi8ke2luZm8uc2l6ZX1gLCBzdGF0dXM6IFwiNDE2XCIgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJhbmdlID0geyBzdGFydCwgZW5kOiBlbmRJbmNsdXNpdmUgKyAxIH07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgbGV0IHJlc3VsdCA9IGF3YWl0IGJ1Y2tldC5zdG9yZS5nZXQyKGZpbGVQYXRoLCB7IHJhbmdlIH0pO1xuICAgICAgICBpZiAoIXJlc3VsdCkge1xuICAgICAgICAgICAgcmV0dXJuIHNldEhUVFBSZXN1bHRIZWFkZXJzKEJ1ZmZlci5mcm9tKFwiXCIpLCB7IHN0YXR1czogXCI0MDRcIiB9KTtcbiAgICAgICAgfVxuICAgICAgICBpZiAocmFuZ2UpIHtcbiAgICAgICAgICAgIHJldHVybiBzZXRIVFRQUmVzdWx0SGVhZGVycyhyZXN1bHQuZGF0YSwgeyAuLi5oZWFkZXJzLCBcIkNvbnRlbnQtUmFuZ2VcIjogYGJ5dGVzICR7cmFuZ2Uuc3RhcnR9LSR7cmFuZ2UuZW5kIC0gMX0vJHtpbmZvLnNpemV9YCwgc3RhdHVzOiBcIjIwNlwiIH0pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBzZXRIVFRQUmVzdWx0SGVhZGVycyhyZXN1bHQuZGF0YSwgaGVhZGVycyk7XG4gICAgfVxufVxuXG5jb25zdCBsYXJnZVVwbG9hZEluZm8gPSBuZXcgTWFwPHN0cmluZywgeyBhY2NvdW50OiBzdHJpbmc7IGJ1Y2tldE5hbWU6IHN0cmluZzsgcGF0aDogc3RyaW5nIH0+KCk7XG5cbi8vIEFjY2VzcyBjaGVja3MgcnVuIGFzIGhvb2tzIG9uIHRoZSByZWdpc3RlciBzaGFwZSBiZWxvdywga2V5ZWQgb2ZmIHRoZSBjYWxsJ3MgYXJndW1lbnRzLCBzbyB0aGVcbi8vIG1ldGhvZCBib2RpZXMgZG9uJ3QgZWFjaCByZXBlYXQgdGhlbVxuY29uc3QgYWNjb3VudEFjY2VzczogU29ja2V0RnVuY3Rpb25Ib29rID0gYXN5bmMgKGNvbnRleHQpID0+IHtcbiAgICBhd2FpdCByZXF1aXJlQWNjZXNzKFN0cmluZyhjb250ZXh0LmNhbGwuYXJnc1swXSkpO1xufTtcbmNvbnN0IHVwbG9hZEFjY2VzczogU29ja2V0RnVuY3Rpb25Ib29rID0gYXN5bmMgKGNvbnRleHQpID0+IHtcbiAgICBsZXQgaW5mbyA9IGxhcmdlVXBsb2FkSW5mby5nZXQoU3RyaW5nKGNvbnRleHQuY2FsbC5hcmdzWzBdKSk7XG4gICAgLy8gVW5rbm93biB1cGxvYWQgaWRzIGFyZSBoYW5kbGVkIGJ5IHRoZSBtZXRob2RzIHRoZW1zZWx2ZXMgKHRocm93IC8gbm8tb3ApXG4gICAgaWYgKCFpbmZvKSByZXR1cm47XG4gICAgYXdhaXQgcmVxdWlyZUFjY2VzcyhpbmZvLmFjY291bnQpO1xufTtcbmNvbnN0IGFkbWluQWNjZXNzOiBTb2NrZXRGdW5jdGlvbkhvb2sgPSBhc3luYyAoKSA9PiB7XG4gICAgcmVxdWlyZUFkbWluKCk7XG59O1xuXG5leHBvcnQgY29uc3QgUmVtb3RlU3RvcmFnZUNvbnRyb2xsZXIgPSBTb2NrZXRGdW5jdGlvbi5yZWdpc3RlcihcbiAgICBSRU1PVEVfU1RPUkFHRV9DTEFTU19HVUlELFxuICAgIG5ldyBSZW1vdGVTdG9yYWdlQ29udHJvbGxlckJhc2UoKSxcbiAgICAoKSA9PiAoe1xuICAgICAgICBwaW5nOiB7fSxcbiAgICAgICAgYXV0aGVudGljYXRlOiB7fSxcbiAgICAgICAgcmVxdWVzdEFjY2Vzczoge30sXG4gICAgICAgIGdldEFjY2Vzc1N0YXRlOiB7fSxcbiAgICAgICAgbGlzdFJlcXVlc3RzRm9ySVA6IHsgaG9va3M6IFthY2NvdW50QWNjZXNzXSB9LFxuICAgICAgICBncmFudEFjY2Vzczoge30sXG4gICAgICAgIGFkbWluTGlzdFJlcXVlc3RzOiB7IGhvb2tzOiBbYWRtaW5BY2Nlc3NdIH0sXG4gICAgICAgIGFkbWluR3JhbnRBY2Nlc3M6IHsgaG9va3M6IFthZG1pbkFjY2Vzc10gfSxcbiAgICAgICAgZ2V0OiB7IGhvb2tzOiBbYWNjb3VudEFjY2Vzc10gfSxcbiAgICAgICAgZ2V0MjogeyBob29rczogW2FjY291bnRBY2Nlc3NdIH0sXG4gICAgICAgIHNldDogeyBob29rczogW2FjY291bnRBY2Nlc3NdIH0sXG4gICAgICAgIGRlbDogeyBob29rczogW2FjY291bnRBY2Nlc3NdIH0sXG4gICAgICAgIGdldEluZm86IHsgaG9va3M6IFthY2NvdW50QWNjZXNzXSB9LFxuICAgICAgICBmaW5kSW5mbzogeyBob29rczogW2FjY291bnRBY2Nlc3NdIH0sXG4gICAgICAgIGdldENoYW5nZXNBZnRlcjogeyBob29rczogW2FjY291bnRBY2Nlc3NdIH0sXG4gICAgICAgIGdldEFyY2hpdmVzQ29uZmlnOiB7IGhvb2tzOiBbYWNjb3VudEFjY2Vzc10gfSxcbiAgICAgICAgZ2V0SW5kZXhJbmZvOiB7IGhvb2tzOiBbYWNjb3VudEFjY2Vzc10gfSxcbiAgICAgICAgZ2V0U3luY1N0YXR1czogeyBob29rczogW2FjY291bnRBY2Nlc3NdIH0sXG4gICAgICAgIHN0YXJ0TGFyZ2VGaWxlOiB7IGhvb2tzOiBbYWNjb3VudEFjY2Vzc10gfSxcbiAgICAgICAgdXBsb2FkUGFydDogeyBob29rczogW3VwbG9hZEFjY2Vzc10gfSxcbiAgICAgICAgZmluaXNoTGFyZ2VGaWxlOiB7IGhvb2tzOiBbdXBsb2FkQWNjZXNzXSB9LFxuICAgICAgICBjYW5jZWxMYXJnZUZpbGU6IHsgaG9va3M6IFt1cGxvYWRBY2Nlc3NdIH0sXG4gICAgICAgIGh0dHBFbnRyeToge30sXG4gICAgfSksXG4gICAgKCkgPT4gKHtcbiAgICAgICAgbm9DbGllbnRIb29rczogdHJ1ZSxcbiAgICAgICAgbm9EZWZhdWx0SG9va3M6IHRydWUsXG4gICAgfSlcbik7XG4iXX0=
500
+ /* _JS_SOURCE_HASH = "1f9c71eed3bbc12aa14eb6d02745131cca48eb4ea142276c2937d85ae7bf92db"; */