UNPKG

trimble-connect-sdk

Version:

Trimble Connect SDK for JavaScript

315 lines 55.2 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import { ServiceError } from './error'; import { ServiceResponse } from './response'; export function extractEndpoint(url) { const schemaIndex = url.indexOf('//'); const firstSeparatorIndex = url.indexOf('/', schemaIndex + 2); return url.substring(0, firstSeparatorIndex); } function delay(ms) { return new Promise((resolve) => { setTimeout(resolve, ms); }); } export class Service { constructor(config) { this.config = config; this.defaultRetryCount = 3; if (!this.config.serviceUri) { throw new Error('The serviceUri is required'); } } makeRequest(url, method = 'GET', body, customHeaders, auth = true) { return __awaiter(this, void 0, void 0, function* () { const headers = new Headers({ Accept: 'application/json' }); if (customHeaders) { customHeaders.forEach((value, key) => { headers.append(key, value); }); } const response = (yield this.request(url, method, body, headers, auth)); if (response.response.status !== 204) { const contentType = response.response.headers.get('content-type'); if (contentType === null || contentType.indexOf('application/json') !== -1) { response.data = (yield response.response.json()); } else { throw new ServiceError(response.response, 'Cannot deserialize response body as it is not in a JSON format.'); } } return response; }); } getItemsWithPages(url, onPageRetrieved, pageSize, body, customHeaders, auth = true) { return __awaiter(this, void 0, void 0, function* () { if (pageSize <= 0 || !Number.isInteger(pageSize)) { throw new RangeError('pageSize must be a positive integer'); } const headers = customHeaders ? new Headers(customHeaders) : new Headers(); const range = { start: 0, end: pageSize - 1 }; headers.set('Range', `items=${range.start}-${range.end}`); let response = yield this.makeRequest(url, 'GET', body, headers, auth); do { const responseRange = this.getRange(response); const hasNextPage = this.hasMorePages(response, responseRange); let nextPage; if (hasNextPage && responseRange && responseRange.total) { range.start = responseRange.end + 1; range.end = Math.min(responseRange.total - 1, range.start + pageSize - 1); headers.set('Range', `items=${range.start}-${range.end}`); nextPage = this.makeRequest(url, 'GET', body, headers, auth); } onPageRetrieved(response); if (nextPage) { response = yield nextPage; } else { break; } } while (true); }); } getItemsWithPagesAdaptive(url, onPageRetrieved, initialPageSize = 10, standardPageSize = 100, threshold = 50, body, customHeaders, auth = true) { return __awaiter(this, void 0, void 0, function* () { if (initialPageSize <= 0 || !Number.isInteger(initialPageSize)) { throw new RangeError('initialPageSize must be a positive integer'); } if (standardPageSize <= 0 || !Number.isInteger(standardPageSize)) { throw new RangeError('standardPageSize must be a positive integer'); } if (threshold < 0 || !Number.isInteger(threshold)) { throw new RangeError('threshold must be a non-negative integer'); } const headers = customHeaders ? new Headers(customHeaders) : new Headers(); let totalLoaded = 0; let currentIndex = 0; const firstPageSize = threshold === 0 ? standardPageSize : initialPageSize; headers.set('Range', `items=${currentIndex}-${currentIndex + firstPageSize - 1}`); let response = yield this.makeRequest(url, 'GET', body, headers, auth); do { const itemsInPage = Array.isArray(response.data) ? response.data.length : 0; const responseRange = this.getRange(response); const hasMorePages = this.hasMorePages(response, responseRange); totalLoaded += itemsInPage; if (responseRange && typeof responseRange.end === 'number') { currentIndex = responseRange.end + 1; } else { currentIndex += itemsInPage; } let nextPage; if (hasMorePages && responseRange && responseRange.total) { const nextPageSize = totalLoaded < threshold ? initialPageSize : standardPageSize; const endIndex = Math.min(responseRange.total - 1, currentIndex + nextPageSize - 1); headers.set('Range', `items=${currentIndex}-${endIndex}`); nextPage = this.makeRequest(url, 'GET', body, headers, auth); } onPageRetrieved(response); if (nextPage) { response = yield nextPage; } else { break; } } while (true); }); } request(url, method = 'GET', body, customHeaders, auth = true) { return __awaiter(this, void 0, void 0, function* () { const requestUrl = url.startsWith('http') ? url : url.startsWith('/') ? extractEndpoint(this.config.serviceUri) + url : this.config.serviceUri + url; const headers = new Headers(); const contentType = customHeaders ? customHeaders.get('Content-Type') : undefined; if (!contentType && body !== undefined) { headers.set('Content-Type', 'application/json'); } if (customHeaders) { customHeaders.forEach((value, key) => { headers.append(key, value); }); } return this.fetchWithRetry(requestUrl, { body, headers, method, redirect: 'follow', }, auth); }); } maxRetries() { if (this.config.maxRetries !== undefined) { return this.config.maxRetries; } else { return this.defaultRetryCount; } } calculateRetryDelay(retryCount) { if (retryCount === 0) { return 0; } else { const base = 100; return Math.random() * (Math.pow(2, retryCount - 1) * base); } } retryableError(error) { if (this.timeoutError(error) || this.networkingError(error) || this.expiredCredentialsError(error) || this.throttledError(error) || error.response.status >= 500) { return true; } return false; } networkingError(error) { return error.errorCode === 'NetworkingError'; } timeoutError(error) { return error.errorCode === 'TimeoutError'; } expiredCredentialsError(error) { if (error.response.status === 401) { const credentials = this.config.credentials; if (credentials && typeof credentials.expired === 'boolean') { credentials.expired = true; } return true; } return false; } throttledError(error) { if (error.response.status === 429) { return true; } else { return false; } } fetchWithRetry(url, params, auth = true) { return __awaiter(this, void 0, void 0, function* () { const logger = this.config.logger; const result = new ServiceResponse(this, new Response(), void 0); do { const credentials = this.config.credentials; if (auth && credentials) { if (typeof credentials.get === 'function') { try { yield credentials.get(); } catch (err) { if (logger !== undefined) { this.log(`[TID] Failed to acquire tokens: ${err.message}`); } throw err; } } if (credentials.token) { params.headers.set('Authorization', 'Bearer ' + credentials.token); } } const startTime = Date.now(); const response = yield this.fetch(url, params); if (logger !== undefined) { const delta = (Date.now() - startTime) / 1000; const isoDate = new Date(startTime).toISOString(); const requestContentLength = params.body ? params.body.length : 0; const responseContentLength = response.headers.get('content-length'); const line = `${isoDate} [TC HTTP] ${params.method} ${url} ${response.status} ${delta} ${result.retryCount} ${requestContentLength} ${responseContentLength}`; this.log(line); } result.response = response; if (response.ok) { return result; } else { let err; const contentType = response.headers.get('content-type'); if (contentType && contentType.indexOf('application/json') !== -1) { const errorInfo = yield response.json(); err = new ServiceError(response, errorInfo.message, errorInfo.code || errorInfo.errorcode); } else { const message = yield response.text(); err = new ServiceError(response, message); } if (result.retryCount + 1 < this.maxRetries() && this.retryableError(err)) { const retryAfterHeader = response.headers.get('retry-after'); const retryAfterMS = retryAfterHeader ? parseInt(retryAfterHeader, 10) * 1000 : 0; const ms = this.calculateRetryDelay(result.retryCount) + retryAfterMS; yield delay(ms); result.retryCount++; } else { throw err; } } } while (true); }); } fetch(url, params) { return fetch(url, params); } getRange(response) { if (!response.response.headers.has('Content-Range')) { return undefined; } try { const contentRange = response.response.headers .get('Content-Range') .split(' '); const rangeTokens = contentRange[1].split('/'); const tokens = rangeTokens[0].split('-'); const start = Number(tokens[0]); const end = Number(tokens[1]); const total = Number(rangeTokens[1]); return { start, end, total }; } catch (_a) { return undefined; } } hasMorePages(response, responseRange) { const range = responseRange !== null && responseRange !== void 0 ? responseRange : this.getRange(response); return (Array.isArray(response.data) && response.data.length !== 0 && range !== undefined && range.total !== undefined && range.end < range.total - 1); } log(line) { return __awaiter(this, void 0, void 0, function* () { const logger = this.config.logger; if (logger !== undefined) { if (typeof logger.log === 'function') { logger.log(line); } else if (typeof logger.write === 'function') { logger.write(line + '\n'); } } }); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIuLyIsInNvdXJjZXMiOlsic2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7QUFHQSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQ3ZDLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFJN0MsTUFBTSxVQUFVLGVBQWUsQ0FBQyxHQUFXO0lBQ3pDLE1BQU0sV0FBVyxHQUFHLEdBQUcsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDdEMsTUFBTSxtQkFBbUIsR0FBRyxHQUFHLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxXQUFXLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFFOUQsT0FBTyxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxtQkFBbUIsQ0FBQyxDQUFDO0FBQy9DLENBQUM7QUFFRCxTQUFTLEtBQUssQ0FBQyxFQUFVO0lBQ3ZCLE9BQU8sSUFBSSxPQUFPLENBQU8sQ0FBQyxPQUFPLEVBQUUsRUFBRTtRQUNuQyxVQUFVLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQzFCLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQU1ELE1BQU0sT0FBTyxPQUFPO0lBUWxCLFlBQTRCLE1BQXFCO1FBQXJCLFdBQU0sR0FBTixNQUFNLENBQWU7UUFOekMsc0JBQWlCLEdBQVcsQ0FBQyxDQUFDO1FBT3BDLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLFVBQVUsRUFBRTtZQUMzQixNQUFNLElBQUksS0FBSyxDQUFDLDRCQUE0QixDQUFDLENBQUM7U0FDL0M7SUFDSCxDQUFDO0lBWVksV0FBVyxDQUN0QixHQUFXLEVBQ1gsU0FBc0QsS0FBSyxFQUMzRCxJQUF3QixFQUN4QixhQUF1QixFQUN2QixPQUFnQixJQUFJOztZQUVwQixNQUFNLE9BQU8sR0FBRyxJQUFJLE9BQU8sQ0FBQyxFQUFFLE1BQU0sRUFBRSxrQkFBa0Is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b3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb25maWd1cmF0aW9uIH0gZnJvbSAnLi9jb25maWcnO1xuaW1wb3J0IHsgQ3JlZGVudGlhbHMgfSBmcm9tICcuL2NyZWRlbnRpYWxzJztcbmltcG9ydCB7IFJhbmdlIH0gZnJvbSAnLi9jb21tb24nO1xuaW1wb3J0IHsgU2VydmljZUVycm9yIH0gZnJvbSAnLi9lcnJvcic7XG5pbXBvcnQgeyBTZXJ2aWNlUmVzcG9uc2UgfSBmcm9tICcuL3Jlc3BvbnNlJztcbmltcG9ydCB7IFNlcnZpY2VDcmVkZW50aWFscyB9IGZyb20gJy4vc2VydmljZV9jcmVkZW50aWFscyc7XG5cbi8qKiBAaW50ZXJuYWwgKi9cbmV4cG9ydCBmdW5jdGlvbiBleHRyYWN0RW5kcG9pbnQodXJsOiBzdHJpbmcpOiBzdHJpbmcge1xuICBjb25zdCBzY2hlbWFJbmRleCA9IHVybC5pbmRleE9mKCcvLycpO1xuICBjb25zdCBmaXJzdFNlcGFyYXRvckluZGV4ID0gdXJsLmluZGV4T2YoJy8nLCBzY2hlbWFJbmRleCArIDIpO1xuXG4gIHJldHVybiB1cmwuc3Vic3RyaW5nKDAsIGZpcnN0U2VwYXJhdG9ySW5kZXgpO1xufVxuXG5mdW5jdGlvbiBkZWxheShtczogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gIHJldHVybiBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSkgPT4ge1xuICAgIHNldFRpbWVvdXQocmVzb2x2ZSwgbXMpO1xuICB9KTtcbn1cblxuLyoqXG4gKiBUaGUgc2VydmljZSBjbGllbnQgdGhhdCByZXByZXNlbnRzIGNvbm5lY3Rpb24gdG8gdGhlIE9yZ2FuaXplciBTZXJ2aWNlLlxuICogRWFjaCBBUEkgb3BlcmF0aW9uIGlzIGV4cG9zZWQgYXMgYSBmdW5jdGlvbiBvbiBzZXJ2aWNlLlxuICovXG5leHBvcnQgY2xhc3MgU2VydmljZSB7XG4gIC8qKiBVc2VkIGlmIG1heFJldHJpZXMgaXMgbm90IHNwZWNpZmllZCBpbiB7QHNlZSBDb25maWd1cmF0aW9uI21heFJldHJpZXMgfS4gVGhlIGRlZmF1bHRSZXRyeUNvdW50IGNhbiBiZSBvdmVycmlkZGVuIGJ5IHNlcnZpY2UgY2xhc3Nlcy4gKi9cbiAgcHJpdmF0ZSBkZWZhdWx0UmV0cnlDb3VudDogbnVtYmVyID0gMztcblxuICAvKipcbiAgICogQGNvbnN0cnVjdG9yIENvbnN0cnVjdHMgYSBzZXJ2aWNlIG9iamVjdC5cbiAgICogQHBhcmFtIHtDb25maWd9IGNvbmZpZyBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIChlLmcuIHNlcnZpY2UgdXJsKS5cbiAgICovXG4gIGNvbnN0cnVjdG9yKHB1YmxpYyByZWFkb25seSBjb25maWc6IENvbmZpZ3VyYXRpb24pIHtcbiAgICBpZiAoIXRoaXMuY29uZmlnLnNlcnZpY2VVcmkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignVGhlIHNlcnZpY2VVcmkgaXMgcmVxdWlyZWQnKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogRmV0Y2hlcyB0aGUgbmV4dCBwYWdlIGZyb20gdGhlIHNlcXVlbmNlIG9mIHBhZ2VzIGluaXRpYXRlZCBieSB7QHNlZSBPcmdhbml6ZXIubGlzdFRyZWVzIH0uXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgVGhlIHVybCB0byBtYWtlIHJlcXVlc3QgdG8uIENvdWxkIGJlIGFic29sdXRlIG9yIHJlbGF0aXZlIHRvIHRoZSBzZXJ2aWNlIGJhc2UgdXJpLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbWV0aG9kIFRoZSBIVFRQIG1ldGhvZC5cbiAgICogQHBhcmFtIHtzdHJpbmcgfCBGb3JtRGF0YX0gYm9keSBPcHRpb25hbCBib2R5IHRvIHNlbmQgaW4gdGhlIHJlcXVlc3QuXG4gICAqIEBwYXJhbSB7SGVhZGVyc30gY3VzdG9tSGVhZGVycyBPcHRpb25hbCBoZWFkZXJzIHRvIGF0dGFjaCB0byByZXF1ZXN0LlxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IGF1dGggVGhlIHZhbHVlIGluZGljYXRpbmcgd2hldGhlciB0aGUgcmVxdWVzdCByZXF1aXJlcyBhdXRoZW50aWNhdGlvbi4gSWYgdHJ1ZSwgdGhlIGNyZWRlbnRpYWxzIHdpbGwgYmUgcmVxdWVzdGVkIGZyb20gdGhlIGNvbmZpZ3VyYXRpb24ge0BzZWUgQ29uZmlnI2NyZWRlbnRpYWxzIH0gYW5kIEF1dGhvcml6YXRpb24gaGVhZGVyIHdpbGwgYmUgYXR0YWNoZWQuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPFNlcnZpY2VSZXNwb25zZTxEPj59IFRoZSBzZXJ2aWNlIHJlc3BvbnNlLlxuICAgKiBAdGhyb3dzIHtTZXJ2aWNlRXJyb3J9IGluIGNhc2Ugb2YgdGhlIGVycm9yIHJlc3BvbnNlIGZyb20gdGhlIHNlcnZpY2UuXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgbWFrZVJlcXVlc3Q8RD4oXG4gICAgdXJsOiBzdHJpbmcsXG4gICAgbWV0aG9kOiAnR0VUJyB8ICdQVVQnIHwgJ1BPU1QnIHwgJ1BBVENIJyB8ICdERUxFVEUnID0gJ0dFVCcsXG4gICAgYm9keT86IHN0cmluZyB8IEZvcm1EYXRhLFxuICAgIGN1c3RvbUhlYWRlcnM/OiBIZWFkZXJzLFxuICAgIGF1dGg6IGJvb2xlYW4gPSB0cnVlLFxuICApOiBQcm9taXNlPFNlcnZpY2VSZXNwb25zZTxEPj4ge1xuICAgIGNvbnN0IGhlYWRlcnMgPSBuZXcgSGVhZGVycyh7IEFjY2VwdDogJ2FwcGxpY2F0aW9uL2pzb24nIH0pO1xuICAgIGlmIChjdXN0b21IZWFkZXJzKSB7XG4gICAgICBjdXN0b21IZWFkZXJzLmZvckVhY2goKHZhbHVlOiBzdHJpbmcsIGtleTogc3RyaW5nKSA9PiB7XG4gICAgICAgIGhlYWRlcnMuYXBwZW5kKGtleSwgdmFsdWUpO1xuICAgICAgfSk7XG4gICAgfVxuICAgIGNvbnN0IHJlc3BvbnNlID0gKGF3YWl0IHRoaXMucmVxdWVzdChcbiAgICAgIHVybCxcbiAgICAgIG1ldGhvZCxcbiAgICAgIGJvZHksXG4gICAgICBoZWFkZXJzLFxuICAgICAgYXV0aCxcbiAgICApKSBhcyBhbnkgYXMgU2VydmljZVJlc3BvbnNlPEQ+O1xuXG4gICAgLy8gZGVzZXJpYWxpemUgcmVzcG9uc2UgYm9keS4gSWYgc2VydmljZSByZXNwb25kZWQgd2l0aCBhbiBlcnJvciBpdCB3YXMgdGhyb3duIGFscmVhZHkuXG4gICAgaWYgKHJlc3BvbnNlLnJlc3BvbnNlLnN0YXR1cyAhPT0gMjA0KSB7XG4gICAgICBjb25zdCBjb250ZW50VHlwZSA9IHJlc3BvbnNlLnJlc3BvbnNlLmhlYWRlcnMuZ2V0KCdjb250ZW50LXR5cGUnKTtcbiAgICAgIGlmIChcbiAgICAgICAgY29udGVudFR5cGUgPT09IG51bGwgfHxcbiAgICAgICAgY29udGVudFR5cGUuaW5kZXhPZignYXBwbGljYXRpb24vanNvbicpICE9PSAtMVxuICAgICAgKSB7XG4gICAgICAgIHJlc3BvbnNlLmRhdGEgPSAoYXdhaXQgcmVzcG9uc2UucmVzcG9uc2UuanNvbigpKSBhcyBEO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgbmV3IFNlcnZpY2VFcnJvcihcbiAgICAgICAgICByZXNwb25zZS5yZXNwb25zZSxcbiAgICAgICAgICAnQ2Fubm90IGRlc2VyaWFsaXplIHJlc3BvbnNlIGJvZHkgYXMgaXQgaXMgbm90IGluIGEgSlNPTiBmb3JtYXQuJyxcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gcmVzcG9uc2U7XG4gIH1cblxuICAvKipcbiAgICogRmV0Y2hlcyBhbGwgdGhlIGl0ZW1zIHBhZ2UgYnkgcGFnZSwgcmV0dXJuaW5nIGVhY2ggcGFnZSByZXN1bHRzIGluIGEgY2FsbGJhY2suXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgVGhlIHVybCB0byBtYWtlIHJlcXVlc3QgdG8uIENvdWxkIGJlIGFic29sdXRlIG9yIHJlbGF0aXZlIHRvIHRoZSBzZXJ2aWNlIGJhc2UgdXJpLlxuICAgKiBAcGFyYW0geyhyZXNwb25zZTogU2VydmljZVJlc3BvbnNlPEQ+KSA9PiB2b2lkfSBvblBhZ2VSZXRyaWV2ZWQgVGhlIGNhbGxiYWNrIHVzZWQgdG8gcmV0dXJuIHJlc3VsdHMsIHBhZ2UgYnkgcGFnZS5cbiAgICogQHBhcmFtIHtudW1iZXJ9IHBhZ2VTaXplIFRoZSBwYWdlIHNpemUgdXNlZCB0byByZXF1ZXN0IGl0ZW1zLlxuICAgKiBAcGFyYW0ge3N0cmluZyB8IEZvcm1EYXRhfSBib2R5IE9wdGlvbmFsIGJvZHkgdG8gc2VuZCBpbiB0aGUgcmVxdWVzdC5cbiAgICogQHBhcmFtIHtIZWFkZXJzfSBjdXN0b21IZWFkZXJzIE9wdGlvbmFsIGhlYWRlcnMgdG8gYXR0YWNoIHRvIHJlcXVlc3QuXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gYXV0aCBUaGUgdmFsdWUgaW5kaWNhdGluZyB3aGV0aGVyIHRoZSByZXF1ZXN0IHJlcXVpcmVzIGF1dGhlbnRpY2F0aW9uLiBJZiB0cnVlLCB0aGUgY3JlZGVudGlhbHMgd2lsbCBiZSByZXF1ZXN0ZWQgZnJvbSB0aGUgY29uZmlndXJhdGlvbiB7QHNlZSBDb25maWcjY3JlZGVudGlhbHMgfSBhbmQgQXV0aG9yaXphdGlvbiBoZWFkZXIgd2lsbCBiZSBhdHRhY2hlZC5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IFByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIGFsbCBwYWdlcyBoYXZlIGJlZW4gcmV0cmlldmVkLlxuICAgKiBAdGhyb3dzIHtTZXJ2aWNlRXJyb3J9IGluIGNhc2Ugb2YgdGhlIGVycm9yIHJlc3BvbnNlIGZyb20gdGhlIHNlcnZpY2UuXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgZ2V0SXRlbXNXaXRoUGFnZXM8RD4oXG4gICAgdXJsOiBzdHJpbmcsXG4gICAgb25QYWdlUmV0cmlldmVkOiAocmVzcG9uc2U6IFNlcnZpY2VSZXNwb25zZTxEPikgPT4gdm9pZCxcbiAgICBwYWdlU2l6ZTogbnVtYmVyLFxuICAgIGJvZHk/OiBzdHJpbmcgfCBGb3JtRGF0YSxcbiAgICBjdXN0b21IZWFkZXJzPzogSGVhZGVycyxcbiAgICBhdXRoOiBib29sZWFuID0gdHJ1ZSxcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgLy8gVmFsaWRhdGUgcGFyYW1ldGVyXG4gICAgaWYgKHBhZ2VTaXplIDw9IDAgfHwgIU51bWJlci5pc0ludGVnZXIocGFnZVNpemUpKSB7XG4gICAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcigncGFnZVNpemUgbXVzdCBiZSBhIHBvc2l0aXZlIGludGVnZXInKTtcbiAgICB9XG5cbiAgICBjb25zdCBoZWFkZXJzID0gY3VzdG9tSGVhZGVycyA/IG5ldyBIZWFkZXJzKGN1c3RvbUhlYWRlcnMpIDogbmV3IEhlYWRlcnMoKTtcbiAgICBjb25zdCByYW5nZTogUmFuZ2UgPSB7IHN0YXJ0OiAwLCBlbmQ6IHBhZ2VTaXplIC0gMSB9O1xuICAgIGhlYWRlcnMuc2V0KCdSYW5nZScsIGBpdGVtcz0ke3JhbmdlLnN0YXJ0fS0ke3JhbmdlLmVuZH1gKTtcblxuICAgIGxldCByZXNwb25zZSA9IGF3YWl0IHRoaXMubWFrZVJlcXVlc3Q8RD4odXJsLCAnR0VUJywgYm9keSwgaGVhZGVycywgYXV0aCk7XG5cbiAgICBkbyB7XG4gICAgICBjb25zdCByZXNwb25zZVJhbmdlID0gdGhpcy5nZXRSYW5nZShyZXNwb25zZSk7XG4gICAgICBjb25zdCBoYXNOZXh0UGFnZSA9IHRoaXMuaGFzTW9yZVBhZ2VzKHJlc3BvbnNlLCByZXNwb25zZVJhbmdlKTtcblxuICAgICAgbGV0IG5leHRQYWdlOiBQcm9taXNlPFNlcnZpY2VSZXNwb25zZTxEPj4gfCB1bmRlZmluZWQ7XG4gICAgICBpZiAoaGFzTmV4dFBhZ2UgJiYgcmVzcG9uc2VSYW5nZSAmJiByZXNwb25zZVJhbmdlLnRvdGFsKSB7XG4gICAgICAgIHJhbmdlLnN0YXJ0ID0gcmVzcG9uc2VSYW5nZS5lbmQgKyAxO1xuICAgICAgICByYW5nZS5lbmQgPSBNYXRoLm1pbihcbiAgICAgICAgICByZXNwb25zZVJhbmdlLnRvdGFsIC0gMSxcbiAgICAgICAgICByYW5nZS5zdGFydCArIHBhZ2VTaXplIC0gMSxcbiAgICAgICAgKTtcbiAgICAgICAgaGVhZGVycy5zZXQoJ1JhbmdlJywgYGl0ZW1zPSR7cmFuZ2Uuc3RhcnR9LSR7cmFuZ2UuZW5kfWApO1xuXG4gICAgICAgIC8vIGluaXRpYXRlIG5leHQgcGFnZSByZXF1ZXN0LCBidXQgZG9uJ3Qgd2FpdCBvbiBpdCB5ZXRcbiAgICAgICAgbmV4dFBhZ2UgPSB0aGlzLm1ha2VSZXF1ZXN0PEQ+KHVybCwgJ0dFVCcsIGJvZHksIGhlYWRlcnMsIGF1dGgpO1xuICAgICAgfVxuXG4gICAgICBvblBhZ2VSZXRyaWV2ZWQocmVzcG9uc2UpO1xuXG4gICAgICBpZiAobmV4dFBhZ2UpIHtcbiAgICAgICAgcmVzcG9uc2UgPSBhd2FpdCBuZXh0UGFnZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuXG4gICAgICAvLyBpZiB3ZSByZWFjaGVkIHRoaXMgcG9pbnQsIHdlIHN0aWxsIGhhdmUgaXRlbXMgdG8gYWNxdWlyZS5cbiAgICB9IHdoaWxlICh0cnVlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGZXRjaGVzIGFsbCB0aGUgaXRlbXMgcGFnZSBieSBwYWdlIHVzaW5nIGFkYXB0aXZlIHBhZ2luYXRpb24sIHJldHVybmluZyBlYWNoIHBhZ2UgcmVzdWx0cyBpbiBhIGNhbGxiYWNrLlxuICAgKiBTdGFydHMgd2l0aCBhIHNtYWxsIGluaXRpYWwgcGFnZSBzaXplIGZvciBmYXN0ZXIgZmlyc3QgcmVzcG9uc2UsIHRoZW4gc3dpdGNoZXMgdG8gYSBsYXJnZXIgcGFnZSBzaXplIGFmdGVyIGEgdGhyZXNob2xkLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gdXJsIFRoZSB1cmwgdG8gbWFrZSByZXF1ZXN0IHRvLiBDb3VsZCBiZSBhYnNvbHV0ZSBvciByZWxhdGl2ZSB0byB0aGUgc2VydmljZSBiYXNlIHVyaS5cbiAgICogQHBhcmFtIHsocmVzcG9uc2U6IFNlcnZpY2VSZXNwb25zZTxEPikgPT4gdm9pZH0gb25QYWdlUmV0cmlldmVkIFRoZSBjYWxsYmFjayB1c2VkIHRvIHJldHVybiByZXN1bHRzLCBwYWdlIGJ5IHBhZ2UuXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBpbml0aWFsUGFnZVNpemUgVGhlIHBhZ2Ugc2l6ZSBmb3IgaW5pdGlhbCByZXF1ZXN0cyAoZGVmYXVsdDogMTApLlxuICAgKiBAcGFyYW0ge251bWJlcn0gc3RhbmRhcmRQYWdlU2l6ZSBUaGUgcGFnZSBzaXplIGFmdGVyIHRocmVzaG9sZCBpcyByZWFjaGVkIChkZWZhdWx0OiAxMDApLlxuICAgKiBAcGFyYW0ge251bWJlcn0gdGhyZXNob2xkIFRoZSBudW1iZXIgb2YgaXRlbXMgdG8gbG9hZCBiZWZvcmUgc3dpdGNoaW5nIHRvIHN0YW5kYXJkIHBhZ2Ugc2l6ZSAoZGVmYXVsdDogNTApLlxuICAgKiBAcGFyYW0ge3N0cmluZyB8IEZvcm1EYXRhfSBib2R5IE9wdGlvbmFsIGJvZHkgdG8gc2VuZCBpbiB0aGUgcmVxdWVzdC5cbiAgICogQHBhcmFtIHtIZWFkZXJzfSBjdXN0b21IZWFkZXJzIE9wdGlvbmFsIGhlYWRlcnMgdG8gYXR0YWNoIHRvIHJlcXVlc3QuXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gYXV0aCBUaGUgdmFsdWUgaW5kaWNhdGluZyB3aGV0aGVyIHRoZSByZXF1ZXN0IHJlcXVpcmVzIGF1dGhlbnRpY2F0aW9uLiBJZiB0cnVlLCB0aGUgY3JlZGVudGlhbHMgd2lsbCBiZSByZXF1ZXN0ZWQgZnJvbSB0aGUgY29uZmlndXJhdGlvbiB7QHNlZSBDb25maWcjY3JlZGVudGlhbHMgfSBhbmQgQXV0aG9yaXphdGlvbiBoZWFkZXIgd2lsbCBiZSBhdHRhY2hlZC5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IFByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIGFsbCBwYWdlcyBoYXZlIGJlZW4gcmV0cmlldmVkLlxuICAgKiBAdGhyb3dzIHtTZXJ2aWNlRXJyb3J9IGluIGNhc2Ugb2YgdGhlIGVycm9yIHJlc3BvbnNlIGZyb20gdGhlIHNlcnZpY2UuXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgZ2V0SXRlbXNXaXRoUGFnZXNBZGFwdGl2ZTxEPihcbiAgICB1cmw6IHN0cmluZyxcbiAgICBvblBhZ2VSZXRyaWV2ZWQ6IChyZXNwb25zZTogU2VydmljZVJlc3BvbnNlPEQ+KSA9PiB2b2lkLFxuICAgIGluaXRpYWxQYWdlU2l6ZTogbnVtYmVyID0gMTAsXG4gICAgc3RhbmRhcmRQYWdlU2l6ZTogbnVtYmVyID0gMTAwLFxuICAgIHRocmVzaG9sZDogbnVtYmVyID0gNTAsXG4gICAgYm9keT86IHN0cmluZyB8IEZvcm1EYXRhLFxuICAgIGN1c3RvbUhlYWRlcnM/OiBIZWFkZXJzLFxuICAgIGF1dGg6IGJvb2xlYW4gPSB0cnVlLFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAvLyBWYWxpZGF0aW5nIHBhcmFtZXRlcnMuLi5cbiAgICBpZiAoaW5pdGlhbFBhZ2VTaXplIDw9IDAgfHwgIU51bWJlci5pc0ludGVnZXIoaW5pdGlhbFBhZ2VTaXplKSkge1xuICAgICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ2luaXRpYWxQYWdlU2l6ZSBtdXN0IGJlIGEgcG9zaXRpdmUgaW50ZWdlcicpO1xuICAgIH1cbiAgICBpZiAoc3RhbmRhcmRQYWdlU2l6ZSA8PSAwIHx8ICFOdW1iZXIuaXNJbnRlZ2VyKHN0YW5kYXJkUGFnZVNpemUpKSB7XG4gICAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignc3RhbmRhcmRQYWdlU2l6ZSBtdXN0IGJlIGEgcG9zaXRpdmUgaW50ZWdlcicpO1xuICAgIH1cbiAgICBpZiAodGhyZXNob2xkIDwgMCB8fCAhTnVtYmVyLmlzSW50ZWdlcih0aHJlc2hvbGQpKSB7XG4gICAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcigndGhyZXNob2xkIG11c3QgYmUgYSBub24tbmVnYXRpdmUgaW50ZWdlcicpO1xuICAgIH1cblxuICAgIGNvbnN0IGhlYWRlcnMgPSBjdXN0b21IZWFkZXJzID8gbmV3IEhlYWRlcnMoY3VzdG9tSGVhZGVycykgOiBuZXcgSGVhZGVycygpO1xuXG4gICAgbGV0IHRvdGFsTG9hZGVkID0gMDtcbiAgICBsZXQgY3VycmVudEluZGV4ID0gMDtcblxuICAgIC8vIE1ha2UgZmlyc3QgcmVxdWVzdCB3aXRoIGFwcHJvcHJpYXRlIHBhZ2Ugc2l6ZSAodXNlIHN0YW5kYXJkUGFnZVNpemUgaWYgdGhyZXNob2xkIGlzIDApXG4gICAgY29uc3QgZmlyc3RQYWdlU2l6ZSA9IHRocmVzaG9sZCA9PT0gMCA/IHN0YW5kYXJkUGFnZVNpemUgOiBpbml0aWFsUGFnZVNpemU7XG4gICAgaGVhZGVycy5zZXQoXG4gICAgICAnUmFuZ2UnLFxuICAgICAgYGl0ZW1zPSR7Y3VycmVudEluZGV4fS0ke2N1cnJlbnRJbmRleCArIGZpcnN0UGFnZVNpemUgLSAxfWAsXG4gICAgKTtcbiAgICBsZXQgcmVzcG9uc2UgPSBhd2FpdCB0aGlzLm1ha2VSZXF1ZXN0PEQ+KHVybCwgJ0dFVCcsIGJvZHksIGhlYWRlcnMsIGF1dGgpO1xuXG4gICAgZG8ge1xuICAgICAgLy8gQ29tcHV0ZSBwYWdpbmF0aW9uIHN0YXRlIEJFRk9SRSBjYWxsaW5nIGNhbGxiYWNrIChpbiBjYXNlIGNhbGxiYWNrIG11dGF0ZXMgcmVzcG9uc2UuZGF0YSlcbiAgICAgIGNvbnN0IGl0ZW1zSW5QYWdlID0gQXJyYXkuaXNBcnJheShyZXNwb25zZS5kYXRhKVxuICAgICAgICA/IHJlc3BvbnNlLmRhdGEubGVuZ3RoXG4gICAgICAgIDogMDtcbiAgICAgIGNvbnN0IHJlc3BvbnNlUmFuZ2UgPSB0aGlzLmdldFJhbmdlKHJlc3BvbnNlKTtcbiAgICAgIGNvbnN0IGhhc01vcmVQYWdlcyA9IHRoaXMuaGFzTW9yZVBhZ2VzKHJlc3BvbnNlLCByZXNwb25zZVJhbmdlKTtcblxuICAgICAgLy8gVXBkYXRlIGNvdW50ZXJzXG4gICAgICAvLyBVc2UgYWN0dWFsIGFycmF5IGxlbmd0aCBmb3IgdG90YWxMb2FkZWQgKHNvdXJjZSBvZiB0cnV0aCBmb3IgaXRlbXMgcmV0cmlldmVkKVxuICAgICAgdG90YWxMb2FkZWQgKz0gaXRlbXNJblBhZ2U7XG5cbiAgICAgIC8vIFVzZSByZXNwb25zZVJhbmdlLmVuZCArIDEgZm9yIG5leHQgaW5kZXggKGF1dGhvcml0YXRpdmUgZm9yIHJhbmdlLWJhc2VkIHBhZ2luYXRpb24pXG4gICAgICAvLyBUaGlzIHByZXZlbnRzIG92ZXJsYXBwaW5nL2R1cGxpY2F0ZSByZXF1ZXN0cyBldmVuIGlmIHRoZSBzZXJ2ZXIgcmV0dXJucyBmZXdlciBpdGVtcyB0aGFuIHRoZSByYW5nZVxuICAgICAgaWYgKHJlc3BvbnNlUmFuZ2UgJiYgdHlwZW9mIHJlc3BvbnNlUmFuZ2UuZW5kID09PSAnbnVtYmVyJykge1xuICAgICAgICBjdXJyZW50SW5kZXggPSByZXNwb25zZVJhbmdlLmVuZCArIDE7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBGYWxsYmFjayBpZiBubyByYW5nZSBoZWFkZXIgKHNob3VsZG4ndCBoYXBwZW4gaW4gbm9ybWFsIHJhbmdlLWJhc2VkIHBhZ2luYXRpb24pXG4gICAgICAgIGN1cnJlbnRJbmRleCArPSBpdGVtc0luUGFnZTtcbiAgICAgIH1cblxuICAgICAgbGV0IG5leHRQYWdlOiBQcm9taXNlPFNlcnZpY2VSZXNwb25zZTxEPj4gfCB1bmRlZmluZWQ7XG4gICAgICBpZiAoaGFzTW9yZVBhZ2VzICYmIHJlc3BvbnNlUmFuZ2UgJiYgcmVzcG9uc2VSYW5nZS50b3RhbCkge1xuICAgICAgICAvLyBEZXRlcm1pbmUgbmV4dCBwYWdlIHNpemUgYmFzZWQgb24gdXBkYXRlZCB0b3RhbExvYWRlZFxuICAgICAgICBjb25zdCBuZXh0UGFnZVNpemUgPVxuICAgICAgICAgIHRvdGFsTG9hZGVkIDwgdGhyZXNob2xkID8gaW5pdGlhbFBhZ2VTaXplIDogc3RhbmRhcmRQYWdlU2l6ZTtcbiAgICAgICAgLy8gVXNlIGN1cnJlbnQgcmVzcG9uc2UncyB0b3RhbCBmb3IgY2xhbXBpbmcgKGhhbmRsZXMgZHluYW1pYyB0b3RhbCBjaGFuZ2VzKVxuICAgICAgICBjb25zdCBlbmRJbmRleCA9IE1hdGgubWluKFxuICAgICAgICAgIHJlc3BvbnNlUmFuZ2UudG90YWwgLSAxLFxuICAgICAgICAgIGN1cnJlbnRJbmRleCArIG5leHRQYWdlU2l6ZSAtIDEsXG4gICAgICAgICk7XG5cbiAgICAgICAgaGVhZGVycy5zZXQoJ1JhbmdlJywgYGl0ZW1zPSR7Y3VycmVudEluZGV4fS0ke2VuZEluZGV4fWApO1xuXG4gICAgICAgIC8vIEluaXRpYXRlIG5leHQgcGFnZSByZXF1ZXN0LCBidXQgZG9uJ3Qgd2FpdCBvbiBpdCB5ZXRcbiAgICAgICAgbmV4dFBhZ2UgPSB0aGlzLm1ha2VSZXF1ZXN0PEQ+KHVybCwgJ0dFVCcsIGJvZHksIGhlYWRlcnMsIGF1dGgpO1xuICAgICAgfVxuXG4gICAgICAvLyBDYWxsIHRoZSBjYWxsYmFjayB3aXRoIHRoZSBwYWdlIGRhdGFcbiAgICAgIG9uUGFnZVJldHJpZXZlZChyZXNwb25zZSk7XG5cbiAgICAgIGlmIChuZXh0UGFnZSkge1xuICAgICAgICByZXNwb25zZSA9IGF3YWl0IG5leHRQYWdlO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG5cbiAgICAgIC8vIElmIHdlIHJlYWNoZWQgdGhpcyBwb2ludCwgd2Ugc3RpbGwgaGF2ZSBpdGVtcyB0byBhY3F1aXJlXG4gICAgfSB3aGlsZSAodHJ1ZSk7XG4gIH1cblxuICAvKipcbiAgICogTWFrZXMgYSBzZXJ2aWNlIHJlcXVlc3Qgd2l0aCBhbGwgbmVlZGVkIGF1dGhlbnRpY2F0aW9uIGFuZCByZXRyeSBsb2dpYy4gQ29udmVydHMgZXJyb3IgcmVzcG9uc2UgdG8gZXhjZXB0aW9uLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gdXJsIFRoZSB1cmwgdG8gbWFrZSByZXF1ZXN0IHRvLiBDb3VsZCBiZSBhYnNvbHV0ZSBvciByZWxhdGl2ZSB0byB0aGUgc2VydmljZSBiYXNlIHVyaS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IG1ldGhvZCBUaGUgSFRUUCBtZXRob2QuXG4gICAqIEBwYXJhbSB7c3RyaW5nIHwgRm9ybURhdGEgfCBCbG9ifSBib2R5IFRoZSBib2R5IHRvIHNlbmQgaW4gdGhlIHJlcXVlc3QuXG4gICAqIEBwYXJhbSB7SGVhZGVyc30gY3VzdG9tSGVhZGVycyBUaGUgY3VzdG9tIGhlYWRlcnMgdG8gYXR0YWNoIHRvIHJlcXVlc3QuXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gYXV0aCBUaGUgdmFsdWUgaW5kaWNhdGluZyB3aGV0aGVyIHRoZSByZXF1ZXN0IHJlcXVpcmVzIGF1dGhlbnRpY2F0aW9uLiBJZiB0cnVlLCB0aGUgY3JlZGVudGlhbHMgd2lsbCBiZSByZXF1ZXN0ZWQgZnJvbSB0aGUgY29uZmlndXJhdGlvbiB7QHNlZSBDb25maWcjY3JlZGVudGlhbHMgfSBhbmQgQXV0aG9yaXphdGlvbiBoZWFkZXIgd2lsbCBiZSBhdHRhY2hlZC5cbiAgICogQHJldHVybnMge1Byb21pc2U8U2VydmljZVJlc3BvbnNlPEQ+Pn0gVGhlIHNlcnZpY2UgcmVzcG9uc2UuXG4gICAqIEB0aHJvd3Mge1NlcnZpY2VFcnJvcn0gaW4gY2FzZSBvZiB0aGUgZXJyb3IgcmVzcG9uc2UgZnJvbSB0aGUgc2VydmljZS5cbiAgICovXG4gIHB1YmxpYyBhc3luYyByZXF1ZXN0KFxuICAgIHVybDogc3RyaW5nLFxuICAgIG1ldGhvZDogJ0dFVCcgfCAnUFVUJyB8ICdQT1NUJyB8ICdQQVRDSCcgfCAnREVMRVRFJyA9ICdHRVQnLFxuICAgIGJvZHk/OiBzdHJpbmcgfCBGb3JtRGF0YSB8IEJsb2IsXG4gICAgY3VzdG9tSGVhZGVycz86IEhlYWRlcnMsXG4gICAgYXV0aDogYm9vbGVhbiA9IHRydWUsXG4gICk6IFByb21pc2U8U2VydmljZVJlc3BvbnNlPHZvaWQ+PiB7XG4gICAgLy8gdGhpcyBtZXRob2Qgc3VwcG9ydHMgMyBjYXNlczogYWJzb2x1dGUgdXJsLCBhYnNvbHV0ZSBwYXRoLCByZWxhdGl2ZSBwYXRoXG4gICAgY29uc3QgcmVxdWVzdFVybCA9IHVybC5zdGFydHNXaXRoKCdodHRwJylcbiAgICAgID8gdXJsXG4gICAgICA6IHVybC5zdGFydHNXaXRoKCcvJylcbiAgICAgICAgPyBleHRyYWN0RW5kcG9pbnQodGhpcy5jb25maWcuc2VydmljZVVyaSkgKyB1cmxcbiAgICAgICAgOiB0aGlzLmNvbmZpZy5zZXJ2aWNlVXJpICsgdXJsO1xuXG4gICAgY29uc3QgaGVhZGVycyA9IG5ldyBIZWFkZXJzKCk7XG4gICAgY29uc3QgY29udGVudFR5cGUgPSBjdXN0b21IZWFkZXJzXG4gICAgICA/IGN1c3RvbUhlYWRlcnMuZ2V0KCdDb250ZW50LVR5cGUnKVxuICAgICAgOiB1bmRlZmluZWQ7XG4gICAgaWYgKCFjb250ZW50VHlwZSAmJiBib2R5ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGhlYWRlcnMuc2V0KCdDb250ZW50LVR5cGUnLCAnYXBwbGljYXRpb24vanNvbicpO1xuICAgIH1cblxuICAgIGlmIChjdXN0b21IZWFkZXJzKSB7XG4gICAgICBjdXN0b21IZWFkZXJzLmZvckVhY2goKHZhbHVlOiBzdHJpbmcsIGtleTogc3RyaW5nKSA9PiB7XG4gICAgICAgIGhlYWRlcnMuYXBwZW5kKGtleSwgdmFsdWUpO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMuZmV0Y2hXaXRoUmV0cnkoXG4gICAgICByZXF1ZXN0VXJsLFxuICAgICAge1xuICAgICAgICBib2R5LFxuICAgICAgICBoZWFkZXJzLFxuICAgICAgICBtZXRob2QsXG4gICAgICAgIHJlZGlyZWN0OiAnZm9sbG93JyxcbiAgICAgIH0sXG4gICAgICBhdXRoLFxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogSG93IG1hbnkgdGltZXMgYSBmYWlsZWQgcmVxdWVzdCBzaG91bGQgYmUgcmV0cmllZCBiZWZvcmUgZ2l2aW5nIHVwLlxuICAgKiB0aGUgZGVmYXVsdFJldHJ5Q291bnQgY2FuIGJlIG92ZXJyaWRkZW4gYnkgc2VydmljZSBjbGFzc2VzLlxuICAgKlxuICAgKiBAYXBpIHByaXZhdGVcbiAgICogQHByaXZhdGVcbiAgICovXG4gIHB1YmxpYyBtYXhSZXRyaWVzKCk6IG51bWJlciB7XG4gICAgaWYgKHRoaXMuY29uZmlnLm1heFJldHJpZXMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgcmV0dXJuIHRoaXMuY29uZmlnLm1heFJldHJpZXM7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiB0aGlzLmRlZmF1bHRSZXRyeUNvdW50O1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBGaXJzdCByZXRyeSBnb2VzIGltbWVkaWF0ZWx5ICgwbXMgZGVsYXkpIHRoZW4gZXhwb25lbnRpYWwgZ3Jvd3RoIHdpdGggMTAwbXMgYXMgYSBiYXNlLlxuICAgKiBAYXBpIHByaXZhdGVcbiAgICogQHByaXZhdGVcbiAgICovXG4gIHB1YmxpYyBjYWxjdWxhdGVSZXRyeURlbGF5KHJldHJ5Q291bnQ6IG51bWJlcik6IG51bWJlciB7XG4gICAgaWYgKHJldHJ5Q291bnQgPT09IDApIHtcbiAgICAgIHJldHVybiAwO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBiYXNlID0gMTAwO1xuICAgICAgcmV0dXJuIE1hdGgucmFuZG9tKCkgKiAoTWF0aC5wb3coMiwgcmV0cnlDb3VudCAtIDEpICogYmFzZSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBhcGkgcHJpdmF0ZVxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgcHJpdmF0ZSByZXRyeWFibGVFcnJvcihlcnJvcjogU2VydmljZUVycm9yKSB7XG4gICAgaWYgKFxuICAgICAgdGhpcy50aW1lb3V0RXJyb3IoZXJyb3IpIHx8XG4gICAgICB0aGlzLm5ldHdvcmtpbmdFcnJvcihlcnJvcikgfHxcbiAgICAgIHRoaXMuZXhwaXJlZENyZWRlbnRpYWxzRXJyb3IoZXJyb3IpIHx8XG4gICAgICB0aGlzLnRocm90dGxlZEVycm9yKGVycm9yKSB8fFxuICAgICAgZXJyb3IucmVzcG9uc2Uuc3RhdHVzID49IDUwMFxuICAgICkge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAYXBpIHByaXZhdGVcbiAgICogQHByaXZhdGVcbiAgICovXG4gIHByaXZhdGUgbmV0d29ya2luZ0Vycm9yKGVycm9yOiBTZXJ2aWNlRXJyb3IpIHtcbiAgICByZXR1cm4gZXJyb3IuZXJyb3JDb2RlID09PSAnTmV0d29ya2luZ0Vycm9yJztcbiAgfVxuXG4gIC8qKlxuICAgKiBAYXBpIHByaXZhdGVcbiAgICogQHByaXZhdGVcbiAgICovXG4gIHByaXZhdGUgdGltZW91dEVycm9yKGVycm9yOiBTZXJ2aWNlRXJyb3IpIHtcbiAgICByZXR1cm4gZXJyb3IuZXJyb3JDb2RlID09PSAnVGltZW91dEVycm9yJztcbiAgfVxuXG4gIC8qKlxuICAgKiBAYXBpIHByaXZhdGVcbiAgICogQHByaXZhdGVcbiAgICovXG4gIHByaXZhdGUgZXhwaXJlZENyZWRlbnRpYWxzRXJyb3IoZXJyb3I6IFNlcnZpY2VFcnJvcikge1xuICAgIGlmIChlcnJvci5yZXNwb25zZS5zdGF0dXMgPT09IDQwMSkge1xuICAgICAgY29uc3QgY3JlZGVudGlhbHMgPSB0aGlzLmNvbmZpZy5jcmVkZW50aWFscztcbiAgICAgIGlmIChcbiAgICAgICAgY3JlZGVudGlhbHMgJiZcbiAgICAgICAgdHlwZW9mIChjcmVkZW50aWFscyBhcyBDcmVkZW50aWFscykuZXhwaXJlZCA9PT0gJ2Jvb2xlYW4nXG4gICAgICApIHtcbiAgICAgICAgKGNyZWRlbnRpYWxzIGFzIENyZWRlbnRpYWxzKS5leHBpcmVkID0gdHJ1ZTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvKipcbiAgICogQGFwaSBwcml2YXRlXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwcml2YXRlIHRocm90dGxlZEVycm9yKGVycm9yOiBTZXJ2aWNlRXJyb3IpIHtcbiAgICAvLyBBV1MgQVBJIEdhdGV3YXkgcmV0dXJucyA0MjkgaW4gY2FzZSBvZiB0aHJvdHRsaW5nIGVycm9yc1xuICAgIGlmIChlcnJvci5yZXNwb25zZS5zdGF0dXMgPT09IDQyOSkge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogTWFrZXMgYSBzZXJ2aWNlIGNhbGwgYW5kIHRha2VzIGNhcmUgYWJvdXQgcmV0cnkgbG9naWMgKHJlLWF1dGhlbnRpY2F0aW9uIGlmIG5lZWRlZCkuXG4gICAqIE5vdGUgdGhlIDx2b2lkPiBhcyBhIGdlbmVyaWMgcGFyYW1ldGVyLiBUaGlzIG1ldGhvZCBkb2VzIG5vdCByZWFkIHRoZSByZXNwb25zZSBib2R5LiBUaGUgU2VydmljZVJlc3BvbnNlIHJldHVybiB2YWx1ZSB3aWxsIGJlIGNhc2VkIHRvIG5lZWRlZCB0eXBlIG9uIHVwcGVyIGxldmVscyBvZiB0aGUgY29kZS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHVybCBUaGUgdXJsIHRvIG1ha2UgcmVxdWVzdCB0by4gQ291bGQgYmUgYWJzb2x1dGUgb3IgcmVsYXRpdmUgdG8gdGhlIHNlcnZpY2UgYmFzZSB1cmkuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJhbXMgVGhlIGZldGNoIHBhcmFtZXRlcnMuXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gYXV0aCBUaGUgdmFsdWUgaW5kaWNhdGluZyB3aGV0aGVyIHRoZSByZXF1ZXN0IHJlcXVpcmVzIGF1dGhlbnRpY2F0aW9uLiBJZiB0cnVlLCB0aGUgY3JlZGVudGlhbHMgd2lsbCBiZSByZXF1ZXN0ZWQgZnJvbSB0aGUgY29uZmlndXJhdGlvbiB7QHNlZSBDb25maWcjY3JlZGVudGlhbHMgfSBhbmQgQXV0aG9yaXphdGlvbiBoZWFkZXIgd2lsbCBiZSBhdHRhY2hlZC5cbiAgICogQHJldHVybnMge1Byb21pc2U8U2VydmljZVJlc3BvbnNlPHZvaWQ+Pn0gVGhlIHNlcnZpY2UgcmVzcG9uc2UuXG4gICAqIEB0aHJvd3Mge1NlcnZpY2VFcnJvcn0gaW4gY2FzZSBvZiB0aGUgZXJyb3IgcmVzcG9uc2UgZnJvbSB0aGUgc2VydmljZS5cbiAgICogQHByaXZhdGVcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZmV0Y2hXaXRoUmV0cnkoXG4gICAgdXJsOiBzdHJpbmcsXG4gICAgcGFyYW1zOiBhbnksXG4gICAgYXV0aDogYm9vbGVhbiA9IHRydWUsXG4gICk6IFByb21pc2U8U2VydmljZVJlc3BvbnNlPHZvaWQ+PiB7XG4gICAgY29uc3QgbG9nZ2VyID0gdGhpcy5jb25maWcubG9nZ2VyO1xuICAgIGNvbnN0IHJlc3VsdDogU2VydmljZVJlc3BvbnNlPHZvaWQ+ID0gbmV3IFNlcnZpY2VSZXNwb25zZTx2b2lkPihcbiAgICAgIHRoaXMsXG4gICAgICBuZXcgUmVzcG9uc2UoKSxcbiAgICAgIHZvaWQgMCxcbiAgICApO1xuICAgIGRvIHtcbiAgICAgIGNvbnN0IGNyZWRlbnRpYWxzID0gdGhpcy5jb25maWcuY3JlZGVudGlhbHM7XG4gICAgICBpZiAoYXV0aCAmJiBjcmVkZW50aWFscykge1xuICAgICAgICBpZiAodHlwZW9mIChjcmVkZW50aWFscyBhcyBTZXJ2aWNlQ3JlZGVudGlhbHMpLmdldCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCAoY3JlZGVudGlhbHMgYXMgU2VydmljZUNyZWRlbnRpYWxzKS5nZXQoKTtcbiAgICAgICAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgICAgICAgaWYgKGxvZ2dlciAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgIHRoaXMubG9nKGBbVElEXSBGYWlsZWQgdG8gYWNxdWlyZSB0b2tlbnM6ICR7ZXJyLm1lc3NhZ2V9YCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoY3JlZGVudGlhbHMudG9rZW4pIHtcbiAgICAgICAgICBwYXJhbXMuaGVhZGVycy5zZXQoJ0F1dGhvcml6YXRpb24nLCAnQmVhcmVyICcgKyBjcmVkZW50aWFscy50b2tlbik7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgY29uc3Qgc3RhcnRUaW1lID0gRGF0ZS5ub3coKTtcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5mZXRjaCh1cmwsIHBhcmFtcyk7XG4gICAgICBpZiAobG9nZ2VyICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgY29uc3QgZGVsdGEgPSAoRGF0ZS5ub3coKSAtIHN0YXJ0VGltZSkgLyAxMDAwO1xuICAgICAgICBjb25zdCBpc29EYXRlID0gbmV3IERhdGUoc3RhcnRUaW1lKS50b0lTT1N0cmluZygpO1xuICAgICAgICBjb25zdCByZXF1ZXN0Q29udGVudExlbmd0aCA9IHBhcmFtcy5ib2R5ID8gcGFyYW1zLmJvZHkubGVuZ3RoIDogMDtcbiAgICAgICAgY29uc3QgcmVzcG9uc2VDb250ZW50TGVuZ3RoI