@appium/images-plugin 1.1.5 → 1.1.10
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/LICENSE +2 -2
- package/README.md +1 -1
- package/build/lib/compare.d.ts +28 -0
- package/build/lib/compare.d.ts.map +1 -0
- package/build/lib/compare.js +62 -65
- package/build/lib/finder.d.ts +156 -0
- package/build/lib/finder.d.ts.map +1 -0
- package/build/lib/finder.js +321 -363
- package/build/lib/image-element.d.ts +107 -0
- package/build/lib/image-element.d.ts.map +1 -0
- package/build/lib/image-element.js +194 -238
- package/build/lib/logger.d.ts +3 -0
- package/build/lib/logger.d.ts.map +1 -0
- package/build/lib/logger.js +15 -5
- package/build/lib/plugin.d.ts +26 -0
- package/build/lib/plugin.d.ts.map +1 -0
- package/build/lib/plugin.js +87 -127
- package/build/tsconfig.tsbuildinfo +1 -0
- package/index.js +1 -3
- package/lib/compare.js +35 -11
- package/lib/finder.js +46 -26
- package/lib/image-element.js +17 -23
- package/lib/logger.js +1 -1
- package/lib/plugin.js +3 -36
- package/package.json +28 -22
- package/build/index.js +0 -27
- package/build/test/e2e/plugin-e2e-specs.js +0 -77
- package/build/test/fixtures/appstore.png +0 -0
- package/build/test/fixtures/img1.png +0 -0
- package/build/test/fixtures/img2.png +0 -0
- package/build/test/fixtures/img2_part.png +0 -0
- package/build/test/fixtures/index.js +0 -24
- package/build/test/unit/basic-specs.js +0 -16
- package/build/test/unit/finder-specs.js +0 -406
- package/build/test/unit/image-element-specs.js +0 -320
- package/build/test/unit/plugin-specs.js +0 -192
package/build/lib/finder.js
CHANGED
|
@@ -1,384 +1,342 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
|
|
5
|
+
Object.defineProperty(exports, "__esModule", {
|
|
6
|
+
value: true
|
|
7
|
+
});
|
|
8
|
+
exports.default = exports.W3C_ELEMENT_KEY = exports.MJSONWP_ELEMENT_KEY = exports.DEFAULT_SETTINGS = exports.DEFAULT_FIX_IMAGE_TEMPLATE_SCALE = void 0;
|
|
9
|
+
|
|
10
|
+
require("source-map-support/register");
|
|
11
|
+
|
|
12
|
+
var _lodash = _interopRequireDefault(require("lodash"));
|
|
13
|
+
|
|
14
|
+
var _lruCache = _interopRequireDefault(require("lru-cache"));
|
|
15
|
+
|
|
16
|
+
var _support = require("@appium/support");
|
|
17
|
+
|
|
18
|
+
var _baseDriver = require("@appium/base-driver");
|
|
19
|
+
|
|
20
|
+
var _imageElement = require("./image-element");
|
|
21
|
+
|
|
22
|
+
var _compare = require("./compare");
|
|
23
|
+
|
|
24
|
+
var _logger = _interopRequireDefault(require("./logger"));
|
|
25
|
+
|
|
22
26
|
const MJSONWP_ELEMENT_KEY = 'ELEMENT';
|
|
23
27
|
exports.MJSONWP_ELEMENT_KEY = MJSONWP_ELEMENT_KEY;
|
|
24
|
-
const W3C_ELEMENT_KEY =
|
|
28
|
+
const W3C_ELEMENT_KEY = _support.util.W3C_WEB_ELEMENT_IDENTIFIER;
|
|
25
29
|
exports.W3C_ELEMENT_KEY = W3C_ELEMENT_KEY;
|
|
26
30
|
const DEFAULT_FIX_IMAGE_TEMPLATE_SCALE = 1;
|
|
27
31
|
exports.DEFAULT_FIX_IMAGE_TEMPLATE_SCALE = DEFAULT_FIX_IMAGE_TEMPLATE_SCALE;
|
|
28
|
-
// Used to compare ratio and screen width
|
|
29
|
-
// Pixel is basically under 1080 for example. 100K is probably enough fo a while.
|
|
30
32
|
const FLOAT_PRECISION = 100000;
|
|
31
|
-
const MAX_CACHE_SIZE = 1024 * 1024 * 40;
|
|
33
|
+
const MAX_CACHE_SIZE = 1024 * 1024 * 40;
|
|
32
34
|
const DEFAULT_SETTINGS = {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
// whether Appium should ensure that an image template sent in during image
|
|
44
|
-
// element find should have its scale adjusted to display size so the match
|
|
45
|
-
// algorithm will not complain.
|
|
46
|
-
// e.g. iOS has `width=375, height=667` window rect, but its screenshot is
|
|
47
|
-
// `width=750 × height=1334` pixels. This setting help to adjust the scale
|
|
48
|
-
// if a user use `width=750 × height=1334` pixels's base template image.
|
|
49
|
-
fixImageTemplateScale: false,
|
|
50
|
-
// Users might have scaled template image to reduce their storage size.
|
|
51
|
-
// This setting allows users to scale a template image they send to Appium server
|
|
52
|
-
// so that the Appium server compares the actual scale users originally had.
|
|
53
|
-
// e.g. If a user has an image of 270 x 32 pixels which was originally 1080 x 126 pixels,
|
|
54
|
-
// the user can set {defaultImageTemplateScale: 4.0} to scale the small image
|
|
55
|
-
// to the original one so that Appium can compare it as the original one.
|
|
56
|
-
defaultImageTemplateScale: image_element_1.DEFAULT_TEMPLATE_IMAGE_SCALE,
|
|
57
|
-
// whether Appium should re-check that an image element can be matched
|
|
58
|
-
// against the current screenshot before clicking it
|
|
59
|
-
checkForImageElementStaleness: true,
|
|
60
|
-
// whether before clicking on an image element Appium should re-determine the
|
|
61
|
-
// position of the element on screen
|
|
62
|
-
autoUpdateImageElementPosition: false,
|
|
63
|
-
// which method to use for tapping by coordinate for image elements. the
|
|
64
|
-
// options are 'w3c' or 'mjsonwp'
|
|
65
|
-
imageElementTapStrategy: image_element_1.IMAGE_EL_TAP_STRATEGY_W3C,
|
|
66
|
-
// which method to use to save the matched image area in ImageElement class.
|
|
67
|
-
// It is used for debugging purpose.
|
|
68
|
-
getMatchedImageResult: false,
|
|
35
|
+
imageMatchThreshold: _compare.DEFAULT_MATCH_THRESHOLD,
|
|
36
|
+
imageMatchMethod: '',
|
|
37
|
+
fixImageFindScreenshotDims: true,
|
|
38
|
+
fixImageTemplateSize: false,
|
|
39
|
+
fixImageTemplateScale: false,
|
|
40
|
+
defaultImageTemplateScale: _imageElement.DEFAULT_TEMPLATE_IMAGE_SCALE,
|
|
41
|
+
checkForImageElementStaleness: true,
|
|
42
|
+
autoUpdateImageElementPosition: false,
|
|
43
|
+
imageElementTapStrategy: _imageElement.IMAGE_EL_TAP_STRATEGY_W3C,
|
|
44
|
+
getMatchedImageResult: false
|
|
69
45
|
};
|
|
70
46
|
exports.DEFAULT_SETTINGS = DEFAULT_SETTINGS;
|
|
47
|
+
|
|
71
48
|
class ImageElementFinder {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
49
|
+
constructor(driver, max = MAX_CACHE_SIZE) {
|
|
50
|
+
this.driver = driver;
|
|
51
|
+
this.imgElCache = new _lruCache.default({
|
|
52
|
+
max,
|
|
53
|
+
length: el => el.template.length
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
setDriver(driver) {
|
|
58
|
+
this.driver = driver;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
registerImageElement(imgEl) {
|
|
62
|
+
this.imgElCache.set(imgEl.id, imgEl);
|
|
63
|
+
const protoKey = this.driver.isW3CProtocol() ? W3C_ELEMENT_KEY : MJSONWP_ELEMENT_KEY;
|
|
64
|
+
return imgEl.asElement(protoKey);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async findByImage(b64Template, {
|
|
68
|
+
shouldCheckStaleness = false,
|
|
69
|
+
multiple = false,
|
|
70
|
+
ignoreDefaultImageTemplateScale = false
|
|
71
|
+
}) {
|
|
72
|
+
if (!this.driver) {
|
|
73
|
+
throw new Error(`Can't find without a driver!`);
|
|
78
74
|
}
|
|
79
|
-
|
|
80
|
-
|
|
75
|
+
|
|
76
|
+
const settings = { ...DEFAULT_SETTINGS,
|
|
77
|
+
...this.driver.settings.getSettings()
|
|
78
|
+
};
|
|
79
|
+
const {
|
|
80
|
+
imageMatchThreshold: threshold,
|
|
81
|
+
imageMatchMethod,
|
|
82
|
+
fixImageTemplateSize,
|
|
83
|
+
fixImageTemplateScale,
|
|
84
|
+
defaultImageTemplateScale,
|
|
85
|
+
getMatchedImageResult: visualize
|
|
86
|
+
} = settings;
|
|
87
|
+
|
|
88
|
+
_logger.default.info(`Finding image element with match threshold ${threshold}`);
|
|
89
|
+
|
|
90
|
+
if (!this.driver.getWindowSize) {
|
|
91
|
+
throw new Error("This driver does not support the required 'getWindowSize' command");
|
|
81
92
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
93
|
+
|
|
94
|
+
const {
|
|
95
|
+
width: screenWidth,
|
|
96
|
+
height: screenHeight
|
|
97
|
+
} = await this.driver.getWindowSize();
|
|
98
|
+
|
|
99
|
+
if (fixImageTemplateSize) {
|
|
100
|
+
b64Template = await this.ensureTemplateSize(b64Template, screenWidth, screenHeight);
|
|
86
101
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
* @param {string} b64Template - base64-encoded image used as a template to be
|
|
102
|
-
* matched in the screenshot
|
|
103
|
-
* @param {FindByImageOptions} - additional options
|
|
104
|
-
*
|
|
105
|
-
* @returns {WebElement} - WebDriver element with a special id prefix
|
|
106
|
-
*/
|
|
107
|
-
findByImage(b64Template, { shouldCheckStaleness = false, multiple = false, ignoreDefaultImageTemplateScale = false, }) {
|
|
108
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
109
|
-
if (!this.driver) {
|
|
110
|
-
throw new Error(`Can't find without a driver!`);
|
|
111
|
-
}
|
|
112
|
-
const settings = Object.assign({}, DEFAULT_SETTINGS, this.driver.settings.getSettings());
|
|
113
|
-
const { imageMatchThreshold: threshold, fixImageTemplateSize, fixImageTemplateScale, defaultImageTemplateScale, getMatchedImageResult: visualize, } = settings;
|
|
114
|
-
logger_1.default.info(`Finding image element with match threshold ${threshold}`);
|
|
115
|
-
if (!this.driver.getWindowSize) {
|
|
116
|
-
throw new Error("This driver does not support the required 'getWindowSize' command");
|
|
117
|
-
}
|
|
118
|
-
const { width: screenWidth, height: screenHeight } = yield this.driver.getWindowSize();
|
|
119
|
-
// someone might have sent in a template that's larger than the screen
|
|
120
|
-
// dimensions. If so let's check and cut it down to size since the algorithm
|
|
121
|
-
// will not work unless we do. But because it requires some potentially
|
|
122
|
-
// expensive commands, only do this if the user has requested it in settings.
|
|
123
|
-
if (fixImageTemplateSize) {
|
|
124
|
-
b64Template = yield this.ensureTemplateSize(b64Template, screenWidth, screenHeight);
|
|
125
|
-
}
|
|
126
|
-
let rect = null;
|
|
127
|
-
let b64Matched = null;
|
|
128
|
-
let score = 0;
|
|
129
|
-
const condition = () => __awaiter(this, void 0, void 0, function* () {
|
|
130
|
-
try {
|
|
131
|
-
const { b64Screenshot, scale } = yield this.getScreenshotForImageFind(screenWidth, screenHeight);
|
|
132
|
-
b64Template = yield this.fixImageTemplateScale(b64Template, Object.assign({ defaultImageTemplateScale, ignoreDefaultImageTemplateScale,
|
|
133
|
-
fixImageTemplateScale }, scale));
|
|
134
|
-
const comparedImage = yield compare_1.compareImages(compare_1.MATCH_TEMPLATE_MODE, b64Screenshot, b64Template, { threshold, visualize });
|
|
135
|
-
rect = comparedImage.rect;
|
|
136
|
-
b64Matched = comparedImage.visualization;
|
|
137
|
-
score = comparedImage.score;
|
|
138
|
-
return true;
|
|
139
|
-
}
|
|
140
|
-
catch (err) {
|
|
141
|
-
// if compareImages fails, we'll get a specific error, but we should
|
|
142
|
-
// retry, so trap that and just return false to trigger the next round of
|
|
143
|
-
// implicitly waiting. For other errors, throw them to get out of the
|
|
144
|
-
// implicit wait loop
|
|
145
|
-
if (err.message.match(/Cannot find any occurrences/)) {
|
|
146
|
-
return false;
|
|
147
|
-
}
|
|
148
|
-
throw err;
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
try {
|
|
152
|
-
yield this.driver.implicitWaitForCondition(condition);
|
|
153
|
-
}
|
|
154
|
-
catch (err) {
|
|
155
|
-
// this `implicitWaitForCondition` method will throw a 'Condition unmet'
|
|
156
|
-
// error if an element is not found eventually. In that case, we will
|
|
157
|
-
// handle the element not found response below. In the case where get some
|
|
158
|
-
// _other_ kind of error, it means something blew up totally apart from the
|
|
159
|
-
// implicit wait timeout. We should not mask that error and instead throw
|
|
160
|
-
// it straightaway
|
|
161
|
-
if (!err.message.match(/Condition unmet/)) {
|
|
162
|
-
throw err;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
if (!rect) {
|
|
166
|
-
if (multiple) {
|
|
167
|
-
return [];
|
|
168
|
-
}
|
|
169
|
-
throw new appium_base_driver_1.errors.NoSuchElementError();
|
|
170
|
-
}
|
|
171
|
-
logger_1.default.info(`Image template matched: ${JSON.stringify(rect)}`);
|
|
172
|
-
if (b64Matched) {
|
|
173
|
-
logger_1.default.info(`Matched base64 data: ${b64Matched.substring(0, 200)}...`);
|
|
174
|
-
}
|
|
175
|
-
const imgEl = new image_element_1.ImageElement(b64Template, rect, score, b64Matched, this);
|
|
176
|
-
// if we're just checking staleness, return straightaway so we don't add
|
|
177
|
-
// a new element to the cache. shouldCheckStaleness does not support multiple
|
|
178
|
-
// elements, since it is a purely internal mechanism
|
|
179
|
-
if (shouldCheckStaleness) {
|
|
180
|
-
return imgEl;
|
|
181
|
-
}
|
|
182
|
-
const protocolEl = this.registerImageElement(imgEl);
|
|
183
|
-
return multiple ? [protocolEl] : protocolEl;
|
|
102
|
+
|
|
103
|
+
const results = [];
|
|
104
|
+
|
|
105
|
+
const condition = async () => {
|
|
106
|
+
try {
|
|
107
|
+
const {
|
|
108
|
+
b64Screenshot,
|
|
109
|
+
scale
|
|
110
|
+
} = await this.getScreenshotForImageFind(screenWidth, screenHeight);
|
|
111
|
+
b64Template = await this.fixImageTemplateScale(b64Template, {
|
|
112
|
+
defaultImageTemplateScale,
|
|
113
|
+
ignoreDefaultImageTemplateScale,
|
|
114
|
+
fixImageTemplateScale,
|
|
115
|
+
...scale
|
|
184
116
|
});
|
|
117
|
+
const comparisonOpts = {
|
|
118
|
+
threshold,
|
|
119
|
+
visualize,
|
|
120
|
+
multiple
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
if (imageMatchMethod) {
|
|
124
|
+
comparisonOpts.method = imageMatchMethod;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (multiple) {
|
|
128
|
+
results.push(...(await (0, _compare.compareImages)(_compare.MATCH_TEMPLATE_MODE, b64Screenshot, b64Template, comparisonOpts)));
|
|
129
|
+
} else {
|
|
130
|
+
results.push(await (0, _compare.compareImages)(_compare.MATCH_TEMPLATE_MODE, b64Screenshot, b64Template, comparisonOpts));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return true;
|
|
134
|
+
} catch (err) {
|
|
135
|
+
if (err.message.match(/Cannot find any occurrences/)) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
throw err;
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
try {
|
|
144
|
+
await this.driver.implicitWaitForCondition(condition);
|
|
145
|
+
} catch (err) {
|
|
146
|
+
if (!err.message.match(/Condition unmet/)) {
|
|
147
|
+
throw err;
|
|
148
|
+
}
|
|
185
149
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
* @returns {string} base64-encoded image, potentially resized
|
|
194
|
-
*/
|
|
195
|
-
ensureTemplateSize(b64Template, screenWidth, screenHeight) {
|
|
196
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
197
|
-
let imgObj = yield appium_support_1.imageUtil.getJimpImage(b64Template);
|
|
198
|
-
let { width: tplWidth, height: tplHeight } = imgObj.bitmap;
|
|
199
|
-
logger_1.default.info(`Template image is ${tplWidth}x${tplHeight}. Screen size is ${screenWidth}x${screenHeight}`);
|
|
200
|
-
// if the template fits inside the screen dimensions, we're good
|
|
201
|
-
if (tplWidth <= screenWidth && tplHeight <= screenHeight) {
|
|
202
|
-
return b64Template;
|
|
203
|
-
}
|
|
204
|
-
logger_1.default.info(`Scaling template image from ${tplWidth}x${tplHeight} to match ` +
|
|
205
|
-
`screen at ${screenWidth}x${screenHeight}`);
|
|
206
|
-
// otherwise, scale it to fit inside the screen dimensions
|
|
207
|
-
imgObj = imgObj.scaleToFit(screenWidth, screenHeight);
|
|
208
|
-
return (yield imgObj.getBuffer(appium_support_1.imageUtil.MIME_PNG)).toString('base64');
|
|
209
|
-
});
|
|
150
|
+
|
|
151
|
+
if (_lodash.default.isEmpty(results)) {
|
|
152
|
+
if (multiple) {
|
|
153
|
+
return [];
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
throw new _baseDriver.errors.NoSuchElementError();
|
|
210
157
|
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
* @param {int} screenWidth - width of screen
|
|
225
|
-
* @param {int} screenHeight - height of screen
|
|
226
|
-
*
|
|
227
|
-
* @returns {Screenshot, ?ScreenshotScale} base64-encoded screenshot and ScreenshotScale
|
|
228
|
-
*/
|
|
229
|
-
getScreenshotForImageFind(screenWidth, screenHeight) {
|
|
230
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
231
|
-
if (!this.driver.getScreenshot) {
|
|
232
|
-
throw new Error("This driver does not support the required 'getScreenshot' command");
|
|
233
|
-
}
|
|
234
|
-
const settings = Object.assign({}, DEFAULT_SETTINGS, this.driver.settings.getSettings());
|
|
235
|
-
const { fixImageFindScreenshotDims } = settings;
|
|
236
|
-
let b64Screenshot = yield this.driver.getScreenshot();
|
|
237
|
-
// if the user has requested not to correct for aspect or size differences
|
|
238
|
-
// between the screenshot and the screen, just return the screenshot now
|
|
239
|
-
if (!fixImageFindScreenshotDims) {
|
|
240
|
-
logger_1.default.info(`Not verifying screenshot dimensions match screen`);
|
|
241
|
-
return { b64Screenshot };
|
|
242
|
-
}
|
|
243
|
-
if (screenWidth < 1 || screenHeight < 1) {
|
|
244
|
-
logger_1.default.warn(`The retrieved screen size ${screenWidth}x${screenHeight} does ` +
|
|
245
|
-
`not seem to be valid. No changes will be applied to the screenshot`);
|
|
246
|
-
return { b64Screenshot };
|
|
247
|
-
}
|
|
248
|
-
// otherwise, do some verification on the screenshot to make sure it matches
|
|
249
|
-
// the screen size and aspect ratio
|
|
250
|
-
logger_1.default.info('Verifying screenshot size and aspect ratio');
|
|
251
|
-
let imgObj = yield appium_support_1.imageUtil.getJimpImage(b64Screenshot);
|
|
252
|
-
let { width: shotWidth, height: shotHeight } = imgObj.bitmap;
|
|
253
|
-
if (shotWidth < 1 || shotHeight < 1) {
|
|
254
|
-
logger_1.default.warn(`The retrieved screenshot size ${shotWidth}x${shotHeight} does ` +
|
|
255
|
-
`not seem to be valid. No changes will be applied to the screenshot`);
|
|
256
|
-
return { b64Screenshot };
|
|
257
|
-
}
|
|
258
|
-
if (screenWidth === shotWidth && screenHeight === shotHeight) {
|
|
259
|
-
// the height and width of the screenshot and the device screen match, which
|
|
260
|
-
// means we should be safe when doing template matches
|
|
261
|
-
logger_1.default.info('Screenshot size matched screen size');
|
|
262
|
-
return { b64Screenshot };
|
|
263
|
-
}
|
|
264
|
-
// otherwise, if they don't match, it could spell problems for the accuracy
|
|
265
|
-
// of coordinates returned by the image match algorithm, since we match based
|
|
266
|
-
// on the screenshot coordinates not the device coordinates themselves. There
|
|
267
|
-
// are two potential types of mismatch: aspect ratio mismatch and scale
|
|
268
|
-
// mismatch. We need to detect and fix both
|
|
269
|
-
const scale = { xScale: 1.0, yScale: 1.0 };
|
|
270
|
-
const screenAR = screenWidth / screenHeight;
|
|
271
|
-
const shotAR = shotWidth / shotHeight;
|
|
272
|
-
if (Math.round(screenAR * FLOAT_PRECISION) === Math.round(shotAR * FLOAT_PRECISION)) {
|
|
273
|
-
logger_1.default.info(`Screenshot aspect ratio '${shotAR}' (${shotWidth}x${shotHeight}) matched ` +
|
|
274
|
-
`screen aspect ratio '${screenAR}' (${screenWidth}x${screenHeight})`);
|
|
275
|
-
}
|
|
276
|
-
else {
|
|
277
|
-
logger_1.default.warn(`When trying to find an element, determined that the screen ` +
|
|
278
|
-
`aspect ratio and screenshot aspect ratio are different. Screen ` +
|
|
279
|
-
`is ${screenWidth}x${screenHeight} whereas screenshot is ` +
|
|
280
|
-
`${shotWidth}x${shotHeight}.`);
|
|
281
|
-
// In the case where the x-scale and y-scale are different, we need to decide
|
|
282
|
-
// which one to respect, otherwise the screenshot and template will end up
|
|
283
|
-
// being resized in a way that changes its aspect ratio (distorts it). For example, let's say:
|
|
284
|
-
// this.getScreenshot(shotWidth, shotHeight) is 540x397,
|
|
285
|
-
// this.getDeviceSize(screenWidth, screenHeight) is 1080x1920.
|
|
286
|
-
// The ratio would then be {xScale: 0.5, yScale: 0.2}.
|
|
287
|
-
// In this case, we must should `yScale: 0.2` as scaleFactor, because
|
|
288
|
-
// if we select the xScale, the height will be bigger than real screenshot size
|
|
289
|
-
// which is used to image comparison by OpenCV as a base image.
|
|
290
|
-
// All of this is primarily useful when the screenshot is a horizontal slice taken out of the
|
|
291
|
-
// screen (for example not including top/bottom nav bars)
|
|
292
|
-
const xScale = (1.0 * shotWidth) / screenWidth;
|
|
293
|
-
const yScale = (1.0 * shotHeight) / screenHeight;
|
|
294
|
-
const scaleFactor = xScale >= yScale ? yScale : xScale;
|
|
295
|
-
logger_1.default.warn(`Resizing screenshot to ${shotWidth * scaleFactor}x${shotHeight * scaleFactor} to match ` +
|
|
296
|
-
`screen aspect ratio so that image element coordinates have a ` +
|
|
297
|
-
`greater chance of being correct.`);
|
|
298
|
-
imgObj = imgObj.resize(shotWidth * scaleFactor, shotHeight * scaleFactor);
|
|
299
|
-
scale.xScale *= scaleFactor;
|
|
300
|
-
scale.yScale *= scaleFactor;
|
|
301
|
-
shotWidth = imgObj.bitmap.width;
|
|
302
|
-
shotHeight = imgObj.bitmap.height;
|
|
303
|
-
}
|
|
304
|
-
// Resize based on the screen dimensions only if both width and height are mismatched
|
|
305
|
-
// since except for that, it might be a situation which is different window rect and
|
|
306
|
-
// screenshot size like `@driver.window_rect #=>x=0, y=0, width=1080, height=1794` and
|
|
307
|
-
// `"deviceScreenSize"=>"1080x1920"`
|
|
308
|
-
if (screenWidth !== shotWidth && screenHeight !== shotHeight) {
|
|
309
|
-
logger_1.default.info(`Scaling screenshot from ${shotWidth}x${shotHeight} to match ` +
|
|
310
|
-
`screen at ${screenWidth}x${screenHeight}`);
|
|
311
|
-
imgObj = imgObj.resize(screenWidth, screenHeight);
|
|
312
|
-
scale.xScale *= (1.0 * screenWidth) / shotWidth;
|
|
313
|
-
scale.yScale *= (1.0 * screenHeight) / shotHeight;
|
|
314
|
-
}
|
|
315
|
-
b64Screenshot = (yield imgObj.getBuffer(appium_support_1.imageUtil.MIME_PNG)).toString('base64');
|
|
316
|
-
return { b64Screenshot, scale };
|
|
317
|
-
});
|
|
158
|
+
|
|
159
|
+
const elements = results.map(({
|
|
160
|
+
rect,
|
|
161
|
+
score,
|
|
162
|
+
visualization
|
|
163
|
+
}) => {
|
|
164
|
+
_logger.default.info(`Image template matched: ${JSON.stringify(rect)}`);
|
|
165
|
+
|
|
166
|
+
return new _imageElement.ImageElement(b64Template, rect, score, visualization, this);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
if (shouldCheckStaleness) {
|
|
170
|
+
return elements[0];
|
|
318
171
|
}
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
172
|
+
|
|
173
|
+
const registeredElements = elements.map(imgEl => this.registerImageElement(imgEl));
|
|
174
|
+
return multiple ? registeredElements : registeredElements[0];
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async ensureTemplateSize(b64Template, screenWidth, screenHeight) {
|
|
178
|
+
let imgObj = await _support.imageUtil.getJimpImage(b64Template);
|
|
179
|
+
let {
|
|
180
|
+
width: tplWidth,
|
|
181
|
+
height: tplHeight
|
|
182
|
+
} = imgObj.bitmap;
|
|
183
|
+
|
|
184
|
+
_logger.default.info(`Template image is ${tplWidth}x${tplHeight}. Screen size is ${screenWidth}x${screenHeight}`);
|
|
185
|
+
|
|
186
|
+
if (tplWidth <= screenWidth && tplHeight <= screenHeight) {
|
|
187
|
+
return b64Template;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
_logger.default.info(`Scaling template image from ${tplWidth}x${tplHeight} to match ` + `screen at ${screenWidth}x${screenHeight}`);
|
|
191
|
+
|
|
192
|
+
imgObj = imgObj.scaleToFit(screenWidth, screenHeight);
|
|
193
|
+
return (await imgObj.getBuffer(_support.imageUtil.MIME_PNG)).toString('base64');
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
async getScreenshotForImageFind(screenWidth, screenHeight) {
|
|
197
|
+
if (!this.driver.getScreenshot) {
|
|
198
|
+
throw new Error("This driver does not support the required 'getScreenshot' command");
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const settings = Object.assign({}, DEFAULT_SETTINGS, this.driver.settings.getSettings());
|
|
202
|
+
const {
|
|
203
|
+
fixImageFindScreenshotDims
|
|
204
|
+
} = settings;
|
|
205
|
+
let b64Screenshot = await this.driver.getScreenshot();
|
|
206
|
+
|
|
207
|
+
if (!fixImageFindScreenshotDims) {
|
|
208
|
+
_logger.default.info(`Not verifying screenshot dimensions match screen`);
|
|
209
|
+
|
|
210
|
+
return {
|
|
211
|
+
b64Screenshot
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (screenWidth < 1 || screenHeight < 1) {
|
|
216
|
+
_logger.default.warn(`The retrieved screen size ${screenWidth}x${screenHeight} does ` + `not seem to be valid. No changes will be applied to the screenshot`);
|
|
217
|
+
|
|
218
|
+
return {
|
|
219
|
+
b64Screenshot
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
_logger.default.info('Verifying screenshot size and aspect ratio');
|
|
224
|
+
|
|
225
|
+
let imgObj = await _support.imageUtil.getJimpImage(b64Screenshot);
|
|
226
|
+
let {
|
|
227
|
+
width: shotWidth,
|
|
228
|
+
height: shotHeight
|
|
229
|
+
} = imgObj.bitmap;
|
|
230
|
+
|
|
231
|
+
if (shotWidth < 1 || shotHeight < 1) {
|
|
232
|
+
_logger.default.warn(`The retrieved screenshot size ${shotWidth}x${shotHeight} does ` + `not seem to be valid. No changes will be applied to the screenshot`);
|
|
233
|
+
|
|
234
|
+
return {
|
|
235
|
+
b64Screenshot
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (screenWidth === shotWidth && screenHeight === shotHeight) {
|
|
240
|
+
_logger.default.info('Screenshot size matched screen size');
|
|
241
|
+
|
|
242
|
+
return {
|
|
243
|
+
b64Screenshot
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const scale = {
|
|
248
|
+
xScale: 1.0,
|
|
249
|
+
yScale: 1.0
|
|
250
|
+
};
|
|
251
|
+
const screenAR = screenWidth / screenHeight;
|
|
252
|
+
const shotAR = shotWidth / shotHeight;
|
|
253
|
+
|
|
254
|
+
if (Math.round(screenAR * FLOAT_PRECISION) === Math.round(shotAR * FLOAT_PRECISION)) {
|
|
255
|
+
_logger.default.info(`Screenshot aspect ratio '${shotAR}' (${shotWidth}x${shotHeight}) matched ` + `screen aspect ratio '${screenAR}' (${screenWidth}x${screenHeight})`);
|
|
256
|
+
} else {
|
|
257
|
+
_logger.default.warn(`When trying to find an element, determined that the screen ` + `aspect ratio and screenshot aspect ratio are different. Screen ` + `is ${screenWidth}x${screenHeight} whereas screenshot is ` + `${shotWidth}x${shotHeight}.`);
|
|
258
|
+
|
|
259
|
+
const xScale = 1.0 * shotWidth / screenWidth;
|
|
260
|
+
const yScale = 1.0 * shotHeight / screenHeight;
|
|
261
|
+
const scaleFactor = xScale >= yScale ? yScale : xScale;
|
|
262
|
+
|
|
263
|
+
_logger.default.warn(`Resizing screenshot to ${shotWidth * scaleFactor}x${shotHeight * scaleFactor} to match ` + `screen aspect ratio so that image element coordinates have a ` + `greater chance of being correct.`);
|
|
264
|
+
|
|
265
|
+
imgObj = imgObj.resize(shotWidth * scaleFactor, shotHeight * scaleFactor);
|
|
266
|
+
scale.xScale *= scaleFactor;
|
|
267
|
+
scale.yScale *= scaleFactor;
|
|
268
|
+
shotWidth = imgObj.bitmap.width;
|
|
269
|
+
shotHeight = imgObj.bitmap.height;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (screenWidth !== shotWidth && screenHeight !== shotHeight) {
|
|
273
|
+
_logger.default.info(`Scaling screenshot from ${shotWidth}x${shotHeight} to match ` + `screen at ${screenWidth}x${screenHeight}`);
|
|
274
|
+
|
|
275
|
+
imgObj = imgObj.resize(screenWidth, screenHeight);
|
|
276
|
+
scale.xScale *= 1.0 * screenWidth / shotWidth;
|
|
277
|
+
scale.yScale *= 1.0 * screenHeight / shotHeight;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
b64Screenshot = (await imgObj.getBuffer(_support.imageUtil.MIME_PNG)).toString('base64');
|
|
281
|
+
return {
|
|
282
|
+
b64Screenshot,
|
|
283
|
+
scale
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
async fixImageTemplateScale(b64Template, opts = {}) {
|
|
288
|
+
if (!opts) {
|
|
289
|
+
return b64Template;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
let {
|
|
293
|
+
fixImageTemplateScale = false,
|
|
294
|
+
defaultImageTemplateScale = _imageElement.DEFAULT_TEMPLATE_IMAGE_SCALE,
|
|
295
|
+
ignoreDefaultImageTemplateScale = false,
|
|
296
|
+
xScale = DEFAULT_FIX_IMAGE_TEMPLATE_SCALE,
|
|
297
|
+
yScale = DEFAULT_FIX_IMAGE_TEMPLATE_SCALE
|
|
298
|
+
} = opts;
|
|
299
|
+
|
|
300
|
+
if (ignoreDefaultImageTemplateScale) {
|
|
301
|
+
defaultImageTemplateScale = _imageElement.DEFAULT_TEMPLATE_IMAGE_SCALE;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
if (defaultImageTemplateScale === _imageElement.DEFAULT_TEMPLATE_IMAGE_SCALE && !fixImageTemplateScale) {
|
|
305
|
+
return b64Template;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (fixImageTemplateScale) {
|
|
309
|
+
xScale *= defaultImageTemplateScale;
|
|
310
|
+
yScale *= defaultImageTemplateScale;
|
|
311
|
+
} else {
|
|
312
|
+
xScale = yScale = 1 * defaultImageTemplateScale;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (!parseFloat(xScale) || !parseFloat(yScale)) {
|
|
316
|
+
return b64Template;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if (Math.round(xScale * FLOAT_PRECISION) === Math.round(DEFAULT_FIX_IMAGE_TEMPLATE_SCALE * FLOAT_PRECISION) && Math.round(yScale * FLOAT_PRECISION === Math.round(DEFAULT_FIX_IMAGE_TEMPLATE_SCALE * FLOAT_PRECISION))) {
|
|
320
|
+
return b64Template;
|
|
381
321
|
}
|
|
322
|
+
|
|
323
|
+
let imgTempObj = await _support.imageUtil.getJimpImage(b64Template);
|
|
324
|
+
let {
|
|
325
|
+
width: baseTempWidth,
|
|
326
|
+
height: baseTempHeigh
|
|
327
|
+
} = imgTempObj.bitmap;
|
|
328
|
+
const scaledWidth = baseTempWidth * xScale;
|
|
329
|
+
const scaledHeight = baseTempHeigh * yScale;
|
|
330
|
+
|
|
331
|
+
_logger.default.info(`Scaling template image from ${baseTempWidth}x${baseTempHeigh}` + ` to ${scaledWidth}x${scaledHeight}`);
|
|
332
|
+
|
|
333
|
+
_logger.default.info(`The ratio is ${xScale} and ${yScale}`);
|
|
334
|
+
|
|
335
|
+
imgTempObj = await imgTempObj.resize(scaledWidth, scaledHeight);
|
|
336
|
+
return (await imgTempObj.getBuffer(_support.imageUtil.MIME_PNG)).toString('base64');
|
|
337
|
+
}
|
|
338
|
+
|
|
382
339
|
}
|
|
340
|
+
|
|
383
341
|
exports.default = ImageElementFinder;
|
|
384
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmluZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vbGliL2ZpbmRlci5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7QUFBQSwwREFBNEI7QUFDNUIsbURBQWlEO0FBQ2pELDJEQUE0QztBQUM1QyxtREFDNEQ7QUFDNUQsdUNBQXdGO0FBQ3hGLHNEQUEyQjtBQUUzQixNQUFNLG1CQUFtQixHQUFHLFNBQVMsQ0FBQztBQXFhWixrREFBbUI7QUFwYTdDLE1BQU0sZUFBZSxHQUFHLHFCQUFJLENBQUMsMEJBQTBCLENBQUM7QUFvYS9DLDBDQUFlO0FBbmF4QixNQUFNLGdDQUFnQyxHQUFHLENBQUMsQ0FBQztBQW1hc0IsNEVBQWdDO0FBbGFqRyx5Q0FBeUM7QUFDekMsaUZBQWlGO0FBQ2pGLE1BQU0sZUFBZSxHQUFHLE1BQU0sQ0FBQztBQUMvQixNQUFNLGNBQWMsR0FBRyxJQUFJLEdBQUcsSUFBSSxHQUFHLEVBQUUsQ0FBQyxDQUFDLE9BQU87QUFFaEQsTUFBTSxnQkFBZ0IsR0FBRztJQUN2QiwwRUFBMEU7SUFDMUUsNEJBQTRCO0lBQzVCLG1CQUFtQixFQUFFLGlDQUF1QjtJQUU1Qyx5RUFBeUU7SUFDekUsbURBQW1EO0lBQ25ELDBCQUEwQixFQUFFLElBQUk7SUFFaEMsMkVBQTJFO0lBQzNFLDZFQUE2RTtJQUM3RSxXQUFXO0lBQ1gsb0JBQW9CLEVBQUUsS0FBSztJQUUzQiwyRUFBMkU7SUFDM0UsMkVBQTJFO0lBQzNFLCtCQUErQjtJQUMvQiwwRUFBMEU7SUFDMUUsK0VBQStFO0lBQy9FLDZFQUE2RTtJQUM3RSxxQkFBcUIsRUFBRSxLQUFLO0lBRTVCLHVFQUF1RTtJQUN2RSxpRkFBaUY7SUFDakYsNEVBQTRFO0lBQzVFLHlGQUF5RjtJQUN6RixrRkFBa0Y7SUFDbEYsOEVBQThFO0lBQzlFLHlCQUF5QixFQUFFLDRDQUE0QjtJQUV2RCxzRUFBc0U7SUFDdEUsb0RBQW9EO0lBQ3BELDZCQUE2QixFQUFFLElB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
|
|
342
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNSlNPTldQX0VMRU1FTlRfS0VZIiwiVzNDX0VMRU1FTlRfS0VZIiwidXRpbCIsIlczQ19XRUJfRUxFTUVOVF9JREVOVElGSUVSIiwiREVGQVVMVF9GSVhfSU1BR0VfVEVNUExBVEVfU0NBTEUiLCJGTE9BVF9QUkVDSVNJT04iLCJNQVhfQ0FDSEVfU0laRSIsIkRFRkFVTFRfU0VUVElOR1MiLCJpbWFnZU1hdGNoVGhyZXNob2xkIiwiREVGQVVMVF9NQVRDSF9USFJFU0hPTEQiLCJpbWFnZU1hdGNoTWV0aG9kIiwiZml4SW1hZ2VGaW5kU2NyZWVuc2hvdERpbXMiLCJmaXhJbWFnZVRlbXBsYXRlU2l6ZSIsImZpeEltYWdlVGVtcGxhdGVTY2FsZSIsImRlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGUiLCJERUZBVUxUX1RFTVBMQVRFX0lNQUdFX1NDQUxFIiwiY2hlY2tGb3JJbWFnZUVsZW1lbnRTdGFsZW5lc3MiLCJhdXRvVXBkYXRlSW1hZ2VFbGVtZW50UG9zaXRpb24iLCJpbWFnZUVsZW1lbnRUYXBTdHJhdGVneSIsIklNQUdFX0VMX1RBUF9TVFJBVEVHWV9XM0MiLCJnZXRNYXRjaGVkSW1hZ2VSZXN1bHQiLCJJbWFnZUVsZW1lbnRGaW5kZXIiLCJjb25zdHJ1Y3RvciIsImRyaXZlciIsIm1heCIsImltZ0VsQ2FjaGUiLCJMUlUiLCJsZW5ndGgiLCJlbCIsInRlbXBsYXRlIiwic2V0RHJpdmVyIiwicmVnaXN0ZXJJbWFnZUVsZW1lbnQiLCJpbWdFbCIsInNldCIsImlkIiwicHJvdG9LZXkiLCJpc1czQ1Byb3RvY29sIiwiYXNFbGVtZW50IiwiZmluZEJ5SW1hZ2UiLCJiNjRUZW1wbGF0ZSIsInNob3VsZENoZWNrU3RhbGVuZXNzIiwibXVsdGlwbGUiLCJpZ25vcmVEZWZhdWx0SW1hZ2VUZW1wbGF0ZVNjYWxlIiwiRXJyb3IiLCJzZXR0aW5ncyIsImdldFNldHRpbmdzIiwidGhyZXNob2xkIiwidmlzdWFsaXplIiwibG9nIiwiaW5mbyIsImdldFdpbmRvd1NpemUiLCJ3aWR0aCIsInNjcmVlbldpZHRoIiwiaGVpZ2h0Iiwic2NyZWVuSGVpZ2h0IiwiZW5zdXJlVGVtcGxhdGVTaXplIiwicmVzdWx0cyIsImNvbmRpdGlvbiIsImI2NFNjcmVlbnNob3QiLCJzY2FsZSIsImdldFNjcmVlbnNob3RGb3JJbWFnZUZpbmQiLCJjb21wYXJpc29uT3B0cyIsIm1ldGhvZCIsInB1c2giLCJNQVRDSF9URU1QTEFURV9NT0RFIiwiZXJyIiwibWVzc2FnZSIsIm1hdGNoIiwiaW1wbGljaXRXYWl0Rm9yQ29uZGl0aW9uIiwiXyIsImlzRW1wdHkiLCJlcnJvcnMiLCJOb1N1Y2hFbGVtZW50RXJyb3IiLCJlbGVtZW50cyIsIm1hcCIsInJlY3QiLCJzY29yZSIsInZpc3VhbGl6YXRpb24iLCJKU09OIiwic3RyaW5naWZ5IiwiSW1hZ2VFbGVtZW50IiwicmVnaXN0ZXJlZEVsZW1lbnRzIiwiaW1nT2JqIiwiaW1hZ2VVdGlsIiwiZ2V0SmltcEltYWdlIiwidHBsV2lkdGgiLCJ0cGxIZWlnaHQiLCJiaXRtYXAiLCJzY2FsZVRvRml0IiwiZ2V0QnVmZmVyIiwiTUlNRV9QTkciLCJ0b1N0cmluZyIsImdldFNjcmVlbnNob3QiLCJPYmplY3QiLCJhc3NpZ24iLCJ3YXJuIiwic2hvdFdpZHRoIiwic2hvdEhlaWdodCIsInhTY2FsZSIsInlTY2FsZSIsInNjcmVlbkFSIiwic2hvdEFSIiwiTWF0aCIsInJvdW5kIiwic2NhbGVGYWN0b3IiLCJyZXNpemUiLCJvcHRzIiwicGFyc2VGbG9hdCIsImltZ1RlbXBPYmoiLCJiYXNlVGVtcFdpZHRoIiwiYmFzZVRlbXBIZWlnaCIsInNjYWxlZFdpZHRoIiwic2NhbGVkSGVpZ2h0Il0sInNvdXJjZXMiOlsiLi4vLi4vbGliL2ZpbmRlci5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgXyBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IExSVSBmcm9tICdscnUtY2FjaGUnO1xuaW1wb3J0IHsgaW1hZ2VVdGlsLCB1dGlsIH0gZnJvbSAnQGFwcGl1bS9zdXBwb3J0JztcbmltcG9ydCB7IGVycm9ycyB9IGZyb20gJ0BhcHBpdW0vYmFzZS1kcml2ZXInO1xuaW1wb3J0IHsgSW1hZ2VFbGVtZW50LCBERUZBVUxUX1RFTVBMQVRFX0lNQUdFX1NDQUxFLFxuICAgICAgICAgSU1BR0VfRUxfVEFQX1NUUkFURUdZX1czQyB9IGZyb20gJy4vaW1hZ2UtZWxlbWVudCc7XG5pbXBvcnQgeyBNQVRDSF9URU1QTEFURV9NT0RFLCBjb21wYXJlSW1hZ2VzLCBERUZBVUxUX01BVENIX1RIUkVTSE9MRCB9IGZyb20gJy4vY29tcGFyZSc7XG5pbXBvcnQgbG9nIGZyb20gJy4vbG9nZ2VyJztcblxuY29uc3QgTUpTT05XUF9FTEVNRU5UX0tFWSA9ICdFTEVNRU5UJztcbmNvbnN0IFczQ19FTEVNRU5UX0tFWSA9IHV0aWwuVzNDX1dFQl9FTEVNRU5UX0lERU5USUZJRVI7XG5jb25zdCBERUZBVUxUX0ZJWF9JTUFHRV9URU1QTEFURV9TQ0FMRSA9IDE7XG4vLyBVc2VkIHRvIGNvbXBhcmUgcmF0aW8gYW5kIHNjcmVlbiB3aWR0aFxuLy8gUGl4ZWwgaXMgYmFzaWNhbGx5IHVuZGVyIDEwODAgZm9yIGV4YW1wbGUuIDEwMEsgaXMgcHJvYmFibHkgZW5vdWdoIGZvIGEgd2hpbGUuXG5jb25zdCBGTE9BVF9QUkVDSVNJT04gPSAxMDAwMDA7XG5jb25zdCBNQVhfQ0FDSEVfU0laRSA9IDEwMjQgKiAxMDI0ICogNDA7IC8vIDQwbWJcblxuY29uc3QgREVGQVVMVF9TRVRUSU5HUyA9IHtcbiAgLy8gdmFsdWUgYmV0d2VlbiAwIGFuZCAxIHJlcHJlc2VudGluZyBtYXRjaCBzdHJlbmd0aCwgYmVsb3cgd2hpY2ggYW4gaW1hZ2VcbiAgLy8gZWxlbWVudCB3aWxsIG5vdCBiZSBmb3VuZFxuICBpbWFnZU1hdGNoVGhyZXNob2xkOiBERUZBVUxUX01BVENIX1RIUkVTSE9MRCxcblxuICAvLyBPbmUgb2YgcG9zc2libGUgaW1hZ2UgbWF0Y2hpbmcgbWV0aG9kcy5cbiAgLy8gUmVhZCBodHRwczovL2RvY3Mub3BlbmN2Lm9yZy8zLjAtYmV0YS9kb2MvcHlfdHV0b3JpYWxzL3B5X2ltZ3Byb2MvcHlfdGVtcGxhdGVfbWF0Y2hpbmcvcHlfdGVtcGxhdGVfbWF0Y2hpbmcuaHRtbFxuICAvLyBmb3IgbW9yZSBkZXRhaWxzLlxuICAvLyBUTV9DQ09FRkZfTk9STUVEIGJ5IGRlZmF1bHRcbiAgaW1hZ2VNYXRjaE1ldGhvZDogJycsXG5cbiAgLy8gaWYgdGhlIGltYWdlIHJldHVybmVkIGJ5IGdldFNjcmVlbnNob3QgZGlmZmVycyBpbiBzaXplIG9yIGFzcGVjdCByYXRpb1xuICAvLyBmcm9tIHRoZSBzY3JlZW4sIGF0dGVtcHQgdG8gZml4IGl0IGF1dG9tYXRpY2FsbHlcbiAgZml4SW1hZ2VGaW5kU2NyZWVuc2hvdERpbXM6IHRydWUsXG5cbiAgLy8gd2hldGhlciBBcHBpdW0gc2hvdWxkIGVuc3VyZSB0aGF0IGFuIGltYWdlIHRlbXBsYXRlIHNlbnQgaW4gZHVyaW5nIGltYWdlXG4gIC8vIGVsZW1lbnQgZmluZCBzaG91bGQgaGF2ZSBpdHMgc2l6ZSBhZGp1c3RlZCBzbyB0aGUgbWF0Y2ggYWxnb3JpdGhtIHdpbGwgbm90XG4gIC8vIGNvbXBsYWluXG4gIGZpeEltYWdlVGVtcGxhdGVTaXplOiBmYWxzZSxcblxuICAvLyB3aGV0aGVyIEFwcGl1bSBzaG91bGQgZW5zdXJlIHRoYXQgYW4gaW1hZ2UgdGVtcGxhdGUgc2VudCBpbiBkdXJpbmcgaW1hZ2VcbiAgLy8gZWxlbWVudCBmaW5kIHNob3VsZCBoYXZlIGl0cyBzY2FsZSBhZGp1c3RlZCB0byBkaXNwbGF5IHNpemUgc28gdGhlIG1hdGNoXG4gIC8vIGFsZ29yaXRobSB3aWxsIG5vdCBjb21wbGFpbi5cbiAgLy8gZS5nLiBpT1MgaGFzIGB3aWR0aD0zNzUsIGhlaWdodD02NjdgIHdpbmRvdyByZWN0LCBidXQgaXRzIHNjcmVlbnNob3QgaXNcbiAgLy8gICAgICBgd2lkdGg9NzUwIMOXIGhlaWdodD0xMzM0YCBwaXhlbHMuIFRoaXMgc2V0dGluZyBoZWxwIHRvIGFkanVzdCB0aGUgc2NhbGVcbiAgLy8gICAgICBpZiBhIHVzZXIgdXNlIGB3aWR0aD03NTAgw5cgaGVpZ2h0PTEzMzRgIHBpeGVscydzIGJhc2UgdGVtcGxhdGUgaW1hZ2UuXG4gIGZpeEltYWdlVGVtcGxhdGVTY2FsZTogZmFsc2UsXG5cbiAgLy8gVXNlcnMgbWlnaHQgaGF2ZSBzY2FsZWQgdGVtcGxhdGUgaW1hZ2UgdG8gcmVkdWNlIHRoZWlyIHN0b3JhZ2Ugc2l6ZS5cbiAgLy8gVGhpcyBzZXR0aW5nIGFsbG93cyB1c2VycyB0byBzY2FsZSBhIHRlbXBsYXRlIGltYWdlIHRoZXkgc2VuZCB0byBBcHBpdW0gc2VydmVyXG4gIC8vIHNvIHRoYXQgdGhlIEFwcGl1bSBzZXJ2ZXIgY29tcGFyZXMgdGhlIGFjdHVhbCBzY2FsZSB1c2VycyBvcmlnaW5hbGx5IGhhZC5cbiAgLy8gZS5nLiBJZiBhIHVzZXIgaGFzIGFuIGltYWdlIG9mIDI3MCB4IDMyIHBpeGVscyB3aGljaCB3YXMgb3JpZ2luYWxseSAxMDgwIHggMTI2IHBpeGVscyxcbiAgLy8gICAgICB0aGUgdXNlciBjYW4gc2V0IHtkZWZhdWx0SW1hZ2VUZW1wbGF0ZVNjYWxlOiA0LjB9IHRvIHNjYWxlIHRoZSBzbWFsbCBpbWFnZVxuICAvLyAgICAgIHRvIHRoZSBvcmlnaW5hbCBvbmUgc28gdGhhdCBBcHBpdW0gY2FuIGNvbXBhcmUgaXQgYXMgdGhlIG9yaWdpbmFsIG9uZS5cbiAgZGVmYXVsdEltYWdlVGVtcGxhdGVTY2FsZTogREVGQVVMVF9URU1QTEFURV9JTUFHRV9TQ0FMRSxcblxuICAvLyB3aGV0aGVyIEFwcGl1bSBzaG91bGQgcmUtY2hlY2sgdGhhdCBhbiBpbWFnZSBlbGVtZW50IGNhbiBiZSBtYXRjaGVkXG4gIC8vIGFnYWluc3QgdGhlIGN1cnJlbnQgc2NyZWVuc2hvdCBiZWZvcmUgY2xpY2tpbmcgaXRcbiAgY2hlY2tGb3JJbWFnZUVsZW1lbnRTdGFsZW5lc3M6IHRydWUsXG5cbiAgLy8gd2hldGhlciBiZWZvcmUgY2xpY2tpbmcgb24gYW4gaW1hZ2UgZWxlbWVudCBBcHBpdW0gc2hvdWxkIHJlLWRldGVybWluZSB0aGVcbiAgLy8gcG9zaXRpb24gb2YgdGhlIGVsZW1lbnQgb24gc2NyZWVuXG4gIGF1dG9VcGRhdGVJbWFnZUVsZW1lbnRQb3NpdGlvbjogZmFsc2UsXG5cbiAgLy8gd2hpY2ggbWV0aG9kIHRvIHVzZSBmb3IgdGFwcGluZyBieSBjb29yZGluYXRlIGZvciBpbWFnZSBlbGVtZW50cy4gdGhlXG4gIC8vIG9wdGlvbnMgYXJlICd3M2MnIG9yICdtanNvbndwJ1xuICBpbWFnZUVsZW1lbnRUYXBTdHJhdGVneTogSU1BR0VfRUxfVEFQX1NUUkFURUdZX1czQyxcblxuICAvLyB3aGljaCBtZXRob2QgdG8gdXNlIHRvIHNhdmUgdGhlIG1hdGNoZWQgaW1hZ2UgYXJlYSBpbiBJbWFnZUVsZW1lbnQgY2xhc3MuXG4gIC8vIEl0IGlzIHVzZWQgZm9yIGRlYnVnZ2luZyBwdXJwb3NlLlxuICBnZXRNYXRjaGVkSW1hZ2VSZXN1bHQ6IGZhbHNlLFxufTtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgSW1hZ2VFbGVtZW50RmluZGVyIHtcbiAgY29uc3RydWN0b3IgKGRyaXZlciwgbWF4ID0gTUFYX0NBQ0hFX1NJWkUpIHtcbiAgICB0aGlzLmRyaXZlciA9IGRyaXZlcjtcbiAgICB0aGlzLmltZ0VsQ2FjaGUgPSBuZXcgTFJVKHtcbiAgICAgIG1heCxcbiAgICAgIGxlbmd0aDogKGVsKSA9PiBlbC50ZW1wbGF0ZS5sZW5ndGgsXG4gICAgfSk7XG4gIH1cblxuICBzZXREcml2ZXIgKGRyaXZlcikge1xuICAgIHRoaXMuZHJpdmVyID0gZHJpdmVyO1xuICB9XG5cbiAgcmVnaXN0ZXJJbWFnZUVsZW1lbnQgKGltZ0VsKSB7XG4gICAgdGhpcy5pbWdFbENhY2hlLnNldChpbWdFbC5pZCwgaW1nRWwpO1xuICAgIGNvbnN0IHByb3RvS2V5ID0gdGhpcy5kcml2ZXIuaXNXM0NQcm90b2NvbCgpID8gVzNDX0VMRU1FTlRfS0VZIDogTUpTT05XUF9FTEVNRU5UX0tFWTtcbiAgICByZXR1cm4gaW1nRWwuYXNFbGVtZW50KHByb3RvS2V5KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAdHlwZWRlZiBGaW5kQnlJbWFnZU9wdGlvbnNcbiAgICogQHByb3BlcnR5IHtib29sZWFufSBbc2hvdWxkQ2hlY2tTdGFsZW5lc3M9ZmFsc2VdIC0gd2hldGhlciB0aGlzIGNhbGwgdG8gZmluZCBhblxuICAgKiBpbWFnZSBpcyBtZXJlbHkgdG8gY2hlY2sgc3RhbGVuZXNzLiBJZiBzbyB3ZSBjYW4gYnlwYXNzIGEgbG90IG9mIGxvZ2ljXG4gICAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0gW211bHRpcGxlPWZhbHNlXSAtIFdoZXRoZXIgd2UgYXJlIGZpbmRpbmcgb25lIGVsZW1lbnQgb3JcbiAgICogbXVsdGlwbGVcbiAgICogQHByb3BlcnR5IHtib29sZWFufSBbaWdub3JlRGVmYXVsdEltYWdlVGVtcGxhdGVTY2FsZT1mYWxzZV0gLSBXaGV0aGVyIHdlXG4gICAqIGlnbm9yZSBkZWZhdWx0SW1hZ2VUZW1wbGF0ZVNjYWxlLiBJdCBjYW4gYmUgdXNlZCB3aGVuIHlvdSB3b3VsZCBsaWtlIHRvXG4gICAqIHNjYWxlIGI2NFRlbXBsYXRlIHdpdGggZGVmYXVsdEltYWdlVGVtcGxhdGVTY2FsZSBzZXR0aW5nLlxuICAgKi9cblxuICAvKipcbiAgICogRmluZCBhIHNjcmVlbiByZWN0IHJlcHJlc2VudGVkIGJ5IGFuIEltYWdlRWxlbWVudCBjb3JyZXNwb25kaW5nIHRvIGFuIGltYWdlXG4gICAqIHRlbXBsYXRlIHNlbnQgaW4gYnkgdGhlIGNsaWVudFxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gYjY0VGVtcGxhdGUgLSBiYXNlNjQtZW5jb2RlZCBpbWFnZSB1c2VkIGFzIGEgdGVtcGxhdGUgdG8gYmVcbiAgICogbWF0Y2hlZCBpbiB0aGUgc2NyZWVuc2hvdFxuICAgKiBAcGFyYW0ge0ZpbmRCeUltYWdlT3B0aW9uc30gLSBhZGRpdGlvbmFsIG9wdGlvbnNcbiAgICpcbiAgICogQHJldHVybnMge1dlYkVsZW1lbnR9IC0gV2ViRHJpdmVyIGVsZW1lbnQgd2l0aCBhIHNwZWNpYWwgaWQgcHJlZml4XG4gICAqL1xuICBhc3luYyBmaW5kQnlJbWFnZSAoYjY0VGVtcGxhdGUsIHtcbiAgICBzaG91bGRDaGVja1N0YWxlbmVzcyA9IGZhbHNlLFxuICAgIG11bHRpcGxlID0gZmFsc2UsXG4gICAgaWdub3JlRGVmYXVsdEltYWdlVGVtcGxhdGVTY2FsZSA9IGZhbHNlLFxuICB9KSB7XG4gICAgaWYgKCF0aGlzLmRyaXZlcikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBDYW4ndCBmaW5kIHdpdGhvdXQgYSBkcml2ZXIhYCk7XG4gICAgfVxuICAgIGNvbnN0IHNldHRpbmdzID0gey4uLkRFRkFVTFRfU0VUVElOR1MsIC4uLnRoaXMuZHJpdmVyLnNldHRpbmdzLmdldFNldHRpbmdzKCl9O1xuICAgIGNvbnN0IHtcbiAgICAgIGltYWdlTWF0Y2hUaHJlc2hvbGQ6IHRocmVzaG9sZCxcbiAgICAgIGltYWdlTWF0Y2hNZXRob2QsXG4gICAgICBmaXhJbWFnZVRlbXBsYXRlU2l6ZSxcbiAgICAgIGZpeEltYWdlVGVtcGxhdGVTY2FsZSxcbiAgICAgIGRlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGUsXG4gICAgICBnZXRNYXRjaGVkSW1hZ2VSZXN1bHQ6IHZpc3VhbGl6ZVxuICAgIH0gPSBzZXR0aW5ncztcblxuICAgIGxvZy5pbmZvKGBGaW5kaW5nIGltYWdlIGVsZW1lbnQgd2l0aCBtYXRjaCB0aHJlc2hvbGQgJHt0aHJlc2hvbGR9YCk7XG4gICAgaWYgKCF0aGlzLmRyaXZlci5nZXRXaW5kb3dTaXplKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJUaGlzIGRyaXZlciBkb2VzIG5vdCBzdXBwb3J0IHRoZSByZXF1aXJlZCAnZ2V0V2luZG93U2l6ZScgY29tbWFuZFwiKTtcbiAgICB9XG4gICAgY29uc3Qge3dpZHRoOiBzY3JlZW5XaWR0aCwgaGVpZ2h0OiBzY3JlZW5IZWlnaHR9ID0gYXdhaXQgdGhpcy5kcml2ZXIuZ2V0V2luZG93U2l6ZSgpO1xuXG4gICAgLy8gc29tZW9uZSBtaWdodCBoYXZlIHNlbnQgaW4gYSB0ZW1wbGF0ZSB0aGF0J3MgbGFyZ2VyIHRoYW4gdGhlIHNjcmVlblxuICAgIC8vIGRpbWVuc2lvbnMuIElmIHNvIGxldCdzIGNoZWNrIGFuZCBjdXQgaXQgZG93biB0byBzaXplIHNpbmNlIHRoZSBhbGdvcml0aG1cbiAgICAvLyB3aWxsIG5vdCB3b3JrIHVubGVzcyB3ZSBkby4gQnV0IGJlY2F1c2UgaXQgcmVxdWlyZXMgc29tZSBwb3RlbnRpYWxseVxuICAgIC8vIGV4cGVuc2l2ZSBjb21tYW5kcywgb25seSBkbyB0aGlzIGlmIHRoZSB1c2VyIGhhcyByZXF1ZXN0ZWQgaXQgaW4gc2V0dGluZ3MuXG4gICAgaWYgKGZpeEltYWdlVGVtcGxhdGVTaXplKSB7XG4gICAgICBiNjRUZW1wbGF0ZSA9IGF3YWl0IHRoaXMuZW5zdXJlVGVtcGxhdGVTaXplKGI2NFRlbXBsYXRlLCBzY3JlZW5XaWR0aCxcbiAgICAgICAgc2NyZWVuSGVpZ2h0KTtcbiAgICB9XG5cbiAgICBjb25zdCByZXN1bHRzID0gW107XG4gICAgY29uc3QgY29uZGl0aW9uID0gYXN5bmMgKCkgPT4ge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3Qge2I2NFNjcmVlbnNob3QsIHNjYWxlfSA9IGF3YWl0IHRoaXMuZ2V0U2NyZWVuc2hvdEZvckltYWdlRmluZChzY3JlZW5XaWR0aCwgc2NyZWVuSGVpZ2h0KTtcblxuICAgICAgICBiNjRUZW1wbGF0ZSA9IGF3YWl0IHRoaXMuZml4SW1hZ2VUZW1wbGF0ZVNjYWxlKGI2NFRlbXBsYXRlLCB7XG4gICAgICAgICAgZGVmYXVsdEltYWdlVGVtcGxhdGVTY2FsZSwgaWdub3JlRGVmYXVsdEltYWdlVGVtcGxhdGVTY2FsZSxcbiAgICAgICAgICBmaXhJbWFnZVRlbXBsYXRlU2NhbGUsIC4uLnNjYWxlXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGNvbnN0IGNvbXBhcmlzb25PcHRzID0ge1xuICAgICAgICAgIHRocmVzaG9sZCxcbiAgICAgICAgICB2aXN1YWxpemUsXG4gICAgICAgICAgbXVsdGlwbGUsXG4gICAgICAgIH07XG4gICAgICAgIGlmIChpbWFnZU1hdGNoTWV0aG9kKSB7XG4gICAgICAgICAgY29tcGFyaXNvbk9wdHMubWV0aG9kID0gaW1hZ2VNYXRjaE1ldGhvZDtcbiAgICAgICAgfVxuICAgICAgICBpZiAobXVsdGlwbGUpIHtcbiAgICAgICAgICByZXN1bHRzLnB1c2goLi4uKGF3YWl0IGNvbXBhcmVJbWFnZXMoTUFUQ0hfVEVNUExBVEVfTU9ERSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYjY0U2NyZWVuc2hvdCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYjY0VGVtcGxhdGUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbXBhcmlzb25PcHRzKSkpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJlc3VsdHMucHVzaChhd2FpdCBjb21wYXJlSW1hZ2VzKE1BVENIX1RFTVBMQVRFX01PREUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYjY0U2NyZWVuc2hvdCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiNjRUZW1wbGF0ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21wYXJpc29uT3B0cykpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0cnVlO1xuXG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgLy8gaWYgY29tcGFyZUltYWdlcyBmYWlscywgd2UnbGwgZ2V0IGEgc3BlY2lmaWMgZXJyb3IsIGJ1dCB3ZSBzaG91bGRcbiAgICAgICAgLy8gcmV0cnksIHNvIHRyYXAgdGhhdCBhbmQganVzdCByZXR1cm4gZmFsc2UgdG8gdHJpZ2dlciB0aGUgbmV4dCByb3VuZCBvZlxuICAgICAgICAvLyBpbXBsaWNpdGx5IHdhaXRpbmcuIEZvciBvdGhlciBlcnJvcnMsIHRocm93IHRoZW0gdG8gZ2V0IG91dCBvZiB0aGVcbiAgICAgICAgLy8gaW1wbGljaXQgd2FpdCBsb29wXG4gICAgICAgIGlmIChlcnIubWVzc2FnZS5tYXRjaCgvQ2Fubm90IGZpbmQgYW55IG9jY3VycmVuY2VzLykpIHtcbiAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgfVxuICAgIH07XG5cbiAgICB0cnkge1xuICAgICAgYXdhaXQgdGhpcy5kcml2ZXIuaW1wbGljaXRXYWl0Rm9yQ29uZGl0aW9uKGNvbmRpdGlvbik7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAvLyB0aGlzIGBpbXBsaWNpdFdhaXRGb3JDb25kaXRpb25gIG1ldGhvZCB3aWxsIHRocm93IGEgJ0NvbmRpdGlvbiB1bm1ldCdcbiAgICAgIC8vIGVycm9yIGlmIGFuIGVsZW1lbnQgaXMgbm90IGZvdW5kIGV2ZW50dWFsbHkuIEluIHRoYXQgY2FzZSwgd2Ugd2lsbFxuICAgICAgLy8gaGFuZGxlIHRoZSBlbGVtZW50IG5vdCBmb3VuZCByZXNwb25zZSBiZWxvdy4gSW4gdGhlIGNhc2Ugd2hlcmUgZ2V0IHNvbWVcbiAgICAgIC8vIF9vdGhlcl8ga2luZCBvZiBlcnJvciwgaXQgbWVhbnMgc29tZXRoaW5nIGJsZXcgdXAgdG90YWxseSBhcGFydCBmcm9tIHRoZVxuICAgICAgLy8gaW1wbGljaXQgd2FpdCB0aW1lb3V0LiBXZSBzaG91bGQgbm90IG1hc2sgdGhhdCBlcnJvciBhbmQgaW5zdGVhZCB0aHJvd1xuICAgICAgLy8gaXQgc3RyYWlnaHRhd2F5XG4gICAgICBpZiAoIWVyci5tZXNzYWdlLm1hdGNoKC9Db25kaXRpb24gdW5tZXQvKSkge1xuICAgICAgICB0aHJvdyBlcnI7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKF8uaXNFbXB0eShyZXN1bHRzKSkge1xuICAgICAgaWYgKG11bHRpcGxlKSB7XG4gICAgICAgIHJldHVybiBbXTtcbiAgICAgIH1cbiAgICAgIHRocm93IG5ldyBlcnJvcnMuTm9TdWNoRWxlbWVudEVycm9yKCk7XG4gICAgfVxuXG4gICAgY29uc3QgZWxlbWVudHMgPSByZXN1bHRzLm1hcCgoe3JlY3QsIHNjb3JlLCB2aXN1YWxpemF0aW9ufSkgPT4ge1xuICAgICAgbG9nLmluZm8oYEltYWdlIHRlbXBsYXRlIG1hdGNoZWQ6ICR7SlNPTi5zdHJpbmdpZnkocmVjdCl9YCk7XG4gICAgICByZXR1cm4gbmV3IEltYWdlRWxlbWVudChiNjRUZW1wbGF0ZSwgcmVjdCwgc2NvcmUsIHZpc3VhbGl6YXRpb24sIHRoaXMpO1xuICAgIH0pO1xuXG4gICAgLy8gaWYgd2UncmUganVzdCBjaGVja2luZyBzdGFsZW5lc3MsIHJldHVybiBzdHJhaWdodGF3YXkgc28gd2UgZG9uJ3QgYWRkXG4gICAgLy8gYSBuZXcgZWxlbWVudCB0byB0aGUgY2FjaGUuIHNob3VsZENoZWNrU3RhbGVuZXNzIGRvZXMgbm90IHN1cHBvcnQgbXVsdGlwbGVcbiAgICAvLyBlbGVtZW50cywgc2luY2UgaXQgaXMgYSBwdXJlbHkgaW50ZXJuYWwgbWVjaGFuaXNtXG4gICAgaWYgKHNob3VsZENoZWNrU3RhbGVuZXNzKSB7XG4gICAgICByZXR1cm4gZWxlbWVudHNbMF07XG4gICAgfVxuXG4gICAgY29uc3QgcmVnaXN0ZXJlZEVsZW1lbnRzID0gZWxlbWVudHMubWFwKChpbWdFbCkgPT4gdGhpcy5yZWdpc3RlckltYWdlRWxlbWVudChpbWdFbCkpO1xuXG4gICAgcmV0dXJuIG11bHRpcGxlID8gcmVnaXN0ZXJlZEVsZW1lbnRzIDogcmVnaXN0ZXJlZEVsZW1lbnRzWzBdO1xuICB9XG5cbiAgLyoqXG4gICAqIEVuc3VyZSB0aGF0IHRoZSBpbWFnZSB0ZW1wbGF0ZSBzZW50IGluIGZvciBhIGZpbmQgaXMgb2YgYSBzdWl0YWJsZSBzaXplXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBiNjRUZW1wbGF0ZSAtIGJhc2U2NC1lbmNvZGVkIGltYWdlXG4gICAqIEBwYXJhbSB7aW50fSBzY3JlZW5XaWR0aCAtIHdpZHRoIG9mIHNjcmVlblxuICAgKiBAcGFyYW0ge2ludH0gc2NyZWVuSGVpZ2h0IC0gaGVpZ2h0IG9mIHNjcmVlblxuICAgKlxuICAgKiBAcmV0dXJucyB7c3RyaW5nfSBiYXNlNjQtZW5jb2RlZCBpbWFnZSwgcG90ZW50aWFsbHkgcmVzaXplZFxuICAgKi9cbiAgYXN5bmMgZW5zdXJlVGVtcGxhdGVTaXplIChiNjRUZW1wbGF0ZSwgc2NyZWVuV2lkdGgsIHNjcmVlbkhlaWdodCkge1xuICAgIGxldCBpbWdPYmogPSBhd2FpdCBpbWFnZVV0aWwuZ2V0SmltcEltYWdlKGI2NFRlbXBsYXRlKTtcbiAgICBsZXQge3dpZHRoOiB0cGxXaWR0aCwgaGVpZ2h0OiB0cGxIZWlnaHR9ID0gaW1nT2JqLmJpdG1hcDtcblxuICAgIGxvZy5pbmZvKGBUZW1wbGF0ZSBpbWFnZSBpcyAke3RwbFdpZHRofXgke3RwbEhlaWdodH0uIFNjcmVlbiBzaXplIGlzICR7c2NyZWVuV2lkdGh9eCR7c2NyZWVuSGVpZ2h0fWApO1xuICAgIC8vIGlmIHRoZSB0ZW1wbGF0ZSBmaXRzIGluc2lkZSB0aGUgc2NyZWVuIGRpbWVuc2lvbnMsIHdlJ3JlIGdvb2RcbiAgICBpZiAodHBsV2lkdGggPD0gc2NyZWVuV2lkdGggJiYgdHBsSGVpZ2h0IDw9IHNjcmVlbkhlaWdodCkge1xuICAgICAgcmV0dXJuIGI2NFRlbXBsYXRlO1xuICAgIH1cblxuICAgIGxvZy5pbmZvKGBTY2FsaW5nIHRlbXBsYXRlIGltYWdlIGZyb20gJHt0cGxXaWR0aH14JHt0cGxIZWlnaHR9IHRvIG1hdGNoIGAgK1xuICAgICAgICAgICAgIGBzY3JlZW4gYXQgJHtzY3JlZW5XaWR0aH14JHtzY3JlZW5IZWlnaHR9YCk7XG4gICAgLy8gb3RoZXJ3aXNlLCBzY2FsZSBpdCB0byBmaXQgaW5zaWRlIHRoZSBzY3JlZW4gZGltZW5zaW9uc1xuICAgIGltZ09iaiA9IGltZ09iai5zY2FsZVRvRml0KHNjcmVlbldpZHRoLCBzY3JlZW5IZWlnaHQpO1xuICAgIHJldHVybiAoYXdhaXQgaW1nT2JqLmdldEJ1ZmZlcihpbWFnZVV0aWwuTUlNRV9QTkcpKS50b1N0cmluZygnYmFzZTY0Jyk7XG4gIH1cblxuICAvKipcbiAgICogQHR5cGVkZWYgU2NyZWVuc2hvdFxuICAgKiBAcHJvcGVydHkge3N0cmluZ30gYjY0U2NyZWVuc2hvdCAtIGJhc2U2NCBiYXNlZCBzY3JlZW5zaG90IHN0cmluZ1xuICAgKi9cbiAgLyoqXG4gICAqIEB0eXBlZGVmIFNjcmVlbnNob3RTY2FsZVxuICAgKiBAcHJvcGVydHkge2Zsb2F0fSB4U2NhbGUgLSBTY2FsZSByYXRpbyBmb3Igd2lkdGhcbiAgICogQHByb3BlcnR5IHtmbG9hdH0geVNjYWxlIC0gU2NhbGUgcmF0aW8gZm9yIGhlaWdodFxuICAgKi9cbiAgLyoqXG4gICAqIEdldCB0aGUgc2NyZWVuc2hvdCBpbWFnZSB0aGF0IHdpbGwgYmUgdXNlZCBmb3IgZmluZCBieSBlbGVtZW50LCBwb3RlbnRpYWxseVxuICAgKiBhbHRlcmluZyBpdCBpbiB2YXJpb3VzIHdheXMgYmFzZWQgb24gdXNlci1yZXF1ZXN0ZWQgc2V0dGluZ3NcbiAgICpcbiAgICogQHBhcmFtIHtpbnR9IHNjcmVlbldpZHRoIC0gd2lkdGggb2Ygc2NyZWVuXG4gICAqIEBwYXJhbSB7aW50fSBzY3JlZW5IZWlnaHQgLSBoZWlnaHQgb2Ygc2NyZWVuXG4gICAqXG4gICAqIEByZXR1cm5zIHsge2I2NFNjcmVlbnNob3Q6IFNjcmVlbnNob3QsIHNjYWxlOiBTY3JlZW5zaG90U2NhbGU/IH0gfSBiYXNlNjQtZW5jb2RlZCBzY3JlZW5zaG90IGFuZCBTY3JlZW5zaG90U2NhbGVcbiAgICovXG4gIGFzeW5jIGdldFNjcmVlbnNob3RGb3JJbWFnZUZpbmQgKHNjcmVlbldpZHRoLCBzY3JlZW5IZWlnaHQpIHtcbiAgICBpZiAoIXRoaXMuZHJpdmVyLmdldFNjcmVlbnNob3QpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIlRoaXMgZHJpdmVyIGRvZXMgbm90IHN1cHBvcnQgdGhlIHJlcXVpcmVkICdnZXRTY3JlZW5zaG90JyBjb21tYW5kXCIpO1xuICAgIH1cbiAgICBjb25zdCBzZXR0aW5ncyA9IE9iamVjdC5hc3NpZ24oe30sIERFRkFVTFRfU0VUVElOR1MsIHRoaXMuZHJpdmVyLnNldHRpbmdzLmdldFNldHRpbmdzKCkpO1xuICAgIGNvbnN0IHtmaXhJbWFnZUZpbmRTY3JlZW5zaG90RGltc30gPSBzZXR0aW5ncztcblxuICAgIGxldCBiNjRTY3JlZW5zaG90ID0gYXdhaXQgdGhpcy5kcml2ZXIuZ2V0U2NyZWVuc2hvdCgpO1xuXG4gICAgLy8gaWYgdGhlIHVzZXIgaGFzIHJlcXVlc3RlZCBub3QgdG8gY29ycmVjdCBmb3IgYXNwZWN0IG9yIHNpemUgZGlmZmVyZW5jZXNcbiAgICAvLyBiZXR3ZWVuIHRoZSBzY3JlZW5zaG90IGFuZCB0aGUgc2NyZWVuLCBqdXN0IHJldHVybiB0aGUgc2NyZWVuc2hvdCBub3dcbiAgICBpZiAoIWZpeEltYWdlRmluZFNjcmVlbnNob3REaW1zKSB7XG4gICAgICBsb2cuaW5mbyhgTm90IHZlcmlmeWluZyBzY3JlZW5zaG90IGRpbWVuc2lvbnMgbWF0Y2ggc2NyZWVuYCk7XG4gICAgICByZXR1cm4ge2I2NFNjcmVlbnNob3R9O1xuICAgIH1cblxuICAgIGlmIChzY3JlZW5XaWR0aCA8IDEgfHwgc2NyZWVuSGVpZ2h0IDwgMSkge1xuICAgICAgbG9nLndhcm4oYFRoZSByZXRyaWV2ZWQgc2NyZWVuIHNpemUgJHtzY3JlZW5XaWR0aH14JHtzY3JlZW5IZWlnaHR9IGRvZXMgYCArXG4gICAgICAgIGBub3Qgc2VlbSB0byBiZSB2YWxpZC4gTm8gY2hhbmdlcyB3aWxsIGJlIGFwcGxpZWQgdG8gdGhlIHNjcmVlbnNob3RgKTtcbiAgICAgIHJldHVybiB7YjY0U2NyZWVuc2hvdH07XG4gICAgfVxuXG4gICAgLy8gb3RoZXJ3aXNlLCBkbyBzb21lIHZlcmlmaWNhdGlvbiBvbiB0aGUgc2NyZWVuc2hvdCB0byBtYWtlIHN1cmUgaXQgbWF0Y2hlc1xuICAgIC8vIHRoZSBzY3JlZW4gc2l6ZSBhbmQgYXNwZWN0IHJhdGlvXG4gICAgbG9nLmluZm8oJ1ZlcmlmeWluZyBzY3JlZW5zaG90IHNpemUgYW5kIGFzcGVjdCByYXRpbycpO1xuXG4gICAgbGV0IGltZ09iaiA9IGF3YWl0IGltYWdlVXRpbC5nZXRKaW1wSW1hZ2UoYjY0U2NyZWVuc2hvdCk7XG4gICAgbGV0IHt3aWR0aDogc2hvdFdpZHRoLCBoZWlnaHQ6IHNob3RIZWlnaHR9ID0gaW1nT2JqLmJpdG1hcDtcblxuICAgIGlmIChzaG90V2lkdGggPCAxIHx8IHNob3RIZWlnaHQgPCAxKSB7XG4gICAgICBsb2cud2FybihgVGhlIHJldHJpZXZlZCBzY3JlZW5zaG90IHNpemUgJHtzaG90V2lkdGh9eCR7c2hvdEhlaWdodH0gZG9lcyBgICtcbiAgICAgICAgYG5vdCBzZWVtIHRvIGJlIHZhbGlkLiBObyBjaGFuZ2VzIHdpbGwgYmUgYXBwbGllZCB0byB0aGUgc2NyZWVuc2hvdGApO1xuICAgICAgcmV0dXJuIHtiNjRTY3JlZW5zaG90fTtcbiAgICB9XG5cbiAgICBpZiAoc2NyZWVuV2lkdGggPT09IHNob3RXaWR0aCAmJiBzY3JlZW5IZWlnaHQgPT09IHNob3RIZWlnaHQpIHtcbiAgICAgIC8vIHRoZSBoZWlnaHQgYW5kIHdpZHRoIG9mIHRoZSBzY3JlZW5zaG90IGFuZCB0aGUgZGV2aWNlIHNjcmVlbiBtYXRjaCwgd2hpY2hcbiAgICAgIC8vIG1lYW5zIHdlIHNob3VsZCBiZSBzYWZlIHdoZW4gZG9pbmcgdGVtcGxhdGUgbWF0Y2hlc1xuICAgICAgbG9nLmluZm8oJ1NjcmVlbnNob3Qgc2l6ZSBtYXRjaGVkIHNjcmVlbiBzaXplJyk7XG4gICAgICByZXR1cm4ge2I2NFNjcmVlbnNob3R9O1xuICAgIH1cblxuICAgIC8vIG90aGVyd2lzZSwgaWYgdGhleSBkb24ndCBtYXRjaCwgaXQgY291bGQgc3BlbGwgcHJvYmxlbXMgZm9yIHRoZSBhY2N1cmFjeVxuICAgIC8vIG9mIGNvb3JkaW5hdGVzIHJldHVybmVkIGJ5IHRoZSBpbWFnZSBtYXRjaCBhbGdvcml0aG0sIHNpbmNlIHdlIG1hdGNoIGJhc2VkXG4gICAgLy8gb24gdGhlIHNjcmVlbnNob3QgY29vcmRpbmF0ZXMgbm90IHRoZSBkZXZpY2UgY29vcmRpbmF0ZXMgdGhlbXNlbHZlcy4gVGhlcmVcbiAgICAvLyBhcmUgdHdvIHBvdGVudGlhbCB0eXBlcyBvZiBtaXNtYXRjaDogYXNwZWN0IHJhdGlvIG1pc21hdGNoIGFuZCBzY2FsZVxuICAgIC8vIG1pc21hdGNoLiBXZSBuZWVkIHRvIGRldGVjdCBhbmQgZml4IGJvdGhcblxuICAgIGNvbnN0IHNjYWxlID0ge3hTY2FsZTogMS4wLCB5U2NhbGU6IDEuMH07XG5cbiAgICBjb25zdCBzY3JlZW5BUiA9IHNjcmVlbldpZHRoIC8gc2NyZWVuSGVpZ2h0O1xuICAgIGNvbnN0IHNob3RBUiA9IHNob3RXaWR0aCAvIHNob3RIZWlnaHQ7XG4gICAgaWYgKE1hdGgucm91bmQoc2NyZWVuQVIgKiBGTE9BVF9QUkVDSVNJT04pID09PSBNYXRoLnJvdW5kKHNob3RBUiAqIEZMT0FUX1BSRUNJU0lPTikpIHtcbiAgICAgIGxvZy5pbmZvKGBTY3JlZW5zaG90IGFzcGVjdCByYXRpbyAnJHtzaG90QVJ9JyAoJHtzaG90V2lkdGh9eCR7c2hvdEhlaWdodH0pIG1hdGNoZWQgYCArXG4gICAgICAgIGBzY3JlZW4gYXNwZWN0IHJhdGlvICcke3NjcmVlbkFSfScgKCR7c2NyZWVuV2lkdGh9eCR7c2NyZWVuSGVpZ2h0fSlgKTtcbiAgICB9IGVsc2Uge1xuICAgICAgbG9nLndhcm4oYFdoZW4gdHJ5aW5nIHRvIGZpbmQgYW4gZWxlbWVudCwgZGV0ZXJtaW5lZCB0aGF0IHRoZSBzY3JlZW4gYCArXG4gICAgICAgICAgICAgICBgYXNwZWN0IHJhdGlvIGFuZCBzY3JlZW5zaG90IGFzcGVjdCByYXRpbyBhcmUgZGlmZmVyZW50LiBTY3JlZW4gYCArXG4gICAgICAgICAgICAgICBgaXMgJHtzY3JlZW5XaWR0aH14JHtzY3JlZW5IZWlnaHR9IHdoZXJlYXMgc2NyZWVuc2hvdCBpcyBgICtcbiAgICAgICAgICAgICAgIGAke3Nob3RXaWR0aH14JHtzaG90SGVpZ2h0fS5gKTtcblxuICAgICAgLy8gSW4gdGhlIGNhc2Ugd2hlcmUgdGhlIHgtc2NhbGUgYW5kIHktc2NhbGUgYXJlIGRpZmZlcmVudCwgd2UgbmVlZCB0byBkZWNpZGVcbiAgICAgIC8vIHdoaWNoIG9uZSB0byByZXNwZWN0LCBvdGhlcndpc2UgdGhlIHNjcmVlbnNob3QgYW5kIHRlbXBsYXRlIHdpbGwgZW5kIHVwXG4gICAgICAvLyBiZWluZyByZXNpemVkIGluIGEgd2F5IHRoYXQgY2hhbmdlcyBpdHMgYXNwZWN0IHJhdGlvIChkaXN0b3J0cyBpdCkuIEZvciBleGFtcGxlLCBsZXQncyBzYXk6XG4gICAgICAvLyB0aGlzLmdldFNjcmVlbnNob3Qoc2hvdFdpZHRoLCBzaG90SGVpZ2h0KSBpcyA1NDB4Mzk3LFxuICAgICAgLy8gdGhpcy5nZXREZXZpY2VTaXplKHNjcmVlbldpZHRoLCBzY3JlZW5IZWlnaHQpIGlzIDEwODB4MTkyMC5cbiAgICAgIC8vIFRoZSByYXRpbyB3b3VsZCB0aGVuIGJlIHt4U2NhbGU6IDAuNSwgeVNjYWxlOiAwLjJ9LlxuICAgICAgLy8gSW4gdGhpcyBjYXNlLCB3ZSBtdXN0IHNob3VsZCBgeVNjYWxlOiAwLjJgIGFzIHNjYWxlRmFjdG9yLCBiZWNhdXNlXG4gICAgICAvLyBpZiB3ZSBzZWxlY3QgdGhlIHhTY2FsZSwgdGhlIGhlaWdodCB3aWxsIGJlIGJpZ2dlciB0aGFuIHJlYWwgc2NyZWVuc2hvdCBzaXplXG4gICAgICAvLyB3aGljaCBpcyB1c2VkIHRvIGltYWdlIGNvbXBhcmlzb24gYnkgT3BlbkNWIGFzIGEgYmFzZSBpbWFnZS5cbiAgICAgIC8vIEFsbCBvZiB0aGlzIGlzIHByaW1hcmlseSB1c2VmdWwgd2hlbiB0aGUgc2NyZWVuc2hvdCBpcyBhIGhvcml6b250YWwgc2xpY2UgdGFrZW4gb3V0IG9mIHRoZVxuICAgICAgLy8gc2NyZWVuIChmb3IgZXhhbXBsZSBub3QgaW5jbHVkaW5nIHRvcC9ib3R0b20gbmF2IGJhcnMpXG4gICAgICBjb25zdCB4U2NhbGUgPSAoMS4wICogc2hvdFdpZHRoKSAvIHNjcmVlbldpZHRoO1xuICAgICAgY29uc3QgeVNjYWxlID0gKDEuMCAqIHNob3RIZWlnaHQpIC8gc2NyZWVuSGVpZ2h0O1xuICAgICAgY29uc3Qgc2NhbGVGYWN0b3IgPSB4U2NhbGUgPj0geVNjYWxlID8geVNjYWxlIDogeFNjYWxlO1xuXG4gICAgICBsb2cud2FybihgUmVzaXppbmcgc2NyZWVuc2hvdCB0byAke3Nob3RXaWR0aCAqIHNjYWxlRmFjdG9yfXgke3Nob3RIZWlnaHQgKiBzY2FsZUZhY3Rvcn0gdG8gbWF0Y2ggYCArXG4gICAgICAgICAgICAgICBgc2NyZWVuIGFzcGVjdCByYXRpbyBzbyB0aGF0IGltYWdlIGVsZW1lbnQgY29vcmRpbmF0ZXMgaGF2ZSBhIGAgK1xuICAgICAgICAgICAgICAgYGdyZWF0ZXIgY2hhbmNlIG9mIGJlaW5nIGNvcnJlY3QuYCk7XG4gICAgICBpbWdPYmogPSBpbWdPYmoucmVzaXplKHNob3RXaWR0aCAqIHNjYWxlRmFjdG9yLCBzaG90SGVpZ2h0ICogc2NhbGVGYWN0b3IpO1xuXG4gICAgICBzY2FsZS54U2NhbGUgKj0gc2NhbGVGYWN0b3I7XG4gICAgICBzY2FsZS55U2NhbGUgKj0gc2NhbGVGYWN0b3I7XG5cbiAgICAgIHNob3RXaWR0aCA9IGltZ09iai5iaXRtYXAud2lkdGg7XG4gICAgICBzaG90SGVpZ2h0ID0gaW1nT2JqLmJpdG1hcC5oZWlnaHQ7XG4gICAgfVxuXG4gICAgLy8gUmVzaXplIGJhc2VkIG9uIHRoZSBzY3JlZW4gZGltZW5zaW9ucyBvbmx5IGlmIGJvdGggd2lkdGggYW5kIGhlaWdodCBhcmUgbWlzbWF0Y2hlZFxuICAgIC8vIHNpbmNlIGV4Y2VwdCBmb3IgdGhhdCwgaXQgbWlnaHQgYmUgYSBzaXR1YXRpb24gd2hpY2ggaXMgZGlmZmVyZW50IHdpbmRvdyByZWN0IGFuZFxuICAgIC8vIHNjcmVlbnNob3Qgc2l6ZSBsaWtlIGBAZHJpdmVyLndpbmRvd19yZWN0ICM9Png9MCwgeT0wLCB3aWR0aD0xMDgwLCBoZWlnaHQ9MTc5NGAgYW5kXG4gICAgLy8gYFwiZGV2aWNlU2NyZWVuU2l6ZVwiPT5cIjEwODB4MTkyMFwiYFxuICAgIGlmIChzY3JlZW5XaWR0aCAhPT0gc2hvdFdpZHRoICYmIHNjcmVlbkhlaWdodCAhPT0gc2hvdEhlaWdodCkge1xuICAgICAgbG9nLmluZm8oYFNjYWxpbmcgc2NyZWVuc2hvdCBmcm9tICR7c2hvdFdpZHRofXgke3Nob3RIZWlnaHR9IHRvIG1hdGNoIGAgK1xuICAgICAgICAgICAgICAgYHNjcmVlbiBhdCAke3NjcmVlbldpZHRofXgke3NjcmVlbkhlaWdodH1gKTtcbiAgICAgIGltZ09iaiA9IGltZ09iai5yZXNpemUoc2NyZWVuV2lkdGgsIHNjcmVlbkhlaWdodCk7XG5cbiAgICAgIHNjYWxlLnhTY2FsZSAqPSAoMS4wICogc2NyZWVuV2lkdGgpIC8gc2hvdFdpZHRoO1xuICAgICAgc2NhbGUueVNjYWxlICo9ICgxLjAgKiBzY3JlZW5IZWlnaHQpIC8gc2hvdEhlaWdodDtcbiAgICB9XG5cbiAgICBiNjRTY3JlZW5zaG90ID0gKGF3YWl0IGltZ09iai5nZXRCdWZmZXIoaW1hZ2VVdGlsLk1JTUVfUE5HKSkudG9TdHJpbmcoJ2Jhc2U2NCcpO1xuICAgIHJldHVybiB7YjY0U2NyZWVuc2hvdCwgc2NhbGV9O1xuICB9XG5cbiAgLyoqXG4gICAqIEB0eXBlZGVmIEltYWdlVGVtcGxhdGVTZXR0aW5nc1xuICAgKiBAcHJvcGVydHkge2Jvb2xlYW59IGZpeEltYWdlVGVtcGxhdGVTY2FsZSAtIGZpeEltYWdlVGVtcGxhdGVTY2FsZSBpbiBkZXZpY2Utc2V0dGluZ3NcbiAgICogQHByb3BlcnR5IHtmbG9hdH0gZGVmYXVsdEltYWdlVGVtcGxhdGVTY2FsZSAtIGRlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGUgaW4gZGV2aWNlLXNldHRpbmdzXG4gICAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0gaWdub3JlRGVmYXVsdEltYWdlVGVtcGxhdGVTY2FsZSAtIElnbm9yZSBkZWZhdWx0SW1hZ2VUZW1wbGF0ZVNjYWxlIGlmIGl0IGhhcyB0cnVlLlxuICAgKiBJZiBiNjRUZW1wbGF0ZSBoYXMgYmVlbiBzY2FsZWQgdG8gZGVmYXVsdEltYWdlVGVtcGxhdGVTY2FsZSBvciBzaG91bGQgaWdub3JlIHRoZSBzY2FsZSxcbiAgICogdGhpcyBwYXJhbWV0ZXIgc2hvdWxkIGJlIHRydWUuIGUuZy4gY2xpY2sgaW4gaW1hZ2UtZWxlbWVudCBtb2R1bGVcbiAgICogQHByb3BlcnR5IHtmbG9hdH0geFNjYWxlIC0gU2NhbGUgcmF0aW8gZm9yIHdpZHRoXG4gICAqIEBwcm9wZXJ0eSB7ZmxvYXR9IHlTY2FsZSAtIFNjYWxlIHJhdGlvIGZvciBoZWlnaHRcblxuICAgKi9cbiAgLyoqXG4gICAqIEdldCBhIGltYWdlIHRoYXQgd2lsbCBiZSB1c2VkIGZvciB0ZW1wbGF0ZSBtYWNoaW5nLlxuICAgKiBSZXR1cm5zIHNjYWxlZCBpbWFnZSBpZiBzY2FsZSByYXRpbyBpcyBwcm92aWRlZC5cbiAgICpcbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IGI2NFRlbXBsYXRlIC0gYmFzZTY0LWVuY29kZWQgaW1hZ2UgdXNlZCBhcyBhIHRlbXBsYXRlIHRvIGJlXG4gICAqIG1hdGNoZWQgaW4gdGhlIHNjcmVlbnNob3RcbiAgICogQHBhcmFtIHtJbWFnZVRlbXBsYXRlU2V0dGluZ3N9IG9wdHMgLSBJbWFnZSB0ZW1wbGF0ZSBzY2FsZSByZWxhdGVkIG9wdGlvbnNcbiAgICpcbiAgICogQHJldHVybnMge3N0cmluZ30gYmFzZTY0LWVuY29kZWQgc2NhbGVkIHRlbXBsYXRlIHNjcmVlbnNob3RcbiAgICovXG4gIGFzeW5jIGZpeEltYWdlVGVtcGxhdGVTY2FsZSAoYjY0VGVtcGxhdGUsIG9wdHMgPSB7fSkge1xuICAgIGlmICghb3B0cykge1xuICAgICAgcmV0dXJuIGI2NFRlbXBsYXRlO1xuICAgIH1cblxuICAgIGxldCB7XG4gICAgICBmaXhJbWFnZVRlbXBsYXRlU2NhbGUgPSBmYWxzZSxcbiAgICAgIGRlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGUgPSBERUZBVUxUX1RFTVBMQVRFX0lNQUdFX1NDQUxFLFxuICAgICAgaWdub3JlRGVmYXVsdEltYWdlVGVtcGxhdGVTY2FsZSA9IGZhbHNlLFxuICAgICAgeFNjYWxlID0gREVGQVVMVF9GSVhfSU1BR0VfVEVNUExBVEVfU0NBTEUsXG4gICAgICB5U2NhbGUgPSBERUZBVUxUX0ZJWF9JTUFHRV9URU1QTEFURV9TQ0FMRVxuICAgIH0gPSBvcHRzO1xuXG4gICAgaWYgKGlnbm9yZURlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGUpIHtcbiAgICAgIGRlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGUgPSBERUZBVUxUX1RFTVBMQVRFX0lNQUdFX1NDQUxFO1xuICAgIH1cblxuICAgIC8vIERlZmF1bHRcbiAgICBpZiAoZGVmYXVsdEltYWdlVGVtcGxhdGVTY2FsZSA9PT0gREVGQVVMVF9URU1QTEFURV9JTUFHRV9TQ0FMRSAmJiAhZml4SW1hZ2VUZW1wbGF0ZVNjYWxlKSB7XG4gICAgICByZXR1cm4gYjY0VGVtcGxhdGU7XG4gICAgfVxuXG4gICAgLy8gQ2FsY3VsYXRlIHhTY2FsZSBhbmQgeVNjYWxlIEFwcGl1bSBzaG91bGQgc2NhbGVcbiAgICBpZiAoZml4SW1hZ2VUZW1wbGF0ZVNjYWxlKSB7XG4gICAgICB4U2NhbGUgKj0gZGVmYXVsdEltYWdlVGVtcGxhdGVTY2FsZTtcbiAgICAgIHlTY2FsZSAqPSBkZWZhdWx0SW1hZ2VUZW1wbGF0ZVNjYWxlO1xuICAgIH0gZWxzZSB7XG4gICAgICB4U2NhbGUgPSB5U2NhbGUgPSAxICogZGVmYXVsdEltYWdlVGVtcGxhdGVTY2FsZTtcbiAgICB9XG5cbiAgICAvLyB4U2NhbGUgYW5kIHlTY2FsZSBjYW4gYmUgTmFOIGlmIGRlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGUgaXMgc3RyaW5nLCBmb3IgZXhhbXBsZVxuICAgIGlmICghcGFyc2VGbG9hdCh4U2NhbGUpIHx8ICFwYXJzZUZsb2F0KHlTY2FsZSkpIHtcbiAgICAgIHJldHVybiBiNjRUZW1wbGF0ZTtcbiAgICB9XG5cbiAgICAvLyBSZXR1cm4gaWYgdGhlIHNjYWxlIGlzIGRlZmF1bHQsIDEsIHZhbHVlXG4gICAgaWYgKE1hdGgucm91bmQoeFNjYWxlICogRkxPQVRfUFJFQ0lTSU9OKSA9PT0gTWF0aC5yb3VuZChERUZBVUxUX0ZJWF9JTUFHRV9URU1QTEFURV9TQ0FMRSAqIEZMT0FUX1BSRUNJU0lPTilcbiAgICAgICAgJiYgTWF0aC5yb3VuZCh5U2NhbGUgKiBGTE9BVF9QUkVDSVNJT04gPT09IE1hdGgucm91bmQoREVGQVVMVF9GSVhfSU1BR0VfVEVNUExBVEVfU0NBTEUgKiBGTE9BVF9QUkVDSVNJT04pKSkge1xuICAgICAgcmV0dXJuIGI2NFRlbXBsYXRlO1xuICAgIH1cblxuICAgIGxldCBpbWdUZW1wT2JqID0gYXdhaXQgaW1hZ2VVdGlsLmdldEppbXBJbWFnZShiNjRUZW1wbGF0ZSk7XG4gICAgbGV0IHt3aWR0aDogYmFzZVRlbXBXaWR0aCwgaGVpZ2h0OiBiYXNlVGVtcEhlaWdofSA9IGltZ1RlbXBPYmouYml0bWFwO1xuXG4gICAgY29uc3Qgc2NhbGVkV2lkdGggPSBiYXNlVGVtcFdpZHRoICogeFNjYWxlO1xuICAgIGNvbnN0IHNjYWxlZEhlaWdodCA9IGJhc2VUZW1wSGVpZ2ggKiB5U2NhbGU7XG4gICAgbG9nLmluZm8oYFNjYWxpbmcgdGVtcGxhdGUgaW1hZ2UgZnJvbSAke2Jhc2VUZW1wV2lkdGh9eCR7YmFzZVRlbXBIZWlnaH1gICtcbiAgICAgICAgICAgICAgYCB0byAke3NjYWxlZFdpZHRofXgke3NjYWxlZEhlaWdodH1gKTtcbiAgICBsb2cuaW5mbyhgVGhlIHJhdGlvIGlzICR7eFNjYWxlfSBhbmQgJHt5U2NhbGV9YCk7XG4gICAgaW1nVGVtcE9iaiA9IGF3YWl0IGltZ1RlbXBPYmoucmVzaXplKHNjYWxlZFdpZHRoLCBzY2FsZWRIZWlnaHQpO1xuICAgIHJldHVybiAoYXdhaXQgaW1nVGVtcE9iai5nZXRCdWZmZXIoaW1hZ2VVdGlsLk1JTUVfUE5HKSkudG9TdHJpbmcoJ2Jhc2U2NCcpO1xuICB9XG59XG5cbmV4cG9ydCB7IFczQ19FTEVNRU5UX0tFWSwgTUpTT05XUF9FTEVNRU5UX0tFWSwgREVGQVVMVF9TRVRUSU5HUywgREVGQVVMVF9GSVhfSU1BR0VfVEVNUExBVEVfU0NBTEUgfTtcbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7QUFBQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFFQTs7QUFDQTs7QUFFQSxNQUFNQSxtQkFBbUIsR0FBRyxTQUE1Qjs7QUFDQSxNQUFNQyxlQUFlLEdBQUdDLGNBQUtDLDBCQUE3Qjs7QUFDQSxNQUFNQyxnQ0FBZ0MsR0FBRyxDQUF6Qzs7QUFHQSxNQUFNQyxlQUFlLEdBQUcsTUFBeEI7QUFDQSxNQUFNQyxjQUFjLEdBQUcsT0FBTyxJQUFQLEdBQWMsRUFBckM7QUFFQSxNQUFNQyxnQkFBZ0IsR0FBRztFQUd2QkMsbUJBQW1CLEVBQUVDLGdDQUhFO0VBU3ZCQyxnQkFBZ0IsRUFBRSxFQVRLO0VBYXZCQywwQkFBMEIsRUFBRSxJQWJMO0VBa0J2QkMsb0JBQW9CLEVBQUUsS0FsQkM7RUEwQnZCQyxxQkFBcUIsRUFBRSxLQTFCQTtFQWtDdkJDLHlCQUF5QixFQUFFQywwQ0FsQ0o7RUFzQ3ZCQyw2QkFBNkIsRUFBRSxJQXRDUjtFQTBDdkJDLDhCQUE4QixFQUFFLEtBMUNUO0VBOEN2QkMsdUJBQXVCLEVBQUVDLHVDQTlDRjtFQWtEdkJDLHFCQUFxQixFQUFFO0FBbERBLENBQXpCOzs7QUFxRGUsTUFBTUMsa0JBQU4sQ0FBeUI7RUFDdENDLFdBQVcsQ0FBRUMsTUFBRixFQUFVQyxHQUFHLEdBQUdsQixjQUFoQixF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
|