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,797 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule && mod.default) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
|
|
6
|
+
//exports.getArchivesBackblazePublic = exports.getArchivesBackblazePublicImmutable = exports.getArchivesBackblazePrivateImmutable = exports.getArchivesBackblaze = exports.ArchivesBackblaze = void 0;
|
|
7
|
+
const caching_1 = require("socket-function/src/caching");
|
|
8
|
+
const misc_1 = require("socket-function/src/misc");
|
|
9
|
+
const batching_1 = require("socket-function/src/batching");
|
|
10
|
+
const format_1 = require("socket-function/src/formatting/format");
|
|
11
|
+
const logColors_1 = require("socket-function/src/formatting/logColors");
|
|
12
|
+
const dns_1 = __importDefault(require("dns"));
|
|
13
|
+
const getSecret_1 = require("../misc/getSecret");
|
|
14
|
+
const https_1 = require("socket-function/src/https");
|
|
15
|
+
const IArchives_1 = require("./IArchives");
|
|
16
|
+
let backblazeCreds = (0, caching_1.lazy)(async () => {
|
|
17
|
+
let keyId = await (0, getSecret_1.getSecret)("backblaze.json.applicationKeyId");
|
|
18
|
+
let key = await (0, getSecret_1.getSecret)("backblaze.json.applicationKey");
|
|
19
|
+
return {
|
|
20
|
+
applicationKeyId: keyId,
|
|
21
|
+
applicationKey: key,
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
const getAPI = (0, caching_1.lazy)(async () => {
|
|
25
|
+
let creds = await backblazeCreds();
|
|
26
|
+
// NOTE: On errors, our retry code resets this lazy, so we DO get new authorize when needed.
|
|
27
|
+
// TODO: Maybe we should get new authorization periodically at well?
|
|
28
|
+
let authorizeRaw = await (0, https_1.httpsRequest)("https://api.backblazeb2.com/b2api/v2/b2_authorize_account", undefined, "GET", undefined, {
|
|
29
|
+
headers: {
|
|
30
|
+
Authorization: "Basic " + Buffer.from(creds.applicationKeyId + ":" + creds.applicationKey).toString("base64"),
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
let auth = JSON.parse(authorizeRaw.toString());
|
|
34
|
+
function createB2Function(name, type, noAccountId) {
|
|
35
|
+
return async (arg) => {
|
|
36
|
+
if (!noAccountId) {
|
|
37
|
+
arg = { accountId: auth.accountId, ...arg };
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
let url = auth.apiUrl + "/b2api/v2/" + name;
|
|
41
|
+
let result = await (0, https_1.httpsRequest)(url, Buffer.from(JSON.stringify(arg)), type, undefined, {
|
|
42
|
+
headers: {
|
|
43
|
+
Authorization: auth.authorizationToken,
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
return JSON.parse(result.toString());
|
|
47
|
+
}
|
|
48
|
+
catch (e) {
|
|
49
|
+
throw new Error(`Error in ${name}, arg ${JSON.stringify(arg).slice(0, 1000)}: ${e.stack}`);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const createBucket = createB2Function("b2_create_bucket", "POST");
|
|
54
|
+
const updateBucket = createB2Function("b2_update_bucket", "POST");
|
|
55
|
+
// https://www.backblaze.com/apidocs/b2-update-bucket
|
|
56
|
+
// TODO: b2_update_bucket, so we can update CORS, etc
|
|
57
|
+
const listBuckets = createB2Function("b2_list_buckets", "POST");
|
|
58
|
+
function encodePath(path) {
|
|
59
|
+
// Preserve slashes, but encode everything else
|
|
60
|
+
path = path.split("/").map(encodeURIComponent).join("/");
|
|
61
|
+
if (path.startsWith("/"))
|
|
62
|
+
path = "%2F" + path.slice(1);
|
|
63
|
+
if (path.endsWith("/"))
|
|
64
|
+
path = path.slice(0, -1) + "%2F";
|
|
65
|
+
// NOTE: For some reason, this won't render in the web UI correctly. BUT, it'll
|
|
66
|
+
// work get get/set and find
|
|
67
|
+
// - ALSO, it seems to add duplicate files? This might also be a web UI thing. It
|
|
68
|
+
// seems to work though.
|
|
69
|
+
while (path.includes("//")) {
|
|
70
|
+
path = path.replaceAll("//", "/%2F");
|
|
71
|
+
}
|
|
72
|
+
return path;
|
|
73
|
+
}
|
|
74
|
+
async function downloadFileByName(config) {
|
|
75
|
+
let fileName = encodePath(config.fileName);
|
|
76
|
+
let result = await (0, https_1.httpsRequest)(auth.apiUrl + "/file/" + config.bucketName + "/" + fileName, Buffer.from(JSON.stringify({
|
|
77
|
+
accountId: auth.accountId,
|
|
78
|
+
responseType: "arraybuffer",
|
|
79
|
+
})), "GET", undefined, {
|
|
80
|
+
headers: Object.fromEntries(Object.entries({
|
|
81
|
+
Authorization: auth.authorizationToken,
|
|
82
|
+
"Content-Type": "application/json",
|
|
83
|
+
Range: config.range ? `bytes=${config.range.start}-${config.range.end - 1}` : undefined,
|
|
84
|
+
}).filter(x => x[1] !== undefined)),
|
|
85
|
+
});
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
// Oh... apparently, we can't reuse these? Huh...
|
|
89
|
+
const getUploadURL = (async (bucketId) => {
|
|
90
|
+
//setTimeout(() => getUploadURL.clear(bucketId), timeInHour * 1);
|
|
91
|
+
let getUploadUrlRaw = await (0, https_1.httpsRequest)(auth.apiUrl + "/b2api/v2/b2_get_upload_url?bucketId=" + bucketId, undefined, "GET", undefined, {
|
|
92
|
+
headers: {
|
|
93
|
+
Authorization: auth.authorizationToken,
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
return JSON.parse(getUploadUrlRaw.toString());
|
|
97
|
+
});
|
|
98
|
+
async function uploadFile(config) {
|
|
99
|
+
let getUploadUrl = await getUploadURL(config.bucketId);
|
|
100
|
+
await (0, https_1.httpsRequest)(getUploadUrl.uploadUrl, config.data, "POST", undefined, {
|
|
101
|
+
headers: {
|
|
102
|
+
Authorization: getUploadUrl.authorizationToken,
|
|
103
|
+
"X-Bz-File-Name": encodePath(config.fileName),
|
|
104
|
+
"Content-Type": "b2/x-auto",
|
|
105
|
+
"X-Bz-Content-Sha1": "do_not_verify",
|
|
106
|
+
"Content-Length": config.data.length + "",
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
const hideFile = createB2Function("b2_hide_file", "POST", "noAccountId");
|
|
111
|
+
const getFileInfo = createB2Function("b2_get_file_info", "POST", "noAccountId");
|
|
112
|
+
const listFileNames = createB2Function("b2_list_file_names", "POST", "noAccountId");
|
|
113
|
+
const copyFile = createB2Function("b2_copy_file", "POST", "noAccountId");
|
|
114
|
+
const startLargeFile = createB2Function("b2_start_large_file", "POST", "noAccountId");
|
|
115
|
+
// Apparently we can't reuse these?
|
|
116
|
+
const getUploadPartURL = (async (fileId) => {
|
|
117
|
+
let uploadPartRaw = await (0, https_1.httpsRequest)(auth.apiUrl + "/b2api/v2/b2_get_upload_part_url?fileId=" + fileId, undefined, "GET", undefined, {
|
|
118
|
+
headers: {
|
|
119
|
+
Authorization: auth.authorizationToken,
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
return JSON.parse(uploadPartRaw.toString());
|
|
123
|
+
});
|
|
124
|
+
async function uploadPart(config) {
|
|
125
|
+
let uploadPart = await getUploadPartURL(config.fileId);
|
|
126
|
+
let result = await (0, https_1.httpsRequest)(uploadPart.uploadUrl, config.data, "POST", undefined, {
|
|
127
|
+
headers: {
|
|
128
|
+
Authorization: uploadPart.authorizationToken,
|
|
129
|
+
"X-Bz-Part-Number": config.partNumber + "",
|
|
130
|
+
"X-Bz-Content-Sha1": config.sha1,
|
|
131
|
+
"Content-Length": config.data.length + "",
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
return JSON.parse(result.toString());
|
|
135
|
+
}
|
|
136
|
+
const finishLargeFile = createB2Function("b2_finish_large_file", "POST", "noAccountId");
|
|
137
|
+
const cancelLargeFile = createB2Function("b2_cancel_large_file", "POST", "noAccountId");
|
|
138
|
+
const getDownloadAuthorization = createB2Function("b2_get_download_authorization", "POST", "noAccountId");
|
|
139
|
+
async function getDownloadURL(path) {
|
|
140
|
+
if (!path.startsWith("/")) {
|
|
141
|
+
path = "/" + path;
|
|
142
|
+
}
|
|
143
|
+
return auth.downloadUrl + path;
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
createBucket,
|
|
147
|
+
updateBucket,
|
|
148
|
+
listBuckets,
|
|
149
|
+
downloadFileByName,
|
|
150
|
+
uploadFile,
|
|
151
|
+
hideFile,
|
|
152
|
+
getFileInfo,
|
|
153
|
+
listFileNames,
|
|
154
|
+
copyFile,
|
|
155
|
+
startLargeFile,
|
|
156
|
+
uploadPart,
|
|
157
|
+
finishLargeFile,
|
|
158
|
+
cancelLargeFile,
|
|
159
|
+
getDownloadAuthorization,
|
|
160
|
+
getDownloadURL,
|
|
161
|
+
apiUrl: auth.apiUrl,
|
|
162
|
+
allowed: auth.allowed,
|
|
163
|
+
};
|
|
164
|
+
});
|
|
165
|
+
class ArchivesBackblaze {
|
|
166
|
+
constructor(config) {
|
|
167
|
+
this.config = config;
|
|
168
|
+
this.bucketName = this.config.bucketName.replaceAll(/[^\w\d]/g, "-");
|
|
169
|
+
this.bucketId = "";
|
|
170
|
+
this.logging = false;
|
|
171
|
+
this.getBucketAPI = (0, caching_1.lazy)(async () => {
|
|
172
|
+
var _a, _b;
|
|
173
|
+
let api = await getAPI();
|
|
174
|
+
let cacheTime = (_a = this.config.cacheTime) !== null && _a !== void 0 ? _a : 0;
|
|
175
|
+
if (this.config.immutable) {
|
|
176
|
+
cacheTime = IArchives_1.IMMUTABLE_CACHE_TIME;
|
|
177
|
+
}
|
|
178
|
+
// ALWAYS set access control, as we can make urls for private buckets with getDownloadAuthorization
|
|
179
|
+
let desiredCorsRules = [{
|
|
180
|
+
corsRuleName: "allowAll",
|
|
181
|
+
allowedOrigins: (_b = this.config.allowedOrigins) !== null && _b !== void 0 ? _b : ["https"],
|
|
182
|
+
allowedOperations: ["b2_download_file_by_id", "b2_download_file_by_name"],
|
|
183
|
+
allowedHeaders: ["range"],
|
|
184
|
+
exposeHeaders: ["x-bz-content-sha1"],
|
|
185
|
+
maxAgeSeconds: cacheTime / 1000,
|
|
186
|
+
}];
|
|
187
|
+
let bucketInfo = {};
|
|
188
|
+
if (cacheTime) {
|
|
189
|
+
bucketInfo["cache-control"] = `max-age=${cacheTime / 1000}`;
|
|
190
|
+
}
|
|
191
|
+
let exists = false;
|
|
192
|
+
let retries = 0;
|
|
193
|
+
while (true) {
|
|
194
|
+
try {
|
|
195
|
+
await api.createBucket({
|
|
196
|
+
bucketName: this.bucketName,
|
|
197
|
+
bucketType: this.config.public ? "allPublic" : "allPrivate",
|
|
198
|
+
lifecycleRules: [{
|
|
199
|
+
"daysFromUploadingToHiding": null,
|
|
200
|
+
// Keep files for 7 days, which should be enough time to recover accidental hiding.
|
|
201
|
+
"daysFromHidingToDeleting": 7,
|
|
202
|
+
"fileNamePrefix": ""
|
|
203
|
+
}],
|
|
204
|
+
corsRules: desiredCorsRules,
|
|
205
|
+
bucketInfo
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
catch (e) {
|
|
209
|
+
if (!e.stack.includes(`"duplicate_bucket_name"`)) {
|
|
210
|
+
if (retries < 3) {
|
|
211
|
+
console.error(`Backblaze create bucket failed, retrying in 5s: ${e.stack}`);
|
|
212
|
+
await (0, batching_1.delay)(5000);
|
|
213
|
+
retries++;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
throw e;
|
|
217
|
+
}
|
|
218
|
+
exists = true;
|
|
219
|
+
}
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
let bucketList = await api.listBuckets({
|
|
223
|
+
bucketName: this.bucketName,
|
|
224
|
+
});
|
|
225
|
+
if (bucketList.buckets.length === 0) {
|
|
226
|
+
throw new Error(`Bucket name "${this.bucketName}" is being used by someone else. Bucket names have to be globally unique. Try a different name until you find a free one.`);
|
|
227
|
+
}
|
|
228
|
+
this.bucketId = bucketList.buckets[0].bucketId;
|
|
229
|
+
if (exists) {
|
|
230
|
+
let bucket = bucketList.buckets[0];
|
|
231
|
+
function normalize(obj) {
|
|
232
|
+
let kvps = Object.entries(obj);
|
|
233
|
+
(0, misc_1.sort)(kvps, x => x[0]);
|
|
234
|
+
return Object.fromEntries(kvps);
|
|
235
|
+
}
|
|
236
|
+
function orderIndependentEqual(lhs, rhs) {
|
|
237
|
+
return JSON.stringify(normalize(lhs)) === JSON.stringify(normalize(rhs));
|
|
238
|
+
}
|
|
239
|
+
function orderIndependentEqualArray(lhs, rhs) {
|
|
240
|
+
if (lhs.length !== rhs.length)
|
|
241
|
+
return false;
|
|
242
|
+
for (let i = 0; i < lhs.length; i++) {
|
|
243
|
+
if (!orderIndependentEqual(lhs[i], rhs[i]))
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
return true;
|
|
247
|
+
}
|
|
248
|
+
if (!orderIndependentEqualArray(bucket.corsRules, desiredCorsRules)
|
|
249
|
+
|| !orderIndependentEqual(bucket.bucketInfo, bucketInfo)) {
|
|
250
|
+
console.log((0, logColors_1.magenta)(`Updating CORS rules for ${this.bucketName}`), bucket.corsRules, desiredCorsRules);
|
|
251
|
+
await api.updateBucket({
|
|
252
|
+
accountId: bucket.accountId,
|
|
253
|
+
bucketId: bucket.bucketId,
|
|
254
|
+
bucketType: bucket.bucketType,
|
|
255
|
+
lifecycleRules: bucket.lifecycleRules,
|
|
256
|
+
corsRules: desiredCorsRules,
|
|
257
|
+
bucketInfo: bucketInfo,
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return api;
|
|
262
|
+
});
|
|
263
|
+
// Keep track of when we last reset because of a 503
|
|
264
|
+
this.last503Reset = 0;
|
|
265
|
+
// Get the api, to setup cors
|
|
266
|
+
void this.getBucketAPI();
|
|
267
|
+
}
|
|
268
|
+
enableLogging() {
|
|
269
|
+
this.logging = true;
|
|
270
|
+
}
|
|
271
|
+
log(text) {
|
|
272
|
+
if (!this.logging)
|
|
273
|
+
return;
|
|
274
|
+
console.log(text);
|
|
275
|
+
}
|
|
276
|
+
getDebugName() {
|
|
277
|
+
return "backblaze/" + this.config.bucketName;
|
|
278
|
+
}
|
|
279
|
+
// IMPORTANT! We must always CATCH AROUND the apiRetryLogic, NEVER inside of fnc. Otherwise we won't
|
|
280
|
+
// be able to recreate the auth token.
|
|
281
|
+
// `context` is a short label (verb + file path) included in every retry/error log so a stuck
|
|
282
|
+
// silent-retry loop is identifiable from the logs.
|
|
283
|
+
async apiRetryLogic(context, fnc, retries = 3) {
|
|
284
|
+
let api;
|
|
285
|
+
try {
|
|
286
|
+
api = await this.getBucketAPI();
|
|
287
|
+
return await fnc(api);
|
|
288
|
+
}
|
|
289
|
+
catch (err) {
|
|
290
|
+
if (retries <= 0)
|
|
291
|
+
throw err;
|
|
292
|
+
// If it's a 503 and it's been a minute since we last reset, then Wait and reset.
|
|
293
|
+
if ((err.stack.includes(`"status": 503`)
|
|
294
|
+
|| err.stack.includes(`"service_unavailable"`)
|
|
295
|
+
|| err.stack.includes(`"internal_error"`)
|
|
296
|
+
|| err.stack.includes(`ENOBUFS`)) && Date.now() - this.last503Reset > 60 * 1000) {
|
|
297
|
+
// Backblaze is so flaky that we're just going to warn here.
|
|
298
|
+
console.warn(`[${context}] Backblaze error, waiting and resetting: ${err.message}`);
|
|
299
|
+
this.log(`[${context}] Backblaze error, waiting and resetting: ${err.message}`);
|
|
300
|
+
this.currentReset = this.currentReset || (async () => {
|
|
301
|
+
await (0, batching_1.delay)(10 * 1000);
|
|
302
|
+
// We check again in case, and in the very likely case that this is being run in parallel, we only want to reset once.
|
|
303
|
+
if (Date.now() - this.last503Reset > 60 * 1000) {
|
|
304
|
+
this.log(`[${context}] Resetting getAPI and getBucketAPI: ${err.message}`);
|
|
305
|
+
this.last503Reset = Date.now();
|
|
306
|
+
getAPI.reset();
|
|
307
|
+
this.getBucketAPI.reset();
|
|
308
|
+
}
|
|
309
|
+
})().finally(() => this.currentReset = undefined);
|
|
310
|
+
await this.currentReset;
|
|
311
|
+
return this.apiRetryLogic(context, fnc, retries - 1);
|
|
312
|
+
}
|
|
313
|
+
// If the error is that the authorization token is invalid, reset getBucketAPI and getAPI
|
|
314
|
+
// If the error is that the bucket isn't found, reset getBucketAPI
|
|
315
|
+
if (err.stack.includes(`"expired_auth_token"`)) {
|
|
316
|
+
this.log(`[${context}] Authorization token expired`);
|
|
317
|
+
getAPI.reset();
|
|
318
|
+
this.getBucketAPI.reset();
|
|
319
|
+
return this.apiRetryLogic(context, fnc, retries - 1);
|
|
320
|
+
}
|
|
321
|
+
if (err.stack.includes(`no tomes available`)
|
|
322
|
+
|| err.stack.includes(`ETIMEDOUT`)
|
|
323
|
+
|| err.stack.includes(`socket hang up`)
|
|
324
|
+
// Eh... this might be bad, but... I think we just get random 400 errors. If this spams errors,
|
|
325
|
+
// we can remove this line.
|
|
326
|
+
|| err.stack.includes(`400 Bad Request`)
|
|
327
|
+
|| err.stack.includes(`getaddrinfo ENOTFOUND`)
|
|
328
|
+
|| err.stack.includes(`ECONNRESET`)
|
|
329
|
+
|| err.stack.includes(`ECONNREFUSED`)
|
|
330
|
+
|| err.stack.includes(`ENOBUFS`)) {
|
|
331
|
+
console.warn(`[${context}] Retrying in 5s: ${err.message}`);
|
|
332
|
+
this.log(`[${context}] ${err.message} retrying in 5s`);
|
|
333
|
+
await (0, batching_1.delay)(5000);
|
|
334
|
+
return this.apiRetryLogic(context, fnc, retries - 1);
|
|
335
|
+
}
|
|
336
|
+
if (err.stack.includes(`getaddrinfo ENOTFOUND`)) {
|
|
337
|
+
if (api) {
|
|
338
|
+
let urlObj = new URL(api.apiUrl);
|
|
339
|
+
let hostname = urlObj.hostname;
|
|
340
|
+
let lookupAddresses = await new Promise(resolve => {
|
|
341
|
+
dns_1.default.lookup(hostname, (err, addresses) => {
|
|
342
|
+
resolve(addresses);
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
let resolveAddresses = await new Promise(resolve => {
|
|
346
|
+
dns_1.default.resolve4(hostname, (err, addresses) => {
|
|
347
|
+
resolve(addresses);
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
console.error(`[${context}] getaddrinfo ENOTFOUND ${hostname}`, { lookupAddresses, resolveAddresses, apiUrl: api.apiUrl, fullError: err.stack });
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
throw err;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
async get(fileName, config) {
|
|
357
|
+
let downloading = true;
|
|
358
|
+
try {
|
|
359
|
+
let time = Date.now();
|
|
360
|
+
const downloadPoll = () => {
|
|
361
|
+
if (!downloading)
|
|
362
|
+
return;
|
|
363
|
+
this.log(`Backblaze download in progress ${fileName}`);
|
|
364
|
+
setTimeout(downloadPoll, 5000);
|
|
365
|
+
};
|
|
366
|
+
setTimeout(downloadPoll, 5000);
|
|
367
|
+
let result = await this.apiRetryLogic(`get ${fileName}`, async (api) => {
|
|
368
|
+
let range = config === null || config === void 0 ? void 0 : config.range;
|
|
369
|
+
if (range) {
|
|
370
|
+
let fileInfo = await this.getInfo(fileName);
|
|
371
|
+
if (!fileInfo)
|
|
372
|
+
throw new Error(`File ${fileName} not found`);
|
|
373
|
+
let rangeStart = range.start;
|
|
374
|
+
let rangeEnd = Math.min(range.end, fileInfo.size);
|
|
375
|
+
// NOTE: I think if we request nothing, it confuses Backblaze and ends up giving us the entire file.
|
|
376
|
+
if (rangeEnd <= rangeStart)
|
|
377
|
+
return Buffer.alloc(0);
|
|
378
|
+
let result = await api.downloadFileByName({
|
|
379
|
+
bucketName: this.bucketName,
|
|
380
|
+
fileName,
|
|
381
|
+
range: { start: rangeStart, end: rangeEnd },
|
|
382
|
+
});
|
|
383
|
+
if (result.length !== rangeEnd - rangeStart) {
|
|
384
|
+
console.error(`Backblaze range download returned the wrong number of bytes. Tried to get ${rangeStart}-${rangeEnd}, but received ${rangeStart}-${rangeStart + result.length}. For file: ${fileName}`);
|
|
385
|
+
}
|
|
386
|
+
return result;
|
|
387
|
+
}
|
|
388
|
+
return await api.downloadFileByName({
|
|
389
|
+
bucketName: this.bucketName,
|
|
390
|
+
fileName,
|
|
391
|
+
});
|
|
392
|
+
});
|
|
393
|
+
let timeStr = (0, format_1.formatTime)(Date.now() - time);
|
|
394
|
+
let rateStr = (0, format_1.formatNumber)(result.length / (Date.now() - time) * 1000) + "B/s";
|
|
395
|
+
this.log(`backblaze download (${(0, format_1.formatNumber)(result.length)}B${(config === null || config === void 0 ? void 0 : config.range) && `, ${(0, format_1.formatNumber)(config.range.start)} - ${(0, format_1.formatNumber)(config.range.end)}` || ""}) in ${timeStr} (${rateStr}, ${fileName})`);
|
|
396
|
+
return result;
|
|
397
|
+
}
|
|
398
|
+
catch (e) {
|
|
399
|
+
this.log(`backblaze file does not exist ${fileName}`);
|
|
400
|
+
return undefined;
|
|
401
|
+
}
|
|
402
|
+
finally {
|
|
403
|
+
downloading = false;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
async get2(fileName, config) {
|
|
407
|
+
// B2 downloads don't return the upload time, so this takes a second API call
|
|
408
|
+
let [data, info] = await Promise.all([this.get(fileName, config), this.getInfo(fileName)]);
|
|
409
|
+
if (!data || !info)
|
|
410
|
+
return undefined;
|
|
411
|
+
return { data, writeTime: info.writeTime, size: info.size };
|
|
412
|
+
}
|
|
413
|
+
async getConfig() {
|
|
414
|
+
return {};
|
|
415
|
+
}
|
|
416
|
+
async hasWriteAccess() {
|
|
417
|
+
var _a;
|
|
418
|
+
try {
|
|
419
|
+
let api = await getAPI();
|
|
420
|
+
// B2 v2 documents allowed as a single object; our type says a list - handle both
|
|
421
|
+
let allowedRaw = api.allowed;
|
|
422
|
+
let allowedList = (Array.isArray(allowedRaw) && allowedRaw || [allowedRaw]);
|
|
423
|
+
return allowedList.some(allowed => allowed.capabilities.includes("writeFiles")
|
|
424
|
+
&& (!allowed.bucketName || allowed.bucketName === this.bucketName));
|
|
425
|
+
}
|
|
426
|
+
catch (e) {
|
|
427
|
+
// No / invalid credentials
|
|
428
|
+
this.log(`backblaze hasWriteAccess check failed: ${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`);
|
|
429
|
+
return false;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
async set(fileName, data, config) {
|
|
433
|
+
if (config === null || config === void 0 ? void 0 : config.lastModified) {
|
|
434
|
+
(0, IArchives_1.assertValidLastModified)(config.lastModified);
|
|
435
|
+
let existing = await this.getInfo(fileName);
|
|
436
|
+
// An older write never overwrites a newer one (see IArchives.set). B2 stamps its own
|
|
437
|
+
// upload time, so the exact lastModified is not preserved on the stored file.
|
|
438
|
+
if (existing && config.lastModified < existing.writeTime)
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
this.log(`backblaze upload (${(0, format_1.formatNumber)(data.length)}B) ${fileName}`);
|
|
442
|
+
let f = fileName;
|
|
443
|
+
await this.apiRetryLogic(`uploadFile ${fileName}`, async (api) => {
|
|
444
|
+
await api.uploadFile({ bucketId: this.bucketId, fileName, data: data, });
|
|
445
|
+
});
|
|
446
|
+
let existsChecks = 30;
|
|
447
|
+
while (existsChecks > 0) {
|
|
448
|
+
let exists = await this.getInfo(fileName);
|
|
449
|
+
if (exists)
|
|
450
|
+
break;
|
|
451
|
+
await (0, batching_1.delay)(1000);
|
|
452
|
+
existsChecks--;
|
|
453
|
+
}
|
|
454
|
+
if (existsChecks === 0) {
|
|
455
|
+
let exists = await this.getInfo(fileName);
|
|
456
|
+
console.warn(`File ${fileName}/${f} was uploaded, but could not be found afterwards. Hopefully it was just deleted, very quickly? If backblaze is taking too long for files to propagate, then we might run into issues with the database atomicity.`);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
async del(fileName) {
|
|
460
|
+
this.log(`backblaze delete ${fileName}`);
|
|
461
|
+
try {
|
|
462
|
+
await this.apiRetryLogic(`hideFile ${fileName}`, async (api) => {
|
|
463
|
+
await api.hideFile({ bucketId: this.bucketId, fileName: fileName });
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
catch (e) {
|
|
467
|
+
this.log(`backblaze error in hide, possibly already hidden ${fileName}\n${e.stack}`);
|
|
468
|
+
}
|
|
469
|
+
// NOTE: Deletion SEEMS to work. This DOES break if we delete a file which keeps being recreated,
|
|
470
|
+
// ex, the heartbeat.
|
|
471
|
+
// let existsChecks = 10;
|
|
472
|
+
// while (existsChecks > 0) {
|
|
473
|
+
// let exists = await this.getInfo(fileName);
|
|
474
|
+
// if (!exists) break;
|
|
475
|
+
// await delay(1000);
|
|
476
|
+
// existsChecks--;
|
|
477
|
+
// }
|
|
478
|
+
// if (existsChecks === 0) {
|
|
479
|
+
// let exists = await this.getInfo(fileName);
|
|
480
|
+
// devDebugbreak();
|
|
481
|
+
// console.warn(`File ${fileName} was deleted, but was still found afterwards`);
|
|
482
|
+
// exists = await this.getInfo(fileName);
|
|
483
|
+
// }
|
|
484
|
+
}
|
|
485
|
+
async setLargeFile(config) {
|
|
486
|
+
let onError = [];
|
|
487
|
+
let time = Date.now();
|
|
488
|
+
try {
|
|
489
|
+
let { path } = config;
|
|
490
|
+
// Backblaze requires 5MB chunks. But, larger is more efficient for us.
|
|
491
|
+
const MIN_CHUNK_SIZE = 32 * 1024 * 1024;
|
|
492
|
+
let dataQueue = [];
|
|
493
|
+
async function getNextData() {
|
|
494
|
+
if (dataQueue.length)
|
|
495
|
+
return dataQueue.shift();
|
|
496
|
+
// Get buffers until we get 5MB, OR, end. Backblaze requires this for large files.
|
|
497
|
+
let totalBytes = 0;
|
|
498
|
+
let buffers = [];
|
|
499
|
+
while (totalBytes < MIN_CHUNK_SIZE) {
|
|
500
|
+
let data = await config.getNextData();
|
|
501
|
+
if (!data)
|
|
502
|
+
break;
|
|
503
|
+
totalBytes += data.length;
|
|
504
|
+
buffers.push(data);
|
|
505
|
+
}
|
|
506
|
+
if (!buffers.length)
|
|
507
|
+
return undefined;
|
|
508
|
+
return Buffer.concat(buffers);
|
|
509
|
+
}
|
|
510
|
+
let fileName = path;
|
|
511
|
+
let data = await getNextData();
|
|
512
|
+
if (!(data === null || data === void 0 ? void 0 : data.length))
|
|
513
|
+
return;
|
|
514
|
+
// Backblaze disallows overly small files
|
|
515
|
+
if (data.length < MIN_CHUNK_SIZE) {
|
|
516
|
+
return await this.set(fileName, data);
|
|
517
|
+
}
|
|
518
|
+
// Backblaze disallows less than 2 chunks
|
|
519
|
+
let secondData = await getNextData();
|
|
520
|
+
if (!(secondData === null || secondData === void 0 ? void 0 : secondData.length)) {
|
|
521
|
+
return await this.set(fileName, data);
|
|
522
|
+
}
|
|
523
|
+
// ALSO, if there are two chunks, but one is too small, combine it. This helps allow us never
|
|
524
|
+
// send small chunks.
|
|
525
|
+
if (secondData.length < MIN_CHUNK_SIZE) {
|
|
526
|
+
return await this.set(fileName, Buffer.concat([data, secondData]));
|
|
527
|
+
}
|
|
528
|
+
this.log(`Uploading large file ${config.path}`);
|
|
529
|
+
dataQueue.unshift(data, secondData);
|
|
530
|
+
let uploadInfo = await this.apiRetryLogic(`startLargeFile ${fileName}`, async (api) => {
|
|
531
|
+
return await api.startLargeFile({
|
|
532
|
+
bucketId: this.bucketId,
|
|
533
|
+
fileName: fileName,
|
|
534
|
+
contentType: "b2/x-auto",
|
|
535
|
+
fileInfo: {},
|
|
536
|
+
});
|
|
537
|
+
});
|
|
538
|
+
onError.push(async () => {
|
|
539
|
+
await this.apiRetryLogic(`cancelLargeFile ${fileName}`, async (api) => {
|
|
540
|
+
await api.cancelLargeFile({ fileId: uploadInfo.fileId });
|
|
541
|
+
});
|
|
542
|
+
});
|
|
543
|
+
const LOG_INTERVAL = misc_1.timeInMinute;
|
|
544
|
+
let nextLogTime = Date.now() + LOG_INTERVAL;
|
|
545
|
+
let partNumber = 1;
|
|
546
|
+
let partSha1Array = [];
|
|
547
|
+
let totalBytes = 0;
|
|
548
|
+
while (true) {
|
|
549
|
+
data = await getNextData();
|
|
550
|
+
if (!data)
|
|
551
|
+
break;
|
|
552
|
+
// So... if the next chunk is the last one, combine it with the current one. This
|
|
553
|
+
// prevents ANY uploads from being < the threshold, as apparently the "last part"
|
|
554
|
+
// check in backblaze fails when we have to retry an upload (due to "no tomes available").
|
|
555
|
+
// Well it can't fail if even the last part is > 5MB, now can it!
|
|
556
|
+
// BUT, only if this isn't the first chunk, otherwise we might try to send
|
|
557
|
+
// a single chunk, which we can't do.
|
|
558
|
+
if (partSha1Array.length > 0) {
|
|
559
|
+
let maybeLastData = await getNextData();
|
|
560
|
+
if (maybeLastData) {
|
|
561
|
+
if (maybeLastData.length < MIN_CHUNK_SIZE) {
|
|
562
|
+
// It's the last one, so consume it now
|
|
563
|
+
data = Buffer.concat([data, maybeLastData]);
|
|
564
|
+
}
|
|
565
|
+
else {
|
|
566
|
+
// It's not the last one. Put it back, in case the one AFTER is the last
|
|
567
|
+
// one, in which case we need to merge maybeLastData with the next next data.
|
|
568
|
+
dataQueue.unshift(maybeLastData);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
let sha1 = require("crypto").createHash("sha1");
|
|
573
|
+
sha1.update(data);
|
|
574
|
+
let sha1Hex = sha1.digest("hex");
|
|
575
|
+
partSha1Array.push(sha1Hex);
|
|
576
|
+
await this.apiRetryLogic(`uploadPart#${partNumber} ${fileName}`, async (api) => {
|
|
577
|
+
if (!data)
|
|
578
|
+
throw new Error("Impossible, data is undefined");
|
|
579
|
+
let timeStr = (0, format_1.formatTime)(Date.now() - time);
|
|
580
|
+
let rateStr = (0, format_1.formatNumber)(totalBytes / (Date.now() - time) * 1000) + "B/s";
|
|
581
|
+
this.log(`Uploading large file part ${partNumber}, uploaded ${(0, logColors_1.blue)((0, format_1.formatNumber)(totalBytes) + "B")} in ${(0, logColors_1.blue)(timeStr)} (${(0, logColors_1.blue)(rateStr)}). ${config.path}`);
|
|
582
|
+
totalBytes += data.length;
|
|
583
|
+
await api.uploadPart({
|
|
584
|
+
fileId: uploadInfo.fileId,
|
|
585
|
+
partNumber: partNumber,
|
|
586
|
+
data: data,
|
|
587
|
+
sha1: sha1Hex,
|
|
588
|
+
});
|
|
589
|
+
});
|
|
590
|
+
partNumber++;
|
|
591
|
+
if (Date.now() > nextLogTime) {
|
|
592
|
+
nextLogTime = Date.now() + LOG_INTERVAL;
|
|
593
|
+
let timeStr = (0, format_1.formatTime)(Date.now() - time);
|
|
594
|
+
let rateStr = (0, format_1.formatNumber)(totalBytes / (Date.now() - time) * 1000) + "B/s";
|
|
595
|
+
console.log(`Still uploading large file at ${Date.now()}. Uploaded ${(0, format_1.formatNumber)(totalBytes)}B in ${timeStr} (${rateStr}). ${config.path}`);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
this.log(`Finished uploading large file uploaded ${(0, logColors_1.green)((0, format_1.formatNumber)(totalBytes))}B`);
|
|
599
|
+
await this.apiRetryLogic(`finishLargeFile ${fileName}`, async (api) => {
|
|
600
|
+
await api.finishLargeFile({
|
|
601
|
+
fileId: uploadInfo.fileId,
|
|
602
|
+
partSha1Array: partSha1Array,
|
|
603
|
+
});
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
catch (e) {
|
|
607
|
+
for (let c of onError) {
|
|
608
|
+
try {
|
|
609
|
+
await c();
|
|
610
|
+
}
|
|
611
|
+
catch (e) {
|
|
612
|
+
console.error(`Error during error clean. Ignoring, we will rethrow the original error, path ${config.path}`, e);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
throw new Error(`Error in setLargeFile for ${config.path}: ${e.stack}`);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
async getInfo(fileName) {
|
|
619
|
+
return await this.apiRetryLogic(`getInfo ${fileName}`, async (api) => {
|
|
620
|
+
try {
|
|
621
|
+
// NOTE: Apparently, there's no other way to do this, as the file name does not equal the file ID, and get file info requires the file ID.
|
|
622
|
+
let info = await api.listFileNames({ bucketId: this.bucketId, prefix: fileName, maxFileCount: 10 });
|
|
623
|
+
let file = info.files.find(x => x.fileName === fileName && x.action === "upload");
|
|
624
|
+
if (!file) {
|
|
625
|
+
this.log(`Backblaze file not exists ${fileName}`);
|
|
626
|
+
return undefined;
|
|
627
|
+
}
|
|
628
|
+
this.log(`Backblaze file exists ${fileName}`);
|
|
629
|
+
return {
|
|
630
|
+
writeTime: file.uploadTimestamp,
|
|
631
|
+
size: file.contentLength,
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
catch (e) {
|
|
635
|
+
if (e.stack.includes(`file_not_found`)) {
|
|
636
|
+
this.log(`Backblaze file not exists ${fileName}`);
|
|
637
|
+
return undefined;
|
|
638
|
+
}
|
|
639
|
+
throw e;
|
|
640
|
+
}
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
// For example findFileNames("ips/")
|
|
644
|
+
async find(prefix, config) {
|
|
645
|
+
let result = await this.findInfo(prefix, config);
|
|
646
|
+
return result.map(x => x.path);
|
|
647
|
+
}
|
|
648
|
+
async findInfo(prefix, config) {
|
|
649
|
+
return await this.apiRetryLogic(`findInfo ${prefix}`, async (api) => {
|
|
650
|
+
if (!(config === null || config === void 0 ? void 0 : config.shallow) && (config === null || config === void 0 ? void 0 : config.type) === "folders") {
|
|
651
|
+
let allFiles = await this.findInfo(prefix);
|
|
652
|
+
let allFolders = new Map();
|
|
653
|
+
for (let { path, createTime, size } of allFiles) {
|
|
654
|
+
let folder = path.split("/").slice(0, -1).join("/");
|
|
655
|
+
if (!folder)
|
|
656
|
+
continue;
|
|
657
|
+
allFolders.set(folder, { path: folder, createTime, size });
|
|
658
|
+
}
|
|
659
|
+
return Array.from(allFolders.values());
|
|
660
|
+
}
|
|
661
|
+
let files = new Map();
|
|
662
|
+
let startFileName = "";
|
|
663
|
+
while (true) {
|
|
664
|
+
let result = await api.listFileNames({
|
|
665
|
+
bucketId: this.bucketId,
|
|
666
|
+
prefix: prefix,
|
|
667
|
+
startFileName,
|
|
668
|
+
maxFileCount: 1000,
|
|
669
|
+
delimiter: (config === null || config === void 0 ? void 0 : config.shallow) ? "/" : undefined,
|
|
670
|
+
});
|
|
671
|
+
for (let file of result.files) {
|
|
672
|
+
if (file.action === "upload" && (config === null || config === void 0 ? void 0 : config.type) !== "folders") {
|
|
673
|
+
files.set(file.fileName, { path: file.fileName, createTime: file.uploadTimestamp, size: file.contentLength });
|
|
674
|
+
}
|
|
675
|
+
else if (file.action === "folder" && (config === null || config === void 0 ? void 0 : config.type) === "folders") {
|
|
676
|
+
let folder = file.fileName;
|
|
677
|
+
if (folder.endsWith("/")) {
|
|
678
|
+
folder = folder.slice(0, -1);
|
|
679
|
+
}
|
|
680
|
+
files.set(folder, { path: folder, createTime: file.uploadTimestamp, size: file.contentLength });
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
startFileName = result.nextFileName;
|
|
684
|
+
if (!startFileName)
|
|
685
|
+
break;
|
|
686
|
+
}
|
|
687
|
+
return Array.from(files.values());
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
async assertPathValid(path) {
|
|
691
|
+
let bytes = Buffer.from(path, "utf8");
|
|
692
|
+
if (bytes.length > 1000) {
|
|
693
|
+
throw new Error(`Path too long: ${path.length} characters > 1000 characters. Path: ${path}`);
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
async move(config) {
|
|
697
|
+
let { path, target, targetPath } = config;
|
|
698
|
+
// A self move should NOOP (and definitely not copy, and then delete itself!)
|
|
699
|
+
if (target === this && path === targetPath) {
|
|
700
|
+
this.log(`Backblaze move path to itself. Skipping move, as there is no work to do. ${path}`);
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
if (target instanceof ArchivesBackblaze) {
|
|
704
|
+
let targetBucketId = target.bucketId;
|
|
705
|
+
if (targetBucketId === this.bucketId && path === targetPath)
|
|
706
|
+
return;
|
|
707
|
+
await this.apiRetryLogic(`move ${path} -> ${targetPath}`, async (api) => {
|
|
708
|
+
// Ugh... listing the file name sucks, but... I guess it's still better than
|
|
709
|
+
// downloading and re-uploading the entire file.
|
|
710
|
+
let info = await api.listFileNames({ bucketId: this.bucketId, prefix: path, maxFileCount: 10 });
|
|
711
|
+
let file = info.files.find(x => x.fileName === path);
|
|
712
|
+
if (!file)
|
|
713
|
+
throw new Error(`File not found to move: ${path}`);
|
|
714
|
+
await api.copyFile({
|
|
715
|
+
sourceFileId: file.fileId,
|
|
716
|
+
fileName: targetPath,
|
|
717
|
+
destinationBucketId: targetBucketId,
|
|
718
|
+
});
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
else {
|
|
722
|
+
let data = await this.get(path);
|
|
723
|
+
if (!data)
|
|
724
|
+
throw new Error(`File not found to move: ${path}`);
|
|
725
|
+
await target.set(targetPath, data);
|
|
726
|
+
}
|
|
727
|
+
if (!config.copyInstead) {
|
|
728
|
+
let exists = await this.getInfo(targetPath);
|
|
729
|
+
if (!exists) {
|
|
730
|
+
console.error(`File not found after move. Leaving BOTH files. ${targetPath} was not found. Being moved from ${path}`);
|
|
731
|
+
}
|
|
732
|
+
else {
|
|
733
|
+
await this.del(path);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
async copy(config) {
|
|
738
|
+
return this.move({ ...config, copyInstead: true });
|
|
739
|
+
}
|
|
740
|
+
async getURL(path) {
|
|
741
|
+
return await this.apiRetryLogic(`getURL ${path}`, async (api) => {
|
|
742
|
+
if (path.startsWith("/")) {
|
|
743
|
+
path = path.slice(1);
|
|
744
|
+
}
|
|
745
|
+
return await api.getDownloadURL("file/" + this.bucketName + "/" + path);
|
|
746
|
+
});
|
|
747
|
+
}
|
|
748
|
+
async getDownloadAuthorization(config) {
|
|
749
|
+
var _a;
|
|
750
|
+
return await this.apiRetryLogic(`getDownloadAuthorization ${(_a = config.fileNamePrefix) !== null && _a !== void 0 ? _a : ""}`, async (api) => {
|
|
751
|
+
var _a;
|
|
752
|
+
return await api.getDownloadAuthorization({
|
|
753
|
+
bucketId: this.bucketId,
|
|
754
|
+
fileNamePrefix: (_a = config.fileNamePrefix) !== null && _a !== void 0 ? _a : "",
|
|
755
|
+
...config,
|
|
756
|
+
});
|
|
757
|
+
});
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
exports.ArchivesBackblaze = ArchivesBackblaze;
|
|
761
|
+
/*
|
|
762
|
+
Names should be a UTF-8 string up to 1024 bytes with the following exceptions:
|
|
763
|
+
Character codes below 32 are not allowed.
|
|
764
|
+
DEL characters (127) are not allowed.
|
|
765
|
+
Backslashes are not allowed.
|
|
766
|
+
File names cannot start with /, end with /, or contain //.
|
|
767
|
+
*/
|
|
768
|
+
exports.getArchivesBackblaze = (0, caching_1.cache)((domain) => {
|
|
769
|
+
return new ArchivesBackblaze({ bucketName: domain });
|
|
770
|
+
});
|
|
771
|
+
exports.getArchivesBackblazePrivateImmutable = (0, caching_1.cache)((domain) => {
|
|
772
|
+
return new ArchivesBackblaze({
|
|
773
|
+
bucketName: domain + "-private-immutable",
|
|
774
|
+
immutable: true
|
|
775
|
+
});
|
|
776
|
+
});
|
|
777
|
+
exports.getArchivesBackblazePublicImmutable = (0, caching_1.cache)((domain) => {
|
|
778
|
+
return new ArchivesBackblaze({
|
|
779
|
+
bucketName: domain + "-public-immutable",
|
|
780
|
+
public: true,
|
|
781
|
+
immutable: true,
|
|
782
|
+
allowedOrigins: [`https://${domain}`, `https://127-0-0-1.${domain}:7007`],
|
|
783
|
+
});
|
|
784
|
+
});
|
|
785
|
+
// NOTE: Cache by a minute. This might be a bad idea, but... usually whole reason for public is
|
|
786
|
+
// for cloudflare caching (as otherwise we can just access it through a server), or for large files
|
|
787
|
+
// (which should be cached anyways, and probably even use immutable caching).
|
|
788
|
+
exports.getArchivesBackblazePublic = (0, caching_1.cache)((domain) => {
|
|
789
|
+
return new ArchivesBackblaze({
|
|
790
|
+
bucketName: domain + "-public",
|
|
791
|
+
public: true,
|
|
792
|
+
cacheTime: misc_1.timeInMinute,
|
|
793
|
+
allowedOrigins: [`https://${domain}`, `https://127-0-0-1.${domain}:7007`],
|
|
794
|
+
});
|
|
795
|
+
});
|
|
796
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFja2JsYXplLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiYmFja2JsYXplLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLHlEQUEwRDtBQUcxRCxtREFBa0Y7QUFDbEYsMkRBQXFEO0FBQ3JELGtFQUFpRjtBQUNqRix3RUFBZ0Y7QUFFaEYsOENBQXNCO0FBQ3RCLGlEQUE4QztBQUM5QyxxREFBeUQ7QUFDekQsMkNBQXVHO0FBT3ZHLElBQUksY0FBYyxHQUFHLElBQUEsY0FBSSxFQUFDLEtBQUssSUFBNkIsRUFBRTtJQUMxRCxJQUFJLEtBQUssR0FBRyxNQUFNLElBQUEscUJBQVMsRUFBQyxpQ0FBaUMsQ0FBQyxDQUFDO0lBQy9ELElBQUksR0FBRyxHQUFHLE1BQU0sSUFBQSxxQkFBUyxFQUFDLCtCQUErQixDQUFDLENBQUM7SUFDM0QsT0FBTztRQUNILGdCQUFnQixFQUFFLEtBQUs7UUFDdkIsY0FBYyxFQUFFLEdBQUc7S0FDdEIsQ0FBQztBQUNOLENBQUMsQ0FBQyxDQUFDO0FBQ0gsTUFBTSxNQUFNLEdBQUcsSUFBQSxjQUFJLEVBQUMsS0FBSyxJQUFJLEVBQUU7SUFDM0IsSUFBSSxLQUFLLEdBQUcsTUFBTSxjQUFjLEVBQUUsQ0FBQztJQUVuQyw0RkFBNEY7SUFDNUYsb0VBQW9FO0lBQ3BFLElBQUksWUFBWSxHQUFHLE1BQU0sSUFBQSxvQkFBWSxFQUFDLDJEQUEyRCxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFO1FBQzVILE9BQU8sRUFBRTtZQUNMLGFBQWEsRUFBRSxRQUFRLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsZ0JBQWdCLEdBQUcsR0FBRyxHQUFHLEtBQUssQ0FBQyxjQUFjLENBQUMsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDO1NBQ2hIO0tBQ0osQ0FBQyxDQUFDO0lBRUgsSUFBSSxJQUFJLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxZQUFZLENBQUMsUUFBUSxFQUFFLENB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QUU7SUFDekQsT0FBTyxJQUFJLGlCQUFpQixDQUFDLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUM7QUFDekQsQ0FBQyxDQUFDLENBQUM7QUFDVSxRQUFBLG9DQUFvQyxHQUFHLElBQUEsZUFBSyxFQUFDLENBQUMsTUFBYyxFQUFFLEVBQUU7SUFDekUsT0FBTyxJQUFJLGlCQUFpQixDQUFDO1FBQ3pCLFVBQVUsRUFBRSxNQUFNLEdBQUcsb0JBQW9CO1FBQ3pDLFNBQVMsRUFBRSxJQUFJO0tBQ2xCLENBQUMsQ0FBQztBQUNQLENBQUMsQ0FBQyxDQUFDO0FBQ1UsUUFBQSxtQ0FBbUMsR0FBRyxJQUFBLGVBQUssRUFBQyxDQUFDLE1BQWMsRUFBRSxFQUFFO0lBQ3hFLE9BQU8sSUFBSSxpQkFBaUIsQ0FBQztRQUN6QixVQUFVLEVBQUUsTUFBTSxHQUFHLG1CQUFtQjtRQUN4QyxNQUFNLEVBQUUsSUFBSTtRQUNaLFNBQVMsRUFBRSxJQUFJO1FBQ2YsY0FBYyxFQUFFLENBQUMsV0FBVyxNQUFNLEVBQUUsRUFBRSxxQkFBcUIsTUFBTSxPQUFPLENBQUM7S0FDNUUsQ0FBQyxDQUFDO0FBQ1AsQ0FBQyxDQUFDLENBQUM7QUFFSCwrRkFBK0Y7QUFDL0Ysb0dBQW9HO0FBQ3BHLDhFQUE4RTtBQUNqRSxRQUFBLDBCQUEwQixHQUFHLElBQUEsZUFBSyxFQUFDLENBQUMsTUFBYyxFQUFFLEVBQUU7SUFDL0QsT0FBTyxJQUFJLGlCQUFpQixDQUFDO1FBQ3pCLFVBQVUsRUFBRSxNQUFNLEdBQUcsU0FBUztRQUM5QixNQUFNLEVBQUUsSUFBSTtRQUNaLFNBQVMsRUFBRSxtQkFBWTtRQUN2QixjQUFjLEVBQUUsQ0FBQyxXQUFXLE1BQU0sRUFBRSxFQUFFLHFCQUFxQixNQUFNLE9BQU8sQ0FBQztLQUM1RSxDQUFDLENBQUM7QUFDUCxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGNhY2hlLCBsYXp5IH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9zcmMvY2FjaGluZ1wiO1xuaW1wb3J0IGZzIGZyb20gXCJmc1wiO1xuaW1wb3J0IG9zIGZyb20gXCJvc1wiO1xuaW1wb3J0IHsgaXNOb2RlLCBzb3J0LCB0aW1lSW5Ib3VyLCB0aW1lSW5NaW51dGUgfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy9taXNjXCI7XG5pbXBvcnQgeyBkZWxheSB9IGZyb20gXCJzb2NrZXQtZnVuY3Rpb24vc3JjL2JhdGNoaW5nXCI7XG5pbXBvcnQgeyBmb3JtYXROdW1iZXIsIGZvcm1hdFRpbWUgfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy9mb3JtYXR0aW5nL2Zvcm1hdFwiO1xuaW1wb3J0IHsgYmx1ZSwgZ3JlZW4sIG1hZ2VudGEgfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy9mb3JtYXR0aW5nL2xvZ0NvbG9yc1wiO1xuaW1wb3J0IGRlYnVnYnJlYWsgZnJvbSBcImRlYnVnYnJlYWtcIjtcbmltcG9ydCBkbnMgZnJvbSBcImRuc1wiO1xuaW1wb3J0IHsgZ2V0U2VjcmV0IH0gZnJvbSBcIi4uL21pc2MvZ2V0U2VjcmV0XCI7XG5pbXBvcnQgeyBodHRwc1JlcXVlc3QgfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy9odHRwc1wiO1xuaW1wb3J0IHsgSUFyY2hpdmVzLCBBcmNoaXZlc0NvbmZpZywgYXNzZXJ0VmFsaWRMYXN0TW9kaWZpZWQsIElNTVVUQUJMRV9DQUNIRV9USU1FIH0gZnJvbSBcIi4vSUFyY2hpdmVzXCI7XG5cbnR5cGUgQmFja2JsYXplQ3JlZHMgPSB7XG4gICAgYXBwbGljYXRpb25LZXlJZDogc3RyaW5nO1xuICAgIGFwcGxpY2F0aW9uS2V5OiBzdHJpbmc7XG59O1xuXG5sZXQgYmFja2JsYXplQ3JlZHMgPSBsYXp5KGFzeW5jICgpOiBQcm9taXNlPEJhY2tibGF6ZUNyZWRzPiA9PiB7XG4gICAgbGV0IGtleUlkID0gYXdhaXQgZ2V0U2VjcmV0KFwiYmFja2JsYXplLmpzb24uYXBwbGljYXRpb25LZXlJZFwiKTtcbiAgICBsZXQga2V5ID0gYXdhaXQgZ2V0U2VjcmV0KFwiYmFja2JsYXplLmpzb24uYXBwbGljYXRpb25LZXlcIik7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgYXBwbGljYXRpb25LZXlJZDoga2V5SWQsXG4gICAgICAgIGFwcGxpY2F0aW9uS2V5OiBrZXksXG4gICAgfTtcbn0pO1xuY29uc3QgZ2V0QVBJID0gbGF6eShhc3luYyAoKSA9PiB7XG4gICAgbGV0IGNyZWRzID0gYXdhaXQgYmFja2JsYXplQ3JlZHMoKTtcblxuICAgIC8vIE5PVEU6IE9uIGVycm9ycywgb3VyIHJldHJ5IGNvZGUgcmVzZXRzIHRoaXMgbGF6eSwgc28gd2UgRE8gZ2V0IG5ldyBhdXRob3JpemUgd2hlbiBuZWVkZWQuXG4gICAgLy8gVE9ETzogTWF5YmUgd2Ugc2hvdWxkIGdldCBuZXcgYXV0aG9yaXphdGlvbiBwZXJpb2RpY2FsbHkgYXQgd2VsbD9cbiAgICBsZXQgYXV0aG9yaXplUmF3ID0gYXdhaXQgaHR0cHNSZXF1ZXN0KFwiaHR0cHM6Ly9hcGkuYmFja2JsYXplYjIuY29tL2IyYXBpL3YyL2IyX2F1dGhvcml6ZV9hY2NvdW50XCIsIHVuZGVmaW5lZCwgXCJHRVRcIiwgdW5kZWZpbmVkLCB7XG4gICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgIEF1dGhvcml6YXRpb246IFwiQmFzaWMgXCIgKyBCdWZmZXIuZnJvbShjcmVkcy5hcHBsaWNhdGlvbktleUlkICsgXCI6XCIgKyBjcmVkcy5hcHBsaWNhdGlvbktleSkudG9TdHJpbmcoXCJiYXNlNjRcIiksXG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgIGxldCBhdXRoID0gSlNPTi5wYXJzZShhdXRob3JpemVSYXcudG9TdHJpbmcoKSkgYXMge1xuICAgICAgICBhY2NvdW50SWQ6IHN0cmluZztcbiAgICAgICAgYXV0aG9yaXphdGlvblRva2VuOiBzdHJpbmc7XG4gICAgICAgIGFwaVVybDogc3RyaW5nO1xuICAgICAgICBkb3dubG9hZFVybDogc3RyaW5nO1xuICAgICAgICBhbGxvd2VkOiB7XG4gICAgICAgICAgICBidWNrZXRJZDogc3RyaW5nO1xuICAgICAgICAgICAgYnVja2V0TmFtZTogc3RyaW5nO1xuICAgICAgICAgICAgY2FwYWJpbGl0aWVzOiBzdHJpbmdbXTtcbiAgICAgICAgICAgIG5hbWVQcmVmaXg6IHN0cmluZztcbiAgICAgICAgfVtdO1xuICAgIH07XG5cbiAgICBmdW5jdGlvbiBjcmVhdGVCMkZ1bmN0aW9uPEFyZywgUmVzdWx0PihuYW1lOiBzdHJpbmcsIHR5cGU6IFwiUE9TVFwiIHwgXCJHRVRcIiwgbm9BY2NvdW50SWQ/OiBcIm5vQWNjb3VudElkXCIpOiAoYXJnOiBBcmcpID0+IFByb21pc2U8UmVzdWx0PiB7XG4gICAgICAgIHJldHVybiBhc3luYyAoYXJnOiBBcmcpID0+IHtcbiAgICAgICAgICAgIGlmICghbm9BY2NvdW50SWQpIHtcbiAgICAgICAgICAgICAgICBhcmcgPSB7IGFjY291bnRJZDogYXV0aC5hY2NvdW50SWQsIC4uLmFyZyB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBsZXQgdXJsID0gYXV0aC5hcGlVcmwgKyBcIi9iMmFwaS92Mi9cIiArIG5hbWU7XG4gICAgICAgICAgICAgICAgbGV0IHJlc3VsdCA9IGF3YWl0IGh0dHBzUmVxdWVzdCh1cmwsIEJ1ZmZlci5mcm9tKEpTT04uc3RyaW5naWZ5KGFyZykpLCB0eXBlLCB1bmRlZmluZWQsIHtcbiAgICAgICAgICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAgICAgICAgICAgQXV0aG9yaXphdGlvbjogYXV0aC5hdXRob3JpemF0aW9uVG9rZW4sXG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShyZXN1bHQudG9TdHJpbmcoKSk7XG4gICAgICAgICAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEVycm9yIGluICR7bmFtZX0sIGFyZyAke0pTT04uc3RyaW5naWZ5KGFyZykuc2xpY2UoMCwgMTAwMCl9OiAke2Uuc3RhY2t9YCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgY29uc3QgY3JlYXRlQnVja2V0ID0gY3JlYXRlQjJGdW5jdGlvbjx7XG4gICAgICAgIGJ1Y2tldE5hbWU6IHN0cmluZztcbiAgICAgICAgYnVja2V0VHlwZTogXCJhbGxQcml2YXRlXCIgfCBcImFsbFB1YmxpY1wiO1xuICAgICAgICBsaWZlY3ljbGVSdWxlcz86IGFueVtdO1xuICAgICAgICBjb3JzUnVsZXM/OiB1bmtub3duW107XG4gICAgICAgIGJ1Y2tldEluZm8/OiB7XG4gICAgICAgICAgICBba2V5OiBzdHJpbmddOiB1bmtub3duO1xuICAgICAgICB9O1xuICAgIH0sIHtcbiAgICAgICAgYWNjb3VudElkOiBzdHJpbmc7XG4gICAgICAgIGJ1Y2tldElkOiBzdHJpbmc7XG4gICAgICAgIGJ1Y2tldE5hbWU6IHN0cmluZztcbiAgICAgICAgYnVja2V0VHlwZTogXCJhbGxQcml2YXRlXCIgfCBcImFsbFB1YmxpY1wiO1xuICAgICAgICBidWNrZXRJbmZvOiB7XG4gICAgICAgICAgICBsaWZlY3ljbGVSdWxlczogYW55W107XG4gICAgICAgIH07XG4gICAgICAgIGNvcnNSdWxlczogYW55W107XG4gICAgICAgIGxpZmVjeWNsZVJ1bGVzOiBhbnlbXTtcbiAgICAgICAgcmV2aXNpb246IG51bWJlcjtcbiAgICB9PihcImIyX2NyZWF0ZV9idWNrZXRcIiwgXCJQT1NUXCIpO1xuXG4gICAgY29uc3QgdXBkYXRlQnVja2V0ID0gY3JlYXRlQjJGdW5jdGlvbjx7XG4gICAgICAgIGFjY291bnRJZDogc3RyaW5nO1xuICAgICAgICBidWNrZXRJZDogc3RyaW5nO1xuICAgICAgICBidWNrZXRUeXBlPzogXCJhbGxQcml2YXRlXCIgfCBcImFsbFB1YmxpY1wiO1xuICAgICAgICBsaWZlY3ljbGVSdWxlcz86IGFueVtdO1xuICAgICAgICBidWNrZXRJbmZvPzoge1xuICAgICAgICAgICAgW2tleTogc3RyaW5nXTogdW5rbm93bjtcbiAgICAgICAgfTtcbiAgICAgICAgY29yc1J1bGVzPzogdW5rbm93bltdO1xuICAgIH0sIHtcbiAgICAgICAgYWNjb3VudElkOiBzdHJpbmc7XG4gICAgICAgIGJ1Y2tldElkOiBzdHJpbmc7XG4gICAgICAgIGJ1Y2tldE5hbWU6IHN0cmluZztcbiAgICAgICAgYnVja2V0VHlwZTogXCJhbGxQcml2YXRlXCIgfCBcImFsbFB1YmxpY1wiO1xuICAgICAgICBidWNrZXRJbmZvOiB7XG4gICAgICAgICAgICBsaWZlY3ljbGVSdWxlczogYW55W107XG4gICAgICAgIH07XG4gICAgICAgIGNvcnNSdWxlczogYW55W107XG4gICAgICAgIGxpZmVjeWNsZVJ1bGVzOiBhbnlbXTtcbiAgICAgICAgcmV2aXNpb246IG51bWJlcjtcbiAgICB9PihcImIyX3VwZGF0ZV9idWNrZXRcIiwgXCJQT1NUXCIpO1xuXG4gICAgLy8gaHR0cHM6Ly93d3cuYmFja2JsYXplLmNvbS9hcGlkb2NzL2IyLXVwZGF0ZS1idWNrZXRcbiAgICAvLyAgVE9ETzogYjJfdXBkYXRlX2J1Y2tldCwgc28gd2UgY2FuIHVwZGF0ZSBDT1JTLCBldGNcblxuICAgIGNvbnN0IGxpc3RCdWNrZXRzID0gY3JlYXRlQjJGdW5jdGlvbjx7XG4gICAgICAgIGJ1Y2tldE5hbWU/OiBzdHJpbmc7XG4gICAgfSwge1xuICAgICAgICBidWNrZXRzOiB7XG4gICAgICAgICAgICBhY2NvdW50SWQ6IHN0cmluZztcbiAgICAgICAgICAgIGJ1Y2tldElkOiBzdHJpbmc7XG4gICAgICAgICAgICBidWNrZXROYW1lOiBzdHJpbmc7XG4gICAgICAgICAgICBidWNrZXRUeXBlOiBcImFsbFByaXZhdGVcIiB8IFwiYWxsUHVibGljXCI7XG4gICAgICAgICAgICBidWNrZXRJbmZvOiB7XG4gICAgICAgICAgICAgICAgbGlmZWN5Y2xlUnVsZXM6IGFueVtdO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGNvcnNSdWxlczogYW55W107XG4gICAgICAgICAgICBsaWZlY3ljbGVSdWxlczogYW55W107XG4gICAgICAgICAgICByZXZpc2lvbjogbnVtYmVyO1xuICAgICAgICB9W107XG4gICAgfT4oXCJiMl9saXN0X2J1Y2tldHNcIiwgXCJQT1NUXCIpO1xuXG4gICAgZnVuY3Rpb24gZW5jb2RlUGF0aChwYXRoOiBzdHJpbmcpIHtcbiAgICAgICAgLy8gUHJlc2VydmUgc2xhc2hlcywgYnV0IGVuY29kZSBldmVyeXRoaW5nIGVsc2VcbiAgICAgICAgcGF0aCA9IHBhdGguc3BsaXQoXCIvXCIpLm1hcChlbmNvZGVVUklDb21wb25lbnQpLmpvaW4oXCIvXCIpO1xuICAgICAgICBpZiAocGF0aC5zdGFydHNXaXRoKFwiL1wiKSkgcGF0aCA9IFwiJTJGXCIgKyBwYXRoLnNsaWNlKDEpO1xuICAgICAgICBpZiAocGF0aC5lbmRzV2l0aChcIi9cIikpIHBhdGggPSBwYXRoLnNsaWNlKDAsIC0xKSArIFwiJTJGXCI7XG4gICAgICAgIC8vIE5PVEU6IEZvciBzb21lIHJlYXNvbiwgdGhpcyB3b24ndCByZW5kZXIgaW4gdGhlIHdlYiBVSSBjb3JyZWN0bHkuIEJVVCwgaXQnbGxcbiAgICAgICAgLy8gIHdvcmsgZ2V0IGdldC9zZXQgYW5kIGZpbmRcbiAgICAgICAgLy8gIC0gQUxTTywgaXQgc2VlbXMgdG8gYWRkIGR1cGxpY2F0ZSBmaWxlcz8gVGhpcyBtaWdodCBhbHNvIGJlIGEgd2ViIFVJIHRoaW5nLiBJdFxuICAgICAgICAvLyAgICAgIHNlZW1zIHRvIHdvcmsgdGhvdWdoLlxuICAgICAgICB3aGlsZSAocGF0aC5pbmNsdWRlcyhcIi8vXCIpKSB7XG4gICAgICAgICAgICBwYXRoID0gcGF0aC5yZXBsYWNlQWxsKFwiLy9cIiwgXCIvJTJGXCIpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBwYXRoO1xuICAgIH1cblxuICAgIGFzeW5jIGZ1bmN0aW9uIGRvd25sb2FkRmlsZUJ5TmFtZShjb25maWc6IHtcbiAgICAgICAgYnVja2V0TmFtZTogc3RyaW5nO1xuICAgICAgICBmaWxlTmFtZTogc3RyaW5nO1xuICAgICAgICByYW5nZT86IHsgc3RhcnQ6IG51bWJlcjsgZW5kOiBudW1iZXI7IH07XG4gICAgfSkge1xuICAgICAgICBsZXQgZmlsZU5hbWUgPSBlbmNvZGVQYXRoKGNvbmZpZy5maWxlTmFtZSk7XG5cbiAgICAgICAgbGV0IHJlc3VsdCA9IGF3YWl0IGh0dHBzUmVxdWVzdChhdXRoLmFwaVVybCArIFwiL2ZpbGUvXCIgKyBjb25maWcuYnVja2V0TmFtZSArIFwiL1wiICsgZmlsZU5hbWUsIEJ1ZmZlci5mcm9tKEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgIGFjY291bnRJZDogYXV0aC5hY2NvdW50SWQsXG4gICAgICAgICAgICByZXNwb25zZVR5cGU6IFwiYXJyYXlidWZmZXJcIixcbiAgICAgICAgfSkpLCBcIkdFVFwiLCB1bmRlZmluZWQsIHtcbiAgICAgICAgICAgIGhlYWRlcnM6IE9iamVjdC5mcm9tRW50cmllcyhPYmplY3QuZW50cmllcyh7XG4gICAgICAgICAgICAgICAgQXV0aG9yaXphdGlvbjogYXV0aC5hdXRob3JpemF0aW9uVG9rZW4sXG4gICAgICAgICAgICAgICAgXCJDb250ZW50LVR5cGVcIjogXCJhcHBsaWNhdGlvbi9qc29uXCIsXG4gICAgICAgICAgICAgICAgUmFuZ2U6IGNvbmZpZy5yYW5nZSA/IGBieXRlcz0ke2NvbmZpZy5yYW5nZS5zdGFydH0tJHtjb25maWcucmFuZ2UuZW5kIC0gMX1gIDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgfSkuZmlsdGVyKHggPT4geFsxXSAhPT0gdW5kZWZpbmVkKSksXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8vIE9oLi4uIGFwcGFyZW50bHksIHdlIGNhbid0IHJldXNlIHRoZXNlPyBIdWguLi5cbiAgICBjb25zdCBnZXRVcGxvYWRVUkwgPSAoYXN5bmMgKGJ1Y2tldElkOiBzdHJpbmcpID0+IHtcbiAgICAgICAgLy9zZXRUaW1lb3V0KCgpID0+IGdldFVwbG9hZFVSTC5jbGVhcihidWNrZXRJZCksIHRpbWVJbkhvdXIgKiAxKTtcbiAgICAgICAgbGV0IGdldFVwbG9hZFVybFJhdyA9IGF3YWl0IGh0dHBzUmVxdWVzdChhdXRoLmFwaVVybCArIFwiL2IyYXBpL3YyL2IyX2dldF91cGxvYWRfdXJsP2J1Y2tldElkPVwiICsgYnVja2V0SWQsIHVuZGVmaW5lZCwgXCJHRVRcIiwgdW5kZWZpbmVkLCB7XG4gICAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAgICAgQXV0aG9yaXphdGlvbjogYXV0aC5hdXRob3JpemF0aW9uVG9rZW4sXG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiBKU09OLnBhcnNlKGdldFVwbG9hZFVybFJhdy50b1N0cmluZygpKSBhcyB7XG4gICAgICAgICAgICBidWNrZXRJZDogc3RyaW5nO1xuICAgICAgICAgICAgdXBsb2FkVXJsOiBzdHJpbmc7XG4gICAgICAgICAgICBhdXRob3JpemF0aW9uVG9rZW46IHN0cmluZztcbiAgICAgICAgfTtcbiAgICB9KTtcblxuICAgIGFzeW5jIGZ1bmN0aW9uIHVwbG9hZEZpbGUoY29uZmlnOiB7XG4gICAgICAgIGJ1Y2tldElkOiBzdHJpbmc7XG4gICAgICAgIGZpbGVOYW1lOiBzdHJpbmc7XG4gICAgICAgIGRhdGE6IEJ1ZmZlcjtcbiAgICB9KSB7XG4gICAgICAgIGxldCBnZXRVcGxvYWRVcmwgPSBhd2FpdCBnZXRVcGxvYWRVUkwoY29uZmlnLmJ1Y2tldElkKTtcblxuICAgICAgICBhd2FpdCBodHRwc1JlcXVlc3QoZ2V0VXBsb2FkVXJsLnVwbG9hZFVybCwgY29uZmlnLmRhdGEsIFwiUE9TVFwiLCB1bmRlZmluZWQsIHtcbiAgICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICAgICBBdXRob3JpemF0aW9uOiBnZXRVcGxvYWRVcmwuYXV0aG9yaXphdGlvblRva2VuLFxuICAgICAgICAgICAgICAgIFwiWC1Cei1GaWxlLU5hbWVcIjogZW5jb2RlUGF0aChjb25maWcuZmlsZU5hbWUpLFxuICAgICAgICAgICAgICAgIFwiQ29udGVudC1UeXBlXCI6IFwiYjIveC1hdXRvXCIsXG4gICAgICAgICAgICAgICAgXCJYLUJ6LUNvbnRlbnQtU2hhMVwiOiBcImRvX25vdF92ZXJpZnlcIixcbiAgICAgICAgICAgICAgICBcIkNvbnRlbnQtTGVuZ3RoXCI6IGNvbmZpZy5kYXRhLmxlbmd0aCArIFwiXCIsXG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGNvbnN0IGhpZGVGaWxlID0gY3JlYXRlQjJGdW5jdGlvbjx7XG4gICAgICAgIGJ1Y2tldElkOiBzdHJpbmc7XG4gICAgICAgIGZpbGVOYW1lOiBzdHJpbmc7XG4gICAgfSwge30+KFwiYjJfaGlkZV9maWxlXCIsIFwiUE9TVFwiLCBcIm5vQWNjb3VudElkXCIpO1xuXG4gICAgY29uc3QgZ2V0RmlsZUluZm8gPSBjcmVhdGVCMkZ1bmN0aW9uPHtcbiAgICAgICAgYnVja2V0TmFtZTogc3RyaW5nO1xuICAgICAgICBmaWxlSWQ6IHN0cmluZztcbiAgICB9LCB7XG4gICAgICAgIGZpbGVJZDogc3RyaW5nO1xuICAgICAgICBmaWxlTmFtZTogc3RyaW5nO1xuICAgICAgICBhY2NvdW50SWQ6IHN0cmluZztcbiAgICAgICAgYnVja2V0SWQ6IHN0cmluZztcbiAgICAgICAgY29udGVudExlbmd0aDogbnVtYmVyO1xuICAgICAgICBjb250ZW50U2hhMTogc3RyaW5nO1xuICAgICAgICBjb250ZW50VHlwZTogc3RyaW5nO1xuICAgICAgICBmaWxlSW5mbzoge1xuICAgICAgICAgICAgc3JjX2xhc3RfbW9kaWZpZWRfbWlsbGlzOiBudW1iZXI7XG4gICAgICAgIH07XG4gICAgICAgIGFjdGlvbjogc3RyaW5nO1xuICAgICAgICB1cGxvYWRUaW1lc3RhbXA6IG51bWJlcjtcbiAgICB9PihcImIyX2dldF9maWxlX2luZm9cIiwgXCJQT1NUXCIsIFwibm9BY2NvdW50SWRcIik7XG5cbiAgICBjb25zdCBsaXN0RmlsZU5hbWVzID0gY3JlYXRlQjJGdW5jdGlvbjx7XG4gICAgICAgIGJ1Y2tldElkOiBzdHJpbmc7XG4gICAgICAgIHByZWZpeDogc3RyaW5nO1xuICAgICAgICBzdGFydEZpbGVOYW1lPzogc3RyaW5nO1xuICAgICAgICBtYXhGaWxlQ291bnQ/OiBudW1iZXI7XG4gICAgICAgIGRlbGltaXRlcj86IHN0cmluZztcbiAgICB9LCB7XG4gICAgICAgIGZpbGVzOiB7XG4gICAgICAgICAgICBmaWxlSWQ6IHN0cmluZztcbiAgICAgICAgICAgIGZpbGVOYW1lOiBzdHJpbmc7XG4gICAgICAgICAgICBhY2NvdW50SWQ6IHN0cmluZztcbiAgICAgICAgICAgIGJ1Y2tldElkOiBzdHJpbmc7XG4gICAgICAgICAgICBjb250ZW50TGVuZ3RoOiBudW1iZXI7XG4gICAgICAgICAgICBjb250ZW50U2hhMTogc3RyaW5nO1xuICAgICAgICAgICAgY29udGVudFR5cGU6IHN0cmluZztcbiAgICAgICAgICAgIGZpbGVJbmZvOiB7XG4gICAgICAgICAgICAgICAgc3JjX2xhc3RfbW9kaWZpZWRfbWlsbGlzOiBudW1iZXI7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgYWN0aW9uOiBzdHJpbmc7XG4gICAgICAgICAgICB1cGxvYWRUaW1lc3RhbXA6IG51bWJlcjtcbiAgICAgICAgfVtdO1xuICAgICAgICBuZXh0RmlsZU5hbWU6IHN0cmluZztcbiAgICB9PihcImIyX2xpc3RfZmlsZV9uYW1lc1wiLCBcIlBPU1RcIiwgXCJub0FjY291bnRJZFwiKTtcblxuICAgIGNvbnN0IGNvcHlGaWxlID0gY3JlYXRlQjJGdW5jdGlvbjx7XG4gICAgICAgIHNvdXJjZUZpbGVJZDogc3RyaW5nO1xuICAgICAgICBmaWxlTmFtZTogc3RyaW5nO1xuICAgICAgICBkZXN0aW5hdGlvbkJ1Y2tldElkOiBzdHJpbmc7XG4gICAgfSwge30+KFwiYjJfY29weV9maWxlXCIsIFwiUE9TVFwiLCBcIm5vQWNjb3VudElkXCIpO1xuXG4gICAgY29uc3Qgc3RhcnRMYXJnZUZpbGUgPSBjcmVhdGVCMkZ1bmN0aW9uPHtcbiAgICAgICAgYnVja2V0SWQ6IHN0cmluZztcbiAgICAgICAgZmlsZU5hbWU6IHN0cmluZztcbiAgICAgICAgY29udGVudFR5cGU6IHN0cmluZztcbiAgICAgICAgZmlsZUluZm86IHsgW2tleTogc3RyaW5nXTogc3RyaW5nIH07XG4gICAgfSwge1xuICAgICAgICBmaWxlSWQ6IHN0cmluZztcbiAgICAgICAgZmlsZU5hbWU6IHN0cmluZztcbiAgICAgICAgYWNjb3VudElkOiBzdHJpbmc7XG4gICAgICAgIGJ1Y2tldElkOiBzdHJpbmc7XG4gICAgICAgIGNvbnRlbnRUeXBlOiBzdHJpbmc7XG4gICAgICAgIGZpbGVJbmZvOiBhbnk7XG4gICAgICAgIHVwbG9hZFRpbWVzdGFtcDogbnVtYmVyO1xuICAgIH0+KFwiYjJfc3RhcnRfbGFyZ2VfZmlsZVwiLCBcIlBPU1RcIiwgXCJub0FjY291bnRJZFwiKTtcblxuICAgIC8vIEFwcGFyZW50bHkgd2UgY2FuJ3QgcmV1c2UgdGhlc2U/XG4gICAgY29uc3QgZ2V0VXBsb2FkUGFydFVSTCA9IChhc3luYyAoZmlsZUlkOiBzdHJpbmcpID0+IHtcbiAgICAgICAgbGV0IHVwbG9hZFBhcnRSYXcgPSBhd2FpdCBodHRwc1JlcXVlc3QoYXV0aC5hcGlVcmwgKyBcIi9iMmFwaS92Mi9iMl9nZXRfdXBsb2FkX3BhcnRfdXJsP2ZpbGVJZD1cIiArIGZpbGVJZCwgdW5kZWZpbmVkLCBcIkdFVFwiLCB1bmRlZmluZWQsIHtcbiAgICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICAgICBBdXRob3JpemF0aW9uOiBhdXRoLmF1dGhvcml6YXRpb25Ub2tlbixcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiBKU09OLnBhcnNlKHVwbG9hZFBhcnRSYXcudG9TdHJpbmcoKSkgYXMge1xuICAgICAgICAgICAgZmlsZUlkOiBzdHJpbmc7XG4gICAgICAgICAgICBwYXJ0TnVtYmVyOiBudW1iZXI7XG4gICAgICAgICAgICB1cGxvYWRVcmw6IHN0cmluZztcbiAgICAgICAgICAgIGF1dGhvcml6YXRpb25Ub2tlbjogc3RyaW5nO1xuICAgICAgICB9O1xuICAgIH0pO1xuICAgIGFzeW5jIGZ1bmN0aW9uIHVwbG9hZFBhcnQoY29uZmlnOiB7XG4gICAgICAgIGZpbGVJZDogc3RyaW5nO1xuICAgICAgICBwYXJ0TnVtYmVyOiBudW1iZXI7XG4gICAgICAgIGRhdGE6IEJ1ZmZlcjtcbiAgICAgICAgc2hhMTogc3RyaW5nO1xuICAgIH0pOiBQcm9taXNlPHtcbiAgICAgICAgZmlsZUlkOiBzdHJpbmc7XG4gICAgICAgIHBhcnROdW1iZXI6IG51bWJlcjtcbiAgICAgICAgY29udGVudExlbmd0aDogbnVtYmVyO1xuICAgICAgICBjb250ZW50U2hhMTogc3RyaW5nO1xuICAgIH0+IHtcbiAgICAgICAgbGV0IHVwbG9hZFBhcnQgPSBhd2FpdCBnZXRVcGxvYWRQYXJ0VVJMKGNvbmZpZy5maWxlSWQpO1xuXG4gICAgICAgIGxldCByZXN1bHQgPSBhd2FpdCBodHRwc1JlcXVlc3QodXBsb2FkUGFydC51cGxvYWRVcmwsIGNvbmZpZy5kYXRhLCBcIlBPU1RcIiwgdW5kZWZpbmVkLCB7XG4gICAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAgICAgQXV0aG9yaXphdGlvbjogdXBsb2FkUGFydC5hdXRob3JpemF0aW9uVG9rZW4sXG4gICAgICAgICAgICAgICAgXCJYLUJ6LVBhcnQtTnVtYmVyXCI6IGNvbmZpZy5wYXJ0TnVtYmVyICsgXCJcIixcbiAgICAgICAgICAgICAgICBcIlgtQnotQ29udGVudC1TaGExXCI6IGNvbmZpZy5zaGExLFxuICAgICAgICAgICAgICAgIFwiQ29udGVudC1MZW5ndGhcIjogY29uZmlnLmRhdGEubGVuZ3RoICsgXCJcIixcblxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UocmVzdWx0LnRvU3RyaW5nKCkpO1xuICAgIH1cblxuICAgIGNvbnN0IGZpbmlzaExhcmdlRmlsZSA9IGNyZWF0ZUIyRnVuY3Rpb248e1xuICAgICAgICBmaWxlSWQ6IHN0cmluZztcbiAgICAgICAgcGFydFNoYTFBcnJheTogc3RyaW5nW107XG4gICAgfSwge1xuICAgICAgICBmaWxlSWQ6IHN0cmluZztcbiAgICAgICAgZmlsZU5hbWU6IHN0cmluZztcbiAgICAgICAgYWNjb3VudElkOiBzdHJpbmc7XG4gICAgICAgIGJ1Y2tldElkOiBzdHJpbmc7XG4gICAgICAgIGNvbnRlbnRMZW5ndGg6IG51bWJlcjtcbiAgICAgICAgY29udGVudFNoYTE6IHN0cmluZztcbiAgICAgICAgY29udGVudFR5cGU6IHN0cmluZztcbiAgICAgICAgZmlsZUluZm86IGFueTtcbiAgICAgICAgdXBsb2FkVGltZXN0YW1wOiBudW1iZXI7XG4gICAgfT4oXCJiMl9maW5pc2hfbGFyZ2VfZmlsZVwiLCBcIlBPU1RcIiwgXCJub0FjY291bnRJZFwiKTtcblxuICAgIGNvbnN0IGNhbmNlbExhcmdlRmlsZSA9IGNyZWF0ZUIyRnVuY3Rpb248e1xuICAgICAgICBmaWxlSWQ6IHN0cmluZztcbiAgICB9LCB7fT4oXCJiMl9jYW5jZWxfbGFyZ2VfZmlsZVwiLCBcIlBPU1RcIiwgXCJub0FjY291bnRJZFwiKTtcblxuICAgIGNvbnN0IGdldERvd25sb2FkQXV0aG9yaXphdGlvbiA9IGNyZWF0ZUIyRnVuY3Rpb248e1xuICAgICAgICBidWNrZXRJZDogc3RyaW5nO1xuICAgICAgICBmaWxlTmFtZVByZWZpeDogc3RyaW5nO1xuICAgICAgICB2YWxpZER1cmF0aW9uSW5TZWNvbmRzOiBudW1iZXI7XG4gICAgICAgIGIyQ29udGVudERpc3Bvc2l0aW9uPzogc3RyaW5nO1xuICAgICAgICBiMkNvbnRlbnRMYW5ndWFnZT86IHN0cmluZztcbiAgICAgICAgYjJFeHBpcmVzPzogc3RyaW5nO1xuICAgICAgICBiMkNhY2hlQ29udHJvbD86IHN0cmluZztcbiAgICAgICAgYjJDb250ZW50RW5jb2Rpbmc/OiBzdHJpbmc7XG4gICAgICAgIGIyQ29udGVudFR5cGU/OiBzdHJpbmc7XG4gICAgfSwge1xuICAgICAgICBidWNrZXRJZDogc3RyaW5nO1xuICAgICAgICBmaWxlTmFtZVByZWZpeDogc3RyaW5nO1xuICAgICAgICBhdXRob3JpemF0aW9uVG9rZW46IHN0cmluZztcbiAgICB9PihcImIyX2dldF9kb3dubG9hZF9hdXRob3JpemF0aW9uXCIsIFwiUE9TVFwiLCBcIm5vQWNjb3VudElkXCIpO1xuXG4gICAgYXN5bmMgZnVuY3Rpb24gZ2V0RG93bmxvYWRVUkwocGF0aDogc3RyaW5nKSB7XG4gICAgICAgIGlmICghcGF0aC5zdGFydHNXaXRoKFwiL1wiKSkge1xuICAgICAgICAgICAgcGF0aCA9IFwiL1wiICsgcGF0aDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gYXV0aC5kb3dubG9hZFVybCArIHBhdGg7XG4gICAgfVxuXG5cbiAgICByZXR1cm4ge1xuICAgICAgICBjcmVhdGVCdWNrZXQsXG4gICAgICAgIHVwZGF0ZUJ1Y2tldCxcbiAgICAgICAgbGlzdEJ1Y2tldHMsXG4gICAgICAgIGRvd25sb2FkRmlsZUJ5TmFtZSxcbiAgICAgICAgdXBsb2FkRmlsZSxcbiAgICAgICAgaGlkZUZpbGUsXG4gICAgICAgIGdldEZpbGVJbmZvLFxuICAgICAgICBsaXN0RmlsZU5hbWVzLFxuICAgICAgICBjb3B5RmlsZSxcbiAgICAgICAgc3RhcnRMYXJnZUZpbGUsXG4gICAgICAgIHVwbG9hZFBhcnQsXG4gICAgICAgIGZpbmlzaExhcmdlRmlsZSxcbiAgICAgICAgY2FuY2VsTGFyZ2VGaWxlLFxuICAgICAgICBnZXREb3dubG9hZEF1dGhvcml6YXRpb24sXG4gICAgICAgIGdldERvd25sb2FkVVJMLFxuICAgICAgICBhcGlVcmw6IGF1dGguYXBpVXJsLFxuICAgICAgICBhbGxvd2VkOiBhdXRoLmFsbG93ZWQsXG4gICAgfTtcbn0pO1xuXG50eXBlIEIyQXBpID0gKHR5cGVvZiBnZXRBUEkpIGV4dGVuZHMgKCkgPT4gUHJvbWlzZTxpbmZlciBUPiA/IFQgOiBuZXZlcjtcblxuXG5leHBvcnQgY2xhc3MgQXJjaGl2ZXNCYWNrYmxhemUgaW1wbGVtZW50cyBJQXJjaGl2ZXMge1xuICAgIHB1YmxpYyBjb25zdHJ1Y3Rvcihwcml2YXRlIGNvbmZpZzoge1xuICAgICAgICBidWNrZXROYW1lOiBzdHJpbmc7XG4gICAgICAgIHB1YmxpYz86IGJvb2xlYW47XG4gICAgICAgIGltbXV0YWJsZT86IGJvb2xlYW47XG4gICAgICAgIGNhY2hlVGltZT86IG51bWJlcjtcbiAgICAgICAgYWxsb3dlZE9yaWdpbnM/OiBzdHJpbmdbXTtcbiAgICB9KSB7XG4gICAgICAgIC8vIEdldCB0aGUgYXBpLCB0byBzZXR1cCBjb3JzXG4gICAgICAgIHZvaWQgdGhpcy5nZXRCdWNrZXRBUEkoKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGJ1Y2tldE5hbWUgPSB0aGlzLmNvbmZpZy5idWNrZXROYW1lLnJlcGxhY2VBbGwoL1teXFx3XFxkXS9nLCBcIi1cIik7XG4gICAgcHJpdmF0ZSBidWNrZXRJZCA9IFwiXCI7XG5cbiAgICBwcml2YXRlIGxvZ2dpbmcgPSBmYWxzZTtcbiAgICBwdWJsaWMgZW5hYmxlTG9nZ2luZygpIHtcbiAgICAgICAgdGhpcy5sb2dnaW5nID0gdHJ1ZTtcbiAgICB9XG4gICAgcHJpdmF0ZSBsb2codGV4dDogc3RyaW5nKSB7XG4gICAgICAgIGlmICghdGhpcy5sb2dnaW5nKSByZXR1cm47XG4gICAgICAgIGNvbnNvbGUubG9nKHRleHQpO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXREZWJ1Z05hbWUoKSB7XG4gICAgICAgIHJldHVybiBcImJhY2tibGF6ZS9cIiArIHRoaXMuY29uZmlnLmJ1Y2tldE5hbWU7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBnZXRCdWNrZXRBUEkgPSBsYXp5KGFzeW5jICgpID0+IHtcbiAgICAgICAgbGV0IGFwaSA9IGF3YWl0IGdldEFQSSgpO1xuXG4gICAgICAgIGxldCBjYWNoZVRpbWUgPSB0aGlzLmNvbmZpZy5jYWNoZVRpbWUgPz8gMDtcbiAgICAgICAgaWYgKHRoaXMuY29uZmlnLmltbXV0YWJsZSkge1xuICAgICAgICAgICAgY2FjaGVUaW1lID0gSU1NVVRBQkxFX0NBQ0hFX1RJTUU7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBBTFdBWVMgc2V0IGFjY2VzcyBjb250cm9sLCBhcyB3ZSBjYW4gbWFrZSB1cmxzIGZvciBwcml2YXRlIGJ1Y2tldHMgd2l0aCBnZXREb3dubG9hZEF1dGhvcml6YXRpb25cbiAgICAgICAgbGV0IGRlc2lyZWRDb3JzUnVsZXMgPSBbe1xuICAgICAgICAgICAgY29yc1J1bGVOYW1lOiBcImFsbG93QWxsXCIsXG4gICAgICAgICAgICBhbGxvd2VkT3JpZ2luczogdGhpcy5jb25maWcuYWxsb3dlZE9yaWdpbnMgPz8gW1wiaHR0cHNcIl0sXG4gICAgICAgICAgICBhbGxvd2VkT3BlcmF0aW9uczogW1wiYjJfZG93bmxvYWRfZmlsZV9ieV9pZFwiLCBcImIyX2Rvd25sb2FkX2ZpbGVfYnlfbmFtZVwiXSxcbiAgICAgICAgICAgIGFsbG93ZWRIZWFkZXJzOiBbXCJyYW5nZVwiXSxcbiAgICAgICAgICAgIGV4cG9zZUhlYWRlcnM6IFtcIngtYnotY29udGVudC1zaGExXCJdLFxuICAgICAgICAgICAgbWF4QWdlU2Vjb25kczogY2FjaGVUaW1lIC8gMTAwMCxcbiAgICAgICAgfV07XG4gICAgICAgIGxldCBidWNrZXRJbmZvOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9O1xuICAgICAgICBpZiAoY2FjaGVUaW1lKSB7XG4gICAgICAgICAgICBidWNrZXRJbmZvW1wiY2FjaGUtY29udHJvbFwiXSA9IGBtYXgtYWdlPSR7Y2FjaGVUaW1lIC8gMTAwMH1gO1xuICAgICAgICB9XG5cblxuICAgICAgICBsZXQgZXhpc3RzID0gZmFsc2U7XG4gICAgICAgIGxldCByZXRyaWVzID0gMDtcbiAgICAgICAgd2hpbGUgKHRydWUpIHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgYXBpLmNyZWF0ZUJ1Y2tldCh7XG4gICAgICAgICAgICAgICAgICAgIGJ1Y2tldE5hbWU6IHRoaXMuYnVja2V0TmFtZSxcbiAgICAgICAgICAgICAgICAgICAgYnVja2V0VHlwZTogdGhpcy5jb25maWcucHVibGljID8gXCJhbGxQdWJsaWNcIiA6IFwiYWxsUHJpdmF0ZVwiLFxuICAgICAgICAgICAgICAgICAgICBsaWZlY3ljbGVSdWxlczogW3tcbiAgICAgICAgICAgICAgICAgICAgICAgIFwiZGF5c0Zyb21VcGxvYWRpbmdUb0hpZGluZ1wiOiBudWxsLFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gS2VlcCBmaWxlcyBmb3IgNyBkYXlzLCB3aGljaCBzaG91bGQgYmUgZW5vdWdoIHRpbWUgdG8gcmVjb3ZlciBhY2NpZGVudGFsIGhpZGluZy5cbiAgICAgICAgICAgICAgICAgICAgICAgIFwiZGF5c0Zyb21IaWRpbmdUb0RlbGV0aW5nXCI6IDcsXG4gICAgICAgICAgICAgICAgICAgICAgICBcImZpbGVOYW1lUHJlZml4XCI6IFwiXCJcbiAgICAgICAgICAgICAgICAgICAgfV0sXG4gICAgICAgICAgICAgICAgICAgIGNvcnNSdWxlczogZGVzaXJlZENvcnNSdWxlcyxcbiAgICAgICAgICAgICAgICAgICAgYnVja2V0SW5mb1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICAgICAgICAgICAgaWYgKCFlLnN0YWNrLmluY2x1ZGVzKGBcImR1cGxpY2F0ZV9idWNrZXRfbmFtZVwiYCkpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHJldHJpZXMgPCAzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKGBCYWNrYmxhemUgY3JlYXRlIGJ1Y2tldCBmYWlsZWQsIHJldHJ5aW5nIGluIDVzOiAke2Uuc3RhY2t9YCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCBkZWxheSg1MDAwKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHJpZXMrKztcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHRocm93IGU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGV4aXN0cyA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBidWNrZXRMaXN0ID0gYXdhaXQgYXBpLmxpc3RCdWNrZXRzKHtcbiAgICAgICAgICAgIGJ1Y2tldE5hbWU6IHRoaXMuYnVja2V0TmFtZSxcbiAgICAgICAgfSk7XG4gICAgICAgIGlmIChidWNrZXRMaXN0LmJ1Y2tldHMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEJ1Y2tldCBuYW1lIFwiJHt0aGlzLmJ1Y2tldE5hbWV9XCIgaXMgYmVpbmcgdXNlZCBieSBzb21lb25lIGVsc2UuIEJ1Y2tldCBuYW1lcyBoYXZlIHRvIGJlIGdsb2JhbGx5IHVuaXF1ZS4gVHJ5IGEgZGlmZmVyZW50IG5hbWUgdW50aWwgeW91IGZpbmQgYSBmcmVlIG9uZS5gKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmJ1Y2tldElkID0gYnVja2V0TGlzdC5idWNrZXRzWzBdLmJ1Y2tldElkO1xuXG4gICAgICAgIGlmIChleGlzdHMpIHtcbiAgICAgICAgICAgIGxldCBidWNrZXQgPSBidWNrZXRMaXN0LmJ1Y2tldHNbMF07XG4gICAgICAgICAgICBmdW5jdGlvbiBub3JtYWxpemUob2JqOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPikge1xuICAgICAgICAgICAgICAgIGxldCBrdnBzID0gT2JqZWN0LmVudHJpZXMob2JqKTtcbiAgICAgICAgICAgICAgICBzb3J0KGt2cHMsIHggPT4geFswXSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIE9iamVjdC5mcm9tRW50cmllcyhrdnBzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGZ1bmN0aW9uIG9yZGVySW5kZXBlbmRlbnRFcXVhbChsaHM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+LCByaHM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KG5vcm1hbGl6ZShsaHMpKSA9PT0gSlNPTi5zdHJpbmdpZnkobm9ybWFsaXplKHJocykpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZnVuY3Rpb24gb3JkZXJJbmRlcGVuZGVudEVxdWFsQXJyYXkobGhzOiB1bmtub3duW10sIHJoczogdW5rbm93bltdKSB7XG4gICAgICAgICAgICAgICAgaWYgKGxocy5sZW5ndGggIT09IHJocy5sZW5ndGgpIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGxocy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgICAgICBpZiAoIW9yZGVySW5kZXBlbmRlbnRFcXVhbChsaHNbaV0gYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4sIHJoc1tpXSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPikpIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgIW9yZGVySW5kZXBlbmRlbnRFcXVhbEFycmF5KGJ1Y2tldC5jb3JzUnVsZXMsIGRlc2lyZWRDb3JzUnVsZXMpXG4gICAgICAgICAgICAgICAgfHwgIW9yZGVySW5kZXBlbmRlbnRFcXVhbChidWNrZXQuYnVja2V0SW5mbywgYnVja2V0SW5mbylcbiAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKG1hZ2VudGEoYFVwZGF0aW5nIENPUlMgcnVsZXMgZm9yICR7dGhpcy5idWNrZXROYW1lfWApLCBidWNrZXQuY29yc1J1bGVzLCBkZXNpcmVkQ29yc1J1bGVzKTtcbiAgICAgICAgICAgICAgICBhd2FpdCBhcGkudXBkYXRlQnVja2V0KHtcbiAgICAgICAgICAgICAgICAgICAgYWNjb3VudElkOiBidWNrZXQuYWNjb3VudElkLFxuICAgICAgICAgICAgICAgICAgICBidWNrZXRJZDogYnVja2V0LmJ1Y2tldElkLFxuICAgICAgICAgICAgICAgICAgICBidWNrZXRUeXBlOiBidWNrZXQuYnVja2V0VHlwZSxcbiAgICAgICAgICAgICAgICAgICAgbGlmZWN5Y2xlUnVsZXM6IGJ1Y2tldC5saWZlY3ljbGVSdWxlcyxcbiAgICAgICAgICAgICAgICAgICAgY29yc1J1bGVzOiBkZXNpcmVkQ29yc1J1bGVzLFxuICAgICAgICAgICAgICAgICAgICBidWNrZXRJbmZvOiBidWNrZXRJbmZvLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBhcGk7XG4gICAgfSk7XG5cbiAgICBwcml2YXRlIGN1cnJlbnRSZXNldDogUHJvbWlzZTx2b2lkPiB8IHVuZGVmaW5lZDtcblxuICAgIC8vIEtlZXAgdHJhY2sgb2Ygd2hlbiB3ZSBsYXN0IHJlc2V0IGJlY2F1c2Ugb2YgYSA1MDNcbiAgICBwcml2YXRlIGxhc3Q1MDNSZXNldCA9IDA7XG4gICAgLy8gSU1QT1JUQU5UISBXZSBtdXN0IGFsd2F5cyBDQVRDSCBBUk9VTkQgdGhlIGFwaVJldHJ5TG9naWMsIE5FVkVSIGluc2lkZSBvZiBmbmMuIE90aGVyd2lzZSB3ZSB3b24ndFxuICAgIC8vICBiZSBhYmxlIHRvIHJlY3JlYXRlIHRoZSBhdXRoIHRva2VuLlxuICAgIC8vICBgY29udGV4dGAgaXMgYSBzaG9ydCBsYWJlbCAodmVyYiArIGZpbGUgcGF0aCkgaW5jbHVkZWQgaW4gZXZlcnkgcmV0cnkvZXJyb3IgbG9nIHNvIGEgc3R1Y2tcbiAgICAvLyAgIHNpbGVudC1yZXRyeSBsb29wIGlzIGlkZW50aWZpYWJsZSBmcm9tIHRoZSBsb2dzLlxuICAgIHByaXZhdGUgYXN5bmMgYXBpUmV0cnlMb2dpYzxUPihcbiAgICAgICAgY29udGV4dDogc3RyaW5nLFxuICAgICAgICBmbmM6IChhcGk6IEIyQXBpKSA9PiBQcm9taXNlPFQ+LFxuICAgICAgICByZXRyaWVzID0gM1xuICAgICk6IFByb21pc2U8VD4ge1xuICAgICAgICBsZXQgYXBpOiBCMkFwaSB8IHVuZGVmaW5lZDtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGFwaSA9IGF3YWl0IHRoaXMuZ2V0QnVja2V0QVBJKCk7XG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgZm5jKGFwaSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgICAgICBpZiAocmV0cmllcyA8PSAwKSB0aHJvdyBlcnI7XG5cbiAgICAgICAgICAgIC8vIElmIGl0J3MgYSA1MDMgYW5kIGl0J3MgYmVlbiBhIG1pbnV0ZSBzaW5jZSB3ZSBsYXN0IHJlc2V0LCB0aGVuIFdhaXQgYW5kIHJlc2V0LlxuICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgIChlcnIuc3RhY2suaW5jbHVkZXMoYFwic3RhdHVzXCI6IDUwM2ApXG4gICAgICAgICAgICAgICAgICAgIHx8IGVyci5zdGFjay5pbmNsdWRlcyhgXCJzZXJ2aWNlX3VuYXZhaWxhYmxlXCJgKVxuICAgICAgICAgICAgICAgICAgICB8fCBlcnIuc3RhY2suaW5jbHVkZXMoYFwiaW50ZXJuYWxfZXJyb3JcImApXG4gICAgICAgICAgICAgICAgICAgIHx8IGVyci5zdGFjay5pbmNsdWRlcyhgRU5PQlVGU2ApXG4gICAgICAgICAgICAgICAgKSAmJiBEYXRlLm5vdygpIC0gdGhpcy5sYXN0NTAzUmVzZXQgPiA2MCAqIDEwMDApIHtcbiAgICAgICAgICAgICAgICAvLyBCYWNrYmxhemUgaXMgc28gZmxha3kgdGhhdCB3ZSdyZSBqdXN0IGdvaW5nIHRvIHdhcm4gaGVyZS5cbiAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oYFske2NvbnRleHR9XSBCYWNrYmxhemUgZXJyb3IsIHdhaXRpbmcgYW5kIHJlc2V0dGluZzogJHtlcnIubWVzc2FnZX1gKTtcbiAgICAgICAgICAgICAgICB0aGlzLmxvZyhgWyR7Y29udGV4dH1dIEJhY2tibGF6ZSBlcnJvciwgd2FpdGluZyBhbmQgcmVzZXR0aW5nOiAke2Vyci5tZXNzYWdlfWApO1xuICAgICAgICAgICAgICAgIHRoaXMuY3VycmVudFJlc2V0ID0gdGhpcy5jdXJyZW50UmVzZXQgfHwgKGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgZGVsYXkoMTAgKiAxMDAwKTtcbiAgICAgICAgICAgICAgICAgICAgLy8gV2UgY2hlY2sgYWdhaW4gaW4gY2FzZSwgYW5kIGluIHRoZSB2ZXJ5IGxpa2VseSBjYXNlIHRoYXQgdGhpcyBpcyBiZWluZyBydW4gaW4gcGFyYWxsZWwsIHdlIG9ubHkgd2FudCB0byByZXNldCBvbmNlLlxuICAgICAgICAgICAgICAgICAgICBpZiAoRGF0ZS5ub3coKSAtIHRoaXMubGFzdDUwM1Jlc2V0ID4gNjAgKiAxMDAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmxvZyhgWyR7Y29udGV4dH1dIFJlc2V0dGluZyBnZXRBUEkgYW5kIGdldEJ1Y2tldEFQSTogJHtlcnIubWVzc2FnZX1gKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMubGFzdDUwM1Jlc2V0ID0gRGF0ZS5ub3coKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGdldEFQSS5yZXNldCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5nZXRCdWNrZXRBUEkucmVzZXQoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pKCkuZmluYWxseSgoKSA9PiB0aGlzLmN1cnJlbnRSZXNldCA9IHVuZGVmaW5lZCk7XG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5jdXJyZW50UmVzZXQ7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuYXBpUmV0cnlMb2dpYyhjb250ZXh0LCBmbmMsIHJldHJpZXMgLSAxKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gSWYgdGhlIGVycm9yIGlzIHRoYXQgdGhlIGF1dGhvcml6YXRpb24gdG9rZW4gaXMgaW52YWxpZCwgcmVzZXQgZ2V0QnVja2V0QVBJIGFuZCBnZXRBUElcbiAgICAgICAgICAgIC8vIElmIHRoZSBlcnJvciBpcyB0aGF0IHRoZSBidWNrZXQgaXNuJ3QgZm91bmQsIHJlc2V0IGdldEJ1Y2tldEFQSVxuICAgICAgICAgICAgaWYgKGVyci5zdGFjay5pbmNsdWRlcyhgXCJleHBpcmVkX2F1dGhfdG9rZW5cImApKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5sb2coYFske2NvbnRleHR9XSBBdXRob3JpemF0aW9uIHRva2VuIGV4cGlyZWRgKTtcbiAgICAgICAgICAgICAgICBnZXRBUEkucmVzZXQoKTtcbiAgICAgICAgICAgICAgICB0aGlzLmdldEJ1Y2tldEFQSS5yZXNldCgpO1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmFwaVJldHJ5TG9naWMoY29udGV4dCwgZm5jLCByZXRyaWVzIC0gMSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICBlcnIuc3RhY2suaW5jbHVkZXMoYG5vIHRvbWVzIGF2YWlsYWJsZWApXG4gICAgICAgICAgICAgICAgfHwgZXJyLnN0YWNrLmluY2x1ZGVzKGBFVElNRURPVVRgKVxuICAgICAgICAgICAgICAgIHx8IGVyci5zdGFjay5pbmNsdWRlcyhgc29ja2V0IGhhbmcgdXBgKVxuICAgICAgICAgICAgICAgIC8vIEVoLi4uIHRoaXMgbWlnaHQgYmUgYmFkLCBidXQuLi4gSSB0aGluayB3ZSBqdXN0IGdldCByYW5kb20gNDAwIGVycm9ycy4gSWYgdGhpcyBzcGFtcyBlcnJvcnMsXG4gICAgICAgICAgICAgICAgLy8gIHdlIGNhbiByZW1vdmUgdGhpcyBsaW5lLlxuICAgICAgICAgICAgICAgIHx8IGVyci5zdGFjay5pbmNsdWRlcyhgNDAwIEJhZCBSZXF1ZXN0YClcbiAgICAgICAgICAgICAgICB8fCBlcnIuc3RhY2suaW5jbHVkZXMoYGdldGFkZHJpbmZvIEVOT1RGT1VORGApXG4gICAgICAgICAgICAgICAgfHwgZXJyLnN0YWNrLmluY2x1ZGVzKGBFQ09OTlJFU0VUYClcbiAgICAgICAgICAgICAgICB8fCBlcnIuc3RhY2suaW5jbHVkZXMoYEVDT05OUkVGVVNFRGApXG4gICAgICAgICAgICAgICAgfHwgZXJyLnN0YWNrLmluY2x1ZGVzKGBFTk9CVUZTYClcbiAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybihgWyR7Y29udGV4dH1dIFJldHJ5aW5nIGluIDVzOiAke2Vyci5tZXNzYWdlfWApO1xuICAgICAgICAgICAgICAgIHRoaXMubG9nKGBbJHtjb250ZXh0fV0gJHtlcnIubWVzc2FnZX0gcmV0cnlpbmcgaW4gNXNgKTtcbiAgICAgICAgICAgICAgICBhd2FpdCBkZWxheSg1MDAwKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5hcGlSZXRyeUxvZ2ljKGNvbnRleHQsIGZuYywgcmV0cmllcyAtIDEpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoZXJyLnN0YWNrLmluY2x1ZGVzKGBnZXRhZGRyaW5mbyBFTk9URk9VTkRgKSkge1xuICAgICAgICAgICAgICAgIGlmIChhcGkpIHtcbiAgICAgICAgICAgICAgICAgICAgbGV0IHVybE9iaiA9IG5ldyBVUkwoYXBpLmFwaVVybCk7XG4gICAgICAgICAgICAgICAgICAgIGxldCBob3N0bmFtZSA9IHVybE9iai5ob3N0bmFtZTtcbiAgICAgICAgICAgICAgICAgICAgbGV0IGxvb2t1cEFkZHJlc3NlcyA9IGF3YWl0IG5ldyBQcm9taXNlKHJlc29sdmUgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgZG5zLmxvb2t1cChob3N0bmFtZSwgKGVyciwgYWRkcmVzc2VzKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x2ZShhZGRyZXNzZXMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICBsZXQgcmVzb2x2ZUFkZHJlc3NlcyA9IGF3YWl0IG5ldyBQcm9taXNlKHJlc29sdmUgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgZG5zLnJlc29sdmU0KGhvc3RuYW1lLCAoZXJyLCBhZGRyZXNzZXMpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXNvbHZlKGFkZHJlc3Nlcyk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYFske2NvbnRleHR9XSBnZXRhZGRyaW5mbyBFTk9URk9VTkQgJHtob3N0bmFtZX1gLCB7IGxvb2t1cEFkZHJlc3NlcywgcmVzb2x2ZUFkZHJlc3NlcywgYXBpVXJsOiBhcGkuYXBpVXJsLCBmdWxsRXJyb3I6IGVyci5zdGFjayB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBnZXQoZmlsZU5hbWU6IHN0cmluZywgY29uZmlnPzogeyByYW5nZT86IHsgc3RhcnQ6IG51bWJlcjsgZW5kOiBudW1iZXI7IH07IHJldHJ5Q291bnQ/OiBudW1iZXIgfSk6IFByb21pc2U8QnVmZmVyIHwgdW5kZWZpbmVkPiB7XG4gICAgICAgIGxldCBkb3dubG9hZGluZyA9IHRydWU7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBsZXQgdGltZSA9IERhdGUubm93KCk7XG4gICAgICAgICAgICBjb25zdCBkb3dubG9hZFBvbGwgPSAoKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKCFkb3dubG9hZGluZykgcmV0dXJuO1xuICAgICAgICAgICAgICAgIHRoaXMubG9nKGBCYWNrYmxhemUgZG93bmxvYWQgaW4gcHJvZ3Jlc3MgJHtmaWxlTmFtZX1gKTtcbiAgICAgICAgICAgICAgICBzZXRUaW1lb3V0KGRvd25sb2FkUG9sbCwgNTAwMCk7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgc2V0VGltZW91dChkb3dubG9hZFBvbGwsIDUwMDApO1xuICAgICAgICAgICAgbGV0IHJlc3VsdCA9IGF3YWl0IHRoaXMuYXBpUmV0cnlMb2dpYyhgZ2V0ICR7ZmlsZU5hbWV9YCwgYXN5bmMgKGFwaSkgPT4ge1xuICAgICAgICAgICAgICAgIGxldCByYW5nZSA9IGNvbmZpZz8ucmFuZ2U7XG4gICAgICAgICAgICAgICAgaWYgKHJhbmdlKSB7XG4gICAgICAgICAgICAgICAgICAgIGxldCBmaWxlSW5mbyA9IGF3YWl0IHRoaXMuZ2V0SW5mbyhmaWxlTmFtZSk7XG4gICAgICAgICAgICAgICAgICAgIGlmICghZmlsZUluZm8pIHRocm93IG5ldyBFcnJvcihgRmlsZSAke2ZpbGVOYW1lfSBub3QgZm91bmRgKTtcbiAgICAgICAgICAgICAgICAgICAgbGV0IHJhbmdlU3RhcnQgPSByYW5nZS5zdGFydDtcbiAgICAgICAgICAgICAgICAgICAgbGV0IHJhbmdlRW5kID0gTWF0aC5taW4ocmFuZ2UuZW5kLCBmaWxlSW5mby5zaXplKTtcbiAgICAgICAgICAgICAgICAgICAgLy8gTk9URTogSSB0aGluayBpZiB3ZSByZXF1ZXN0IG5vdGhpbmcsIGl0IGNvbmZ1c2VzIEJhY2tibGF6ZSBhbmQgZW5kcyB1cCBnaXZpbmcgdXMgdGhlIGVudGlyZSBmaWxlLlxuICAgICAgICAgICAgICAgICAgICBpZiAocmFuZ2VFbmQgPD0gcmFuZ2VTdGFydCkgcmV0dXJuIEJ1ZmZlci5hbGxvYygwKTtcbiAgICAgICAgICAgICAgICAgICAgbGV0IHJlc3VsdCA9IGF3YWl0IGFwaS5kb3dubG9hZEZpbGVCeU5hbWUoe1xuICAgICAgICAgICAgICAgICAgICAgICAgYnVja2V0TmFtZTogdGhpcy5idWNrZXROYW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgZmlsZU5hbWUsXG4gICAgICAgICAgICAgICAgICAgICAgICByYW5nZTogeyBzdGFydDogcmFuZ2VTdGFydCwgZW5kOiByYW5nZUVuZCB9LFxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHJlc3VsdC5sZW5ndGggIT09IHJhbmdlRW5kIC0gcmFuZ2VTdGFydCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihgQmFja2JsYXplIHJhbmdlIGRvd25sb2FkIHJldHVybmVkIHRoZSB3cm9uZyBudW1iZXIgb2YgYnl0ZXMuIFRyaWVkIHRvIGdldCAke3JhbmdlU3RhcnR9LSR7cmFuZ2VFbmR9LCBidXQgcmVjZWl2ZWQgJHtyYW5nZVN0YXJ0fS0ke3JhbmdlU3RhcnQgKyByZXN1bHQubGVuZ3RofS4gRm9yIGZpbGU6ICR7ZmlsZU5hbWV9YCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIGF3YWl0IGFwaS5kb3dubG9hZEZpbGVCeU5hbWUoe1xuICAgICAgICAgICAgICAgICAgICBidWNrZXROYW1lOiB0aGlzLmJ1Y2tldE5hbWUsXG4gICAgICAgICAgICAgICAgICAgIGZpbGVOYW1lLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBsZXQgdGltZVN0ciA9IGZvcm1hdFRpbWUoRGF0ZS5ub3coKSAtIHRpbWUpO1xuICAgICAgICAgICAgbGV0IHJhdGVTdHIgPSBmb3JtYXROdW1iZXIocmVzdWx0Lmxlbmd0aCAvIChEYXRlLm5vdygpIC0gdGltZSkgKiAxMDAwKSArIFwiQi9zXCI7XG4gICAgICAgICAgICB0aGlzLmxvZyhgYmFja2JsYXplIGRvd25sb2FkICgke2Zvcm1hdE51bWJlcihyZXN1bHQubGVuZ3RoKX1CJHtjb25maWc/LnJhbmdlICYmIGAsICR7Zm9ybWF0TnVtYmVyKGNvbmZpZy5yYW5nZS5zdGFydCl9IC0gJHtmb3JtYXROdW1iZXIoY29uZmlnLnJhbmdlLmVuZCl9YCB8fCBcIlwifSkgaW4gJHt0aW1lU3RyfSAoJHtyYXRlU3RyfSwgJHtmaWxlTmFtZX0pYCk7XG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICB0aGlzLmxvZyhgYmFja2JsYXplIGZpbGUgZG9lcyBub3QgZXhpc3QgJHtmaWxlTmFtZX1gKTtcbiAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIH0gZmluYWxseSB7XG4gICAgICAgICAgICBkb3dubG9hZGluZyA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxuICAgIHB1YmxpYyBhc3luYyBnZXQyKGZpbGVOYW1lOiBzdHJpbmcsIGNvbmZpZz86IHsgcmFuZ2U/OiB7IHN0YXJ0OiBudW1iZXI7IGVuZDogbnVtYmVyOyB9IH0pOiBQcm9taXNlPHsgZGF0YTogQnVmZmVyOyB3cml0ZVRpbWU6IG51bWJlcjsgc2l6ZTogbnVtYmVyIH0gfCB1bmRlZmluZWQ+IHtcbiAgICAgICAgLy8gQjIgZG93bmxvYWRzIGRvbid0IHJldHVybiB0aGUgdXBsb2FkIHRpbWUsIHNvIHRoaXMgdGFrZXMgYSBzZWNvbmQgQVBJIGNhbGxcbiAgICAgICAgbGV0IFtkYXRhLCBpbmZvXSA9IGF3YWl0IFByb21pc2UuYWxsKFt0aGlzLmdldChmaWxlTmFtZSwgY29uZmlnKSwgdGhpcy5nZXRJbmZvKGZpbGVOYW1lKV0pO1xuICAgICAgICBpZiAoIWRhdGEgfHwgIWluZm8pIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIHJldHVybiB7IGRhdGEsIHdyaXRlVGltZTogaW5mby53cml0ZVRpbWUsIHNpemU6IGluZm8uc2l6ZSB9O1xuICAgIH1cbiAgICBwdWJsaWMgYXN5bmMgZ2V0Q29uZmlnKCk6IFByb21pc2U8QXJjaGl2ZXNDb25maWc+IHtcbiAgICAgICAgcmV0dXJuIHt9O1xuICAgIH1cbiAgICBwdWJsaWMgYXN5bmMgaGFzV3JpdGVBY2Nlc3MoKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBsZXQgYXBpID0gYXdhaXQgZ2V0QVBJKCk7XG4gICAgICAgICAgICAvLyBCMiB2MiBkb2N1bWVudHMgYWxsb3dlZCBhcyBhIHNpbmdsZSBvYmplY3Q7IG91ciB0eXBlIHNheXMgYSBsaXN0IC0gaGFuZGxlIGJvdGhcbiAgICAgICAgICAgIGxldCBhbGxvd2VkUmF3ID0gYXBpLmFsbG93ZWQgYXMgdW5rbm93bjtcbiAgICAgICAgICAgIGxldCBhbGxvd2VkTGlzdCA9IChBcnJheS5pc0FycmF5KGFsbG93ZWRSYXcpICYmIGFsbG93ZWRSYXcgfHwgW2FsbG93ZWRSYXddKSBhcyB0eXBlb2YgYXBpLmFsbG93ZWQ7XG4gICAgICAgICAgICByZXR1cm4gYWxsb3dlZExpc3Quc29tZShhbGxvd2VkID0+XG4gICAgICAgICAgICAgICAgYWxsb3dlZC5jYXBhYmlsaXRpZXMuaW5jbHVkZXMoXCJ3cml0ZUZpbGVzXCIpXG4gICAgICAgICAgICAgICAgJiYgKCFhbGxvd2VkLmJ1Y2tldE5hbWUgfHwgYWxsb3dlZC5idWNrZXROYW1lID09PSB0aGlzLmJ1Y2tldE5hbWUpXG4gICAgICAgICAgICApO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAvLyBObyAvIGludmFsaWQgY3JlZGVudGlhbHNcbiAgICAgICAgICAgIHRoaXMubG9nKGBiYWNrYmxhemUgaGFzV3JpdGVBY2Nlc3MgY2hlY2sgZmFpbGVkOiAkeyhlIGFzIEVycm9yKS5zdGFjayA/PyBlfWApO1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxuICAgIHB1YmxpYyBhc3luYyBzZXQoZmlsZU5hbWU6IHN0cmluZywgZGF0YTogQnVmZmVyLCBjb25maWc/OiB7IGxhc3RNb2RpZmllZD86IG51bWJlciB9KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmIChjb25maWc/Lmxhc3RNb2RpZmllZCkge1xuICAgICAgICAgICAgYXNzZXJ0VmFsaWRMYXN0TW9kaWZpZWQoY29uZmlnLmxhc3RNb2RpZmllZCk7XG4gICAgICAgICAgICBsZXQgZXhpc3RpbmcgPSBhd2FpdCB0aGlzLmdldEluZm8oZmlsZU5hbWUpO1xuICAgICAgICAgICAgLy8gQW4gb2xkZXIgd3JpdGUgbmV2ZXIgb3ZlcndyaXRlcyBhIG5ld2VyIG9uZSAoc2VlIElBcmNoaXZlcy5zZXQpLiBCMiBzdGFtcHMgaXRzIG93blxuICAgICAgICAgICAgLy8gdXBsb2FkIHRpbWUsIHNvIHRoZSBleGFjdCBsYXN0TW9kaWZpZWQgaXMgbm90IHByZXNlcnZlZCBvbiB0aGUgc3RvcmVkIGZpbGUuXG4gICAgICAgICAgICBpZiAoZXhpc3RpbmcgJiYgY29uZmlnLmxhc3RNb2RpZmllZCA8IGV4aXN0aW5nLndyaXRlVGltZSkgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMubG9nKGBiYWNrYmxhemUgdXBsb2FkICgke2Zvcm1hdE51bWJlcihkYXRhLmxlbmd0aCl9QikgJHtmaWxlTmFtZX1gKTtcbiAgICAgICAgbGV0IGYgPSBmaWxlTmFtZTtcbiAgICAgICAgYXdhaXQgdGhpcy5hcGlSZXRyeUxvZ2ljKGB1cGxvYWRGaWxlICR7ZmlsZU5hbWV9YCwgYXN5bmMgKGFwaSkgPT4ge1xuICAgICAgICAgICAgYXdhaXQgYXBpLnVwbG9hZEZpbGUoeyBidWNrZXRJZDogdGhpcy5idWNrZXRJZCwgZmlsZU5hbWUsIGRhdGE6IGRhdGEsIH0pO1xuICAgICAgICB9KTtcbiAgICAgICAgbGV0IGV4aXN0c0NoZWNrcyA9IDMwO1xuICAgICAgICB3aGlsZSAoZXhpc3RzQ2hlY2tzID4gMCkge1xuICAgICAgICAgICAgbGV0IGV4aXN0cyA9IGF3YWl0IHRoaXMuZ2V0SW5mbyhmaWxlTmFtZSk7XG4gICAgICAgICAgICBpZiAoZXhpc3RzKSBicmVhaztcbiAgICAgICAgICAgIGF3YWl0IGRlbGF5KDEwMDApO1xuICAgICAgICAgICAgZXhpc3RzQ2hlY2tzLS07XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGV4aXN0c0NoZWNrcyA9PT0gMCkge1xuICAgICAgICAgICAgbGV0IGV4aXN0cyA9IGF3YWl0IHRoaXMuZ2V0SW5mbyhmaWxlTmFtZSk7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oYEZpbGUgJHtmaWxlTmFtZX0vJHtmfSB3YXMgdXBsb2FkZWQsIGJ1dCBjb3VsZCBub3QgYmUgZm91bmQgYWZ0ZXJ3YXJkcy4gSG9wZWZ1bGx5IGl0IHdhcyBqdXN0IGRlbGV0ZWQsIHZlcnkgcXVpY2tseT8gSWYgYmFja2JsYXplIGlzIHRha2luZyB0b28gbG9uZyBmb3IgZmlsZXMgdG8gcHJvcGFnYXRlLCB0aGVuIHdlIG1pZ2h0IHJ1biBpbnRvIGlzc3VlcyB3aXRoIHRoZSBkYXRhYmFzZSBhdG9taWNpdHkuYCk7XG4gICAgICAgIH1cblxuICAgIH1cbiAgICBwdWJsaWMgYXN5bmMgZGVsKGZpbGVOYW1lOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgdGhpcy5sb2coYGJhY2tibGF6ZSBkZWxldGUgJHtmaWxlTmFtZX1gKTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuYXBpUmV0cnlMb2dpYyhgaGlkZUZpbGUgJHtmaWxlTmFtZX1gLCBhc3luYyAoYXBpKSA9PiB7XG4gICAgICAgICAgICAgICAgYXdhaXQgYXBpLmhpZGVGaWxlKHsgYnVja2V0SWQ6IHRoaXMuYnVja2V0SWQsIGZpbGVOYW1lOiBmaWxlTmFtZSB9KTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgICAgICAgIHRoaXMubG9nKGBiYWNrYmxhemUgZXJyb3IgaW4gaGlkZSwgcG9zc2libHkgYWxyZWFkeSBoaWRkZW4gJHtmaWxlTmFtZX1cXG4ke2Uuc3RhY2t9YCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBOT1RFOiBEZWxldGlvbiBTRUVNUyB0byB3b3JrLiBUaGlzIERPRVMgYnJlYWsgaWYgd2UgZGVsZXRlIGEgZmlsZSB3aGljaCBrZWVwcyBiZWluZyByZWNyZWF0ZWQsXG4gICAgICAgIC8vICBleCwgdGhlIGhlYXJ0YmVhdC5cbiAgICAgICAgLy8gbGV0IGV4aXN0c0NoZWNrcyA9IDEwO1xuICAgICAgICAvLyB3aGlsZSAoZXhpc3RzQ2hlY2tzID4gMCkge1xuICAgICAgICAvLyAgICAgbGV0IGV4aXN0cyA9IGF3YWl0IHRoaXMuZ2V0SW5mbyhmaWxlTmFtZSk7XG4gICAgICAgIC8vICAgICBpZiAoIWV4aXN0cykgYnJlYWs7XG4gICAgICAgIC8vICAgICBhd2FpdCBkZWxheSgxMDAwKTtcbiAgICAgICAgLy8gICAgIGV4aXN0c0NoZWNrcy0tO1xuICAgICAgICAvLyB9XG4gICAgICAgIC8vIGlmIChleGlzdHNDaGVja3MgPT09IDApIHtcbiAgICAgICAgLy8gICAgIGxldCBleGlzdHMgPSBhd2FpdCB0aGlzLmdldEluZm8oZmlsZU5hbWUpO1xuICAgICAgICAvLyAgICAgZGV2RGVidWdicmVhaygpO1xuICAgICAgICAvLyAgICAgY29uc29sZS53YXJuKGBGaWxlICR7ZmlsZU5hbWV9IHdhcyBkZWxldGVkLCBidXQgd2FzIHN0aWxsIGZvdW5kIGFmdGVyd2FyZHNgKTtcbiAgICAgICAgLy8gICAgIGV4aXN0cyA9IGF3YWl0IHRoaXMuZ2V0SW5mbyhmaWxlTmFtZSk7XG4gICAgICAgIC8vIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgc2V0TGFyZ2VGaWxlKGNvbmZpZzogeyBwYXRoOiBzdHJpbmc7IGdldE5leHREYXRhKCk6IFByb21pc2U8QnVmZmVyIHwgdW5kZWZpbmVkPjsgfSk6IFByb21pc2U8dm9pZD4ge1xuXG4gICAgICAgIGxldCBvbkVycm9yOiAoKCkgPT4gUHJvbWlzZTx2b2lkPilbXSA9IFtdO1xuICAgICAgICBsZXQgdGltZSA9IERhdGUubm93KCk7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBsZXQgeyBwYXRoIH0gPSBjb25maWc7XG4gICAgICAgICAgICAvLyBCYWNrYmxhemUgcmVxdWlyZXMgNU1CIGNodW5rcy4gQnV0LCBsYXJnZXIgaXMgbW9yZSBlZmZpY2llbnQgZm9yIHVzLlxuICAgICAgICAgICAgY29uc3QgTUlOX0NIVU5LX1NJWkUgPSAzMiAqIDEwMjQgKiAxMDI0O1xuICAgICAgICAgICAgbGV0IGRhdGFRdWV1ZTogQnVmZmVyW10gPSBbXTtcbiAgICAgICAgICAgIGFzeW5jIGZ1bmN0aW9uIGdldE5leHREYXRhKCk6IFByb21pc2U8QnVmZmVyIHwgdW5kZWZpbmVkPiB7XG4gICAgICAgICAgICAgICAgaWYgKGRhdGFRdWV1ZS5sZW5ndGgpIHJldHVybiBkYXRhUXVldWUuc2hpZnQoKTtcbiAgICAgICAgICAgICAgICAvLyBHZXQgYnVmZmVycyB1bnRpbCB3ZSBnZXQgNU1CLCBPUiwgZW5kLiBCYWNrYmxhemUgcmVxdWlyZXMgdGhpcyBmb3IgbGFyZ2UgZmlsZXMuXG4gICAgICAgICAgICAgICAgbGV0IHRvdGFsQnl0ZXMgPSAwO1xuICAgICAgICAgICAgICAgIGxldCBidWZmZXJzOiBCdWZmZXJbXSA9IFtdO1xuICAgICAgICAgICAgICAgIHdoaWxlICh0b3RhbEJ5dGVzIDwgTUlOX0NIVU5LX1NJWkUpIHtcbiAgICAgICAgICAgICAgICAgICAgbGV0IGRhdGEgPSBhd2FpdCBjb25maWcuZ2V0TmV4dERhdGEoKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFkYXRhKSBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgdG90YWxCeXRlcyArPSBkYXRhLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgYnVmZmVycy5wdXNoKGRhdGEpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoIWJ1ZmZlcnMubGVuZ3RoKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgIHJldHVybiBCdWZmZXIuY29uY2F0KGJ1ZmZlcnMpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBsZXQgZmlsZU5hbWUgPSBwYXRoO1xuICAgICAgICAgICAgbGV0IGRhdGEgPSBhd2FpdCBnZXROZXh0RGF0YSgpO1xuICAgICAgICAgICAgaWYgKCFkYXRhPy5sZW5ndGgpIHJldHVybjtcbiAgICAgICAgICAgIC8vIEJhY2tibGF6ZSBkaXNhbGxvd3Mgb3Zlcmx5IHNtYWxsIGZpbGVzXG4gICAgICAgICAgICBpZiAoZGF0YS5sZW5ndGggPCBNSU5fQ0hVTktfU0laRSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBhd2FpdCB0aGlzLnNldChmaWxlTmFtZSwgZGF0YSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBCYWNrYmxhemUgZGlzYWxsb3dzIGxlc3MgdGhhbiAyIGNodW5rc1xuICAgICAgICAgICAgbGV0IHNlY29uZERhdGEgPSBhd2FpdCBnZXROZXh0RGF0YSgpO1xuICAgICAgICAgICAgaWYgKCFzZWNvbmREYXRhPy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5zZXQoZmlsZU5hbWUsIGRhdGEpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gQUxTTywgaWYgdGhlcmUgYXJlIHR3byBjaHVua3MsIGJ1dCBvbmUgaXMgdG9vIHNtYWxsLCBjb21iaW5lIGl0LiBUaGlzIGhlbHBzIGFsbG93IHVzIG5ldmVyXG4gICAgICAgICAgICAvLyAgc2VuZCBzbWFsbCBjaHVua3MuXG4gICAgICAgICAgICBpZiAoc2Vjb25kRGF0YS5sZW5ndGggPCBNSU5fQ0hVTktfU0laRSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBhd2FpdCB0aGlzLnNldChmaWxlTmFtZSwgQnVmZmVyLmNvbmNhdChbZGF0YSwgc2Vjb25kRGF0YV0pKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMubG9nKGBVcGxvYWRpbmcgbGFyZ2UgZmlsZSAke2NvbmZpZy5wYXRofWApO1xuICAgICAgICAgICAgZGF0YVF1ZXVlLnVuc2hpZnQoZGF0YSwgc2Vjb25kRGF0YSk7XG5cblxuICAgICAgICAgICAgbGV0IHVwbG9hZEluZm8gPSBhd2FpdCB0aGlzLmFwaVJldHJ5TG9naWMoYHN0YXJ0TGFyZ2VGaWxlICR7ZmlsZU5hbWV9YCwgYXN5bmMgKGFwaSkgPT4ge1xuICAgICAgICAgICAgICAgIHJldHVybiBhd2FpdCBhcGkuc3RhcnRMYXJnZUZpbGUoe1xuICAgICAgICAgICAgICAgICAgICBidWNrZXRJZDogdGhpcy5idWNrZXRJZCxcbiAgICAgICAgICAgICAgICAgICAgZmlsZU5hbWU6IGZpbGVOYW1lLFxuICAgICAgICAgICAgICAgICAgICBjb250ZW50VHlwZTogXCJiMi94LWF1dG9cIixcbiAgICAgICAgICAgICAgICAgICAgZmlsZUluZm86IHt9LFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBvbkVycm9yLnB1c2goYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMuYXBpUmV0cnlMb2dpYyhgY2FuY2VsTGFyZ2VGaWxlICR7ZmlsZU5hbWV9YCwgYXN5bmMgKGFwaSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBhd2FpdCBhcGkuY2FuY2VsTGFyZ2VGaWxlKHsgZmlsZUlkOiB1cGxvYWRJbmZvLmZpbGVJZCB9KTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICBjb25zdCBMT0dfSU5URVJWQUwgPSB0aW1lSW5NaW51dGU7XG4gICAgICAgICAgICBsZXQgbmV4dExvZ1RpbWUgPSBEYXRlLm5vdygpICsgTE9HX0lOVEVSVkFMO1xuXG4gICAgICAgICAgICBsZXQgcGFydE51bWJlciA9IDE7XG4gICAgICAgICAgICBsZXQgcGFydFNoYTFBcnJheTogc3RyaW5nW10gPSBbXTtcbiAgICAgICAgICAgIGxldCB0b3RhbEJ5dGVzID0gMDtcbiAgICAgICAgICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICAgICAgICAgICAgZGF0YSA9IGF3YWl0IGdldE5leHREYXRhKCk7XG4gICAgICAgICAgICAgICAgaWYgKCFkYXRhKSBicmVhaztcbiAgICAgICAgICAgICAgICAvLyBTby4uLiBpZiB0aGUgbmV4dCBjaHVuayBpcyB0aGUgbGFzdCBvbmUsIGNvbWJpbmUgaXQgd2l0aCB0aGUgY3VycmVudCBvbmUuIFRoaXNcbiAgICAgICAgICAgICAgICAvLyAgcHJldmVudHMgQU5ZIHVwbG9hZHMgZnJvbSBiZWluZyA8IHRoZSB0aHJlc2hvbGQsIGFzIGFwcGFyZW50bHkgdGhlIFwibGFzdCBwYXJ0XCJcbiAgICAgICAgICAgICAgICAvLyAgY2hlY2sgaW4gYmFja2JsYXplIGZhaWxzIHdoZW4gd2UgaGF2ZSB0byByZXRyeSBhbiB1cGxvYWQgKGR1ZSB0byBcIm5vIHRvbWVzIGF2YWlsYWJsZVwiKS5cbiAgICAgICAgICAgICAgICAvLyAgV2VsbCBpdCBjYW4ndCBmYWlsIGlmIGV2ZW4gdGhlIGxhc3QgcGFydCBpcyA+IDVNQiwgbm93IGNhbiBpdCFcbiAgICAgICAgICAgICAgICAvLyBCVVQsIG9ubHkgaWYgdGhpcyBpc24ndCB0aGUgZmlyc3QgY2h1bmssIG90aGVyd2lzZSB3ZSBtaWdodCB0cnkgdG8gc2VuZFxuICAgICAgICAgICAgICAgIC8vICBhIHNpbmdsZSBjaHVuaywgd2hpY2ggd2UgY2FuJ3QgZG8uXG4gICAgICAgICAgICAgICAgaWYgKHBhcnRTaGExQXJyYXkubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgICAgICBsZXQgbWF5YmVMYXN0RGF0YSA9IGF3YWl0IGdldE5leHREYXRhKCk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChtYXliZUxhc3REYXRhKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAobWF5YmVMYXN0RGF0YS5sZW5ndGggPCBNSU5fQ0hVTktfU0laRSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEl0J3MgdGhlIGxhc3Qgb25lLCBzbyBjb25zdW1lIGl0IG5vd1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBCdWZmZXIuY29uY2F0KFtkYXRhLCBtYXliZUxhc3REYXRhXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEl0J3Mgbm90IHRoZSBsYXN0IG9uZS4gUHV0IGl0IGJhY2ssIGluIGNhc2UgdGhlIG9uZSBBRlRFUiBpcyB0aGUgbGFzdFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vICBvbmUsIGluIHdoaWNoIGNhc2Ugd2UgbmVlZCB0byBtZXJnZSBtYXliZUxhc3REYXRhIHdpdGggdGhlIG5leHQgbmV4dCBkYXRhLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGFRdWV1ZS51bnNoaWZ0KG1heWJlTGFzdERhdGEpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGxldCBzaGExID0gcmVxdWlyZShcImNyeXB0b1wiKS5jcmVhdGVIYXNoKFwic2hhMVwiKTtcbiAgICAgICAgICAgICAgICBzaGExLnVwZGF0ZShkYXRhKTtcbiAgICAgICAgICAgICAgICBsZXQgc2hhMUhleCA9IHNoYTEuZGlnZXN0KFwiaGV4XCIpO1xuICAgICAgICAgICAgICAgIHBhcnRTaGExQXJyYXkucHVzaChzaGExSGV4KTtcbiAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLmFwaVJldHJ5TG9naWMoYHVwbG9hZFBhcnQjJHtwYXJ0TnVtYmVyfSAke2ZpbGVOYW1lfWAsIGFzeW5jIChhcGkpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFkYXRhKSB0aHJvdyBuZXcgRXJyb3IoXCJJbXBvc3NpYmxlLCBkYXRhIGlzIHVuZGVmaW5lZFwiKTtcblxuICAgICAgICAgICAgICAgICAgICBsZXQgdGltZVN0ciA9IGZvcm1hdFRpbWUoRGF0ZS5ub3coKSAtIHRpbWUpO1xuICAgICAgICAgICAgICAgICAgICBsZXQgcmF0ZVN0ciA9IGZvcm1hdE51bWJlcih0b3RhbEJ5dGVzIC8gKERhdGUubm93KCkgLSB0aW1lKSAqIDEwMDApICsgXCJCL3NcIjtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2coYFVwbG9hZGluZyBsYXJnZSBmaWxlIHBhcnQgJHtwYXJ0TnVtYmVyfSwgdXBsb2FkZWQgJHtibHVlKGZvcm1hdE51bWJlcih0b3RhbEJ5dGVzKSArIFwiQlwiKX0gaW4gJHtibHVlKHRpbWVTdHIpfSAoJHtibHVlKHJhdGVTdHIpfSkuICR7Y29uZmlnLnBhdGh9YCk7XG4gICAgICAgICAgICAgICAgICAgIHRvdGFsQnl0ZXMgKz0gZGF0YS5sZW5ndGg7XG5cbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgYXBpLnVwbG9hZFBhcnQoe1xuICAgICAgICAgICAgICAgICAgICAgICAgZmlsZUlkOiB1cGxvYWRJbmZvLmZpbGVJZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIHBhcnROdW1iZXI6IHBhcnROdW1iZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICBkYXRhOiBkYXRhLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2hhMTogc2hhMUhleCxcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcGFydE51bWJlcisrO1xuXG4gICAgICAgICAgICAgICAgaWYgKERhdGUubm93KCkgPiBuZXh0TG9nVGltZSkge1xuICAgICAgICAgICAgICAgICAgICBuZXh0TG9nVGltZSA9IERhdGUubm93KCkgKyBMT0dfSU5URVJWQUw7XG4gICAgICAgICAgICAgICAgICAgIGxldCB0aW1lU3RyID0gZm9ybWF0VGltZShEYXRlLm5vdygpIC0gdGltZSk7XG4gICAgICAgICAgICAgICAgICAgIGxldCByYXRlU3RyID0gZm9ybWF0TnVtYmVyKHRvdGFsQnl0ZXMgLyAoRGF0ZS5ub3coKSAtIHRpbWUpICogMTAwMCkgKyBcIkIvc1wiO1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhgU3RpbGwgdXBsb2FkaW5nIGxhcmdlIGZpbGUgYXQgJHtEYXRlLm5vdygpfS4gVXBsb2FkZWQgJHtmb3JtYXROdW1iZXIodG90YWxCeXRlcyl9QiBpbiAke3RpbWVTdHJ9ICgke3JhdGVTdHJ9KS4gJHtjb25maWcucGF0aH1gKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLmxvZyhgRmluaXNoZWQgdXBsb2FkaW5nIGxhcmdlIGZpbGUgdXBsb2FkZWQgJHtncmVlbihmb3JtYXROdW1iZXIodG90YWxCeXRlcykpfUJgKTtcblxuICAgICAgICAgICAgYXdhaXQgdGhpcy5hcGlSZXRyeUxvZ2ljKGBmaW5pc2hMYXJnZUZpbGUgJHtmaWxlTmFtZX1gLCBhc3luYyAoYXBpKSA9PiB7XG4gICAgICAgICAgICAgICAgYXdhaXQgYXBpLmZpbmlzaExhcmdlRmlsZSh7XG4gICAgICAgICAgICAgICAgICAgIGZpbGVJZDogdXBsb2FkSW5mby5maWxlSWQsXG4gICAgICAgICAgICAgICAgICAgIHBhcnRTaGExQXJyYXk6IHBhcnRTaGExQXJyYXksXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICAgICAgICBmb3IgKGxldCBjIG9mIG9uRXJyb3IpIHtcbiAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICBhd2FpdCBjKCk7XG4gICAgICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKGBFcnJvciBkdXJpbmcgZXJyb3IgY2xlYW4uIElnbm9yaW5nLCB3ZSB3aWxsIHJldGhyb3cgdGhlIG9yaWdpbmFsIGVycm9yLCBwYXRoICR7Y29uZmlnLnBhdGh9YCwgZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEVycm9yIGluIHNldExhcmdlRmlsZSBmb3IgJHtjb25maWcucGF0aH06ICR7ZS5zdGFja31gKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBnZXRJbmZvKGZpbGVOYW1lOiBzdHJpbmcpOiBQcm9taXNlPHsgd3JpdGVUaW1lOiBudW1iZXI7IHNpemU6IG51bWJlcjsgfSB8IHVuZGVmaW5lZD4ge1xuICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5hcGlSZXRyeUxvZ2ljKGBnZXRJbmZvICR7ZmlsZU5hbWV9YCwgYXN5bmMgKGFwaSkgPT4ge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAvLyBOT1RFOiBBcHBhcmVudGx5LCB0aGVyZSdzIG5vIG90aGVyIHdheSB0byBkbyB0aGlzLCBhcyB0aGUgZmlsZSBuYW1lIGRvZXMgbm90IGVxdWFsIHRoZSBmaWxlIElELCBhbmQgZ2V0IGZpbGUgaW5mbyByZXF1aXJlcyB0aGUgZmlsZSBJRC5cbiAgICAgICAgICAgICAgICBsZXQgaW5mbyA9IGF3YWl0IGFwaS5saXN0RmlsZU5hbWVzKHsgYnVja2V0SWQ6IHRoaXMuYnVja2V0SWQsIHByZWZpeDogZmlsZU5hbWUsIG1heEZpbGVDb3VudDogMTAgfSk7XG4gICAgICAgICAgICAgICAgbGV0IGZpbGUgPSBpbmZvLmZpbGVzLmZpbmQoeCA9PiB4LmZpbGVOYW1lID09PSBmaWxlTmFtZSAmJiB4LmFjdGlvbiA9PT0gXCJ1cGxvYWRcIik7XG4gICAgICAgICAgICAgICAgaWYgKCFmaWxlKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMubG9nKGBCYWNrYmxhemUgZmlsZSBub3QgZXhpc3RzICR7ZmlsZU5hbWV9YCk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRoaXMubG9nKGBCYWNrYmxhemUgZmlsZSBleGlzdHMgJHtmaWxlTmFtZX1gKTtcbiAgICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgICAgICB3cml0ZVRpbWU6IGZpbGUudXBsb2FkVGltZXN0YW1wLFxuICAgICAgICAgICAgICAgICAgICBzaXplOiBmaWxlLmNvbnRlbnRMZW5ndGgsXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgICAgICAgICAgIGlmIChlLnN0YWNrLmluY2x1ZGVzKGBmaWxlX25vdF9mb3VuZGApKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMubG9nKGBCYWNrYmxhemUgZmlsZSBub3QgZXhpc3RzICR7ZmlsZU5hbWV9YCk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRocm93IGU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIC8vIEZvciBleGFtcGxlIGZpbmRGaWxlTmFtZXMoXCJpcHMvXCIpXG4gICAgcHVibGljIGFzeW5jIGZpbmQocHJlZml4OiBzdHJpbmcsIGNvbmZpZz86IHsgc2hhbGxvdz86IGJvb2xlYW47IHR5cGU6IFwiZmlsZXNcIiB8IFwiZm9sZGVyc1wiIH0pOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gICAgICAgIGxldCByZXN1bHQgPSBhd2FpdCB0aGlzLmZpbmRJbmZvKHByZWZpeCwgY29uZmlnKTtcbiAgICAgICAgcmV0dXJuIHJlc3VsdC5tYXAoeCA9PiB4LnBhdGgpO1xuICAgIH1cbiAgICBwdWJsaWMgYXN5bmMgZmluZEluZm8ocHJlZml4OiBzdHJpbmcsIGNvbmZpZz86IHsgc2hhbGxvdz86IGJvb2xlYW47IHR5cGU6IFwiZmlsZXNcIiB8IFwiZm9sZGVyc1wiIH0pOiBQcm9taXNlPHsgcGF0aDogc3RyaW5nOyBjcmVhdGVUaW1lOiBudW1iZXI7IHNpemU6IG51bWJlcjsgfVtdPiB7XG4gICAgICAgIHJldHVybiBhd2FpdCB0aGlzLmFwaVJldHJ5TG9naWMoYGZpbmRJbmZvICR7cHJlZml4fWAsIGFzeW5jIChhcGkpID0+IHtcbiAgICAgICAgICAgIGlmICghY29uZmlnPy5zaGFsbG93ICYmIGNvbmZpZz8udHlwZSA9PT0gXCJmb2xkZXJzXCIpIHtcbiAgICAgICAgICAgICAgICBsZXQgYWxsRmlsZXMgPSBhd2FpdCB0aGlzLmZpbmRJbmZvKHByZWZpeCk7XG4gICAgICAgICAgICAgICAgbGV0IGFsbEZvbGRlcnMgPSBuZXcgTWFwPHN0cmluZywgeyBwYXRoOiBzdHJpbmc7IGNyZWF0ZVRpbWU6IG51bWJlcjsgc2l6ZTogbnVtYmVyIH0+KCk7XG4gICAgICAgICAgICAgICAgZm9yIChsZXQgeyBwYXRoLCBjcmVhdGVUaW1lLCBzaXplIH0gb2YgYWxsRmlsZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgbGV0IGZvbGRlciA9IHBhdGguc3BsaXQoXCIvXCIpLnNsaWNlKDAsIC0xKS5qb2luKFwiL1wiKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFmb2xkZXIpIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgICAgICBhbGxGb2xkZXJzLnNldChmb2xkZXIsIHsgcGF0aDogZm9sZGVyLCBjcmVhdGVUaW1lLCBzaXplIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gQXJyYXkuZnJvbShhbGxGb2xkZXJzLnZhbHVlcygpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxldCBmaWxlcyA9IG5ldyBNYXA8c3RyaW5nLCB7IHBhdGg6IHN0cmluZzsgY3JlYXRlVGltZTogbnVtYmVyOyBzaXplOiBudW1iZXI7IH0+KCk7XG4gICAgICAgICAgICBsZXQgc3RhcnRGaWxlTmFtZSA9IFwiXCI7XG4gICAgICAgICAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgICAgICAgICAgIGxldCByZXN1bHQgPSBhd2FpdCBhcGkubGlzdEZpbGVOYW1lcyh7XG4gICAgICAgICAgICAgICAgICAgIGJ1Y2tldElkOiB0aGlzLmJ1Y2tldElkLFxuICAgICAgICAgICAgICAgICAgICBwcmVmaXg6IHByZWZpeCxcbiAgICAgICAgICAgICAgICAgICAgc3RhcnRGaWxlTmFtZSxcbiAgICAgICAgICAgICAgICAgICAgbWF4RmlsZUNvdW50OiAxMDAwLFxuICAgICAgICAgICAgICAgICAgICBkZWxpbWl0ZXI6IGNvbmZpZz8uc2hhbGxvdyA/IFwiL1wiIDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIGZvciAobGV0IGZpbGUgb2YgcmVzdWx0LmZpbGVzKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChmaWxlLmFjdGlvbiA9PT0gXCJ1cGxvYWRcIiAmJiBjb25maWc/LnR5cGUgIT09IFwiZm9sZGVyc1wiKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBmaWxlcy5zZXQoZmlsZS5maWxlTmFtZSwgeyBwYXRoOiBmaWxlLmZpbGVOYW1lLCBjcmVhdGVUaW1lOiBmaWxlLnVwbG9hZFRpbWVzdGFtcCwgc2l6ZTogZmlsZS5jb250ZW50TGVuZ3RoIH0pO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGZpbGUuYWN0aW9uID09PSBcImZvbGRlclwiICYmIGNvbmZpZz8udHlwZSA9PT0gXCJmb2xkZXJzXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGxldCBmb2xkZXIgPSBmaWxlLmZpbGVOYW1lO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGZvbGRlci5lbmRzV2l0aChcIi9cIikpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb2xkZXIgPSBmb2xkZXIuc2xpY2UoMCwgLTEpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgZmlsZXMuc2V0KGZvbGRlciwgeyBwYXRoOiBmb2xkZXIsIGNyZWF0ZVRpbWU6IGZpbGUudXBsb2FkVGltZXN0YW1wLCBzaXplOiBmaWxlLmNvbnRlbnRMZW5ndGggfSk7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBzdGFydEZpbGVOYW1lID0gcmVzdWx0Lm5leHRGaWxlTmFtZTtcbiAgICAgICAgICAgICAgICBpZiAoIXN0YXJ0RmlsZU5hbWUpIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIEFycmF5LmZyb20oZmlsZXMudmFsdWVzKCkpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgYXNzZXJ0UGF0aFZhbGlkKHBhdGg6IHN0cmluZykge1xuICAgICAgICBsZXQgYnl0ZXMgPSBCdWZmZXIuZnJvbShwYXRoLCBcInV0ZjhcIik7XG4gICAgICAgIGlmIChieXRlcy5sZW5ndGggPiAxMDAwKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFBhdGggdG9vIGxvbmc6ICR7cGF0aC5sZW5ndGh9IGNoYXJhY3RlcnMgPiAxMDAwIGNoYXJhY3RlcnMuIFBhdGg6ICR7cGF0aH1gKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBtb3ZlKGNvbmZpZzoge1xuICAgICAgICBwYXRoOiBzdHJpbmc7XG4gICAgICAgIHRhcmdldDogSUFyY2hpdmVzO1xuICAgICAgICB0YXJnZXRQYXRoOiBzdHJpbmc7XG4gICAgICAgIGNvcHlJbnN0ZWFkPzogYm9vbGVhbjtcbiAgICB9KSB7XG4gICAgICAgIGxldCB7IHBhdGgsIHRhcmdldCwgdGFyZ2V0UGF0aCB9ID0gY29uZmlnO1xuICAgICAgICAvLyBBIHNlbGYgbW92ZSBzaG91bGQgTk9PUCAoYW5kIGRlZmluaXRlbHkgbm90IGNvcHksIGFuZCB0aGVuIGRlbGV0ZSBpdHNlbGYhKVxuICAgICAgICBpZiAodGFyZ2V0ID09PSB0aGlzICYmIHBhdGggPT09IHRhcmdldFBhdGgpIHtcbiAgICAgICAgICAgIHRoaXMubG9nKGBCYWNrYmxhemUgbW92ZSBwYXRoIHRvIGl0c2VsZi4gU2tpcHBpbmcgbW92ZSwgYXMgdGhlcmUgaXMgbm8gd29yayB0byBkby4gJHtwYXRofWApO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0YXJnZXQgaW5zdGFuY2VvZiBBcmNoaXZlc0JhY2tibGF6ZSkge1xuICAgICAgICAgICAgbGV0IHRhcmdldEJ1Y2tldElkID0gdGFyZ2V0LmJ1Y2tldElkO1xuICAgICAgICAgICAgaWYgKHRhcmdldEJ1Y2tldElkID09PSB0aGlzLmJ1Y2tldElkICYmIHBhdGggPT09IHRhcmdldFBhdGgpIHJldHVybjtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuYXBpUmV0cnlMb2dpYyhgbW92ZSAke3BhdGh9IC0+ICR7dGFyZ2V0UGF0aH1gLCBhc3luYyAoYXBpKSA9PiB7XG4gICAgICAgICAgICAgICAgLy8gVWdoLi4uIGxpc3RpbmcgdGhlIGZpbGUgbmFtZSBzdWNrcywgYnV0Li4uIEkgZ3Vlc3MgaXQncyBzdGlsbCBiZXR0ZXIgdGhhblxuICAgICAgICAgICAgICAgIC8vICBkb3dubG9hZGluZyBhbmQgcmUtdXBsb2FkaW5nIHRoZSBlbnRpcmUgZmlsZS5cbiAgICAgICAgICAgICAgICBsZXQgaW5mbyA9IGF3YWl0IGFwaS5saXN0RmlsZU5hbWVzKHsgYnVja2V0SWQ6IHRoaXMuYnVja2V0SWQsIHByZWZpeDogcGF0aCwgbWF4RmlsZUNvdW50OiAxMCB9KTtcbiAgICAgICAgICAgICAgICBsZXQgZmlsZSA9IGluZm8uZmlsZXMuZmluZCh4ID0+IHguZmlsZU5hbWUgPT09IHBhdGgpO1xuICAgICAgICAgICAgICAgIGlmICghZmlsZSkgdGhyb3cgbmV3IEVycm9yKGBGaWxlIG5vdCBmb3VuZCB0byBtb3ZlOiAke3BhdGh9YCk7XG4gICAgICAgICAgICAgICAgYXdhaXQgYXBpLmNvcHlGaWxlKHtcbiAgICAgICAgICAgICAgICAgICAgc291cmNlRmlsZUlkOiBmaWxlLmZpbGVJZCxcbiAgICAgICAgICAgICAgICAgICAgZmlsZU5hbWU6IHRhcmdldFBhdGgsXG4gICAgICAgICAgICAgICAgICAgIGRlc3RpbmF0aW9uQnVja2V0SWQ6IHRhcmdldEJ1Y2tldElkLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBsZXQgZGF0YSA9IGF3YWl0IHRoaXMuZ2V0KHBhdGgpO1xuICAgICAgICAgICAgaWYgKCFkYXRhKSB0aHJvdyBuZXcgRXJyb3IoYEZpbGUgbm90IGZvdW5kIHRvIG1vdmU6ICR7cGF0aH1gKTtcbiAgICAgICAgICAgIGF3YWl0IHRhcmdldC5zZXQodGFyZ2V0UGF0aCwgZGF0YSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIWNvbmZpZy5jb3B5SW5zdGVhZCkge1xuICAgICAgICAgICAgbGV0IGV4aXN0cyA9IGF3YWl0IHRoaXMuZ2V0SW5mbyh0YXJnZXRQYXRoKTtcbiAgICAgICAgICAgIGlmICghZXhpc3RzKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihgRmlsZSBub3QgZm91bmQgYWZ0ZXIgbW92ZS4gTGVhdmluZyBCT1RIIGZpbGVzLiAke3RhcmdldFBhdGh9IHdhcyBub3QgZm91bmQuIEJlaW5nIG1vdmVkIGZyb20gJHtwYXRofWApO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLmRlbChwYXRoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBjb3B5KGNvbmZpZzoge1xuICAgICAgICBwYXRoOiBzdHJpbmc7XG4gICAgICAgIHRhcmdldDogSUFyY2hpdmVzO1xuICAgICAgICB0YXJnZXRQYXRoOiBzdHJpbmc7XG4gICAgfSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICByZXR1cm4gdGhpcy5tb3ZlKHsgLi4uY29uZmlnLCBjb3B5SW5zdGVhZDogdHJ1ZSB9KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgZ2V0VVJMKHBhdGg6IHN0cmluZykge1xuICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5hcGlSZXRyeUxvZ2ljKGBnZXRVUkwgJHtwYXRofWAsIGFzeW5jIChhcGkpID0+IHtcbiAgICAgICAgICAgIGlmIChwYXRoLnN0YXJ0c1dpdGgoXCIvXCIpKSB7XG4gICAgICAgICAgICAgICAgcGF0aCA9IHBhdGguc2xpY2UoMSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgYXBpLmdldERvd25sb2FkVVJMKFwiZmlsZS9cIiArIHRoaXMuYnVja2V0TmFtZSArIFwiL1wiICsgcGF0aCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBnZXREb3dubG9hZEF1dGhvcml6YXRpb24oY29uZmlnOiB7XG4gICAgICAgIGZpbGVOYW1lUHJlZml4Pzogc3RyaW5nO1xuICAgICAgICB2YWxpZER1cmF0aW9uSW5TZWNvbmRzOiBudW1iZXI7XG4gICAgICAgIGIyQ29udGVudERpc3Bvc2l0aW9uPzogc3RyaW5nO1xuICAgICAgICBiMkNvbnRlbnRMYW5ndWFnZT86IHN0cmluZztcbiAgICAgICAgYjJFeHBpcmVzPzogc3RyaW5nO1xuICAgICAgICBiMkNhY2hlQ29udHJvbD86IHN0cmluZztcbiAgICAgICAgYjJDb250ZW50RW5jb2Rpbmc/OiBzdHJpbmc7XG4gICAgICAgIGIyQ29udGVudFR5cGU/OiBzdHJpbmc7XG4gICAgfSk6IFByb21pc2U8e1xuICAgICAgICBidWNrZXRJZDogc3RyaW5nO1xuICAgICAgICBmaWxlTmFtZVByZWZpeDogc3RyaW5nO1xuICAgICAgICBhdXRob3JpemF0aW9uVG9rZW46IHN0cmluZztcbiAgICB9PiB7XG4gICAgICAgIHJldHVybiBhd2FpdCB0aGlzLmFwaVJldHJ5TG9naWMoYGdldERvd25sb2FkQXV0aG9yaXphdGlvbiAke2NvbmZpZy5maWxlTmFtZVByZWZpeCA/PyBcIlwifWAsIGFzeW5jIChhcGkpID0+IHtcbiAgICAgICAgICAgIHJldHVybiBhd2FpdCBhcGkuZ2V0RG93bmxvYWRBdXRob3JpemF0aW9uKHtcbiAgICAgICAgICAgICAgICBidWNrZXRJZDogdGhpcy5idWNrZXRJZCxcbiAgICAgICAgICAgICAgICBmaWxlTmFtZVByZWZpeDogY29uZmlnLmZpbGVOYW1lUHJlZml4ID8/IFwiXCIsXG4gICAgICAgICAgICAgICAgLi4uY29uZmlnLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgIH1cbn1cblxuLypcbk5hbWVzIHNob3VsZCBiZSBhIFVURi04IHN0cmluZyB1cCB0byAxMDI0IGJ5dGVzIHdpdGggdGhlIGZvbGxvd2luZyBleGNlcHRpb25zOlxuICAgIENoYXJhY3RlciBjb2RlcyBiZWxvdyAzMiBhcmUgbm90IGFsbG93ZWQuXG4gICAgREVMIGNoYXJhY3RlcnMgKDEyNykgYXJlIG5vdCBhbGxvd2VkLlxuICAgIEJhY2tzbGFzaGVzIGFyZSBub3QgYWxsb3dlZC5cbiAgICBGaWxlIG5hbWVzIGNhbm5vdCBzdGFydCB3aXRoIC8sIGVuZCB3aXRoIC8sIG9yIGNvbnRhaW4gLy8uXG4qL1xuXG5cbmV4cG9ydCBjb25zdCBnZXRBcmNoaXZlc0JhY2tibGF6ZSA9IGNhY2hlKChkb21haW46IHN0cmluZykgPT4ge1xuICAgIHJldHVybiBuZXcgQXJjaGl2ZXNCYWNrYmxhemUoeyBidWNrZXROYW1lOiBkb21haW4gfSk7XG59KTtcbmV4cG9ydCBjb25zdCBnZXRBcmNoaXZlc0JhY2tibGF6ZVByaXZhdGVJbW11dGFibGUgPSBjYWNoZSgoZG9tYWluOiBzdHJpbmcpID0+IHtcbiAgICByZXR1cm4gbmV3IEFyY2hpdmVzQmFja2JsYXplKHtcbiAgICAgICAgYnVja2V0TmFtZTogZG9tYWluICsgXCItcHJpdmF0ZS1pbW11dGFibGVcIixcbiAgICAgICAgaW1tdXRhYmxlOiB0cnVlXG4gICAgfSk7XG59KTtcbmV4cG9ydCBjb25zdCBnZXRBcmNoaXZlc0JhY2tibGF6ZVB1YmxpY0ltbXV0YWJsZSA9IGNhY2hlKChkb21haW46IHN0cmluZykgPT4ge1xuICAgIHJldHVybiBuZXcgQXJjaGl2ZXNCYWNrYmxhemUoe1xuICAgICAgICBidWNrZXROYW1lOiBkb21haW4gKyBcIi1wdWJsaWMtaW1tdXRhYmxlXCIsXG4gICAgICAgIHB1YmxpYzogdHJ1ZSxcbiAgICAgICAgaW1tdXRhYmxlOiB0cnVlLFxuICAgICAgICBhbGxvd2VkT3JpZ2luczogW2BodHRwczovLyR7ZG9tYWlufWAsIGBodHRwczovLzEyNy0wLTAtMS4ke2RvbWFpbn06NzAwN2BdLFxuICAgIH0pO1xufSk7XG5cbi8vIE5PVEU6IENhY2hlIGJ5IGEgbWludXRlLiBUaGlzIG1pZ2h0IGJlIGEgYmFkIGlkZWEsIGJ1dC4uLiB1c3VhbGx5IHdob2xlIHJlYXNvbiBmb3IgcHVibGljIGlzXG4vLyAgZm9yIGNsb3VkZmxhcmUgY2FjaGluZyAoYXMgb3RoZXJ3aXNlIHdlIGNhbiBqdXN0IGFjY2VzcyBpdCB0aHJvdWdoIGEgc2VydmVyKSwgb3IgZm9yIGxhcmdlIGZpbGVzXG4vLyAgKHdoaWNoIHNob3VsZCBiZSBjYWNoZWQgYW55d2F5cywgYW5kIHByb2JhYmx5IGV2ZW4gdXNlIGltbXV0YWJsZSBjYWNoaW5nKS5cbmV4cG9ydCBjb25zdCBnZXRBcmNoaXZlc0JhY2tibGF6ZVB1YmxpYyA9IGNhY2hlKChkb21haW46IHN0cmluZykgPT4ge1xuICAgIHJldHVybiBuZXcgQXJjaGl2ZXNCYWNrYmxhemUoe1xuICAgICAgICBidWNrZXROYW1lOiBkb21haW4gKyBcIi1wdWJsaWNcIixcbiAgICAgICAgcHVibGljOiB0cnVlLFxuICAgICAgICBjYWNoZVRpbWU6IHRpbWVJbk1pbnV0ZSxcbiAgICAgICAgYWxsb3dlZE9yaWdpbnM6IFtgaHR0cHM6Ly8ke2RvbWFpbn1gLCBgaHR0cHM6Ly8xMjctMC0wLTEuJHtkb21haW59OjcwMDdgXSxcbiAgICB9KTtcbn0pOyJdfQ==
|
|
797
|
+
/* _JS_SOURCE_HASH = "3e97e23ad6f49500641f2b4f9e5b6d839e15c53a0f7ebecd2222f65b2bc61eae"; */
|