213 lines
32 KiB
Plaintext
213 lines
32 KiB
Plaintext
import BatchingQueue from "/_nuxt/@fs/D:/speckle-server/packages/objectloader2/dist/esm/queues/batchingQueue.js";
|
|
import { ObjectLoaderRuntimeError } from "/_nuxt/@fs/D:/speckle-server/packages/objectloader2/dist/esm/types/errors.js";
|
|
import { indexOf, isBase, take } from "/_nuxt/@fs/D:/speckle-server/packages/objectloader2/dist/esm/types/functions.js";
|
|
const MAX_SAFARI_DECODE_BYTES = 2 * 1024 * 1024 * 1024 - 1024 * 1024; // 2GB minus a margin
|
|
export default class ServerDownloader {
|
|
#requestUrlRootObj;
|
|
#requestUrlChildren;
|
|
#headers;
|
|
#options;
|
|
#fetch;
|
|
#results;
|
|
#total;
|
|
#logger;
|
|
#downloadQueue;
|
|
#decoder = new TextDecoder('utf-8', { fatal: true });
|
|
#decodedBytesCount = 0;
|
|
#rawStrings = [];
|
|
#rawEncodings = [];
|
|
constructor(options) {
|
|
this.#options = options;
|
|
this.#logger = options.logger;
|
|
this.#fetch =
|
|
options.fetch ?? ((...args) => globalThis.fetch(...args));
|
|
this.#headers = {};
|
|
if (options.headers) {
|
|
for (const header of options.headers.entries()) {
|
|
this.#headers[header[0]] = header[1];
|
|
}
|
|
}
|
|
this.#headers['Accept'] = `text/plain`;
|
|
if (this.#options.token) {
|
|
this.#headers['Authorization'] = `Bearer ${this.#options.token}`;
|
|
}
|
|
this.#requestUrlChildren = `${this.#options.serverUrl}/api/v2/projects/${this.#options.streamId}/object-stream/`;
|
|
this.#requestUrlRootObj = `${this.#options.serverUrl}/objects/${this.#options.streamId}/${this.#options.objectId}/single`;
|
|
const encoder = new TextEncoder();
|
|
if (options.objectTypeMask) {
|
|
this.#rawStrings.push(...options.objectTypeMask);
|
|
this.#rawEncodings.push(...options.objectTypeMask.map((val) => encoder.encode(val)));
|
|
}
|
|
}
|
|
initialize(params) {
|
|
const { results, total, maxDownloadBatchWait } = params;
|
|
this.#results = results;
|
|
this.#total = total;
|
|
this.#downloadQueue = new BatchingQueue({
|
|
batchSize: 15000, // 15k is a good number for most cases
|
|
maxWaitTime: maxDownloadBatchWait ?? 1000, // 1 second
|
|
processFunction: (batch) => this.downloadBatch({
|
|
batch,
|
|
url: this.#requestUrlChildren,
|
|
headers: this.#headers
|
|
})
|
|
});
|
|
}
|
|
add(id) {
|
|
this.#downloadQueue?.add(id, id);
|
|
}
|
|
/*
|
|
This is the most frequently reported and confirmed reason for this error in Safari. There's a known bug in WebKit (Safari's rendering engine) where TextDecoder can fail or throw a RangeError after decoding around 2GB of data. Chrome and other browsers handle much larger amounts of data without this specific limitation.
|
|
|
|
Why it happens: It seems to be an internal memory or indexing limitation within Safari's TextDecoder implementation. After a certain threshold of data has been processed by a TextDecoder instance, it starts throwing this error.
|
|
|
|
Chrome's behavior: Chrome generally handles larger data sizes without this specific RangeError. It might become slow or run out of general memory, but not typically with this specific error.
|
|
*/
|
|
decodeChunk(chunkBuffer) {
|
|
if (this.#decodedBytesCount + chunkBuffer.byteLength > MAX_SAFARI_DECODE_BYTES) {
|
|
// Safari is approaching its limit, create a new decoder
|
|
this.#decoder = new TextDecoder('utf-8', { fatal: true });
|
|
this.#decodedBytesCount = 0; // Reset counter for the new decoder
|
|
}
|
|
const decodedText = this.#decoder.decode(chunkBuffer);
|
|
this.#decodedBytesCount += chunkBuffer.byteLength;
|
|
return decodedText;
|
|
}
|
|
async disposeAsync() {
|
|
await this.#downloadQueue?.disposeAsync();
|
|
}
|
|
async downloadBatch(params) {
|
|
const { batch, url, headers } = params;
|
|
const start = performance.now();
|
|
this.#logger(`Downloading batch of ${batch.length} items...`);
|
|
const attributeMask = this.#options.attributeMask;
|
|
const keys = new Set(batch);
|
|
const response = await this.#fetch(url, {
|
|
method: 'POST',
|
|
headers: { ...headers, 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ objectIds: batch, attributeMask })
|
|
});
|
|
this.#validateResponse(response);
|
|
if (!response.body) {
|
|
throw new Error('ReadableStream not supported or response has no body.');
|
|
}
|
|
const reader = response.body.getReader();
|
|
let leftover = new Uint8Array(0);
|
|
let count = 0;
|
|
while (true) {
|
|
const { done, value } = await reader.read();
|
|
if (done)
|
|
break;
|
|
leftover = await this.#processArray(leftover, value, keys, async () => {
|
|
count++;
|
|
if (count % 1000 === 0) {
|
|
await new Promise((resolve) => setTimeout(resolve, 100)); //allow other stuff to happen
|
|
}
|
|
});
|
|
}
|
|
if (keys.size > 0) {
|
|
throw new Error('Items requested were not downloaded: ' + take(keys.values(), 10).join(','));
|
|
}
|
|
count += keys.size; // count the leftovers
|
|
if (count >= this.#total) {
|
|
await this.#results?.disposeAsync(); // mark the queue as done
|
|
}
|
|
this.#logger(`Downloaded batch of ${batch.length} items in ${performance.now() - start}ms`);
|
|
}
|
|
async #processArray(leftover, value, keys, callback) {
|
|
//this concat will allocate a new array
|
|
const combined = this.#concatUint8Arrays(leftover, value);
|
|
let start = 0;
|
|
//subarray doesn't allocate
|
|
for (let i = 0; i < combined.length; i++) {
|
|
if (combined[i] === 0x0a) {
|
|
const line = combined.subarray(start, i); // line without \n
|
|
//strings are allocated here
|
|
const item = this.#processLine(line);
|
|
start = i + 1;
|
|
await callback();
|
|
keys.delete(item.baseId);
|
|
this.#results?.add(item);
|
|
}
|
|
}
|
|
return combined.subarray(start); // carry over remainder
|
|
}
|
|
#processLine(line) {
|
|
for (let i = 0; i < line.length; i++) {
|
|
if (line[i] === 0x09) {
|
|
//this is a tab
|
|
const baseId = this.decodeChunk(line.subarray(0, i));
|
|
const jsonBytes = line.subarray(i + 1);
|
|
if (!this.#isValidBytes(jsonBytes)) {
|
|
return { baseId, base: undefined };
|
|
}
|
|
const base = this.decodeChunk(jsonBytes);
|
|
const item = this.#processJson(baseId, base);
|
|
item.size = jsonBytes.length;
|
|
return item;
|
|
}
|
|
}
|
|
throw new ObjectLoaderRuntimeError('Invalid line format in response: ' + this.decodeChunk(line));
|
|
}
|
|
#processJson(baseId, unparsedBase) {
|
|
let base;
|
|
try {
|
|
base = JSON.parse(unparsedBase);
|
|
}
|
|
catch (e) {
|
|
throw new Error(`Error parsing object ${baseId}: ${e.message}`);
|
|
}
|
|
if (isBase(base)) {
|
|
return { baseId, base };
|
|
}
|
|
else {
|
|
throw new ObjectLoaderRuntimeError(`${baseId} is not a base`);
|
|
}
|
|
}
|
|
#isValidString(json) {
|
|
for (const rawString of this.#rawStrings)
|
|
if (json.includes(rawString)) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
#isValidBytes(json) {
|
|
for (const rawEncoding of this.#rawEncodings)
|
|
if (indexOf(json, rawEncoding) !== -1) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
#concatUint8Arrays(a, b) {
|
|
const c = new Uint8Array(a.length + b.length);
|
|
c.set(a, 0);
|
|
c.set(b, a.length);
|
|
return c;
|
|
}
|
|
async downloadSingle() {
|
|
const response = await this.#fetch(this.#requestUrlRootObj, {
|
|
headers: this.#headers
|
|
});
|
|
this.#validateResponse(response);
|
|
const responseText = await response.text();
|
|
if (!this.#isValidString(responseText)) {
|
|
throw new ObjectLoaderRuntimeError('Invalid base object');
|
|
}
|
|
const item = this.#processJson(this.#options.objectId, responseText);
|
|
if (!item.base) {
|
|
throw new ObjectLoaderRuntimeError('Invalid base object');
|
|
}
|
|
item.size = 0;
|
|
return item;
|
|
}
|
|
#validateResponse(response) {
|
|
if (!response.ok) {
|
|
if ([401, 403].includes(response.status)) {
|
|
throw new ObjectLoaderRuntimeError('You do not have access!');
|
|
}
|
|
throw new ObjectLoaderRuntimeError(`Failed to fetch objects: ${response.status} ${response.statusText})`);
|
|
}
|
|
}
|
|
}
|
|
|
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmVyRG93bmxvYWRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9jb3JlL3N0YWdlcy9zZXJ2ZXJEb3dubG9hZGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sYUFBYSxNQUFNLCtCQUErQixDQUFBO0FBRXpELE9BQU8sRUFBRSx3QkFBd0IsRUFBRSxNQUFNLHVCQUF1QixDQUFBO0FBQ2hFLE9BQU8sRUFBeUIsT0FBTyxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQTtBQWdCdkYsTUFBTSx1QkFBdUIsR0FBRyxDQUFDLEdBQUcsSUFBSSxHQUFHLElBQUksR0FBRyxJQUFJLEdBQUcsSUFBSSxHQUFHLElBQUksQ0FBQSxDQUFDLHFCQUFxQjtBQUUxRixNQUFNLENBQUMsT0FBTyxPQUFPLGdCQUFnQjtJQUNuQyxrQkFBa0IsQ0FBUTtJQUMxQixtQkFBbUIsQ0FBUTtJQUMzQixRQUFRLENBQWE7SUFDckIsUUFBUSxDQUF5QjtJQUNqQyxNQUFNLENBQVM7SUFDZixRQUFRLENBQWM7SUFDdEIsTUFBTSxDQUFTO0lBQ2YsT0FBTyxDQUFjO0lBRXJCLGNBQWMsQ0FBd0I7SUFDdEMsUUFBUSxHQUFHLElBQUksV0FBVyxDQUFDLE9BQU8sRUFBRSxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFBO0lBQ3BELGtCQUFrQixHQUFHLENBQUMsQ0FBQTtJQUV0QixXQUFXLEdBQWtCLEVBQUUsQ0FBQTtJQUMvQixhQUFhLEdBQXNCLEVBQUUsQ0FBQTtJQUVyQyxZQUFZLE9BQWdDO1FBQzFDLElBQUksQ0FBQyxRQUFRLEdBQUcsT0FBTyxDQUFBO1FBQ3ZCLElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQTtRQUM3QixJQUFJLENBQUMsTUFBTTtZQUNULE9BQU8sQ0FBQyxLQUFLLElBQUksQ0FBQyxDQUFDLEdBQUcsSUFBSSxFQUFxQixFQUFFLENBQUMs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QyxrQkFBa0IsRUFBRTtZQUMxRCxPQUFPLEVBQUUsSUFBSSxDQUFDLFFBQVE7U0FDdkIsQ0FBQyxDQUFBO1FBQ0YsSUFBSSxDQUFDLGlCQUFpQixDQUFDLFFBQVEsQ0FBQyxDQUFBO1FBQ2hDLE1BQU0sWUFBWSxHQUFHLE1BQU0sUUFBUSxDQUFDLElBQUksRUFBRSxDQUFBO1FBQzFDLElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLFlBQVksQ0FBQyxFQUFFLENBQUM7WUFDdkMsTUFBTSxJQUFJLHdCQUF3QixDQUFDLHFCQUFxQixDQUFDLENBQUE7UUFDM0QsQ0FBQztRQUNELE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUUsWUFBWSxDQUFDLENBQUE7UUFDcEUsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNmLE1BQU0sSUFBSSx3QkFBd0IsQ0FBQyxxQkFBcUIsQ0FBQyxDQUFBO1FBQzNELENBQUM7UUFDRCxJQUFJLENBQUMsSUFBSSxHQUFHLENBQUMsQ0FBQTtRQUNiLE9BQU8sSUFBSSxDQUFBO0lBQ2IsQ0FBQztJQUVELGlCQUFpQixDQUFDLFFBQWtCO1FBQ2xDLElBQUksQ0FBQyxRQUFRLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDakIsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLENBQUMsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7Z0JBQ3pDLE1BQU0sSUFBSSx3QkFBd0IsQ0FBQyx5QkFBeUIsQ0FBQyxDQUFBO1lBQy9ELENBQUM7WUFDRCxNQUFNLElBQUksd0JBQXdCLENBQ2hDLDRCQUE0QixRQUFRLENBQUMsTUFBTSxJQUFJLFFBQVEsQ0FBQyxVQUFVLEdBQUcsQ0FDdEUsQ0FBQTtRQUNILENBQUM7SUFDSCxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgQmF0Y2hpbmdRdWV1ZSBmcm9tICcuLi8uLi9xdWV1ZXMvYmF0Y2hpbmdRdWV1ZS5qcydcclxuaW1wb3J0IFF1ZXVlIGZyb20gJy4uLy4uL3F1ZXVlcy9xdWV1ZS5qcydcclxuaW1wb3J0IHsgT2JqZWN0TG9hZGVyUnVudGltZUVycm9yIH0gZnJvbSAnLi4vLi4vdHlwZXMvZXJyb3JzLmpzJ1xyXG5pbXBvcnQgeyBDdXN0b21Mb2dnZXIsIEZldGNoZXIsIGluZGV4T2YsIGlzQmFzZSwgdGFrZSB9IGZyb20gJy4uLy4uL3R5cGVzL2Z1bmN0aW9ucy5qcydcclxuaW1wb3J0IHsgSXRlbSwgT2JqZWN0QXR0cmlidXRlTWFzayB9IGZyb20gJy4uLy4uL3R5cGVzL3R5cGVzLmpzJ1xyXG5pbXBvcnQgeyBEb3dubG9hZGVyIH0gZnJvbSAnLi4vaW50ZXJmYWNlcy5qcydcclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgU2VydmVyRG93bmxvYWRlck9wdGlvbnMge1xyXG4gIHNlcnZlclVybDogc3RyaW5nXHJcbiAgc3RyZWFtSWQ6IHN0cmluZ1xyXG4gIG9iamVjdElkOiBzdHJpbmdcclxuICB0b2tlbj86IHN0cmluZ1xyXG4gIGhlYWRlcnM/OiBIZWFkZXJzXHJcbiAgbG9nZ2VyOiBDdXN0b21Mb2dnZXJcclxuICBmZXRjaD86IEZldGNoZXJcclxuICBhdHRyaWJ1dGVNYXNrPzogT2JqZWN0QXR0cmlidXRlTWFza1xyXG4gIG9iamVjdFR5cGVNYXNrPzogc3RyaW5nW10gLy8gVGVtcG9yYXJ5IHVudGlsIHNlcnZlciBmaWx0ZXJzIGFyZSBlbGV2YXRlZCBhbmQgcmVhZHlcclxufVxyXG5cclxuY29uc3QgTUFYX1NBRkFSSV9ERUNPREVfQllURVMgPSAyICogMTAyNCAqIDEwMjQgKiAxMDI0IC0gMTAyNCAqIDEwMjQgLy8gMkdCIG1pbnVzIGEgbWFyZ2luXHJcblxyXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBTZXJ2ZXJEb3dubG9hZGVyIGltcGxlbWVudHMgRG93bmxvYWRlciB7XHJcbiAgI3JlcXVlc3RVcmxSb290T2JqOiBzdHJpbmdcclxuICAjcmVxdWVzdFVybENoaWxkcmVuOiBzdHJpbmdcclxuICAjaGVhZGVyczogSGVhZGVyc0luaXRcclxuICAjb3B0aW9uczogU2VydmVyRG93bmxvYWRlck9wdGlvbnNcclxuICAjZmV0Y2g6IEZldGNoZXJcclxuICAjcmVzdWx0cz86IFF1ZXVlPEl0ZW0+XHJcbiAgI3RvdGFsPzogbnVtYmVyXHJcbiAgI2xvZ2dlcjogQ3VzdG9tTG9nZ2VyXHJcblxyXG4gICNkb3dubG9hZFF1ZXVlPzogQmF0Y2hpbmdRdWV1ZTxzdHJpbmc+XHJcbiAgI2RlY29kZXIgPSBuZXcgVGV4dERlY29kZXIoJ3V0Zi04JywgeyBmYXRhbDogdHJ1ZSB9KVxyXG4gICNkZWNvZGVkQnl0ZXNDb3VudCA9IDBcclxuXHJcbiAgI3Jhd1N0cmluZ3M6IEFycmF5PHN0cmluZz4gPSBbXVxyXG4gICNyYXdFbmNvZGluZ3M6IEFycmF5PFVpbnQ4QXJyYXk+ID0gW11cclxuXHJcbiAgY29uc3RydWN0b3Iob3B0aW9uczogU2VydmVyRG93bmxvYWRlck9wdGlvbnMpIHtcclxuICAgIHRoaXMuI29wdGlvbnMgPSBvcHRpb25zXHJcbiAgICB0aGlzLiNsb2dnZXIgPSBvcHRpb25zLmxvZ2dlclxyXG4gICAgdGhpcy4jZmV0Y2ggPVxyXG4gICAgICBvcHRpb25zLmZldGNoID8/ICgoLi4uYXJncyk6IFByb21pc2U8UmVzcG9uc2U+ID0+IGdsb2JhbFRoaXMuZmV0Y2goLi4uYXJncykpXHJcblxyXG4gICAgdGhpcy4jaGVhZGVycyA9IHt9XHJcbiAgICBpZiAob3B0aW9ucy5oZWFkZXJzKSB7XHJcbiAgICAgIGZvciAoY29uc3QgaGVhZGVyIG9mIG9wdGlvbnMuaGVhZGVycy5lbnRyaWVzKCkpIHtcclxuICAgICAgICB0aGlzLiNoZWFkZXJzW2hlYWRlclswXV0gPSBoZWFkZXJbMV1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgdGhpcy4jaGVhZGVyc1snQWNjZXB0J10gPSBgdGV4dC9wbGFpbmBcclxuXHJcbiAgICBpZiAodGhpcy4jb3B0aW9ucy50b2tlbikge1xyXG4gICAgICB0aGlzLiNoZWFkZXJzWydBdXRob3JpemF0aW9uJ10gPSBgQmVhcmVyICR7dGhpcy4jb3B0aW9ucy50b2tlbn1gXHJcbiAgICB9XHJcbiAgICB0aGlzLiNyZXF1ZXN0VXJsQ2hpbGRyZW4gPSBgJHt0aGlzLiNvcHRpb25zLnNlcnZlclVybH0vYXBpL3YyL3Byb2plY3RzLyR7XHJcbiAgICAgIHRoaXMuI29wdGlvbnMuc3RyZWFtSWRcclxuICAgIH0vb2JqZWN0LXN0cmVhbS9gXHJcblxyXG4gICAgdGhpcy4jcmVxdWVzdFVybFJvb3RPYmogPSBgJHt0aGlzLiNvcHRpb25zLnNlcnZlclVybH0vb2JqZWN0cy8ke1xyXG4gICAgICB0aGlzLiNvcHRpb25zLnN0cmVhbUlkXHJcbiAgICB9LyR7dGhpcy4jb3B0aW9ucy5vYmplY3RJZH0vc2luZ2xlYFxyXG5cclxuICAgIGNvbnN0IGVuY29kZXIgPSBuZXcgVGV4dEVuY29kZXIoKVxyXG4gICAgaWYgKG9wdGlvbnMub2JqZWN0VHlwZU1hc2spIHtcclxuICAgICAgdGhpcy4jcmF3U3RyaW5ncy5wdXNoKC4uLm9wdGlvbnMub2JqZWN0VHlwZU1hc2spXHJcbiAgICAgIHRoaXMuI3Jhd0VuY29kaW5ncy5wdXNoKFxyXG4gICAgICAgIC4uLm9wdGlvbnMub2JqZWN0VHlwZU1hc2subWFwKCh2YWwpID0+IGVuY29kZXIuZW5jb2RlKHZhbCkpXHJcbiAgICAgIClcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGluaXRpYWxpemUocGFyYW1zOiB7XHJcbiAgICByZXN1bHRzOiBRdWV1ZTxJdGVtPlxyXG4gICAgdG90YWw6IG51bWJlclxyXG4gICAgbWF4RG93bmxvYWRCYXRjaFdhaXQ/OiBudW1iZXJcclxuICB9KTogdm9pZCB7XHJcbiAgICBjb25zdCB7IHJlc3VsdHMsIHRvdGFsLCBtYXhEb3dubG9hZEJhdGNoV2FpdCB9ID0gcGFyYW1zXHJcbiAgICB0aGlzLiNyZXN1bHRzID0gcmVzdWx0c1xyXG4gICAgdGhpcy4jdG90YWwgPSB0b3RhbFxyXG4gICAgdGhpcy4jZG93bmxvYWRRdWV1ZSA9IG5ldyBCYXRjaGluZ1F1ZXVlPHN0cmluZz4oe1xyXG4gICAgICBiYXRjaFNpemU6IDE1MDAwLCAvLyAxNWsgaXMgYSBnb29kIG51bWJlciBmb3IgbW9zdCBjYXNlc1xyXG4gICAgICBtYXhXYWl0VGltZTogbWF4RG93bmxvYWRCYXRjaFdhaXQgPz8gMTAwMCwgLy8gMSBzZWNvbmRcclxuICAgICAgcHJvY2Vzc0Z1bmN0aW9uOiAoYmF0Y2g6IHN0cmluZ1tdKTogUHJvbWlzZTx2b2lkPiA9PlxyXG4gICAgICAgIHRoaXMuZG93bmxvYWRCYXRjaCh7XHJcbiAgICAgICAgICBiYXRjaCxcclxuICAgICAgICAgIHVybDogdGhpcy4jcmVxdWVzdFVybENoaWxkcmVuLFxyXG4gICAgICAgICAgaGVhZGVyczogdGhpcy4jaGVhZGVyc1xyXG4gICAgICAgIH0pXHJcbiAgICB9KVxyXG4gIH1cclxuXHJcbiAgYWRkKGlkOiBzdHJpbmcpOiB2b2lkIHtcclxuICAgIHRoaXMuI2Rvd25sb2FkUXVldWU/LmFkZChpZCwgaWQpXHJcbiAgfVxyXG5cclxuICAvKlxyXG4gIFRoaXMgaXMgdGhlIG1vc3QgZnJlcXVlbnRseSByZXBvcnRlZCBhbmQgY29uZmlybWVkIHJlYXNvbiBmb3IgdGhpcyBlcnJvciBpbiBTYWZhcmkuIFRoZXJlJ3MgYSBrbm93biBidWcgaW4gV2ViS2l0IChTYWZhcmkncyByZW5kZXJpbmcgZW5naW5lKSB3aGVyZSBUZXh0RGVjb2RlciBjYW4gZmFpbCBvciB0aHJvdyBhIFJhbmdlRXJyb3IgYWZ0ZXIgZGVjb2RpbmcgYXJvdW5kIDJHQiBvZiBkYXRhLiBDaHJvbWUgYW5kIG90aGVyIGJyb3dzZXJzIGhhbmRsZSBtdWNoIGxhcmdlciBhbW91bnRzIG9mIGRhdGEgd2l0aG91dCB0aGlzIHNwZWNpZmljIGxpbWl0YXRpb24uXHJcblxyXG5XaHkgaXQgaGFwcGVuczogSXQgc2VlbXMgdG8gYmUgYW4gaW50ZXJuYWwgbWVtb3J5IG9yIGluZGV4aW5nIGxpbWl0YXRpb24gd2l0aGluIFNhZmFyaSdzIFRleHREZWNvZGVyIGltcGxlbWVudGF0aW9uLiBBZnRlciBhIGNlcnRhaW4gdGhyZXNob2xkIG9mIGRhdGEgaGFzIGJlZW4gcHJvY2Vzc2VkIGJ5IGEgVGV4dERlY29kZXIgaW5zdGFuY2UsIGl0IHN0YXJ0cyB0aHJvd2luZyB0aGlzIGVycm9yLlxyXG5cclxuQ2hyb21lJ3MgYmVoYXZpb3I6IENocm9tZSBnZW5lcmFsbHkgaGFuZGxlcyBsYXJnZXIgZGF0YSBzaXplcyB3aXRob3V0IHRoaXMgc3BlY2lmaWMgUmFuZ2VFcnJvci4gSXQgbWlnaHQgYmVjb21lIHNsb3cgb3IgcnVuIG91dCBvZiBnZW5lcmFsIG1lbW9yeSwgYnV0IG5vdCB0eXBpY2FsbHkgd2l0aCB0aGlzIHNwZWNpZmljIGVycm9yLlxyXG4gICovXHJcbiAgZGVjb2RlQ2h1bmsoY2h1bmtCdWZmZXI6IFVpbnQ4QXJyYXkpOiBzdHJpbmcge1xyXG4gICAgaWYgKHRoaXMuI2RlY29kZWRCeXRlc0NvdW50ICsgY2h1bmtCdWZmZXIuYnl0ZUxlbmd0aCA+IE1BWF9TQUZBUklfREVDT0RFX0JZVEVTKSB7XHJcbiAgICAgIC8vIFNhZmFyaSBpcyBhcHByb2FjaGluZyBpdHMgbGltaXQsIGNyZWF0ZSBhIG5ldyBkZWNvZGVyXHJcbiAgICAgIHRoaXMuI2RlY29kZXIgPSBuZXcgVGV4dERlY29kZXIoJ3V0Zi04JywgeyBmYXRhbDogdHJ1ZSB9KVxyXG4gICAgICB0aGlzLiNkZWNvZGVkQnl0ZXNDb3VudCA9IDAgLy8gUmVzZXQgY291bnRlciBmb3IgdGhlIG5ldyBkZWNvZGVyXHJcbiAgICB9XHJcbiAgICBjb25zdCBkZWNvZGVkVGV4dCA9IHRoaXMuI2RlY29kZXIuZGVjb2RlKGNodW5rQnVmZmVyKVxyXG4gICAgdGhpcy4jZGVjb2RlZEJ5dGVzQ291bnQgKz0gY2h1bmtCdWZmZXIuYnl0ZUxlbmd0aFxyXG4gICAgcmV0dXJuIGRlY29kZWRUZXh0XHJcbiAgfVxyXG5cclxuICBhc3luYyBkaXNwb3NlQXN5bmMoKTogUHJvbWlzZTx2b2lkPiB7XHJcbiAgICBhd2FpdCB0aGlzLiNkb3dubG9hZFF1ZXVlPy5kaXNwb3NlQXN5bmMoKVxyXG4gIH1cclxuXHJcbiAgYXN5bmMgZG93bmxvYWRCYXRjaChwYXJhbXM6IHtcclxuICAgIGJhdGNoOiBzdHJpbmdbXVxyXG4gICAgdXJsOiBzdHJpbmdcclxuICAgIGhlYWRlcnM6IEhlYWRlcnNJbml0XHJcbiAgfSk6IFByb21pc2U8dm9pZD4ge1xyXG4gICAgY29uc3QgeyBiYXRjaCwgdXJsLCBoZWFkZXJzIH0gPSBwYXJhbXNcclxuXHJcbiAgICBjb25zdCBzdGFydCA9IHBlcmZvcm1hbmNlLm5vdygpXHJcbiAgICB0aGlzLiNsb2dnZXIoYERvd25sb2FkaW5nIGJhdGNoIG9mICR7YmF0Y2gubGVuZ3RofSBpdGVtcy4uLmApXHJcbiAgICBjb25zdCBhdHRyaWJ1dGVNYXNrID0gdGhpcy4jb3B0aW9ucy5hdHRyaWJ1dGVNYXNrXHJcbiAgICBjb25zdCBrZXlzID0gbmV3IFNldDxzdHJpbmc+KGJhdGNoKVxyXG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCB0aGlzLiNmZXRjaCh1cmwsIHtcclxuICAgICAgbWV0aG9kOiAnUE9TVCcsXHJcbiAgICAgIGhlYWRlcnM6IHsgLi4uaGVhZGVycywgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyB9LFxyXG4gICAgICBib2R5OiBKU09OLnN0cmluZ2lmeSh7IG9iamVjdElkczogYmF0Y2gsIGF0dHJpYnV0ZU1hc2sgfSlcclxuICAgIH0pXHJcblxyXG4gICAgdGhpcy4jdmFsaWRhdGVSZXNwb25zZShyZXNwb25zZSlcclxuICAgIGlmICghcmVzcG9uc2UuYm9keSkge1xyXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1JlYWRhYmxlU3RyZWFtIG5vdCBzdXBwb3J0ZWQgb3IgcmVzcG9uc2UgaGFzIG5vIGJvZHkuJylcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCByZWFkZXIgPSByZXNwb25zZS5ib2R5LmdldFJlYWRlcigpXHJcbiAgICBsZXQgbGVmdG92ZXIgPSBuZXcgVWludDhBcnJheSgwKVxyXG5cclxuICAgIGxldCBjb3VudCA9IDBcclxuICAgIHdoaWxlICh0cnVlKSB7XHJcbiAgICAgIGNvbnN0IHsgZG9uZSwgdmFsdWUgfSA9IGF3YWl0IHJlYWRlci5yZWFkKClcclxuICAgICAgaWYgKGRvbmUpIGJyZWFrXHJcblxyXG4gICAgICBsZWZ0b3ZlciA9IGF3YWl0IHRoaXMuI3Byb2Nlc3NBcnJheShsZWZ0b3ZlciwgdmFsdWUsIGtleXMsIGFzeW5jICgpID0+IHtcclxuICAgICAgICBjb3VudCsrXHJcbiAgICAgICAgaWYgKGNvdW50ICUgMTAwMCA9PT0gMCkge1xyXG4gICAgICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgMTAwKSkgLy9hbGxvdyBvdGhlciBzdHVmZiB0byBoYXBwZW5cclxuICAgICAgICB9XHJcbiAgICAgIH0pXHJcbiAgICB9XHJcbiAgICBpZiAoa2V5cy5zaXplID4gMCkge1xyXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXHJcbiAgICAgICAgJ0l0ZW1zIHJlcXVlc3RlZCB3ZXJlIG5vdCBkb3dubG9hZGVkOiAnICsgdGFrZShrZXlzLnZhbHVlcygpLCAxMCkuam9pbignLCcpXHJcbiAgICAgIClcclxuICAgIH1cclxuICAgIGNvdW50ICs9IGtleXMuc2l6ZSAvLyBjb3VudCB0aGUgbGVmdG92ZXJzXHJcbiAgICBpZiAoY291bnQgPj0gdGhpcy4jdG90YWwhKSB7XHJcbiAgICAgIGF3YWl0IHRoaXMuI3Jlc3VsdHM/LmRpc3Bvc2VBc3luYygpIC8vIG1hcmsgdGhlIHF1ZXVlIGFzIGRvbmVcclxuICAgIH1cclxuICAgIHRoaXMuI2xvZ2dlcihcclxuICAgICAgYERvd25sb2FkZWQgYmF0Y2ggb2YgJHtiYXRjaC5sZW5ndGh9IGl0ZW1zIGluICR7cGVyZm9ybWFuY2Uubm93KCkgLSBzdGFydH1tc2BcclxuICAgIClcclxuICB9XHJcblxyXG4gIGFzeW5jICNwcm9jZXNzQXJyYXkoXHJcbiAgICBsZWZ0b3ZlcjogVWludDhBcnJheSxcclxuICAgIHZhbHVlOiBVaW50OEFycmF5LFxyXG4gICAga2V5czogU2V0PHN0cmluZz4sXHJcbiAgICBjYWxsYmFjazogKCkgPT4gUHJvbWlzZTx2b2lkPlxyXG4gICk6IFByb21pc2U8VWludDhBcnJheT4ge1xyXG4gICAgLy90aGlzIGNvbmNhdCB3aWxsIGFsbG9jYXRlIGEgbmV3IGFycmF5XHJcbiAgICBjb25zdCBjb21iaW5lZCA9IHRoaXMuI2NvbmNhdFVpbnQ4QXJyYXlzKGxlZnRvdmVyLCB2YWx1ZSlcclxuICAgIGxldCBzdGFydCA9IDBcclxuXHJcbiAgICAvL3N1YmFycmF5IGRvZXNuJ3QgYWxsb2NhdGVcclxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgY29tYmluZWQubGVuZ3RoOyBpKyspIHtcclxuICAgICAgaWYgKGNvbWJpbmVkW2ldID09PSAweDBhKSB7XHJcbiAgICAgICAgY29uc3QgbGluZSA9IGNvbWJpbmVkLnN1YmFycmF5KHN0YXJ0LCBpKSAvLyBsaW5lIHdpdGhvdXQgXFxuXHJcbiAgICAgICAgLy9zdHJpbmdzIGFyZSBhbGxvY2F0ZWQgaGVyZVxyXG4gICAgICAgIGNvbnN0IGl0ZW0gPSB0aGlzLiNwcm9jZXNzTGluZShsaW5lKVxyXG4gICAgICAgIHN0YXJ0ID0gaSArIDFcclxuICAgICAgICBhd2FpdCBjYWxsYmFjaygpXHJcbiAgICAgICAga2V5cy5kZWxldGUoaXRlbS5iYXNlSWQpXHJcbiAgICAgICAgdGhpcy4jcmVzdWx0cz8uYWRkKGl0ZW0pXHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIHJldHVybiBjb21iaW5lZC5zdWJhcnJheShzdGFydCkgLy8gY2Fycnkgb3ZlciByZW1haW5kZXJcclxuICB9XHJcblxyXG4gICNwcm9jZXNzTGluZShsaW5lOiBVaW50OEFycmF5KTogSXRlbSB7XHJcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGxpbmUubGVuZ3RoOyBpKyspIHtcclxuICAgICAgaWYgKGxpbmVbaV0gPT09IDB4MDkpIHtcclxuICAgICAgICAvL3RoaXMgaXMgYSB0YWJcclxuICAgICAgICBjb25zdCBiYXNlSWQgPSB0aGlzLmRlY29kZUNodW5rKGxpbmUuc3ViYXJyYXkoMCwgaSkpXHJcbiAgICAgICAgY29uc3QganNvbkJ5dGVzID0gbGluZS5zdWJhcnJheShpICsgMSlcclxuXHJcbiAgICAgICAgaWYgKCF0aGlzLiNpc1ZhbGlkQnl0ZXMoanNvbkJ5dGVzKSkge1xyXG4gICAgICAgICAgcmV0dXJuIHsgYmFzZUlkLCBiYXNlOiB1bmRlZmluZWQgfVxyXG4gICAgICAgIH1cclxuICAgICAgICBjb25zdCBiYXNlID0gdGhpcy5kZWNvZGVDaHVuayhqc29uQnl0ZXMpXHJcbiAgICAgICAgY29uc3QgaXRlbSA9IHRoaXMuI3Byb2Nlc3NKc29uKGJhc2VJZCwgYmFzZSlcclxuICAgICAgICBpdGVtLnNpemUgPSBqc29uQnl0ZXMubGVuZ3RoXHJcbiAgICAgICAgcmV0dXJuIGl0ZW1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgdGhyb3cgbmV3IE9iamVjdExvYWRlclJ1bnRpbWVFcnJvcihcclxuICAgICAgJ0ludmFsaWQgbGluZSBmb3JtYXQgaW4gcmVzcG9uc2U6ICcgKyB0aGlzLmRlY29kZUNodW5rKGxpbmUpXHJcbiAgICApXHJcbiAgfVxyXG5cclxuICAjcHJvY2Vzc0pzb24oYmFzZUlkOiBzdHJpbmcsIHVucGFyc2VkQmFzZTogc3RyaW5nKTogSXRlbSB7XHJcbiAgICBsZXQgYmFzZTogdW5rbm93blxyXG4gICAgdHJ5IHtcclxuICAgICAgYmFzZSA9IEpTT04ucGFyc2UodW5wYXJzZWRCYXNlKVxyXG4gICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xyXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEVycm9yIHBhcnNpbmcgb2JqZWN0ICR7YmFzZUlkfTogJHsoZSBhcyBFcnJvcikubWVzc2FnZX1gKVxyXG4gICAgfVxyXG4gICAgaWYgKGlzQmFzZShiYXNlKSkge1xyXG4gICAgICByZXR1cm4geyBiYXNlSWQsIGJhc2UgfVxyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhyb3cgbmV3IE9iamVjdExvYWRlclJ1bnRpbWVFcnJvcihgJHtiYXNlSWR9IGlzIG5vdCBhIGJhc2VgKVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgI2lzVmFsaWRTdHJpbmcoanNvbjogc3RyaW5nKTogYm9vbGVhbiB7XHJcbiAgICBmb3IgKGNvbnN0IHJhd1N0cmluZyBvZiB0aGlzLiNyYXdTdHJpbmdzKVxyXG4gICAgICBpZiAoanNvbi5pbmNsdWRlcyhyYXdTdHJpbmcpKSB7XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlXHJcbiAgICAgIH1cclxuICAgIHJldHVybiB0cnVlXHJcbiAgfVxyXG5cclxuICAjaXNWYWxpZEJ5dGVzKGpzb246IFVpbnQ4QXJyYXkpOiBib29sZWFuIHtcclxuICAgIGZvciAoY29uc3QgcmF3RW5jb2Rpbmcgb2YgdGhpcy4jcmF3RW5jb2RpbmdzKVxyXG4gICAgICBpZiAoaW5kZXhPZihqc29uLCByYXdFbmNvZGluZykgIT09IC0xKSB7XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlXHJcbiAgICAgIH1cclxuICAgIHJldHVybiB0cnVlXHJcbiAgfVxyXG5cclxuICAjY29uY2F0VWludDhBcnJheXMoYTogVWludDhBcnJheSwgYjogVWludDhBcnJheSk6IFVpbnQ4QXJyYXkge1xyXG4gICAgY29uc3QgYyA9IG5ldyBVaW50OEFycmF5KGEubGVuZ3RoICsgYi5sZW5ndGgpXHJcbiAgICBjLnNldChhLCAwKVxyXG4gICAgYy5zZXQoYiwgYS5sZW5ndGgpXHJcbiAgICByZXR1cm4gY1xyXG4gIH1cclxuXHJcbiAgYXN5bmMgZG93bmxvYWRTaW5nbGUoKTogUHJvbWlzZTxJdGVtPiB7XHJcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuI2ZldGNoKHRoaXMuI3JlcXVlc3RVcmxSb290T2JqLCB7XHJcbiAgICAgIGhlYWRlcnM6IHRoaXMuI2hlYWRlcnNcclxuICAgIH0pXHJcbiAgICB0aGlzLiN2YWxpZGF0ZVJlc3BvbnNlKHJlc3BvbnNlKVxyXG4gICAgY29uc3QgcmVzcG9uc2VUZXh0ID0gYXdhaXQgcmVzcG9uc2UudGV4dCgpXHJcbiAgICBpZiAoIXRoaXMuI2lzVmFsaWRTdHJpbmcocmVzcG9uc2VUZXh0KSkge1xyXG4gICAgICB0aHJvdyBuZXcgT2JqZWN0TG9hZGVyUnVudGltZUVycm9yKCdJbnZhbGlkIGJhc2Ugb2JqZWN0JylcclxuICAgIH1cclxuICAgIGNvbnN0IGl0ZW0gPSB0aGlzLiNwcm9jZXNzSnNvbih0aGlzLiNvcHRpb25zLm9iamVjdElkLCByZXNwb25zZVRleHQpXHJcbiAgICBpZiAoIWl0ZW0uYmFzZSkge1xyXG4gICAgICB0aHJvdyBuZXcgT2JqZWN0TG9hZGVyUnVudGltZUVycm9yKCdJbnZhbGlkIGJhc2Ugb2JqZWN0JylcclxuICAgIH1cclxuICAgIGl0ZW0uc2l6ZSA9IDBcclxuICAgIHJldHVybiBpdGVtXHJcbiAgfVxyXG5cclxuICAjdmFsaWRhdGVSZXNwb25zZShyZXNwb25zZTogUmVzcG9uc2UpOiB2b2lkIHtcclxuICAgIGlmICghcmVzcG9uc2Uub2spIHtcclxuICAgICAgaWYgKFs0MDEsIDQwM10uaW5jbHVkZXMocmVzcG9uc2Uuc3RhdHVzKSkge1xyXG4gICAgICAgIHRocm93IG5ldyBPYmplY3RMb2FkZXJSdW50aW1lRXJyb3IoJ1lvdSBkbyBub3QgaGF2ZSBhY2Nlc3MhJylcclxuICAgICAgfVxyXG4gICAgICB0aHJvdyBuZXcgT2JqZWN0TG9hZGVyUnVudGltZUVycm9yKFxyXG4gICAgICAgIGBGYWlsZWQgdG8gZmV0Y2ggb2JqZWN0czogJHtyZXNwb25zZS5zdGF0dXN9ICR7cmVzcG9uc2Uuc3RhdHVzVGV4dH0pYFxyXG4gICAgICApXHJcbiAgICB9XHJcbiAgfVxyXG59XHJcbiJdfQ== |