gst-atom-xcuitest-driver
Version:
ATOM driver for iOS using XCUITest for backend
451 lines (340 loc) • 56 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
require("source-map-support/register");
var _gstAtomIosDriver = require("gst-atom-ios-driver");
var _gstAtomRemoteDebugger = require("gst-atom-remote-debugger");
var _gstAtomBaseDriver = require("gst-atom-base-driver");
var _appiumSupport = require("appium-support");
var _logger = _interopRequireDefault(require("../logger"));
var _asyncbox = require("asyncbox");
var _lodash = _interopRequireDefault(require("lodash"));
const WEBVIEW_BASE = `${_gstAtomIosDriver.WEBVIEW_WIN}_`;
let commands = {},
helpers = {},
extensions = {};
Object.assign(extensions, _gstAtomIosDriver.iosCommands.context);
extensions.closeAlertBeforeTest = async function closeAlertBeforeTest() {
return true;
};
extensions.navToInitialWebview = async function navToInitialWebview() {
if (this.useNewSafari()) {
await this.typeAndNavToUrl();
} else if (!this.isRealDevice() && this.opts.safari) {
await this.navToViewThroughFavorites();
} else {
await this.navToViewWithTitle(/.*/);
}
};
extensions.getLatestWebviewContextForTitle = async function getLatestWebviewContextForTitle(regExp) {
const currentUrl = this.getCurrentUrl();
const contexts = _lodash.default.filter(await this.getContextsAndViews(), 'view');
if (currentUrl) {
for (const ctx of contexts) {
if ((ctx.view.url || '') === this.getCurrentUrl()) {
return ctx.id;
}
}
}
for (const ctx of contexts) {
if (ctx.view.title && regExp.test(ctx.view.title) || ctx.view.url && regExp.test(ctx.view.url)) {
return ctx.id;
}
}
};
extensions.isWebContext = function isWebContext() {
return !!this.curContext && this.curContext !== _gstAtomIosDriver.iosCommands.context.NATIVE_WIN;
};
extensions.isWebview = function isWebview() {
return this.isWebContext();
};
extensions.getNewRemoteDebugger = async function getNewRemoteDebugger() {
let socketPath;
if (!this.isRealDevice()) {
socketPath = await this.opts.device.getWebInspectorSocket();
}
return (0, _gstAtomRemoteDebugger.createRemoteDebugger)({
bundleId: this.opts.bundleId,
additionalBundleIds: this.opts.additionalWebviewBundleIds,
isSafari: this.isSafari(),
includeSafari: this.opts.includeSafariInWebviews,
useNewSafari: this.useNewSafari(),
pageLoadMs: this.pageLoadMs,
platformVersion: this.opts.platformVersion,
socketPath,
remoteDebugProxy: this.opts.remoteDebugProxy,
garbageCollectOnExecute: _appiumSupport.util.hasValue(this.opts.safariGarbageCollect) ? !!this.opts.safariGarbageCollect : false,
udid: this.opts.udid,
logAllCommunication: this.opts.safariLogAllCommunication,
logAllCommunicationHexDump: this.opts.safariLogAllCommunicationHexDump,
socketChunkSize: this.opts.safariSocketChunkSize,
usbmuxdRemoteHost: this.opts.usbmuxdRemoteHost,
usbmuxdRemotePort: this.opts.usbmuxdRemotePort
}, this.isRealDevice());
};
commands.setContext = async function setContext(name, callback, skipReadyCheck) {
function alreadyInContext(desired, current) {
return desired === current || desired === null && current === _gstAtomIosDriver.NATIVE_WIN || desired === _gstAtomIosDriver.NATIVE_WIN && current === null;
}
function isNativeContext(context) {
return context === _gstAtomIosDriver.NATIVE_WIN || context === null;
}
if (name && name.id) {
name = name.id;
}
_logger.default.debug(`Attempting to set context to '${name || _gstAtomIosDriver.NATIVE_WIN}' from '${this.curContext ? this.curContext : _gstAtomIosDriver.NATIVE_WIN}'`);
if (alreadyInContext(name, this.curContext) || alreadyInContext(_lodash.default.replace(name, WEBVIEW_BASE, ''), this.curContext)) {
_logger.default.debug(`Already in '${name || _gstAtomIosDriver.NATIVE_WIN}' context. Doing nothing.`);
return;
}
if (isNativeContext(name)) {
this.curContext = null;
return;
}
if (_lodash.default.isUndefined(this.contexts)) {
await this.getContexts();
}
let contextId = _lodash.default.replace(name, WEBVIEW_BASE, '');
if (contextId === '') {
contextId = this.contexts[1];
}
if (!_lodash.default.includes(this.contexts, contextId)) {
throw new _gstAtomBaseDriver.errors.NoSuchContextError();
}
const oldContext = this.curContext;
this.curContext = this.curWindowHandle = contextId;
const [appIdKey, pageIdKey] = _lodash.default.map(contextId.split('.'), id => parseInt(id, 10));
try {
this.selectingNewPage = true;
await this.remote.selectPage(appIdKey, pageIdKey, skipReadyCheck);
} catch (err) {
this.curContext = this.curWindowHandle = oldContext;
throw err;
} finally {
this.selectingNewPage = false;
}
if (this.opts.enablePerformanceLogging && this.remote) {
_logger.default.debug(`Starting performance log on '${this.curContext}'`);
this.logs.performance = new _gstAtomIosDriver.IOSPerformanceLog(this.remote);
await this.logs.performance.startCapture();
}
if (name && name !== _gstAtomIosDriver.NATIVE_WIN && this.logs) {
if (this.logs.safariConsole) {
await this.remote.startConsole(this.logs.safariConsole.addLogLine.bind(this.logs.safariConsole));
}
if (this.logs.safariNetwork) {
await this.remote.startNetwork(this.logs.safariNetwork.addLogLine.bind(this.logs.safariNetwork));
}
}
};
extensions.connectToRemoteDebugger = async function connectToRemoteDebugger() {
this.remote = await this.getNewRemoteDebugger();
this.remote.on(_gstAtomRemoteDebugger.RemoteDebugger.EVENT_PAGE_CHANGE, this.onPageChange.bind(this));
this.remote.on(_gstAtomRemoteDebugger.RemoteDebugger.EVENT_FRAMES_DETACHED, () => {
if (!_lodash.default.isEmpty(this.curWebFrames)) {
_logger.default.debug(`Clearing ${_appiumSupport.util.pluralize('frame', this.curWebFrames.length, true)}: ${this.curWebFrames.join(', ')}`);
}
this.curWebFrames = [];
});
await this.remote.connect(this.opts.webviewConnectTimeout);
};
extensions.listWebFrames = async function listWebFrames(useUrl = true) {
if (!this.opts.bundleId) {
_logger.default.errorAndThrow('Cannot enter web frame without a bundle ID');
}
useUrl = useUrl && !this.isRealDevice() && !!this.getCurrentUrl();
_logger.default.debug(`Selecting by url: ${useUrl} ${useUrl ? `(expected url: '${this.getCurrentUrl()}')` : ''}`);
const currentUrl = useUrl ? this.getCurrentUrl() : undefined;
let pageArray = [];
const getWebviewPages = async () => {
try {
return await this.remote.selectApp(currentUrl, this.opts.webviewConnectRetries, this.opts.ignoreAboutBlankUrl);
} catch (err) {
_logger.default.debug(`No available web pages: ${err.message}`);
return [];
}
};
if (this.remote && this.remote.appIdKey) {
pageArray = await getWebviewPages();
} else {
if (!this.remote) {
await this.connectToRemoteDebugger();
}
await this.remote.setConnectionKey();
pageArray = await getWebviewPages();
const alertErrorMsg = 'Close alert failed. Retry.';
try {
await (0, _asyncbox.retryInterval)(6, 1000, async () => {
if (!(await this.closeAlertBeforeTest())) {
throw new Error(alertErrorMsg);
}
});
} catch (err) {
if (err.message !== alertErrorMsg) {
_logger.default.errorAndThrow(err);
}
}
}
if (pageArray.length === 0) {
_logger.default.debug('No web frames found.');
}
return pageArray;
};
commands.getContexts = async function getContexts() {
_logger.default.debug('Getting list of available contexts');
const contexts = await this.getContextsAndViews(false);
const mapFn = this.opts.fullContextList ? function (context) {
return {
id: context.id.toString(),
title: context.view.title,
url: context.view.url,
bundleId: context.view.bundleId
};
} : context => context.id.toString();
return contexts.map(mapFn);
};
extensions.mobileGetContexts = async function mobileGetContexts(opts = {}) {
let {
waitForWebviewMs = 0
} = opts;
if (!_lodash.default.isNumber(waitForWebviewMs)) {
waitForWebviewMs = parseInt(waitForWebviewMs, 10);
if (isNaN(waitForWebviewMs)) {
waitForWebviewMs = 0;
}
}
const curOpt = this.opts.fullContextList;
this.opts.fullContextList = true;
const timer = new _appiumSupport.timing.Timer().start();
try {
let contexts;
do {
contexts = await this.getContexts();
if (contexts.length >= 2) {
_logger.default.debug(`Found webview context after ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`);
return contexts;
}
_logger.default.debug(`No webviews found in ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`);
} while (timer.getDuration().asMilliSeconds < waitForWebviewMs);
return contexts;
} finally {
this.opts.fullContextList = curOpt;
}
};
commands.setWindow = async function setWindow(name, skipReadyCheck) {
try {
await this.setContext(name, _lodash.default.noop, skipReadyCheck);
} catch (err) {
throw (0, _gstAtomBaseDriver.isErrorType)(err, _gstAtomBaseDriver.errors.NoSuchContextError) ? new _gstAtomBaseDriver.errors.NoSuchWindowError() : err;
}
};
commands.getWindowHandle = async function getWindowHandle() {
if (!this.isWebContext()) {
throw new _gstAtomBaseDriver.errors.NotImplementedError();
}
_logger.default.debug(`Getting current window handle`);
return this.curContext;
};
commands.getWindowHandles = async function getWindowHandles() {
if (!this.isWebContext()) {
throw new _gstAtomBaseDriver.errors.NotImplementedError();
}
_logger.default.debug('Getting list of available window handles');
const contexts = await this.getContextsAndViews(false);
return contexts.filter(context => context.id !== _gstAtomIosDriver.NATIVE_WIN).map(context => context.view.id.toString());
};
extensions.onPageChange = async function onPageChange(pageChangeNotification) {
_logger.default.debug(`Remote debugger notified us of a new page listing: ${JSON.stringify(pageChangeNotification)}`);
if (this.selectingNewPage) {
_logger.default.debug('We are in the middle of selecting a page, ignoring');
return;
}
if (!this.remote || !this.remote.isConnected) {
_logger.default.debug('We have not yet connected, ignoring');
return;
}
const {
appIdKey,
pageArray
} = pageChangeNotification;
let newIds = [];
let newPages = [];
let keyId = null;
for (const page of pageArray) {
const id = page.id.toString();
newIds.push(id);
if (page.isKey) {
keyId = id;
}
const contextId = `${appIdKey}.${id}`;
if (!_lodash.default.includes(this.contexts, contextId)) {
newPages.push(id);
this.contexts.push(contextId);
}
}
if (!keyId) {
_logger.default.debug('No key id found. Choosing first id from page array');
keyId = newIds[0] || null;
}
if (!_appiumSupport.util.hasValue(this.curContext)) {
_logger.default.debug('We do not appear to have window set yet, ignoring');
return;
}
const [curAppIdKey, curPageIdKey] = this.curContext.split('.');
if (curAppIdKey !== appIdKey) {
_logger.default.debug('Page change not referring to currently selected app, ignoring.');
return;
}
let newPage = null;
if (newPages.length) {
newPage = _lodash.default.last(newPages);
_logger.default.debug(`We have new pages, selecting page '${newPage}'`);
} else if (!_lodash.default.includes(newIds, curPageIdKey)) {
_logger.default.debug('New page listing from remote debugger does not contain ' + 'current window; assuming it is closed');
if (!_appiumSupport.util.hasValue(keyId)) {
_logger.default.error('Do not have our current window anymore, and there ' + 'are not any more to load! Doing nothing...');
this.setCurrentUrl(undefined);
return;
}
_logger.default.debug(`Debugger already selected page '${keyId}', ` + `confirming that choice.`);
this.curContext = `${appIdKey}.${keyId}`;
newPage = keyId;
} else {
_logger.default.debug('Checking if page needs to load');
const needsPageLoad = (() => {
const contextArray = _lodash.default.map(pageArray, page => `${appIdKey}.${page.id}`);
return !_lodash.default.isEqual(_lodash.default.find(this.contexts, this.curContext), _lodash.default.find(contextArray, this.curContext));
})();
if (needsPageLoad) {
_logger.default.debug('Page load needed. Loading...');
await this.remote.pageLoad();
}
_logger.default.debug('New page listing is same as old, doing nothing');
}
if (_appiumSupport.util.hasValue(this.curContext)) {
let currentPageId = parseInt(_lodash.default.last(this.curContext.split('.')), 10);
let page = _lodash.default.find(pageArray, p => parseInt(p.id, 10) === currentPageId);
if (page && page.url !== this.getCurrentUrl()) {
_logger.default.debug(`Redirected from '${this.getCurrentUrl()}' to '${page.url}'`);
this.setCurrentUrl(page.url);
}
}
if (_appiumSupport.util.hasValue(newPage)) {
this.selectingNewPage = true;
const oldContext = this.curContext;
this.curContext = `${appIdKey}.${newPage}`;
this.remote.selectPage(appIdKey, parseInt(newPage, 10)).catch(err => {
_logger.default.warn(`Failed to select page: ${err.message}`);
this.curContext = oldContext;
});
this.selectingNewPage = false;
}
this.windowHandleCache = pageArray;
};
Object.assign(extensions, commands, helpers);
var _default = extensions;
exports.default = _default;require('source-map-support').install();
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImxpYi9jb21tYW5kcy9jb250ZXh0LmpzIl0sIm5hbWVzIjpbIldFQlZJRVdfQkFTRSIsIldFQlZJRVdfV0lOIiwiY29tbWFuZHMiLCJoZWxwZXJzIiwiZXh0ZW5zaW9ucyIsIk9iamVjdCIsImFzc2lnbiIsImlvc0NvbW1hbmRzIiwiY29udGV4dCIsImNsb3NlQWxlcnRCZWZvcmVUZXN0IiwibmF2VG9Jbml0aWFsV2VidmlldyIsInVzZU5ld1NhZmFyaSIsInR5cGVBbmROYXZUb1VybCIsImlzUmVhbERldmljZSIsIm9wdHMiLCJzYWZhcmkiLCJuYXZUb1ZpZXdUaHJvdWdoRmF2b3JpdGVzIiwibmF2VG9WaWV3V2l0aFRpdGxlIiwiZ2V0TGF0ZXN0V2Vidmlld0NvbnRleHRGb3JUaXRsZSIsInJlZ0V4cCIsImN1cnJlbnRVcmwiLCJnZXRDdXJyZW50VXJsIiwiY29udGV4dHMiLCJfIiwiZmlsdGVyIiwiZ2V0Q29udGV4dHNBbmRWaWV3cyIsImN0eCIsInZpZXciLCJ1cmwiLCJpZCIsInRpdGxlIiwidGVzdCIsImlzV2ViQ29udGV4dCIsImN1ckNvbnRleHQiLCJOQVRJVkVfV0lOIiwiaXNXZWJ2aWV3IiwiZ2V0TmV3UmVtb3RlRGVidWdnZXIiLCJzb2NrZXRQYXRoIiwiZGV2aWNlIiwiZ2V0V2ViSW5zcGVjdG9yU29ja2V0IiwiYnVuZGxlSWQiLCJhZGRpdGlvbmFsQnVuZGxlSWRzIiwiYWRkaXRpb25hbFdlYnZpZXdCdW5kbGVJZHMiLCJpc1NhZmFyaSIsImluY2x1ZGVTYWZhcmkiLCJpbmNsdWRlU2FmYXJpSW5XZWJ2aWV3cyIsInBhZ2VMb2FkTXMiLCJwbGF0Zm9ybVZlcnNpb24iLCJyZW1vdGVEZWJ1Z1Byb3h5IiwiZ2FyYmFnZUNvbGxlY3RPbkV4ZWN1dGUiLCJ1dGlsIiwiaGFzVmFsdWUiLCJzYWZhcmlHYXJiYWdlQ29sbGVjdCIsInVkaWQiLCJsb2dBbGxDb21tdW5pY2F0aW9uIiwic2FmYXJpTG9nQWxsQ29tbXVuaWNhdGlvbiIsImxvZ0FsbENvbW11bmljYXRpb25IZXhEdW1wIiwic2FmYXJpTG9nQWxsQ29tbXVuaWNhdGlvbkhleER1bXAiLCJzb2NrZXRDaHVua1NpemUiLCJzYWZhcmlTb2NrZXRDaHVua1NpemUiLCJ1c2JtdXhkUmVtb3RlSG9zdCIsInVzYm11eGRSZW1vdGVQb3J0Iiwic2V0Q29udGV4dCIsIm5hbWUiLCJjYWxsYmFjayIsInNraXBSZWFkeUNoZWNrIiwiYWxyZWFkeUluQ29udGV4dCIsImRlc2lyZWQiLCJjdXJyZW50IiwiaXNOYXRpdmVDb250ZXh0IiwibG9nIiwiZGVidWciLCJyZXBsYWNlIiwiaXNVbmRlZmluZWQiLCJnZXRDb250ZXh0cyIsImNvbnRleHRJZCIsImluY2x1ZGVzIiwiZXJyb3JzIiwiTm9TdWNoQ29udGV4dEVycm9yIiwib2xkQ29udGV4dCIsImN1cldpbmRvd0hhbmRsZSIsImFwcElkS2V5IiwicGFnZUlkS2V5IiwibWFwIiwic3BsaXQiLCJwYXJzZUludCIsInNlbGVjdGluZ05ld1BhZ2UiLCJyZW1vdGUiLCJzZWxlY3RQYWdlIiwiZXJyIiwiZW5hYmxlUGVyZm9ybWFuY2VMb2dnaW5nIiwibG9ncyIsInBlcmZvcm1hbmNlIiwiSU9TUGVyZm9ybWFuY2VMb2ciLCJzdGFydENhcHR1cmUiLCJzYWZhcmlDb25zb2xlIiwic3RhcnRDb25zb2xlIiwiYWRkTG9nTGluZSIsImJpbmQiLCJzYWZhcmlOZXR3b3JrIiwic3RhcnROZXR3b3JrIiwiY29ubmVjdFRvUmVtb3RlRGVidWdnZXIiLCJvbiIsIlJlbW90ZURlYnVnZ2VyIiwiRVZFTlRfUEFHRV9DSEFOR0UiLCJvblBhZ2VDaGFuZ2UiLCJFVkVOVF9GUkFNRVNfREVUQUNIRUQiLCJpc0VtcHR5IiwiY3VyV2ViRnJhbWVzIiwicGx1cmFsaXplIiwibGVuZ3RoIiwiam9pbiIsImNvbm5lY3QiLCJ3ZWJ2aWV3Q29ubmVjdFRpbWVvdXQiLCJsaXN0V2ViRnJhbWVzIiwidXNlVXJsIiwiZXJyb3JBbmRUaHJvdyIsInVuZGVmaW5lZCIsInBhZ2VBcnJheSIsImdldFdlYnZpZXdQYWdlcyIsInNlbGVjdEFwcCIsIndlYnZpZXdDb25uZWN0UmV0cmllcyIsImlnbm9yZUFib3V0QmxhbmtVcmwiLCJtZXNzYWdlIiwic2V0Q29ubmVjdGlvbktleSIsImFsZXJ0RXJyb3JNc2ciLCJFcnJvciIsIm1hcEZuIiwiZnVsbENvbnRleHRMaXN0IiwidG9TdHJpbmciLCJtb2JpbGVHZXRDb250ZXh0cyIsIndhaXRGb3JXZWJ2aWV3TXMiLCJpc051bWJlciIsImlzTmFOIiwiY3VyT3B0IiwidGltZXIiLCJ0aW1pbmciLCJUaW1lciIsInN0YXJ0IiwiZ2V0RHVyYXRpb24iLCJhc01pbGxpU2Vjb25kcyIsInRvRml4ZWQiLCJzZXRXaW5kb3ciLCJub29wIiwiTm9TdWNoV2luZG93RXJyb3IiLCJnZXRXaW5kb3dIYW5kbGUiLCJOb3RJbXBsZW1lbnRlZEVycm9yIiwiZ2V0V2luZG93SGFuZGxlcyIsInBhZ2VDaGFuZ2VOb3RpZmljYXRpb24iLCJKU09OIiwic3RyaW5naWZ5IiwiaXNDb25uZWN0ZWQiLCJuZXdJZHMiLCJuZXdQYWdlcyIsImtleUlkIiwicGFnZSIsInB1c2giLCJpc0tleSIsImN1ckFwcElkS2V5IiwiY3VyUGFnZUlkS2V5IiwibmV3UGFnZSIsImxhc3QiLCJlcnJvciIsInNldEN1cnJlbnRVcmwiLCJuZWVkc1BhZ2VMb2FkIiwiY29udGV4dEFycmF5IiwiaXNFcXVhbCIsImZpbmQiLCJwYWdlTG9hZCIsImN1cnJlbnRQYWdlSWQiLCJwIiwiY2F0Y2giLCJ3YXJuIiwid2luZG93SGFuZGxlQ2FjaGUiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7O0FBQUE7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBR0EsTUFBTUEsWUFBWSxHQUFJLEdBQUVDLDZCQUFZLEdBQXBDO0FBRUEsSUFBSUMsUUFBUSxHQUFHLEVBQWY7QUFBQSxJQUFtQkMsT0FBTyxHQUFHLEVBQTdCO0FBQUEsSUFBaUNDLFVBQVUsR0FBRyxFQUE5QztBQUVBQyxNQUFNLENBQUNDLE1B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Q0FBQ3FGLENBQUMsQ0FBQzdJLEVBQUgsRUFBTyxFQUFQLENBQVIsS0FBdUI0SSxhQUFoRCxDQUFYOztBQUNBLFFBQUlkLElBQUksSUFBSUEsSUFBSSxDQUFDL0gsR0FBTCxLQUFhLEtBQUtQLGFBQUwsRUFBekIsRUFBK0M7QUFDN0NpRCxzQkFBSUMsS0FBSixDQUFXLG9CQUFtQixLQUFLbEQsYUFBTCxFQUFxQixTQUFRc0ksSUFBSSxDQUFDL0gsR0FBSSxHQUFwRTs7QUFDQSxXQUFLdUksYUFBTCxDQUFtQlIsSUFBSSxDQUFDL0gsR0FBeEI7QUFDRDtBQUNGOztBQUVELE1BQUlzQixvQkFBS0MsUUFBTCxDQUFjNkcsT0FBZCxDQUFKLEVBQTRCO0FBQzFCLFNBQUsxRSxnQkFBTCxHQUF3QixJQUF4QjtBQUNBLFVBQU1QLFVBQVUsR0FBRyxLQUFLOUMsVUFBeEI7QUFDQSxTQUFLQSxVQUFMLEdBQW1CLEdBQUVnRCxRQUFTLElBQUcrRSxPQUFRLEVBQXpDO0FBRUEsU0FBS3pFLE1BQUwsQ0FBWUMsVUFBWixDQUF1QlAsUUFBdkIsRUFBaUNJLFFBQVEsQ0FBQzJFLE9BQUQsRUFBVSxFQUFWLENBQXpDLEVBQ0dXLEtBREgsQ0FDVWxGLEdBQUQsSUFBUztBQUNkbkIsc0JBQUlzRyxJQUFKLENBQVUsMEJBQXlCbkYsR0FBRyxDQUFDa0MsT0FBUSxFQUEvQzs7QUFDQSxXQUFLMUYsVUFBTCxHQUFrQjhDLFVBQWxCO0FBQ0QsS0FKSDtBQUtBLFNBQUtPLGdCQUFMLEdBQXdCLEtBQXhCO0FBQ0Q7O0FBQ0QsT0FBS3VGLGlCQUFMLEdBQXlCdkQsU0FBekI7QUFDRCxDQWhIRDs7QUFtSEFqSCxNQUFNLENBQUNDLE1BQVAsQ0FBY0YsVUFBZCxFQUEwQkYsUUFBMUIsRUFBb0NDLE9BQXBDO2VBQ2VDLFUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBpb3NDb21tYW5kcywgSU9TUGVyZm9ybWFuY2VMb2csIE5BVElWRV9XSU4sIFdFQlZJRVdfV0lOIH0gZnJvbSAnZ3N0LWF0b20taW9zLWRyaXZlcic7XG5pbXBvcnQgeyBjcmVhdGVSZW1vdGVEZWJ1Z2dlciwgUmVtb3RlRGVidWdnZXIgfSBmcm9tICdnc3QtYXRvbS1yZW1vdGUtZGVidWdnZXInO1xuaW1wb3J0IHsgZXJyb3JzLCBpc0Vycm9yVHlwZSB9IGZyb20gJ2dzdC1hdG9tLWJhc2UtZHJpdmVyJztcbmltcG9ydCB7IHV0aWwsIHRpbWluZyB9IGZyb20gJ2FwcGl1bS1zdXBwb3J0JztcbmltcG9ydCBsb2cgZnJvbSAnLi4vbG9nZ2VyJztcbmltcG9ydCB7IHJldHJ5SW50ZXJ2YWwgfSBmcm9tICdhc3luY2JveCc7XG5pbXBvcnQgXyBmcm9tICdsb2Rhc2gnO1xuXG5cbmNvbnN0IFdFQlZJRVdfQkFTRSA9IGAke1dFQlZJRVdfV0lOfV9gO1xuXG5sZXQgY29tbWFuZHMgPSB7fSwgaGVscGVycyA9IHt9LCBleHRlbnNpb25zID0ge307XG5cbk9iamVjdC5hc3NpZ24oZXh0ZW5zaW9ucywgaW9zQ29tbWFuZHMuY29udGV4dCk7XG5cbi8vIG92ZXJyaWRlLCBhcyBnc3QtYXRvbS1pb3MtZHJpdmVyJ3MgdmVyc2lvbiB1c2VzIFVJIEF1dG9tYXRpb24gdG8gY2xvc2VcbmV4dGVuc2lvbnMuY2xvc2VBbGVydEJlZm9yZVRlc3QgPSBhc3luYyBmdW5jdGlvbiBjbG9zZUFsZXJ0QmVmb3JlVGVzdCAoKSB7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgcmVxdWlyZS1hd2FpdFxuICByZXR1cm4gdHJ1ZTtcbn07XG5cbi8vIHRoZSBnc3QtYXRvbS1pb3MtZHJpdmVyIHZlcnNpb24gaGFzIGEgd2FpdCBvbiByZWFsIGRldmljZXMsIHdoaWNoIGlzIG5vIGxvbmdlclxuLy8gbmVjZXNzYXJ5XG5leHRlbnNpb25zLm5hdlRvSW5pdGlhbFdlYnZpZXcgPSBhc3luYyBmdW5jdGlvbiBuYXZUb0luaXRpYWxXZWJ2aWV3ICgpIHtcbiAgaWYgKHRoaXMudXNlTmV3U2FmYXJpKCkpIHtcbiAgICBhd2FpdCB0aGlzLnR5cGVBbmROYXZUb1VybCgpO1xuICB9IGVsc2UgaWYgKCF0aGlzLmlzUmVhbERldmljZSgpICYmIHRoaXMub3B0cy5zYWZhcmkpIHtcbiAgICBhd2FpdCB0aGlzLm5hdlRvVmlld1Rocm91Z2hGYXZvcml0ZXMoKTtcbiAgfSBlbHNlIHtcbiAgICBhd2FpdCB0aGlzLm5hdlRvVmlld1dpdGhUaXRsZSgvLiovKTtcbiAgfVxufTtcblxuLy8gdGhlIGdzdC1hdG9tLWlvcy1kcml2ZXIgdmVyc2lvbiBvZiB0aGlzIGZ1bmN0aW9uIGZhaWxzIGluIENJLFxuLy8gYW5kIHRoZSB3cm9uZyB3ZWJ2aWV3IGlzIGFsbW9zdCBhbHdheXMgcmV0cmlldmVkXG4vLyBhbHNvIG92ZXJyaWRlIHNvIHRoYXQgdGhlIGNhc2Ugd2hlcmUgdGhlIFNESyB2ZXJzaW9uIGlzIG5vdCBzZXQgZG9lcyBub3QgZmFpbFxuZXh0ZW5zaW9ucy5nZXRMYXRlc3RXZWJ2aWV3Q29udGV4dEZvclRpdGxlID0gYXN5bmMgZnVuY3Rpb24gZ2V0TGF0ZXN0V2Vidmlld0NvbnRleHRGb3JUaXRsZSAocmVnRXhwKSB7XG4gIGNvbnN0IGN1cnJlbnRVcmwgPSB0aGlzLmdldEN1cnJlbnRVcmwoKTtcblxuICBjb25zdCBjb250ZXh0cyA9IF8uZmlsdGVyKGF3YWl0IHRoaXMuZ2V0Q29udGV4dHNBbmRWaWV3cygpLCAndmlldycpO1xuXG4gIGlmIChjdXJyZW50VXJsKSB7XG4gICAgLy8gZmlyc3QgdHJ5IHRvIG1hdGNoIGJ5IGN1cnJlbnQgdXJsXG4gICAgZm9yIChjb25zdCBjdHggb2YgY29udGV4dHMpIHtcbiAgICAgIGlmICgoY3R4LnZpZXcudXJsIHx8ICcnKSA9PT0gdGhpcy5nZXRDdXJyZW50VXJsKCkpIHtcbiAgICAgICAgcmV0dXJuIGN0eC5pZDtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvLyBpZiBub3QsIHRyeSB0byBtYXRjaCBieSByZWd1bGFyIGV4cHJlc3Npb25cbiAgZm9yIChjb25zdCBjdHggb2YgY29udGV4dHMpIHtcbiAgICBpZiAoKGN0eC52aWV3LnRpdGxlICYmIHJlZ0V4cC50ZXN0KGN0eC52aWV3LnRpdGxlKSkgfHwgKGN0eC52aWV3LnVybCAmJiByZWdFeHAudGVzdChjdHgudmlldy51cmwpKSkge1xuICAgICAgcmV0dXJuIGN0eC5pZDtcbiAgICB9XG4gIH1cbn07XG5cbmV4dGVuc2lvbnMuaXNXZWJDb250ZXh0ID0gZnVuY3Rpb24gaXNXZWJDb250ZXh0ICgpIHtcbiAgcmV0dXJuICEhdGhpcy5jdXJDb250ZXh0ICYmIHRoaXMuY3VyQ29udGV4dCAhPT0gaW9zQ29tbWFuZHMuY29udGV4dC5OQVRJVkVfV0lOO1xufTtcblxuZXh0ZW5zaW9ucy5pc1dlYnZpZXcgPSBmdW5jdGlvbiBpc1dlYnZpZXcgKCkge1xuICByZXR1cm4gdGhpcy5pc1dlYkNvbnRleHQoKTtcbn07XG5cbmV4dGVuc2lvbnMuZ2V0TmV3UmVtb3RlRGVidWdnZXIgPSBhc3luYyBmdW5jdGlvbiBnZXROZXdSZW1vdGVEZWJ1Z2dlciAoKSB7XG4gIGxldCBzb2NrZXRQYXRoO1xuICBpZiAoIXRoaXMuaXNSZWFsRGV2aWNlKCkpIHtcbiAgICBzb2NrZXRQYXRoID0gYXdhaXQgdGhpcy5vcHRzLmRldmljZS5nZXRXZWJJbnNwZWN0b3JTb2NrZXQoKTtcbiAgfVxuICByZXR1cm4gY3JlYXRlUmVtb3RlRGVidWdnZXIoe1xuICAgIGJ1bmRsZUlkOiB0aGlzLm9wdHMuYnVuZGxlSWQsXG4gICAgYWRkaXRpb25hbEJ1bmRsZUlkczogdGhpcy5vcHRzLmFkZGl0aW9uYWxXZWJ2aWV3QnVuZGxlSWRzLFxuICAgIGlzU2FmYXJpOiB0aGlzLmlzU2FmYXJpKCksXG4gICAgaW5jbHVkZVNhZmFyaTogdGhpcy5vcHRzLmluY2x1ZGVTYWZhcmlJbldlYnZpZXdzLFxuICAgIHVzZU5ld1NhZmFyaTogdGhpcy51c2VOZXdTYWZhcmkoKSxcbiAgICBwYWdlTG9hZE1zOiB0aGlzLnBhZ2VMb2FkTXMsXG4gICAgcGxhdGZvcm1WZXJzaW9uOiB0aGlzLm9wdHMucGxhdGZvcm1WZXJzaW9uLFxuICAgIHNvY2tldFBhdGgsXG4gICAgcmVtb3RlRGVidWdQcm94eTogdGhpcy5vcHRzLnJlbW90ZURlYnVnUHJveHksXG4gICAgZ2FyYmFnZUNvbGxlY3RPbkV4ZWN1dGU6IHV0aWwuaGFzVmFsdWUodGhpcy5vcHRzLnNhZmFyaUdhcmJhZ2VDb2xsZWN0KVxuICAgICAgPyAhIXRoaXMub3B0cy5zYWZhcmlHYXJiYWdlQ29sbGVjdFxuICAgICAgOiBmYWxzZSxcbiAgICB1ZGlkOiB0aGlzLm9wdHMudWRpZCxcbiAgICBsb2dBbGxDb21tdW5pY2F0aW9uOiB0aGlzLm9wdHMuc2FmYXJpTG9nQWxsQ29tbXVuaWNhdGlvbixcbiAgICBsb2dBbGxDb21tdW5pY2F0aW9uSGV4RHVtcDogdGhpcy5vcHRzLnNhZmFyaUxvZ0FsbENvbW11bmljYXRpb25IZXhEdW1wLFxuICAgIHNvY2tldENodW5rU2l6ZTogdGhpcy5vcHRzLnNhZmFyaVNvY2tldENodW5rU2l6ZSxcbiAgICB1c2JtdXhkUmVtb3RlSG9zdDogdGhpcy5vcHRzLnVzYm11eGRSZW1vdGVIb3N0LFxuICAgIHVzYm11eGRSZW1vdGVQb3J0OiB0aGlzLm9wdHMudXNibXV4ZFJlbW90ZVBvcnQsXG4gIH0sIHRoaXMuaXNSZWFsRGV2aWNlKCkpO1xufTtcblxuLyoqXG4gKiBTZXQgY29udGV4dFxuICpcbiAqIEBwYXJhbSB7P3N0cmluZ30gbmFtZSAtIFRoZSBuYW1lIG9mIGNvbnRleHQgdG8gc2V0LiBJdCBjb3VsZCBiZSAnbnVsbCcgYXMgTkFUSVZFX1dJTi5cbiAqIEBwYXJhbSB7Y2FsbGJhY2t9IGNhbGxiYWNrIFRoZSBjYWxsYmFjay4gKEl0IGlzIG5vdCBjYWxsZWQgaW4gdGhpcyBtZXRob2QpXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHNraXBSZWFkeUNoZWNrIC0gV2hldGhlciBpdCB3YWl0cyBmb3IgdGhlIG5ldyBjb250ZXh0IGlzIHJlYWR5XG4gKi9cbmNvbW1hbmRzLnNldENvbnRleHQgPSBhc3luYyBmdW5jdGlvbiBzZXRDb250ZXh0IChuYW1lLCBjYWxsYmFjaywgc2tpcFJlYWR5Q2hlY2spIHtcbiAgZnVuY3Rpb24gYWxyZWFkeUluQ29udGV4dCAoZGVzaXJlZCwgY3VycmVudCkge1xuICAgIHJldHVybiAoZGVzaXJlZCA9PT0gY3VycmVudCB8fFxuICAgICAgICAgICAoZGVzaXJlZCA9PT0gbnVsbCAmJiBjdXJyZW50ID09PSBOQVRJVkVfV0lOKSB8fFxuICAgICAgICAgICAoZGVzaXJlZCA9PT0gTkFUSVZFX1dJTiAmJiBjdXJyZW50ID09PSBudWxsKSk7XG4gIH1cbiAgZnVuY3Rpb24gaXNOYXRpdmVDb250ZXh0IChjb250ZXh0KSB7XG4gICAgcmV0dXJuIGNvbnRleHQgPT09IE5BVElWRV9XSU4gfHwgY29udGV4dCA9PT0gbnVsbDtcbiAgfVxuXG4gIC8vIGFsbG93IHRoZSBmdWxsIGNvbnRleHQgbGlzdCB0byBiZSBwYXNzZWQgaW5cbiAgaWYgKG5hbWUgJiYgbmFtZS5pZCkge1xuICAgIG5hbWUgPSBuYW1lLmlkO1xuICB9XG5cbiAgbG9nLmRlYnVnKGBBdHRlbXB0aW5nIHRvIHNldCBjb250ZXh0IHRvICcke25hbWUgfHwgTkFUSVZFX1dJTn0nIGZyb20gJyR7dGhpcy5jdXJDb250ZXh0ID8gdGhpcy5jdXJDb250ZXh0IDogTkFUSVZFX1dJTn0nYCk7XG5cbiAgaWYgKGFscmVhZHlJbkNvbnRleHQobmFtZSwgdGhpcy5jdXJDb250ZXh0KSB8fCBhbHJlYWR5SW5Db250ZXh0KF8ucmVwbGFjZShuYW1lLCBXRUJWSUVXX0JBU0UsICcnKSwgdGhpcy5jdXJDb250ZXh0KSkge1xuICAgIC8vIGFscmVhZHkgaW4gdGhlIG5hbWVkIGNvbnRleHQsIG5vIG5lZWQgdG8gZG8gYW55dGhpbmdcbiAgICBsb2cuZGVidWcoYEFscmVhZHkgaW4gJyR7bmFtZSB8fCBOQVRJVkVfV0lOfScgY29udGV4dC4gRG9pbmcgbm90aGluZy5gKTtcbiAgICByZXR1cm47XG4gIH1cbiAgaWYgKGlzTmF0aXZlQ29udGV4dChuYW1lKSkge1xuICAgIC8vIHN3aXRjaGluZyBpbnRvIHRoZSBuYXRpdmUgY29udGV4dFxuICAgIHRoaXMuY3VyQ29udGV4dCA9IG51bGw7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgLy8gc3dpdGNoaW5nIGludG8gYSB3ZWJ2aWV3IGNvbnRleHRcblxuICAvLyBpZiBjb250ZXh0cyBoYXZlIG5vdCBhbHJlYWR5IGJlZW4gcmV0cmlldmVkLCBnZXQgdGhlbVxuICBpZiAoXy5pc1VuZGVmaW5lZCh0aGlzLmNvbnRleHRzKSkge1xuICAgIGF3YWl0IHRoaXMuZ2V0Q29udGV4dHMoKTtcbiAgfVxuXG4gIGxldCBjb250ZXh0SWQgPSBfLnJlcGxhY2UobmFtZSwgV0VCVklFV19CQVNFLCAnJyk7XG4gIGlmIChjb250ZXh0SWQgPT09ICcnKSB7XG4gICAgLy8gYWxsb3cgdXNlciB0byBwYXNzIGluIFwiV0VCVklFV1wiIHdpdGhvdXQgYW4gaW5kZXhcbiAgICAvLyB0aGUgc2Vjb25kIGNvbnRleHQgd2lsbCBiZSB0aGUgZmlyc3Qgd2VidmlldyBhc1xuICAgIC8vIHRoZSBmaXJzdCBpcyBhbHdheXMgTkFUSVZFX0FQUFxuICAgIGNvbnRleHRJZCA9IHRoaXMuY29udGV4dHNbMV07XG4gIH1cbiAgaWYgKCFfLmluY2x1ZGVzKHRoaXMuY29udGV4dHMsIGNvbnRleHRJZCkpIHtcbiAgICB0aHJvdyBuZXcgZXJyb3JzLk5vU3VjaENvbnRleHRFcnJvcigpO1xuICB9XG5cbiAgY29uc3Qgb2xkQ29udGV4dCA9IHRoaXMuY3VyQ29udGV4dDtcbiAgdGhpcy5jdXJDb250ZXh0ID0gdGhpcy5jdXJXaW5kb3dIYW5kbGUgPSBjb250ZXh0SWQ7XG5cbiAgLy8gYGNvbnRleHRJZGAgd2lsbCBiZSBpbiB0aGUgZm9ybSBvZiBgYXBwSWQucGFnZUlkYCBpbiB0aGlzIGNhc2VcbiAgY29uc3QgW2FwcElkS2V5LCBwYWdlSWRLZXldID0gXy5tYXAoY29udGV4dElkLnNwbGl0KCcuJyksIChpZCkgPT4gcGFyc2VJbnQoaWQsIDEwKSk7XG4gIHRyeSB7XG4gICAgdGhpcy5zZWxlY3RpbmdOZXdQYWdlID0gdHJ1ZTtcbiAgICBhd2FpdCB0aGlzLnJlbW90ZS5zZWxlY3RQYWdlKGFwcElkS2V5LCBwYWdlSWRLZXksIHNraXBSZWFkeUNoZWNrKTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgdGhpcy5jdXJDb250ZXh0ID0gdGhpcy5jdXJXaW5kb3dIYW5kbGUgPSBvbGRDb250ZXh0O1xuICAgIHRocm93IGVycjtcbiAgfSBmaW5hbGx5IHtcbiAgICB0aGlzLnNlbGVjdGluZ05ld1BhZ2UgPSBmYWxzZTtcbiAgfVxuXG4gIC8vIGF0dGVtcHQgdG8gc3RhcnQgcGVyZm9ybWFuY2UgbG9nZ2luZywgaWYgcmVxdWVzdGVkXG4gIGlmICh0aGlzLm9wdHMuZW5hYmxlUGVyZm9ybWFuY2VMb2dnaW5nICYmIHRoaXMucmVtb3RlKSB7XG4gICAgbG9nLmRlYnVnKGBTdGFydGluZyBwZXJmb3JtYW5jZSBsb2cgb24gJyR7dGhpcy5jdXJDb250ZXh0fSdgKTtcbiAgICB0aGlzLmxvZ3MucGVyZm9ybWFuY2UgPSBuZXcgSU9TUGVyZm9ybWFuY2VMb2codGhpcy5yZW1vdGUpO1xuICAgIGF3YWl0IHRoaXMubG9ncy5wZXJmb3JtYW5jZS5zdGFydENhcHR1cmUoKTtcbiAgfVxuXG4gIC8vIHN0YXJ0IHNhZmFyaSBsb2dnaW5nIGlmIHRoZSBsb2dzIGhhbmRsZXJzIGFyZSBhY3RpdmVcbiAgaWYgKG5hbWUgJiYgbmFtZSAhPT0gTkFUSVZFX1dJTiAmJiB0aGlzLmxvZ3MpIHtcbiAgICBpZiAodGhpcy5sb2dzLnNhZmFyaUNvbnNvbGUpIHtcbiAgICAgIGF3YWl0IHRoaXMucmVtb3RlLnN0YXJ0Q29uc29sZSh0aGlzLmxvZ3Muc2FmYXJpQ29uc29sZS5hZGRMb2dMaW5lLmJpbmQodGhpcy5sb2dzLnNhZmFyaUNvbnNvbGUpKTtcbiAgICB9XG4gICAgaWYgKHRoaXMubG9ncy5zYWZhcmlOZXR3b3JrKSB7XG4gICAgICBhd2FpdCB0aGlzLnJlbW90ZS5zdGFydE5ldHdvcmsodGhpcy5sb2dzLnNhZmFyaU5ldHdvcmsuYWRkTG9nTGluZS5iaW5kKHRoaXMubG9ncy5zYWZhcmlOZXR3b3JrKSk7XG4gICAgfVxuICB9XG59O1xuXG5leHRlbnNpb25zLmNvbm5lY3RUb1JlbW90ZURlYnVnZ2VyID0gYXN5bmMgZnVuY3Rpb24gY29ubmVjdFRvUmVtb3RlRGVidWdnZXIgKCkge1xuICB0aGlzLnJlbW90ZSA9IGF3YWl0IHRoaXMuZ2V0TmV3UmVtb3RlRGVidWdnZXIoKTtcblxuICB0aGlzLnJlbW90ZS5vbihSZW1vdGVEZWJ1Z2dlci5FVkVOVF9QQUdFX0NIQU5HRSwgdGhpcy5vblBhZ2VDaGFuZ2UuYmluZCh0aGlzKSk7XG4gIHRoaXMucmVtb3RlLm9uKFJlbW90ZURlYnVnZ2VyLkVWRU5UX0ZSQU1FU19ERVRBQ0hFRCwgKCkgPT4ge1xuICAgIGlmICghXy5pc0VtcHR5KHRoaXMuY3VyV2ViRnJhbWVzKSkge1xuICAgICAgbG9nLmRlYnVnKGBDbGVhcmluZyAke3V0aWwucGx1cmFsaXplKCdmcmFtZScsIHRoaXMuY3VyV2ViRnJhbWVzLmxlbmd0aCwgdHJ1ZSl9OiAke3RoaXMuY3VyV2ViRnJhbWVzLmpvaW4oJywgJyl9YCk7XG4gICAgfVxuICAgIHRoaXMuY3VyV2ViRnJhbWVzID0gW107XG4gIH0pO1xuXG4gIGF3YWl0IHRoaXMucmVtb3RlLmNvbm5lY3QodGhpcy5vcHRzLndlYnZpZXdDb25uZWN0VGltZW91dCk7XG59O1xuXG5leHRlbnNpb25zLmxpc3RXZWJGcmFtZXMgPSBhc3luYyBmdW5jdGlvbiBsaXN0V2ViRnJhbWVzICh1c2VVcmwgPSB0cnVlKSB7XG4gIGlmICghdGhpcy5vcHRzLmJ1bmRsZUlkKSB7XG4gICAgbG9nLmVycm9yQW5kVGhyb3coJ0Nhbm5vdCBlbnRlciB3ZWIgZnJhbWUgd2l0aG91dCBhIGJ1bmRsZSBJRCcpO1xuICB9XG5cbiAgdXNlVXJsID0gdXNlVXJsICYmICF0aGlzLmlzUmVhbERldmljZSgpICYmICEhdGhpcy5nZXRDdXJyZW50VXJsKCk7XG4gIGxvZy5kZWJ1ZyhgU2VsZWN0aW5nIGJ5IHVybDogJHt1c2VVcmx9ICR7dXNlVXJsID8gYChleHBlY3RlZCB1cmw6ICcke3RoaXMuZ2V0Q3VycmVudFVybCgpfScpYCA6ICcnfWApO1xuXG4gIGNvbnN0IGN1cnJlbnRVcmwgPSB1c2VVcmwgPyB0aGlzLmdldEN1cnJlbnRVcmwoKSA6IHVuZGVmaW5lZDtcbiAgbGV0IHBhZ2VBcnJheSA9IFtdO1xuICBjb25zdCBnZXRXZWJ2aWV3UGFnZXMgPSBhc3luYyAoKSA9PiB7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBhd2FpdCB0aGlzLnJlbW90ZS5zZWxlY3RBcHAoY3VycmVudFVybCwgdGhpcy5vcHRzLndlYnZpZXdDb25uZWN0UmV0cmllcywgdGhpcy5vcHRzLmlnbm9yZUFib3V0QmxhbmtVcmwpO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgbG9nLmRlYnVnKGBObyBhdmFpbGFibGUgd2ViIHBhZ2VzOiAke2Vyci5tZXNzYWdlfWApO1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cbiAgfTtcblxuICBpZiAodGhpcy5yZW1vdGUgJiYgdGhpcy5yZW1vdGUuYXBwSWRLZXkpIHtcbiAgICAvLyBhbHJlYWR5IGNvbm5lY3RlZFxuICAgIHBhZ2VBcnJheSA9IGF3YWl0IGdldFdlYnZpZXdQYWdlcygpO1xuICB9IGVsc2Uge1xuICAgIGlmICghdGhpcy5yZW1vdGUpIHtcbiAgICAgIGF3YWl0IHRoaXMuY29ubmVjdFRvUmVtb3RlRGVidWdnZXIoKTtcbiAgICB9XG4gICAgYXdhaXQgdGhpcy5yZW1vdGUuc2V0Q29ubmVjdGlvbktleSgpO1xuXG4gICAgcGFnZUFycmF5ID0gYXdhaXQgZ2V0V2Vidmlld1BhZ2VzKCk7XG5cbiAgICBjb25zdCBhbGVydEVycm9yTXNnID0gJ0Nsb3NlIGFsZXJ0IGZhaWxlZC4gUmV0cnkuJztcbiAgICB0cnkge1xuICAgICAgYXdhaXQgcmV0cnlJbnRlcnZhbCg2LCAxMDAwLCBhc3luYyAoKSA9PiB7XG4gICAgICAgIGlmICghYXdhaXQgdGhpcy5jbG9zZUFsZXJ0QmVmb3JlVGVzdCgpKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGFsZXJ0RXJyb3JNc2cpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIC8vIGlmIHRoZSBsb29wIHRvIGNsb3NlIGFsZXJ0cyBmYWlsZWQgdG8gZGlzbWlzcywgaWdub3JlLFxuICAgICAgLy8gb3RoZXJ3aXNlIGxvZyBhbmQgdGhyb3cgdGhlIGVycm9yXG4gICAgICBpZiAoZXJyLm1lc3NhZ2UgIT09IGFsZXJ0RXJyb3JNc2cpIHtcbiAgICAgICAgbG9nLmVycm9yQW5kVGhyb3coZXJyKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBpZiAocGFnZUFycmF5Lmxlbmd0aCA9PT0gMCkge1xuICAgIC8vIHdlIGhhdmUgbm8gd2ViIGZyYW1lcywgYnV0IGNvbnRpbnVlIGFueXdheVxuICAgIGxvZy5kZWJ1ZygnTm8gd2ViIGZyYW1lcyBmb3VuZC4nKTtcbiAgfVxuICByZXR1cm4gcGFnZUFycmF5O1xufTtcblxuY29tbWFuZHMuZ2V0Q29udGV4dHMgPSBhc3luYyBmdW5jdGlvbiBnZXRDb250ZXh0cyAoKSB7XG4gIGxvZy5kZWJ1ZygnR2V0dGluZyBsaXN0IG9mIGF2YWlsYWJsZSBjb250ZXh0cycpO1xuICBjb25zdCBjb250ZXh0cyA9IGF3YWl0IHRoaXMuZ2V0Q29udGV4dHNBbmRWaWV3cyhmYWxzZSk7XG5cbiAgY29uc3QgbWFwRm4gPSB0aGlzLm9wdHMuZnVsbENvbnRleHRMaXN0XG4gICAgPyBmdW5jdGlvbiAoY29udGV4dCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgaWQ6IGNvbnRleHQuaWQudG9TdHJpbmcoKSxcbiAgICAgICAgdGl0bGU6IGNvbnRleHQudmlldy50aXRsZSxcbiAgICAgICAgdXJsOiBjb250ZXh0LnZpZXcudXJsLFxuICAgICAgICBidW5kbGVJZDogY29udGV4dC52aWV3LmJ1bmRsZUlkLFxuICAgICAgfTtcbiAgICB9XG4gICAgOiAoY29udGV4dCkgPT4gY29udGV4dC5pZC50b1N0cmluZygpO1xuICByZXR1cm4gY29udGV4dHMubWFwKG1hcEZuKTtcbn07XG5cbi8qKlxuICogQHR5cGVkZWYge09iamVjdH0gQ29udGV4dFxuICpcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBpZCAtIFRoZSBpZGVudGlmaWVyIG9mIHRoZSBjb250ZXh0LiBUaGUgbmF0aXZlIGNvbnRleHRcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICB3aWxsIGJlICdOQVRJVkVfQVBQJyBhbmQgdGhlIHdlYnZpZXdzIHdpbGwgYmVcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAnV0VCVklFV194eHgnXG4gKiBAcHJvcGVydHkgez9zdHJpbmd9IHRpdGxlIC0gVGhlIHRpdGxlIGFzc29jaWF0ZWQgd2l0aCB0aGUgd2VidmlldyBjb250ZW50XG4gKiBAcHJvcGVydHkgez9zdHJpbmd9IHVybCAtIFRoZSB1cmwgYXNzb2NpYXRlZCB3aXRoIHRoZSB3ZWJ2aWV3IGNvbnRlbnRcbiAqL1xuXG4vKipcbiAqIEdldCB0aGUgY29udGV4dHMgYXZhaWxhYmxlLCB3aXRoIGluZm9ybWF0aW9uIGFib3V0IHRoZSB1cmwgYW5kIHRpdGxlIG9mIGVhY2hcbiAqIHdlYnZpZXdcbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0cyAtIE9wdGlvbnMgc2V0LCB3aGljaCBjYW4gaW5jbHVkZSBgd2FpdEZvcldlYnZpZXdNc2AgdG9cbiAqICAgICAgICAgICAgICAgICAgICAgICAgc3BlY2lmeSB0aGUgcGVyaW9kIHRvIHBvbGwgZm9yIGF2YWlsYWJsZSB3ZWJ2aWV3c1xuICogQHJldHVybnMge0FycmF5fSBMaXN0IG9mIENvbnRleHQgb2JqZWN0c1xuICovXG5leHRlbnNpb25zLm1vYmlsZUdldENvbnRleHRzID0gYXN5bmMgZnVuY3Rpb24gbW9iaWxlR2V0Q29udGV4dHMgKG9wdHMgPSB7fSkge1xuICBsZXQge1xuICAgIHdhaXRGb3JXZWJ2aWV3TXMgPSAwLFxuICB9ID0gb3B0cztcblxuICAvLyBtYWtlIHN1cmUgaXQgaXMgYSBudW1iZXIsIHNvIHRoZSBkdXJhdGlvbiBjaGVjayB3b3JrcyBwcm9wZXJseVxuICBpZiAoIV8uaXNOdW1iZXIod2FpdEZvcldlYnZpZXdNcykpIHtcbiAgICB3YWl0Rm9yV2Vidmlld01zID0gcGFyc2VJbnQod2FpdEZvcldlYnZpZXdNcywgMTApO1xuICAgIGlmIChpc05hTih3YWl0Rm9yV2Vidmlld01zKSkge1xuICAgICAgd2FpdEZvcldlYnZpZXdNcyA9IDA7XG4gICAgfVxuICB9XG5cbiAgY29uc3QgY3VyT3B0ID0gdGhpcy5vcHRzLmZ1bGxDb250ZXh0TGlzdDtcbiAgLy8gYGdzdC1hdG9tLWlvcy1kcml2ZXIjZ2V0Q29udGV4dHNgIHJldHVybnMgdGhlIGZ1bGwgbGlzdCBvZiBjb250ZXh0c1xuICAvLyBpZiB0aGlzIG9wdGlvbiBpcyBvblxuICB0aGlzLm9wdHMuZnVsbENvbnRleHRMaXN0ID0gdHJ1ZTtcblxuICBjb25zdCB0aW1lciA9IG5ldyB0aW1pbmcuVGltZXIoKS5zdGFydCgpO1xuICB0cnkge1xuICAgIGxldCBjb250ZXh0cztcbiAgICBkbyB7XG4gICAgICBjb250ZXh0cyA9IGF3YWl0IHRoaXMuZ2V0Q29udGV4dHMoKTtcblxuICAgICAgaWYgKGNvbnRleHRzLmxlbmd0aCA+PSAyKSB7XG4gICAgICAgIGxvZy5kZWJ1ZyhgRm91bmQgd2VidmlldyBjb250ZXh0IGFmdGVyICR7dGltZXIuZ2V0RHVyYXRpb24oKS5hc01pbGxpU2Vjb25kcy50b0ZpeGVkKDApfW1zYCk7XG4gICAgICAgIHJldHVybiBjb250ZXh0cztcbiAgICAgIH1cbiAgICAgIGxvZy5kZWJ1ZyhgTm8gd2Vidmlld3MgZm91bmQgaW4gJHt0aW1lci5nZXREdXJhdGlvbigpLmFzTWlsbGlTZWNvbmRzLnRvRml4ZWQoMCl9bXNgKTtcbiAgICB9IHdoaWxlICh0aW1lci5nZXREdXJhdGlvbigpLmFzTWlsbGlTZWNvbmRzIDwgd2FpdEZvcldlYnZpZXdNcyk7XG4gICAgcmV0dXJuIGNvbnRleHRzO1xuICB9IGZpbmFsbHkge1xuICAgIC8vIHJlc2V0IHRoZSBvcHRpb24gc28gdGhlcmUgYXJlIG5vIHNpZGUgZWZmZWN0c1xuICAgIHRoaXMub3B0cy5mdWxsQ29udGV4dExpc3QgPSBjdXJPcHQ7XG4gIH1cbn07XG5cbmNvbW1hbmRzLnNldFdpbmRvdyA9IGFzeW5jIGZ1bmN0aW9uIHNldFdpbmRvdyAobmFtZSwgc2tpcFJlYWR5Q2hlY2spIHtcbiAgdHJ5IHtcbiAgICBhd2FpdCB0aGlzLnNldENvbnRleHQobmFtZSwgXy5ub29wLCBza2lwUmVhZHlDaGVjayk7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIC8vIHRyYW5zbGF0ZSB0aGUgZXJyb3IgaW4gdGVybXMgb2Ygd2luZG93c1xuICAgIHRocm93IGlzRXJyb3JUeXBlKGVyciwgZXJyb3JzLk5vU3VjaENvbnRleHRFcnJvcilcbiAgICAgID8gbmV3IGVycm9ycy5Ob1N1Y2hXaW5kb3dFcnJvcigpXG4gICAgICA6IGVycjtcbiAgfVxufTtcblxuY29tbWFuZHMuZ2V0V2luZG93SGFuZGxlID0gYXN5bmMgZnVuY3Rpb24gZ2V0V2luZG93SGFuZGxlICgpIHsgLy8gZXNsaW50LWRpc2FibGUtbGluZSByZXF1aXJlLWF3YWl0XG4gIGlmICghdGhpcy5pc1dlYkNvbnRleHQoKSkge1xuICAgIHRocm93IG5ldyBlcnJvcnMuTm90SW1wbGVtZW50ZWRFcnJvcigpO1xuICB9XG4gIGxvZy5kZWJ1ZyhgR2V0dGluZyBjdXJyZW50IHdpbmRvdyBoYW5kbGVgKTtcbiAgcmV0dXJuIHRoaXMuY3VyQ29udGV4dDtcbn07XG5cbmNvbW1hbmRzLmdldFdpbmRvd0hhbmRsZXMgPSBhc3luYyBmdW5jdGlvbiBnZXRXaW5kb3dIYW5kbGVzICgpIHtcbiAgaWYgKCF0aGlzLmlzV2ViQ29udGV4dCgpKSB7XG4gICAgdGhyb3cgbmV3IGVycm9ycy5Ob3RJbXBsZW1lbnRlZEVycm9yKCk7XG4gIH1cbiAgbG9nLmRlYnVnKCdHZXR0aW5nIGxpc3Qgb2YgYXZhaWxhYmxlIHdpbmRvdyBoYW5kbGVzJyk7XG4gIGNvbnN0IGNvbnRleHRzID0gYXdhaXQgdGhpcy5nZXRDb250ZXh0c0FuZFZpZXdzKGZhbHNlKTtcbiAgcmV0dX