UNPKG

testcafe-browser-provider-browserstack

Version:
201 lines 27.1 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const util_1 = require("util"); const base_1 = __importDefault(require("./base")); const request_api_1 = __importDefault(require("../utils/request-api")); const create_browserstack_status_1 = __importDefault(require("../utils/create-browserstack-status")); const get_api_polling_interval_1 = __importDefault(require("../utils/get-api-polling-interval")); const ERROR_MESSAGES = __importStar(require("../templates/error-messages")); const sharp_1 = __importDefault(require("sharp")); const API_POLLING_INTERVAL = (0, get_api_polling_interval_1.default)(); const BROWSERSTACK_API_PATHS = { browserList: { url: 'https://api.browserstack.com/automate/browsers.json' }, newSession: { url: 'https://hub-cloud.browserstack.com/wd/hub/session', method: 'POST' }, openUrl: id => ({ url: `https://hub-cloud.browserstack.com/wd/hub/session/${id}/url`, method: 'POST' }), getWindowSize: id => ({ url: `https://hub-cloud.browserstack.com/wd/hub/session/${id}/window/current/size` }), setWindowSize: id => ({ url: `https://hub-cloud.browserstack.com/wd/hub/session/${id}/window/current/size`, method: 'POST' }), maximizeWindow: id => ({ url: `https://hub-cloud.browserstack.com/wd/hub/session/${id}/window/current/maximize`, method: 'POST' }), getUrl: id => ({ url: `https://hub-cloud.browserstack.com/wd/hub/session/${id}/url` }), deleteSession: id => ({ url: `https://hub-cloud.browserstack.com/wd/hub/session/${id}`, method: 'DELETE' }), screenshot: id => ({ url: `https://hub-cloud.browserstack.com/wd/hub/session/${id}/screenshot` }), getStatus: id => ({ url: `https://api.browserstack.com/automate/sessions/${id}.json` }), setStatus: id => ({ url: `https://api.browserstack.com/automate/sessions/${id}.json`, method: 'PUT' }) }; function requestApi(path, params) { return (0, request_api_1.default)(path, params) .then(response => { if (response.status) { throw new Error(ERROR_MESSAGES.REMOTE_API_REQUEST_FAILED({ status: response.status, apiResponse: response.value && response.value.message || (0, util_1.inspect)(response) })); } return response; }); } function getCorrectedSize(currentClientAreaSize, currentWindowSize, requestedSize) { var horizontalChrome = currentWindowSize.width - currentClientAreaSize.width; var verticalChrome = currentWindowSize.height - currentClientAreaSize.height; return { width: requestedSize.width + horizontalChrome, height: requestedSize.height + verticalChrome }; } class AutomateBackend extends base_1.default { constructor(...args) { super(...args); this.sessions = {}; } static _ensureSessionId(sessionInfo) { const sessionData = sessionInfo.value || {}; const sessionCapabilities = sessionData.capabilities || {}; sessionInfo.sessionId = sessionInfo.sessionId || sessionData.sessionId || sessionData['webdriver.remote.sessionid'] || sessionCapabilities['webdriver.remote.sessionid']; if (!sessionInfo.sessionId) { throw new Error(ERROR_MESSAGES.SESSION_ID_NOT_FOUND({ sessionInfoDump: (0, util_1.inspect)(sessionInfo) })); } } async _requestSessionInfo(id) { var sessionInfo = await (0, request_api_1.default)(BROWSERSTACK_API_PATHS.getStatus(this.sessions[id].sessionId)); return sessionInfo['automation_session']; } async _requestCurrentWindowSize(id) { var currentWindowSizeData = await requestApi(BROWSERSTACK_API_PATHS.getWindowSize(this.sessions[id].sessionId)); return { width: currentWindowSizeData.value.width, height: currentWindowSizeData.value.height }; } async getBrowsersList() { var platformsInfo = await (0, request_api_1.default)(BROWSERSTACK_API_PATHS.browserList); return platformsInfo.reverse(); } getSessionUrl(id) { return this.sessions[id] ? this.sessions[id].sessionUrl : ''; } async getOSInfo(id) { if (this.sessions[id]) return this.sessions[id].osInfo; return null; } async openBrowser(id, pageUrl, capabilities) { var { localIdentifier, local } = capabilities, restCapabilities = __rest(capabilities, ["localIdentifier", "local"]); capabilities = Object.assign({ 'browserstack.localIdentifier': localIdentifier, 'browserstack.local': local }, restCapabilities); this.sessions[id] = await requestApi(BROWSERSTACK_API_PATHS.newSession, { body: { desiredCapabilities: capabilities }, }); AutomateBackend._ensureSessionId(this.sessions[id]); const sessionInfo = await this._requestSessionInfo(id); const osInfo = { name: sessionInfo['os'] || '', version: sessionInfo['os_version'] || '' }; this.sessions[id].sessionUrl = sessionInfo['browser_url']; this.sessions[id].osInfo = osInfo; var sessionId = this.sessions[id].sessionId; this.sessions[id].interval = setInterval(() => requestApi(BROWSERSTACK_API_PATHS.getUrl(sessionId)), API_POLLING_INTERVAL); await requestApi(BROWSERSTACK_API_PATHS.openUrl(sessionId), { body: { url: pageUrl } }); } async closeBrowser(id) { const session = this.sessions[id]; if (!session) return; clearInterval(session.interval); delete this.sessions[id]; // Delete session whose sessionId is created if (session.sessionId && session.sessionId !== '') await requestApi(BROWSERSTACK_API_PATHS.deleteSession(session.sessionId)); } async takeScreenshot(id, screenshotPath) { var base64Data = await requestApi(BROWSERSTACK_API_PATHS.screenshot(this.sessions[id].sessionId)); var buffer = Buffer.from(base64Data.value, 'base64'); await (0, sharp_1.default)(buffer).toFile(screenshotPath); } async resizeWindow(id, width, height, currentWidth, currentHeight) { var sessionId = this.sessions[id].sessionId; var currentWindowSize = await this._requestCurrentWindowSize(id); var currentClientAreaSize = { width: currentWidth, height: currentHeight }; var requestedSize = { width, height }; var correctedSize = getCorrectedSize(currentClientAreaSize, currentWindowSize, requestedSize); await requestApi(BROWSERSTACK_API_PATHS.setWindowSize(sessionId), { body: correctedSize }); } async maximizeWindow(id) { await requestApi(BROWSERSTACK_API_PATHS.maximizeWindow(this.sessions[id].sessionId)); } async reportJobResult(id, jobResult, jobData, possibleResults) { var sessionId = this.sessions[id].sessionId; var jobStatus = (0, create_browserstack_status_1.default)(jobResult, jobData, possibleResults); await (0, request_api_1.default)(BROWSERSTACK_API_PATHS.setStatus(sessionId), { body: jobStatus }); } } exports.default = AutomateBackend; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0b21hdGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYmFja2VuZHMvYXV0b21hdGUuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsK0JBQStCO0FBQy9CLGtEQUFpQztBQUNqQyx1RUFBa0Q7QUFDbEQscUdBQTJFO0FBQzNFLGlHQUFzRTtBQUN0RSw0RUFBOEQ7QUFDOUQsa0RBQTBCO0FBRTFCLE1BQU0sb0JBQW9CLEdBQUcsSUFBQSxrQ0FBcUIsR0FBRSxDQUFDO0FBRXJELE1BQU0sc0JBQXNCLEdBQUc7SUFDM0IsV0FBVyxFQUFFO1FBQ1QsR0FBRyxFQUFFLHFEQUFxRDtLQUM3RDtJQUVELFVBQVUsRUFBRTtRQUNSLEdBQUcsRUFBSyxtREFBbUQ7UUFDM0QsTUFBTSxFQUFFLE1BQU07S0FDakI7SUFFRCxPQUFPLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ1osR0FBRyxFQUFLLHFEQUFxRCxFQUFFLE1BQU07UUFDckUsTUFBTSxFQUFFLE1BQU07S0FDakIsQ0FBQztJQUVGLGFBQWEsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDbEIsR0FBRyxFQUFFLHFEQUFxRCxFQUFFLHNCQUFzQjtLQUNyRixDQUFDO0lBRUYsYUFBYSxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUNsQixHQUFHLEVBQUsscURBQXFELEVBQUUsc0JBQXNCO1FBQ3JGLE1BQU0sRUFBRSxNQUFNO0tBQ2pCLENBQUM7SUFFRixjQUFjLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ25CLEdBQUcsRUFBSyxxREFBcUQsRUFBRSwwQkFBMEI7UUFDekYsTUFBTSxFQUFFLE1BQU07S0FDakIsQ0FBQztJQUVGLE1BQU0sRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDWCxHQUFHLEVBQUUscURBQXFELEVBQUUsTUFBTTtL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LHFCQUFxQixHQUFHLEVBQUUsS0FBSyxFQUFFLFlBQVksRUFBRSxNQUFNLEVBQUUsYUFBYSxFQUFFLENBQUM7UUFDM0UsSUFBSSxhQUFhLEdBQVcsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLENBQUM7UUFDOUMsSUFBSSxhQUFhLEdBQVcsZ0JBQWdCLENBQUMscUJBQXFCLEVBQUUsaUJBQWlCLEVBQUUsYUFBYSxDQUFDLENBQUM7UUFFdEcsTUFBTSxVQUFVLENBQUMsc0JBQXNCLENBQUMsYUFBYSxDQUFDLFNBQVMsQ0FBQyxFQUFFLEVBQUUsSUFBSSxFQUFFLGFBQWEsRUFBRSxDQUFDLENBQUM7SUFDL0YsQ0FBQztJQUVELEtBQUssQ0FBQyxjQUFjLENBQUUsRUFBRTtRQUNwQixNQUFNLFVBQVUsQ0FBQyxzQkFBc0IsQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDO0lBQ3pGLENBQUM7SUFFRCxLQUFLLENBQUMsZUFBZSxDQUFFLEVBQUUsRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLGVBQWU7UUFDMUQsSUFBSSxTQUFTLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsQ0FBQyxTQUFTLENBQUM7UUFDNUMsSUFBSSxTQUFTLEdBQUcsSUFBQSxvQ0FBd0IsRUFBQyxTQUFTLEVBQUUsT0FBTyxFQUFFLGVBQWUsQ0FBQyxDQUFDO1FBRTlFLE1BQU0sSUFBQSxxQkFBYyxFQUFDLHNCQUFzQixDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUMsRUFBRSxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsQ0FBQyxDQUFDO0lBQzNGLENBQUM7Q0FDSjtBQWhJRCxrQ0FnSUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBpbnNwZWN0IH0gZnJvbSAndXRpbCc7XG5pbXBvcnQgQmFzZUJhY2tlbmQgZnJvbSAnLi9iYXNlJztcbmltcG9ydCByZXF1ZXN0QXBpQmFzZSBmcm9tICcuLi91dGlscy9yZXF1ZXN0LWFwaSc7XG5pbXBvcnQgY3JlYXRlQnJvd3NlcnN0YWNrU3RhdHVzIGZyb20gJy4uL3V0aWxzL2NyZWF0ZS1icm93c2Vyc3RhY2stc3RhdHVzJztcbmltcG9ydCBnZXRBUElQb2xsaW5nSW50ZXJ2YWwgZnJvbSAnLi4vdXRpbHMvZ2V0LWFwaS1wb2xsaW5nLWludGVydmFsJztcbmltcG9ydCAqIGFzIEVSUk9SX01FU1NBR0VTIGZyb20gJy4uL3RlbXBsYXRlcy9lcnJvci1tZXNzYWdlcyc7XG5pbXBvcnQgc2hhcnAgZnJvbSAnc2hhcnAnO1xuXG5jb25zdCBBUElfUE9MTElOR19JTlRFUlZBTCA9IGdldEFQSVBvbGxpbmdJbnRlcnZhbCgpO1xuXG5jb25zdCBCUk9XU0VSU1RBQ0tfQVBJX1BBVEhTID0ge1xuICAgIGJyb3dzZXJMaXN0OiB7XG4gICAgICAgIHVybDogJ2h0dHBzOi8vYXBpLmJyb3dzZXJzdGFjay5jb20vYXV0b21hdGUvYnJvd3NlcnMuanNvbidcbiAgICB9LFxuXG4gICAgbmV3U2Vzc2lvbjoge1xuICAgICAgICB1cmw6ICAgICdodHRwczovL2h1Yi1jbG91ZC5icm93c2Vyc3RhY2suY29tL3dkL2h1Yi9zZXNzaW9uJyxcbiAgICAgICAgbWV0aG9kOiAnUE9TVCdcbiAgICB9LFxuXG4gICAgb3BlblVybDogaWQgPT4gKHtcbiAgICAgICAgdXJsOiAgICBgaHR0cHM6Ly9odWItY2xvdWQuYnJvd3NlcnN0YWNrLmNvbS93ZC9odWIvc2Vzc2lvbi8ke2lkfS91cmxgLFxuICAgICAgICBtZXRob2Q6ICdQT1NUJ1xuICAgIH0pLFxuXG4gICAgZ2V0V2luZG93U2l6ZTogaWQgPT4gKHtcbiAgICAgICAgdXJsOiBgaHR0cHM6Ly9odWItY2xvdWQuYnJvd3NlcnN0YWNrLmNvbS93ZC9odWIvc2Vzc2lvbi8ke2lkfS93aW5kb3cvY3VycmVudC9zaXplYFxuICAgIH0pLFxuXG4gICAgc2V0V2luZG93U2l6ZTogaWQgPT4gKHtcbiAgICAgICAgdXJsOiAgICBgaHR0cHM6Ly9odWItY2xvdWQuYnJvd3NlcnN0YWNrLmNvbS93ZC9odWIvc2Vzc2lvbi8ke2lkfS93aW5kb3cvY3VycmVudC9zaXplYCxcbiAgICAgICAgbWV0aG9kOiAnUE9TVCdcbiAgICB9KSxcblxuICAgIG1heGltaXplV2luZG93OiBpZCA9PiAoe1xuICAgICAgICB1cmw6ICAgIGBodHRwczovL2h1Yi1jbG91ZC5icm93c2Vyc3RhY2suY29tL3dkL2h1Yi9zZXNzaW9uLyR7aWR9L3dpbmRvdy9jdXJyZW50L21heGltaXplYCxcbiAgICAgICAgbWV0aG9kOiAnUE9TVCdcbiAgICB9KSxcblxuICAgIGdldFVybDogaWQgPT4gKHtcbiAgICAgICAgdXJsOiBgaHR0cHM6Ly9odWItY2xvdWQuYnJvd3NlcnN0YWNrLmNvbS93ZC9odWIvc2Vzc2lvbi8ke2lkfS91cmxgXG4gICAgfSksXG5cbiAgICBkZWxldGVTZXNzaW9uOiBpZCA9PiAoe1xuICAgICAgICB1cmw6ICAgIGBodHRwczovL2h1Yi1jbG91ZC5icm93c2Vyc3RhY2suY29tL3dkL2h1Yi9zZXNzaW9uLyR7aWR9YCxcbiAgICAgICAgbWV0aG9kOiAnREVMRVRFJ1xuICAgIH0pLFxuXG4gICAgc2NyZWVuc2hvdDogaWQgPT4gKHtcbiAgICAgICAgdXJsOiBgaHR0cHM6Ly9odWItY2xvdWQuYnJvd3NlcnN0YWNrLmNvbS93ZC9odWIvc2Vzc2lvbi8ke2lkfS9zY3JlZW5zaG90YFxuICAgIH0pLFxuXG4gICAgZ2V0U3RhdHVzOiBpZCA9PiAoe1xuICAgICAgICB1cmw6IGBodHRwczovL2FwaS5icm93c2Vyc3RhY2suY29tL2F1dG9tYXRlL3Nlc3Npb25zLyR7aWR9Lmpzb25gXG4gICAgfSksXG5cbiAgICBzZXRTdGF0dXM6IGlkID0+ICh7XG4gICAgICAgIHVybDogICAgYGh0dHBzOi8vYXBpLmJyb3dzZXJzdGFjay5jb20vYXV0b21hdGUvc2Vzc2lvbnMvJHtpZH0uanNvbmAsXG4gICAgICAgIG1ldGhvZDogJ1BVVCdcbiAgICB9KVxufTtcblxuXG5mdW5jdGlvbiByZXF1ZXN0QXBpIChwYXRoLCBwYXJhbXMpIHtcbiAgICByZXR1cm4gcmVxdWVzdEFwaUJhc2UocGF0aCwgcGFyYW1zKVxuICAgICAgICAudGhlbihyZXNwb25zZSA9PiB7XG4gICAgICAgICAgICBpZiAocmVzcG9uc2Uuc3RhdHVzKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKEVSUk9SX01FU1NBR0VTLlJFTU9URV9BUElfUkVRVUVTVF9GQUlMRUQoe1xuICAgICAgICAgICAgICAgICAgICBzdGF0dXM6ICAgICAgcmVzcG9uc2Uuc3RhdHVzLFxuICAgICAgICAgICAgICAgICAgICBhcGlSZXNwb25zZTogcmVzcG9uc2UudmFsdWUgJiYgcmVzcG9uc2UudmFsdWUubWVzc2FnZSB8fCBpbnNwZWN0KHJlc3BvbnNlKVxuICAgICAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHJlc3BvbnNlO1xuICAgICAgICB9KTtcbn1cblxuZnVuY3Rpb24gZ2V0Q29ycmVjdGVkU2l6ZSAoY3VycmVudENsaWVudEFyZWFTaXplLCBjdXJyZW50V2luZG93U2l6ZSwgcmVxdWVzdGVkU2l6ZSkge1xuICAgIHZhciBob3Jpem9udGFsQ2hyb21lID0gY3VycmVudFdpbmRvd1NpemUud2lkdGggLSBjdXJyZW50Q2xpZW50QXJlYVNpemUud2lkdGg7XG4gICAgdmFyIHZlcnRpY2FsQ2hyb21lICAgPSBjdXJyZW50V2luZG93U2l6ZS5oZWlnaHQgLSBjdXJyZW50Q2xpZW50QXJlYVNpemUuaGVpZ2h0O1xuXG4gICAgcmV0dXJuIHtcbiAgICAgICAgd2lkdGg6ICByZXF1ZXN0ZWRTaXplLndpZHRoICsgaG9yaXpvbnRhbENocm9tZSxcbiAgICAgICAgaGVpZ2h0OiByZXF1ZXN0ZWRTaXplLmhlaWdodCArIHZlcnRpY2FsQ2hyb21lXG4gICAgfTtcbn1cblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQXV0b21hdGVCYWNrZW5kIGV4dGVuZHMgQmFzZUJhY2tlbmQge1xuICAgIGNvbnN0cnVjdG9yICguLi5hcmdzKSB7XG4gICAgICAgIHN1cGVyKC4uLmFyZ3MpO1xuXG4gICAgICAgIHRoaXMuc2Vzc2lvbnMgPSB7fTtcbiAgICB9XG5cbiAgICBzdGF0aWMgX2Vuc3VyZVNlc3Npb25JZCAoc2Vzc2lvbkluZm8pIHtcbiAgICAgICAgY29uc3Qgc2Vzc2lvbkRhdGEgICAgICAgICA9IHNlc3Npb25JbmZvLnZhbHVlIHx8IHt9O1xuICAgICAgICBjb25zdCBzZXNzaW9uQ2FwYWJpbGl0aWVzID0gc2Vzc2lvbkRhdGEuY2FwYWJpbGl0aWVzIHx8IHt9O1xuXG4gICAgICAgIHNlc3Npb25JbmZvLnNlc3Npb25JZCA9IHNlc3Npb25JbmZvLnNlc3Npb25JZCB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXNzaW9uRGF0YS5zZXNzaW9uSWQgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2Vzc2lvbkRhdGFbJ3dlYmRyaXZlci5yZW1vdGUuc2Vzc2lvbmlkJ10gfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2Vzc2lvbkNhcGFiaWxpdGllc1snd2ViZHJpdmVyLnJlbW90ZS5zZXNzaW9uaWQnXTtcblxuICAgICAgICBpZiAoIXNlc3Npb25JbmZvLnNlc3Npb25JZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKEVSUk9SX01FU1NBR0VTLlNFU1NJT05fSURfTk9UX0ZPVU5EKHtcbiAgICAgICAgICAgICAgICBzZXNzaW9uSW5mb0R1bXA6IGluc3BlY3Qoc2Vzc2lvbkluZm8pXG4gICAgICAgICAgICB9KSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBhc3luYyBfcmVxdWVzdFNlc3Npb25JbmZvIChpZCkge1xuICAgICAgICB2YXIgc2Vzc2lvbkluZm8gPSBhd2FpdCByZXF1ZXN0QXBpQmFzZShCUk9XU0VSU1RBQ0tfQVBJX1BBVEhTLmdldFN0YXR1cyh0aGlzLnNlc3Npb25zW2lkXS5zZXNzaW9uSWQpKTtcblxuICAgICAgICByZXR1cm4gc2Vzc2lvbkluZm9bJ2F1dG9tYXRpb25fc2Vzc2lvbiddO1xuICAgIH1cblxuICAgIGFzeW5jIF9yZXF1ZXN0Q3VycmVudFdpbmRvd1NpemUgKGlkKSB7XG4gICAgICAgIHZhciBjdXJyZW50V2luZG93U2l6ZURhdGEgPSBhd2FpdCByZXF1ZXN0QXBpKEJST1dTRVJTVEFDS19BUElfUEFUSFMuZ2V0V2luZG93U2l6ZSh0aGlzLnNlc3Npb25zW2lkXS5zZXNzaW9uSWQpKTtcblxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgd2lkdGg6ICBjdXJyZW50V2luZG93U2l6ZURhdGEudmFsdWUud2lkdGgsXG4gICAgICAgICAgICBoZWlnaHQ6IGN1cnJlbnRXaW5kb3dTaXplRGF0YS52YWx1ZS5oZWlnaHRcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBhc3luYyBnZXRCcm93c2Vyc0xpc3QgKCkge1xuICAgICAgICB2YXIgcGxhdGZvcm1zSW5mbyA9IGF3YWl0IHJlcXVlc3RBcGlCYXNlKEJST1dTRVJTVEFDS19BUElfUEFUSFMuYnJvd3Nlckxpc3QpO1xuXG4gICAgICAgIHJldHVybiBwbGF0Zm9ybXNJbmZvLnJldmVyc2UoKTtcbiAgICB9XG5cbiAgICBnZXRTZXNzaW9uVXJsIChpZCkge1xuICAgICAgICByZXR1cm4gdGhpcy5zZXNzaW9uc1tpZF0gPyB0aGlzLnNlc3Npb25zW2lkXS5zZXNzaW9uVXJsIDogJyc7XG4gICAgfVxuXG4gICAgYXN5bmMgZ2V0T1NJbmZvIChpZCkge1xuICAgICAgICBpZiAodGhpcy5zZXNzaW9uc1tpZF0pXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5zZXNzaW9uc1tpZF0ub3NJbmZvO1xuXG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIGFzeW5jIG9wZW5Ccm93c2VyIChpZCwgcGFnZVVybCwgY2FwYWJpbGl0aWVzKSB7XG4gICAgICAgIHZhciB7IGxvY2FsSWRlbnRpZmllciwgbG9jYWwsIC4uLnJlc3RDYXBhYmlsaXRpZXMgfSA9IGNhcGFiaWxpdGllcztcblxuICAgICAgICBjYXBhYmlsaXRpZXMgPSB7XG4gICAgICAgICAgICAnYnJvd3NlcnN0YWNrLmxvY2FsSWRlbnRpZmllcic6IGxvY2FsSWRlbnRpZmllcixcbiAgICAgICAgICAgICdicm93c2Vyc3RhY2subG9jYWwnOiAgICAgICAgICAgbG9jYWwsXG4gICAgICAgICAgICAuLi5yZXN0Q2FwYWJpbGl0aWVzXG4gICAgICAgIH07XG5cbiAgICAgICAgdGhpcy5zZXNzaW9uc1tpZF0gPSBhd2FpdCByZXF1ZXN0QXBpKEJST1dTRVJTVEFDS19BUElfUEFUSFMubmV3U2Vzc2lvbiwge1xuICAgICAgICAgICAgYm9keTogeyBkZXNpcmVkQ2FwYWJpbGl0aWVzOiBjYXBhYmlsaXRpZXMgfSxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgQXV0b21hdGVCYWNrZW5kLl9lbnN1cmVTZXNzaW9uSWQodGhpcy5zZXNzaW9uc1tpZF0pO1xuXG4gICAgICAgIGNvbnN0IHNlc3Npb25JbmZvID0gYXdhaXQgdGhpcy5fcmVxdWVzdFNlc3Npb25JbmZvKGlkKTtcbiAgICAgICAgY29uc3Qgb3NJbmZvICAgICAgPSB7XG4gICAgICAgICAgICBuYW1lOiAgICBzZXNzaW9uSW5mb1snb3MnXSB8fCAnJyxcbiAgICAgICAgICAgIHZlcnNpb246IHNlc3Npb25JbmZvWydvc192ZXJzaW9uJ10gfHwgJydcbiAgICAgICAgfTtcblxuICAgICAgICB0aGlzLnNlc3Npb25zW2lkXS5zZXNzaW9uVXJsID0gc2Vzc2lvbkluZm9bJ2Jyb3dzZXJfdXJsJ107XG4gICAgICAgIHRoaXMuc2Vzc2lvbnNbaWRdLm9zSW5mbyAgICAgPSBvc0luZm87XG5cbiAgICAgICAgdmFyIHNlc3Npb25JZCA9IHRoaXMuc2Vzc2lvbnNbaWRdLnNlc3Npb25JZDtcblxuICAgICAgICB0aGlzLnNlc3Npb25zW2lkXS5pbnRlcnZhbCA9IHNldEludGVydmFsKCgpID0+IHJlcXVlc3RBcGkoQlJPV1NFUlNUQUNLX0FQSV9QQVRIUy5nZXRVcmwoc2Vzc2lvbklkKSksIEFQSV9QT0xMSU5HX0lOVEVSVkFMKTtcblxuICAgICAgICBhd2FpdCByZXF1ZXN0QXBpKEJST1dTRVJTVEFDS19BUElfUEFUSFMub3BlblVybChzZXNzaW9uSWQpLCB7IGJvZHk6IHsgdXJsOiBwYWdlVXJsIH0gfSk7XG4gICAgfVxuXG4gICAgYXN5bmMgY2xvc2VCcm93c2VyIChpZCkge1xuICAgICAgICBjb25zdCBzZXNzaW9uID0gdGhpcy5zZXNzaW9uc1tpZF07XG5cbiAgICAgICAgaWYgKCFzZXNzaW9uKVxuICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIGNsZWFySW50ZXJ2YWwoc2Vzc2lvbi5pbnRlcnZhbCk7XG5cbiAgICAgICAgZGVsZXRlIHRoaXMuc2Vzc2lvbnNbaWRdO1xuXG4gICAgICAgIC8vIERlbGV0ZSBzZXNzaW9uIHdob3NlIHNlc3Npb25JZCBpcyBjcmVhdGVkXG4gICAgICAgIGlmIChzZXNzaW9uLnNlc3Npb25JZCAmJiBzZXNzaW9uLnNlc3Npb25JZCAhPT0gJycpXG4gICAgICAgICAgICBhd2FpdCByZXF1ZXN0QXBpKEJST1dTRVJTVEFDS19BUElfUEFUSFMuZGVsZXRlU2Vzc2lvbihzZXNzaW9uLnNlc3Npb25JZCkpO1xuICAgIH1cblxuICAgIGFzeW5jIHRha2VTY3JlZW5zaG90IChpZCwgc2NyZWVuc2hvdFBhdGgpIHtcbiAgICAgICAgdmFyIGJhc2U2NERhdGEgID0gYXdhaXQgcmVxdWVzdEFwaShCUk9XU0VSU1RBQ0tfQVBJX1BBVEhTLnNjcmVlbnNob3QodGhpcy5zZXNzaW9uc1tpZF0uc2Vzc2lvbklkKSk7XG4gICAgICAgIHZhciBidWZmZXIgICAgICA9IEJ1ZmZlci5mcm9tKGJhc2U2NERhdGEudmFsdWUsICdiYXNlNjQnKTtcblxuICAgICAgICBhd2FpdCBzaGFycChidWZmZXIpLnRvRmlsZShzY3JlZW5zaG90UGF0aCk7XG4gICAgfVxuXG4gICAgYXN5bmMgcmVzaXplV2luZG93IChpZCwgd2lkdGgsIGhlaWdodCwgY3VycmVudFdpZHRoLCBjdXJyZW50SGVpZ2h0KSB7XG4gICAgICAgIHZhciBzZXNzaW9uSWQgICAgICAgICAgICAgPSB0aGlzLnNlc3Npb25zW2lkXS5zZXNzaW9uSWQ7XG4gICAgICAgIHZhciBjdXJyZW50V2luZG93U2l6ZSAgICAgPSBhd2FpdCB0aGlzLl9yZXF1ZXN0Q3VycmVudFdpbmRvd1NpemUoaWQpO1xuICAgICAgICB2YXIgY3VycmVudENsaWVudEFyZWFTaXplID0geyB3aWR0aDogY3VycmVudFdpZHRoLCBoZWlnaHQ6IGN1cnJlbnRIZWlnaHQgfTtcbiAgICAgICAgdmFyIHJlcXVlc3RlZFNpemUgICAgICAgICA9IHsgd2lkdGgsIGhlaWdodCB9O1xuICAgICAgICB2YXIgY29ycmVjdGVkU2l6ZSAgICAgICAgID0gZ2V0Q29ycmVjdGVkU2l6ZShjdXJyZW50Q2xpZW50QXJlYVNpemUsIGN1cnJlbnRXaW5kb3dTaXplLCByZXF1ZXN0ZWRTaXplKTtcblxuICAgICAgICBhd2FpdCByZXF1ZXN0QXBpKEJST1dTRVJTVEFDS19BUElfUEFUSFMuc2V0V2luZG93U2l6ZShzZXNzaW9uSWQpLCB7IGJvZHk6IGNvcnJlY3RlZFNpemUgfSk7XG4gICAgfVxuXG4gICAgYXN5bmMgbWF4aW1pemVXaW5kb3cgKGlkKSB7XG4gICAgICAgIGF3YWl0IHJlcXVlc3RBcGkoQlJPV1NFUlNUQUNLX0FQSV9QQVRIUy5tYXhpbWl6ZVdpbmRvdyh0aGlzLnNlc3Npb25zW2lkXS5zZXNzaW9uSWQpKTtcbiAgICB9XG5cbiAgICBhc3luYyByZXBvcnRKb2JSZXN1bHQgKGlkLCBqb2JSZXN1bHQsIGpvYkRhdGEsIHBvc3NpYmxlUmVzdWx0cykge1xuICAgICAgICB2YXIgc2Vzc2lvbklkID0gdGhpcy5zZXNzaW9uc1tpZF0uc2Vzc2lvbklkO1xuICAgICAgICB2YXIgam9iU3RhdHVzID0gY3JlYXRlQnJvd3NlcnN0YWNrU3RhdHVzKGpvYlJlc3VsdCwgam9iRGF0YSwgcG9zc2libGVSZXN1bHRzKTtcblxuICAgICAgICBhd2FpdCByZXF1ZXN0QXBpQmFzZShCUk9XU0VSU1RBQ0tfQVBJX1BBVEhTLnNldFN0YXR1cyhzZXNzaW9uSWQpLCB7IGJvZHk6IGpvYlN0YXR1cyB9KTtcbiAgICB9XG59XG4iXX0=