appium-android-driver 5.13.1 → 5.13.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/build/index.js +43 -40
- package/build/lib/android-helpers.d.ts +136 -0
- package/build/lib/android-helpers.d.ts.map +1 -0
- package/build/lib/android-helpers.js +760 -679
- package/build/lib/android-helpers.js.map +1 -1
- package/build/lib/bootstrap.d.ts +29 -0
- package/build/lib/bootstrap.d.ts.map +1 -0
- package/build/lib/bootstrap.js +192 -179
- package/build/lib/bootstrap.js.map +1 -1
- package/build/lib/commands/actions.d.ts +209 -0
- package/build/lib/commands/actions.d.ts.map +1 -0
- package/build/lib/commands/actions.js +327 -265
- package/build/lib/commands/actions.js.map +1 -1
- package/build/lib/commands/alert.d.ts +10 -0
- package/build/lib/commands/alert.d.ts.map +1 -0
- package/build/lib/commands/alert.js +12 -18
- package/build/lib/commands/alert.js.map +1 -1
- package/build/lib/commands/app-management.d.ts +314 -0
- package/build/lib/commands/app-management.d.ts.map +1 -0
- package/build/lib/commands/app-management.js +278 -110
- package/build/lib/commands/app-management.js.map +1 -1
- package/build/lib/commands/context.d.ts +94 -0
- package/build/lib/commands/context.d.ts.map +1 -0
- package/build/lib/commands/context.js +412 -260
- package/build/lib/commands/context.js.map +1 -1
- package/build/lib/commands/coverage.d.ts +5 -0
- package/build/lib/commands/coverage.d.ts.map +1 -0
- package/build/lib/commands/coverage.js +14 -17
- package/build/lib/commands/coverage.js.map +1 -1
- package/build/lib/commands/element.d.ts +36 -0
- package/build/lib/commands/element.d.ts.map +1 -0
- package/build/lib/commands/element.js +97 -127
- package/build/lib/commands/element.js.map +1 -1
- package/build/lib/commands/emu-console.d.ts +49 -0
- package/build/lib/commands/emu-console.d.ts.map +1 -0
- package/build/lib/commands/emu-console.js +36 -25
- package/build/lib/commands/emu-console.js.map +1 -1
- package/build/lib/commands/execute.d.ts +6 -0
- package/build/lib/commands/execute.d.ts.map +1 -0
- package/build/lib/commands/execute.js +68 -69
- package/build/lib/commands/execute.js.map +1 -1
- package/build/lib/commands/file-actions.d.ts +129 -0
- package/build/lib/commands/file-actions.d.ts.map +1 -0
- package/build/lib/commands/file-actions.js +321 -178
- package/build/lib/commands/file-actions.js.map +1 -1
- package/build/lib/commands/find.d.ts +13 -0
- package/build/lib/commands/find.d.ts.map +1 -0
- package/build/lib/commands/find.js +69 -51
- package/build/lib/commands/find.js.map +1 -1
- package/build/lib/commands/general.d.ts +133 -0
- package/build/lib/commands/general.d.ts.map +1 -0
- package/build/lib/commands/general.js +275 -216
- package/build/lib/commands/general.js.map +1 -1
- package/build/lib/commands/ime.d.ts +11 -0
- package/build/lib/commands/ime.d.ts.map +1 -0
- package/build/lib/commands/ime.js +27 -33
- package/build/lib/commands/ime.js.map +1 -1
- package/build/lib/commands/index.d.ts +3 -0
- package/build/lib/commands/index.d.ts.map +1 -0
- package/build/lib/commands/index.js +32 -35
- package/build/lib/commands/index.js.map +1 -1
- package/build/lib/commands/intent.d.ts +418 -0
- package/build/lib/commands/intent.d.ts.map +1 -0
- package/build/lib/commands/intent.js +281 -151
- package/build/lib/commands/intent.js.map +1 -1
- package/build/lib/commands/keyboard.d.ts +6 -0
- package/build/lib/commands/keyboard.d.ts.map +1 -0
- package/build/lib/commands/keyboard.js +6 -14
- package/build/lib/commands/keyboard.js.map +1 -1
- package/build/lib/commands/log.d.ts +45 -0
- package/build/lib/commands/log.d.ts.map +1 -0
- package/build/lib/commands/log.js +117 -103
- package/build/lib/commands/log.js.map +1 -1
- package/build/lib/commands/media-projection.d.ts +144 -0
- package/build/lib/commands/media-projection.d.ts.map +1 -0
- package/build/lib/commands/media-projection.js +228 -171
- package/build/lib/commands/media-projection.js.map +1 -1
- package/build/lib/commands/network.d.ts +139 -0
- package/build/lib/commands/network.d.ts.map +1 -0
- package/build/lib/commands/network.js +249 -181
- package/build/lib/commands/network.js.map +1 -1
- package/build/lib/commands/performance.d.ts +101 -0
- package/build/lib/commands/performance.d.ts.map +1 -0
- package/build/lib/commands/performance.js +390 -236
- package/build/lib/commands/performance.js.map +1 -1
- package/build/lib/commands/permissions.d.ts +93 -0
- package/build/lib/commands/permissions.d.ts.map +1 -0
- package/build/lib/commands/permissions.js +133 -93
- package/build/lib/commands/permissions.js.map +1 -1
- package/build/lib/commands/recordscreen.d.ts +194 -0
- package/build/lib/commands/recordscreen.d.ts.map +1 -0
- package/build/lib/commands/recordscreen.js +293 -224
- package/build/lib/commands/recordscreen.js.map +1 -1
- package/build/lib/commands/shell.d.ts +8 -0
- package/build/lib/commands/shell.d.ts.map +1 -0
- package/build/lib/commands/shell.js +38 -43
- package/build/lib/commands/shell.js.map +1 -1
- package/build/lib/commands/streamscreen.d.ts +104 -0
- package/build/lib/commands/streamscreen.d.ts.map +1 -0
- package/build/lib/commands/streamscreen.js +364 -305
- package/build/lib/commands/streamscreen.js.map +1 -1
- package/build/lib/commands/system-bars.d.ts +100 -0
- package/build/lib/commands/system-bars.d.ts.map +1 -0
- package/build/lib/commands/system-bars.js +148 -90
- package/build/lib/commands/system-bars.js.map +1 -1
- package/build/lib/commands/touch.d.ts +30 -0
- package/build/lib/commands/touch.d.ts.map +1 -0
- package/build/lib/commands/touch.js +311 -287
- package/build/lib/commands/touch.js.map +1 -1
- package/build/lib/desired-caps.d.ts +353 -0
- package/build/lib/desired-caps.d.ts.map +1 -0
- package/build/lib/desired-caps.js +291 -292
- package/build/lib/desired-caps.js.map +1 -1
- package/build/lib/driver.d.ts +430 -0
- package/build/lib/driver.d.ts.map +1 -0
- package/build/lib/driver.js +449 -384
- package/build/lib/driver.js.map +1 -1
- package/build/lib/logger.d.ts +3 -0
- package/build/lib/logger.d.ts.map +1 -0
- package/build/lib/logger.js +5 -11
- package/build/lib/logger.js.map +1 -1
- package/build/lib/method-map.d.ts +389 -0
- package/build/lib/method-map.d.ts.map +1 -0
- package/build/lib/method-map.js +220 -394
- package/build/lib/method-map.js.map +1 -1
- package/build/lib/stubs.d.ts +8 -0
- package/build/lib/stubs.d.ts.map +1 -0
- package/build/lib/stubs.js +5 -0
- package/build/lib/stubs.js.map +1 -0
- package/build/lib/uiautomator.d.ts +24 -0
- package/build/lib/uiautomator.d.ts.map +1 -0
- package/build/lib/uiautomator.js +86 -82
- package/build/lib/uiautomator.js.map +1 -1
- package/build/lib/unlock-helpers.d.ts +38 -0
- package/build/lib/unlock-helpers.d.ts.map +1 -0
- package/build/lib/unlock-helpers.js +228 -204
- package/build/lib/unlock-helpers.js.map +1 -1
- package/build/lib/utils.d.ts +11 -0
- package/build/lib/utils.d.ts.map +1 -0
- package/build/lib/utils.js +23 -18
- package/build/lib/utils.js.map +1 -1
- package/build/lib/webview-helpers.d.ts +223 -0
- package/build/lib/webview-helpers.d.ts.map +1 -0
- package/build/lib/webview-helpers.js +476 -298
- package/build/lib/webview-helpers.js.map +1 -1
- package/index.js +3 -1
- package/lib/android-helpers.js +2 -1
- package/lib/stubs.ts +8 -0
- package/lib/unlock-helpers.js +2 -2
- package/package.json +23 -14
|
@@ -1,320 +1,472 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
Object.
|
|
5
|
-
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
6
17
|
});
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
var
|
|
10
|
-
var
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
var
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.setupNewChromedriver = exports.helpers = exports.commands = void 0;
|
|
30
|
+
const lodash_1 = __importDefault(require("lodash"));
|
|
31
|
+
const appium_chromedriver_1 = __importDefault(require("appium-chromedriver"));
|
|
32
|
+
const portfinder_1 = __importDefault(require("portfinder"));
|
|
33
|
+
const bluebird_1 = __importDefault(require("bluebird"));
|
|
34
|
+
const support_1 = require("@appium/support");
|
|
35
|
+
const driver_1 = require("appium/driver");
|
|
36
|
+
const webview_helpers_1 = __importStar(require("../webview-helpers"));
|
|
37
|
+
const android_helpers_1 = require("../android-helpers");
|
|
19
38
|
const CHROMEDRIVER_AUTODOWNLOAD_FEATURE = 'chromedriver_autodownload';
|
|
20
|
-
let commands = {},
|
|
21
|
-
helpers = {},
|
|
22
|
-
extensions = {};
|
|
23
|
-
exports.helpers = helpers;
|
|
39
|
+
let commands = {}, helpers = {}, extensions = {};
|
|
24
40
|
exports.commands = commands;
|
|
41
|
+
exports.helpers = helpers;
|
|
42
|
+
/* -------------------------------
|
|
43
|
+
* Actual MJSONWP command handlers
|
|
44
|
+
* ------------------------------- */
|
|
25
45
|
commands.getCurrentContext = async function getCurrentContext() {
|
|
26
|
-
|
|
46
|
+
// if the current context is `null`, indicating no context
|
|
47
|
+
// explicitly set, it is the default context
|
|
48
|
+
return this.curContext || this.defaultContextName();
|
|
27
49
|
};
|
|
28
50
|
commands.getContexts = async function getContexts() {
|
|
29
|
-
|
|
30
|
-
|
|
51
|
+
const webviewsMapping = await webview_helpers_1.default.getWebViewsMapping(this.adb, this.opts);
|
|
52
|
+
return this.assignContexts(webviewsMapping);
|
|
31
53
|
};
|
|
32
54
|
commands.setContext = async function setContext(name) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
name
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
55
|
+
if (!support_1.util.hasValue(name)) {
|
|
56
|
+
name = this.defaultContextName();
|
|
57
|
+
}
|
|
58
|
+
else if (name === webview_helpers_1.WEBVIEW_WIN) {
|
|
59
|
+
// handle setContext "WEBVIEW"
|
|
60
|
+
name = this.defaultWebviewName();
|
|
61
|
+
}
|
|
62
|
+
// if we're already in the context we want, do nothing
|
|
63
|
+
if (name === this.curContext) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const webviewsMapping = await webview_helpers_1.default.getWebViewsMapping(this.adb, this.opts);
|
|
67
|
+
const contexts = this.assignContexts(webviewsMapping);
|
|
68
|
+
// if the context we want doesn't exist, fail
|
|
69
|
+
if (!lodash_1.default.includes(contexts, name)) {
|
|
70
|
+
throw new driver_1.errors.NoSuchContextError();
|
|
71
|
+
}
|
|
72
|
+
await this.switchContext(name, webviewsMapping);
|
|
73
|
+
this.curContext = name;
|
|
48
74
|
};
|
|
75
|
+
/**
|
|
76
|
+
* @typedef {Object} WebviewsMapping
|
|
77
|
+
* @property {string} proc The name of the Devtools Unix socket
|
|
78
|
+
* @property {string} webview The web view alias. Looks like `WEBVIEW_`
|
|
79
|
+
* prefix plus PID or package name
|
|
80
|
+
* @property {?Object} info Webview information as it is retrieved by
|
|
81
|
+
* /json/version CDP endpoint
|
|
82
|
+
* @property {?Array<Object>} pages Webview pages list as it is retrieved by
|
|
83
|
+
* /json/list CDP endpoint
|
|
84
|
+
* @propery {?string} webviewName An actual webview name for switching context.
|
|
85
|
+
* This value becomes null when failing to find a PID for a webview.
|
|
86
|
+
*
|
|
87
|
+
* The following json demonstrates the example of WebviewsMapping object.
|
|
88
|
+
* Note that `description` in `page` can be an empty string most likely when it comes to Mobile Chrome)
|
|
89
|
+
* {
|
|
90
|
+
* "proc": "@webview_devtools_remote_22138",
|
|
91
|
+
* "webview": "WEBVIEW_22138",
|
|
92
|
+
* "info": {
|
|
93
|
+
* "Android-Package": "io.appium.settings",
|
|
94
|
+
* "Browser": "Chrome/74.0.3729.185",
|
|
95
|
+
* "Protocol-Version": "1.3",
|
|
96
|
+
* "User-Agent": "Mozilla/5.0 (Linux; Android 10; Android SDK built for x86 Build/QSR1.190920.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/74.0.3729.185 Mobile Safari/537.36",
|
|
97
|
+
* "V8-Version": "7.4.288.28",
|
|
98
|
+
* "WebKit-Version": "537.36 (@22955682f94ce09336197bfb8dffea991fa32f0d)",
|
|
99
|
+
* "webSocketDebuggerUrl": "ws://127.0.0.1:10900/devtools/browser"
|
|
100
|
+
* },
|
|
101
|
+
* "pages": [
|
|
102
|
+
* {
|
|
103
|
+
* "description": "{\"attached\":true,\"empty\":false,\"height\":1458,\"screenX\":0,\"screenY\":336,\"visible\":true,\"width\":1080}",
|
|
104
|
+
* "devtoolsFrontendUrl": "http://chrome-devtools-frontend.appspot.com/serve_rev/@22955682f94ce09336197bfb8dffea991fa32f0d/inspector.html?ws=127.0.0.1:10900/devtools/page/27325CC50B600D31B233F45E09487B1F",
|
|
105
|
+
* "id": "27325CC50B600D31B233F45E09487B1F",
|
|
106
|
+
* "title": "Releases · appium/appium · GitHub",
|
|
107
|
+
* "type": "page",
|
|
108
|
+
* "url": "https://github.com/appium/appium/releases",
|
|
109
|
+
* "webSocketDebuggerUrl": "ws://127.0.0.1:10900/devtools/page/27325CC50B600D31B233F45E09487B1F"
|
|
110
|
+
* }
|
|
111
|
+
* ],
|
|
112
|
+
* "webviewName": "WEBVIEW_com.io.appium.setting"
|
|
113
|
+
* }
|
|
114
|
+
*/
|
|
115
|
+
/**
|
|
116
|
+
* Returns a webviewsMapping based on CDP endpoints
|
|
117
|
+
*
|
|
118
|
+
* @return {Array<WebviewsMapping>} webviewsMapping
|
|
119
|
+
*/
|
|
49
120
|
commands.mobileGetContexts = async function mobileGetContexts() {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
121
|
+
const opts = {
|
|
122
|
+
androidDeviceSocket: this.opts.androidDeviceSocket,
|
|
123
|
+
ensureWebviewsHavePages: true,
|
|
124
|
+
webviewDevtoolsPort: this.opts.webviewDevtoolsPort,
|
|
125
|
+
enableWebviewDetailsCollection: true
|
|
126
|
+
};
|
|
127
|
+
return await webview_helpers_1.default.getWebViewsMapping(this.adb, opts);
|
|
57
128
|
};
|
|
58
129
|
helpers.assignContexts = function assignContexts(webviewsMapping) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
this.log.debug(`Available contexts: ${JSON.stringify(this.contexts)}`);
|
|
65
|
-
return this.contexts;
|
|
130
|
+
const opts = Object.assign({ isChromeSession: this.isChromeSession }, this.opts);
|
|
131
|
+
const webviews = webview_helpers_1.default.parseWebviewNames(webviewsMapping, opts);
|
|
132
|
+
this.contexts = [webview_helpers_1.NATIVE_WIN, ...webviews];
|
|
133
|
+
this.log.debug(`Available contexts: ${JSON.stringify(this.contexts)}`);
|
|
134
|
+
return this.contexts;
|
|
66
135
|
};
|
|
67
136
|
helpers.switchContext = async function switchContext(name, webviewsMapping) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
137
|
+
// We have some options when it comes to webviews. If we want a
|
|
138
|
+
// Chromedriver webview, we can only control one at a time.
|
|
139
|
+
if (this.isChromedriverContext(name)) {
|
|
140
|
+
// start proxying commands directly to chromedriver
|
|
141
|
+
await this.startChromedriverProxy(name, webviewsMapping);
|
|
142
|
+
}
|
|
143
|
+
else if (this.isChromedriverContext(this.curContext)) {
|
|
144
|
+
// if we're moving to a non-chromedriver webview, and our current context
|
|
145
|
+
// _is_ a chromedriver webview, if caps recreateChromeDriverSessions is set
|
|
146
|
+
// to true then kill chromedriver session using stopChromedriverProxies or
|
|
147
|
+
// else simply suspend proxying to the latter
|
|
148
|
+
if (this.opts.recreateChromeDriverSessions) {
|
|
149
|
+
this.log.debug('recreateChromeDriverSessions set to true; killing existing chromedrivers');
|
|
150
|
+
await this.stopChromedriverProxies();
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
await this.suspendChromedriverProxy();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
throw new Error(`Didn't know how to handle switching to context '${name}'`);
|
|
76
158
|
}
|
|
77
|
-
} else {
|
|
78
|
-
throw new Error(`Didn't know how to handle switching to context '${name}'`);
|
|
79
|
-
}
|
|
80
159
|
};
|
|
160
|
+
/* ---------------------------------
|
|
161
|
+
* On-object context-related helpers
|
|
162
|
+
* --------------------------------- */
|
|
163
|
+
// The reason this is a function and not just a constant is that both android-
|
|
164
|
+
// driver and selendroid-driver use this logic, and each one returns
|
|
165
|
+
// a different default context name
|
|
81
166
|
helpers.defaultContextName = function defaultContextName() {
|
|
82
|
-
|
|
167
|
+
return webview_helpers_1.NATIVE_WIN;
|
|
83
168
|
};
|
|
84
169
|
helpers.defaultWebviewName = function defaultWebviewName() {
|
|
85
|
-
|
|
170
|
+
return webview_helpers_1.WEBVIEW_BASE + (this.opts.autoWebviewName || this.opts.appPackage);
|
|
86
171
|
};
|
|
87
172
|
helpers.isWebContext = function isWebContext() {
|
|
88
|
-
|
|
173
|
+
return this.curContext !== null && this.curContext !== webview_helpers_1.NATIVE_WIN;
|
|
89
174
|
};
|
|
175
|
+
// Turn on proxying to an existing Chromedriver session or a new one
|
|
90
176
|
helpers.startChromedriverProxy = async function startChromedriverProxy(context, webviewsMapping) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const appState = await this.queryAppState(knownPackage);
|
|
113
|
-
if (_lodash.default.includes([_androidHelpers.APP_STATE.RUNNING_IN_BACKGROUND, _androidHelpers.APP_STATE.RUNNING_IN_FOREGROUND], appState)) {
|
|
114
|
-
opts.chromeAndroidPackage = knownPackage;
|
|
115
|
-
this.log.debug(`Identified chromeAndroidPackage as '${opts.chromeAndroidPackage}' ` + `for context '${context}' by querying states of Chrome app packages`);
|
|
116
|
-
break;
|
|
177
|
+
this.log.debug(`Connecting to chrome-backed webview context '${context}'`);
|
|
178
|
+
let cd;
|
|
179
|
+
if (this.sessionChromedrivers[context]) {
|
|
180
|
+
// in the case where we've already set up a chromedriver for a context,
|
|
181
|
+
// we want to reconnect to it, not create a whole new one
|
|
182
|
+
this.log.debug(`Found existing Chromedriver for context '${context}'. Using it.`);
|
|
183
|
+
cd = this.sessionChromedrivers[context];
|
|
184
|
+
await setupExistingChromedriver(this.log, cd);
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
let opts = lodash_1.default.cloneDeep(this.opts);
|
|
188
|
+
opts.chromeUseRunningApp = true;
|
|
189
|
+
// if requested, tell chromedriver to attach to the android package we have
|
|
190
|
+
// associated with the context name, rather than the package of the AUT.
|
|
191
|
+
// And turn this on by default for chrome--if chrome pops up with a webview
|
|
192
|
+
// and someone wants to switch to it, we should let chromedriver connect to
|
|
193
|
+
// chrome rather than staying stuck on the AUT
|
|
194
|
+
if (opts.extractChromeAndroidPackageFromContextName || context === `${webview_helpers_1.WEBVIEW_BASE}chrome`) {
|
|
195
|
+
let androidPackage = context.match(`${webview_helpers_1.WEBVIEW_BASE}(.+)`);
|
|
196
|
+
if (androidPackage && androidPackage.length > 0) {
|
|
197
|
+
opts.chromeAndroidPackage = androidPackage[1];
|
|
117
198
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
199
|
+
if (!opts.extractChromeAndroidPackageFromContextName) {
|
|
200
|
+
if (lodash_1.default.has(this.opts, 'enableWebviewDetailsCollection') && !this.opts.enableWebviewDetailsCollection) {
|
|
201
|
+
// When enableWebviewDetailsCollection capability is explicitly disabled, try to identify
|
|
202
|
+
// chromeAndroidPackage based on contexts, known chrome variant packages and queryAppState result
|
|
203
|
+
// since webviewsMapping does not have info object
|
|
204
|
+
const contexts = webviewsMapping.map((wm) => wm.webviewName);
|
|
205
|
+
for (const knownPackage of webview_helpers_1.KNOWN_CHROME_PACKAGE_NAMES) {
|
|
206
|
+
if (lodash_1.default.includes(contexts, `${webview_helpers_1.WEBVIEW_BASE}${knownPackage}`)) {
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
const appState = await this.queryAppState(knownPackage);
|
|
210
|
+
if (lodash_1.default.includes([android_helpers_1.APP_STATE.RUNNING_IN_BACKGROUND, android_helpers_1.APP_STATE.RUNNING_IN_FOREGROUND], appState)) {
|
|
211
|
+
opts.chromeAndroidPackage = knownPackage;
|
|
212
|
+
this.log.debug(`Identified chromeAndroidPackage as '${opts.chromeAndroidPackage}' ` +
|
|
213
|
+
`for context '${context}' by querying states of Chrome app packages`);
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
for (const wm of webviewsMapping) {
|
|
220
|
+
if (wm.webviewName === context && lodash_1.default.has(wm?.info, 'Android-Package')) {
|
|
221
|
+
opts.chromeAndroidPackage = wm.info['Android-Package'];
|
|
222
|
+
this.log.debug(`Identified chromeAndroidPackage as '${opts.chromeAndroidPackage}' ` +
|
|
223
|
+
`for context '${context}' by CDP`);
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
125
228
|
}
|
|
126
|
-
}
|
|
127
229
|
}
|
|
128
|
-
|
|
230
|
+
cd = await this.setupNewChromedriver(opts, this.adb.curDeviceId, this.adb, context);
|
|
231
|
+
// bind our stop/exit handler, passing in context so we know which
|
|
232
|
+
// one stopped unexpectedly
|
|
233
|
+
cd.on(appium_chromedriver_1.default.EVENT_CHANGED, (msg) => {
|
|
234
|
+
if (msg.state === appium_chromedriver_1.default.STATE_STOPPED) {
|
|
235
|
+
this.onChromedriverStop(context);
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
// save the chromedriver object under the context
|
|
239
|
+
this.sessionChromedrivers[context] = cd;
|
|
129
240
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
});
|
|
136
|
-
this.sessionChromedrivers[context] = cd;
|
|
137
|
-
}
|
|
138
|
-
this.chromedriver = cd;
|
|
139
|
-
this.proxyReqRes = this.chromedriver.proxyReq.bind(this.chromedriver);
|
|
140
|
-
this.proxyCommand = this.chromedriver.jwproxy.command.bind(this.chromedriver.jwproxy);
|
|
141
|
-
this.jwpProxyActive = true;
|
|
241
|
+
// hook up the local variables so we can proxy this biz
|
|
242
|
+
this.chromedriver = cd;
|
|
243
|
+
this.proxyReqRes = this.chromedriver.proxyReq.bind(this.chromedriver);
|
|
244
|
+
this.proxyCommand = this.chromedriver.jwproxy.command.bind(this.chromedriver.jwproxy);
|
|
245
|
+
this.jwpProxyActive = true;
|
|
142
246
|
};
|
|
247
|
+
// Stop proxying to any Chromedriver
|
|
143
248
|
helpers.suspendChromedriverProxy = function suspendChromedriverProxy() {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
249
|
+
this.chromedriver = null;
|
|
250
|
+
this.proxyReqRes = null;
|
|
251
|
+
this.proxyCommand = null;
|
|
252
|
+
this.jwpProxyActive = false;
|
|
148
253
|
};
|
|
254
|
+
// Handle an out-of-band Chromedriver stop event
|
|
149
255
|
helpers.onChromedriverStop = async function onChromedriverStop(context) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
256
|
+
this.log.warn(`Chromedriver for context ${context} stopped unexpectedly`);
|
|
257
|
+
if (context === this.curContext) {
|
|
258
|
+
// we exited unexpectedly while automating the current context and so want
|
|
259
|
+
// to shut down the session and respond with an error
|
|
260
|
+
let err = new Error('Chromedriver quit unexpectedly during session');
|
|
261
|
+
await this.startUnexpectedShutdown(err);
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
// if a Chromedriver in the non-active context barfs, we don't really
|
|
265
|
+
// care, we'll just make a new one next time we need the context.
|
|
266
|
+
this.log.warn("Chromedriver quit unexpectedly, but it wasn't the active " +
|
|
267
|
+
'context, ignoring');
|
|
268
|
+
delete this.sessionChromedrivers[context];
|
|
269
|
+
}
|
|
158
270
|
};
|
|
271
|
+
// Intentionally stop all the chromedrivers currently active, and ignore
|
|
272
|
+
// their exit events
|
|
159
273
|
helpers.stopChromedriverProxies = async function stopChromedriverProxies() {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
274
|
+
this.suspendChromedriverProxy(); // make sure we turn off the proxy flag
|
|
275
|
+
for (let context of lodash_1.default.keys(this.sessionChromedrivers)) {
|
|
276
|
+
let cd = this.sessionChromedrivers[context];
|
|
277
|
+
this.log.debug(`Stopping chromedriver for context ${context}`);
|
|
278
|
+
// stop listening for the stopped state event
|
|
279
|
+
cd.removeAllListeners(appium_chromedriver_1.default.EVENT_CHANGED);
|
|
280
|
+
try {
|
|
281
|
+
await cd.stop();
|
|
282
|
+
}
|
|
283
|
+
catch (err) {
|
|
284
|
+
this.log.warn(`Error stopping Chromedriver: ${err.message}`);
|
|
285
|
+
}
|
|
286
|
+
delete this.sessionChromedrivers[context];
|
|
169
287
|
}
|
|
170
|
-
delete this.sessionChromedrivers[context];
|
|
171
|
-
}
|
|
172
288
|
};
|
|
173
289
|
helpers.isChromedriverContext = function isChromedriverContext(viewName) {
|
|
174
|
-
|
|
290
|
+
return lodash_1.default.includes(viewName, webview_helpers_1.WEBVIEW_WIN) || viewName === webview_helpers_1.CHROMIUM_WIN;
|
|
175
291
|
};
|
|
176
292
|
helpers.shouldDismissChromeWelcome = function shouldDismissChromeWelcome() {
|
|
177
|
-
|
|
293
|
+
return !!this.opts.chromeOptions &&
|
|
294
|
+
lodash_1.default.isArray(this.opts.chromeOptions.args) &&
|
|
295
|
+
this.opts.chromeOptions.args.includes('--no-first-run');
|
|
178
296
|
};
|
|
179
297
|
helpers.dismissChromeWelcome = async function dismissChromeWelcome() {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
await this.click(el.ELEMENT);
|
|
188
|
-
try {
|
|
189
|
-
let el = await this.findElOrEls('id', 'com.android.chrome:id/negative_button', false);
|
|
298
|
+
this.log.info('Trying to dismiss Chrome welcome');
|
|
299
|
+
let activity = await this.getCurrentActivity();
|
|
300
|
+
if (activity !== 'org.chromium.chrome.browser.firstrun.FirstRunActivity') {
|
|
301
|
+
this.log.info('Chrome welcome dialog never showed up! Continuing');
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
let el = await this.findElOrEls('id', 'com.android.chrome:id/terms_accept', false);
|
|
190
305
|
await this.click(el.ELEMENT);
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
306
|
+
try {
|
|
307
|
+
let el = await this.findElOrEls('id', 'com.android.chrome:id/negative_button', false);
|
|
308
|
+
await this.click(el.ELEMENT);
|
|
309
|
+
}
|
|
310
|
+
catch (e) {
|
|
311
|
+
// DO NOTHING, THIS DEVICE DIDNT LAUNCH THE SIGNIN DIALOG
|
|
312
|
+
// IT MUST BE A NON GMS DEVICE
|
|
313
|
+
this.log.warn(`This device did not show Chrome SignIn dialog, ${e.message}`);
|
|
314
|
+
}
|
|
194
315
|
};
|
|
195
316
|
helpers.startChromeSession = async function startChromeSession() {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
317
|
+
this.log.info('Starting a chrome-based browser session');
|
|
318
|
+
let opts = lodash_1.default.cloneDeep(this.opts);
|
|
319
|
+
const knownPackages = [
|
|
320
|
+
'org.chromium.chrome.shell',
|
|
321
|
+
'com.android.chrome',
|
|
322
|
+
'com.chrome.beta',
|
|
323
|
+
'org.chromium.chrome',
|
|
324
|
+
'org.chromium.webview_shell',
|
|
325
|
+
];
|
|
326
|
+
if (lodash_1.default.includes(knownPackages, this.opts.appPackage)) {
|
|
327
|
+
opts.chromeBundleId = this.opts.appPackage;
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
opts.chromeAndroidActivity = this.opts.appActivity;
|
|
331
|
+
}
|
|
332
|
+
this.chromedriver = await this.setupNewChromedriver(opts, this.adb.curDeviceId, this.adb);
|
|
333
|
+
this.chromedriver.on(appium_chromedriver_1.default.EVENT_CHANGED, (msg) => {
|
|
334
|
+
if (msg.state === appium_chromedriver_1.default.STATE_STOPPED) {
|
|
335
|
+
this.onChromedriverStop(webview_helpers_1.CHROMIUM_WIN);
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
// Now that we have a Chrome session, we ensure that the context is
|
|
339
|
+
// appropriately set and that this chromedriver is added to the list
|
|
340
|
+
// of session chromedrivers so we can switch back and forth
|
|
341
|
+
this.curContext = webview_helpers_1.CHROMIUM_WIN;
|
|
342
|
+
this.sessionChromedrivers[webview_helpers_1.CHROMIUM_WIN] = this.chromedriver;
|
|
343
|
+
this.proxyReqRes = this.chromedriver.proxyReq.bind(this.chromedriver);
|
|
344
|
+
this.proxyCommand = this.chromedriver.jwproxy.command.bind(this.chromedriver.jwproxy);
|
|
345
|
+
this.jwpProxyActive = true;
|
|
346
|
+
if (this.shouldDismissChromeWelcome()) {
|
|
347
|
+
// dismiss Chrome welcome dialog
|
|
348
|
+
await this.dismissChromeWelcome();
|
|
208
349
|
}
|
|
209
|
-
});
|
|
210
|
-
this.curContext = _webviewHelpers.CHROMIUM_WIN;
|
|
211
|
-
this.sessionChromedrivers[_webviewHelpers.CHROMIUM_WIN] = this.chromedriver;
|
|
212
|
-
this.proxyReqRes = this.chromedriver.proxyReq.bind(this.chromedriver);
|
|
213
|
-
this.proxyCommand = this.chromedriver.jwproxy.command.bind(this.chromedriver.jwproxy);
|
|
214
|
-
this.jwpProxyActive = true;
|
|
215
|
-
if (this.shouldDismissChromeWelcome()) {
|
|
216
|
-
await this.dismissChromeWelcome();
|
|
217
|
-
}
|
|
218
350
|
};
|
|
351
|
+
/* --------------------------
|
|
352
|
+
* Internal library functions
|
|
353
|
+
* -------------------------- */
|
|
219
354
|
async function setupExistingChromedriver(log, chromedriver) {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
await chromedriver.
|
|
223
|
-
|
|
224
|
-
|
|
355
|
+
// check the status by sending a simple window-based command to ChromeDriver
|
|
356
|
+
// if there is an error, we want to recreate the ChromeDriver session
|
|
357
|
+
if (!await chromedriver.hasWorkingWebview()) {
|
|
358
|
+
log.debug('ChromeDriver is not associated with a window. ' +
|
|
359
|
+
'Re-initializing the session.');
|
|
360
|
+
await chromedriver.restart();
|
|
361
|
+
}
|
|
362
|
+
return chromedriver;
|
|
225
363
|
}
|
|
364
|
+
/**
|
|
365
|
+
* Find a free port to have Chromedriver listen on.
|
|
366
|
+
*
|
|
367
|
+
* @param {array} portSpec - Array which is a list of ports. A list item may
|
|
368
|
+
* also itself be an array of length 2 specifying a start and end port of
|
|
369
|
+
* a range. Some valid port specs:
|
|
370
|
+
* - [8000, 8001, 8002]
|
|
371
|
+
* - [[8000, 8005]]
|
|
372
|
+
* - [8000, [9000, 9100]]
|
|
373
|
+
* @param {Object?} log Logger instance
|
|
374
|
+
*
|
|
375
|
+
* @return {number} A free port
|
|
376
|
+
*/
|
|
226
377
|
async function getChromedriverPort(portSpec, log = null) {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
}
|
|
235
|
-
log === null || log === void 0 ? void 0 : log.debug(`Finding a free port for chromedriver using spec ${JSON.stringify(portSpec)}`);
|
|
236
|
-
let foundPort = null;
|
|
237
|
-
for (const potentialPort of portSpec) {
|
|
238
|
-
let port, stopPort;
|
|
239
|
-
if (_lodash.default.isArray(potentialPort)) {
|
|
240
|
-
[port, stopPort] = potentialPort;
|
|
241
|
-
} else {
|
|
242
|
-
port = parseInt(potentialPort, 10);
|
|
243
|
-
stopPort = port;
|
|
378
|
+
const getPort = bluebird_1.default.promisify(portfinder_1.default.getPort, { context: portfinder_1.default });
|
|
379
|
+
// if the user didn't give us any specific information about chromedriver
|
|
380
|
+
// port ranges, just find any free port
|
|
381
|
+
if (!portSpec) {
|
|
382
|
+
const port = await getPort();
|
|
383
|
+
log?.debug(`A port was not given, using random free port: ${port}`);
|
|
384
|
+
return port;
|
|
244
385
|
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
stopPort
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
386
|
+
// otherwise find the free port based on a list or range provided by the user
|
|
387
|
+
log?.debug(`Finding a free port for chromedriver using spec ${JSON.stringify(portSpec)}`);
|
|
388
|
+
let foundPort = null;
|
|
389
|
+
for (const potentialPort of portSpec) {
|
|
390
|
+
let port, stopPort;
|
|
391
|
+
if (lodash_1.default.isArray(potentialPort)) {
|
|
392
|
+
([port, stopPort] = potentialPort);
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
port = parseInt(potentialPort, 10); // ensure we have a number and not a string
|
|
396
|
+
stopPort = port;
|
|
397
|
+
}
|
|
398
|
+
try {
|
|
399
|
+
log?.debug(`Checking port range ${port}:${stopPort}`);
|
|
400
|
+
foundPort = await getPort({ port, stopPort });
|
|
401
|
+
break;
|
|
402
|
+
}
|
|
403
|
+
catch (e) {
|
|
404
|
+
log?.debug(`Nothing in port range ${port}:${stopPort} was available`);
|
|
405
|
+
}
|
|
254
406
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
407
|
+
if (foundPort === null) {
|
|
408
|
+
throw new Error(`Could not find a free port for chromedriver using ` +
|
|
409
|
+
`chromedriverPorts spec ${JSON.stringify(portSpec)}`);
|
|
410
|
+
}
|
|
411
|
+
log?.debug(`Using free port ${foundPort} for chromedriver`);
|
|
412
|
+
return foundPort;
|
|
261
413
|
}
|
|
262
414
|
helpers.isChromedriverAutodownloadEnabled = function isChromedriverAutodownloadEnabled() {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
415
|
+
if (this.isFeatureEnabled(CHROMEDRIVER_AUTODOWNLOAD_FEATURE)) {
|
|
416
|
+
return true;
|
|
417
|
+
}
|
|
418
|
+
this?.log?.debug(`Automated Chromedriver download is disabled. ` +
|
|
419
|
+
`Use '${CHROMEDRIVER_AUTODOWNLOAD_FEATURE}' server feature to enable it`);
|
|
420
|
+
return false;
|
|
269
421
|
};
|
|
270
422
|
helpers.setupNewChromedriver = async function setupNewChromedriver(opts, curDeviceId, adb, context = null) {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
opts.chromedriverPort
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
423
|
+
if (opts.chromeDriverPort) {
|
|
424
|
+
this?.log?.warn(`The 'chromeDriverPort' capability is deprecated. Please use 'chromedriverPort' instead`);
|
|
425
|
+
opts.chromedriverPort = opts.chromeDriverPort;
|
|
426
|
+
}
|
|
427
|
+
if (opts.chromedriverPort) {
|
|
428
|
+
this?.log?.debug(`Using user-specified port ${opts.chromedriverPort} for chromedriver`);
|
|
429
|
+
}
|
|
430
|
+
else {
|
|
431
|
+
// if a single port wasn't given, we'll look for a free one
|
|
432
|
+
opts.chromedriverPort = await getChromedriverPort(opts.chromedriverPorts, this?.log);
|
|
433
|
+
}
|
|
434
|
+
const details = context ? webview_helpers_1.default.getWebviewDetails(adb, context) : undefined;
|
|
435
|
+
if (!lodash_1.default.isEmpty(details)) {
|
|
436
|
+
this?.log?.debug('Passing web view details to the Chromedriver constructor: ' +
|
|
437
|
+
JSON.stringify(details, null, 2));
|
|
438
|
+
}
|
|
439
|
+
const chromedriver = new appium_chromedriver_1.default({
|
|
440
|
+
port: opts.chromedriverPort,
|
|
441
|
+
executable: opts.chromedriverExecutable,
|
|
442
|
+
adb,
|
|
443
|
+
cmdArgs: opts.chromedriverArgs,
|
|
444
|
+
verbose: !!opts.showChromedriverLog,
|
|
445
|
+
executableDir: opts.chromedriverExecutableDir,
|
|
446
|
+
mappingPath: opts.chromedriverChromeMappingFile,
|
|
447
|
+
bundleId: opts.chromeBundleId,
|
|
448
|
+
useSystemExecutable: opts.chromedriverUseSystemExecutable,
|
|
449
|
+
disableBuildCheck: opts.chromedriverDisableBuildCheck,
|
|
450
|
+
details,
|
|
451
|
+
isAutodownloadEnabled: this?.isChromedriverAutodownloadEnabled?.()
|
|
452
|
+
});
|
|
453
|
+
// make sure there are chromeOptions
|
|
454
|
+
opts.chromeOptions = opts.chromeOptions || {};
|
|
455
|
+
// try out any prefixed chromeOptions,
|
|
456
|
+
// and strip the prefix
|
|
457
|
+
for (const opt of lodash_1.default.keys(opts)) {
|
|
458
|
+
if (opt.endsWith(':chromeOptions')) {
|
|
459
|
+
this?.log?.warn(`Merging '${opt}' into 'chromeOptions'. This may cause unexpected behavior`);
|
|
460
|
+
lodash_1.default.merge(opts.chromeOptions, opts[opt]);
|
|
461
|
+
}
|
|
308
462
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
return chromedriver;
|
|
463
|
+
const caps = webview_helpers_1.default.createChromedriverCaps(opts, curDeviceId, details);
|
|
464
|
+
this?.log?.debug(`Before starting chromedriver, androidPackage is '${caps.chromeOptions.androidPackage}'`);
|
|
465
|
+
await chromedriver.start(caps);
|
|
466
|
+
return chromedriver;
|
|
314
467
|
};
|
|
315
468
|
const setupNewChromedriver = helpers.setupNewChromedriver;
|
|
316
469
|
exports.setupNewChromedriver = setupNewChromedriver;
|
|
317
470
|
Object.assign(extensions, commands, helpers);
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbG9kYXNoIiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfYXBwaXVtQ2hyb21lZHJpdmVyIiwiX3BvcnRmaW5kZXIiLCJfYmx1ZWJpcmQiLCJfc3VwcG9ydCIsIl9kcml2ZXIiLCJfd2Vidmlld0hlbHBlcnMiLCJfaW50ZXJvcFJlcXVpcmVXaWxkY2FyZCIsIl9hbmRyb2lkSGVscGVycyIsIl9nZXRSZXF1aXJlV2lsZGNhcmRDYWNoZSIsIm5vZGVJbnRlcm9wIiwiV2Vha01hcCIsImNhY2hlQmFiZWxJbnRlcm9wIiwiY2FjaGVOb2RlSW50ZXJvcCIsIm9iaiIsIl9fZXNNb2R1bGUiLCJkZWZhdWx0IiwiY2FjaGUiLCJoYXMiLCJnZXQiLCJuZXdPYmoiLCJoYXNQcm9wZXJ0eURlc2NyaXB0b3IiLCJPYmplY3QiLCJkZWZpbmVQcm9wZXJ0eSIsImdldE93blByb3BlcnR5RGVzY3JpcHRvciIsImtleSIsInByb3RvdHlwZSIsImhhc093blByb3BlcnR5IiwiY2FsbCIsImRlc2MiLCJzZXQiLCJDSFJPTUVEUklWRVJfQVVUT0RPV05MT0FEX0ZFQVRVUkUiLCJjb21tYW5kcyIsImhlbHBlcnMiLCJleHRlbnNpb25zIiwiZXhwb3J0cyIsImdldEN1cnJlbnRDb250ZXh0IiwiY3VyQ29udGV4dCIsImRlZmF1bHRDb250ZXh0TmFtZSIsImdldENvbnRleHRzIiwid2Vidmlld3NNYXBwaW5nIiwid2Vidmlld0hlbHBlcnMiLCJnZXRXZWJWaWV3c01hcHBpbmciLCJhZGIiLCJvcHRzIiwiYXNzaWduQ29udGV4dHMiLCJzZXRDb250ZXh0IiwibmFtZSIsInV0aWwiLCJoYXNWYWx1ZSIsIldFQlZJRVdfV0lOIiwiZGVmYXVsdFdlYnZpZXdOYW1lIiwiY29udGV4dHMiLCJfIiwiaW5jbHVkZXMiLCJlcnJvcnMiLCJOb1N1Y2hDb250ZXh0RXJyb3IiLCJzd2l0Y2hDb250ZXh0IiwibW9iaWxlR2V0Q29udGV4dHMiLCJhbmRyb2lkRGV2aWNlU29ja2V0IiwiZW5zdXJlV2Vidmlld3NIYXZlUGFnZXMiLCJ3ZWJ2aWV3RGV2dG9vbHNQb3J0IiwiZW5hYmxlV2Vidmlld0RldGFpbHNDb2xsZWN0aW9uIiwiYXNzaWduIiwiaXNDaHJvbWVTZXNzaW9uIiwid2Vidmlld3MiLCJwYXJzZVdlYnZpZXdOYW1lcyIsIk5BVElWRV9XSU4iLCJsb2ciLCJkZWJ1ZyIsIkpTT04iLCJzdHJpbmdpZnkiLCJpc0Nocm9tZWRyaXZlckNvbnRleHQiLCJzdGFydENocm9tZWRyaXZlclByb3h5IiwicmVjcmVhdGVDaHJvbWVEcml2ZXJTZXNzaW9ucyIsInN0b3BDaHJvbWVkcml2ZXJQcm94aWVzIiwic3VzcGVuZENocm9tZWRyaXZlclByb3h5IiwiRXJyb3IiLCJXRUJWSUVXX0JBU0UiLCJhdXRvV2Vidmlld05hbWUiLCJhcHBQYWNrYWdlIiwiaXNXZWJDb250ZXh0IiwiY29udGV4dCIsImNkIiwic2Vzc2lvbkNocm9tZWRyaXZlcnMiLCJzZXR1cEV4aXN0aW5nQ2hyb21lZHJpdmVyIiwiY2xvbmVEZWVwIiwiY2hyb21lVXNlUnVubmluZ0FwcCIsImV4dHJhY3RDaHJvbWVBbmRyb2lkUGFja2FnZUZyb21Db250ZXh0TmFtZSIsImFuZHJvaWRQYWNrYWdlIiwibWF0Y2giLCJsZW5ndGgiLCJjaHJvbWVBbmRyb2lkUGFja2FnZSIsIm1hcCIsIndtIiwid2Vidmlld05hbWUiLCJrbm93blBhY2thZ2UiLCJLTk9XTl9DSFJPTUVfUEFDS0FHRV9OQU1FUyIsImFwcFN0YXRlIiwicXVlcnlBcHBTdGF0ZSIsIkFQUF9TVEFURSIsIlJVTk5JTkdfSU5fQkFDS0dST1VORCIsIlJVTk5JTkdfSU5fRk9SRUdST1VORCIsImluZm8iLCJzZXR1cE5ld0Nocm9tZWRyaXZlciIsImN1ckRldmljZUlkIiwib24iLCJDaHJvbWVkcml2ZXIiLCJFVkVOVF9DSEFOR0VEIiwibXNnIiwic3RhdGUiLCJTVEFURV9TVE9QUEVEIiwib25DaHJvbWVkcml2ZXJTdG9wIiwiY2hyb21lZHJpdmVyIiwicHJveHlSZXFSZXMiLCJwcm94eVJlcSIsImJpbmQiLCJwcm94eUNvbW1hbmQiLCJqd3Byb3h5IiwiY29tbWFuZCIsImp3cFByb3h5QWN0aXZlIiwid2FybiIsImVyciIsInN0YXJ0VW5leHBlY3RlZFNodXRkb3duIiwia2V5cyIsInJlbW92ZUFsbExpc3RlbmVycyIsInN0b3AiLCJtZXNzYWdlIiwidmlld05hbWUiLCJDSFJPTUlVTV9XSU4iLCJzaG91bGREaXNtaXNzQ2hyb21lV2VsY29tZSIsImNocm9tZU9wdGlvbnMiLCJpc0FycmF5IiwiYXJncyIsImRpc21pc3NDaHJvbWVXZWxjb21lIiwiYWN0aXZpdHkiLCJnZXRDdXJyZW50QWN0aXZpdHkiLCJlbCIsImZpbmRFbE9yRWxzIiwiY2xpY2siLCJFTEVNRU5UIiwiZSIsInN0YXJ0Q2hyb21lU2Vzc2lvbiIsImtub3duUGFja2FnZXMiLCJjaHJvbWVCdW5kbGVJZCIsImNocm9tZUFuZHJvaWRBY3Rpdml0eSIsImFwcEFjdGl2aXR5IiwiaGFzV29ya2luZ1dlYnZpZXciLCJyZXN0YXJ0IiwiZ2V0Q2hyb21lZHJpdmVyUG9ydCIsInBvcnRTcGVjIiwiZ2V0UG9ydCIsIkIiLCJwcm9taXNpZnkiLCJQb3J0RmluZGVyIiwicG9ydCIsImZvdW5kUG9ydCIsInBvdGVudGlhbFBvcnQiLCJzdG9wUG9ydCIsInBhcnNlSW50IiwiaXNDaHJvbWVkcml2ZXJBdXRvZG93bmxvYWRFbmFibGVkIiwiX3RoaXMkbG9nIiwiaXNGZWF0dXJlRW5hYmxlZCIsIl90aGlzJGlzQ2hyb21lZHJpdmVyQSIsIl90aGlzJGxvZzYiLCJjaHJvbWVEcml2ZXJQb3J0IiwiX3RoaXMkbG9nMiIsImNocm9tZWRyaXZlclBvcnQiLCJfdGhpcyRsb2czIiwiY2hyb21lZHJpdmVyUG9ydHMiLCJkZXRhaWxzIiwiZ2V0V2Vidmlld0RldGFpbHMiLCJ1bmRlZmluZWQiLCJpc0VtcHR5IiwiX3RoaXMkbG9nNCIsImV4ZWN1dGFibGUiLCJjaHJvbWVkcml2ZXJFeGVjdXRhYmxlIiwiY21kQXJncyIsImNocm9tZWRyaXZlckFyZ3MiLCJ2ZXJib3NlIiwic2hvd0Nocm9tZWRyaXZlckxvZyIsImV4ZWN1dGFibGVEaXIiLCJjaHJvbWVkcml2ZXJFeGVjdXRhYmxlRGlyIiwibWFwcGluZ1BhdGgiLCJjaHJvbWVkcml2ZXJDaHJvbWVNYXBwaW5nRmlsZSIsImJ1bmRsZUlkIiwidXNlU3lzdGVtRXhlY3V0YWJsZSIsImNocm9tZWRyaXZlclVzZVN5c3RlbUV4ZWN1dGFibGUiLCJkaXNhYmxlQnVpbGRDaGVjayIsImNocm9tZWRyaXZlckRpc2FibGVCdWlsZENoZWNrIiwiaXNBdXRvZG93bmxvYWRFbmFibGVkIiwib3B0IiwiZW5kc1dpdGgiLCJfdGhpcyRsb2c1IiwibWVyZ2UiLCJjYXBzIiwiY3JlYXRlQ2hyb21lZHJpdmVyQ2FwcyIsInN0YXJ0IiwiX2RlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi8uLi9saWIvY29tbWFuZHMvY29udGV4dC5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgXyBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IENocm9tZWRyaXZlciBmcm9tICdhcHBpdW0tY2hyb21lZHJpdmVyJztcbmltcG9ydCBQb3J0RmluZGVyIGZyb20gJ3BvcnRmaW5kZXInO1xuaW1wb3J0IEIgZnJvbSAnYmx1ZWJpcmQnO1xuaW1wb3J0IHsgdXRpbCB9IGZyb20gJ0BhcHBpdW0vc3VwcG9ydCc7XG5pbXBvcnQgeyBlcnJvcnMgfSBmcm9tICdhcHBpdW0vZHJpdmVyJztcbmltcG9ydCB7XG4gIGRlZmF1bHQgYXMgd2Vidmlld0hlbHBlcnMsXG4gIE5BVElWRV9XSU4sIFdFQlZJRVdfQkFTRSwgV0VCVklFV19XSU4sIENIUk9NSVVNX1dJTiwgS05PV05fQ0hST01FX1BBQ0tBR0VfTkFNRVNcbn0gZnJvbSAnLi4vd2Vidmlldy1oZWxwZXJzJztcbmltcG9ydCB7IEFQUF9TVEFURSB9IGZyb20gJy4uL2FuZHJvaWQtaGVscGVycyc7XG5cbmNvbnN0IENIUk9NRURSSVZFUl9BVVRPRE9XTkxPQURfRkVBVFVSRSA9ICdjaHJvbWVkcml2ZXJfYXV0b2Rvd25sb2FkJztcblxubGV0IGNvbW1hbmRzID0ge30sIGhlbHBlcnMgPSB7fSwgZXh0ZW5zaW9ucyA9IHt9O1xuXG5cbi8qIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqIEFjdHVhbCBNSlNPTldQIGNvbW1hbmQgaGFuZGxlcnNcbiAqIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cbmNvbW1hbmRzLmdldEN1cnJlbnRDb250ZXh0ID0gYXN5bmMgZnVuY3Rpb24gZ2V0Q3VycmVudENvbnRleHQgKCkgeyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIHJlcXVpcmUtYXdhaXRcbiAgLy8gaWYgdGhlIGN1cnJlbnQgY29udGV4dCBpcyBgbnVsbGAsIGluZGljYXRpbmcgbm8gY29udGV4dFxuICAvLyBleHBsaWNpdGx5IHNldCwgaXQgaXMgdGhlIGRlZmF1bHQgY29udGV4dFxuICByZXR1cm4gdGhpcy5jdXJDb250ZXh0IHx8IHRoaXMuZGVmYXVsdENvbnRleHROYW1lKCk7XG59O1xuXG5jb21tYW5kcy5nZXRDb250ZXh0cyA9IGFzeW5jIGZ1bmN0aW9uIGdldENvbnRleHRzICgpIHtcbiAgY29uc3Qgd2Vidmlld3NNYXBwaW5nID0gYXdhaXQgd2Vidmlld0hlbHBlcnMuZ2V0V2ViVmlld3NNYXBwaW5nKHRoaXMuYWRiLCB0aGlzLm9wdHMpO1xuICByZXR1cm4gdGhpcy5hc3NpZ25Db250ZXh0cyh3ZWJ2aWV3c01hcHBpbmcpO1xufTtcblxuY29tbWFuZHMuc2V0Q29udGV4dCA9IGFzeW5jIGZ1bmN0aW9uIHNldENvbnRleHQgKG5hbWUpIHtcbiAgaWYgKCF1dGlsLmhhc1ZhbHVlKG5hbWUpKSB7XG4gICAgbmFtZSA9IHRoaXMuZGVmYXVsdENvbnRleHROYW1lKCk7XG4gIH0gZWxzZSBpZiAobmFtZSA9PT0gV0VCVklFV19XSU4pIHtcbiAgICAvLyBoYW5kbGUgc2V0Q29udGV4dCBcIldFQlZJRVdcIlxuICAgIG5hbWUgPSB0aGlzLmRlZmF1bHRXZWJ2aWV3TmFtZSgpO1xuICB9XG4gIC8vIGlmIHdlJ3JlIGFscmVhZHkgaW4gdGhlIGNvbnRleHQgd2Ugd2FudCwgZG8gbm90aGluZ1xuICBpZiAobmFtZSA9PT0gdGhpcy5jdXJDb250ZXh0KSB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgY29uc3Qgd2Vidmlld3NNYXBwaW5nID0gYXdhaXQgd2Vidmlld0hlbHBlcnMuZ2V0V2ViVmlld3NNYXBwaW5nKHRoaXMuYWRiLCB0aGlzLm9wdHMpO1xuICBjb25zdCBjb250ZXh0cyA9IHRoaXMuYXNzaWduQ29udGV4dHMod2Vidmlld3NNYXBwaW5nKTtcbiAgLy8gaWYgdGhlIGNvbnRleHQgd2Ugd2FudCBkb2Vzbid0IGV4aXN0LCBmYWlsXG4gIGlmICghXy5pbmNsdWRlcyhjb250ZXh0cywgbmFtZSkpIHtcbiAgICB0aHJvdyBuZXcgZXJyb3JzLk5vU3VjaENvbnRleHRFcnJvcigpO1xuICB9XG5cbiAgYXdhaXQgdGhpcy5zd2l0Y2hDb250ZXh0KG5hbWUsIHdlYnZpZXdzTWFwcGluZyk7XG4gIHRoaXMuY3VyQ29udGV4dCA9IG5hbWU7XG59O1xuXG4vKipcbiAqIEB0eXBlZGVmIHtPYmplY3R9IFdlYnZpZXdzTWFwcGluZ1xuICogQHByb3BlcnR5IHtzdHJpbmd9IHByb2MgVGhlIG5hbWUgb2YgdGhlIERldnRvb2xzIFVuaXggc29ja2V0XG4gKiBAcHJvcGVydHkge3N0cmluZ30gd2VidmlldyBUaGUgd2ViIHZpZXcgYWxpYXMuIExvb2tzIGxpa2UgYFdFQlZJRVdfYFxuICogcHJlZml4IHBsdXMgUElEIG9yIHBhY2thZ2UgbmFtZVxuICogQHByb3BlcnR5IHs/T2JqZWN0fSBpbmZvIFdlYnZpZXcgaW5mb3JtYXRpb24gYXMgaXQgaXMgcmV0cmlldmVkIGJ5XG4gKiAvanNvbi92ZXJzaW9uIENEUCBlbmRwb2ludFxuICogQHByb3BlcnR5IHs/QXJyYXk8T2JqZWN0Pn0gcGFnZXMgV2VidmlldyBwYWdlcyBsaXN0IGFzIGl0IGlzIHJldHJpZXZlZCBieVxuICogL2pzb24vbGlzdCBDRFAgZW5kcG9pbnRcbiAqIEBwcm9wZXJ5IHs/c3RyaW5nfSB3ZWJ2aWV3TmFtZSBBbiBhY3R1YWwgd2VidmlldyBuYW1lIGZvciBzd2l0Y2hpbmcgY29udGV4dC5cbiAqIFRoaXMgdmFsdWUgYmVjb21lcyBudWxsIHdoZW4gZmFpbGluZyB0byBmaW5kIGEgUElEIGZvciBhIHdlYnZpZXcuXG4gKlxuICogVGhlIGZvbGxvd2luZyBqc29uIGRlbW9uc3RyYXRlcyB0aGUgZXhhbXBsZSBvZiBXZWJ2aWV3c01hcHBpbmcgb2JqZWN0LlxuICogTm90ZSB0aGF0IGBkZXNjcmlwdGlvbmAgaW4gYHBhZ2VgIGNhbiBiZSBhbiBlbXB0eSBzdHJpbmcgbW9zdCBsaWtlbHkgd2hlbiBpdCBjb21lcyB0byBNb2JpbGUgQ2hyb21lKVxuICoge1xuICogICBcInByb2NcIjogXCJAd2Vidmlld19kZXZ0b29sc19yZW1vdGVfMjIxMzhcIixcbiAqICAgXCJ3ZWJ2aWV3XCI6IFwiV0VCVklFV18yMjEzOFwiLFxuICogICBcImluZm9cIjoge1xuICogICAgIFwiQW5kcm9pZC1QYWNrYWdlXCI6IFwiaW8uYXBwaXVtLnNldHRpbmdzXCIsXG4gKiAgICAgXCJCcm93c2VyXCI6IFwiQ2hyb21lLzc0LjAuMzcyOS4xODVcIixcbiAqICAgICBcIlByb3RvY29sLVZlcnNpb25cIjogXCIxLjNcIixcbiAqICAgICBcIlVzZXItQWdlbnRcIjogXCJNb3ppbGxhLzUuMCAoTGludXg7IEFuZHJvaWQgMTA7IEFuZHJvaWQgU0RLIGJ1aWx0IGZvciB4ODYgQnVpbGQvUVNSMS4xOTA5MjAuMDAxOyB3dikgQXBwbGVXZWJLaXQvNTM3LjM2IChLSFRNTCwgbGlrZSBHZWNrbykgVmVyc2lvbi80LjAgQ2hyb21lLzc0LjAuMzcyOS4xODUgTW9iaWxlIFNhZmFyaS81MzcuMzZcIixcbiAqICAgICBcIlY4LVZlcnNpb25cIjogXCI3LjQuMjg4LjI4XCIsXG4gKiAgICAgXCJXZWJLaXQtVmVyc2lvblwiOiBcIjUzNy4zNiAoQDIyOTU1NjgyZjk0Y2UwOTMzNjE5N2JmYjhkZmZlYTk5MWZhMzJmMGQpXCIsXG4gKiAgICAgXCJ3ZWJTb2NrZXREZWJ1Z2dlclVybFwiOiBcIndzOi8vMTI3LjAuMC4xOjEwOTAwL2RldnRvb2xzL2Jyb3dzZXJcIlxuICogICB9LFxuICogICBcInBhZ2VzXCI6IFtcbiAqICAgICB7XG4gKiAgICAgICBcImRlc2NyaXB0aW9uXCI6IFwie1xcXCJhdHRhY2hlZFxcXCI6dHJ1ZSxcXFwiZW1wdHlcXFwiOmZhbHNlLFxcXCJoZWlnaHRcXFwiOjE0NTgsXFxcInNjcmVlblhcXFwiOjAsXFxcInNjcmVlbllcXFwiOjMzNixcXFwidmlzaWJsZVxcXCI6dHJ1ZSxcXFwid2lkdGhcXFwiOjEwODB9XCIsXG4gKiAgICAgICBcImRldnRvb2xzRnJvbnRlbmRVcmxcIjogXCJodHRwOi8vY2hyb21lLWRldnRvb2xzLWZyb250ZW5kLmFwcHNwb3QuY29tL3NlcnZlX3Jldi9AMjI5NTU2ODJmOTRjZTA5MzM2MTk3YmZiOGRmZmVhOTkxZmEzMmYwZC9pbnNwZWN0b3IuaHRtbD93cz0xMjcuMC4wLjE6MTA5MDAvZGV2dG9vbHMvcGFnZS8yNzMyNUNDNTBCNjAwRDMxQjIzM0Y0NUUwOTQ4N0IxRlwiLFxuICogICAgICAgXCJpZFwiOiBcIjI3MzI1Q0M1MEI2MDBEMzFCMjMzRjQ1RTA5NDg3QjFGXCIsXG4gKiAgICAgICBcInRpdGxlXCI6IFwiUmVsZWFzZXMgwrcgYXBwaXVtL2FwcGl1bSDCtyBHaXRIdWJcIixcbiAqICAgICAgIFwidHlwZVwiOiBcInBhZ2VcIixcbiAqICAgICAgIFwidXJsXCI6IFwiaHR0cHM6Ly9naXRodWIuY29tL2FwcGl1bS9hcHBpdW0vcmVsZWFzZXNcIixcbiAqICAgICAgIFwid2ViU29ja2V0RGVidWdnZXJVcmxcIjogXCJ3czovLzEyNy4wLjAuMToxMDkwMC9kZXZ0b29scy9wYWdlLzI3MzI1Q0M1MEI2MDBEMzFCMjMzRjQ1RTA5NDg3QjFGXCJcbiAqICAgICB9XG4gKiAgIF0sXG4gKiAgIFwid2Vidmlld05hbWVcIjogXCJXRUJWSUVXX2NvbS5pby5hcHBpdW0uc2V0dGluZ1wiXG4gKiB9XG4gKi9cblxuLyoqXG4gKiBSZXR1cm5zIGEgd2Vidmlld3NNYXBwaW5nIGJhc2VkIG9uIENEUCBlbmRwb2ludHNcbiAqXG4gKiBAcmV0dXJuIHtBcnJheTxXZWJ2aWV3c01hcHBpbmc+fSB3ZWJ2aWV3c01hcHBpbmdcbiAqL1xuY29tbWFuZHMubW9iaWxlR2V0Q29udGV4dHMgPSBhc3luYyBmdW5jdGlvbiBtb2JpbGVHZXRDb250ZXh0cyAoKSB7XG4gIGNvbnN0IG9wdHMgPSB7XG4gICAgYW5kcm9pZERldmljZVNvY2tldDogdGhpcy5vcHRzLmFuZHJvaWREZXZpY2VTb2NrZXQsXG4gICAgZW5zdXJlV2Vidmlld3NIYXZlUGFnZXM6IHRydWUsXG4gICAgd2Vidmlld0RldnRvb2xzUG9ydDogdGhpcy5vcHRzLndlYnZpZXdEZXZ0b29sc1BvcnQsXG4gICAgZW5hYmxlV2Vidmlld0RldGFpbHNDb2xsZWN0aW9uOiB0cnVlXG4gIH07XG4gIHJldHVybiBhd2FpdCB3ZWJ2aWV3SGVscGVycy5nZXRXZWJWaWV3c01hcHBpbmcodGhpcy5hZGIsIG9wdHMpO1xufTtcblxuaGVscGVycy5hc3NpZ25Db250ZXh0cyA9IGZ1bmN0aW9uIGFzc2lnbkNvbnRleHRzICh3ZWJ2aWV3c01hcHBpbmcpIHtcbiAgY29uc3Qgb3B0cyA9IE9iamVjdC5hc3NpZ24oe2lzQ2hyb21lU2Vzc2lvbjogdGhpcy5pc0Nocm9tZVNlc3Npb259LCB0aGlzLm9wdHMpO1xuICBjb25zdCB3ZWJ2aWV3cyA9IHdlYnZpZXdIZWxwZXJzLnBhcnNlV2Vidmlld05hbWVzKHdlYnZpZXdzTWFwcGluZywgb3B0cyk7XG4gIHRoaXMuY29udGV4dHMgPSBbTkFUSVZFX1dJTiwgLi4ud2Vidmlld3NdO1xuICB0aGlzLmxvZy5kZWJ1ZyhgQXZhaWxhYmxlIGNvbnRleHRzOiAke0pTT04uc3RyaW5naWZ5KHRoaXMuY29udGV4dHMpfWApO1xuICByZXR1cm4gdGhpcy5jb250ZXh0cztcbn07XG5cbmhlbHBlcnMuc3dpdGNoQ29udGV4dCA9IGFzeW5jIGZ1bmN0aW9uIHN3aXRjaENvbnRleHQgKG5hbWUsIHdlYnZpZXdzTWFwcGluZykge1xuICAvLyBXZSBoYXZlIHNvbWUgb3B0aW9ucyB3aGVuIGl0IGNvbWVzIHRvIHdlYnZpZXdzLiBJZiB3ZSB3YW50IGFcbiAgLy8gQ2hyb21lZHJpdmVyIHdlYnZpZXcsIHdlIGNhbiBvbmx5IGNvbnRyb2wgb25lIGF0IGEgdGltZS5cbiAgaWYgKHRoaXMuaXNDaHJvbWVkcml2ZXJDb250ZXh0KG5hbWUpKSB7XG4gICAgLy8gc3RhcnQgcHJveHlpbmcgY29tbWFuZHMgZGlyZWN0bHkgdG8gY2hyb21lZHJpdmVyXG4gICAgYXdhaXQgdGhpcy5zdGFydENocm9tZWRyaXZlclByb3h5KG5hbWUsIHdlYnZpZXdzTWFwcGluZyk7XG4gIH0gZWxzZSBpZiAodGhpcy5pc0Nocm9tZWRyaXZlckNvbnRleHQodGhpcy5jdXJDb250ZXh0KSkge1xuICAgIC8vIGlmIHdlJ3JlIG1vdmluZyB0byBhIG5vbi1jaHJvbWVkcml2ZXIgd2VidmlldywgYW5kIG91ciBjdXJyZW50IGNvbnRleHRcbiAgICAvLyBfaXNfIGEgY2hyb21lZHJpdmVyIHdlYnZpZXcsIGlmIGNhcHMgcmVjcmVhdGVDaHJvbWVEcml2ZXJTZXNzaW9ucyBpcyBzZXRcbiAgICAvLyB0byB0cnVlIHRoZW4ga2lsbCBjaHJvbWVkcml2ZXIgc2Vzc2lvbiB1c2luZyBzdG9wQ2hyb21lZHJpdmVyUHJveGllcyBvclxuICAgIC8vIGVsc2Ugc2ltcGx5IHN1c3BlbmQgcHJveHlpbmcgdG8gdGhlIGxhdHRlclxuICAgIGlmICh0aGlzLm9wdHMucmVjcmVhdGVDaHJvbWVEcml2ZXJTZXNzaW9ucykge1xuICAgICAgdGhpcy5sb2cuZGVidWcoJ3JlY3JlYXRlQ2hyb21lRHJpdmVyU2Vzc2lvbnMgc2V0IHRvIHRydWU7IGtpbGxpbmcgZXhpc3RpbmcgY2hyb21lZHJpdmVycycpO1xuICAgICAgYXdhaXQgdGhpcy5zdG9wQ2hyb21lZHJpdmVyUHJveGllcygpO1xuICAgIH0gZWxzZSB7XG4gICAgICBhd2FpdCB0aGlzLnN1c3BlbmRDaHJvbWVkcml2ZXJQcm94eSgpO1xuICAgIH1cbiAgfSBlbHNlIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYERpZG4ndCBrbm93IGhvdyB0byBoYW5kbGUgc3dpdGNoaW5nIHRvIGNvbnRleHQgJyR7bmFtZX0nYCk7XG4gIH1cbn07XG5cblxuLyogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiBPbi1vYmplY3QgY29udGV4dC1yZWxhdGVkIGhlbHBlcnNcbiAqIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqL1xuXG4vLyBUaGUgcmVhc29uIHRoaXMgaXMgYSBmdW5jdGlvbiBhbmQgbm90IGp1c3QgYSBjb25zdGFudCBpcyB0aGF0IGJvdGggYW5kcm9pZC1cbi8vIGRyaXZlciBhbmQgc2VsZW5kcm9pZC1kcml2ZXIgdXNlIHRoaXMgbG9naWMsIGFuZCBlYWNoIG9uZSByZXR1cm5zXG4vLyBhIGRpZmZlcmVudCBkZWZhdWx0IGNvbnRleHQgbmFtZVxuaGVscGVycy5kZWZhdWx0Q29udGV4dE5hbWUgPSBmdW5jdGlvbiBkZWZhdWx0Q29udGV4dE5hbWUgKCkge1xuICByZXR1cm4gTkFUSVZFX1dJTjtcbn07XG5cbmhlbHBlcnMuZGVmYXVsdFdlYnZpZXdOYW1lID0gZnVuY3Rpb24gZGVmYXVsdFdlYnZpZXdOYW1lICgpIHtcbiAgcmV0dXJuIFdFQlZJRVdfQkFTRSArICh0aGlzLm9wdHMuYXV0b1dlYnZpZXdOYW1lIHx8IHRoaXMub3B0cy5hcHBQYWNrYWdlKTtcbn07XG5cbmhlbHBlcnMuaXNXZWJDb250ZXh0ID0gZnVuY3Rpb24gaXNXZWJDb250ZXh0ICgpIHtcbiAgcmV0dXJuIHRoaXMuY3VyQ29udGV4dCAhPT0gbnVsbCAmJiB0aGlzLmN1ckNvbnRleHQgIT09IE5BVElWRV9XSU47XG59O1xuXG4vLyBUdXJuIG9uIHByb3h5aW5nIHRvIGFuIGV4aXN0aW5nIENocm9tZWRyaXZlciBzZXNzaW9uIG9yIGEgbmV3IG9uZVxuaGVscGVycy5zdGFydENocm9tZWRyaXZlclByb3h5ID0gYXN5bmMgZnVuY3Rpb24gc3RhcnRDaHJvbWVkcml2ZXJQcm94eSAoY29udGV4dCwgd2Vidmlld3NNYXBwaW5nKSB7XG4gIHRoaXMubG9nLmRlYnVnKGBDb25uZWN0aW5nIHRvIGNocm9tZS1iYWNrZWQgd2VidmlldyBjb250ZXh0ICcke2NvbnRleHR9J2ApO1xuXG4gIGxldCBjZDtcbiAgaWYgKHRoaXMuc2Vzc2lvbkNocm9tZWRyaXZlcnNbY29udGV4dF0pIHtcbiAgICAvLyBpbiB0aGUgY2FzZSB3aGVyZSB3ZSd2ZSBhbHJlYWR5IHNldCB1cCBhIGNocm9tZWRyaXZlciBmb3IgYSBjb250ZXh0LFxuICAgIC8vIHdlIHdhbnQgdG8gcmVjb25uZWN0IHRvIGl0LCBub3QgY3JlYXRlIGEgd2hvbGUgbmV3IG9uZVxuICAgIHRoaXMubG9nLmRlYnVnKGBGb3VuZCBleGlzdGluZyBDaHJvbWVkcml2ZXIgZm9yIGNvbnRleHQgJyR7Y29udGV4dH0nLiBVc2luZyBpdC5gKTtcbiAgICBjZCA9IHRoaXMuc2Vzc2lvbkNocm9tZWRyaXZlcnNbY29udGV4dF07XG4gICAgYXdhaXQgc2V0dXBFeGlzdGluZ0Nocm9tZWRyaXZlcih0aGlzLmxvZywgY2QpO1xuICB9IGVsc2Uge1xuICAgIGxldCBvcHRzID0gXy5jbG9uZURlZXAodGhpcy5vcHRzKTtcbiAgICBvcHRzLmNocm9tZVVzZVJ1bm5pbmdBcHAgPSB0cnVlO1xuXG4gICAgLy8gaWYgcmVxdWVzdGVkLCB0ZWxsIGNocm9tZWRyaXZlciB0byBhdHRhY2ggdG8gdGhlIGFuZHJvaWQgcGFja2FnZSB3ZSBoYXZlXG4gICAgLy8gYXNzb2NpYXRlZCB3aXRoIHRoZSBjb250ZXh0IG5hbWUsIHJhdGhlciB0aGFuIHRoZSBwYWNrYWdlIG9mIHRoZSBBVVQuXG4gICAgLy8gQW5kIHR1cm4gdGhpcyBvbiBieSBkZWZhdWx0IGZvciBjaHJvbWUtLWlmIGNocm9tZSBwb3BzIHVwIHdpdGggYSB3ZWJ2aWV3XG4gICAgLy8gYW5kIHNvbWVvbmUgd2FudHMgdG8gc3dpdGNoIHRvIGl0LCB3ZSBzaG91bGQgbGV0IGNocm9tZWRyaXZlciBjb25uZWN0IHRvXG4gICAgLy8gY2hyb21lIHJhdGhlciB0aGFuIHN0YXlpbmcgc3R1Y2sgb24gdGhlIEFVVFxuICAgIGlmIChvcHRzLmV4dHJhY3RDaHJvbWVBbmRyb2lkUGFja2FnZUZyb21Db250ZXh0TmFtZSB8fCBjb250ZXh0ID09PSBgJHtXRUJWSUVXX0JBU0V9Y2hyb21lYCkge1xuICAgICAgbGV0IGFuZHJvaWRQYWNrYWdlID0gY29udGV4dC5tYXRjaChgJHtXRUJWSUVXX0JBU0V9KC4rKWApO1xuICAgICAgaWYgKGFuZHJvaWRQYWNrYWdlICYmIGFuZHJvaWRQYWNrYWdlLmxlbmd0aCA+IDApIHtcbiAgICAgICAgb3B0cy5jaHJvbWVBbmRyb2lkUGFja2FnZSA9IGFuZHJvaWRQYWNrYWdlWzFdO1xuICAgICAgfVxuICAgICAgaWYgKCFvcHRzLmV4dHJhY3RDaHJvbWVBbmRyb2lkUGFja2FnZUZyb21Db250ZXh0TmFtZSkge1xuICAgICAgICBpZiAoXy5oYXModGhpcy5vcHRzLCAnZW5hYmxlV2Vidmlld0RldGFpbHNDb2xsZWN0aW9uJykgJiYgIXRoaXMub3B0cy5lbmFibGVXZWJ2aWV3RGV0YWlsc0NvbGxlY3Rpb24pIHtcbiAgICAgICAgICAvLyBXaGVuIGVuYWJsZVdlYnZpZXdEZXRhaWxzQ29sbGVjdGlvbiBjYXBhYmlsaXR5IGlzIGV4cGxpY2l0bHkgZGlzYWJsZWQsIHRyeSB0byBpZGVudGlmeVxuICAgICAgICAgIC8vIGNocm9tZUFuZHJvaWRQYWNrYWdlIGJhc2VkIG9uIGNvbnRleHRzLCBrbm93biBjaHJvbWUgdmFyaWFudCBwYWNrYWdlcyBhbmQgcXVlcnlBcHBTdGF0ZSByZXN1bHRcbiAgICAgICAgICAvLyBzaW5jZSB3ZWJ2aWV3c01hcHBpbmcgZG9lcyBub3QgaGF2ZSBpbmZvIG9iamVjdFxuICAgICAgICAgIGNvbnN0IGNvbnRleHRzID0gd2Vidmlld3NNYXBwaW5nLm1hcCgod20pID0+IHdtLndlYnZpZXdOYW1lKTtcbiAgICAgICAgICBmb3IgKGNvbnN0IGtub3duUGFja2FnZSBvZiBLTk9XTl9DSFJPTUVfUEFDS0FHRV9OQU1FUykge1xuICAgICAgICAgICAgaWYgKF8uaW5jbHVkZXMoY29udGV4dHMsIGAke1dFQlZJRVdfQkFTRX0ke2tub3duUGFja2FnZX1gKSkge1xuICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IGFwcFN0YXRlID0gYXdhaXQgdGhpcy5xdWVyeUFwcFN0YXRlKGtub3duUGFja2FnZSk7XG4gICAgICAgICAgICBpZiAoXy5pbmNsdWRlcyhbQVBQX1NUQVRFLlJVTk5JTkdfSU5fQkFDS0dST1VORCwgQVBQX1NUQVRFLlJVTk5JTkdfSU5fRk9SRUdST1VORF0sIGFwcFN0YXRlKSkge1xuICAgICAgICAgICAgICBvcHRzLmNocm9tZUFuZHJvaWRQYWNrYWdlID0ga25vd25QYWNrYWdlO1xuICAgICAgICAgICAgICB0aGlzLmxvZy5kZWJ1ZyhgSWRlbnRpZmllZCBjaHJvbWVBbmRyb2lkUGFja2FnZSBhcyAnJHtvcHRzLmNocm9tZUFuZHJvaWRQYWNrYWdlfScgYCArXG4gICAgICAgICAgICAgICAgYGZvciBjb250ZXh0ICcke2NvbnRleHR9JyBieSBxdWVyeWluZyBzdGF0ZXMgb2YgQ2hyb21lIGFwcCBwYWNrYWdlc2ApO1xuICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgZm9yIChjb25zdCB3bSBvZiB3ZWJ2aWV3c01hcHBpbmcpIHtcbiAgICAgICAgICAgIGlmICh3bS53ZWJ2aWV3TmFtZSA9PT0gY29udGV4dCAmJiBfLmhhcyh3bT8uaW5mbywgJ0FuZHJvaWQtUGFja2FnZScpKSB7XG4gICAgICAgICAgICAgIG9wdHMuY2hyb21lQW5kcm9pZFBhY2thZ2UgPSB3bS5pbmZvWydBbmRyb2lkLVBhY2thZ2UnXTtcbiAgICAgICAgICAgICAgdGhpcy5sb2cuZGVidWcoYElkZW50aWZpZWQgY2hyb21lQW5kcm9pZFBhY2thZ2UgYXMgJyR7b3B0cy5jaHJvbWVBbmRyb2lkUGFja2FnZX0nIGAgK1xuICAgICAgICAgICAgICAgIGBmb3IgY29udGV4dCAnJHtjb250ZXh0fScgYnkgQ0RQYCk7XG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIGNkID0gYXdhaXQgdGhpcy5zZXR1cE5ld0Nocm9tZWRyaXZlcihvcHRzLCB0aGlzLmFkYi5jdXJEZXZpY2VJZCwgdGhpcy5hZGIsIGNvbnRleHQpO1xuICAgIC8vIGJpbmQgb3VyIHN0b3AvZXhpdCBoYW5kbGVyLCBwYXNzaW5nIGluIGNvbnRleHQgc28gd2Uga25vdyB3aGljaFxuICAgIC8vIG9uZSBzdG9wcGVkIHVuZXhwZWN0ZWRseVxuICAgIGNkLm9uKENocm9tZWRyaXZlci5FVkVOVF9DSEFOR0VELCAobXNnKSA9PiB7XG4gICAgICBpZiAobXNnLnN0YXRlID09PSBDaHJvbWVkcml2ZXIuU1RBVEVfU1RPUFBFRCkge1xuICAgICAgICB0aGlzLm9uQ2hyb21lZHJpdmVyU3RvcChjb250ZXh0KTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICAvLyBzYXZlIHRoZSBjaHJvbWVkcml2ZXIgb2JqZWN0IHVuZGVyIHRoZSBjb250ZXh0XG4gICAgdGhpcy5zZXNzaW9uQ2hyb21lZHJpdmVyc1tjb250ZXh0XSA9IGNkO1xuICB9XG4gIC8vIGhvb2sgdXAgdGhlIGxvY2FsIHZhcmlhYmxlcyBzbyB3ZSBjYW4gcHJveHkgdGhpcyBiaXpcbiAgdGhpcy5jaHJvbWVkcml2ZXIgPSBjZDtcbiAgdGhpcy5wcm94eVJlcVJlcyA9IHRoaXMuY2hyb21lZHJpdmVyLnByb3h5UmVxLmJpbmQodGhpcy5jaHJvbWVkcml2ZXIpO1xuICB0aGlzLnByb3h5Q29tbWFuZCA9IHRoaXMuY2hyb21lZHJpdmVyLmp3cHJveHkuY29tbWFuZC5iaW5kKHRoaXMuY2hyb21lZHJpdmVyLmp3cHJveHkpO1xuICB0aGlzLmp3cFByb3h5QWN0aXZlID0gdHJ1ZTtcbn07XG5cbi8vIFN0b3AgcHJveHlpbmcgdG8gYW55IENocm9tZWRyaXZlclxuaGVscGVycy5zdXNwZW5kQ2hyb21lZHJpdmVyUHJveHkgPSBmdW5jdGlvbiBzdXNwZW5kQ2hyb21lZHJpdmVyUHJveHkgKCkge1xuICB0aGlzLmNocm9tZWRyaXZlciA9IG51bGw7XG4gIHRoaXMucHJveHlSZXFSZXMgPSBudWxsO1xuICB0aGlzLnByb3h5Q29tbWFuZCA9IG51bGw7XG4gIHRoaXMuandwUHJveHlBY3RpdmUgPSBmYWxzZTtcbn07XG5cbi8vIEhhbmRsZSBhbiBvdXQtb2YtYmFuZCBDaHJvbWVkcml2ZXIgc3RvcCBldmVudFxuaGVscGVycy5vbkNocm9tZWRyaXZlclN0b3AgPSBhc3luYyBmdW5jdGlvbiBvbkNocm9tZWRyaXZlclN0b3AgKGNvbnRleHQpIHtcbiAgdGhpcy5sb2cud2FybihgQ2hyb21lZHJpdmVyIGZvciBjb250ZXh0ICR7Y29udGV4dH0gc3RvcHBlZCB1bmV4cGVjdGVkbHlgKTtcbiAgaWYgKGNvbnRleHQgPT09IHRoaXMuY3VyQ29udGV4dCkge1xuICAgIC8vIHdlIGV4aXRlZCB1bmV4cGVjdGVkbHkgd2hpbGUgYXV0b21hdGluZyB0aGUgY3VycmVudCBjb250ZXh0IGFuZCBzbyB3YW50XG4gICAgLy8gdG8gc2h1dCBkb3duIHRoZSBzZXNzaW9uIGFuZCByZXNwb25kIHdpdGggYW4gZXJyb3JcbiAgICBsZXQgZXJyID0gbmV3IEVycm9yKCdDaHJvbWVkcml2ZXIgcXVpdCB1bmV4cGVjdGVkbHkgZHVyaW5nIHNlc3Npb24nKTtcbiAgICBhd2FpdCB0aGlzLnN0YXJ0VW5leHBlY3RlZFNodXRkb3duKGVycik7XG4gIH0gZWxzZSB7XG4gICAgLy8gaWYgYSBDaHJvbWVkcml2ZXIgaW4gdGhlIG5vbi1hY3RpdmUgY29udGV4dCBiYXJmcywgd2UgZG9uJ3QgcmVhbGx5XG4gICAgLy8gY2FyZSwgd2UnbGwganVzdCBtYWtlIGEgbmV3IG9uZSBuZXh0IHRpbWUgd2UgbmVlZCB0aGUgY29udGV4dC5cbiAgICB0aGlzLmxvZy53YXJuKFwiQ2hyb21lZHJpdmVyIHF1aXQgdW5leHBlY3RlZGx5LCBidXQgaXQgd2Fzbid0IHRoZSBhY3RpdmUgXCIgK1xuICAgICAgJ2NvbnRleHQsIGlnbm9yaW5nJyk7XG4gICAgZGVsZXRlIHRoaXMuc2Vzc2lvbkNocm9tZWRyaXZlcnNbY29udGV4dF07XG4gIH1cbn07XG5cbi8vIEludGVudGlvbmFsbHkgc3RvcCBhbGwgdGhlIGNocm9tZWRyaXZlcnMgY3VycmVudGx5IGFjdGl2ZSwgYW5kIGlnbm9yZVxuLy8gdGhlaXIgZXhpdCBldmVudHNcbmhlbHBlcnMuc3RvcENocm9tZWRyaXZlclByb3hpZXMgPSBhc3luYyBmdW5jdGlvbiBzdG9wQ2hyb21lZHJpdmVyUHJveGllcyAoKSB7XG4gIHRoaXMuc3VzcGVuZENocm9tZWRyaXZlclByb3h5KCk7IC8vIG1ha2Ugc3VyZSB3ZSB0dXJuIG9mZiB0aGUgcHJveHkgZmxhZ1xuICBmb3IgKGxldCBjb250ZXh0IG9mIF8ua2V5cyh0aGlzLnNlc3Npb25DaHJvbWVkcml2ZXJzKSkge1xuICAgIGxldCBjZCA9IHRoaXMuc2Vzc2lvbkNocm9tZWRyaXZlcnNbY29udGV4dF07XG4gICAgdGhpcy5sb2cuZGVidWcoYFN0b3BwaW5nIGNocm9tZWRyaXZlciBmb3IgY29udGV4dCAke2NvbnRleHR9YCk7XG4gICAgLy8gc3RvcCBsaXN0ZW5pbmcgZm9yIHRoZSBzdG9wcGVkIHN0YXRlIGV2ZW50XG4gICAgY2QucmVtb3ZlQWxsTGlzdGVuZXJzKENocm9tZWRyaXZlci5FVkVOVF9DSEFOR0VEKTtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgY2Quc3RvcCgpO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgdGhpcy5sb2cud2FybihgRXJyb3Igc3RvcHBpbmcgQ2hyb21lZHJpdmVyOiAke2Vyci5tZXNzYWdlfWApO1xuICAgIH1cbiAgICBkZWxldGUgdGhpcy5zZXNzaW9uQ2hyb21lZHJpdmVyc1tjb250ZXh0XTtcbiAgfVxufTtcblxuaGVscGVycy5pc0Nocm9tZWRyaXZlckNvbnRleHQgPSBmdW5jdGlvbiBpc0Nocm9tZWRyaXZlckNvbnRleHQgKHZpZXdOYW1lKSB7XG4gIHJldHVybiBfLmluY2x1ZGVzKHZpZXdOYW1lLCBXRUJWSUVXX1dJTikgfHwgdmlld05hbWUgPT09IENIUk9NSVVNX1dJTjtcbn07XG5cbmhlbHBlcnMuc2hvdWxkRGlzbWlzc0Nocm9tZVdlbGNvbWUgPSBmdW5jdGlvbiBzaG91bGREaXNtaXNzQ2hyb21lV2VsY29tZSAoKSB7XG4gIHJldHVybiAhIXRoaXMub3B0cy5jaHJvbWVPcHRpb25zICYmXG4gICAgICAgICBfLmlzQXJyYXkodGhpcy5vcHRzLmNocm9tZU9wdGlvbnMuYXJncykgJiZcbiAgICAgICAgIHRoaXMub3B0cy5jaHJvbWVPcHRpb25zLmFyZ3MuaW5jbHVkZXMoJy0tbm8tZmlyc3QtcnVuJyk7XG59O1xuXG5oZWxwZXJzLmRpc21pc3NDaHJvbWVXZWxjb21lID0gYXN5bmMgZnVuY3Rpb24gZGlzbWlzc0Nocm9tZVdlbGNvbWUgKCkge1xuICB0aGlzLmxvZy5pbmZvKCdUcnlpbmcgdG8gZGlzbWlzcyBDaHJvbWUgd2VsY29tZScpO1xuICBsZXQgYWN0aXZpdHkgPSBhd2FpdCB0aGlzLmdldEN1cnJlbnRBY3Rpdml0eSgpO1xuICBpZiAoYWN0aXZpdHkgIT09ICdvcmcuY2hyb21pdW0uY2hyb21lLmJyb3dzZXIuZmlyc3RydW4uRmlyc3RSdW5BY3Rpdml0eScpIHtcbiAgICB0aGlzLmxvZy5pbmZvKCdDaHJvbWUgd2VsY29tZSBkaWFsb2cgbmV2ZXIgc2hvd2VkIHVwISBDb250aW51aW5nJyk7XG4gICAgcmV0dXJuO1xuICB9XG4gIGxldCBlbCA9IGF3YWl0IHRoaXMuZmluZEVsT3JFbHMoJ2lkJywgJ2NvbS5hbmRyb2lkLmNocm9tZTppZC90ZXJtc19hY2NlcHQnLCBmYWxzZSk7XG4gIGF3YWl0IHRoaXMuY2xpY2soZWwuRUxFTUVOVCk7XG4gIHRyeSB7XG4gICAgbGV0IGVsID0gYXdhaXQgdGhpcy5maW5kRWxPckVscygnaWQnLCAnY29tLmFuZHJvaWQuY2hyb21lOmlkL25lZ2F0aXZlX2J1dHRvbicsIGZhbHNlKTtcbiAgICBhd2FpdCB0aGlzLmNsaWNrKGVsLkVMRU1FTlQpO1xuICB9IGNhdGNoIChlKSB7XG4gICAgLy8gRE8gTk9USElORywgVEhJUyBERVZJQ0UgRElETlQgTEFVTkNIIFRIRSBTSUdOSU4gRElBTE9HXG4gICAgLy8gSVQgTVVTVCBCRSBBIE5PTiBHTVMgREVWSUNFXG4gICAgdGhpcy5sb2cud2FybihgVGhpcyBkZXZpY2UgZGlkIG5vdCBzaG93IENocm9tZSBTaWduSW4gZGlhbG9nLCAke2UubWVzc2FnZX1gKTtcbiAgfVxufTtcblxuaGVscGVycy5zdGFydENocm9tZVNlc3Npb24gPSBhc3luYyBmdW5jdGlvbiBzdGFydENocm9tZVNlc3Npb24gKCkge1xuICB0aGlzLmxvZy5pbmZvKCdTdGFydGluZyBhIGNocm9tZS1iYXNlZCBicm93c2VyIHNlc3Npb24nKTtcbiAgbGV0IG9wdHMgPSBfLmNsb25lRGVlcCh0aGlzLm9wdHMpO1xuXG4gIGNvbnN0IGtub3duUGFja2FnZXMgPSBbXG4gICAgJ29yZy5jaHJvbWl1bS5jaHJvbWUuc2hlbGwnLFxuICAgICdjb20uYW5kcm9pZC5jaHJvbWUnLFxuICAgICdjb20uY2hyb21lLmJldGEnLFxuICAgICdvcmcuY2hyb21pdW0uY2hyb21lJyxcbiAgICAnb3JnLmNocm9taXVtLndlYnZpZXdfc2hlbGwnLFxuICBdO1xuXG4gIGlmIChfLmluY2x1ZGVzKGtub3duUGFja2FnZXMsIHRoaXMub3B0cy5hcHBQYWNrYWdlKSkge1xuICAgIG9wdHMuY2hyb21lQnVuZGxlSWQgPSB0aGlzLm9wdHMuYXBwUGFja2FnZTtcbiAgfSBlbHNlIHtcbiAgICBvcHRzLmNocm9tZUFuZHJvaWRBY3Rpdml0eSA9IHRoaXMub3B0cy5hcHBBY3Rpdml0eTtcbiAgfVxuICB0aGlzLmNocm9tZWRyaXZlciA9IGF3YWl0IHRoaXMuc2V0dXBOZXdDaHJvbWVkcml2ZXIob3B0cywgdGhpcy5hZGIuY3VyRGV2aWNlSWQsIHRoaXMuYWRiKTtcbiAgdGhpcy5jaHJvbWVkcml2ZXIub24oQ2hyb21lZHJpdmVyLkVWRU5UX0NIQU5HRUQsIChtc2cpID0+IHtcbiAgICBpZiAobXNnLnN0YXRlID09PSBDaHJvbWVkcml2ZXIuU1RBVEVfU1RPUFBFRCkge1xuICAgICAgdGhpcy5vbkNocm9tZWRyaXZlclN0b3AoQ0hST01JVU1fV0lOKTtcbiAgICB9XG4gIH0pO1xuXG4gIC8vIE5vdyB0aGF0IHdlIGhhdmUgYSBDaHJvbWUgc2Vzc2lvbiwgd2UgZW5zdXJlIHRoYXQgdGhlIGNvbnRleHQgaXNcbiAgLy8gYXBwcm9wcmlhdGVseSBzZXQgYW5kIHRoYXQgdGhpcyBjaHJvbWVkcml2ZXIgaXMgYWRkZWQgdG8gdGhlIGxpc3RcbiAgLy8gb2Ygc2Vzc2lvbiBjaHJvbWVkcml2ZXJzIHNvIHdlIGNhbiBzd2l0Y2ggYmFjayBhbmQgZm9ydGhcbiAgdGhpcy5jdXJDb250ZXh0ID0gQ0hST01JVU1fV0lOO1xuICB0aGlzLnNlc3Npb25DaHJvbWVkcml2ZXJzW0NIUk9NSVVNX1dJTl0gPSB0aGlzLmNocm9tZWRyaXZlcjtcbiAgdGhpcy5wcm94eVJlcVJlcyA9IHRoaXMuY2hyb21lZHJpdmVyLnByb3h5UmVxLmJpbmQodGhpcy5jaHJvbWVkcml2ZXIpO1xuICB0aGlzLnByb3h5Q29tbWFuZCA9IHRoaXMuY2hyb21lZHJpdmVyLmp3cHJveHkuY29tbWFuZC5iaW5kKHRoaXMuY2hyb21lZHJpdmVyLmp3cHJveHkpO1xuICB0aGlzLmp3cFByb3h5QWN0aXZlID0gdHJ1ZTtcblxuICBpZiAodGhpcy5zaG91bGREaXNtaXNzQ2hyb21lV2VsY29tZSgpKSB7XG4gICAgLy8gZGlzbWlzcyBDaHJvbWUgd2VsY29tZSBkaWFsb2dcbiAgICBhd2FpdCB0aGlzLmRpc21pc3NDaHJvbWVXZWxjb21lKCk7XG4gIH1cbn07XG5cblxuLyogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqIEludGVybmFsIGxpYnJhcnkgZnVuY3Rpb25zXG4gKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqL1xuXG5hc3luYyBmdW5jdGlvbiBzZXR1cEV4aXN0aW5nQ2hyb21lZHJpdmVyIChsb2csIGNocm9tZWRyaXZlcikge1xuICAvLyBjaGVjayB0aGUgc3RhdHVzIGJ5IHNlbmRpbmcgYSBzaW1wbGUgd2luZG93LWJhc2VkIGNvbW1hbmQgdG8gQ2hyb21lRHJpdmVyXG4gIC8vIGlmIHRoZXJlIGlzIGFuIGVycm9yLCB3ZSB3YW50IHRvIHJlY3JlYXRlIHRoZSBDaHJvbWVEcml2ZXIgc2Vzc2lvblxuICBpZiAoIWF3YWl0IGNocm9tZWRyaXZlci5oYXNXb3JraW5nV2VidmlldygpKSB7XG4gICAgbG9nLmRlYnVnKCdDaHJvbWVEcml2ZXIgaXMgbm90IGFzc29jaWF0ZWQgd2l0aCBhIHdpbmRvdy4gJyArXG4gICAgICAgICAgICAgICAgICdSZS1pbml0aWFsaXppbmcgdGhlIHNlc3Npb24uJyk7XG4gICAgYXdhaXQgY2hyb21lZHJpdmVyLnJlc3RhcnQoKTtcbiAgfVxuICByZXR1cm4gY2hyb21lZHJpdmVyO1xufVxuXG4vKipcbiAqIEZpbmQgYSBmcmVlIHBvcnQgdG8gaGF2ZSBDaHJvbWVkcml2ZXIgbGlzdGVuIG9uLlxuICpcbiAqIEBwYXJhbSB7YXJyYXl9IHBvcnRTcGVjIC0gQXJyYXkgd2hpY2ggaXMgYSBsaXN0IG9mIHBvcnRzLiBBIGxpc3QgaXRlbSBtYXlcbiAqIGFsc28gaXRzZWxmIGJlIGFuIGFycmF5IG9mIGxlbmd0aCAyIHNwZWNpZnlpbmcgYSBzdGFydCBhbmQgZW5kIHBvcnQgb2ZcbiAqIGEgcmFuZ2UuIFNvbWUgdmFsaWQgcG9ydCBzcGVjczpcbiAqICAgIC0gWzgwMDAsIDgwMDEsIDgwMDJdXG4gKiAgICAtIFtbODAwMCwgODAwNV1dXG4gKiAgICAtIFs4MDAwLCBbOTAwMCwgOTEwMF1dXG4gKiBAcGFyYW0ge09iamVjdD99IGxvZyBMb2dnZXIgaW5zdGFuY2VcbiAqXG4gKiBAcmV0dXJuIHtudW1iZXJ9IEEgZnJlZSBwb3J0XG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGdldENocm9tZWRyaXZlclBvcnQgKHBvcnRTcGVjLCBsb2cgPSBudWxsKSB7XG4gIGNvbnN0IGdldFBvcnQgPSBCLnByb21pc2lmeShQb3J0RmluZGVyLmdldFBvcnQsIHtjb250ZXh0OiBQb3J0RmluZGVyfSk7XG5cbiAgLy8gaWYgdGhlIHVzZXIgZGlkbid0IGdpdmUgdXMgYW55IHNwZWNpZmljIGluZm9ybWF0aW9uIGFib3V0IGNocm9tZWRyaXZlclxuICAvLyBwb3J0IHJhbmdlcywganVzdCBmaW5kIGFueSBmcmVlIHBvcnRcbiAgaWYgKCFwb3J0U3BlYykge1xuICAgIGNvbnN0IHBvcnQgPSBhd2FpdCBnZXRQb3J0KCk7XG4gICAgbG9nPy5kZWJ1ZyhgQSBwb3J0IHdhcyBub3QgZ2l2ZW4sIHVzaW5nIHJhbmRvbSBmcmVlIHBvcnQ6ICR7cG9ydH1gKTtcbiAgICByZXR1cm4gcG9ydDtcbiAgfVxuXG4gIC8vIG90aGVyd2lzZSBmaW5kIHRoZSBmcmVlIHBvcnQgYmFzZWQgb24gYSBsaXN0IG9yIHJhbmdlIHByb3ZpZGVkIGJ5IHRoZSB1c2VyXG4gIGxvZz8uZGVidWcoYEZpbmRpbmcgYSBmcmVlIHBvcnQgZm9yIGNocm9tZWRyaXZlciB1c2luZyBzcGVjICR7SlNPTi5zdHJpbmdpZnkocG9ydFNwZWMpfWApO1xuICBsZXQgZm91bmRQb3J0ID0gbnVsbDtcbiAgZm9yIChjb25zdCBwb3RlbnRpYWxQb3J0IG9mIHBvcnRTcGVjKSB7XG4gICAgbGV0IHBvcnQsIHN0b3BQb3J0O1xuICAgIGlmIChfLmlzQXJyYXkocG90ZW50aWFsUG9ydCkpIHtcbiAgICAgIChbcG9ydCwgc3RvcFBvcnRdID0gcG90ZW50aWFsUG9ydCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHBvcnQgPSBwYXJzZUludChwb3RlbnRpYWxQb3J0LCAxMCk7IC8vIGVuc3VyZSB3ZSBoYXZlIGEgbnVtYmVyIGFuZCBub3QgYSBzdHJpbmdcbiAgICAgIHN0b3BQb3J0ID0gcG9ydDtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgIGxvZz8uZGVidWcoYENoZWNraW5nIHBvcnQgcmFuZ2UgJHtwb3J0fToke3N0b3BQb3J0fWApO1xuICAgICAgZm91bmRQb3J0ID0gYXdhaXQgZ2V0UG9ydCh7cG9ydCwgc3RvcFBvcnR9KTtcbiAgICAgIGJyZWFrO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGxvZz8uZGVidWcoYE5vdGhpbmcgaW4gcG9ydCByYW5nZSAke3BvcnR9OiR7c3RvcFBvcnR9IHdhcyBhdmFpbGFibGVgKTtcbiAgICB9XG4gIH1cblxuICBpZiAoZm91bmRQb3J0ID09PSBudWxsKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBDb3VsZCBub3QgZmluZCBhIGZyZWUgcG9ydCBmb3IgY2hyb21lZHJpdmVyIHVzaW5nIGAgK1xuICAgICAgICAgICAgICAgICAgICBgY2hyb21lZHJpdmVyUG9ydHMgc3BlYyAke0pTT04uc3RyaW5naWZ5KHBvcnRTcGVjKX1gKTtcbiAgfVxuXG4gIGxvZz8uZGVidWcoYFVzaW5nIGZyZWUgcG9ydCAke2ZvdW5kUG9ydH0gZm9yIGNocm9tZWRyaXZlcmApO1xuICByZXR1cm4gZm91bmRQb3J0O1xufVxuXG5oZWxwZXJzLmlzQ2hyb21lZHJpdmVyQXV0b2Rvd25sb2FkRW5hYmxlZCA9IGZ1bmN0aW9uIGlzQ2hyb21lZHJpdmVyQXV0b2Rvd25sb2FkRW5hYmxlZCAoKSB7XG4gIGlmICh0aGlzLmlzRmVhdHVyZUVuYWJsZWQoQ0hST01FRFJJVkVSX0FVVE9ET1dOTE9BRF9GRUFUVVJFKSkge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG4gIHRoaXM/LmxvZz8uZGVidWcoYEF1dG9tYXRlZCBDaHJvbWVkcml2ZXIgZG93bmxvYWQgaXMgZGlzYWJsZWQuIGAgK1xuICAgIGBVc2UgJyR7Q0hST01FRFJJVkVSX0FVVE9ET1dOTE9BRF9GRUFUVVJFfScgc2VydmVyIGZlYXR1cmUgdG8gZW5hYmxlIGl0YCk7XG4gIHJldHVybiBmYWxzZTtcbn07XG5cbmhlbHBlcnMuc2V0dXBOZXdDaHJvbWVkcml2ZXIgPSBhc3luYyBmdW5jdGlvbiBzZXR1cE5ld0Nocm9tZWRyaXZlciAob3B0cywgY3VyRGV2aWNlSWQsIGFkYiwgY29udGV4dCA9IG51bGwpIHtcbiAgaWYgKG9wdHMuY2hyb21lRHJpdmVyUG9ydCkge1xuICAgIHRoaXM/LmxvZz8ud2FybihgVGhlICdjaHJvbWVEcml2ZXJQb3J0JyBjYXBhYmlsaXR5IGlzIGRlcHJlY2F0ZWQuIFBsZWFzZSB1c2UgJ2Nocm9tZWRyaXZlclBvcnQnIGluc3RlYWRgKTtcbiAgICBvcHRzLmNocm9tZWRyaXZlclBvcnQgPSBvcHRzLmNocm9tZURyaXZlclBvcnQ7XG4gIH1cblxuICBpZiAob3B0cy5jaHJvbWVkcml2ZXJQb3J0KSB7XG4gICAgdGhpcz8ubG9nPy5kZWJ1ZyhgVXNpbmcgdXNlci1zcGVjaWZpZWQgcG9ydCAke29wdHMuY2hyb21lZHJpdmVyUG9ydH0gZm9yIGNocm9tZWRyaXZlcmApO1xuICB9IGVsc2Uge1xuICAgIC8vIGlmIGEgc2luZ2xlIHBvcnQgd2Fzbid0IGdpdmVuLCB3ZSdsbCBsb29rIGZvciBhIGZyZWUgb25lXG4gICAgb3B0cy5jaHJvbWVkcml2ZXJQb3J0ID0gYXdhaXQgZ2V0Q2hyb21lZHJpdmVyUG9ydChvcHRzLmNocm9tZWRyaXZlclBvcnRzLCB0aGlzPy5sb2cpO1xuICB9XG5cbiAgY29uc3QgZGV0YWlscyA9IGNvbnRleHQgPyB3ZWJ2aWV3SGVscGVycy5nZXRXZWJ2aWV3RGV0YWlscyhhZGIsIGNvbnRleHQpIDogdW5kZWZpbmVkO1xuICBpZiAoIV8uaXNFbXB0eShkZXRhaWxzKSkge1xuICAgIHRoaXM/LmxvZz8uZGVidWcoJ1Bhc3Npbmcgd2ViIHZpZXcgZGV0YWlscyB0byB0aGUgQ2hyb21lZHJpdmVyIGNvbnN0cnVjdG9yOiAnICtcbiAgICAgIEpTT04uc3RyaW5naWZ5KGRldGFpbHMsIG51bGwsIDIpKTtcbiAgfVxuXG4gIGNvbnN0IGNocm9tZWRyaXZlciA9IG5ldyBDaHJvbWVkcml2ZXIoe1xuICAgIHBvcnQ6IG9wdHMuY2hyb21lZHJpdmVyUG9ydCxcbiAgICBleGVjdXRhYmxlOiBvcHRzLmNocm9tZWRyaXZlckV4ZWN1dGFibGUsXG4gICAgYWRiLFxuICAgIGNtZEFyZ3M6IG9wdHMuY2hyb21lZHJpdmVyQXJncyxcbiAgICB2ZXJib3NlOiAhIW9wdHMuc2hvd0Nocm9tZWRyaXZlckxvZyxcbiAgICBleGVjdXRhYmxlRGlyOiBvcHRzLmNocm9tZWRyaXZlckV4ZWN1dGFibGVEaXIsXG4gICAgbWFwcGluZ1BhdGg6IG9wdHMuY2hyb21lZHJpdmVyQ2hyb21lTWFwcGluZ0ZpbGUsXG4gICAgYnVuZGxlSWQ6IG9wdHMuY2hyb21lQnVuZGxlSWQsXG4gICAgdXNlU3lzdGVtRXhlY3V0YWJsZTogb3B0cy5jaHJvbWVkcml2ZXJVc2VTeXN0ZW1FeGVjdXRhYmxlLFxuICAgIGRpc2FibGVCdWlsZENoZWNrOiBvcHRzLmNocm9tZWRyaXZlckRpc2FibGVCdWlsZENoZWNrLFxuICAgIGRldGFpbHMsXG4gICAgaXNBdXRvZG93bmxvYWRFbmFibGVkOiB0aGlzPy5pc0Nocm9tZWRyaXZlckF1dG9kb3dubG9hZEVuYWJsZWQ/LigpXG4gIH0pO1xuXG4gIC8vIG1ha2Ugc3VyZSB0aGVyZSBhcmUgY2hyb21lT3B0aW9uc1xuICBvcHRzLmNocm9tZU9wdGlvbnMgPSBvcHRzLmNocm9tZU9wdGlvbnMgfHwge307XG4gIC8vIHRyeSBvdXQgYW55IHByZWZpeGVkIGNocm9tZU9wdGlvbnMsXG4gIC8vIGFuZCBzdHJpcCB0aGUgcHJlZml4XG4gIGZvciAoY29uc3Qgb3B0IG9mIF8ua2V5cyhvcHRzKSkge1xuICAgIGlmIChvcHQuZW5kc1dpdGgoJzpjaHJvbWVPcHRpb25zJykpIHtcbiAgICAgIHRoaXM/LmxvZz8ud2FybihgTWVyZ2luZyAnJHtvcHR9JyBpbnRvICdjaHJvbWVPcHRpb25zJy4gVGhpcyBtYXkgY2F1c2UgdW5leHBlY3RlZCBiZWhhdmlvcmApO1xuICAgICAgXy5tZXJnZShvcHRzLmNocm9tZU9wdGlvbnMsIG9wdHNbb3B0XSk7XG4gICAgfVxuICB9XG5cbiAgY29uc3QgY2FwcyA9IHdlYnZpZXdIZWxwZXJzLmNyZWF0ZUNocm9tZWRyaXZlckNhcHMob3B0cywgY3VyRGV2aWNlSWQsIGRldGFpbHMpO1xuICB0aGlzPy5sb2c/LmRlYnVnKGBCZWZvcmUgc3RhcnRpbmcgY2hyb21lZHJpdmVyLCBhbmRyb2lkUGFja2FnZSBpcyAnJHtjYXBzLmNocm9tZU9wdGlvbnMuYW5kcm9pZFBhY2thZ2V9J2ApO1xuICBhd2FpdCBjaHJvbWVkcml2ZXIuc3RhcnQoY2Fwcyk7XG4gIHJldHVybiBjaHJvbWVkcml2ZXI7XG59O1xuY29uc3Qgc2V0dXBOZXdDaHJvbWVkcml2ZXIgPSBoZWxwZXJzLnNldHVwTmV3Q2hyb21lZHJpdmVyO1xuXG5cbk9iamVjdC5hc3NpZ24oZXh0ZW5zaW9ucywgY29tbWFuZHMsIGhlbHBlcnMpO1xuZXhwb3J0IHsgY29tbWFuZHMsIGhlbHBlcnMsIHNldHVwTmV3Q2hyb21lZHJpdmVyIH07XG5leHBvcnQgZGVmYXVsdCBleHRlbnNpb25zO1xuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7OztBQUFBLElBQUFBLE9BQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFDLG1CQUFBLEdBQUFGLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBRSxXQUFBLEdBQUFILHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBRyxTQUFBLEdBQUFKLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBSSxRQUFBLEdBQUFKLE9BQUE7QUFDQSxJQUFBSyxPQUFBLEdBQUFMLE9BQUE7QUFDQSxJQUFBTSxlQUFBLEdBQUFDLHVCQUFBLENBQUFQLE9BQUE7QUFJQSxJQUFBUSxlQUFBLEdBQUFSLE9BQUE7QUFBK0MsU0FBQVMseUJBQUFDLFdBQUEsZUFBQUMsT0FBQSxrQ0FBQUMsaUJBQUEsT0FBQUQsT0FBQSxRQUFBRSxnQkFBQSxPQUFBRixPQUFBLFlBQUFGLHdCQUFBLFlBQUFBLENBQUFDLFdBQUEsV0FBQUEsV0FBQSxHQUFBRyxnQkFBQSxHQUFBRCxpQkFBQSxLQUFBRixXQUFBO0FBQUEsU0FBQUgsd0JBQUFPLEdBQUEsRUFBQUosV0FBQSxTQUFBQSxXQUFBLElBQUFJLEdBQUEsSUFBQUEsR0FBQSxDQUFBQyxVQUFBLFdBQUFELEdBQUEsUUFBQUEsR0FBQSxvQkFBQUEsR0FBQSx3QkFBQUEsR0FBQSw0QkFBQUUsT0FBQSxFQUFBRixHQUFBLFVBQUFHLEtBQUEsR0FBQVIsd0JBQUEsQ0FBQUMsV0FBQSxPQUFBTyxLQUFBLElBQUFBLEtBQUEsQ0FBQUMsR0FBQSxDQUFBSixHQUFBLFlBQUFHLEtBQUEsQ0FBQUUsR0FBQSxDQUFBTCxHQUFBLFNBQUFNLE1BQUEsV0FBQUMscUJBQUEsR0FBQUMsTUFBQSxDQUFBQyxjQUFBLElBQUFELE1BQUEsQ0FBQUUsd0JBQUEsV0FBQUMsR0FBQSxJQUFBWCxHQUFBLFFBQUFXLEdBQUEsa0JBQUFILE1BQUEsQ0FBQUksU0FBQSxDQUFBQyxjQUFBLENBQUFDLElBQUEsQ0FBQWQsR0FBQSxFQUFBVyxHQUFBLFNBQUFJLElBQUEsR0FBQVIscUJBQUEsR0FBQUMsTUFBQSxDQUFBRSx3QkFBQSxDQUFBVixHQUFBLEVBQUFXLEdBQUEsY0FBQUksSUFBQSxLQUFBQSxJQUFBLENBQUFWLEdBQUEsSUFBQVUsSUFBQSxDQUFBQyxHQUFBLEtBQUFSLE1BQUEsQ0FBQUMsY0FBQSxDQUFBSCxNQUFBLEVBQUFLLEdBQUEsRUFBQUksSUFBQSxZQUFBVCxNQUFBLENBQUFLLEdBQUEsSUFBQVgsR0FBQSxDQUFBVyxHQUFBLFNBQUFMLE1BQUEsQ0FBQUosT0FBQSxHQUFBRixHQUFBLE1BQUFHLEtBQUEsSUFBQUEsS0FBQSxDQUFBYSxHQUFBLENBQUFoQixHQUFBLEVBQUFNLE1BQUEsWUFBQUEsTUFBQTtBQUUvQyxNQUFNVyxpQ0FBaUMsR0FBRywyQkFBMkI7QUFFckUsSUFBSUMsUUFBUSxHQUFHLENBQUMsQ0FBQztFQUFFQyxPQUFPLEdBQUcsQ0FBQyxDQUFDO0VBQUVDLFVBQVUsR0FBRyxDQUFDLENBQUM7QUFBQ0MsT0FBQSxDQUFBRixPQUFBLEdBQUFBLE9BQUE7QUFBQUUsT0FBQSxDQUFBSCxRQUFBLEdBQUFBLFFBQUE7QUFNakRBLFFBQVEsQ0FBQ0ksaUJBQWlCLEdBQUcsZUFBZUEsaUJBQWlCQSxDQUFBLEVBQUk7RUFHL0QsT0FBTyxJQUFJLENBQUNDLFVBQVUsSUFBSSxJQUFJLENBQUNDLGtCQUFrQixDQUFDLENBQUM7QUFDckQsQ0FBQztBQUVETixRQUFRLENBQUNPLFdBQVcsR0FBRyxlQUFlQSxXQUFXQSxDQUFBLEVBQUk7RUFDbkQsTUFBTUMsZUFBZSxHQUFHLE1BQU1DLHVCQUFjLENBQUNDLGtCQUFrQixDQUFDLElBQUksQ0FBQ0MsR0FBRyxFQUFFLElBQUksQ0FBQ0MsSUFBSSxDQUFDO0VBQ3BGLE9BQU8sSUFBSSxDQUFDQyxjQUFjLENBQUNMLGVBQWUsQ0FBQztBQUM3QyxDQUFDO0FBRURSLFFBQVEsQ0FBQ2MsVUFBVSxHQUFHLGVBQWVBLFVBQVVBLENBQUVDLElBQUksRUFBRTtFQUNyRCxJQUFJLENBQUNDLGFBQUksQ0FBQ0MsUUFBUSxDQUFDRixJQUFJLENBQUMsRUFBRTtJQUN4QkEsSUFBSSxHQUFHLElBQUksQ0FBQ1Qsa0JBQWtCLENBQUMsQ0FBQztFQUNsQyxDQUFDLE1BQU0sSUFBSVMsSUFBSSxLQUFLRywyQkFBVyxFQUFFO0lBRS9CSCxJQUFJLEdBQUcsSUFBSSxDQUFDSSxrQkFBa0IsQ0FBQyxDQUFDO0VBQ2xDO0VBRUEsSUFBSUosSUFBSSxLQUFLLElBQUksQ0FBQ1YsVUFBVSxFQUFFO0lBQzVCO0VBQ0Y7RUFFQSxNQUFNRyxlQUFlLEdBQUcsTUFBTUMsdUJBQWMsQ0FBQ0Msa0JBQWtCLENBQUMsSUFBSSxDQUFDQyxHQUFHLEVBQUUsSUFBSSxDQUFDQyxJQUFJLENBQUM7RUFDcEYsTUFBTVEsUUFBUSxHQUFHLElBQUksQ0FBQ1AsY0FBYyxDQUFDTCxlQUFlLENBQUM7RUFFckQsSUFBSSxDQUFDYSxlQUFDLENBQUNDLFFBQVEsQ0FBQ0YsUUFBUSxFQUFFTCxJQUFJLENBQUMsRUFBRTtJQUMvQixNQUFNLElBQUlRLGNBQU0sQ0FBQ0Msa0JBQWtCLENBQUMsQ0FBQztFQUN2QztFQUVBLE1BQU0sSUFBSSxDQUFDQyxhQUFhLENBQUNWLElBQUksRUFBRVAsZUFBZSxDQUFDO0VBQy9DLElBQUksQ0FBQ0gsVUFBVSxHQUFHVSxJQUFJO0FBQ3hCLENBQUM7QUFnRERmLFFBQVEsQ0FBQzBCLGlCQUFpQixHQUFHLGVBQWVBLGlCQUFpQkEsQ0FBQSxFQUFJO0VBQy9ELE1BQU1kLElBQUksR0FBRztJQUNYZSxtQkFBbUIsRUFBRSxJQUFJLENBQUNmLElBQUksQ0FBQ2UsbUJBQW1CO0lBQ2xEQyx1QkFBdUIsRUFBRSxJQUFJO0lBQzdCQyxtQkFBbUIsRUFBRSxJQUFJLENBQUNqQixJQUFJLENBQUNpQixtQkFBbUI7SUFDbERDLDhCQUE4QixFQUFFO0VBQ2xDLENBQUM7RUFDRCxPQUFPLE1BQU1yQix1QkFBYyxDQUFDQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUNDLEdBQUcsRUFBRUMsSUFBSSxDQUFDO0FBQ2hFLENBQUM7QUFFRFgsT0FBTyxDQUFDWSxjQUFjLEdBQUcsU0FBU0EsY0FBY0EsQ0FBRUwsZUFBZSxFQUFFO0VBQ2pFLE1BQU1JLElBQUksR0FBR3RCLE1BQU0sQ0FBQ3lDLE1BQU0sQ0FBQztJQUFDQyxlQUFlLEVBQUUsSUFBSSxDQUFDQTtFQUFlLENBQUMsRUFBRSxJQUFJLENBQUNwQixJQUFJLENBQUM7RUFDOUUsTUFBTXFCLFFBQVEsR0FBR3hCLHVCQUFjLENBQUN5QixpQkFBaUIsQ0FBQzFCLGVBQWUsRUFBRUksSUFBSSxDQUFDO0VBQ3hFLElBQUksQ0FBQ1EsUUFBUSxHQUFHLENBQUNlLDBCQUFVLEVBQUUsR0FBR0YsUUFBUSxDQUFDO0VBQ3pDLElBQUksQ0FBQ0csR0FBRyxDQUFDQyxLQUFLLENBQUUsdUJBQXNCQyxJQUFJLENBQUNDLFNBQVMsQ0FBQyxJQUFJLENBQUNuQixRQUFRLENBQUUsRUFBQyxDQUFDO0VBQ3RFLE9BQU8sSUFBSSxDQUFDQSxRQUFRO0FBQ3RCLENBQUM7QUFFRG5CLE9BQU8sQ0FBQ3dCLGFBQWEsR0FBRyxlQUFlQSxhQUFhQSxDQUFFVixJQUFJLEVBQUVQLGVBQWUsRUFBRTtFQUczRSxJQUFJLElBQUksQ0FBQ2dDLHFCQUFxQixDQUFDekIsSUFBSSxDQUFDLEVBQUU7SUFFcEMsTUFBTSxJQUFJLENBQUMwQixzQkFBc0IsQ0FBQzFCLElBQUksRUFBRVAsZUFBZSxDQUFDO0VBQzFELENBQUMsTUFBTSxJQUFJLElBQUksQ0FBQ2dDLHFCQUFxQixDQUFDLElBQUksQ0FBQ25DLFVBQVUsQ0FBQyxFQUFFO0lBS3RELElBQUksSUFBSSxDQUFDTyxJQUFJLENBQUM4Qiw0QkFBNEIsRUFBRTtNQUMxQyxJQUFJLENBQUNOLEdBQUcsQ0FBQ0MsS0FBSyxDQUFDLDBFQUEwRSxDQUFDO01BQzFGLE1BQU0sSUFBSSxDQUFDTSx1QkFBdUIsQ0FBQyxDQUFDO0lBQ3RDLENBQUMsTUFBTTtNQUNMLE1BQU0sSUFBSSxDQUFDQyx3QkFBd0IsQ0FBQyxDQUFDO0lBQ3ZDO0VBQ0YsQ0FBQyxNQUFNO0lBQ0wsTUFBTSxJQUFJQyxLQUFLLENBQUUsbURBQWtEOUIsSUFBSyxHQUFFLENBQUM7RUFDN0U7QUFDRixDQUFDO0FBVURkLE9BQU8sQ0FBQ0ssa0JBQWtCLEdBQUcsU0FBU0Esa0JBQWtCQSxDQUFBLEVBQUk7RUFDMUQsT0FBTzZCLDBCQUFVO0FBQ25CLENBQUM7QUFFRGxDLE9BQU8sQ0FBQ2tCLGtCQUFrQixHQUFHLFNBQVNBLGtCQUFrQkEsQ0FBQSxFQUFJO0VBQzFELE9BQU8yQiw0QkFBWSxJQUFJLElBQUksQ0FBQ2xDLElBQUksQ0FBQ21DLGVBQWUsSUFBSSxJQUFJLENBQUNuQyxJQUFJLENBQUNvQyxVQUFVLENBQUM7QUFDM0UsQ0FBQztBQUVEL0MsT0FBTyxDQUFDZ0QsWUFBWSxHQUFHLFNBQVNBLFlBQVlBLENBQUEsRUFBSTtFQUM5QyxPQUFPLElBQUksQ0FBQzVDLFVBQVUsS0FBSyxJQUFJLElBQUksSUFBSSxDQUFDQSxVQUFVLEtBQUs4QiwwQkFBVTtBQUNuRSxDQUFDO0FBR0RsQyxPQUFPLENBQUN3QyxzQkFBc0IsR0FBRyxlQUFlQSxzQkFBc0JBLENBQUVTLE9BQU8sRUFBRTFDLGVBQWUsRUFBRTtFQUNoRyxJQUFJLENBQUM0QixHQUFHLENBQUNDLEtBQUssQ0FBRSxnREFBK0NhLE9BQVEsR0FBRSxDQUFDO0VBRTFFLElBQUlDLEVBQUU7RUFDTixJQUFJLElBQUksQ0FBQ0Msb0JBQW9CLENBQUNGLE9BQU8sQ0FBQyxFQUFFO0lBR3RDLElBQUksQ0FBQ2QsR0FBRyxDQUFDQyxLQUFLLENBQUUsNENBQTJDYSxPQUFRLGNBQWEsQ0FBQztJQUNqRkMsRUFBRSxHQUFHLElBQUksQ0FBQ0Msb0JBQW9CLENBQUNGLE9BQU8sQ0FBQztJQUN2QyxNQUFNRyx5QkFBeUIsQ0FBQyxJQUFJLENBQUNqQixHQUFHLEVBQUVlLEVBQUUsQ0FBQztFQUMvQyxDQUFDLE1BQU07SUFDTCxJQUFJdkMsSUFBSSxHQUFHUyxlQUFDLENBQUNpQyxTQUFTLENBQUMsSUFBSSxDQUFDMUMsSUFBSSxDQUFDO0lBQ2pDQSxJQUFJLENBQUMyQyxtQkFBbUIsR0FBRyxJQUFJO0lBTy9CLElBQUkzQyxJQUFJLENBQUM0QywwQ0FBMEMsSUFBSU4sT0FBTyxLQUFNLEdBQUVKLDRCQUFhLFFBQU8sRUFBRTtNQUMxRixJQUFJVyxjQUFjLEdBQUdQLE9BQU8sQ0FBQ1EsS0FBSyxDQUFFLEdBQUVaLDRCQUFhLE1BQUssQ0FBQztNQUN6RCxJQUFJVyxjQUFjLElBQUlBLGNBQWMsQ0FBQ0UsTUFBTSxHQUFHLENBQUMsRUFBRTtRQUMvQy9DLElBQUksQ0FBQ2dELG9CQUFvQixHQUFHSCxjQUFjLENBQUMsQ0FBQyxDQUFDO01BQy9DO01BQ0EsSUFBSSxDQUFDN0MsSUFBSSxDQUFDNEMsMENBQTBDLEVBQUU7UUFDcEQsSUFBSW5DLGVBQUMsQ0FBQ25DLEdBQUcsQ0FBQyxJQUFJLENBQUMwQixJQUFJLEVBQUUsZ0NBQWdDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQ0EsSUFBSSxDQUFDa0IsOEJBQThCLEVBQUU7VUFJbkcsTUFBTVYsUUFBUSxHQUFHWixlQUFlLENBQUNxRCxHQUFHLENBQUVDLEVBQUUsSUFBS0EsRUFBRSxDQUFDQyxXQUFXLENBQUM7VUFDNUQsS0FBSyxNQUFNQyxZQUFZLElBQUlDLDBDQUEwQixFQUFFO1lBQ3JELElBQUk1QyxlQUFDLENBQUNDLFFBQVEsQ0FBQ0YsUUFBUSxFQUFHLEdBQUUwQiw0QkFBYSxHQUFFa0IsWUFBYSxFQUFDLENBQUMsRUFBRTtjQUMxRDtZQUNGO1lBQ0EsTUFBTUUsUUFBUSxHQUFHLE1BQU0sSUFBSSxDQUFDQyxhQUFhLENBQUNILFlBQVksQ0FBQztZQUN2RCxJQUFJM0MsZUFBQyxDQUFDQyxRQUFRLENBQUMsQ0FBQzhDLHlCQUFTLENBQUNDLHFCQUFxQixFQUFFRCx5QkFBUyxDQUFDRSxxQkFBcUIsQ0FBQyxFQUFFSixRQUFRLENBQUMsRUFBRTtjQUM1RnRELElBQUksQ0FBQ2dELG9CQUFvQixHQUFHSSxZQUFZO2NBQ3hDLElBQUksQ0FBQzVCLEdBQUcsQ0FBQ0MsS0FBSyxDQUFFLHVDQUFzQ3pCLElBQUksQ0FBQ2dELG9CQUFxQixJQUFHLEdBQ2hGLGdCQUFlVixPQUFRLDZDQUE0QyxDQUFDO2NBQ3ZFO1lBQ0Y7VUFDRjtRQUNGLENBQUMsTUFBTTtVQUNMLEtBQUssTUFBTVksRUFBRSxJQUFJdEQsZUFBZSxFQUFFO1lBQ2hDLElBQUlzRCxFQUFFLENBQUNDLFdBQVcsS0FBS2IsT0FBTyxJQUFJN0IsZUFBQyxDQUFDbkMsR0FBRyxDQUFDNEUsRUFBRSxhQUFGQSxFQUFFLHVCQUFGQSxFQUFFLENBQUVTLElBQUksRUFBRSxpQkFBaUIsQ0FBQyxFQUFFO2NBQ3BFM0QsSUFBSSxDQUFDZ0Qsb0JBQW9CLEdBQUdFLEVBQUUsQ0FBQ1MsSUFBSSxDQUFDLGlCQUFpQixDQUFDO2NBQ3RELElBQUksQ0FBQ25DLEdBQUcsQ0FBQ0MsS0FBSyxDQUFFLHVDQUFzQ3pCLElBQUksQ0FBQ2dELG9CQUFxQixJQUFHLEdBQ2hGLGdCQUFlVixPQUFRLFVBQVMsQ0FBQztjQUNwQztZQUNGO1VBQ0Y7UUFDRjtNQUNGO0lBQ0Y7SUFFQUMsRUFBRSxHQUFHLE1BQU0sSUFBSSxDQUFDcUIsb0JBQW9CLENBQUM1RCxJQUFJLEVBQUUsSUFBSSxDQUFDRCxHQUFHLENBQUM4RCxXQUFXLEVBQUUsSUFBSSxDQUFDOUQsR0FBRyxFQUFFdUMsT0FBTyxDQUFDO0lBR25GQyxFQUFFLENBQUN1QixFQUFFLENBQUNDLDJCQUFZLENBQUNDLGFBQWEsRUFBR0MsR0FBRyxJQUFLO01BQ3pDLElBQUlBLEdBQUcsQ0FBQ0MsS0FBSyxLQUFLSCwyQkFBWSxDQUFDSSxhQUFhLEVBQUU7UUFDNUMsSUFBSSxDQUFDQyxrQkFBa0IsQ0FBQzlCLE9BQU8sQ0FBQztNQUNsQztJQUNGLENBQUMsQ0FBQztJQUVGLElBQUksQ0FBQ0Usb0JBQW9CLENBQUNGLE9BQU8sQ0FBQyxHQUFHQyxFQUFFO0VBQ3pDO0VBRUEsSUFBSSxDQUFDOEIsWUFBWSxHQUFHOUIsRUFBRTtFQUN0QixJQUFJLENBQUMrQixXQUFXLEdBQUcsSUFBSSxDQUFDRCxZQUFZLENBQUNFLFFBQVEsQ0FBQ0MsSUFBSSxDQUFDLElBQUksQ0FBQ0gsWUFBWSxDQUFDO0VBQ3JFLElBQUksQ0FBQ0ksWUFBWSxHQUFHLElBQUksQ0FBQ0osWUFBWSxDQUFDSyxPQUFPLENBQUNDLE9BQU8sQ0FBQ0gsSUFBSSxDQUFDLElBQUksQ0FBQ0gsWUFBWSxDQUFDSyxPQUFPLENBQUM7RUFDckYsSUFBSSxDQUFDRSxjQUFjLEdBQUcsSUFBSTtBQUM1QixDQUFDO0FBR0R2RixPQUFPLENBQUMyQyx3QkFBd0IsR0FBRyxTQUFTQSx3QkFBd0JBLENBQUEsRUFBSTtFQUN0RSxJQUFJLENBQUNxQyxZQUFZLEdBQUcsSUFBSTtFQUN4QixJQUFJLENBQUNDLFdBQVcsR0FBRyxJQUFJO0VBQ3ZCLElBQUksQ0FBQ0csWUFBWSxHQUFHLElBQUk7RUFDeEIsSUFBSSxDQUFDRyxjQUFjLEdBQUcsS0FBSztBQUM3QixDQUFDO0FBR0R2RixPQUFPLENBQUMrRSxrQkFBa0IsR0FBRyxlQUFlQSxrQkFBa0JBLENBQUU5QixPQUFPLEVBQUU7RUFDdkUsSUFBSSxDQUFDZCxHQUFHLENBQUNxRCxJQUFJLENBQUUsNEJBQTJCdkMsT0FBUSx1QkFBc0IsQ0FBQztFQUN6RSxJQUFJQSxPQUFPLEtBQUssSUFBSSxDQUFDN0MsVUFBVSxFQUFFO0lBRy9CLElBQUlxRixHQUFHLEdBQUcsSUFBSTdDLEtBQUssQ0FBQywrQ0FBK0MsQ0FBQztJQUNwRSxNQUFNLElBQUksQ0FBQzhDLHVCQUF1QixDQUFDRCxHQUFHLENBQUM7RUFDekMsQ0FBQyxNQUFNO0lBR0wsSUFBSSxDQUFDdEQsR0FBRyxDQUFDcUQsSUFBSSxDQUFDLDJEQUEyRCxHQUN2RSxtQkFBbUIsQ0FBQztJQUN0QixPQUFPLElBQUksQ0FBQ3JDLG9CQUFvQixDQUFDRixPQUFPLENBQUM7RUFDM0M7QUFDRixDQUFDO0FBSURqRCxPQUFPLENBQUMwQyx1QkFBdUIsR0FBRyxlQUFlQSx1QkFBdUJBLENBQUEsRUFBSTtFQUMxRSxJQUFJLENBQUNDLHdCQUF3QixDQUFDLENBQUM7RUFDL0IsS0FBSyxJQUFJTSxPQUFPLElBQUk3QixlQUFDLENBQUN1RSxJQUFJLENBQUMsSUFBSSxDQUFDeEMsb0JBQW9CLENBQUMsRUFBRTtJQUNyRCxJQUFJRCxFQUFFLEdBQUcsSUFBSSxDQUFDQyxvQkFBb0IsQ0FBQ0YsT0FBTyxDQUFDO0lBQzNDLElBQUksQ0FBQ2QsR0FBRyxDQUFDQyxLQUFLLENBQUUscUNBQW9DYSxPQUFRLEVBQUMsQ0FBQztJQUU5REMsRUFBRSxDQUFDMEMsa0JBQWtCLENBQUNsQiwyQkFBWSxDQUFDQyxhQUFhLENBQUM7SUFDakQsSUFBSTtNQUNGLE1BQU16QixFQUFFLENBQUMyQyxJQUFJLENBQUMsQ0FBQztJQUNqQixDQUFDLENBQUMsT0FBT0osR0FBRyxFQUFFO01BQ1osSUFBSSxDQUFDdEQsR0FBRyxDQUFDcUQsSUFBSSxDQUFFLGdDQUErQkMsR0FBRyxDQUFDSyxPQUFRLEVBQUMsQ0FBQztJQUM5RDtJQUNBLE9BQU8sSUFBSSxDQUFDM0Msb0JBQW9CLENBQUNGLE9BQU8sQ0FBQztFQUMzQztBQUNGLENBQUM7QUFFRGpELE9BQU8sQ0FBQ3VDLHFCQUFxQixHQUFHLFNBQVNBLHFCQUFxQkEsQ0FBRXdELFFBQVEsRUFBRTtFQUN4RSxPQUFPM0UsZUFBQyxDQUFDQyxRQUFRLENBQUMwRSxRQUFRLEVBQUU5RSwyQkFBVyxDQUFDLElBQUk4RSxRQUFRLEtBQUtDLDRCQUFZO0FBQ3ZFLENBQUM7QUFFRGhHLE9BQU8sQ0FBQ2lHLDBCQUEwQixHQUFHLFNBQVNBLDBCQUEwQkEsQ0FBQSxFQUFJO0VBQzFFLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FBQ3RGLElBQUksQ0FBQ3VGLGFBQWEsSUFDekI5RSxlQUFDLENBQUMrRSxPQUFPLENBQUMsSUFBSSxDQUFDeEYsSUFBSSxDQUFDdUYsYUFBYSxDQUFDRSxJQUFJLENBQUMsSUFDdkMsSUFBSSxDQUFDekYsSUFBSSxDQUFDdUYsYUFBYSxDQUFDRSxJQUFJLENBQUMvRSxRQUFRLENBQUMsZ0JBQWdCLENBQUM7QUFDaEUsQ0FBQztBQUVEckIsT0FBTyxDQUFDcUcsb0JBQW9CLEdBQUcsZUFBZUEsb0JBQW9CQSxDQUFBLEVBQUk7RUFDcEUsSUFBSSxDQUFDbEUsR0FBRyxDQUFDbUMsSUFBSSxDQUFDLGtDQUFrQyxDQUFDO0VBQ2pELElBQUlnQyxRQUFRLEdBQUcsTUFBTSxJQUFJLENBQUNDLGtCQUFrQixDQUFDLENBQUM7RUFDOUMsSUFBSUQsUUFBUSxLQUFLLHVEQUF1RCxFQUFFO0lBQ3hFLElBQUksQ0FBQ25FLEdBQUcsQ0FBQ21DLElBQUksQ0FBQyxtREFBbUQsQ0FBQztJQUNsRTtFQUNGO0VBQ0EsSUFBSWtDLEVBQUUsR0FBRyxNQUFNLElBQUksQ0FBQ0MsV0FBVyxDQUFDLElBQUksRUFBRSxvQ0FBb0MsRUFBRSxLQUFLLENBQUM7RUFDbEYsTUFBTSxJQUFJLENBQUNDLEtBQUssQ0FBQ0YsRUFBRSxDQUFDRyxPQUFPLENBQUM7RUFDNUIsSUFBSTtJQUNGLElBQUlILEVBQUUsR0FBRyxNQUFNLElBQUksQ0FBQ0MsV0FBVyxDQUFDLElBQUksRUFBRSx1Q0FBdUMsRUFBRSxLQUFLLENBQUM7SUFDckYsTUFBTSxJQUFJLENBQUNDLEtBQUssQ0FBQ0YsRUFBRSxDQUFDRyxPQUFPLENBQUM7RUFDOUIsQ0FBQyxDQUFDLE9BQU9DLENBQUMsRUFBRTtJQUdWLElBQUksQ0FBQ3pFLEdBQUcsQ0FBQ3FELElBQUksQ0FBRSxrREFBaURvQixDQUFDLENBQUNkLE9BQVEsRUFBQyxDQUFDO0VBQzlFO0FBQ0YsQ0FBQztBQUVEOUYsT0FBTyxDQUFDNkcsa0JBQWtCLEdBQUcsZUFBZUEsa0JBQWtCQSxDQUFBLEVBQUk7RUFDaEUsSUFBSSxDQUFDMUUsR0FBRyxDQUFDbUMsSUFBSSxDQUFDLHlDQUF5QyxDQUFDO0VBQ3hELElBQUkzRCxJQUFJLEdBQUdTLGVBQUMsQ0FBQ2lDLFNBQVMsQ0FBQyxJQUFJLENBQUMxQyxJQUFJLENBQUM7RUFFakMsTUFBTW1HLGFBQWEsR0FBRyxDQUNwQiwyQkFBMkIsRUFDM0Isb0JBQW9CLEVBQ3BCLGlCQUFpQixFQUNqQixxQkFBcUIsRUFDckIsNEJBQTRCLENBQzdCO0VBRUQsSUFBSTFGLGVBQUMsQ0FBQ0MsUUFBUSxDQUFDeUYsYUFBYSxFQUFFLElBQUksQ0FBQ25HLElBQUksQ0FBQ29DLFVBQVUsQ0FBQyxFQUFFO0lBQ25EcEMsSUFBSSxDQUFDb0csY0FBYyxHQUFHLElBQUksQ0FBQ3BHLElBQUksQ0FBQ29DLFVBQVU7RUFDNUMsQ0FBQyxNQUFNO0lBQ0xwQyxJQUFJLENBQUNxRyxxQkFBcUIsR0FBRyxJQUFJLENBQUNyRyxJQUFJLENBQUNzRyxXQUFXO0VBQ3BEO0VBQ0EsSUFBSSxDQUFDakMsWUFBWSxHQUFHLE1BQU0sSUFBSSxDQUFDVCxvQkFBb0IsQ0FBQzVELElBQUksRUFBRSxJQUFJLENBQUNELEdBQUcsQ0FBQzhELFdBQVcsRUFBRSxJQUFJLENBQUM5RCxHQUFHLENBQUM7RUFDekYsSUFBSSxDQUFDc0UsWUFBWSxDQUFDUCxFQUFFLENBQUNDLDJCQUFZLENBQUNDLGFBQWEsRUFBR0MsR0FBRyxJQUFLO0lBQ3hELElBQUlBLEdBQUcsQ0FBQ0MsS0FBSyxLQUFLSCwyQkFBWSxDQUFDSSxhQUFhLEVBQUU7TUFDNUMsSUFBSSxDQUFDQyxrQkFBa0IsQ0FBQ2lCLDRCQUFZLENBQUM7SUFDdkM7RUFDRixDQUFDLENBQUM7RUFLRixJQUFJLENBQUM1RixVQUFVLEdBQUc0Riw0QkFBWTtFQUM5QixJQUFJLENBQUM3QyxvQkFBb0IsQ0FBQzZDLDRCQUFZLENBQUMsR0FBRyxJQUFJLENBQUNoQixZQUFZO0VBQzNELElBQUksQ0FBQ0MsV0FBVyxHQUFHLElBQUksQ0FBQ0QsWUFBWSxDQUFDRSxRQUFRLENBQUNDLElBQUksQ0FBQyxJQUFJLENBQUNILFlBQVksQ0FBQztFQUNyRSxJQUFJLENBQUNJLFlBQVksR0FBRyxJQUFJLENBQUNKLFlBQVksQ0FBQ0ssT0FBTyxDQUFDQyxPQUFPLENBQUNILElBQUksQ0FBQyxJQUFJLENBQUNILFlBQVksQ0FBQ0ssT0FBTyxDQUFDO0VBQ3JGLElBQUksQ0FBQ0UsY0FBYyxHQUFHLElBQUk7RUFFMUIsSUFBSSxJQUFJLENBQUNVLDBCQUEwQixDQUFDLENBQUMsRUFBRTtJQUVyQyxNQUFNLElBQUksQ0FBQ0ksb0JBQW9CLENBQUMsQ0FBQztFQUNuQztBQUNGLENBQUM7QUFPRCxlQUFlakQseUJBQXlCQSxDQUFFakIsR0FBRyxFQUFFNkMsWUFBWSxFQUFFO0VBRzNELElBQUksRUFBQyxNQUFNQSxZQUFZLENBQUNrQyxpQkFBaUIsQ0FBQyxDQUFDLEdBQUU7SUFDM0MvRSxHQUFHLENBQUNDLEtBQUssQ0FBQyxnREFBZ0QsR0FDN0MsOEJBQThCLENBQUM7SUFDNUMsTUFBTTRDLFlBQVksQ0FBQ21DLE9BQU8sQ0FBQyxDQUFDO0VBQzlCO0VBQ0EsT0FBT25DLFlBQVk7QUFDckI7QUFlQSxlQUFlb0MsbUJBQW1CQSxDQUFFQyxRQUFRLEVBQUVsRixHQUFHLEdBQUcsSUFBSSxFQUFFO0VBQ3hELE1BQU1tRixPQUFPLEdBQUdDLGlCQUFDLENBQUNDLFNBQVMsQ0FBQ0MsbUJBQVUsQ0FBQ0gsT0FBTyxFQUFFO0lBQUNyRSxPQUFPLEVBQUV3RTtFQUFVLENBQUMsQ0FBQztFQUl0RSxJQUFJLENBQUNKLFFBQVEsRUFBRTtJQUNiLE1BQU1LLElBQUksR0FBRyxNQUFNSixPQUFPLENBQUMsQ0FBQztJQUM1Qm5GLEdBQUcsYUFBSEEsR0FBRyx1QkFBSEEsR0FBRyxDQUFFQyxLQUFLLENBQUUsaURBQWdEc0YsSUFBSyxFQUFDLENBQUM7SUFDbkUsT0FBT0EsSUFBSTtFQUNiO0VBR0F2RixHQUFHLGFBQUhBLEdBQUcsdUJBQUhBLEdBQUcsQ0FBRUMsS0FBSyxDQUFFLG1EQUFrREMsSUFBSSxDQUFDQyxTQUFTLENBQUMrRSxRQUFRLENBQUUsRUFBQyxDQUFDO0VBQ3pGLElBQUlNLFNBQVMsR0FBRyxJQUFJO0VBQ3BCLEtBQUssTUFBTUMsYUFBYSxJQUFJUCxRQUFRLEVBQUU7SUFDcEMsSUFBSUssSUFBSSxFQUFFRyxRQUFRO0lBQ2xCLElBQUl6RyxlQUFDLENBQUMrRSxPQUFPLENBQUN5QixhQUFhLENBQUMsRUFBRTtNQUMzQixDQUFDRixJQUFJLEVBQUVHLFFBQVEsQ0FBQyxHQUFHRCxhQUFhO0lBQ25DLENBQUMsTUFBTTtNQUNMRixJQUFJLEdBQUdJLFFBQVEsQ0FBQ0YsYUFBYSxFQUFFLEVBQUUsQ0FBQztNQUNsQ0MsUUFBUSxHQUFHSCxJQUFJO0lBQ2pCO0lBQ0EsSUFBSTtNQUNGdkYsR0FBRyxhQUFIQSxHQUFHLHVCQUFIQSxHQUFHLENBQUVDLEtBQUssQ0FBRSx1QkFBc0JzRixJQUFLLElBQUdHLFFBQVMsRUFBQyxDQUFDO01BQ3JERixTQUFTLEdBQUcsTUFBTUwsT0FBTyxDQUFDO1FBQUNJLElBQUk7UUFBRUc7TUFBUSxDQUFDLENBQUM7TUFDM0M7SUFDRixDQUFDLENBQUMsT0FBT2pCLENBQUMsRUFBRTtNQUNWekUsR0FBRyxhQUFIQSxHQUFHLHVCQUFIQSxHQUFHLENBQUVDLEtBQUssQ0FBRSx5QkFBd0JzRixJQUFLLElBQUdHLFFBQVMsZ0JBQWUsQ0FBQztJQUN2RTtFQUNGO0VBRUEsSUFBSUYsU0FBUyxLQUFLLElBQUksRUFBRTtJQUN0QixNQUFNLElBQUkvRSxLQUFLLENBQUUsb0RBQW1ELEdBQ25ELDBCQUF5QlAsSUFBSSxDQUFDQyxTQUFTLENBQUMrRSxRQUFRLENBQUUsRUFBQyxDQUFDO0VBQ3ZFO0VBRUFsRixHQUFHLGFBQUhBLEdBQUcsdUJBQUhBLEdBQUcsQ0FBRUMsS0FBSyxDQUFFLG1CQUFrQnVGLFNBQVUsbUJBQWtCLENBQUM7RUFDM0QsT0FBT0EsU0FBUztBQUNsQjtBQUVBM0gsT0FBTyxDQUFDK0gsaUNBQWlDLEdBQUcsU0FBU0EsaUNBQWlDQSxDQUFBLEVBQUk7RUFBQSxJQUFBQyxTQUFBO0VBQ3hGLElBQUksSUFBSSxDQUFDQyxnQkFBZ0IsQ0FBQ25JLGlDQUFpQyxDQUFDLEVBQUU7SUFDNUQsT0FBTyxJQUFJO0VBQ2I7RUFDQSxJQUFJLGFBQUosSUFBSSx3QkFBQWtJLFNBQUEsR0FBSixJQUFJLENBQUU3RixHQUFHLGNBQUE2RixTQUFBLHVCQUFUQSxTQUFBLENBQVc1RixLQUFLLENBQUUsK0NBQThDLEdBQzdELFFBQU90QyxpQ0FBa0MsK0JBQThCLENBQUM7RUFDM0UsT0FBTyxLQUFLO0FBQ2QsQ0FBQztBQUVERSxPQUFPLENBQUN1RSxvQkFBb0IsR0FBRyxlQUFlQSxvQkFBb0JBLENBQUU1RCxJQUFJLEVBQUU2RCxXQUFXLEVBQUU5RCxHQUFHLEVBQUV1QyxPQUFPLEdBQUcsSUFBSSxFQUFFO0VBQUEsSUFBQWlGLHFCQUFBLEVBQUFDLFVBQUE7RUFDMUcsSUFBSXhILElBQUksQ0FBQ3lILGdCQUFnQixFQUFFO0lBQUEsSUFBQUMsVUFBQTtJQUN6QixJQUFJLGFBQUosSUFBSSx3QkFBQUEsVUFBQSxHQUFKLElBQUksQ0FBRWxHLEdBQUcsY0FBQWtHLFVBQUEsdUJBQVRBLFVBQUEsQ0FBVzdDLElBQUksQ0FBRSx3RkFBdUYsQ0FBQztJQUN6RzdFLElBQUksQ0FBQzJILGdCQUFnQixHQUFHM0gsSUFBSSxDQUFDeUgsZ0JBQWdCO0VBQy9DO0VBRUEsSUFBSXpILElBQUksQ0FBQzJILGdCQUFnQixFQUFFO0lBQUEsSUFBQUMsVUFBQTtJQUN6QixJQUFJLGFBQUosSUFBSSx3QkFBQUEsVUFBQSxHQUFKLElBQUksQ0FBRXBHLEdBQUcsY0FBQW9HLFVBQUEsdUJBQVRBLFVBQUEsQ0FBV25HLEtBQUssQ0FBRSw2QkFBNEJ6QixJQUFJLENBQUMySCxnQkFBaUIsbUJBQWtCLENBQUM7RUFDekYsQ0FBQyxNQUFNO0lBRUwzSCxJQUFJLENBQUMySCxnQkFBZ0IsR0FBRyxNQUFNbEIsbUJBQW1CLENBQUN6RyxJQUFJLENBQUM2SCxpQkFBaUIsRUFBRSxJQUFJLGFBQUosSUFBSSx1QkFBSixJQUFJLENBQUVyRyxHQUFHLENBQUM7RUFDdEY7RUFFQSxNQUFNc0csT0FBTyxHQUFHeEYsT0FBTyxHQUFHekMsdUJBQWMsQ0FBQ2tJLGlCQUFpQixDQUFDaEksR0FBRyxFQUFFdUMsT0FBTyxDQUFDLEdBQUcwRixTQUFTO0VBQ3BGLElBQUksQ0FBQ3ZILGVBQUMsQ0FBQ3dILE9BQU8sQ0FBQ0gsT0FBTyxDQUFDLEVBQUU7SUFBQSxJQUFBSSxVQUFBO0lBQ3ZCLElBQUksYUFBSixJQUFJLHdCQUFBQSxVQUFBLEdBQUosSUFBSSxDQUFFMUcsR0FBRyxjQUFBMEcsVUFBQSx1QkFBVEEsVUFBQSxDQUFXekcsS0FBSyxDQUFDLDREQUE0RCxHQUMzRUMsSUFBSSxDQUFDQyxTQUFTLENBQUNtRyxPQUFPLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDO0VBQ3JDO0VBRUEsTUFBTXpELFlBQVksR0FBRyxJQUFJTiwyQkFBWSxDQUFDO0lBQ3BDZ0QsSUFBSSxFQUFFL0csSUFBSSxDQUFDMkgsZ0JBQWdCO0lBQzNCUSxVQUFVLEVBQUVuSSxJQUFJLENBQUNvSSxzQkFBc0I7SUFDdkNySSxHQUFHO0lBQ0hzSSxPQUFPLEVBQUVySSxJQUFJLENBQUNzSSxnQkFBZ0I7SUFDOUJDLE9BQU8sRUFBRSxDQUFDLENBQUN2SSxJQUFJLENBQUN3SSxtQkFBbUI7SUFDbkNDLGFBQWEsRUFBRXpJLElBQUksQ0FBQzBJLHlCQUF5QjtJQUM3Q0MsV0FBVyxFQUFFM0ksSUFBSSxDQUFDNEksNkJBQTZCO0lBQy9DQyxRQUFRLEVBQUU3SSxJQUFJLENBQUNvRyxjQUFjO0lBQzdCMEMsbUJBQW1CLEVBQUU5SSxJQUFJLENBQUMrSSwrQkFBK0I7SUFDekRDLGlCQUFpQixFQUFFaEosSUFBSSxDQUFDaUosNkJBQTZCO0lBQ3JEbkIsT0FBTztJQUNQb0IscUJBQXFCLEVBQUUsSUFBSSxhQUFKLElBQUksd0JBQUEzQixxQkFBQSxHQUFKLElBQUksQ0FBRUgsaUNBQWlDLGNBQUFHLHFCQUFBLHVCQUF2Q0EscUJBQUEsQ0FBQXZJLElBQUEsS0FBMEM7RUFDbkUsQ0FBQyxDQUFDO0VBR0ZnQixJQUFJLENBQUN1RixhQUFhLEdBQUd2RixJQUFJLENBQUN1RixhQUFhLElBQUksQ0FBQyxDQUFDO0VBRzdDLEtBQUssTUFBTTRELEdBQUcsSUFBSTFJLGVBQUMsQ0FBQ3VFLElBQUksQ0FBQ2hGLElBQUksQ0FBQyxFQUFFO0lBQzlCLElBQUltSixHQUFHLENBQUNDLFFBQVEsQ0FBQyxnQkFBZ0IsQ0FBQyxFQUFFO01BQUEsSUFBQUMsVUFBQTtNQUNsQyxJQUFJLGFBQUosSUFBSSx3QkFBQUEsVUFBQSxHQUFKLElBQUksQ0FBRTdILEdBQUcsY0FBQTZILFVBQUEsdUJBQVRBLFVBQUEsQ0FBV3hFLElBQUksQ0FBRSxZQUFXc0UsR0FBSSw0REFBMkQsQ0FBQztNQUM1RjFJLGVBQUMsQ0FBQzZJLEtBQUssQ0FBQ3RKLElBQUksQ0FBQ3VGLGFBQWEsRUFBRXZGLElBQUksQ0FBQ21KLEdBQUcsQ0FBQyxDQUFDO0lBQ3hDO0VBQ0Y7RUFFQSxNQUFNSSxJQUFJLEdBQUcxSix1QkFBYyxDQUFDMkosc0JBQXNCLENBQUN4SixJQUFJLEVBQUU2RCxXQUFXLEVBQUVpRSxPQUFPLENBQUM7RUFDOUUsSUFBSSxhQUFKLElBQUksd0JBQUFOLFVBQUEsR0FBSixJQUFJLENBQUVoRyxHQUFHLGNBQUFnRyxVQUFBLHVCQUFUQSxVQUFBLENBQVcvRixLQUFLLENBQUUsb0RBQW1EOEgsSUFBSSxDQUFDaEUsYUFBYSxDQUFDMUMsY0FBZSxHQUFFLENBQUM7RUFDMUcsTUFBTXdCLFlBQVksQ0FBQ29GLEtBQUssQ0FBQ0YsSUFBSSxDQUFDO0VBQzlCLE9BQU9sRixZQUFZO0FBQ3JCLENBQUM7QUFDRCxNQUFNVCxvQkFBb0IsR0FBR3ZFLE9BQU8sQ0FBQ3VFLG9CQUFvQjtBQUFDckUsT0FBQSxDQUFBcUUsb0JBQUEsR0FBQUEsb0JBQUE7QUFHMURsRixNQUFNLENBQUN5QyxNQUFNLENBQUM3QixVQUFVLEVBQUVGLFFBQVEsRUFBRUMsT0FBTyxDQUFDO0FBQUMsSUFBQXFLLFFBQUEsR0FFOUJwSyxVQUFVO0FBQUFDLE9BQUEsQ0FBQW5CLE9BQUEsR0FBQXNMLFFBQUEifQ==
|
|
471
|
+
exports.default = extensions;
|
|
472
|
+
//# sourceMappingURL=context.js.map
|