UNPKG

trimble-connect-sdk

Version:

Trimble Connect SDK for JavaScript

320 lines 55.3 kB
"use strict"; 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()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Service = exports.extractEndpoint = void 0; const error_1 = require("./error"); const response_1 = require("./response"); function extractEndpoint(url) { const schemaIndex = url.indexOf('//'); const firstSeparatorIndex = url.indexOf('/', schemaIndex + 2); return url.substring(0, firstSeparatorIndex); } exports.extractEndpoint = extractEndpoint; function delay(ms) { return new Promise((resolve) => { setTimeout(resolve, ms); }); } 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 error_1.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 response_1.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 error_1.ServiceError(response, errorInfo.message, errorInfo.code || errorInfo.errorcode); } else { const message = yield response.text(); err = new error_1.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'); } } }); } } exports.Service = Service; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIuLyIsInNvdXJjZXMiOlsic2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7QUFHQSxtQ0FBdUM7QUFDdkMseUNBQTZDO0FBSTdDLFNBQWdCLGVBQWUsQ0FBQyxHQUFXO0lBQ3pDLE1BQU0sV0FBVyxHQUFHLEdBQUcsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDdEMsTUFBTSxtQkFBbUIsR0FBRyxHQUFHLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxXQUFXLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFFOUQsT0FBTyxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxtQkFBbUIsQ0FBQyxDQUFDO0FBQy9DLENBQUM7QUFMRCwwQ0FLQztBQUVELFNBQVMsS0FBSyxDQUFDLEVBQVU7SUFDdkIsT0FBTyxJQUFJLE9BQU8sQ0FBTyxDQUFDLE9BQU8sRUFBRSxFQUFFO1FBQ25DLFVBQVUsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDMUIsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDO0FBTUQsTUFBYSxPQUFPO0lBUWxCLFlBQTRCLE1BQXFCO1FBQXJCLFdBQU0sR0FBTixNQUFNLENBQWU7UUFOekMsc0JBQWlCLEdBQVcsQ0FBQyxDQUFDO1FBT3BDLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLFVBQVUsRUFBRTtZQUMzQixNQUFNLElBQUksS0FBSyxDQUFDLDRCQUE0QixDQUFDLENBQUM7U0FDL0M7SUFDSCxDQUFDO0lBWVksV0FBVyxDQUN0QixHQUFXLEVBQ1gsU0FBc0QsS0FBSyxFQUMzRCxJQUF3QixFQUN4QixhQUF1QixFQUN2QixPQUFnQixJQUFJOztZQUVwQixNQUFNLE9BQU8sR0FBRyxJQUFJLE9BQU8sQ0FBQyxFQUFFLE1BQU0sRUFBRSxrQkFBa0IsRUFBRSxDQUFDLENBQUM7WUFDNUQsSUFBSSxhQUFhLEVBQUU7Z0JBQ2pCLGFBQWEsQ0FB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dXJhdGlvbiB9IGZyb20gJy4vY29uZmlnJztcbmltcG9ydCB7IENyZWRlbnRpYWxzIH0gZnJvbSAnLi9jcmVkZW50aWFscyc7XG5pbXBvcnQgeyBSYW5nZSB9IGZyb20gJy4vY29tbW9uJztcbmltcG9ydCB7IFNlcnZpY2VFcnJvciB9IGZyb20gJy4vZXJyb3InO1xuaW1wb3J0IHsgU2VydmljZVJlc3BvbnNlIH0gZnJvbSAnLi9yZXNwb25zZSc7XG5pbXBvcnQgeyBTZXJ2aWNlQ3JlZGVudGlhbHMgfSBmcm9tICcuL3NlcnZpY2VfY3JlZGVudGlhbHMnO1xuXG4vKiogQGludGVybmFsICovXG5leHBvcnQgZnVuY3Rpb24gZXh0cmFjdEVuZHBvaW50KHVybDogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3Qgc2NoZW1hSW5kZXggPSB1cmwuaW5kZXhPZignLy8nKTtcbiAgY29uc3QgZmlyc3RTZXBhcmF0b3JJbmRleCA9IHVybC5pbmRleE9mKCcvJywgc2NoZW1hSW5kZXggKyAyKTtcblxuICByZXR1cm4gdXJsLnN1YnN0cmluZygwLCBmaXJzdFNlcGFyYXRvckluZGV4KTtcbn1cblxuZnVuY3Rpb24gZGVsYXkobXM6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICByZXR1cm4gbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUpID0+IHtcbiAgICBzZXRUaW1lb3V0KHJlc29sdmUsIG1zKTtcbiAgfSk7XG59XG5cbi8qKlxuICogVGhlIHNlcnZpY2UgY2xpZW50IHRoYXQgcmVwcmVzZW50cyBjb25uZWN0aW9uIHRvIHRoZSBPcmdhbml6ZXIgU2VydmljZS5cbiAqIEVhY2ggQVBJIG9wZXJhdGlvbiBpcyBleHBvc2VkIGFzIGEgZnVuY3Rpb24gb24gc2VydmljZS5cbiAqL1xuZXhwb3J0IGNsYXNzIFNlcnZpY2Uge1xuICAvKiogVXNlZCBpZiBtYXhSZXRyaWVzIGlzIG5vdCBzcGVjaWZpZWQgaW4ge0BzZWUgQ29uZmlndXJhdGlvbiNtYXhSZXRyaWVzIH0uIFRoZSBkZWZhdWx0UmV0cnlDb3VudCBjYW4gYmUgb3ZlcnJpZGRlbiBieSBzZXJ2aWNlIGNsYXNzZXMuICovXG4gIHByaXZhdGUgZGVmYXVsdFJldHJ5Q291bnQ6IG51bWJlciA9IDM7XG5cbiAgLyoqXG4gICAqIEBjb25zdHJ1Y3RvciBDb25zdHJ1Y3RzIGEgc2VydmljZSBvYmplY3QuXG4gICAqIEBwYXJhbSB7Q29uZmlnfSBjb25maWcgVGhlIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyAoZS5nLiBzZXJ2aWNlIHVybCkuXG4gICAqL1xuICBjb25zdHJ1Y3RvcihwdWJsaWMgcmVhZG9ubHkgY29uZmlnOiBDb25maWd1cmF0aW9uKSB7XG4gICAgaWYgKCF0aGlzLmNvbmZpZy5zZXJ2aWNlVXJpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1RoZSBzZXJ2aWNlVXJpIGlzIHJlcXVpcmVkJyk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEZldGNoZXMgdGhlIG5leHQgcGFnZSBmcm9tIHRoZSBzZXF1ZW5jZSBvZiBwYWdlcyBpbml0aWF0ZWQgYnkge0BzZWUgT3JnYW5pemVyLmxpc3RUcmVlcyB9LlxuICAgKiBAcGFyYW0ge3N0cmluZ30gdXJsIFRoZSB1cmwgdG8gbWFrZSByZXF1ZXN0IHRvLiBDb3VsZCBiZSBhYnNvbHV0ZSBvciByZWxhdGl2ZSB0byB0aGUgc2VydmljZSBiYXNlIHVyaS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IG1ldGhvZCBUaGUgSFRUUCBtZXRob2QuXG4gICAqIEBwYXJhbSB7c3RyaW5nIHwgRm9ybURhdGF9IGJvZHkgT3B0aW9uYWwgYm9keSB0byBzZW5kIGluIHRoZSByZXF1ZXN0LlxuICAgKiBAcGFyYW0ge0hlYWRlcnN9IGN1c3RvbUhlYWRlcnMgT3B0aW9uYWwgaGVhZGVycyB0byBhdHRhY2ggdG8gcmVxdWVzdC5cbiAgICogQHBhcmFtIHtib29sZWFufSBhdXRoIFRoZSB2YWx1ZSBpbmRpY2F0aW5nIHdoZXRoZXIgdGhlIHJlcXVlc3QgcmVxdWlyZXMgYXV0aGVudGljYXRpb24uIElmIHRydWUsIHRoZSBjcmVkZW50aWFscyB3aWxsIGJlIHJlcXVlc3RlZCBmcm9tIHRoZSBjb25maWd1cmF0aW9uIHtAc2VlIENvbmZpZyNjcmVkZW50aWFscyB9IGFuZCBBdXRob3JpemF0aW9uIGhlYWRlciB3aWxsIGJlIGF0dGFjaGVkLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxTZXJ2aWNlUmVzcG9uc2U8RD4+fSBUaGUgc2VydmljZSByZXNwb25zZS5cbiAgICogQHRocm93cyB7U2VydmljZUVycm9yfSBpbiBjYXNlIG9mIHRoZSBlcnJvciByZXNwb25zZSBmcm9tIHRoZSBzZXJ2aWNlLlxuICAgKi9cbiAgcHVibGljIGFzeW5jIG1ha2VSZXF1ZXN0PEQ+KFxuICAgIHVybDogc3RyaW5nLFxuICAgIG1ldGhvZDogJ0dFVCcgfCAnUFVUJyB8ICdQT1NUJyB8ICdQQVRDSCcgfCAnREVMRVRFJyA9ICdHRVQnLFxuICAgIGJvZHk/OiBzdHJpbmcgfCBGb3JtRGF0YSxcbiAgICBjdXN0b21IZWFkZXJzPzogSGVhZGVycyxcbiAgICBhdXRoOiBib29sZWFuID0gdHJ1ZSxcbiAgKTogUHJvbWlzZTxTZXJ2aWNlUmVzcG9uc2U8RD4+IHtcbiAgICBjb25zdCBoZWFkZXJzID0gbmV3IEhlYWRlcnMoeyBBY2NlcHQ6ICdhcHBsaWNhdGlvbi9qc29uJyB9KTtcbiAgICBpZiAoY3VzdG9tSGVhZGVycykge1xuICAgICAgY3VzdG9tSGVhZGVycy5mb3JFYWNoKCh2YWx1ZTogc3RyaW5nLCBrZXk6IHN0cmluZykgPT4ge1xuICAgICAgICBoZWFkZXJzLmFwcGVuZChrZXksIHZhbHVlKTtcbiAgICAgIH0pO1xuICAgIH1cbiAgICBjb25zdCByZXNwb25zZSA9IChhd2FpdCB0aGlzLnJlcXVlc3QoXG4gICAgICB1cmwsXG4gICAgICBtZXRob2QsXG4gICAgICBib2R5LFxuICAgICAgaGVhZGVycyxcbiAgICAgIGF1dGgsXG4gICAgKSkgYXMgYW55IGFzIFNlcnZpY2VSZXNwb25zZTxEPjtcblxuICAgIC8vIGRlc2VyaWFsaXplIHJlc3BvbnNlIGJvZHkuIElmIHNlcnZpY2UgcmVzcG9uZGVkIHdpdGggYW4gZXJyb3IgaXQgd2FzIHRocm93biBhbHJlYWR5LlxuICAgIGlmIChyZXNwb25zZS5yZXNwb25zZS5zdGF0dXMgIT09IDIwNCkge1xuICAgICAgY29uc3QgY29udGVudFR5cGUgPSByZXNwb25zZS5yZXNwb25zZS5oZWFkZXJzLmdldCgnY29udGVudC10eXBlJyk7XG4gICAgICBpZiAoXG4gICAgICAgIGNvbnRlbnRUeXBlID09PSBudWxsIHx8XG4gICAgICAgIGNvbnRlbnRUeXBlLmluZGV4T2YoJ2FwcGxpY2F0aW9uL2pzb24nKSAhPT0gLTFcbiAgICAgICkge1xuICAgICAgICByZXNwb25zZS5kYXRhID0gKGF3YWl0IHJlc3BvbnNlLnJlc3BvbnNlLmpzb24oKSkgYXMgRDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBTZXJ2aWNlRXJyb3IoXG4gICAgICAgICAgcmVzcG9uc2UucmVzcG9uc2UsXG4gICAgICAgICAgJ0Nhbm5vdCBkZXNlcmlhbGl6ZSByZXNwb25zZSBib2R5IGFzIGl0IGlzIG5vdCBpbiBhIEpTT04gZm9ybWF0LicsXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3BvbnNlO1xuICB9XG5cbiAgLyoqXG4gICAqIEZldGNoZXMgYWxsIHRoZSBpdGVtcyBwYWdlIGJ5IHBhZ2UsIHJldHVybmluZyBlYWNoIHBhZ2UgcmVzdWx0cyBpbiBhIGNhbGxiYWNrLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gdXJsIFRoZSB1cmwgdG8gbWFrZSByZXF1ZXN0IHRvLiBDb3VsZCBiZSBhYnNvbHV0ZSBvciByZWxhdGl2ZSB0byB0aGUgc2VydmljZSBiYXNlIHVyaS5cbiAgICogQHBhcmFtIHsocmVzcG9uc2U6IFNlcnZpY2VSZXNwb25zZTxEPikgPT4gdm9pZH0gb25QYWdlUmV0cmlldmVkIFRoZSBjYWxsYmFjayB1c2VkIHRvIHJldHVybiByZXN1bHRzLCBwYWdlIGJ5IHBhZ2UuXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBwYWdlU2l6ZSBUaGUgcGFnZSBzaXplIHVzZWQgdG8gcmVxdWVzdCBpdGVtcy5cbiAgICogQHBhcmFtIHtzdHJpbmcgfCBGb3JtRGF0YX0gYm9keSBPcHRpb25hbCBib2R5IHRvIHNlbmQgaW4gdGhlIHJlcXVlc3QuXG4gICAqIEBwYXJhbSB7SGVhZGVyc30gY3VzdG9tSGVhZGVycyBPcHRpb25hbCBoZWFkZXJzIHRvIGF0dGFjaCB0byByZXF1ZXN0LlxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IGF1dGggVGhlIHZhbHVlIGluZGljYXRpbmcgd2hldGhlciB0aGUgcmVxdWVzdCByZXF1aXJlcyBhdXRoZW50aWNhdGlvbi4gSWYgdHJ1ZSwgdGhlIGNyZWRlbnRpYWxzIHdpbGwgYmUgcmVxdWVzdGVkIGZyb20gdGhlIGNvbmZpZ3VyYXRpb24ge0BzZWUgQ29uZmlnI2NyZWRlbnRpYWxzIH0gYW5kIEF1dGhvcml6YXRpb24gaGVhZGVyIHdpbGwgYmUgYXR0YWNoZWQuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiBhbGwgcGFnZXMgaGF2ZSBiZWVuIHJldHJpZXZlZC5cbiAgICogQHRocm93cyB7U2VydmljZUVycm9yfSBpbiBjYXNlIG9mIHRoZSBlcnJvciByZXNwb25zZSBmcm9tIHRoZSBzZXJ2aWNlLlxuICAgKi9cbiAgcHVibGljIGFzeW5jIGdldEl0ZW1zV2l0aFBhZ2VzPEQ+KFxuICAgIHVybDogc3RyaW5nLFxuICAgIG9uUGFnZVJldHJpZXZlZDogKHJlc3BvbnNlOiBTZXJ2aWNlUmVzcG9uc2U8RD4pID0+IHZvaWQsXG4gICAgcGFnZVNpemU6IG51bWJlcixcbiAgICBib2R5Pzogc3RyaW5nIHwgRm9ybURhdGEsXG4gICAgY3VzdG9tSGVhZGVycz86IEhlYWRlcnMsXG4gICAgYXV0aDogYm9vbGVhbiA9IHRydWUsXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIC8vIFZhbGlkYXRlIHBhcmFtZXRlclxuICAgIGlmIChwYWdlU2l6ZSA8PSAwIHx8ICFOdW1iZXIuaXNJbnRlZ2VyKHBhZ2VTaXplKSkge1xuICAgICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ3BhZ2VTaXplIG11c3QgYmUgYSBwb3NpdGl2ZSBpbnRlZ2VyJyk7XG4gICAgfVxuXG4gICAgY29uc3QgaGVhZGVycyA9IGN1c3RvbUhlYWRlcnMgPyBuZXcgSGVhZGVycyhjdXN0b21IZWFkZXJzKSA6IG5ldyBIZWFkZXJzKCk7XG4gICAgY29uc3QgcmFuZ2U6IFJhbmdlID0geyBzdGFydDogMCwgZW5kOiBwYWdlU2l6ZSAtIDEgfTtcbiAgICBoZWFkZXJzLnNldCgnUmFuZ2UnLCBgaXRlbXM9JHtyYW5nZS5zdGFydH0tJHtyYW5nZS5lbmR9YCk7XG5cbiAgICBsZXQgcmVzcG9uc2UgPSBhd2FpdCB0aGlzLm1ha2VSZXF1ZXN0PEQ+KHVybCwgJ0dFVCcsIGJvZHksIGhlYWRlcnMsIGF1dGgpO1xuXG4gICAgZG8ge1xuICAgICAgY29uc3QgcmVzcG9uc2VSYW5nZSA9IHRoaXMuZ2V0UmFuZ2UocmVzcG9uc2UpO1xuICAgICAgY29uc3QgaGFzTmV4dFBhZ2UgPSB0aGlzLmhhc01vcmVQYWdlcyhyZXNwb25zZSwgcmVzcG9uc2VSYW5nZSk7XG5cbiAgICAgIGxldCBuZXh0UGFnZTogUHJvbWlzZTxTZXJ2aWNlUmVzcG9uc2U8RD4+IHwgdW5kZWZpbmVkO1xuICAgICAgaWYgKGhhc05leHRQYWdlICYmIHJlc3BvbnNlUmFuZ2UgJiYgcmVzcG9uc2VSYW5nZS50b3RhbCkge1xuICAgICAgICByYW5nZS5zdGFydCA9IHJlc3BvbnNlUmFuZ2UuZW5kICsgMTtcbiAgICAgICAgcmFuZ2UuZW5kID0gTWF0aC5taW4oXG4gICAgICAgICAgcmVzcG9uc2VSYW5nZS50b3RhbCAtIDEsXG4gICAgICAgICAgcmFuZ2Uuc3RhcnQgKyBwYWdlU2l6ZSAtIDEsXG4gICAgICAgICk7XG4gICAgICAgIGhlYWRlcnMuc2V0KCdSYW5nZScsIGBpdGVtcz0ke3JhbmdlLnN0YXJ0fS0ke3JhbmdlLmVuZH1gKTtcblxuICAgICAgICAvLyBpbml0aWF0ZSBuZXh0IHBhZ2UgcmVxdWVzdCwgYnV0IGRvbid0IHdhaXQgb24gaXQgeWV0XG4gICAgICAgIG5leHRQYWdlID0gdGhpcy5tYWtlUmVxdWVzdDxEPih1cmwsICdHRVQnLCBib2R5LCBoZWFkZXJzLCBhdXRoKTtcbiAgICAgIH1cblxuICAgICAgb25QYWdlUmV0cmlldmVkKHJlc3BvbnNlKTtcblxuICAgICAgaWYgKG5leHRQYWdlKSB7XG4gICAgICAgIHJlc3BvbnNlID0gYXdhaXQgbmV4dFBhZ2U7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBicmVhaztcbiAgICAgIH1cblxuICAgICAgLy8gaWYgd2UgcmVhY2hlZCB0aGlzIHBvaW50LCB3ZSBzdGlsbCBoYXZlIGl0ZW1zIHRvIGFjcXVpcmUuXG4gICAgfSB3aGlsZSAodHJ1ZSk7XG4gIH1cblxuICAvKipcbiAgICogRmV0Y2hlcyBhbGwgdGhlIGl0ZW1zIHBhZ2UgYnkgcGFnZSB1c2luZyBhZGFwdGl2ZSBwYWdpbmF0aW9uLCByZXR1cm5pbmcgZWFjaCBwYWdlIHJlc3VsdHMgaW4gYSBjYWxsYmFjay5cbiAgICogU3RhcnRzIHdpdGggYSBzbWFsbCBpbml0aWFsIHBhZ2Ugc2l6ZSBmb3IgZmFzdGVyIGZpcnN0IHJlc3BvbnNlLCB0aGVuIHN3aXRjaGVzIHRvIGEgbGFyZ2VyIHBhZ2Ugc2l6ZSBhZnRlciBhIHRocmVzaG9sZC5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHVybCBUaGUgdXJsIHRvIG1ha2UgcmVxdWVzdCB0by4gQ291bGQgYmUgYWJzb2x1dGUgb3IgcmVsYXRpdmUgdG8gdGhlIHNlcnZpY2UgYmFzZSB1cmkuXG4gICAqIEBwYXJhbSB7KHJlc3BvbnNlOiBTZXJ2aWNlUmVzcG9uc2U8RD4pID0+IHZvaWR9IG9uUGFnZVJldHJpZXZlZCBUaGUgY2FsbGJhY2sgdXNlZCB0byByZXR1cm4gcmVzdWx0cywgcGFnZSBieSBwYWdlLlxuICAgKiBAcGFyYW0ge251bWJlcn0gaW5pdGlhbFBhZ2VTaXplIFRoZSBwYWdlIHNpemUgZm9yIGluaXRpYWwgcmVxdWVzdHMgKGRlZmF1bHQ6IDEwKS5cbiAgICogQHBhcmFtIHtudW1iZXJ9IHN0YW5kYXJkUGFnZVNpemUgVGhlIHBhZ2Ugc2l6ZSBhZnRlciB0aHJlc2hvbGQgaXMgcmVhY2hlZCAoZGVmYXVsdDogMTAwKS5cbiAgICogQHBhcmFtIHtudW1iZXJ9IHRocmVzaG9sZCBUaGUgbnVtYmVyIG9mIGl0ZW1zIHRvIGxvYWQgYmVmb3JlIHN3aXRjaGluZyB0byBzdGFuZGFyZCBwYWdlIHNpemUgKGRlZmF1bHQ6IDUwKS5cbiAgICogQHBhcmFtIHtzdHJpbmcgfCBGb3JtRGF0YX0gYm9keSBPcHRpb25hbCBib2R5IHRvIHNlbmQgaW4gdGhlIHJlcXVlc3QuXG4gICAqIEBwYXJhbSB7SGVhZGVyc30gY3VzdG9tSGVhZGVycyBPcHRpb25hbCBoZWFkZXJzIHRvIGF0dGFjaCB0byByZXF1ZXN0LlxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IGF1dGggVGhlIHZhbHVlIGluZGljYXRpbmcgd2hldGhlciB0aGUgcmVxdWVzdCByZXF1aXJlcyBhdXRoZW50aWNhdGlvbi4gSWYgdHJ1ZSwgdGhlIGNyZWRlbnRpYWxzIHdpbGwgYmUgcmVxdWVzdGVkIGZyb20gdGhlIGNvbmZpZ3VyYXRpb24ge0BzZWUgQ29uZmlnI2NyZWRlbnRpYWxzIH0gYW5kIEF1dGhvcml6YXRpb24gaGVhZGVyIHdpbGwgYmUgYXR0YWNoZWQuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiBhbGwgcGFnZXMgaGF2ZSBiZWVuIHJldHJpZXZlZC5cbiAgICogQHRocm93cyB7U2VydmljZUVycm9yfSBpbiBjYXNlIG9mIHRoZSBlcnJvciByZXNwb25zZSBmcm9tIHRoZSBzZXJ2aWNlLlxuICAgKi9cbiAgcHVibGljIGFzeW5jIGdldEl0ZW1zV2l0aFBhZ2VzQWRhcHRpdmU8RD4oXG4gICAgdXJsOiBzdHJpbmcsXG4gICAgb25QYWdlUmV0cmlldmVkOiAocmVzcG9uc2U6IFNlcnZpY2VSZXNwb25zZTxEPikgPT4gdm9pZCxcbiAgICBpbml0aWFsUGFnZVNpemU6IG51bWJlciA9IDEwLFxuICAgIHN0YW5kYXJkUGFnZVNpemU6IG51bWJlciA9IDEwMCxcbiAgICB0aHJlc2hvbGQ6IG51bWJlciA9IDUwLFxuICAgIGJvZHk/OiBzdHJpbmcgfCBGb3JtRGF0YSxcbiAgICBjdXN0b21IZWFkZXJzPzogSGVhZGVycyxcbiAgICBhdXRoOiBib29sZWFuID0gdHJ1ZSxcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgLy8gVmFsaWRhdGluZyBwYXJhbWV0ZXJzLi4uXG4gICAgaWYgKGluaXRpYWxQYWdlU2l6ZSA8PSAwIHx8ICFOdW1iZXIuaXNJbnRlZ2VyKGluaXRpYWxQYWdlU2l6ZSkpIHtcbiAgICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCdpbml0aWFsUGFnZVNpemUgbXVzdCBiZSBhIHBvc2l0aXZlIGludGVnZXInKTtcbiAgICB9XG4gICAgaWYgKHN0YW5kYXJkUGFnZVNpemUgPD0gMCB8fCAhTnVtYmVyLmlzSW50ZWdlcihzdGFuZGFyZFBhZ2VTaXplKSkge1xuICAgICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ3N0YW5kYXJkUGFnZVNpemUgbXVzdCBiZSBhIHBvc2l0aXZlIGludGVnZXInKTtcbiAgICB9XG4gICAgaWYgKHRocmVzaG9sZCA8IDAgfHwgIU51bWJlci5pc0ludGVnZXIodGhyZXNob2xkKSkge1xuICAgICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ3RocmVzaG9sZCBtdXN0IGJlIGEgbm9uLW5lZ2F0aXZlIGludGVnZXInKTtcbiAgICB9XG5cbiAgICBjb25zdCBoZWFkZXJzID0gY3VzdG9tSGVhZGVycyA/IG5ldyBIZWFkZXJzKGN1c3RvbUhlYWRlcnMpIDogbmV3IEhlYWRlcnMoKTtcblxuICAgIGxldCB0b3RhbExvYWRlZCA9IDA7XG4gICAgbGV0IGN1cnJlbnRJbmRleCA9IDA7XG5cbiAgICAvLyBNYWtlIGZpcnN0IHJlcXVlc3Qgd2l0aCBhcHByb3ByaWF0ZSBwYWdlIHNpemUgKHVzZSBzdGFuZGFyZFBhZ2VTaXplIGlmIHRocmVzaG9sZCBpcyAwKVxuICAgIGNvbnN0IGZpcnN0UGFnZVNpemUgPSB0aHJlc2hvbGQgPT09IDAgPyBzdGFuZGFyZFBhZ2VTaXplIDogaW5pdGlhbFBhZ2VTaXplO1xuICAgIGhlYWRlcnMuc2V0KFxuICAgICAgJ1JhbmdlJyxcbiAgICAgIGBpdGVtcz0ke2N1cnJlbnRJbmRleH0tJHtjdXJyZW50SW5kZXggKyBmaXJzdFBhZ2VTaXplIC0gMX1gLFxuICAgICk7XG4gICAgbGV0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5tYWtlUmVxdWVzdDxEPih1cmwsICdHRVQnLCBib2R5LCBoZWFkZXJzLCBhdXRoKTtcblxuICAgIGRvIHtcbiAgICAgIC8vIENvbXB1dGUgcGFnaW5hdGlvbiBzdGF0ZSBCRUZPUkUgY2FsbGluZyBjYWxsYmFjayAoaW4gY2FzZSBjYWxsYmFjayBtdXRhdGVzIHJlc3BvbnNlLmRhdGEpXG4gICAgICBjb25zdCBpdGVtc0luUGFnZSA9IEFycmF5LmlzQXJyYXkocmVzcG9uc2UuZGF0YSlcbiAgICAgICAgPyByZXNwb25zZS5kYXRhLmxlbmd0aFxuICAgICAgICA6IDA7XG4gICAgICBjb25zdCByZXNwb25zZVJhbmdlID0gdGhpcy5nZXRSYW5nZShyZXNwb25zZSk7XG4gICAgICBjb25zdCBoYXNNb3JlUGFnZXMgPSB0aGlzLmhhc01vcmVQYWdlcyhyZXNwb25zZSwgcmVzcG9uc2VSYW5nZSk7XG5cbiAgICAgIC8vIFVwZGF0ZSBjb3VudGVyc1xuICAgICAgLy8gVXNlIGFjdHVhbCBhcnJheSBsZW5ndGggZm9yIHRvdGFsTG9hZGVkIChzb3VyY2Ugb2YgdHJ1dGggZm9yIGl0ZW1zIHJldHJpZXZlZClcbiAgICAgIHRvdGFsTG9hZGVkICs9IGl0ZW1zSW5QYWdlO1xuXG4gICAgICAvLyBVc2UgcmVzcG9uc2VSYW5nZS5lbmQgKyAxIGZvciBuZXh0IGluZGV4IChhdXRob3JpdGF0aXZlIGZvciByYW5nZS1iYXNlZCBwYWdpbmF0aW9uKVxuICAgICAgLy8gVGhpcyBwcmV2ZW50cyBvdmVybGFwcGluZy9kdXBsaWNhdGUgcmVxdWVzdHMgZXZlbiBpZiB0aGUgc2VydmVyIHJldHVybnMgZmV3ZXIgaXRlbXMgdGhhbiB0aGUgcmFuZ2VcbiAgICAgIGlmIChyZXNwb25zZVJhbmdlICYmIHR5cGVvZiByZXNwb25zZVJhbmdlLmVuZCA9PT0gJ251bWJlcicpIHtcbiAgICAgICAgY3VycmVudEluZGV4ID0gcmVzcG9uc2VSYW5nZS5lbmQgKyAxO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gRmFsbGJhY2sgaWYgbm8gcmFuZ2UgaGVhZGVyIChzaG91bGRuJ3QgaGFwcGVuIGluIG5vcm1hbCByYW5nZS1iYXNlZCBwYWdpbmF0aW9uKVxuICAgICAgICBjdXJyZW50SW5kZXggKz0gaXRlbXNJblBhZ2U7XG4gICAgICB9XG5cbiAgICAgIGxldCBuZXh0UGFnZTogUHJvbWlzZTxTZXJ2aWNlUmVzcG9uc2U8RD4+IHwgdW5kZWZpbmVkO1xuICAgICAgaWYgKGhhc01vcmVQYWdlcyAmJiByZXNwb25zZVJhbmdlICYmIHJlc3BvbnNlUmFuZ2UudG90YWwpIHtcbiAgICAgICAgLy8gRGV0ZXJtaW5lIG5leHQgcGFnZSBzaXplIGJhc2VkIG9uIHVwZGF0ZWQgdG90YWxMb2FkZWRcbiAgICAgICAgY29uc3QgbmV4dFBhZ2VTaXplID1cbiAgICAgICAgICB0b3RhbExvYWRlZCA8IHRocmVzaG9sZCA/IGluaXRpYWxQYWdlU2l6ZSA6IHN0YW5kYXJkUGFnZVNpemU7XG4gICAgICAgIC8vIFVzZSBjdXJyZW50IHJlc3BvbnNlJ3MgdG90YWwgZm9yIGNsYW1waW5nIChoYW5kbGVzIGR5bmFtaWMgdG90YWwgY2hhbmdlcylcbiAgICAgICAgY29uc3QgZW5kSW5kZXggPSBNYXRoLm1pbihcbiAgICAgICAgICByZXNwb25zZVJhbmdlLnRvdGFsIC0gMSxcbiAgICAgICAgICBjdXJyZW50SW5kZXggKyBuZXh0UGFnZVNpemUgLSAxLFxuICAgICAgICApO1xuXG4gICAgICAgIGhlYWRlcnMuc2V0KCdSYW5nZScsIGBpdGVtcz0ke2N1cnJlbnRJbmRleH0tJHtlbmRJbmRleH1gKTtcblxuICAgICAgICAvLyBJbml0aWF0ZSBuZXh0IHBhZ2UgcmVxdWVzdCwgYnV0IGRvbid0IHdhaXQgb24gaXQgeWV0XG4gICAgICAgIG5leHRQYWdlID0gdGhpcy5tYWtlUmVxdWVzdDxEPih1cmwsICdHRVQnLCBib2R5LCBoZWFkZXJzLCBhdXRoKTtcbiAgICAgIH1cblxuICAgICAgLy8gQ2FsbCB0aGUgY2FsbGJhY2sgd2l0aCB0aGUgcGFnZSBkYXRhXG4gICAgICBvblBhZ2VSZXRyaWV2ZWQocmVzcG9uc2UpO1xuXG4gICAgICBpZiAobmV4dFBhZ2UpIHtcbiAgICAgICAgcmVzcG9uc2UgPSBhd2FpdCBuZXh0UGFnZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuXG4gICAgICAvLyBJZiB3ZSByZWFjaGVkIHRoaXMgcG9pbnQsIHdlIHN0aWxsIGhhdmUgaXRlbXMgdG8gYWNxdWlyZVxuICAgIH0gd2hpbGUgKHRydWUpO1xuICB9XG5cbiAgLyoqXG4gICAqIE1ha2VzIGEgc2VydmljZSByZXF1ZXN0IHdpdGggYWxsIG5lZWRlZCBhdXRoZW50aWNhdGlvbiBhbmQgcmV0cnkgbG9naWMuIENvbnZlcnRzIGVycm9yIHJlc3BvbnNlIHRvIGV4Y2VwdGlvbi5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHVybCBUaGUgdXJsIHRvIG1ha2UgcmVxdWVzdCB0by4gQ291bGQgYmUgYWJzb2x1dGUgb3IgcmVsYXRpdmUgdG8gdGhlIHNlcnZpY2UgYmFzZSB1cmkuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBtZXRob2QgVGhlIEhUVFAgbWV0aG9kLlxuICAgKiBAcGFyYW0ge3N0cmluZyB8IEZvcm1EYXRhIHwgQmxvYn0gYm9keSBUaGUgYm9keSB0byBzZW5kIGluIHRoZSByZXF1ZXN0LlxuICAgKiBAcGFyYW0ge0hlYWRlcnN9IGN1c3RvbUhlYWRlcnMgVGhlIGN1c3RvbSBoZWFkZXJzIHRvIGF0dGFjaCB0byByZXF1ZXN0LlxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IGF1dGggVGhlIHZhbHVlIGluZGljYXRpbmcgd2hldGhlciB0aGUgcmVxdWVzdCByZXF1aXJlcyBhdXRoZW50aWNhdGlvbi4gSWYgdHJ1ZSwgdGhlIGNyZWRlbnRpYWxzIHdpbGwgYmUgcmVxdWVzdGVkIGZyb20gdGhlIGNvbmZpZ3VyYXRpb24ge0BzZWUgQ29uZmlnI2NyZWRlbnRpYWxzIH0gYW5kIEF1dGhvcml6YXRpb24gaGVhZGVyIHdpbGwgYmUgYXR0YWNoZWQuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPFNlcnZpY2VSZXNwb25zZTxEPj59IFRoZSBzZXJ2aWNlIHJlc3BvbnNlLlxuICAgKiBAdGhyb3dzIHtTZXJ2aWNlRXJyb3J9IGluIGNhc2Ugb2YgdGhlIGVycm9yIHJlc3BvbnNlIGZyb20gdGhlIHNlcnZpY2UuXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgcmVxdWVzdChcbiAgICB1cmw6IHN0cmluZyxcbiAgICBtZXRob2Q6ICdHRVQnIHwgJ1BVVCcgfCAnUE9TVCcgfCAnUEFUQ0gnIHwgJ0RFTEVURScgPSAnR0VUJyxcbiAgICBib2R5Pzogc3RyaW5nIHwgRm9ybURhdGEgfCBCbG9iLFxuICAgIGN1c3RvbUhlYWRlcnM/OiBIZWFkZXJzLFxuICAgIGF1dGg6IGJvb2xlYW4gPSB0cnVlLFxuICApOiBQcm9taXNlPFNlcnZpY2VSZXNwb25zZTx2b2lkPj4ge1xuICAgIC8vIHRoaXMgbWV0aG9kIHN1cHBvcnRzIDMgY2FzZXM6IGFic29sdXRlIHVybCwgYWJzb2x1dGUgcGF0aCwgcmVsYXRpdmUgcGF0aFxuICAgIGNvbnN0IHJlcXVlc3RVcmwgPSB1cmwuc3RhcnRzV2l0aCgnaHR0cCcpXG4gICAgICA/IHVybFxuICAgICAgOiB1cmwuc3RhcnRzV2l0aCgnLycpXG4gICAgICAgID8gZXh0cmFjdEVuZHBvaW50KHRoaXMuY29uZmlnLnNlcnZpY2VVcmkpICsgdXJsXG4gICAgICAgIDogdGhpcy5jb25maWcuc2VydmljZVVyaSArIHVybDtcblxuICAgIGNvbnN0IGhlYWRlcnMgPSBuZXcgSGVhZGVycygpO1xuICAgIGNvbnN0IGNvbnRlbnRUeXBlID0gY3VzdG9tSGVhZGVyc1xuICAgICAgPyBjdXN0b21IZWFkZXJzLmdldCgnQ29udGVudC1UeXBlJylcbiAgICAgIDogdW5kZWZpbmVkO1xuICAgIGlmICghY29udGVudFR5cGUgJiYgYm9keSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBoZWFkZXJzLnNldCgnQ29udGVudC1UeXBlJywgJ2FwcGxpY2F0aW9uL2pzb24nKTtcbiAgICB9XG5cbiAgICBpZiAoY3VzdG9tSGVhZGVycykge1xuICAgICAgY3VzdG9tSGVhZGVycy5mb3JFYWNoKCh2YWx1ZTogc3RyaW5nLCBrZXk6IHN0cmluZykgPT4ge1xuICAgICAgICBoZWFkZXJzLmFwcGVuZChrZXksIHZhbHVlKTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzLmZldGNoV2l0aFJldHJ5KFxuICAgICAgcmVxdWVzdFVybCxcbiAgICAgIHtcbiAgICAgICAgYm9keSxcbiAgICAgICAgaGVhZGVycyxcbiAgICAgICAgbWV0aG9kLFxuICAgICAgICByZWRpcmVjdDogJ2ZvbGxvdycsXG4gICAgICB9LFxuICAgICAgYXV0aCxcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIEhvdyBtYW55IHRpbWVzIGEgZmFpbGVkIHJlcXVlc3Qgc2hvdWxkIGJlIHJldHJpZWQgYmVmb3JlIGdpdmluZyB1cC5cbiAgICogdGhlIGRlZmF1bHRSZXRyeUNvdW50IGNhbiBiZSBvdmVycmlkZGVuIGJ5IHNlcnZpY2UgY2xhc3Nlcy5cbiAgICpcbiAgICogQGFwaSBwcml2YXRlXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwdWJsaWMgbWF4UmV0cmllcygpOiBudW1iZXIge1xuICAgIGlmICh0aGlzLmNvbmZpZy5tYXhSZXRyaWVzICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybiB0aGlzLmNvbmZpZy5tYXhSZXRyaWVzO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gdGhpcy5kZWZhdWx0UmV0cnlDb3VudDtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogRmlyc3QgcmV0cnkgZ29lcyBpbW1lZGlhdGVseSAoMG1zIGRlbGF5KSB0aGVuIGV4cG9uZW50aWFsIGdyb3d0aCB3aXRoIDEwMG1zIGFzIGEgYmFzZS5cbiAgICogQGFwaSBwcml2YXRlXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwdWJsaWMgY2FsY3VsYXRlUmV0cnlEZWxheShyZXRyeUNvdW50OiBudW1iZXIpOiBudW1iZXIge1xuICAgIGlmIChyZXRyeUNvdW50ID09PSAwKSB7XG4gICAgICByZXR1cm4gMDtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgYmFzZSA9IDEwMDtcbiAgICAgIHJldHVybiBNYXRoLnJhbmRvbSgpICogKE1hdGgucG93KDIsIHJldHJ5Q291bnQgLSAxKSAqIGJhc2UpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAYXBpIHByaXZhdGVcbiAgICogQHByaXZhdGVcbiAgICovXG4gIHByaXZhdGUgcmV0cnlhYmxlRXJyb3IoZXJyb3I6IFNlcnZpY2VFcnJvcikge1xuICAgIGlmIChcbiAgICAgIHRoaXMudGltZW91dEVycm9yKGVycm9yKSB8fFxuICAgICAgdGhpcy5uZXR3b3JraW5nRXJyb3IoZXJyb3IpIHx8XG4gICAgICB0aGlzLmV4cGlyZWRDcmVkZW50aWFsc0Vycm9yKGVycm9yKSB8fFxuICAgICAgdGhpcy50aHJvdHRsZWRFcnJvcihlcnJvcikgfHxcbiAgICAgIGVycm9yLnJlc3BvbnNlLnN0YXR1cyA+PSA1MDBcbiAgICApIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvKipcbiAgICogQGFwaSBwcml2YXRlXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwcml2YXRlIG5ldHdvcmtpbmdFcnJvcihlcnJvcjogU2VydmljZUVycm9yKSB7XG4gICAgcmV0dXJuIGVycm9yLmVycm9yQ29kZSA9PT0gJ05ldHdvcmtpbmdFcnJvcic7XG4gIH1cblxuICAvKipcbiAgICogQGFwaSBwcml2YXRlXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwcml2YXRlIHRpbWVvdXRFcnJvcihlcnJvcjogU2VydmljZUVycm9yKSB7XG4gICAgcmV0dXJuIGVycm9yLmVycm9yQ29kZSA9PT0gJ1RpbWVvdXRFcnJvcic7XG4gIH1cblxuICAvKipcbiAgICogQGFwaSBwcml2YXRlXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwcml2YXRlIGV4cGlyZWRDcmVkZW50aWFsc0Vycm9yKGVycm9yOiBTZXJ2aWNlRXJyb3IpIHtcbiAgICBpZiAoZXJyb3IucmVzcG9uc2Uuc3RhdHVzID09PSA0MDEpIHtcbiAgICAgIGNvbnN0IGNyZWRlbnRpYWxzID0gdGhpcy5jb25maWcuY3JlZGVudGlhbHM7XG4gICAgICBpZiAoXG4gICAgICAgIGNyZWRlbnRpYWxzICYmXG4gICAgICAgIHR5cGVvZiAoY3JlZGVudGlhbHMgYXMgQ3JlZGVudGlhbHMpLmV4cGlyZWQgPT09ICdib29sZWFuJ1xuICAgICAgKSB7XG4gICAgICAgIChjcmVkZW50aWFscyBhcyBDcmVkZW50aWFscykuZXhwaXJlZCA9IHRydWU7XG4gICAgICB9XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIEBhcGkgcHJpdmF0ZVxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgcHJpdmF0ZSB0aHJvdHRsZWRFcnJvcihlcnJvcjogU2VydmljZUVycm9yKSB7XG4gICAgLy8gQVdTIEFQSSBHYXRld2F5IHJldHVybnMgNDI5IGluIGNhc2Ugb2YgdGhyb3R0bGluZyBlcnJvcnNcbiAgICBpZiAoZXJyb3IucmVzcG9uc2Uuc3RhdHVzID09PSA0MjkpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIE1ha2VzIGEgc2VydmljZSBjYWxsIGFuZCB0YWtlcyBjYXJlIGFib3V0IHJldHJ5IGxvZ2ljIChyZS1hdXRoZW50aWNhdGlvbiBpZiBuZWVkZWQpLlxuICAgKiBOb3RlIHRoZSA8dm9pZD4gYXMgYSBnZW5lcmljIHBhcmFtZXRlci4gVGhpcyBtZXRob2QgZG9lcyBub3QgcmVhZCB0aGUgcmVzcG9uc2UgYm9keS4gVGhlIFNlcnZpY2VSZXNwb25zZSByZXR1cm4gdmFsdWUgd2lsbCBiZSBjYXNlZCB0byBuZWVkZWQgdHlwZSBvbiB1cHBlciBsZXZlbHMgb2YgdGhlIGNvZGUuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgVGhlIHVybCB0byBtYWtlIHJlcXVlc3QgdG8uIENvdWxkIGJlIGFic29sdXRlIG9yIHJlbGF0aXZlIHRvIHRoZSBzZXJ2aWNlIGJhc2UgdXJpLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyYW1zIFRoZSBmZXRjaCBwYXJhbWV0ZXJzLlxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IGF1dGggVGhlIHZhbHVlIGluZGljYXRpbmcgd2hldGhlciB0aGUgcmVxdWVzdCByZXF1aXJlcyBhdXRoZW50aWNhdGlvbi4gSWYgdHJ1ZSwgdGhlIGNyZWRlbnRpYWxzIHdpbGwgYmUgcmVxdWVzdGVkIGZyb20gdGhlIGNvbmZpZ3VyYXRpb24ge0BzZWUgQ29uZmlnI2NyZWRlbnRpYWxzIH0gYW5kIEF1dGhvcml6YXRpb24gaGVhZGVyIHdpbGwgYmUgYXR0YWNoZWQuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPFNlcnZpY2VSZXNwb25zZTx2b2lkPj59IFRoZSBzZXJ2aWNlIHJlc3BvbnNlLlxuICAgKiBAdGhyb3dzIHtTZXJ2aWNlRXJyb3J9IGluIGNhc2Ugb2YgdGhlIGVycm9yIHJlc3BvbnNlIGZyb20gdGhlIHNlcnZpY2UuXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGZldGNoV2l0aFJldHJ5KFxuICAgIHVybDogc3RyaW5nLFxuICAgIHBhcmFtczogYW55LFxuICAgIGF1dGg6IGJvb2xlYW4gPSB0cnVlLFxuICApOiBQcm9taXNlPFNlcnZpY2VSZXNwb25zZTx2b2lkPj4ge1xuICAgIGNvbnN0IGxvZ2dlciA9IHRoaXMuY29uZmlnLmxvZ2dlcjtcbiAgICBjb25zdCByZXN1bHQ6IFNlcnZpY2VSZXNwb25zZTx2b2lkPiA9IG5ldyBTZXJ2aWNlUmVzcG9uc2U8dm9pZD4oXG4gICAgICB0aGlzLFxuICAgICAgbmV3IFJlc3BvbnNlKCksXG4gICAgICB2b2lkIDAsXG4gICAgKTtcbiAgICBkbyB7XG4gICAgICBjb25zdCBjcmVkZW50aWFscyA9IHRoaXMuY29uZmlnLmNyZWRlbnRpYWxzO1xuICAgICAgaWYgKGF1dGggJiYgY3JlZGVudGlhbHMpIHtcbiAgICAgICAgaWYgKHR5cGVvZiAoY3JlZGVudGlhbHMgYXMgU2VydmljZUNyZWRlbnRpYWxzKS5nZXQgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXdhaXQgKGNyZWRlbnRpYWxzIGFzIFNlcnZpY2VDcmVkZW50aWFscykuZ2V0KCk7XG4gICAgICAgICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgICAgICAgIGlmIChsb2dnZXIgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICB0aGlzLmxvZyhgW1RJRF0gRmFpbGVkIHRvIGFjcXVpcmUgdG9rZW5zOiAke2Vyci5tZXNzYWdlfWApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGNyZWRlbnRpYWxzLnRva2VuKSB7XG4gICAgICAgICAgcGFyYW1zLmhlYWRlcnMuc2V0KCdBdXRob3JpemF0aW9uJywgJ0JlYXJlciAnICsgY3JlZGVudGlhbHMudG9rZW4pO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHN0YXJ0VGltZSA9IERhdGUubm93KCk7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuZmV0Y2godXJsLCBwYXJhbXMpO1xuICAgICAgaWYgKGxvZ2dlciAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGNvbnN0IGRlbHRhID0gKERhdGUubm93KCkgLSBzdGFydFRpbWUpIC8gMTAwMDtcbiAgICAgICAgY29uc3QgaXNvRGF0ZSA9IG5ldyBEYXRlKHN0YXJ0VGltZSkud