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.
- package/bin/storageserver.js +4 -0
- package/{teststorage → examplestorage}/browser.tsx +18 -22
- package/{teststorage/server.ts → examplestorage/exampleserver.ts} +4 -6
- package/index.d.ts +770 -84
- package/misc/dist/environment.ts.cache +3 -3
- package/misc/dist/getSecret.ts.cache +139 -0
- package/misc/dist/strings.ts.cache +13 -0
- package/misc/dist/zip.ts.cache +9 -0
- package/misc/getSecret.ts +38 -16
- package/misc/https/cloudflareHelpers.d.ts +19 -0
- package/misc/https/cloudflareHelpers.ts +69 -0
- package/misc/https/dist/certs.ts.cache +115 -179
- package/misc/https/dist/cloudflareHelpers.ts.cache +68 -0
- package/misc/https/dist/dns.ts.cache +112 -100
- package/misc/https/dist/hostServer.ts.cache +130 -0
- package/misc/https/dist/httpsCerts.ts.cache +24 -5
- package/misc/https/dist/persistentLocalStorage.ts.cache +3 -2
- package/misc/https/dns.d.ts +41 -8
- package/misc/https/dns.ts +104 -106
- package/misc/https/hostServer.d.ts +0 -3
- package/misc/https/hostServer.ts +12 -8
- package/package.json +3 -2
- package/render-utils/dist/observer.tsx.cache +3 -2
- package/spec.txt +0 -55
- package/storage/ArchivesDisk.d.ts +67 -0
- package/storage/ArchivesDisk.ts +369 -0
- package/storage/BulkDatabase2/dist/BulkDatabaseBase.ts.cache +1242 -0
- package/storage/BulkDatabase2/dist/BulkDatabaseFormat.ts.cache +513 -0
- package/storage/BulkDatabase2/dist/BulkDatabaseMerge.ts.cache +352 -0
- package/storage/BulkDatabase2/dist/BulkDatabaseReader.ts.cache +306 -0
- package/storage/BulkDatabase2/dist/LoadedIndex.ts.cache +435 -0
- package/storage/BulkDatabase2/dist/WriteOverlay.ts.cache +58 -0
- package/storage/BulkDatabase2/dist/blockCache.ts.cache +179 -0
- package/storage/BulkDatabase2/dist/mergeLock.ts.cache +149 -0
- package/storage/BulkDatabase2/dist/mergeMarkers.ts.cache +101 -0
- package/storage/BulkDatabase2/dist/streamLog.ts.cache +227 -0
- package/storage/BulkDatabase2/dist/syncClient.ts.cache +104 -0
- package/storage/IArchives.d.ts +127 -1
- package/storage/IArchives.ts +201 -1
- package/storage/backblaze.d.ts +29 -2
- package/storage/backblaze.ts +214 -78
- package/storage/dist/ArchivesDisk.ts.cache +373 -0
- package/storage/dist/FileFolderAPI.tsx.cache +508 -65
- package/storage/dist/IArchives.ts.cache +44 -0
- package/storage/dist/IndexedDBFileFolderAPI.ts.cache +8 -2
- package/storage/dist/JSONStorage.ts.cache +6 -2
- package/storage/dist/PendingManager.tsx.cache +1 -1
- package/storage/dist/TransactionStorage.ts.cache +231 -92
- package/storage/dist/backblaze.ts.cache +797 -0
- package/storage/dist/fileSystemPointer.ts.cache +36 -3
- package/storage/dist/remoteFileStorage.ts.cache +495 -0
- package/storage/remoteStorage/ArchivesRemote.d.ts +34 -18
- package/storage/remoteStorage/ArchivesRemote.ts +85 -65
- package/storage/remoteStorage/ArchivesUrl.d.ts +48 -0
- package/storage/remoteStorage/ArchivesUrl.ts +86 -0
- package/storage/remoteStorage/accessPage.tsx +111 -28
- package/storage/remoteStorage/blobStore.d.ts +128 -25
- package/storage/remoteStorage/blobStore.ts +757 -290
- package/storage/remoteStorage/cliArgs.d.ts +1 -0
- package/storage/remoteStorage/cliArgs.ts +9 -0
- package/storage/remoteStorage/createArchives.d.ts +85 -0
- package/storage/remoteStorage/createArchives.ts +612 -0
- package/storage/remoteStorage/dist/ArchivesRemote.ts.cache +197 -0
- package/storage/remoteStorage/dist/ArchivesUrl.ts.cache +85 -0
- package/storage/remoteStorage/dist/accessPage.tsx.cache +222 -0
- package/storage/remoteStorage/dist/blobStore.ts.cache +837 -0
- package/storage/remoteStorage/dist/cliArgs.ts.cache +16 -0
- package/storage/remoteStorage/dist/createArchives.ts.cache +610 -0
- package/storage/remoteStorage/dist/remoteConfig.ts.cache +206 -0
- package/storage/remoteStorage/dist/sourceWrapper.ts.cache +223 -0
- package/storage/remoteStorage/dist/storageController.ts.cache +500 -0
- package/storage/remoteStorage/dist/storageServer.ts.cache +106 -0
- package/storage/remoteStorage/dist/storageServerCli.ts.cache +39 -0
- package/storage/remoteStorage/dist/storageServerState.ts.cache +518 -0
- package/storage/remoteStorage/grantAccess.js +4 -0
- package/storage/remoteStorage/grantAccessCli.d.ts +1 -0
- package/storage/remoteStorage/grantAccessCli.ts +27 -0
- package/storage/remoteStorage/remoteConfig.d.ts +29 -0
- package/storage/remoteStorage/remoteConfig.ts +194 -0
- package/storage/remoteStorage/sourceWrapper.d.ts +41 -0
- package/storage/remoteStorage/sourceWrapper.ts +223 -0
- package/storage/remoteStorage/spec.md +31 -0
- package/storage/remoteStorage/storageController.d.ts +30 -27
- package/storage/remoteStorage/storageController.ts +297 -159
- package/storage/remoteStorage/storageServer.d.ts +6 -0
- package/storage/remoteStorage/storageServer.ts +88 -94
- package/storage/remoteStorage/storageServerCli.d.ts +1 -0
- package/storage/remoteStorage/storageServerCli.ts +38 -0
- package/storage/remoteStorage/storageServerState.d.ts +43 -0
- package/storage/remoteStorage/storageServerState.ts +540 -0
- package/testsite/server.ts +0 -2
- package/yarn.lock +11 -6
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
|
|
3
|
+
//exports.ArchivesRemote = exports.authenticateStorage = exports.parseStorageUrl = void 0;
|
|
4
|
+
module.allowclient = true;
|
|
5
|
+
const SocketFunction_1 = require("socket-function/SocketFunction");
|
|
6
|
+
const misc_1 = require("socket-function/src/misc");
|
|
7
|
+
const batching_1 = require("socket-function/src/batching");
|
|
8
|
+
const certs_1 = require("../../misc/https/certs");
|
|
9
|
+
const remoteConfig_1 = require("./remoteConfig");
|
|
10
|
+
const storageController_1 = require("./storageController");
|
|
11
|
+
// A bucket on our remote storage server (storageServer.ts), used like ArchivesBackblaze. Works in
|
|
12
|
+
// Node.js and the browser. Authenticates with this machine's certs.ts identity; if the account
|
|
13
|
+
// hasn't trusted this machine yet it requests access, and by default waits, logging instructions
|
|
14
|
+
// every minute (calls block until access is granted).
|
|
15
|
+
const ACCESS_RETRY_DELAY = 1000 * 30;
|
|
16
|
+
const LARGE_FILE_PART_SIZE = 8 * 1024 * 1024;
|
|
17
|
+
function parseStorageUrl(url) {
|
|
18
|
+
let u = new URL(url);
|
|
19
|
+
if (u.protocol !== "https:") {
|
|
20
|
+
throw new Error(`Storage URL must use https, got ${JSON.stringify(u.protocol)} in ${JSON.stringify(url)}`);
|
|
21
|
+
}
|
|
22
|
+
return { address: u.hostname, port: +u.port || 443 };
|
|
23
|
+
}
|
|
24
|
+
exports.parseStorageUrl = parseStorageUrl;
|
|
25
|
+
// Authenticates a connection to a storage server with this machine's certs.ts identity
|
|
26
|
+
async function authenticateStorage(config) {
|
|
27
|
+
// hostServer nodeIds are machine-specific, so connections by domain must target "any server
|
|
28
|
+
// at this address" (which is how browsers always connect)
|
|
29
|
+
SocketFunction_1.SocketFunction.ENABLE_CLIENT_MODE = true;
|
|
30
|
+
let rootDomain = config.address.split(".").slice(-2).join(".");
|
|
31
|
+
await (0, certs_1.loadIdentityCA)(rootDomain);
|
|
32
|
+
let ca = (0, certs_1.getIdentityCA)(rootDomain);
|
|
33
|
+
let time = Date.now();
|
|
34
|
+
let signature = (0, certs_1.sign)({ key: ca.key }, {
|
|
35
|
+
purpose: storageController_1.STORAGE_AUTH_PURPOSE,
|
|
36
|
+
time,
|
|
37
|
+
server: `${config.address}:${config.port}`,
|
|
38
|
+
});
|
|
39
|
+
return await storageController_1.RemoteStorageController.nodes[config.nodeId].authenticate({ certPem: ca.cert.toString(), time, signature });
|
|
40
|
+
}
|
|
41
|
+
exports.authenticateStorage = authenticateStorage;
|
|
42
|
+
class ArchivesRemote {
|
|
43
|
+
constructor(config) {
|
|
44
|
+
this.config = config;
|
|
45
|
+
this.parsed = (0, remoteConfig_1.parseHostedUrl)(this.config.url);
|
|
46
|
+
this.account = this.config.accountName || this.parsed.account;
|
|
47
|
+
this.bucketName = this.parsed.bucketName;
|
|
48
|
+
this.nodeId = SocketFunction_1.SocketFunction.connect({ address: this.parsed.address, port: this.parsed.port });
|
|
49
|
+
this.controller = storageController_1.RemoteStorageController.nodes[this.nodeId];
|
|
50
|
+
this.lastDeniedLog = 0;
|
|
51
|
+
// hostServer nodeIds are machine-specific, so connections by domain must target "any
|
|
52
|
+
// server at this address" (which is how browsers always connect)
|
|
53
|
+
SocketFunction_1.SocketFunction.ENABLE_CLIENT_MODE = true;
|
|
54
|
+
}
|
|
55
|
+
getDebugName() {
|
|
56
|
+
return `remoteStorage/${this.parsed.address}:${this.parsed.port}/${this.account}/${this.bucketName}`;
|
|
57
|
+
}
|
|
58
|
+
isConnected() {
|
|
59
|
+
return SocketFunction_1.SocketFunction.isNodeConnected(this.nodeId);
|
|
60
|
+
}
|
|
61
|
+
async ping() {
|
|
62
|
+
await this.controller.ping();
|
|
63
|
+
}
|
|
64
|
+
async authenticate() {
|
|
65
|
+
await authenticateStorage({ address: this.parsed.address, port: this.parsed.port, nodeId: this.nodeId });
|
|
66
|
+
}
|
|
67
|
+
// Runs a call, authenticating (and re-authenticating after reconnects) as needed. Unlike
|
|
68
|
+
// call(), does NOT wait for account access.
|
|
69
|
+
async callAuthed(fnc) {
|
|
70
|
+
try {
|
|
71
|
+
return await fnc();
|
|
72
|
+
}
|
|
73
|
+
catch (e) {
|
|
74
|
+
if (!String(e.stack || e).includes(storageController_1.STORAGE_NOT_AUTHENTICATED))
|
|
75
|
+
throw e;
|
|
76
|
+
await this.authenticate();
|
|
77
|
+
return await fnc();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Returns undefined if this machine has access to the account. Otherwise puts in an access
|
|
81
|
+
// request and returns our machineId + ip (so the caller can display them alongside the link,
|
|
82
|
+
// for the approver to match the incoming request) and the link to the grant page.
|
|
83
|
+
async waitingForAccess() {
|
|
84
|
+
let state = await this.callAuthed(() => this.controller.getAccessState(this.account));
|
|
85
|
+
if (state.hasAccess)
|
|
86
|
+
return undefined;
|
|
87
|
+
let requested = await this.callAuthed(() => this.controller.requestAccess(this.account));
|
|
88
|
+
return {
|
|
89
|
+
link: `https://${this.parsed.address}:${this.parsed.port}/${this.account}`,
|
|
90
|
+
machineId: requested.machineId,
|
|
91
|
+
ip: requested.ip,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
async hasWriteAccess() {
|
|
95
|
+
let state = await this.callAuthed(() => this.controller.getAccessState(this.account));
|
|
96
|
+
return !!state.hasAccess;
|
|
97
|
+
}
|
|
98
|
+
// Registers our access request server-side (so an admin has a requestId to grant) and logs the
|
|
99
|
+
// grant instructions, at most once a minute
|
|
100
|
+
async registerAccessRequest() {
|
|
101
|
+
let requested = await this.callAuthed(() => this.controller.requestAccess(this.account));
|
|
102
|
+
if (Date.now() - this.lastDeniedLog > misc_1.timeInMinute) {
|
|
103
|
+
this.lastDeniedLog = Date.now();
|
|
104
|
+
console.log(`No access to storage account ${JSON.stringify(this.account)} on ${this.parsed.address}:${this.parsed.port} (our machine ${requested.machineId}, ip ${requested.ip}). See https://${this.parsed.address}:${this.parsed.port}/${this.account} - or grant it with: ${requested.grantAccessCommand}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Runs a call, authenticating (and re-authenticating after reconnects) and waiting for account
|
|
108
|
+
// access as needed. With waitForAccess false, denied calls throw immediately instead - but the
|
|
109
|
+
// access request is still registered (in the background), so the denial is grantable.
|
|
110
|
+
async call(fnc) {
|
|
111
|
+
while (true) {
|
|
112
|
+
try {
|
|
113
|
+
return await fnc();
|
|
114
|
+
}
|
|
115
|
+
catch (e) {
|
|
116
|
+
let message = String(e.stack || e);
|
|
117
|
+
if (message.includes(storageController_1.STORAGE_NOT_AUTHENTICATED)) {
|
|
118
|
+
await this.authenticate();
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (message.includes(storageController_1.STORAGE_ACCESS_DENIED)) {
|
|
122
|
+
if (this.config.waitForAccess === false) {
|
|
123
|
+
void this.registerAccessRequest().catch(() => { });
|
|
124
|
+
throw e;
|
|
125
|
+
}
|
|
126
|
+
await this.registerAccessRequest();
|
|
127
|
+
await (0, batching_1.delay)(ACCESS_RETRY_DELAY);
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
throw e;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
async get(fileName, config) {
|
|
135
|
+
let result = await this.get2(fileName, config);
|
|
136
|
+
return result && result.data || undefined;
|
|
137
|
+
}
|
|
138
|
+
async get2(fileName, config) {
|
|
139
|
+
let result = await this.call(() => this.controller.get2(this.account, this.bucketName, fileName, config === null || config === void 0 ? void 0 : config.range));
|
|
140
|
+
return result && { data: Buffer.from(result.data), writeTime: result.writeTime, size: result.size } || undefined;
|
|
141
|
+
}
|
|
142
|
+
async set(fileName, data, config) {
|
|
143
|
+
await this.call(() => this.controller.set(this.account, this.bucketName, fileName, data, config === null || config === void 0 ? void 0 : config.lastModified));
|
|
144
|
+
}
|
|
145
|
+
async del(fileName) {
|
|
146
|
+
await this.call(() => this.controller.del(this.account, this.bucketName, fileName));
|
|
147
|
+
}
|
|
148
|
+
async getInfo(fileName) {
|
|
149
|
+
return await this.call(() => this.controller.getInfo(this.account, this.bucketName, fileName));
|
|
150
|
+
}
|
|
151
|
+
async findInfo(prefix, config) {
|
|
152
|
+
return await this.call(() => this.controller.findInfo(this.account, this.bucketName, prefix, config));
|
|
153
|
+
}
|
|
154
|
+
async find(prefix, config) {
|
|
155
|
+
return (await this.findInfo(prefix, config)).map(x => x.path);
|
|
156
|
+
}
|
|
157
|
+
async getChangesAfter(time) {
|
|
158
|
+
return await this.call(() => this.controller.getChangesAfter(this.account, this.bucketName, time));
|
|
159
|
+
}
|
|
160
|
+
async getConfig() {
|
|
161
|
+
return await this.call(() => this.controller.getArchivesConfig(this.account, this.bucketName));
|
|
162
|
+
}
|
|
163
|
+
async getSyncStatus() {
|
|
164
|
+
return await this.call(() => this.controller.getSyncStatus(this.account, this.bucketName));
|
|
165
|
+
}
|
|
166
|
+
async setLargeFile(config) {
|
|
167
|
+
// Ensure we're authenticated with access BEFORE consuming any data (the stream cannot be
|
|
168
|
+
// rewound, so we can't use the retry loop around the actual upload)
|
|
169
|
+
await this.call(() => this.controller.getInfo(this.account, this.bucketName, config.path));
|
|
170
|
+
let uploadId = await this.controller.startLargeFile(this.account, this.bucketName, config.path);
|
|
171
|
+
try {
|
|
172
|
+
while (true) {
|
|
173
|
+
let data = await config.getNextData();
|
|
174
|
+
if (!data)
|
|
175
|
+
break;
|
|
176
|
+
for (let offset = 0; offset < data.length; offset += LARGE_FILE_PART_SIZE) {
|
|
177
|
+
await this.controller.uploadPart(uploadId, data.subarray(offset, offset + LARGE_FILE_PART_SIZE));
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
await this.controller.finishLargeFile(uploadId);
|
|
181
|
+
}
|
|
182
|
+
catch (e) {
|
|
183
|
+
try {
|
|
184
|
+
await this.controller.cancelLargeFile(uploadId);
|
|
185
|
+
}
|
|
186
|
+
catch (_a) { }
|
|
187
|
+
throw e;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
async getURL(path) {
|
|
191
|
+
// Only actually loads for public buckets (the server rejects plain URL reads otherwise)
|
|
192
|
+
return (0, remoteConfig_1.buildFileUrl)((0, remoteConfig_1.getBucketBaseUrl)(this.config.url), path);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
exports.ArchivesRemote = ArchivesRemote;
|
|
196
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQXJjaGl2ZXNSZW1vdGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJBcmNoaXZlc1JlbW90ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxNQUFNLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQztBQUUxQixtRUFBZ0U7QUFDaEUsbURBQXdEO0FBQ3hELDJEQUFxRDtBQUNyRCxrREFBNkU7QUFFN0UsaURBQWdGO0FBQ2hGLDJEQUc2QjtBQUU3QixrR0FBa0c7QUFDbEcsK0ZBQStGO0FBQy9GLGlHQUFpRztBQUNqRyxzREFBc0Q7QUFFdEQsTUFBTSxrQkFBa0IsR0FBRyxJQUFJLEdBQUcsRUFBRSxDQUFDO0FBQ3JDLE1BQU0sb0JBQW9CLEdBQUcsQ0FBQyxHQUFHLElBQUksR0FBRyxJQUFJLENBQUM7QUFhN0MsU0FBZ0IsZUFBZSxDQUFDLEdBQVc7SUFDdkMsSUFBSSxDQUFDLEdBQUcsSUFBSSxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDckIsSUFBSSxDQUFDLENBQUMsUUFBUSxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQzFCLE1BQU0sSUFBSSxLQUFLLENBQUMsbUNBQW1DLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQy9HLENBQUM7SUFDRCxPQUFPLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQyxRQUFRLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksSUFBSSxHQUFHLEVBQUUsQ0FBQztBQUN6RCxDQUFDO0FBTkQsMENBTUM7QUFFRCx1RkFBdUY7QUFDaEYsS0FBSyxVQUFVLG1CQUFtQixDQUFDLE1BQXlEO0lBQy9GLDRGQUE0RjtJQUM1RiwwREFBMEQ7SUFDMUQsK0JBQWMsQ0FBQyxrQkFBa0IsR0FBRyxJQUFJLENBQUM7SUFDekMsSUFBSSxVQUFVLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FB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ZS5hbGxvd2NsaWVudCA9IHRydWU7XG5cbmltcG9ydCB7IFNvY2tldEZ1bmN0aW9uIH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9Tb2NrZXRGdW5jdGlvblwiO1xuaW1wb3J0IHsgdGltZUluTWludXRlIH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9zcmMvbWlzY1wiO1xuaW1wb3J0IHsgZGVsYXkgfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy9iYXRjaGluZ1wiO1xuaW1wb3J0IHsgZ2V0SWRlbnRpdHlDQSwgbG9hZElkZW50aXR5Q0EsIHNpZ24gfSBmcm9tIFwiLi4vLi4vbWlzYy9odHRwcy9jZXJ0c1wiO1xuaW1wb3J0IHsgSUFyY2hpdmVzLCBBcmNoaXZlRmlsZUluZm8sIEFyY2hpdmVzQ29uZmlnLCBBcmNoaXZlc1N5bmNTdGF0dXMgfSBmcm9tIFwiLi4vSUFyY2hpdmVzXCI7XG5pbXBvcnQgeyBwYXJzZUhvc3RlZFVybCwgZ2V0QnVja2V0QmFzZVVybCwgYnVpbGRGaWxlVXJsIH0gZnJvbSBcIi4vcmVtb3RlQ29uZmlnXCI7XG5pbXBvcnQge1xuICAgIFJlbW90ZVN0b3JhZ2VDb250cm9sbGVyLCBTVE9SQUdFX0FVVEhfUFVSUE9TRSxcbiAgICBTVE9SQUdFX05PVF9BVVRIRU5USUNBVEVELCBTVE9SQUdFX0FDQ0VTU19ERU5JRUQsXG59IGZyb20gXCIuL3N0b3JhZ2VDb250cm9sbGVyXCI7XG5cbi8vIEEgYnVja2V0IG9uIG91ciByZW1vdGUgc3RvcmFnZSBzZXJ2ZXIgKHN0b3JhZ2VTZXJ2ZXIudHMpLCB1c2VkIGxpa2UgQXJjaGl2ZXNCYWNrYmxhemUuIFdvcmtzIGluXG4vLyBOb2RlLmpzIGFuZCB0aGUgYnJvd3Nlci4gQXV0aGVudGljYXRlcyB3aXRoIHRoaXMgbWFjaGluZSdzIGNlcnRzLnRzIGlkZW50aXR5OyBpZiB0aGUgYWNjb3VudFxuLy8gaGFzbid0IHRydXN0ZWQgdGhpcyBtYWNoaW5lIHlldCBpdCByZXF1ZXN0cyBhY2Nlc3MsIGFuZCBieSBkZWZhdWx0IHdhaXRzLCBsb2dnaW5nIGluc3RydWN0aW9uc1xuLy8gZXZlcnkgbWludXRlIChjYWxscyBibG9jayB1bnRpbCBhY2Nlc3MgaXMgZ3JhbnRlZCkuXG5cbmNvbnN0IEFDQ0VTU19SRVRSWV9ERUxBWSA9IDEwMDAgKiAzMDtcbmNvbnN0IExBUkdFX0ZJTEVfUEFSVF9TSVpFID0gOCAqIDEwMjQgKiAxMDI0O1xuXG5leHBvcnQgdHlwZSBBcmNoaXZlc1JlbW90ZUNvbmZpZyA9IHtcbiAgICAvLyBUaGUgYnVja2V0J3Mgcm91dGluZyBVUkwsIHdoaWNoIGFkZHJlc3NlcyB0aGUgc2VydmVyLCBhY2NvdW50LCBhbmQgYnVja2V0IGluIG9uZTpcbiAgICAvLyAgaHR0cHM6Ly9zdG9yYWdlLmV4YW1wbGUuY29tOjQ0NDQvZmlsZS88YWNjb3VudD4vPGJ1Y2tldE5hbWU+L3N0b3JhZ2Uvc3RvcmFnZXJvdXRpbmcuanNvblxuICAgIHVybDogc3RyaW5nO1xuICAgIC8vIEFjY2VzcyBpcyBjaGVja2VkIGFnYWluc3QgdGhpcyBhY2NvdW50IChkZWZhdWx0cyB0byB0aGUgYWNjb3VudCBpbiB0aGUgdXJsKVxuICAgIGFjY291bnROYW1lPzogc3RyaW5nO1xuICAgIC8vIGZhbHNlOiBhY2Nlc3MtZGVuaWVkIGNhbGxzIHRocm93IGltbWVkaWF0ZWx5ICh0aGUgZXJyb3IgaW5jbHVkZXMgdGhlIGFjY2VzcyBwYWdlIGxpbmspXG4gICAgLy8gaW5zdGVhZCBvZiByZXF1ZXN0aW5nIGFjY2VzcyBhbmQgYmxvY2tpbmcgdW50aWwgaXQgaXMgZ3JhbnRlZCAodGhlIGRlZmF1bHQpLlxuICAgIHdhaXRGb3JBY2Nlc3M/OiBib29sZWFuO1xufTtcblxuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlU3RvcmFnZVVybCh1cmw6IHN0cmluZyk6IHsgYWRkcmVzczogc3RyaW5nOyBwb3J0OiBudW1iZXIgfSB7XG4gICAgbGV0IHUgPSBuZXcgVVJMKHVybCk7XG4gICAgaWYgKHUucHJvdG9jb2wgIT09IFwiaHR0cHM6XCIpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBTdG9yYWdlIFVSTCBtdXN0IHVzZSBodHRwcywgZ290ICR7SlNPTi5zdHJpbmdpZnkodS5wcm90b2NvbCl9IGluICR7SlNPTi5zdHJpbmdpZnkodXJsKX1gKTtcbiAgICB9XG4gICAgcmV0dXJuIHsgYWRkcmVzczogdS5ob3N0bmFtZSwgcG9ydDogK3UucG9ydCB8fCA0NDMgfTtcbn1cblxuLy8gQXV0aGVudGljYXRlcyBhIGNvbm5lY3Rpb24gdG8gYSBzdG9yYWdlIHNlcnZlciB3aXRoIHRoaXMgbWFjaGluZSdzIGNlcnRzLnRzIGlkZW50aXR5XG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gYXV0aGVudGljYXRlU3RvcmFnZShjb25maWc6IHsgYWRkcmVzczogc3RyaW5nOyBwb3J0OiBudW1iZXI7IG5vZGVJZDogc3RyaW5nIH0pOiBQcm9taXNlPHsgbWFjaGluZUlkOiBzdHJpbmc7IGlwOiBzdHJpbmcgfT4ge1xuICAgIC8vIGhvc3RTZXJ2ZXIgbm9kZUlkcyBhcmUgbWFjaGluZS1zcGVjaWZpYywgc28gY29ubmVjdGlvbnMgYnkgZG9tYWluIG11c3QgdGFyZ2V0IFwiYW55IHNlcnZlclxuICAgIC8vIGF0IHRoaXMgYWRkcmVzc1wiICh3aGljaCBpcyBob3cgYnJvd3NlcnMgYWx3YXlzIGNvbm5lY3QpXG4gICAgU29ja2V0RnVuY3Rpb24uRU5BQkxFX0NMSUVOVF9NT0RFID0gdHJ1ZTtcbiAgICBsZXQgcm9vdERvbWFpbiA9IGNvbmZpZy5hZGRyZXNzLnNwbGl0KFwiLlwiKS5zbGljZSgtMikuam9pbihcIi5cIik7XG4gICAgYXdhaXQgbG9hZElkZW50aXR5Q0Eocm9vdERvbWFpbik7XG4gICAgbGV0IGNhID0gZ2V0SWRlbnRpdHlDQShyb290RG9tYWluKTtcbiAgICBsZXQgdGltZSA9IERhdGUubm93KCk7XG4gICAgbGV0IHNpZ25hdHVyZSA9IHNpZ24oeyBrZXk6IGNhLmtleSB9LCB7XG4gICAgICAgIHB1cnBvc2U6IFNUT1JBR0VfQVVUSF9QVVJQT1NFLFxuICAgICAgICB0aW1lLFxuICAgICAgICBzZXJ2ZXI6IGAke2NvbmZpZy5hZGRyZXNzfToke2NvbmZpZy5wb3J0fWAsXG4gICAgfSk7XG4gICAgcmV0dXJuIGF3YWl0IFJlbW90ZVN0b3JhZ2VDb250cm9sbGVyLm5vZGVzW2NvbmZpZy5ub2RlSWRdLmF1dGhlbnRpY2F0ZSh7IGNlcnRQZW06IGNhLmNlcnQudG9TdHJpbmcoKSwgdGltZSwgc2lnbmF0dXJlIH0pO1xufVxuXG5leHBvcnQgY2xhc3MgQXJjaGl2ZXNSZW1vdGUgaW1wbGVtZW50cyBJQXJjaGl2ZXMge1xuICAgIGNvbnN0cnVjdG9yKHByaXZhdGUgY29uZmlnOiBBcmNoaXZlc1JlbW90ZUNvbmZpZykge1xuICAgICAgICAvLyBob3N0U2VydmVyIG5vZGVJZHMgYXJlIG1hY2hpbmUtc3BlY2lmaWMsIHNvIGNvbm5lY3Rpb25zIGJ5IGRvbWFpbiBtdXN0IHRhcmdldCBcImFueVxuICAgICAgICAvLyBzZXJ2ZXIgYXQgdGhpcyBhZGRyZXNzXCIgKHdoaWNoIGlzIGhvdyBicm93c2VycyBhbHdheXMgY29ubmVjdClcbiAgICAgICAgU29ja2V0RnVuY3Rpb24uRU5BQkxFX0NMSUVOVF9NT0RFID0gdHJ1ZTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHBhcnNlZCA9IHBhcnNlSG9zdGVkVXJsKHRoaXMuY29uZmlnLnVybCk7XG4gICAgcHJpdmF0ZSBhY2NvdW50ID0gdGhpcy5jb25maWcuYWNjb3VudE5hbWUgfHwgdGhpcy5wYXJzZWQuYWNjb3VudDtcbiAgICBwcml2YXRlIGJ1Y2tldE5hbWUgPSB0aGlzLnBhcnNlZC5idWNrZXROYW1lO1xuICAgIHByaXZhdGUgbm9kZUlkID0gU29ja2V0RnVuY3Rpb24uY29ubmVjdCh7IGFkZHJlc3M6IHRoaXMucGFyc2VkLmFkZHJlc3MsIHBvcnQ6IHRoaXMucGFyc2VkLnBvcnQgfSk7XG4gICAgcHJpdmF0ZSBjb250cm9sbGVyID0gUmVtb3RlU3RvcmFnZUNvbnRyb2xsZXIubm9kZXNbdGhpcy5ub2RlSWRdO1xuICAgIHByaXZhdGUgbGFzdERlbmllZExvZyA9IDA7XG5cbiAgICBwdWJsaWMgZ2V0RGVidWdOYW1lKCkge1xuICAgICAgICByZXR1cm4gYHJlbW90ZVN0b3JhZ2UvJHt0aGlzLnBhcnNlZC5hZGRyZXNzfToke3RoaXMucGFyc2VkLnBvcnR9LyR7dGhpcy5hY2NvdW50fS8ke3RoaXMuYnVja2V0TmFtZX1gO1xuICAgIH1cblxuICAgIHB1YmxpYyBpc0Nvbm5lY3RlZCgpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIFNvY2tldEZ1bmN0aW9uLmlzTm9kZUNvbm5lY3RlZCh0aGlzLm5vZGVJZCk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHBpbmcoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IHRoaXMuY29udHJvbGxlci5waW5nKCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBhdXRoZW50aWNhdGUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IGF1dGhlbnRpY2F0ZVN0b3JhZ2UoeyBhZGRyZXNzOiB0aGlzLnBhcnNlZC5hZGRyZXNzLCBwb3J0OiB0aGlzLnBhcnNlZC5wb3J0LCBub2RlSWQ6IHRoaXMubm9kZUlkIH0pO1xuICAgIH1cblxuICAgIC8vIFJ1bnMgYSBjYWxsLCBhdXRoZW50aWNhdGluZyAoYW5kIHJlLWF1dGhlbnRpY2F0aW5nIGFmdGVyIHJlY29ubmVjdHMpIGFzIG5lZWRlZC4gVW5saWtlXG4gICAgLy8gY2FsbCgpLCBkb2VzIE5PVCB3YWl0IGZvciBhY2NvdW50IGFjY2Vzcy5cbiAgICBwcml2YXRlIGFzeW5jIGNhbGxBdXRoZWQ8VD4oZm5jOiAoKSA9PiBQcm9taXNlPFQ+KTogUHJvbWlzZTxUPiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgZm5jKCk7XG4gICAgICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgICAgICAgaWYgKCFTdHJpbmcoZS5zdGFjayB8fCBlKS5pbmNsdWRlcyhTVE9SQUdFX05PVF9BVVRIRU5USUNBVEVEKSkgdGhyb3cgZTtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuYXV0aGVudGljYXRlKCk7XG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgZm5jKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBSZXR1cm5zIHVuZGVmaW5lZCBpZiB0aGlzIG1hY2hpbmUgaGFzIGFjY2VzcyB0byB0aGUgYWNjb3VudC4gT3RoZXJ3aXNlIHB1dHMgaW4gYW4gYWNjZXNzXG4gICAgLy8gcmVxdWVzdCBhbmQgcmV0dXJucyBvdXIgbWFjaGluZUlkICsgaXAgKHNvIHRoZSBjYWxsZXIgY2FuIGRpc3BsYXkgdGhlbSBhbG9uZ3NpZGUgdGhlIGxpbmssXG4gICAgLy8gZm9yIHRoZSBhcHByb3ZlciB0byBtYXRjaCB0aGUgaW5jb21pbmcgcmVxdWVzdCkgYW5kIHRoZSBsaW5rIHRvIHRoZSBncmFudCBwYWdlLlxuICAgIHB1YmxpYyBhc3luYyB3YWl0aW5nRm9yQWNjZXNzKCk6IFByb21pc2U8eyBsaW5rOiBzdHJpbmc7IG1hY2hpbmVJZDogc3RyaW5nOyBpcDogc3RyaW5nIH0gfCB1bmRlZmluZWQ+IHtcbiAgICAgICAgbGV0IHN0YXRlID0gYXdhaXQgdGhpcy5jYWxsQXV0aGVkKCgpID0+IHRoaXMuY29udHJvbGxlci5nZXRBY2Nlc3NTdGF0ZSh0aGlzLmFjY291bnQpKTtcbiAgICAgICAgaWYgKHN0YXRlLmhhc0FjY2VzcykgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgbGV0IHJlcXVlc3RlZCA9IGF3YWl0IHRoaXMuY2FsbEF1dGhlZCgoKSA9PiB0aGlzLmNvbnRyb2xsZXIucmVxdWVzdEFjY2Vzcyh0aGlzLmFjY291bnQpKTtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGxpbms6IGBodHRwczovLyR7dGhpcy5wYXJzZWQuYWRkcmVzc306JHt0aGlzLnBhcnNlZC5wb3J0fS8ke3RoaXMuYWNjb3VudH1gLFxuICAgICAgICAgICAgbWFjaGluZUlkOiByZXF1ZXN0ZWQubWFjaGluZUlkLFxuICAgICAgICAgICAgaXA6IHJlcXVlc3RlZC5pcCxcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgaGFzV3JpdGVBY2Nlc3MoKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgICAgIGxldCBzdGF0ZSA9IGF3YWl0IHRoaXMuY2FsbEF1dGhlZCgoKSA9PiB0aGlzLmNvbnRyb2xsZXIuZ2V0QWNjZXNzU3RhdGUodGhpcy5hY2NvdW50KSk7XG4gICAgICAgIHJldHVybiAhIXN0YXRlLmhhc0FjY2VzcztcbiAgICB9XG5cbiAgICAvLyBSZWdpc3RlcnMgb3VyIGFjY2VzcyByZXF1ZXN0IHNlcnZlci1zaWRlIChzbyBhbiBhZG1pbiBoYXMgYSByZXF1ZXN0SWQgdG8gZ3JhbnQpIGFuZCBsb2dzIHRoZVxuICAgIC8vIGdyYW50IGluc3RydWN0aW9ucywgYXQgbW9zdCBvbmNlIGEgbWludXRlXG4gICAgcHJpdmF0ZSBhc3luYyByZWdpc3RlckFjY2Vzc1JlcXVlc3QoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGxldCByZXF1ZXN0ZWQgPSBhd2FpdCB0aGlzLmNhbGxBdXRoZWQoKCkgPT4gdGhpcy5jb250cm9sbGVyLnJlcXVlc3RBY2Nlc3ModGhpcy5hY2NvdW50KSk7XG4gICAgICAgIGlmIChEYXRlLm5vdygpIC0gdGhpcy5sYXN0RGVuaWVkTG9nID4gdGltZUluTWludXRlKSB7XG4gICAgICAgICAgICB0aGlzLmxhc3REZW5pZWRMb2cgPSBEYXRlLm5vdygpO1xuICAgICAgICAgICAgY29uc29sZS5sb2coYE5vIGFjY2VzcyB0byBzdG9yYWdlIGFjY291bnQgJHtKU09OLnN0cmluZ2lmeSh0aGlzLmFjY291bnQpfSBvbiAke3RoaXMucGFyc2VkLmFkZHJlc3N9OiR7dGhpcy5wYXJzZWQucG9ydH0gKG91ciBtYWNoaW5lICR7cmVxdWVzdGVkLm1hY2hpbmVJZH0sIGlwICR7cmVxdWVzdGVkLmlwfSkuIFNlZSBodHRwczovLyR7dGhpcy5wYXJzZWQuYWRkcmVzc306JHt0aGlzLnBhcnNlZC5wb3J0fS8ke3RoaXMuYWNjb3VudH0gLSBvciBncmFudCBpdCB3aXRoOiAke3JlcXVlc3RlZC5ncmFudEFjY2Vzc0NvbW1hbmR9YCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBSdW5zIGEgY2FsbCwgYXV0aGVudGljYXRpbmcgKGFuZCByZS1hdXRoZW50aWNhdGluZyBhZnRlciByZWNvbm5lY3RzKSBhbmQgd2FpdGluZyBmb3IgYWNjb3VudFxuICAgIC8vIGFjY2VzcyBhcyBuZWVkZWQuIFdpdGggd2FpdEZvckFjY2VzcyBmYWxzZSwgZGVuaWVkIGNhbGxzIHRocm93IGltbWVkaWF0ZWx5IGluc3RlYWQgLSBidXQgdGhlXG4gICAgLy8gYWNjZXNzIHJlcXVlc3QgaXMgc3RpbGwgcmVnaXN0ZXJlZCAoaW4gdGhlIGJhY2tncm91bmQpLCBzbyB0aGUgZGVuaWFsIGlzIGdyYW50YWJsZS5cbiAgICBwcml2YXRlIGFzeW5jIGNhbGw8VD4oZm5jOiAoKSA9PiBQcm9taXNlPFQ+KTogUHJvbWlzZTxUPiB7XG4gICAgICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIHJldHVybiBhd2FpdCBmbmMoKTtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgICAgICAgICAgIGxldCBtZXNzYWdlID0gU3RyaW5nKGUuc3RhY2sgfHwgZSk7XG4gICAgICAgICAgICAgICAgaWYgKG1lc3NhZ2UuaW5jbHVkZXMoU1RPUkFHRV9OT1RfQVVUSEVOVElDQVRFRCkpIHtcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5hdXRoZW50aWNhdGUoKTtcbiAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChtZXNzYWdlLmluY2x1ZGVzKFNUT1JBR0VfQUNDRVNTX0RFTklFRCkpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuY29uZmlnLndhaXRGb3JBY2Nlc3MgPT09IGZhbHNlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2b2lkIHRoaXMucmVnaXN0ZXJBY2Nlc3NSZXF1ZXN0KCkuY2F0Y2goKCkgPT4geyB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IGU7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5yZWdpc3RlckFjY2Vzc1JlcXVlc3QoKTtcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgZGVsYXkoQUNDRVNTX1JFVFJZX0RFTEFZKTtcbiAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRocm93IGU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgZ2V0KGZpbGVOYW1lOiBzdHJpbmcsIGNvbmZpZz86IHsgcmFuZ2U/OiB7IHN0YXJ0OiBudW1iZXI7IGVuZDogbnVtYmVyIH0gfSk6IFByb21pc2U8QnVmZmVyIHwgdW5kZWZpbmVkPiB7XG4gICAgICAgIGxldCByZXN1bHQgPSBhd2FpdCB0aGlzLmdldDIoZmlsZU5hbWUsIGNvbmZpZyk7XG4gICAgICAgIHJldHVybiByZXN1bHQgJiYgcmVzdWx0LmRhdGEgfHwgdW5kZWZpbmVkO1xuICAgIH1cbiAgICBwdWJsaWMgYXN5bmMgZ2V0MihmaWxlTmFtZTogc3RyaW5nLCBjb25maWc/OiB7IHJhbmdlPzogeyBzdGFydDogbnVtYmVyOyBlbmQ6IG51bWJlciB9IH0pOiBQcm9taXNlPHsgZGF0YTogQnVmZmVyOyB3cml0ZVRpbWU6IG51bWJlcjsgc2l6ZTogbnVtYmVyIH0gfCB1bmRlZmluZWQ+IHtcbiAgICAgICAgbGV0IHJlc3VsdCA9IGF3YWl0IHRoaXMuY2FsbCgoKSA9PiB0aGlzLmNvbnRyb2xsZXIuZ2V0Mih0aGlzLmFjY291bnQsIHRoaXMuYnVja2V0TmFtZSwgZmlsZU5hbWUsIGNvbmZpZz8ucmFuZ2UpKTtcbiAgICAgICAgcmV0dXJuIHJlc3VsdCAmJiB7IGRhdGE6IEJ1ZmZlci5mcm9tKHJlc3VsdC5kYXRhKSwgd3JpdGVUaW1lOiByZXN1bHQud3JpdGVUaW1lLCBzaXplOiByZXN1bHQuc2l6ZSB9IHx8IHVuZGVmaW5lZDtcbiAgICB9XG4gICAgcHVibGljIGFzeW5jIHNldChmaWxlTmFtZTogc3RyaW5nLCBkYXRhOiBCdWZmZXIsIGNvbmZpZz86IHsgbGFzdE1vZGlmaWVkPzogbnVtYmVyIH0pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5jYWxsKCgpID0+IHRoaXMuY29udHJvbGxlci5zZXQodGhpcy5hY2NvdW50LCB0aGlzLmJ1Y2tldE5hbWUsIGZpbGVOYW1lLCBkYXRhLCBjb25maWc/Lmxhc3RNb2RpZmllZCkpO1xuICAgIH1cbiAgICBwdWJsaWMgYXN5bmMgZGVsKGZpbGVOYW1lOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5jYWxsKCgpID0+IHRoaXMuY29udHJvbGxlci5kZWwodGhpcy5hY2NvdW50LCB0aGlzLmJ1Y2tldE5hbWUsIGZpbGVOYW1lKSk7XG4gICAgfVxuICAgIHB1YmxpYyBhc3luYyBnZXRJbmZvKGZpbGVOYW1lOiBzdHJpbmcpOiBQcm9taXNlPHsgd3JpdGVUaW1lOiBudW1iZXI7IHNpemU6IG51bWJlciB9IHwgdW5kZWZpbmVkPiB7XG4gICAgICAgIHJldHVybiBhd2FpdCB0aGlzLmNhbGwoKCkgPT4gdGhpcy5jb250cm9sbGVyLmdldEluZm8odGhpcy5hY2NvdW50LCB0aGlzLmJ1Y2tldE5hbWUsIGZpbGVOYW1lKSk7XG4gICAgfVxuICAgIHB1YmxpYyBhc3luYyBmaW5kSW5mbyhwcmVmaXg6IHN0cmluZywgY29uZmlnPzogeyBzaGFsbG93PzogYm9vbGVhbjsgdHlwZTogXCJmaWxlc1wiIHwgXCJmb2xkZXJzXCIgfSk6IFByb21pc2U8QXJjaGl2ZUZpbGVJbmZvW10+IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuY2FsbCgoKSA9PiB0aGlzLmNvbnRyb2xsZXIuZmluZEluZm8odGhpcy5hY2NvdW50LCB0aGlzLmJ1Y2tldE5hbWUsIHByZWZpeCwgY29uZmlnKSk7XG4gICAgfVxuICAgIHB1YmxpYyBhc3luYyBmaW5kKHByZWZpeDogc3RyaW5nLCBjb25maWc/OiB7IHNoYWxsb3c/OiBib29sZWFuOyB0eXBlOiBcImZpbGVzXCIgfCBcImZvbGRlcnNcIiB9KTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICAgICAgICByZXR1cm4gKGF3YWl0IHRoaXMuZmluZEluZm8ocHJlZml4LCBjb25maWcpKS5tYXAoeCA9PiB4LnBhdGgpO1xuICAgIH1cbiAgICBwdWJsaWMgYXN5bmMgZ2V0Q2hhbmdlc0FmdGVyKHRpbWU6IG51bWJlcik6IFByb21pc2U8QXJjaGl2ZUZpbGVJbmZvW10+IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuY2FsbCgoKSA9PiB0aGlzLmNvbnRyb2xsZXIuZ2V0Q2hhbmdlc0FmdGVyKHRoaXMuYWNjb3VudCwgdGhpcy5idWNrZXROYW1lLCB0aW1lKSk7XG4gICAgfVxuICAgIHB1YmxpYyBhc3luYyBnZXRDb25maWcoKTogUHJvbWlzZTxBcmNoaXZlc0NvbmZpZz4ge1xuICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5jYWxsKCgpID0+IHRoaXMuY29udHJvbGxlci5nZXRBcmNoaXZlc0NvbmZpZyh0aGlzLmFjY291bnQsIHRoaXMuYnVja2V0TmFtZSkpO1xuICAgIH1cbiAgICBwdWJsaWMgYXN5bmMgZ2V0U3luY1N0YXR1cygpOiBQcm9taXNlPEFyY2hpdmVzU3luY1N0YXR1cz4ge1xuICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5jYWxsKCgpID0+IHRoaXMuY29udHJvbGxlci5nZXRTeW5jU3RhdHVzKHRoaXMuYWNjb3VudCwgdGhpcy5idWNrZXROYW1lKSk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHNldExhcmdlRmlsZShjb25maWc6IHsgcGF0aDogc3RyaW5nOyBnZXROZXh0RGF0YSgpOiBQcm9taXNlPEJ1ZmZlciB8IHVuZGVmaW5lZD4gfSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICAvLyBFbnN1cmUgd2UncmUgYXV0aGVudGljYXRlZCB3aXRoIGFjY2VzcyBCRUZPUkUgY29uc3VtaW5nIGFueSBkYXRhICh0aGUgc3RyZWFtIGNhbm5vdCBiZVxuICAgICAgICAvLyByZXdvdW5kLCBzbyB3ZSBjYW4ndCB1c2UgdGhlIHJldHJ5IGxvb3AgYXJvdW5kIHRoZSBhY3R1YWwgdXBsb2FkKVxuICAgICAgICBhd2FpdCB0aGlzLmNhbGwoKCkgPT4gdGhpcy5jb250cm9sbGVyLmdldEluZm8odGhpcy5hY2NvdW50LCB0aGlzLmJ1Y2tldE5hbWUsIGNvbmZpZy5wYXRoKSk7XG4gICAgICAgIGxldCB1cGxvYWRJZCA9IGF3YWl0IHRoaXMuY29udHJvbGxlci5zdGFydExhcmdlRmlsZSh0aGlzLmFjY291bnQsIHRoaXMuYnVja2V0TmFtZSwgY29uZmlnLnBhdGgpO1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgd2hpbGUgKHRydWUpIHtcbiAgICAgICAgICAgICAgICBsZXQgZGF0YSA9IGF3YWl0IGNvbmZpZy5nZXROZXh0RGF0YSgpO1xuICAgICAgICAgICAgICAgIGlmICghZGF0YSkgYnJlYWs7XG4gICAgICAgICAgICAgICAgZm9yIChsZXQgb2Zmc2V0ID0gMDsgb2Zmc2V0IDwgZGF0YS5sZW5ndGg7IG9mZnNldCArPSBMQVJHRV9GSUxFX1BBUlRfU0laRSkge1xuICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLmNvbnRyb2xsZXIudXBsb2FkUGFydCh1cGxvYWRJZCwgZGF0YS5zdWJhcnJheShvZmZzZXQsIG9mZnNldCArIExBUkdFX0ZJTEVfUEFSVF9TSVpFKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYXdhaXQgdGhpcy5jb250cm9sbGVyLmZpbmlzaExhcmdlRmlsZSh1cGxvYWRJZCk7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5jb250cm9sbGVyLmNhbmNlbExhcmdlRmlsZSh1cGxvYWRJZCk7XG4gICAgICAgICAgICB9IGNhdGNoIHsgfVxuICAgICAgICAgICAgdGhyb3cgZTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBnZXRVUkwocGF0aDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICAgICAgLy8gT25seSBhY3R1YWxseSBsb2FkcyBmb3IgcHVibGljIGJ1Y2tldHMgKHRoZSBzZXJ2ZXIgcmVqZWN0cyBwbGFpbiBVUkwgcmVhZHMgb3RoZXJ3aXNlKVxuICAgICAgICByZXR1cm4gYnVpbGRGaWxlVXJsKGdldEJ1Y2tldEJhc2VVcmwodGhpcy5jb25maWcudXJsKSwgcGF0aCk7XG4gICAgfVxufVxuIl19
|
|
197
|
+
/* _JS_SOURCE_HASH = "065b8b11387821eb401e95ea507db3d6f1dba4b1bb63cbc23ec898f5490b85ce"; */
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
|
|
3
|
+
//exports.ArchivesUrl = void 0;
|
|
4
|
+
module.allowclient = true;
|
|
5
|
+
const remoteConfig_1 = require("./remoteConfig");
|
|
6
|
+
// Read-only IArchives over a public bucket's plain-URL form (our storage server's
|
|
7
|
+
// /file/<account>/<bucketName>/... route, or a backblaze friendly URL). Used when we have no API
|
|
8
|
+
// access to a source. Only single-file reads work: there is no listing, and writes always throw.
|
|
9
|
+
class ArchivesUrl {
|
|
10
|
+
// base is the bucket's public base URL, e.g. https://host:port/file/<account>/<bucketName>
|
|
11
|
+
constructor(base) {
|
|
12
|
+
this.base = base;
|
|
13
|
+
}
|
|
14
|
+
getDebugName() {
|
|
15
|
+
return `url/${this.base}`;
|
|
16
|
+
}
|
|
17
|
+
readOnlyError(operation) {
|
|
18
|
+
return new Error(`${operation} is not supported over URL-form access (no API access to this source, only public URL reads). Source: ${this.base}`);
|
|
19
|
+
}
|
|
20
|
+
async get(fileName, config) {
|
|
21
|
+
let result = await this.get2(fileName, config);
|
|
22
|
+
return result && result.data || undefined;
|
|
23
|
+
}
|
|
24
|
+
async get2(fileName, config) {
|
|
25
|
+
let url = (0, remoteConfig_1.buildFileUrl)(this.base, fileName);
|
|
26
|
+
let headers = {};
|
|
27
|
+
let range = config === null || config === void 0 ? void 0 : config.range;
|
|
28
|
+
if (range) {
|
|
29
|
+
headers["Range"] = `bytes=${range.start}-${range.end - 1}`;
|
|
30
|
+
}
|
|
31
|
+
let response = await fetch(url, { headers });
|
|
32
|
+
if (response.status === 404)
|
|
33
|
+
return undefined;
|
|
34
|
+
if (!response.ok) {
|
|
35
|
+
throw new Error(`Read of ${url} failed: ${response.status} ${response.statusText}`);
|
|
36
|
+
}
|
|
37
|
+
let data = Buffer.from(await response.arrayBuffer());
|
|
38
|
+
// A real 206 only returns the requested slice, so the full size lives in Content-Range's total.
|
|
39
|
+
let size = data.length;
|
|
40
|
+
let contentRange = response.headers.get("content-range");
|
|
41
|
+
let total = contentRange && Number(contentRange.split("/")[1]);
|
|
42
|
+
if (total && Number.isFinite(total)) {
|
|
43
|
+
size = total;
|
|
44
|
+
}
|
|
45
|
+
// Servers that don't support ranges return the full file with a 200 (ours serves real
|
|
46
|
+
// 206s, but backblaze friendly URLs and proxies may not)
|
|
47
|
+
if (range && response.status === 200) {
|
|
48
|
+
data = data.subarray(Math.min(range.start, data.length), Math.min(range.end, data.length));
|
|
49
|
+
}
|
|
50
|
+
let lastModified = response.headers.get("last-modified");
|
|
51
|
+
let writeTime = lastModified && new Date(lastModified).getTime() || 0;
|
|
52
|
+
return { data, writeTime, size };
|
|
53
|
+
}
|
|
54
|
+
async getInfo(fileName) {
|
|
55
|
+
let result = await this.get2(fileName);
|
|
56
|
+
return result && { writeTime: result.writeTime, size: result.size } || undefined;
|
|
57
|
+
}
|
|
58
|
+
async set(fileName, data, config) {
|
|
59
|
+
throw this.readOnlyError("set");
|
|
60
|
+
}
|
|
61
|
+
async del(fileName) {
|
|
62
|
+
throw this.readOnlyError("del");
|
|
63
|
+
}
|
|
64
|
+
async setLargeFile(config) {
|
|
65
|
+
throw this.readOnlyError("setLargeFile");
|
|
66
|
+
}
|
|
67
|
+
async find(prefix, config) {
|
|
68
|
+
throw this.readOnlyError("find (listing)");
|
|
69
|
+
}
|
|
70
|
+
async findInfo(prefix, config) {
|
|
71
|
+
throw this.readOnlyError("findInfo (listing)");
|
|
72
|
+
}
|
|
73
|
+
async getURL(path) {
|
|
74
|
+
return (0, remoteConfig_1.buildFileUrl)(this.base, path);
|
|
75
|
+
}
|
|
76
|
+
async getConfig() {
|
|
77
|
+
return {};
|
|
78
|
+
}
|
|
79
|
+
async hasWriteAccess() {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
exports.ArchivesUrl = ArchivesUrl;
|
|
84
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQXJjaGl2ZXNVcmwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJBcmNoaXZlc1VybC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxNQUFNLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQztBQUcxQixpREFBOEM7QUFFOUMsa0ZBQWtGO0FBQ2xGLGlHQUFpRztBQUNqRyxpR0FBaUc7QUFFakcsTUFBYSxXQUFXO0lBQ3BCLDJGQUEyRjtJQUMzRixZQUFvQixJQUFZO1FBQVosU0FBSSxHQUFKLElBQUksQ0FBUTtJQUFJLENBQUM7SUFFOUIsWUFBWTtRQUNmLE9BQU8sT0FBTyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDOUIsQ0FBQztJQUVPLGFBQWEsQ0FBQyxTQUFpQjtRQUNuQyxPQUFPLElBQUksS0FBSyxDQUFDLEdBQUcsU0FBUyx5R0FBeUcsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7SUFDdkosQ0FBQztJQUVNLEtBQUssQ0FBQyxHQUFHLENBQUMsUUFBZ0IsRUFBRSxNQUFtRDtRQUNsRixJQUFJLE1BQU0sR0FBRyxNQUFNLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBQy9DLE9BQU8sTUFBTSxJQUFJLE1BQU0sQ0FBQyxJQUFJLElBQUksU0FBUyxDQUFDO0lBQzlDLENBQUM7SUFDTSxLQUFLLENBQUMsSUFBSSxDQUFDLFFBQWdCLEVBQUUsTUFBbUQ7UUFDbkYsSUFBSSxHQUFHLEdBQUcsSUFBQSwyQkFBWSxFQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFDNUMsSUFBSSxPQUFPLEdBQTJCLEVBQUUsQ0FBQztRQUN6QyxJQUFJLEtBQUssR0FBRyxNQUFNLGFBQU4sTUFBTSx1QkFBTixNQUFNLENBQUUsS0FBSyxDQUFDO1FBQzFCLElBQUksS0FBSyxFQUFFLENBQUM7WUFDUixPQUFPLENBQUMsT0FBTyxDQUFDLEdBQUcsU0FBUyxLQUFLLENBQUMsS0FB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TUFBYyxFQUFFLE1BQXlEO1FBQzNGLE1BQU0sSUFBSSxDQUFDLGFBQWEsQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO0lBQ25ELENBQUM7SUFFTSxLQUFLLENBQUMsTUFBTSxDQUFDLElBQVk7UUFDNUIsT0FBTyxJQUFBLDJCQUFZLEVBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQztJQUN6QyxDQUFDO0lBQ00sS0FBSyxDQUFDLFNBQVM7UUFDbEIsT0FBTyxFQUFFLENBQUM7SUFDZCxDQUFDO0lBRU0sS0FBSyxDQUFDLGNBQWM7UUFDdkIsT0FBTyxLQUFLLENBQUM7SUFDakIsQ0FBQztDQUNKO0FBNUVELGtDQTRFQyIsInNvdXJjZXNDb250ZW50IjpbIm1vZHVsZS5hbGxvd2NsaWVudCA9IHRydWU7XG5cbmltcG9ydCB7IElBcmNoaXZlcywgQXJjaGl2ZUZpbGVJbmZvLCBBcmNoaXZlc0NvbmZpZyB9IGZyb20gXCIuLi9JQXJjaGl2ZXNcIjtcbmltcG9ydCB7IGJ1aWxkRmlsZVVybCB9IGZyb20gXCIuL3JlbW90ZUNvbmZpZ1wiO1xuXG4vLyBSZWFkLW9ubHkgSUFyY2hpdmVzIG92ZXIgYSBwdWJsaWMgYnVja2V0J3MgcGxhaW4tVVJMIGZvcm0gKG91ciBzdG9yYWdlIHNlcnZlcidzXG4vLyAvZmlsZS88YWNjb3VudD4vPGJ1Y2tldE5hbWU+Ly4uLiByb3V0ZSwgb3IgYSBiYWNrYmxhemUgZnJpZW5kbHkgVVJMKS4gVXNlZCB3aGVuIHdlIGhhdmUgbm8gQVBJXG4vLyBhY2Nlc3MgdG8gYSBzb3VyY2UuIE9ubHkgc2luZ2xlLWZpbGUgcmVhZHMgd29yazogdGhlcmUgaXMgbm8gbGlzdGluZywgYW5kIHdyaXRlcyBhbHdheXMgdGhyb3cuXG5cbmV4cG9ydCBjbGFzcyBBcmNoaXZlc1VybCBpbXBsZW1lbnRzIElBcmNoaXZlcyB7XG4gICAgLy8gYmFzZSBpcyB0aGUgYnVja2V0J3MgcHVibGljIGJhc2UgVVJMLCBlLmcuIGh0dHBzOi8vaG9zdDpwb3J0L2ZpbGUvPGFjY291bnQ+LzxidWNrZXROYW1lPlxuICAgIGNvbnN0cnVjdG9yKHByaXZhdGUgYmFzZTogc3RyaW5nKSB7IH1cblxuICAgIHB1YmxpYyBnZXREZWJ1Z05hbWUoKSB7XG4gICAgICAgIHJldHVybiBgdXJsLyR7dGhpcy5iYXNlfWA7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSByZWFkT25seUVycm9yKG9wZXJhdGlvbjogc3RyaW5nKTogRXJyb3Ige1xuICAgICAgICByZXR1cm4gbmV3IEVycm9yKGAke29wZXJhdGlvbn0gaXMgbm90IHN1cHBvcnRlZCBvdmVyIFVSTC1mb3JtIGFjY2VzcyAobm8gQVBJIGFjY2VzcyB0byB0aGlzIHNvdXJjZSwgb25seSBwdWJsaWMgVVJMIHJlYWRzKS4gU291cmNlOiAke3RoaXMuYmFzZX1gKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgZ2V0KGZpbGVOYW1lOiBzdHJpbmcsIGNvbmZpZz86IHsgcmFuZ2U/OiB7IHN0YXJ0OiBudW1iZXI7IGVuZDogbnVtYmVyIH0gfSk6IFByb21pc2U8QnVmZmVyIHwgdW5kZWZpbmVkPiB7XG4gICAgICAgIGxldCByZXN1bHQgPSBhd2FpdCB0aGlzLmdldDIoZmlsZU5hbWUsIGNvbmZpZyk7XG4gICAgICAgIHJldHVybiByZXN1bHQgJiYgcmVzdWx0LmRhdGEgfHwgdW5kZWZpbmVkO1xuICAgIH1cbiAgICBwdWJsaWMgYXN5bmMgZ2V0MihmaWxlTmFtZTogc3RyaW5nLCBjb25maWc/OiB7IHJhbmdlPzogeyBzdGFydDogbnVtYmVyOyBlbmQ6IG51bWJlciB9IH0pOiBQcm9taXNlPHsgZGF0YTogQnVmZmVyOyB3cml0ZVRpbWU6IG51bWJlcjsgc2l6ZTogbnVtYmVyIH0gfCB1bmRlZmluZWQ+IHtcbiAgICAgICAgbGV0IHVybCA9IGJ1aWxkRmlsZVVybCh0aGlzLmJhc2UsIGZpbGVOYW1lKTtcbiAgICAgICAgbGV0IGhlYWRlcnM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7fTtcbiAgICAgICAgbGV0IHJhbmdlID0gY29uZmlnPy5yYW5nZTtcbiAgICAgICAgaWYgKHJhbmdlKSB7XG4gICAgICAgICAgICBoZWFkZXJzW1wiUmFuZ2VcIl0gPSBgYnl0ZXM9JHtyYW5nZS5zdGFydH0tJHtyYW5nZS5lbmQgLSAxfWA7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2godXJsLCB7IGhlYWRlcnMgfSk7XG4gICAgICAgIGlmIChyZXNwb25zZS5zdGF0dXMgPT09IDQwNCkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgaWYgKCFyZXNwb25zZS5vaykge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBSZWFkIG9mICR7dXJsfSBmYWlsZWQ6ICR7cmVzcG9uc2Uuc3RhdHVzfSAke3Jlc3BvbnNlLnN0YXR1c1RleHR9YCk7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IGRhdGEgPSBCdWZmZXIuZnJvbShhd2FpdCByZXNwb25zZS5hcnJheUJ1ZmZlcigpKTtcbiAgICAgICAgLy8gQSByZWFsIDIwNiBvbmx5IHJldHVybnMgdGhlIHJlcXVlc3RlZCBzbGljZSwgc28gdGhlIGZ1bGwgc2l6ZSBsaXZlcyBpbiBDb250ZW50LVJhbmdlJ3MgdG90YWwuXG4gICAgICAgIGxldCBzaXplID0gZGF0YS5sZW5ndGg7XG4gICAgICAgIGxldCBjb250ZW50UmFuZ2UgPSByZXNwb25zZS5oZWFkZXJzLmdldChcImNvbnRlbnQtcmFuZ2VcIik7XG4gICAgICAgIGxldCB0b3RhbCA9IGNvbnRlbnRSYW5nZSAmJiBOdW1iZXIoY29udGVudFJhbmdlLnNwbGl0KFwiL1wiKVsxXSk7XG4gICAgICAgIGlmICh0b3RhbCAmJiBOdW1iZXIuaXNGaW5pdGUodG90YWwpKSB7XG4gICAgICAgICAgICBzaXplID0gdG90YWw7XG4gICAgICAgIH1cbiAgICAgICAgLy8gU2VydmVycyB0aGF0IGRvbid0IHN1cHBvcnQgcmFuZ2VzIHJldHVybiB0aGUgZnVsbCBmaWxlIHdpdGggYSAyMDAgKG91cnMgc2VydmVzIHJlYWxcbiAgICAgICAgLy8gMjA2cywgYnV0IGJhY2tibGF6ZSBmcmllbmRseSBVUkxzIGFuZCBwcm94aWVzIG1heSBub3QpXG4gICAgICAgIGlmIChyYW5nZSAmJiByZXNwb25zZS5zdGF0dXMgPT09IDIwMCkge1xuICAgICAgICAgICAgZGF0YSA9IGRhdGEuc3ViYXJyYXkoTWF0aC5taW4ocmFuZ2Uuc3RhcnQsIGRhdGEubGVuZ3RoKSwgTWF0aC5taW4ocmFuZ2UuZW5kLCBkYXRhLmxlbmd0aCkpO1xuICAgICAgICB9XG4gICAgICAgIGxldCBsYXN0TW9kaWZpZWQgPSByZXNwb25zZS5oZWFkZXJzLmdldChcImxhc3QtbW9kaWZpZWRcIik7XG4gICAgICAgIGxldCB3cml0ZVRpbWUgPSBsYXN0TW9kaWZpZWQgJiYgbmV3IERhdGUobGFzdE1vZGlmaWVkKS5nZXRUaW1lKCkgfHwgMDtcbiAgICAgICAgcmV0dXJuIHsgZGF0YSwgd3JpdGVUaW1lLCBzaXplIH07XG4gICAgfVxuICAgIHB1YmxpYyBhc3luYyBnZXRJbmZvKGZpbGVOYW1lOiBzdHJpbmcpOiBQcm9taXNlPHsgd3JpdGVUaW1lOiBudW1iZXI7IHNpemU6IG51bWJlciB9IHwgdW5kZWZpbmVkPiB7XG4gICAgICAgIGxldCByZXN1bHQgPSBhd2FpdCB0aGlzLmdldDIoZmlsZU5hbWUpO1xuICAgICAgICByZXR1cm4gcmVzdWx0ICYmIHsgd3JpdGVUaW1lOiByZXN1bHQud3JpdGVUaW1lLCBzaXplOiByZXN1bHQuc2l6ZSB9IHx8IHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgc2V0KGZpbGVOYW1lOiBzdHJpbmcsIGRhdGE6IEJ1ZmZlciwgY29uZmlnPzogeyBsYXN0TW9kaWZpZWQ/OiBudW1iZXIgfSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICB0aHJvdyB0aGlzLnJlYWRPbmx5RXJyb3IoXCJzZXRcIik7XG4gICAgfVxuICAgIHB1YmxpYyBhc3luYyBkZWwoZmlsZU5hbWU6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICB0aHJvdyB0aGlzLnJlYWRPbmx5RXJyb3IoXCJkZWxcIik7XG4gICAgfVxuICAgIHB1YmxpYyBhc3luYyBzZXRMYXJnZUZpbGUoY29uZmlnOiB7IHBhdGg6IHN0cmluZzsgZ2V0TmV4dERhdGEoKTogUHJvbWlzZTxCdWZmZXIgfCB1bmRlZmluZWQ+IH0pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgdGhyb3cgdGhpcy5yZWFkT25seUVycm9yKFwic2V0TGFyZ2VGaWxlXCIpO1xuICAgIH1cbiAgICBwdWJsaWMgYXN5bmMgZmluZChwcmVmaXg6IHN0cmluZywgY29uZmlnPzogeyBzaGFsbG93PzogYm9vbGVhbjsgdHlwZTogXCJmaWxlc1wiIHwgXCJmb2xkZXJzXCIgfSk6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgICAgICAgdGhyb3cgdGhpcy5yZWFkT25seUVycm9yKFwiZmluZCAobGlzdGluZylcIik7XG4gICAgfVxuICAgIHB1YmxpYyBhc3luYyBmaW5kSW5mbyhwcmVmaXg6IHN0cmluZywgY29uZmlnPzogeyBzaGFsbG93PzogYm9vbGVhbjsgdHlwZTogXCJmaWxlc1wiIHwgXCJmb2xkZXJzXCIgfSk6IFByb21pc2U8QXJjaGl2ZUZpbGVJbmZvW10+IHtcbiAgICAgICAgdGhyb3cgdGhpcy5yZWFkT25seUVycm9yKFwiZmluZEluZm8gKGxpc3RpbmcpXCIpO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBnZXRVUkwocGF0aDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICAgICAgcmV0dXJuIGJ1aWxkRmlsZVVybCh0aGlzLmJhc2UsIHBhdGgpO1xuICAgIH1cbiAgICBwdWJsaWMgYXN5bmMgZ2V0Q29uZmlnKCk6IFByb21pc2U8QXJjaGl2ZXNDb25maWc+IHtcbiAgICAgICAgcmV0dXJuIHt9O1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBoYXNXcml0ZUFjY2VzcygpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbn1cbiJdfQ==
|
|
85
|
+
/* _JS_SOURCE_HASH = "3b08e87dc92fd46752eef014c02d0b938c7e7ae588bb1d9582446c2f1b980993"; */
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"use strict"; var console = (function shimConsole() { let baseConsole = globalThis.console; if (typeof window !== "undefined") return baseConsole; let name = __filename.replaceAll("\\", "/").split("/").pop(); let dirName = __dirname.replaceAll("\\", "/").split("/").pop(); let context = { __FILE__: __filename, __DIR__: __dirname, __NAME__: name, __DIRNAME__: dirName }; let newConsole = { ...baseConsole }; for (let shim of ["log", "info", "warn", "error"]) { newConsole[shim] = (...args) => { args.push(context); baseConsole[shim](...args); }; } newConsole.__context = context; return newConsole; })(); "use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
+
return (mod && mod.__esModule && mod.default) ? mod : { "default": mod };
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
|
|
12
|
+
module.allowclient = true;
|
|
13
|
+
const preact_1 = __importDefault(require("preact"));
|
|
14
|
+
const mobx_1 = require("mobx");
|
|
15
|
+
const observer_1 = require("../../render-utils/observer");
|
|
16
|
+
const misc_1 = require("socket-function/src/misc");
|
|
17
|
+
const typesafecss_1 = require("typesafecss");
|
|
18
|
+
const SocketFunction_1 = require("socket-function/SocketFunction");
|
|
19
|
+
const storageController_1 = require("./storageController");
|
|
20
|
+
const ArchivesRemote_1 = require("./ArchivesRemote");
|
|
21
|
+
// The storage server's access page. Visit https://<storageDomain>:<port>/<accountName> to request
|
|
22
|
+
// access to that account for this browser's machine identity. Once granted, lists the machines that
|
|
23
|
+
// have access. To approve someone else's request, the user must type in the requester's IP —
|
|
24
|
+
// pending requests are NEVER shown unsolicited (so a trusted user can't accidentally approve a
|
|
25
|
+
// random machine's request).
|
|
26
|
+
const REFRESH_INTERVAL = 1000 * 15;
|
|
27
|
+
const COPIED_RESET_DELAY = 2000;
|
|
28
|
+
let CopyableCommand = class CopyableCommand extends preact_1.default.Component {
|
|
29
|
+
constructor() {
|
|
30
|
+
super(...arguments);
|
|
31
|
+
this.synced = (0, mobx_1.observable)({
|
|
32
|
+
copied: false,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
render() {
|
|
36
|
+
let command = this.props.command;
|
|
37
|
+
return preact_1.default.createElement("div", { className: typesafecss_1.css.hbox(8).alignItems("flex-start") },
|
|
38
|
+
preact_1.default.createElement("button", { onClick: async () => {
|
|
39
|
+
await navigator.clipboard.writeText(command);
|
|
40
|
+
this.synced.copied = true;
|
|
41
|
+
setTimeout(() => { this.synced.copied = false; }, COPIED_RESET_DELAY);
|
|
42
|
+
} }, this.synced.copied && "Copied!" || "Copy"),
|
|
43
|
+
preact_1.default.createElement("code", { className: typesafecss_1.css.fontFamily("monospace").whiteSpace("pre-wrap")
|
|
44
|
+
.hsl(0, 0, 92).pad2(8, 4).borderRadius(4) }, command));
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
CopyableCommand = __decorate([
|
|
48
|
+
observer_1.observer
|
|
49
|
+
], CopyableCommand);
|
|
50
|
+
let AccessPage = class AccessPage extends preact_1.default.Component {
|
|
51
|
+
constructor() {
|
|
52
|
+
super(...arguments);
|
|
53
|
+
this.synced = (0, mobx_1.observable)({
|
|
54
|
+
account: "",
|
|
55
|
+
state: undefined,
|
|
56
|
+
error: "",
|
|
57
|
+
lookupIp: "",
|
|
58
|
+
lookupResults: undefined,
|
|
59
|
+
lookupError: "",
|
|
60
|
+
looking: false,
|
|
61
|
+
granting: "",
|
|
62
|
+
});
|
|
63
|
+
this.authenticated = false;
|
|
64
|
+
this.lookupIP = async () => {
|
|
65
|
+
let ip = this.synced.lookupIp.trim();
|
|
66
|
+
if (!ip)
|
|
67
|
+
return;
|
|
68
|
+
this.synced.looking = true;
|
|
69
|
+
this.synced.lookupError = "";
|
|
70
|
+
try {
|
|
71
|
+
let controller = await this.controller();
|
|
72
|
+
let requests = await controller.listRequestsForIP(this.synced.account, ip);
|
|
73
|
+
this.synced.lookupResults = { ip, requests };
|
|
74
|
+
}
|
|
75
|
+
catch (e) {
|
|
76
|
+
this.synced.lookupError = String(e);
|
|
77
|
+
}
|
|
78
|
+
finally {
|
|
79
|
+
this.synced.looking = false;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
this.approve = async (request) => {
|
|
83
|
+
this.synced.granting = request.requestId;
|
|
84
|
+
try {
|
|
85
|
+
let controller = await this.controller();
|
|
86
|
+
await controller.grantAccess(request.requestId);
|
|
87
|
+
if (this.synced.lookupResults) {
|
|
88
|
+
this.synced.lookupResults.requests = this.synced.lookupResults.requests.filter(r => r.requestId !== request.requestId);
|
|
89
|
+
}
|
|
90
|
+
await this.refresh(this.synced.account);
|
|
91
|
+
}
|
|
92
|
+
catch (e) {
|
|
93
|
+
this.synced.lookupError = String(e);
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
this.synced.granting = "";
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
componentDidMount() {
|
|
101
|
+
let account = decodeURIComponent(location.pathname.split("/")[1] || "");
|
|
102
|
+
this.synced.account = account;
|
|
103
|
+
if (!account)
|
|
104
|
+
return;
|
|
105
|
+
void (async () => {
|
|
106
|
+
var _a;
|
|
107
|
+
while (true) {
|
|
108
|
+
try {
|
|
109
|
+
await this.refresh(account);
|
|
110
|
+
}
|
|
111
|
+
catch (e) {
|
|
112
|
+
this.synced.error = String(e);
|
|
113
|
+
}
|
|
114
|
+
if ((_a = this.synced.state) === null || _a === void 0 ? void 0 : _a.hasAccess)
|
|
115
|
+
break;
|
|
116
|
+
await new Promise(resolve => setTimeout(resolve, REFRESH_INTERVAL));
|
|
117
|
+
}
|
|
118
|
+
})();
|
|
119
|
+
}
|
|
120
|
+
async controller() {
|
|
121
|
+
let address = location.hostname;
|
|
122
|
+
let port = +location.port || 443;
|
|
123
|
+
let nodeId = SocketFunction_1.SocketFunction.connect({ address, port });
|
|
124
|
+
if (!this.authenticated) {
|
|
125
|
+
await (0, ArchivesRemote_1.authenticateStorage)({ address, port, nodeId });
|
|
126
|
+
this.authenticated = true;
|
|
127
|
+
}
|
|
128
|
+
return storageController_1.RemoteStorageController.nodes[nodeId];
|
|
129
|
+
}
|
|
130
|
+
async refresh(account) {
|
|
131
|
+
let controller = await this.controller();
|
|
132
|
+
await controller.requestAccess(account);
|
|
133
|
+
this.synced.state = await controller.getAccessState(account);
|
|
134
|
+
this.synced.error = "";
|
|
135
|
+
}
|
|
136
|
+
render() {
|
|
137
|
+
let synced = this.synced;
|
|
138
|
+
let { account, state, error } = synced;
|
|
139
|
+
if (!account) {
|
|
140
|
+
return preact_1.default.createElement("div", { className: typesafecss_1.css.vbox(8).pad2(16) },
|
|
141
|
+
preact_1.default.createElement("div", null, "Remote storage server."),
|
|
142
|
+
preact_1.default.createElement("div", null, "Visit /(account name) to request access to an account for this browser."));
|
|
143
|
+
}
|
|
144
|
+
return preact_1.default.createElement("div", { className: typesafecss_1.css.vbox(12).pad2(16) },
|
|
145
|
+
preact_1.default.createElement("div", null,
|
|
146
|
+
"Storage account: ",
|
|
147
|
+
account),
|
|
148
|
+
error && preact_1.default.createElement("div", null,
|
|
149
|
+
"Error: ",
|
|
150
|
+
error),
|
|
151
|
+
!state && !error && preact_1.default.createElement("div", null, "Requesting access..."),
|
|
152
|
+
state && !state.hasAccess && preact_1.default.createElement("div", { className: typesafecss_1.css.vbox(8) },
|
|
153
|
+
preact_1.default.createElement("div", null,
|
|
154
|
+
"This machine (",
|
|
155
|
+
state.machineId,
|
|
156
|
+
", ip ",
|
|
157
|
+
state.ip,
|
|
158
|
+
") does NOT have access yet."),
|
|
159
|
+
preact_1.default.createElement("div", null, "An access request has been made. To grant it, run this command:"),
|
|
160
|
+
state.grantAccessCommand && preact_1.default.createElement(CopyableCommand, { command: state.grantAccessCommand }),
|
|
161
|
+
preact_1.default.createElement("div", null,
|
|
162
|
+
"This page rechecks every ",
|
|
163
|
+
REFRESH_INTERVAL / 1000,
|
|
164
|
+
" seconds.")),
|
|
165
|
+
state && state.hasAccess && preact_1.default.createElement("div", { className: typesafecss_1.css.vbox(16) },
|
|
166
|
+
preact_1.default.createElement("div", null,
|
|
167
|
+
"This machine (",
|
|
168
|
+
state.machineId,
|
|
169
|
+
", ip ",
|
|
170
|
+
state.ip,
|
|
171
|
+
") has access."),
|
|
172
|
+
preact_1.default.createElement("div", { className: typesafecss_1.css.vbox(6) },
|
|
173
|
+
preact_1.default.createElement("div", null, "Machines with access:"),
|
|
174
|
+
preact_1.default.createElement("table", null,
|
|
175
|
+
preact_1.default.createElement("thead", null,
|
|
176
|
+
preact_1.default.createElement("tr", null,
|
|
177
|
+
preact_1.default.createElement("th", { className: typesafecss_1.css.pad2(8, 2).textAlign("left") }, "Machine"),
|
|
178
|
+
preact_1.default.createElement("th", { className: typesafecss_1.css.pad2(8, 2).textAlign("left") }, "IP"),
|
|
179
|
+
preact_1.default.createElement("th", { className: typesafecss_1.css.pad2(8, 2).textAlign("left") }, "Granted"))),
|
|
180
|
+
preact_1.default.createElement("tbody", null, (state.trustedMachines || []).map(m => preact_1.default.createElement("tr", { key: m.machineId },
|
|
181
|
+
preact_1.default.createElement("td", { className: typesafecss_1.css.pad2(8, 2) }, m.machineId),
|
|
182
|
+
preact_1.default.createElement("td", { className: typesafecss_1.css.pad2(8, 2) }, m.ip),
|
|
183
|
+
preact_1.default.createElement("td", { className: typesafecss_1.css.pad2(8, 2) }, new Date(m.time).toLocaleString())))))),
|
|
184
|
+
preact_1.default.createElement("div", { className: typesafecss_1.css.vbox(6) },
|
|
185
|
+
preact_1.default.createElement("div", null, "Approve request"),
|
|
186
|
+
preact_1.default.createElement("div", { className: typesafecss_1.css.hbox(8).alignItems("center") },
|
|
187
|
+
preact_1.default.createElement("input", { placeholder: "ip", value: synced.lookupIp, onInput: e => { synced.lookupIp = e.currentTarget.value; }, onKeyDown: e => { if (e.key === "Enter")
|
|
188
|
+
void this.lookupIP(); } }),
|
|
189
|
+
preact_1.default.createElement("button", { disabled: synced.looking || !synced.lookupIp.trim(), onClick: this.lookupIP }, "search")),
|
|
190
|
+
synced.lookupError && preact_1.default.createElement("div", null,
|
|
191
|
+
"Error: ",
|
|
192
|
+
synced.lookupError),
|
|
193
|
+
synced.lookupResults && synced.lookupResults.requests.length === 0 && preact_1.default.createElement("div", null,
|
|
194
|
+
"No pending requests for ",
|
|
195
|
+
synced.lookupResults.ip,
|
|
196
|
+
" on this account."),
|
|
197
|
+
synced.lookupResults && synced.lookupResults.requests.length > 0 && preact_1.default.createElement("table", null,
|
|
198
|
+
preact_1.default.createElement("thead", null,
|
|
199
|
+
preact_1.default.createElement("tr", null,
|
|
200
|
+
preact_1.default.createElement("th", { className: typesafecss_1.css.pad2(8, 2).textAlign("left") }, "Machine"),
|
|
201
|
+
preact_1.default.createElement("th", { className: typesafecss_1.css.pad2(8, 2).textAlign("left") }, "IP"),
|
|
202
|
+
preact_1.default.createElement("th", { className: typesafecss_1.css.pad2(8, 2).textAlign("left") }, "Requested"),
|
|
203
|
+
preact_1.default.createElement("th", { className: typesafecss_1.css.pad2(8, 2).textAlign("left") }))),
|
|
204
|
+
preact_1.default.createElement("tbody", null, synced.lookupResults.requests.map(r => preact_1.default.createElement("tr", { key: r.requestId },
|
|
205
|
+
preact_1.default.createElement("td", { className: typesafecss_1.css.pad2(8, 2) }, r.machineId),
|
|
206
|
+
preact_1.default.createElement("td", { className: typesafecss_1.css.pad2(8, 2) }, r.ip),
|
|
207
|
+
preact_1.default.createElement("td", { className: typesafecss_1.css.pad2(8, 2) }, new Date(r.time).toLocaleString()),
|
|
208
|
+
preact_1.default.createElement("td", { className: typesafecss_1.css.pad2(8, 2) },
|
|
209
|
+
preact_1.default.createElement("button", { disabled: !!synced.granting, onClick: async () => this.approve(r) }, synced.granting === r.requestId && "Approving..." || "Approve")))))))));
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
AccessPage = __decorate([
|
|
213
|
+
observer_1.observer
|
|
214
|
+
], AccessPage);
|
|
215
|
+
async function main() {
|
|
216
|
+
if ((0, misc_1.isNode)())
|
|
217
|
+
return;
|
|
218
|
+
preact_1.default.render(preact_1.default.createElement(AccessPage, null), document.body);
|
|
219
|
+
}
|
|
220
|
+
main().catch(console.error);
|
|
221
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWNjZXNzUGFnZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImFjY2Vzc1BhZ2UudHN4Il0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7O0FBQUEsTUFBTSxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUM7QUFFMUIsb0RBQTRCO0FBQzVCLCtCQUFrQztBQUNsQywwREFBdUQ7QUFDdkQsbURBQWtEO0FBQ2xELDZDQUFrQztBQUNsQyxtRUFBZ0U7QUFDaEUsMkRBQTBGO0FBQzFGLHFEQUF1RDtBQUV2RCxrR0FBa0c7QUFDbEcsb0dBQW9HO0FBQ3BHLDZGQUE2RjtBQUM3RiwrRkFBK0Y7QUFDL0YsNkJBQTZCO0FBRTdCLE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxHQUFHLEVBQUUsQ0FBQztBQUNuQyxNQUFNLGtCQUFrQixHQUFHLElBQUksQ0FBQztBQUdoQyxJQUFNLGVBQWUsR0FBckIsTUFBTSxlQUFnQixTQUFRLGdCQUFNLENBQUMsU0FBOEI7SUFBbkU7O1FBQ0ksV0FBTSxHQUFHLElBQUEsaUJBQVUsRUFBQztZQUNoQixNQUFNLEVBQUUsS0FBSztTQUNoQixDQUFDLENBQUM7SUFtQlAsQ0FBQztJQWpCRyxNQUFNO1FBQ0YsSUFBSSxPQUFPLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUM7UUFDakMsT0FBTyx3Q0FBSyxTQUFTLEVBQUUsaUJBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLFlBQVksQ0FBQztZQUN2RCwyQ0FBUSxPQUFPLEVBQUUsS0FBSyxJQUFJLEVBQUU7b0JBQ3hCLE1BQU0sU0FBUyxDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLENBQUM7b0JBQzdDLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQztvQkFDMUIsVUFBVSxDQUFDLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQyxDQUFDLENB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YWN0IGZyb20gXCJwcmVhY3RcIjtcbmltcG9ydCB7IG9ic2VydmFibGUgfSBmcm9tIFwibW9ieFwiO1xuaW1wb3J0IHsgb2JzZXJ2ZXIgfSBmcm9tIFwiLi4vLi4vcmVuZGVyLXV0aWxzL29ic2VydmVyXCI7XG5pbXBvcnQgeyBpc05vZGUgfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy9taXNjXCI7XG5pbXBvcnQgeyBjc3MgfSBmcm9tIFwidHlwZXNhZmVjc3NcIjtcbmltcG9ydCB7IFNvY2tldEZ1bmN0aW9uIH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9Tb2NrZXRGdW5jdGlvblwiO1xuaW1wb3J0IHsgUmVtb3RlU3RvcmFnZUNvbnRyb2xsZXIsIEFjY2Vzc1N0YXRlLCBBY2Nlc3NSZXF1ZXN0IH0gZnJvbSBcIi4vc3RvcmFnZUNvbnRyb2xsZXJcIjtcbmltcG9ydCB7IGF1dGhlbnRpY2F0ZVN0b3JhZ2UgfSBmcm9tIFwiLi9BcmNoaXZlc1JlbW90ZVwiO1xuXG4vLyBUaGUgc3RvcmFnZSBzZXJ2ZXIncyBhY2Nlc3MgcGFnZS4gVmlzaXQgaHR0cHM6Ly88c3RvcmFnZURvbWFpbj46PHBvcnQ+LzxhY2NvdW50TmFtZT4gdG8gcmVxdWVzdFxuLy8gYWNjZXNzIHRvIHRoYXQgYWNjb3VudCBmb3IgdGhpcyBicm93c2VyJ3MgbWFjaGluZSBpZGVudGl0eS4gT25jZSBncmFudGVkLCBsaXN0cyB0aGUgbWFjaGluZXMgdGhhdFxuLy8gaGF2ZSBhY2Nlc3MuIFRvIGFwcHJvdmUgc29tZW9uZSBlbHNlJ3MgcmVxdWVzdCwgdGhlIHVzZXIgbXVzdCB0eXBlIGluIHRoZSByZXF1ZXN0ZXIncyBJUCDigJRcbi8vIHBlbmRpbmcgcmVxdWVzdHMgYXJlIE5FVkVSIHNob3duIHVuc29saWNpdGVkIChzbyBhIHRydXN0ZWQgdXNlciBjYW4ndCBhY2NpZGVudGFsbHkgYXBwcm92ZSBhXG4vLyByYW5kb20gbWFjaGluZSdzIHJlcXVlc3QpLlxuXG5jb25zdCBSRUZSRVNIX0lOVEVSVkFMID0gMTAwMCAqIDE1O1xuY29uc3QgQ09QSUVEX1JFU0VUX0RFTEFZID0gMjAwMDtcblxuQG9ic2VydmVyXG5jbGFzcyBDb3B5YWJsZUNvbW1hbmQgZXh0ZW5kcyBwcmVhY3QuQ29tcG9uZW50PHsgY29tbWFuZDogc3RyaW5nIH0+IHtcbiAgICBzeW5jZWQgPSBvYnNlcnZhYmxlKHtcbiAgICAgICAgY29waWVkOiBmYWxzZSxcbiAgICB9KTtcblxuICAgIHJlbmRlcigpIHtcbiAgICAgICAgbGV0IGNvbW1hbmQgPSB0aGlzLnByb3BzLmNvbW1hbmQ7XG4gICAgICAgIHJldHVybiA8ZGl2IGNsYXNzTmFtZT17Y3NzLmhib3goOCkuYWxpZ25JdGVtcyhcImZsZXgtc3RhcnRcIil9PlxuICAgICAgICAgICAgPGJ1dHRvbiBvbkNsaWNrPXthc3luYyAoKSA9PiB7XG4gICAgICAgICAgICAgICAgYXdhaXQgbmF2aWdhdG9yLmNsaXBib2FyZC53cml0ZVRleHQoY29tbWFuZCk7XG4gICAgICAgICAgICAgICAgdGhpcy5zeW5jZWQuY29waWVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHsgdGhpcy5zeW5jZWQuY29waWVkID0gZmFsc2U7IH0sIENPUElFRF9SRVNFVF9ERUxBWSk7XG4gICAgICAgICAgICB9fT5cbiAgICAgICAgICAgICAgICB7dGhpcy5zeW5jZWQuY29waWVkICYmIFwiQ29waWVkIVwiIHx8IFwiQ29weVwifVxuICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICA8Y29kZSBjbGFzc05hbWU9e2Nzcy5mb250RmFtaWx5KFwibW9ub3NwYWNlXCIpLndoaXRlU3BhY2UoXCJwcmUtd3JhcFwiKVxuICAgICAgICAgICAgICAgIC5oc2woMCwgMCwgOTIpLnBhZDIoOCwgNCkuYm9yZGVyUmFkaXVzKDQpXG4gICAgICAgICAgICB9PlxuICAgICAgICAgICAgICAgIHtjb21tYW5kfVxuICAgICAgICAgICAgPC9jb2RlPlxuICAgICAgICA8L2Rpdj47XG4gICAgfVxufVxuXG5Ab2JzZXJ2ZXJcbmNsYXNzIEFjY2Vzc1BhZ2UgZXh0ZW5kcyBwcmVhY3QuQ29tcG9uZW50IHtcbiAgICBzeW5jZWQgPSBvYnNlcnZhYmxlKHtcbiAgICAgICAgYWNjb3VudDogXCJcIixcbiAgICAgICAgc3RhdGU6IHVuZGVmaW5lZCBhcyBBY2Nlc3NTdGF0ZSB8IHVuZGVmaW5lZCxcbiAgICAgICAgZXJyb3I6IFwiXCIsXG4gICAgICAgIGxvb2t1cElwOiBcIlwiLFxuICAgICAgICBsb29rdXBSZXN1bHRzOiB1bmRlZmluZWQgYXMgeyBpcDogc3RyaW5nOyByZXF1ZXN0czogQWNjZXNzUmVxdWVzdFtdIH0gfCB1bmRlZmluZWQsXG4gICAgICAgIGxvb2t1cEVycm9yOiBcIlwiLFxuICAgICAgICBsb29raW5nOiBmYWxzZSxcbiAgICAgICAgZ3JhbnRpbmc6IFwiXCIsXG4gICAgfSk7XG5cbiAgICBjb21wb25lbnREaWRNb3VudCgpIHtcbiAgICAgICAgbGV0IGFjY291bnQgPSBkZWNvZGVVUklDb21wb25lbnQobG9jYXRpb24ucGF0aG5hbWUuc3BsaXQoXCIvXCIpWzFdIHx8IFwiXCIpO1xuICAgICAgICB0aGlzLnN5bmNlZC5hY2NvdW50ID0gYWNjb3VudDtcbiAgICAgICAgaWYgKCFhY2NvdW50KSByZXR1cm47XG4gICAgICAgIHZvaWQgKGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5yZWZyZXNoKGFjY291bnQpO1xuICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zeW5jZWQuZXJyb3IgPSBTdHJpbmcoZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmICh0aGlzLnN5bmNlZC5zdGF0ZT8uaGFzQWNjZXNzKSBicmVhaztcbiAgICAgICAgICAgICAgICBhd2FpdCBuZXcgUHJvbWlzZShyZXNvbHZlID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgUkVGUkVTSF9JTlRFUlZBTCkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KSgpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXV0aGVudGljYXRlZCA9IGZhbHNlO1xuICAgIHByaXZhdGUgYXN5bmMgY29udHJvbGxlcigpIHtcbiAgICAgICAgbGV0IGFkZHJlc3MgPSBsb2NhdGlvbi5ob3N0bmFtZTtcbiAgICAgICAgbGV0IHBvcnQgPSArbG9jYXRpb24ucG9ydCB8fCA0NDM7XG4gICAgICAgIGxldCBub2RlSWQgPSBTb2NrZXRGdW5jdGlvbi5jb25uZWN0KHsgYWRkcmVzcywgcG9ydCB9KTtcbiAgICAgICAgaWYgKCF0aGlzLmF1dGhlbnRpY2F0ZWQpIHtcbiAgICAgICAgICAgIGF3YWl0IGF1dGhlbnRpY2F0ZVN0b3JhZ2UoeyBhZGRyZXNzLCBwb3J0LCBub2RlSWQgfSk7XG4gICAgICAgICAgICB0aGlzLmF1dGhlbnRpY2F0ZWQgPSB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBSZW1vdGVTdG9yYWdlQ29udHJvbGxlci5ub2Rlc1tub2RlSWRdO1xuICAgIH1cbiAgICBwcml2YXRlIGFzeW5jIHJlZnJlc2goYWNjb3VudDogc3RyaW5nKSB7XG4gICAgICAgIGxldCBjb250cm9sbGVyID0gYXdhaXQgdGhpcy5jb250cm9sbGVyKCk7XG4gICAgICAgIGF3YWl0IGNvbnRyb2xsZXIucmVxdWVzdEFjY2VzcyhhY2NvdW50KTtcbiAgICAgICAgdGhpcy5zeW5jZWQuc3RhdGUgPSBhd2FpdCBjb250cm9sbGVyLmdldEFjY2Vzc1N0YXRlKGFjY291bnQpO1xuICAgICAgICB0aGlzLnN5bmNlZC5lcnJvciA9IFwiXCI7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBsb29rdXBJUCA9IGFzeW5jICgpID0+IHtcbiAgICAgICAgbGV0IGlwID0gdGhpcy5zeW5jZWQubG9va3VwSXAudHJpbSgpO1xuICAgICAgICBpZiAoIWlwKSByZXR1cm47XG4gICAgICAgIHRoaXMuc3luY2VkLmxvb2tpbmcgPSB0cnVlO1xuICAgICAgICB0aGlzLnN5bmNlZC5sb29rdXBFcnJvciA9IFwiXCI7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBsZXQgY29udHJvbGxlciA9IGF3YWl0IHRoaXMuY29udHJvbGxlcigpO1xuICAgICAgICAgICAgbGV0IHJlcXVlc3RzID0gYXdhaXQgY29udHJvbGxlci5saXN0UmVxdWVzdHNGb3JJUCh0aGlzLnN5bmNlZC5hY2NvdW50LCBpcCk7XG4gICAgICAgICAgICB0aGlzLnN5bmNlZC5sb29rdXBSZXN1bHRzID0geyBpcCwgcmVxdWVzdHMgfTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgdGhpcy5zeW5jZWQubG9va3VwRXJyb3IgPSBTdHJpbmcoZSk7XG4gICAgICAgIH0gZmluYWxseSB7XG4gICAgICAgICAgICB0aGlzLnN5bmNlZC5sb29raW5nID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBhcHByb3ZlID0gYXN5bmMgKHJlcXVlc3Q6IEFjY2Vzc1JlcXVlc3QpID0+IHtcbiAgICAgICAgdGhpcy5zeW5jZWQuZ3JhbnRpbmcgPSByZXF1ZXN0LnJlcXVlc3RJZDtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGxldCBjb250cm9sbGVyID0gYXdhaXQgdGhpcy5jb250cm9sbGVyKCk7XG4gICAgICAgICAgICBhd2FpdCBjb250cm9sbGVyLmdyYW50QWNjZXNzKHJlcXVlc3QucmVxdWVzdElkKTtcbiAgICAgICAgICAgIGlmICh0aGlzLnN5bmNlZC5sb29rdXBSZXN1bHRzKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zeW5jZWQubG9va3VwUmVzdWx0cy5yZXF1ZXN0cyA9IHRoaXMuc3luY2VkLmxvb2t1cFJlc3VsdHMucmVxdWVzdHMuZmlsdGVyKHIgPT4gci5yZXF1ZXN0SWQgIT09IHJlcXVlc3QucmVxdWVzdElkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGF3YWl0IHRoaXMucmVmcmVzaCh0aGlzLnN5bmNlZC5hY2NvdW50KTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgdGhpcy5zeW5jZWQubG9va3VwRXJyb3IgPSBTdHJpbmcoZSk7XG4gICAgICAgIH0gZmluYWxseSB7XG4gICAgICAgICAgICB0aGlzLnN5bmNlZC5ncmFudGluZyA9IFwiXCI7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgcmVuZGVyKCkge1xuICAgICAgICBsZXQgc3luY2VkID0gdGhpcy5zeW5jZWQ7XG4gICAgICAgIGxldCB7IGFjY291bnQsIHN0YXRlLCBlcnJvciB9ID0gc3luY2VkO1xuICAgICAgICBpZiAoIWFjY291bnQpIHtcbiAgICAgICAgICAgIHJldHVybiA8ZGl2IGNsYXNzTmFtZT17Y3NzLnZib3goOCkucGFkMigxNil9PlxuICAgICAgICAgICAgICAgIDxkaXY+UmVtb3RlIHN0b3JhZ2Ugc2VydmVyLjwvZGl2PlxuICAgICAgICAgICAgICAgIDxkaXY+VmlzaXQgLyhhY2NvdW50IG5hbWUpIHRvIHJlcXVlc3QgYWNjZXNzIHRvIGFuIGFjY291bnQgZm9yIHRoaXMgYnJvd3Nlci48L2Rpdj5cbiAgICAgICAgICAgIDwvZGl2PjtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gPGRpdiBjbGFzc05hbWU9e2Nzcy52Ym94KDEyKS5wYWQyKDE2KX0+XG4gICAgICAgICAgICA8ZGl2PlN0b3JhZ2UgYWNjb3VudDoge2FjY291bnR9PC9kaXY+XG4gICAgICAgICAgICB7ZXJyb3IgJiYgPGRpdj5FcnJvcjoge2Vycm9yfTwvZGl2Pn1cbiAgICAgICAgICAgIHshc3RhdGUgJiYgIWVycm9yICYmIDxkaXY+UmVxdWVzdGluZyBhY2Nlc3MuLi48L2Rpdj59XG4gICAgICAgICAgICB7c3RhdGUgJiYgIXN0YXRlLmhhc0FjY2VzcyAmJiA8ZGl2IGNsYXNzTmFtZT17Y3NzLnZib3goOCl9PlxuICAgICAgICAgICAgICAgIDxkaXY+VGhpcyBtYWNoaW5lICh7c3RhdGUubWFjaGluZUlkfSwgaXAge3N0YXRlLmlwfSkgZG9lcyBOT1QgaGF2ZSBhY2Nlc3MgeWV0LjwvZGl2PlxuICAgICAgICAgICAgICAgIDxkaXY+QW4gYWNjZXNzIHJlcXVlc3QgaGFzIGJlZW4gbWFkZS4gVG8gZ3JhbnQgaXQsIHJ1biB0aGlzIGNvbW1hbmQ6PC9kaXY+XG4gICAgICAgICAgICAgICAge3N0YXRlLmdyYW50QWNjZXNzQ29tbWFuZCAmJiA8Q29weWFibGVDb21tYW5kIGNvbW1hbmQ9e3N0YXRlLmdyYW50QWNjZXNzQ29tbWFuZH0gLz59XG4gICAgICAgICAgICAgICAgPGRpdj5UaGlzIHBhZ2UgcmVjaGVja3MgZXZlcnkge1JFRlJFU0hfSU5URVJWQUwgLyAxMDAwfSBzZWNvbmRzLjwvZGl2PlxuICAgICAgICAgICAgPC9kaXY+fVxuICAgICAgICAgICAge3N0YXRlICYmIHN0YXRlLmhhc0FjY2VzcyAmJiA8ZGl2IGNsYXNzTmFtZT17Y3NzLnZib3goMTYpfT5cbiAgICAgICAgICAgICAgICA8ZGl2PlRoaXMgbWFjaGluZSAoe3N0YXRlLm1hY2hpbmVJZH0sIGlwIHtzdGF0ZS5pcH0pIGhhcyBhY2Nlc3MuPC9kaXY+XG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9e2Nzcy52Ym94KDYpfT5cbiAgICAgICAgICAgICAgICAgICAgPGRpdj5NYWNoaW5lcyB3aXRoIGFjY2Vzczo8L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAgPHRhYmxlPlxuICAgICAgICAgICAgICAgICAgICAgICAgPHRoZWFkPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRoIGNsYXNzTmFtZT17Y3NzLnBhZDIoOCwgMikudGV4dEFsaWduKFwibGVmdFwiKX0+TWFjaGluZTwvdGg+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0aCBjbGFzc05hbWU9e2Nzcy5wYWQyKDgsIDIpLnRleHRBbGlnbihcImxlZnRcIil9PklQPC90aD5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRoIGNsYXNzTmFtZT17Y3NzLnBhZDIoOCwgMikudGV4dEFsaWduKFwibGVmdFwiKX0+R3JhbnRlZDwvdGg+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj5cbiAgICAgICAgICAgICAgICAgICAgICAgIDwvdGhlYWQ+XG4gICAgICAgICAgICAgICAgICAgICAgICA8dGJvZHk+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgeyhzdGF0ZS50cnVzdGVkTWFjaGluZXMgfHwgW10pLm1hcChtID0+IDx0ciBrZXk9e20ubWFjaGluZUlkfT5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGNsYXNzTmFtZT17Y3NzLnBhZDIoOCwgMil9PnttLm1hY2hpbmVJZH08L3RkPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgY2xhc3NOYW1lPXtjc3MucGFkMig4LCAyKX0+e20uaXB9PC90ZD5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkIGNsYXNzTmFtZT17Y3NzLnBhZDIoOCwgMil9PntuZXcgRGF0ZShtLnRpbWUpLnRvTG9jYWxlU3RyaW5nKCl9PC90ZD5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPil9XG4gICAgICAgICAgICAgICAgICAgICAgICA8L3Rib2R5PlxuICAgICAgICAgICAgICAgICAgICA8L3RhYmxlPlxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPXtjc3MudmJveCg2KX0+XG4gICAgICAgICAgICAgICAgICAgIDxkaXY+QXBwcm92ZSByZXF1ZXN0PC9kaXY+XG4gICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPXtjc3MuaGJveCg4KS5hbGlnbkl0ZW1zKFwiY2VudGVyXCIpfT5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyPVwiaXBcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlPXtzeW5jZWQubG9va3VwSXB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb25JbnB1dD17ZSA9PiB7IHN5bmNlZC5sb29rdXBJcCA9IChlLmN1cnJlbnRUYXJnZXQgYXMgSFRNTElucHV0RWxlbWVudCkudmFsdWU7IH19XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb25LZXlEb3duPXtlID0+IHsgaWYgKGUua2V5ID09PSBcIkVudGVyXCIpIHZvaWQgdGhpcy5sb29rdXBJUCgpOyB9fVxuICAgICAgICAgICAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxidXR0b24gZGlzYWJsZWQ9e3N5bmNlZC5sb29raW5nIHx8ICFzeW5jZWQubG9va3VwSXAudHJpbSgpfSBvbkNsaWNrPXt0aGlzLmxvb2t1cElQfT5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWFyY2hcbiAgICAgICAgICAgICAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAge3N5bmNlZC5sb29rdXBFcnJvciAmJiA8ZGl2PkVycm9yOiB7c3luY2VkLmxvb2t1cEVycm9yfTwvZGl2Pn1cbiAgICAgICAgICAgICAgICAgICAge3N5bmNlZC5sb29rdXBSZXN1bHRzICYmIHN5bmNlZC5sb29rdXBSZXN1bHRzLnJlcXVlc3RzLmxlbmd0aCA9PT0gMCAmJiA8ZGl2PlxuICAgICAgICAgICAgICAgICAgICAgICAgTm8gcGVuZGluZyByZXF1ZXN0cyBmb3Ige3N5bmNlZC5sb29rdXBSZXN1bHRzLmlwfSBvbiB0aGlzIGFjY291bnQuXG4gICAgICAgICAgICAgICAgICAgIDwvZGl2Pn1cbiAgICAgICAgICAgICAgICAgICAge3N5bmNlZC5sb29rdXBSZXN1bHRzICYmIHN5bmNlZC5sb29rdXBSZXN1bHRzLnJlcXVlc3RzLmxlbmd0aCA+IDAgJiYgPHRhYmxlPlxuICAgICAgICAgICAgICAgICAgICAgICAgPHRoZWFkPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRoIGNsYXNzTmFtZT17Y3NzLnBhZDIoOCwgMikudGV4dEFsaWduKFwibGVmdFwiKX0+TWFjaGluZTwvdGg+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0aCBjbGFzc05hbWU9e2Nzcy5wYWQyKDgsIDIpLnRleHRBbGlnbihcImxlZnRcIil9PklQPC90aD5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRoIGNsYXNzTmFtZT17Y3NzLnBhZDIoOCwgMikudGV4dEFsaWduKFwibGVmdFwiKX0+UmVxdWVzdGVkPC90aD5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRoIGNsYXNzTmFtZT17Y3NzLnBhZDIoOCwgMikudGV4dEFsaWduKFwibGVmdFwiKX0+PC90aD5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPlxuICAgICAgICAgICAgICAgICAgICAgICAgPC90aGVhZD5cbiAgICAgICAgICAgICAgICAgICAgICAgIDx0Ym9keT5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7c3luY2VkLmxvb2t1cFJlc3VsdHMucmVxdWVzdHMubWFwKHIgPT4gPHRyIGtleT17ci5yZXF1ZXN0SWR9PlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgY2xhc3NOYW1lPXtjc3MucGFkMig4LCAyKX0+e3IubWFjaGluZUlkfTwvdGQ+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCBjbGFzc05hbWU9e2Nzcy5wYWQyKDgsIDIpfT57ci5pcH08L3RkPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgY2xhc3NOYW1lPXtjc3MucGFkMig4LCAyKX0+e25ldyBEYXRlKHIudGltZSkudG9Mb2NhbGVTdHJpbmcoKX08L3RkPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgY2xhc3NOYW1lPXtjc3MucGFkMig4LCAyKX0+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8YnV0dG9uIGRpc2FibGVkPXshIXN5bmNlZC5ncmFudGluZ30gb25DbGljaz17YXN5bmMgKCkgPT4gdGhpcy5hcHByb3ZlKHIpfT5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7c3luY2VkLmdyYW50aW5nID09PSByLnJlcXVlc3RJZCAmJiBcIkFwcHJvdmluZy4uLlwiIHx8IFwiQXBwcm92ZVwifVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4pfVxuICAgICAgICAgICAgICAgICAgICAgICAgPC90Ym9keT5cbiAgICAgICAgICAgICAgICAgICAgPC90YWJsZT59XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8L2Rpdj59XG4gICAgICAgIDwvZGl2PjtcbiAgICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIG1haW4oKSB7XG4gICAgaWYgKGlzTm9kZSgpKSByZXR1cm47XG4gICAgcHJlYWN0LnJlbmRlcig8QWNjZXNzUGFnZSAvPiwgZG9jdW1lbnQuYm9keSk7XG59XG5cbm1haW4oKS5jYXRjaChjb25zb2xlLmVycm9yKTtcbiJdfQ=//=
|
|
222
|
+
/* _JS_SOURCE_HASH = "d43f249567654f23591587d34655a51c9c544bab51526debcd47389968cadb82"; */
|