@appium/images-plugin 1.1.6 → 1.1.9
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 -199
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,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL2xpYi9maW5kZXIuanMiXSwibmFtZXMiOlsiTUpTT05XUF9FTEVNRU5UX0tFWSIsIlczQ19FTEVNRU5UX0tFWSIsInV0aWwiLCJXM0NfV0VCX0VMRU1FTlRfSURFTlRJRklFUiIsIkRFRkFVTFRfRklYX0lNQUdFX1RFTVBMQVRFX1NDQUxFIiwiRkxPQVRfUFJFQ0lTSU9OIiwiTUFYX0NBQ0hFX1NJWkUiLCJERUZBVUxUX1NFVFRJTkdTIiwiaW1hZ2VNYXRjaFRocmVzaG9sZCIsIkRFRkFVTFRfTUFUQ0hfVEhSRVNIT0xEIiwiaW1hZ2VNYXRjaE1ldGhvZCIsImZpeEltYWdlRmluZFNjcmVlbnNob3REaW1zIiwiZml4SW1hZ2VUZW1wbGF0ZVNpemUiLCJmaXhJbWFnZVRlbXBsYXRlU2NhbGUiLCJkZWZhdWx0SW1hZ2VUZW1wbGF0ZVNjYWxlIiwiREVGQVVMVF9URU1QTEFURV9JTUFHRV9TQ0FMRSIsImNoZWNrRm9ySW1hZ2VFbGVtZW50U3RhbGVuZXNzIiwiYXV0b1VwZGF0ZUltYWdlRWxlbWVudFBvc2l0aW9uIiwiaW1hZ2VFbGVtZW50VGFwU3RyYXRlZ3kiLCJJTUFHRV9FTF9UQVBfU1RSQVRFR1lfVzNDIiwiZ2V0TWF0Y2hlZEltYWdlUmVzdWx0IiwiSW1hZ2VFbGVtZW50RmluZGVyIiwiY29uc3RydWN0b3IiLCJkcml2ZXIiLCJtYXgiLCJpbWdFbENhY2hlIiwiTFJVIiwibGVuZ3RoIiwiZWwiLCJ0ZW1wbGF0ZSIsInNldERyaXZlciIsInJlZ2lzdGVySW1hZ2VFbGVtZW50IiwiaW1nRWwiLCJzZXQiLCJpZCIsInByb3RvS2V5IiwiaXNXM0NQcm90b2NvbCIsImFzRWxlbWVudCIsImZpbmRCeUltYWdlIiwiYjY0VGVtcGxhdGUiLCJzaG91bGRDaGVja1N0YWxlbmVzcyIsIm11bHRpcGxlIiwiaWdub3JlRGVmYXVsdEltYWdlVGVtcGxhdGVTY2FsZSIsIkVycm9yIiwic2V0dGluZ3MiLCJnZXRTZXR0aW5ncyIsInRocmVzaG9sZCIsInZpc3VhbGl6ZSIsImxvZyIsImluZm8iLCJnZXRXaW5kb3dTaXplIiwid2lkdGgiLCJzY3JlZW5XaWR0aCIsImhlaWdodCIsInNjcmVlbkhlaWdodCIsImVuc3VyZVRlbXBsYXRlU2l6ZSIsInJlc3VsdHMiLCJjb25kaXRpb24iLCJiNjRTY3JlZW5zaG90Iiwic2NhbGUiLCJnZXRTY3JlZW5zaG90Rm9ySW1hZ2VGaW5kIiwiY29tcGFyaXNvbk9wdHMiLCJtZXRob2QiLCJwdXNoIiwiTUFUQ0hfVEVNUExBVEVfTU9ERSIsImVyciIsIm1lc3NhZ2UiLCJtYXRjaCIsImltcGxpY2l0V2FpdEZvckNvbmRpdGlvbiIsIl8iLCJpc0VtcHR5IiwiZXJyb3JzIiwiTm9TdWNoRWxlbWVudEVycm9yIiwiZWxlbWVudHMiLCJtYXAiLCJyZWN0Iiwic2NvcmUiLCJ2aXN1YWxpemF0aW9uIiwiSlNPTiIsInN0cmluZ2lmeSIsIkltYWdlRWxlbWVudCIsInJlZ2lzdGVyZWRFbGVtZW50cyIsImltZ09iaiIsImltYWdlVXRpbCIsImdldEppbXBJbWFnZSIsInRwbFdpZHRoIiwidHBsSGVpZ2h0IiwiYml0bWFwIiwic2NhbGVUb0ZpdCIsImdldEJ1ZmZlciIsIk1JTUVfUE5HIiwidG9TdHJpbmciLCJnZXRTY3JlZW5zaG90IiwiT2JqZWN0IiwiYXNzaWduIiwid2FybiIsInNob3RXaWR0aCIsInNob3RIZWlnaHQiLCJ4U2NhbGUiLCJ5U2NhbGUiLCJzY3JlZW5BUiIsInNob3RBUiIsIk1hdGgiLCJyb3VuZCIsInNjYWxlRmFjdG9yIiwicmVzaXplIiwib3B0cyIsInBhcnNlRmxvYXQiLCJpbWdUZW1wT2JqIiwiYmFzZVRlbXBXaWR0aCIsImJhc2VUZW1wSGVpZ2giLCJzY2FsZWRXaWR0aCIsInNjYWxlZEhlaWdodCJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7QUFBQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFFQTs7QUFDQTs7QUFFQSxNQUFNQSxtQkFBbUIsR0FBRyxTQUE1Qjs7QUFDQSxNQUFNQyxlQUFlLEdBQUdDLGNB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QWMsRUFBOUQsR0FDRSxPQUFNQyxXQUFZLElBQUdDLFlBQWEsRUFEN0M7O0FBRUFoRSxvQkFBSUMsSUFBSixDQUFVLGdCQUFlaUQsTUFBTyxRQUFPQyxNQUFPLEVBQTlDOztBQUNBUyxJQUFBQSxVQUFVLEdBQUcsTUFBTUEsVUFBVSxDQUFDSCxNQUFYLENBQWtCTSxXQUFsQixFQUErQkMsWUFBL0IsQ0FBbkI7QUFDQSxXQUFPLENBQUMsTUFBTUosVUFBVSxDQUFDbkIsU0FBWCxDQUFxQk4sbUJBQVVPLFFBQS9CLENBQVAsRUFBaURDLFFBQWpELENBQTBELFFBQTFELENBQVA7QUFDRDs7QUF4WHFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCBMUlUgZnJvbSAnbHJ1LWNhY2hlJztcbmltcG9ydCB7IGltYWdlVXRpbCwgdXRpbCB9IGZyb20gJ0BhcHBpdW0vc3VwcG9ydCc7XG5pbXBvcnQgeyBlcnJvcnMgfSBmcm9tICdAYXBwaXVtL2Jhc2UtZHJpdmVyJztcbmltcG9ydCB7IEltYWdlRWxlbWVudCwgREVGQVVMVF9URU1QTEFURV9JTUFHRV9TQ0FMRSxcbiAgICAgICAgIElNQUdFX0VMX1RBUF9TVFJBVEVHWV9XM0MgfSBmcm9tICcuL2ltYWdlLWVsZW1lbnQnO1xuaW1wb3J0IHsgTUFUQ0hfVEVNUExBVEVfTU9ERSwgY29tcGFyZUltYWdlcywgREVGQVVMVF9NQVRDSF9USFJFU0hPTEQgfSBmcm9tICcuL2NvbXBhcmUnO1xuaW1wb3J0IGxvZyBmcm9tICcuL2xvZ2dlcic7XG5cbmNvbnN0IE1KU09OV1BfRUxFTUVOVF9LRVkgPSAnRUxFTUVOVCc7XG5jb25zdCBXM0NfRUxFTUVOVF9LRVkgPSB1dGlsLlczQ19XRUJfRUxFTUVOVF9JREVOVElGSUVSO1xuY29uc3QgREVGQVVMVF9GSVhfSU1BR0VfVEVNUExBVEVfU0NBTEUgPSAxO1xuLy8gVXNlZCB0byBjb21wYXJlIHJhdGlvIGFuZCBzY3JlZW4gd2lkdGhcbi8vIFBpeGVsIGlzIGJhc2ljYWxseSB1bmRlciAxMDgwIGZvciBleGFtcGxlLiAxMDBLIGlzIHByb2JhYmx5IGVub3VnaCBmbyBhIHdoaWxlLlxuY29uc3QgRkxPQVRfUFJFQ0lTSU9OID0gMTAwMDAwO1xuY29uc3QgTUFYX0NBQ0hFX1NJWkUgPSAxMDI0ICogMTAyNCAqIDQwOyAvLyA0MG1iXG5cbmNvbnN0IERFRkFVTFRfU0VUVElOR1MgPSB7XG4gIC8vIHZhbHVlIGJldHdlZW4gMCBhbmQgMSByZXByZXNlbnRpbmcgbWF0Y2ggc3RyZW5ndGgsIGJlbG93IHdoaWNoIGFuIGltYWdlXG4gIC8vIGVsZW1lbnQgd2lsbCBub3QgYmUgZm91bmRcbiAgaW1hZ2VNYXRjaFRocmVzaG9sZDogREVGQVVMVF9NQVRDSF9USFJFU0hPTEQsXG5cbiAgLy8gT25lIG9mIHBvc3NpYmxlIGltYWdlIG1hdGNoaW5nIG1ldGhvZHMuXG4gIC8vIFJlYWQgaHR0cHM6Ly9kb2NzLm9wZW5jdi5vcmcvMy4wLWJldGEvZG9jL3B5X3R1dG9yaWFscy9weV9pbWdwcm9jL3B5X3RlbXBsYXRlX21hdGNoaW5nL3B5X3RlbXBsYXRlX21hdGNoaW5nLmh0bWxcbiAgLy8gZm9yIG1vcmUgZGV0YWlscy5cbiAgLy8gVE1fQ0NPRUZGX05PUk1FRCBieSBkZWZhdWx0XG4gIGltYWdlTWF0Y2hNZXRob2Q6ICcnLFxuXG4gIC8vIGlmIHRoZSBpbWFnZSByZXR1cm5lZCBieSBnZXRTY3JlZW5zaG90IGRpZmZlcnMgaW4gc2l6ZSBvciBhc3BlY3QgcmF0aW9cbiAgLy8gZnJvbSB0aGUgc2NyZWVuLCBhdHRlbXB0IHRvIGZpeCBpdCBhdXRvbWF0aWNhbGx5XG4gIGZpeEltYWdlRmluZFNjcmVlbnNob3REaW1zOiB0cnVlLFxuXG4gIC8vIHdoZXRoZXIgQXBwaXVtIHNob3VsZCBlbnN1cmUgdGhhdCBhbiBpbWFnZSB0ZW1wbGF0ZSBzZW50IGluIGR1cmluZyBpbWFnZVxuICAvLyBlbGVtZW50IGZpbmQgc2hvdWxkIGhhdmUgaXRzIHNpemUgYWRqdXN0ZWQgc28gdGhlIG1hdGNoIGFsZ29yaXRobSB3aWxsIG5vdFxuICAvLyBjb21wbGFpblxuICBmaXhJbWFnZVRlbXBsYXRlU2l6ZTogZmFsc2UsXG5cbiAgLy8gd2hldGhlciBBcHBpdW0gc2hvdWxkIGVuc3VyZSB0aGF0IGFuIGltYWdlIHRlbXBsYXRlIHNlbnQgaW4gZHVyaW5nIGltYWdlXG4gIC8vIGVsZW1lbnQgZmluZCBzaG91bGQgaGF2ZSBpdHMgc2NhbGUgYWRqdXN0ZWQgdG8gZGlzcGxheSBzaXplIHNvIHRoZSBtYXRjaFxuICAvLyBhbGdvcml0aG0gd2lsbCBub3QgY29tcGxhaW4uXG4gIC8vIGUuZy4gaU9TIGhhcyBgd2lkdGg9Mzc1LCBoZWlnaHQ9NjY3YCB3aW5kb3cgcmVjdCwgYnV0IGl0cyBzY3JlZW5zaG90IGlzXG4gIC8vICAgICAgYHdpZHRoPTc1MCDDlyBoZWlnaHQ9MTMzNGAgcGl4ZWxzLiBUaGlzIHNldHRpbmcgaGVscCB0byBhZGp1c3QgdGhlIHNjYWxlXG4gIC8vICAgICAgaWYgYSB1c2VyIHVzZSBgd2lkdGg9NzUwIMOXIGhlaWdodD0xMzM0YCBwaXhlbHMncyBiYXNlIHRlbXBsYXRlIGltYWdlLlxuICBmaXhJbWFnZVRlbXBsYXRlU2NhbGU6IGZhbHNlLFxuXG4gIC8vIFVzZXJzIG1pZ2h0IGhhdmUgc2NhbGVkIHRlbXBsYXRlIGltYWdlIHRvIHJlZHVjZSB0aGVpciBzdG9yYWdlIHNpemUuXG4gIC8vIFRoaXMgc2V0dGluZyBhbGxvd3MgdXNlcnMgdG8gc2NhbGUgYSB0ZW1wbGF0ZSBpbWFnZSB0aGV5IHNlbmQgdG8gQXBwaXVtIHNlcnZlclxuICAvLyBzbyB0aGF0IHRoZSBBcHBpdW0gc2VydmVyIGNvbXBhcmVzIHRoZSBhY3R1YWwgc2NhbGUgdXNlcnMgb3JpZ2luYWxseSBoYWQuXG4gIC8vIGUuZy4gSWYgYSB1c2VyIGhhcyBhbiBpbWFnZSBvZiAyNzAgeCAzMiBwaXhlbHMgd2hpY2ggd2FzIG9yaWdpbmFsbHkgMTA4MCB4IDEyNiBwaXhlbHMsXG4gIC8vICAgICAgdGhlIHVzZXIgY2FuIHNldCB7ZGVmYXVsdEltYWdlVGVtcGxhdGVTY2FsZTogNC4wfSB0byBzY2FsZSB0aGUgc21hbGwgaW1hZ2VcbiAgLy8gICAgICB0byB0aGUgb3JpZ2luYWwgb25lIHNvIHRoYXQgQXBwaXVtIGNhbiBjb21wYXJlIGl0IGFzIHRoZSBvcmlnaW5hbCBvbmUuXG4gIGRlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGU6IERFRkFVTFRfVEVNUExBVEVfSU1BR0VfU0NBTEUsXG5cbiAgLy8gd2hldGhlciBBcHBpdW0gc2hvdWxkIHJlLWNoZWNrIHRoYXQgYW4gaW1hZ2UgZWxlbWVudCBjYW4gYmUgbWF0Y2hlZFxuICAvLyBhZ2FpbnN0IHRoZSBjdXJyZW50IHNjcmVlbnNob3QgYmVmb3JlIGNsaWNraW5nIGl0XG4gIGNoZWNrRm9ySW1hZ2VFbGVtZW50U3RhbGVuZXNzOiB0cnVlLFxuXG4gIC8vIHdoZXRoZXIgYmVmb3JlIGNsaWNraW5nIG9uIGFuIGltYWdlIGVsZW1lbnQgQXBwaXVtIHNob3VsZCByZS1kZXRlcm1pbmUgdGhlXG4gIC8vIHBvc2l0aW9uIG9mIHRoZSBlbGVtZW50IG9uIHNjcmVlblxuICBhdXRvVXBkYXRlSW1hZ2VFbGVtZW50UG9zaXRpb246IGZhbHNlLFxuXG4gIC8vIHdoaWNoIG1ldGhvZCB0byB1c2UgZm9yIHRhcHBpbmcgYnkgY29vcmRpbmF0ZSBmb3IgaW1hZ2UgZWxlbWVudHMuIHRoZVxuICAvLyBvcHRpb25zIGFyZSAndzNjJyBvciAnbWpzb253cCdcbiAgaW1hZ2VFbGVtZW50VGFwU3RyYXRlZ3k6IElNQUdFX0VMX1RBUF9TVFJBVEVHWV9XM0MsXG5cbiAgLy8gd2hpY2ggbWV0aG9kIHRvIHVzZSB0byBzYXZlIHRoZSBtYXRjaGVkIGltYWdlIGFyZWEgaW4gSW1hZ2VFbGVtZW50IGNsYXNzLlxuICAvLyBJdCBpcyB1c2VkIGZvciBkZWJ1Z2dpbmcgcHVycG9zZS5cbiAgZ2V0TWF0Y2hlZEltYWdlUmVzdWx0OiBmYWxzZSxcbn07XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEltYWdlRWxlbWVudEZpbmRlciB7XG4gIGNvbnN0cnVjdG9yIChkcml2ZXIsIG1heCA9IE1BWF9DQUNIRV9TSVpFKSB7XG4gICAgdGhpcy5kcml2ZXIgPSBkcml2ZXI7XG4gICAgdGhpcy5pbWdFbENhY2hlID0gbmV3IExSVSh7XG4gICAgICBtYXgsXG4gICAgICBsZW5ndGg6IChlbCkgPT4gZWwudGVtcGxhdGUubGVuZ3RoLFxuICAgIH0pO1xuICB9XG5cbiAgc2V0RHJpdmVyIChkcml2ZXIpIHtcbiAgICB0aGlzLmRyaXZlciA9IGRyaXZlcjtcbiAgfVxuXG4gIHJlZ2lzdGVySW1hZ2VFbGVtZW50IChpbWdFbCkge1xuICAgIHRoaXMuaW1nRWxDYWNoZS5zZXQoaW1nRWwuaWQsIGltZ0VsKTtcbiAgICBjb25zdCBwcm90b0tleSA9IHRoaXMuZHJpdmVyLmlzVzNDUHJvdG9jb2woKSA/IFczQ19FTEVNRU5UX0tFWSA6IE1KU09OV1BfRUxFTUVOVF9LRVk7XG4gICAgcmV0dXJuIGltZ0VsLmFzRWxlbWVudChwcm90b0tleSk7XG4gIH1cblxuICAvKipcbiAgICogQHR5cGVkZWYgRmluZEJ5SW1hZ2VPcHRpb25zXG4gICAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0gW3Nob3VsZENoZWNrU3RhbGVuZXNzPWZhbHNlXSAtIHdoZXRoZXIgdGhpcyBjYWxsIHRvIGZpbmQgYW5cbiAgICogaW1hZ2UgaXMgbWVyZWx5IHRvIGNoZWNrIHN0YWxlbmVzcy4gSWYgc28gd2UgY2FuIGJ5cGFzcyBhIGxvdCBvZiBsb2dpY1xuICAgKiBAcHJvcGVydHkge2Jvb2xlYW59IFttdWx0aXBsZT1mYWxzZV0gLSBXaGV0aGVyIHdlIGFyZSBmaW5kaW5nIG9uZSBlbGVtZW50IG9yXG4gICAqIG11bHRpcGxlXG4gICAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0gW2lnbm9yZURlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGU9ZmFsc2VdIC0gV2hldGhlciB3ZVxuICAgKiBpZ25vcmUgZGVmYXVsdEltYWdlVGVtcGxhdGVTY2FsZS4gSXQgY2FuIGJlIHVzZWQgd2hlbiB5b3Ugd291bGQgbGlrZSB0b1xuICAgKiBzY2FsZSBiNjRUZW1wbGF0ZSB3aXRoIGRlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGUgc2V0dGluZy5cbiAgICovXG5cbiAgLyoqXG4gICAqIEZpbmQgYSBzY3JlZW4gcmVjdCByZXByZXNlbnRlZCBieSBhbiBJbWFnZUVsZW1lbnQgY29ycmVzcG9uZGluZyB0byBhbiBpbWFnZVxuICAgKiB0ZW1wbGF0ZSBzZW50IGluIGJ5IHRoZSBjbGllbnRcbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IGI2NFRlbXBsYXRlIC0gYmFzZTY0LWVuY29kZWQgaW1hZ2UgdXNlZCBhcyBhIHRlbXBsYXRlIHRvIGJlXG4gICAqIG1hdGNoZWQgaW4gdGhlIHNjcmVlbnNob3RcbiAgICogQHBhcmFtIHtGaW5kQnlJbWFnZU9wdGlvbnN9IC0gYWRkaXRpb25hbCBvcHRpb25zXG4gICAqXG4gICAqIEByZXR1cm5zIHtXZWJFbGVtZW50fSAtIFdlYkRyaXZlciBlbGVtZW50IHdpdGggYSBzcGVjaWFsIGlkIHByZWZpeFxuICAgKi9cbiAgYXN5bmMgZmluZEJ5SW1hZ2UgKGI2NFRlbXBsYXRlLCB7XG4gICAgc2hvdWxkQ2hlY2tTdGFsZW5lc3MgPSBmYWxzZSxcbiAgICBtdWx0aXBsZSA9IGZhbHNlLFxuICAgIGlnbm9yZURlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGUgPSBmYWxzZSxcbiAgfSkge1xuICAgIGlmICghdGhpcy5kcml2ZXIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgQ2FuJ3QgZmluZCB3aXRob3V0IGEgZHJpdmVyIWApO1xuICAgIH1cbiAgICBjb25zdCBzZXR0aW5ncyA9IHsuLi5ERUZBVUxUX1NFVFRJTkdTLCAuLi50aGlzLmRyaXZlci5zZXR0aW5ncy5nZXRTZXR0aW5ncygpfTtcbiAgICBjb25zdCB7XG4gICAgICBpbWFnZU1hdGNoVGhyZXNob2xkOiB0aHJlc2hvbGQsXG4gICAgICBpbWFnZU1hdGNoTWV0aG9kLFxuICAgICAgZml4SW1hZ2VUZW1wbGF0ZVNpemUsXG4gICAgICBmaXhJbWFnZVRlbXBsYXRlU2NhbGUsXG4gICAgICBkZWZhdWx0SW1hZ2VUZW1wbGF0ZVNjYWxlLFxuICAgICAgZ2V0TWF0Y2hlZEltYWdlUmVzdWx0OiB2aXN1YWxpemVcbiAgICB9ID0gc2V0dGluZ3M7XG5cbiAgICBsb2cuaW5mbyhgRmluZGluZyBpbWFnZSBlbGVtZW50IHdpdGggbWF0Y2ggdGhyZXNob2xkICR7dGhyZXNob2xkfWApO1xuICAgIGlmICghdGhpcy5kcml2ZXIuZ2V0V2luZG93U2l6ZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiVGhpcyBkcml2ZXIgZG9lcyBub3Qgc3VwcG9ydCB0aGUgcmVxdWlyZWQgJ2dldFdpbmRvd1NpemUnIGNvbW1hbmRcIik7XG4gICAgfVxuICAgIGNvbnN0IHt3aWR0aDogc2NyZWVuV2lkdGgsIGhlaWdodDogc2NyZWVuSGVpZ2h0fSA9IGF3YWl0IHRoaXMuZHJpdmVyLmdldFdpbmRvd1NpemUoKTtcblxuICAgIC8vIHNvbWVvbmUgbWlnaHQgaGF2ZSBzZW50IGluIGEgdGVtcGxhdGUgdGhhdCdzIGxhcmdlciB0aGFuIHRoZSBzY3JlZW5cbiAgICAvLyBkaW1lbnNpb25zLiBJZiBzbyBsZXQncyBjaGVjayBhbmQgY3V0IGl0IGRvd24gdG8gc2l6ZSBzaW5jZSB0aGUgYWxnb3JpdGhtXG4gICAgLy8gd2lsbCBub3Qgd29yayB1bmxlc3Mgd2UgZG8uIEJ1dCBiZWNhdXNlIGl0IHJlcXVpcmVzIHNvbWUgcG90ZW50aWFsbHlcbiAgICAvLyBleHBlbnNpdmUgY29tbWFuZHMsIG9ubHkgZG8gdGhpcyBpZiB0aGUgdXNlciBoYXMgcmVxdWVzdGVkIGl0IGluIHNldHRpbmdzLlxuICAgIGlmIChmaXhJbWFnZVRlbXBsYXRlU2l6ZSkge1xuICAgICAgYjY0VGVtcGxhdGUgPSBhd2FpdCB0aGlzLmVuc3VyZVRlbXBsYXRlU2l6ZShiNjRUZW1wbGF0ZSwgc2NyZWVuV2lkdGgsXG4gICAgICAgIHNjcmVlbkhlaWdodCk7XG4gICAgfVxuXG4gICAgY29uc3QgcmVzdWx0cyA9IFtdO1xuICAgIGNvbnN0IGNvbmRpdGlvbiA9IGFzeW5jICgpID0+IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHtiNjRTY3JlZW5zaG90LCBzY2FsZX0gPSBhd2FpdCB0aGlzLmdldFNjcmVlbnNob3RGb3JJbWFnZUZpbmQoc2NyZWVuV2lkdGgsIHNjcmVlbkhlaWdodCk7XG5cbiAgICAgICAgYjY0VGVtcGxhdGUgPSBhd2FpdCB0aGlzLmZpeEltYWdlVGVtcGxhdGVTY2FsZShiNjRUZW1wbGF0ZSwge1xuICAgICAgICAgIGRlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGUsIGlnbm9yZURlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGUsXG4gICAgICAgICAgZml4SW1hZ2VUZW1wbGF0ZVNjYWxlLCAuLi5zY2FsZVxuICAgICAgICB9KTtcblxuICAgICAgICBjb25zdCBjb21wYXJpc29uT3B0cyA9IHtcbiAgICAgICAgICB0aHJlc2hvbGQsXG4gICAgICAgICAgdmlzdWFsaXplLFxuICAgICAgICAgIG11bHRpcGxlLFxuICAgICAgICB9O1xuICAgICAgICBpZiAoaW1hZ2VNYXRjaE1ldGhvZCkge1xuICAgICAgICAgIGNvbXBhcmlzb25PcHRzLm1ldGhvZCA9IGltYWdlTWF0Y2hNZXRob2Q7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG11bHRpcGxlKSB7XG4gICAgICAgICAgcmVzdWx0cy5wdXNoKC4uLihhd2FpdCBjb21wYXJlSW1hZ2VzKE1BVENIX1RFTVBMQVRFX01PREUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGI2NFNjcmVlbnNob3QsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGI2NFRlbXBsYXRlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21wYXJpc29uT3B0cykpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICByZXN1bHRzLnB1c2goYXdhaXQgY29tcGFyZUltYWdlcyhNQVRDSF9URU1QTEFURV9NT0RFLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGI2NFNjcmVlbnNob3QsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYjY0VGVtcGxhdGUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tcGFyaXNvbk9wdHMpKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdHJ1ZTtcblxuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIC8vIGlmIGNvbXBhcmVJbWFnZXMgZmFpbHMsIHdlJ2xsIGdldCBhIHNwZWNpZmljIGVycm9yLCBidXQgd2Ugc2hvdWxkXG4gICAgICAgIC8vIHJldHJ5LCBzbyB0cmFwIHRoYXQgYW5kIGp1c3QgcmV0dXJuIGZhbHNlIHRvIHRyaWdnZXIgdGhlIG5leHQgcm91bmQgb2ZcbiAgICAgICAgLy8gaW1wbGljaXRseSB3YWl0aW5nLiBGb3Igb3RoZXIgZXJyb3JzLCB0aHJvdyB0aGVtIHRvIGdldCBvdXQgb2YgdGhlXG4gICAgICAgIC8vIGltcGxpY2l0IHdhaXQgbG9vcFxuICAgICAgICBpZiAoZXJyLm1lc3NhZ2UubWF0Y2goL0Nhbm5vdCBmaW5kIGFueSBvY2N1cnJlbmNlcy8pKSB7XG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIHRocm93IGVycjtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHRoaXMuZHJpdmVyLmltcGxpY2l0V2FpdEZvckNvbmRpdGlvbihjb25kaXRpb24pO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgLy8gdGhpcyBgaW1wbGljaXRXYWl0Rm9yQ29uZGl0aW9uYCBtZXRob2Qgd2lsbCB0aHJvdyBhICdDb25kaXRpb24gdW5tZXQnXG4gICAgICAvLyBlcnJvciBpZiBhbiBlbGVtZW50IGlzIG5vdCBmb3VuZCBldmVudHVhbGx5LiBJbiB0aGF0IGNhc2UsIHdlIHdpbGxcbiAgICAgIC8vIGhhbmRsZSB0aGUgZWxlbWVudCBub3QgZm91bmQgcmVzcG9uc2UgYmVsb3cuIEluIHRoZSBjYXNlIHdoZXJlIGdldCBzb21lXG4gICAgICAvLyBfb3RoZXJfIGtpbmQgb2YgZXJyb3IsIGl0IG1lYW5zIHNvbWV0aGluZyBibGV3IHVwIHRvdGFsbHkgYXBhcnQgZnJvbSB0aGVcbiAgICAgIC8vIGltcGxpY2l0IHdhaXQgdGltZW91dC4gV2Ugc2hvdWxkIG5vdCBtYXNrIHRoYXQgZXJyb3IgYW5kIGluc3RlYWQgdGhyb3dcbiAgICAgIC8vIGl0IHN0cmFpZ2h0YXdheVxuICAgICAgaWYgKCFlcnIubWVzc2FnZS5tYXRjaCgvQ29uZGl0aW9uIHVubWV0LykpIHtcbiAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChfLmlzRW1wdHkocmVzdWx0cykpIHtcbiAgICAgIGlmIChtdWx0aXBsZSkge1xuICAgICAgICByZXR1cm4gW107XG4gICAgICB9XG4gICAgICB0aHJvdyBuZXcgZXJyb3JzLk5vU3VjaEVsZW1lbnRFcnJvcigpO1xuICAgIH1cblxuICAgIGNvbnN0IGVsZW1lbnRzID0gcmVzdWx0cy5tYXAoKHtyZWN0LCBzY29yZSwgdmlzdWFsaXphdGlvbn0pID0+IHtcbiAgICAgIGxvZy5pbmZvKGBJbWFnZSB0ZW1wbGF0ZSBtYXRjaGVkOiAke0pTT04uc3RyaW5naWZ5KHJlY3QpfWApO1xuICAgICAgcmV0dXJuIG5ldyBJbWFnZUVsZW1lbnQoYjY0VGVtcGxhdGUsIHJlY3QsIHNjb3JlLCB2aXN1YWxpemF0aW9uLCB0aGlzKTtcbiAgICB9KTtcblxuICAgIC8vIGlmIHdlJ3JlIGp1c3QgY2hlY2tpbmcgc3RhbGVuZXNzLCByZXR1cm4gc3RyYWlnaHRhd2F5IHNvIHdlIGRvbid0IGFkZFxuICAgIC8vIGEgbmV3IGVsZW1lbnQgdG8gdGhlIGNhY2hlLiBzaG91bGRDaGVja1N0YWxlbmVzcyBkb2VzIG5vdCBzdXBwb3J0IG11bHRpcGxlXG4gICAgLy8gZWxlbWVudHMsIHNpbmNlIGl0IGlzIGEgcHVyZWx5IGludGVybmFsIG1lY2hhbmlzbVxuICAgIGlmIChzaG91bGRDaGVja1N0YWxlbmVzcykge1xuICAgICAgcmV0dXJuIGVsZW1lbnRzWzBdO1xuICAgIH1cblxuICAgIGNvbnN0IHJlZ2lzdGVyZWRFbGVtZW50cyA9IGVsZW1lbnRzLm1hcCgoaW1nRWwpID0+IHRoaXMucmVnaXN0ZXJJbWFnZUVsZW1lbnQoaW1nRWwpKTtcblxuICAgIHJldHVybiBtdWx0aXBsZSA/IHJlZ2lzdGVyZWRFbGVtZW50cyA6IHJlZ2lzdGVyZWRFbGVtZW50c1swXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFbnN1cmUgdGhhdCB0aGUgaW1hZ2UgdGVtcGxhdGUgc2VudCBpbiBmb3IgYSBmaW5kIGlzIG9mIGEgc3VpdGFibGUgc2l6ZVxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gYjY0VGVtcGxhdGUgLSBiYXNlNjQtZW5jb2RlZCBpbWFnZVxuICAgKiBAcGFyYW0ge2ludH0gc2NyZWVuV2lkdGggLSB3aWR0aCBvZiBzY3JlZW5cbiAgICogQHBhcmFtIHtpbnR9IHNjcmVlbkhlaWdodCAtIGhlaWdodCBvZiBzY3JlZW5cbiAgICpcbiAgICogQHJldHVybnMge3N0cmluZ30gYmFzZTY0LWVuY29kZWQgaW1hZ2UsIHBvdGVudGlhbGx5IHJlc2l6ZWRcbiAgICovXG4gIGFzeW5jIGVuc3VyZVRlbXBsYXRlU2l6ZSAoYjY0VGVtcGxhdGUsIHNjcmVlbldpZHRoLCBzY3JlZW5IZWlnaHQpIHtcbiAgICBsZXQgaW1nT2JqID0gYXdhaXQgaW1hZ2VVdGlsLmdldEppbXBJbWFnZShiNjRUZW1wbGF0ZSk7XG4gICAgbGV0IHt3aWR0aDogdHBsV2lkdGgsIGhlaWdodDogdHBsSGVpZ2h0fSA9IGltZ09iai5iaXRtYXA7XG5cbiAgICBsb2cuaW5mbyhgVGVtcGxhdGUgaW1hZ2UgaXMgJHt0cGxXaWR0aH14JHt0cGxIZWlnaHR9LiBTY3JlZW4gc2l6ZSBpcyAke3NjcmVlbldpZHRofXgke3NjcmVlbkhlaWdodH1gKTtcbiAgICAvLyBpZiB0aGUgdGVtcGxhdGUgZml0cyBpbnNpZGUgdGhlIHNjcmVlbiBkaW1lbnNpb25zLCB3ZSdyZSBnb29kXG4gICAgaWYgKHRwbFdpZHRoIDw9IHNjcmVlbldpZHRoICYmIHRwbEhlaWdodCA8PSBzY3JlZW5IZWlnaHQpIHtcbiAgICAgIHJldHVybiBiNjRUZW1wbGF0ZTtcbiAgICB9XG5cbiAgICBsb2cuaW5mbyhgU2NhbGluZyB0ZW1wbGF0ZSBpbWFnZSBmcm9tICR7dHBsV2lkdGh9eCR7dHBsSGVpZ2h0fSB0byBtYXRjaCBgICtcbiAgICAgICAgICAgICBgc2NyZWVuIGF0ICR7c2NyZWVuV2lkdGh9eCR7c2NyZWVuSGVpZ2h0fWApO1xuICAgIC8vIG90aGVyd2lzZSwgc2NhbGUgaXQgdG8gZml0IGluc2lkZSB0aGUgc2NyZWVuIGRpbWVuc2lvbnNcbiAgICBpbWdPYmogPSBpbWdPYmouc2NhbGVUb0ZpdChzY3JlZW5XaWR0aCwgc2NyZWVuSGVpZ2h0KTtcbiAgICByZXR1cm4gKGF3YWl0IGltZ09iai5nZXRCdWZmZXIoaW1hZ2VVdGlsLk1JTUVfUE5HKSkudG9TdHJpbmcoJ2Jhc2U2NCcpO1xuICB9XG5cbiAgLyoqXG4gICAqIEB0eXBlZGVmIFNjcmVlbnNob3RcbiAgICogQHByb3BlcnR5IHtzdHJpbmd9IGI2NFNjcmVlbnNob3QgLSBiYXNlNjQgYmFzZWQgc2NyZWVuc2hvdCBzdHJpbmdcbiAgICovXG4gIC8qKlxuICAgKiBAdHlwZWRlZiBTY3JlZW5zaG90U2NhbGVcbiAgICogQHByb3BlcnR5IHtmbG9hdH0geFNjYWxlIC0gU2NhbGUgcmF0aW8gZm9yIHdpZHRoXG4gICAqIEBwcm9wZXJ0eSB7ZmxvYXR9IHlTY2FsZSAtIFNjYWxlIHJhdGlvIGZvciBoZWlnaHRcbiAgICovXG4gIC8qKlxuICAgKiBHZXQgdGhlIHNjcmVlbnNob3QgaW1hZ2UgdGhhdCB3aWxsIGJlIHVzZWQgZm9yIGZpbmQgYnkgZWxlbWVudCwgcG90ZW50aWFsbHlcbiAgICogYWx0ZXJpbmcgaXQgaW4gdmFyaW91cyB3YXlzIGJhc2VkIG9uIHVzZXItcmVxdWVzdGVkIHNldHRpbmdzXG4gICAqXG4gICAqIEBwYXJhbSB7aW50fSBzY3JlZW5XaWR0aCAtIHdpZHRoIG9mIHNjcmVlblxuICAgKiBAcGFyYW0ge2ludH0gc2NyZWVuSGVpZ2h0IC0gaGVpZ2h0IG9mIHNjcmVlblxuICAgKlxuICAgKiBAcmV0dXJucyB7IHtiNjRTY3JlZW5zaG90OiBTY3JlZW5zaG90LCBzY2FsZTogU2NyZWVuc2hvdFNjYWxlPyB9IH0gYmFzZTY0LWVuY29kZWQgc2NyZWVuc2hvdCBhbmQgU2NyZWVuc2hvdFNjYWxlXG4gICAqL1xuICBhc3luYyBnZXRTY3JlZW5zaG90Rm9ySW1hZ2VGaW5kIChzY3JlZW5XaWR0aCwgc2NyZWVuSGVpZ2h0KSB7XG4gICAgaWYgKCF0aGlzLmRyaXZlci5nZXRTY3JlZW5zaG90KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJUaGlzIGRyaXZlciBkb2VzIG5vdCBzdXBwb3J0IHRoZSByZXF1aXJlZCAnZ2V0U2NyZWVuc2hvdCcgY29tbWFuZFwiKTtcbiAgICB9XG4gICAgY29uc3Qgc2V0dGluZ3MgPSBPYmplY3QuYXNzaWduKHt9LCBERUZBVUxUX1NFVFRJTkdTLCB0aGlzLmRyaXZlci5zZXR0aW5ncy5nZXRTZXR0aW5ncygpKTtcbiAgICBjb25zdCB7Zml4SW1hZ2VGaW5kU2NyZWVuc2hvdERpbXN9ID0gc2V0dGluZ3M7XG5cbiAgICBsZXQgYjY0U2NyZWVuc2hvdCA9IGF3YWl0IHRoaXMuZHJpdmVyLmdldFNjcmVlbnNob3QoKTtcblxuICAgIC8vIGlmIHRoZSB1c2VyIGhhcyByZXF1ZXN0ZWQgbm90IHRvIGNvcnJlY3QgZm9yIGFzcGVjdCBvciBzaXplIGRpZmZlcmVuY2VzXG4gICAgLy8gYmV0d2VlbiB0aGUgc2NyZWVuc2hvdCBhbmQgdGhlIHNjcmVlbiwganVzdCByZXR1cm4gdGhlIHNjcmVlbnNob3Qgbm93XG4gICAgaWYgKCFmaXhJbWFnZUZpbmRTY3JlZW5zaG90RGltcykge1xuICAgICAgbG9nLmluZm8oYE5vdCB2ZXJpZnlpbmcgc2NyZWVuc2hvdCBkaW1lbnNpb25zIG1hdGNoIHNjcmVlbmApO1xuICAgICAgcmV0dXJuIHtiNjRTY3JlZW5zaG90fTtcbiAgICB9XG5cbiAgICBpZiAoc2NyZWVuV2lkdGggPCAxIHx8IHNjcmVlbkhlaWdodCA8IDEpIHtcbiAgICAgIGxvZy53YXJuKGBUaGUgcmV0cmlldmVkIHNjcmVlbiBzaXplICR7c2NyZWVuV2lkdGh9eCR7c2NyZWVuSGVpZ2h0fSBkb2VzIGAgK1xuICAgICAgICBgbm90IHNlZW0gdG8gYmUgdmFsaWQuIE5vIGNoYW5nZXMgd2lsbCBiZSBhcHBsaWVkIHRvIHRoZSBzY3JlZW5zaG90YCk7XG4gICAgICByZXR1cm4ge2I2NFNjcmVlbnNob3R9O1xuICAgIH1cblxuICAgIC8vIG90aGVyd2lzZSwgZG8gc29tZSB2ZXJpZmljYXRpb24gb24gdGhlIHNjcmVlbnNob3QgdG8gbWFrZSBzdXJlIGl0IG1hdGNoZXNcbiAgICAvLyB0aGUgc2NyZWVuIHNpemUgYW5kIGFzcGVjdCByYXRpb1xuICAgIGxvZy5pbmZvKCdWZXJpZnlpbmcgc2NyZWVuc2hvdCBzaXplIGFuZCBhc3BlY3QgcmF0aW8nKTtcblxuICAgIGxldCBpbWdPYmogPSBhd2FpdCBpbWFnZVV0aWwuZ2V0SmltcEltYWdlKGI2NFNjcmVlbnNob3QpO1xuICAgIGxldCB7d2lkdGg6IHNob3RXaWR0aCwgaGVpZ2h0OiBzaG90SGVpZ2h0fSA9IGltZ09iai5iaXRtYXA7XG5cbiAgICBpZiAoc2hvdFdpZHRoIDwgMSB8fCBzaG90SGVpZ2h0IDwgMSkge1xuICAgICAgbG9nLndhcm4oYFRoZSByZXRyaWV2ZWQgc2NyZWVuc2hvdCBzaXplICR7c2hvdFdpZHRofXgke3Nob3RIZWlnaHR9IGRvZXMgYCArXG4gICAgICAgIGBub3Qgc2VlbSB0byBiZSB2YWxpZC4gTm8gY2hhbmdlcyB3aWxsIGJlIGFwcGxpZWQgdG8gdGhlIHNjcmVlbnNob3RgKTtcbiAgICAgIHJldHVybiB7YjY0U2NyZWVuc2hvdH07XG4gICAgfVxuXG4gICAgaWYgKHNjcmVlbldpZHRoID09PSBzaG90V2lkdGggJiYgc2NyZWVuSGVpZ2h0ID09PSBzaG90SGVpZ2h0KSB7XG4gICAgICAvLyB0aGUgaGVpZ2h0IGFuZCB3aWR0aCBvZiB0aGUgc2NyZWVuc2hvdCBhbmQgdGhlIGRldmljZSBzY3JlZW4gbWF0Y2gsIHdoaWNoXG4gICAgICAvLyBtZWFucyB3ZSBzaG91bGQgYmUgc2FmZSB3aGVuIGRvaW5nIHRlbXBsYXRlIG1hdGNoZXNcbiAgICAgIGxvZy5pbmZvKCdTY3JlZW5zaG90IHNpemUgbWF0Y2hlZCBzY3JlZW4gc2l6ZScpO1xuICAgICAgcmV0dXJuIHtiNjRTY3JlZW5zaG90fTtcbiAgICB9XG5cbiAgICAvLyBvdGhlcndpc2UsIGlmIHRoZXkgZG9uJ3QgbWF0Y2gsIGl0IGNvdWxkIHNwZWxsIHByb2JsZW1zIGZvciB0aGUgYWNjdXJhY3lcbiAgICAvLyBvZiBjb29yZGluYXRlcyByZXR1cm5lZCBieSB0aGUgaW1hZ2UgbWF0Y2ggYWxnb3JpdGhtLCBzaW5jZSB3ZSBtYXRjaCBiYXNlZFxuICAgIC8vIG9uIHRoZSBzY3JlZW5zaG90IGNvb3JkaW5hdGVzIG5vdCB0aGUgZGV2aWNlIGNvb3JkaW5hdGVzIHRoZW1zZWx2ZXMuIFRoZXJlXG4gICAgLy8gYXJlIHR3byBwb3RlbnRpYWwgdHlwZXMgb2YgbWlzbWF0Y2g6IGFzcGVjdCByYXRpbyBtaXNtYXRjaCBhbmQgc2NhbGVcbiAgICAvLyBtaXNtYXRjaC4gV2UgbmVlZCB0byBkZXRlY3QgYW5kIGZpeCBib3RoXG5cbiAgICBjb25zdCBzY2FsZSA9IHt4U2NhbGU6IDEuMCwgeVNjYWxlOiAxLjB9O1xuXG4gICAgY29uc3Qgc2NyZWVuQVIgPSBzY3JlZW5XaWR0aCAvIHNjcmVlbkhlaWdodDtcbiAgICBjb25zdCBzaG90QVIgPSBzaG90V2lkdGggLyBzaG90SGVpZ2h0O1xuICAgIGlmIChNYXRoLnJvdW5kKHNjcmVlbkFSICogRkxPQVRfUFJFQ0lTSU9OKSA9PT0gTWF0aC5yb3VuZChzaG90QVIgKiBGTE9BVF9QUkVDSVNJT04pKSB7XG4gICAgICBsb2cuaW5mbyhgU2NyZWVuc2hvdCBhc3BlY3QgcmF0aW8gJyR7c2hvdEFSfScgKCR7c2hvdFdpZHRofXgke3Nob3RIZWlnaHR9KSBtYXRjaGVkIGAgK1xuICAgICAgICBgc2NyZWVuIGFzcGVjdCByYXRpbyAnJHtzY3JlZW5BUn0nICgke3NjcmVlbldpZHRofXgke3NjcmVlbkhlaWdodH0pYCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGxvZy53YXJuKGBXaGVuIHRyeWluZyB0byBmaW5kIGFuIGVsZW1lbnQsIGRldGVybWluZWQgdGhhdCB0aGUgc2NyZWVuIGAgK1xuICAgICAgICAgICAgICAgYGFzcGVjdCByYXRpbyBhbmQgc2NyZWVuc2hvdCBhc3BlY3QgcmF0aW8gYXJlIGRpZmZlcmVudC4gU2NyZWVuIGAgK1xuICAgICAgICAgICAgICAgYGlzICR7c2NyZWVuV2lkdGh9eCR7c2NyZWVuSGVpZ2h0fSB3aGVyZWFzIHNjcmVlbnNob3QgaXMgYCArXG4gICAgICAgICAgICAgICBgJHtzaG90V2lkdGh9eCR7c2hvdEhlaWdodH0uYCk7XG5cbiAgICAgIC8vIEluIHRoZSBjYXNlIHdoZXJlIHRoZSB4LXNjYWxlIGFuZCB5LXNjYWxlIGFyZSBkaWZmZXJlbnQsIHdlIG5lZWQgdG8gZGVjaWRlXG4gICAgICAvLyB3aGljaCBvbmUgdG8gcmVzcGVjdCwgb3RoZXJ3aXNlIHRoZSBzY3JlZW5zaG90IGFuZCB0ZW1wbGF0ZSB3aWxsIGVuZCB1cFxuICAgICAgLy8gYmVpbmcgcmVzaXplZCBpbiBhIHdheSB0aGF0IGNoYW5nZXMgaXRzIGFzcGVjdCByYXRpbyAoZGlzdG9ydHMgaXQpLiBGb3IgZXhhbXBsZSwgbGV0J3Mgc2F5OlxuICAgICAgLy8gdGhpcy5nZXRTY3JlZW5zaG90KHNob3RXaWR0aCwgc2hvdEhlaWdodCkgaXMgNTQweDM5NyxcbiAgICAgIC8vIHRoaXMuZ2V0RGV2aWNlU2l6ZShzY3JlZW5XaWR0aCwgc2NyZWVuSGVpZ2h0KSBpcyAxMDgweDE5MjAuXG4gICAgICAvLyBUaGUgcmF0aW8gd291bGQgdGhlbiBiZSB7eFNjYWxlOiAwLjUsIHlTY2FsZTogMC4yfS5cbiAgICAgIC8vIEluIHRoaXMgY2FzZSwgd2UgbXVzdCBzaG91bGQgYHlTY2FsZTogMC4yYCBhcyBzY2FsZUZhY3RvciwgYmVjYXVzZVxuICAgICAgLy8gaWYgd2Ugc2VsZWN0IHRoZSB4U2NhbGUsIHRoZSBoZWlnaHQgd2lsbCBiZSBiaWdnZXIgdGhhbiByZWFsIHNjcmVlbnNob3Qgc2l6ZVxuICAgICAgLy8gd2hpY2ggaXMgdXNlZCB0byBpbWFnZSBjb21wYXJpc29uIGJ5IE9wZW5DViBhcyBhIGJhc2UgaW1hZ2UuXG4gICAgICAvLyBBbGwgb2YgdGhpcyBpcyBwcmltYXJpbHkgdXNlZnVsIHdoZW4gdGhlIHNjcmVlbnNob3QgaXMgYSBob3Jpem9udGFsIHNsaWNlIHRha2VuIG91dCBvZiB0aGVcbiAgICAgIC8vIHNjcmVlbiAoZm9yIGV4YW1wbGUgbm90IGluY2x1ZGluZyB0b3AvYm90dG9tIG5hdiBiYXJzKVxuICAgICAgY29uc3QgeFNjYWxlID0gKDEuMCAqIHNob3RXaWR0aCkgLyBzY3JlZW5XaWR0aDtcbiAgICAgIGNvbnN0IHlTY2FsZSA9ICgxLjAgKiBzaG90SGVpZ2h0KSAvIHNjcmVlbkhlaWdodDtcbiAgICAgIGNvbnN0IHNjYWxlRmFjdG9yID0geFNjYWxlID49IHlTY2FsZSA/IHlTY2FsZSA6IHhTY2FsZTtcblxuICAgICAgbG9nLndhcm4oYFJlc2l6aW5nIHNjcmVlbnNob3QgdG8gJHtzaG90V2lkdGggKiBzY2FsZUZhY3Rvcn14JHtzaG90SGVpZ2h0ICogc2NhbGVGYWN0b3J9IHRvIG1hdGNoIGAgK1xuICAgICAgICAgICAgICAgYHNjcmVlbiBhc3BlY3QgcmF0aW8gc28gdGhhdCBpbWFnZSBlbGVtZW50IGNvb3JkaW5hdGVzIGhhdmUgYSBgICtcbiAgICAgICAgICAgICAgIGBncmVhdGVyIGNoYW5jZSBvZiBiZWluZyBjb3JyZWN0LmApO1xuICAgICAgaW1nT2JqID0gaW1nT2JqLnJlc2l6ZShzaG90V2lkdGggKiBzY2FsZUZhY3Rvciwgc2hvdEhlaWdodCAqIHNjYWxlRmFjdG9yKTtcblxuICAgICAgc2NhbGUueFNjYWxlICo9IHNjYWxlRmFjdG9yO1xuICAgICAgc2NhbGUueVNjYWxlICo9IHNjYWxlRmFjdG9yO1xuXG4gICAgICBzaG90V2lkdGggPSBpbWdPYmouYml0bWFwLndpZHRoO1xuICAgICAgc2hvdEhlaWdodCA9IGltZ09iai5iaXRtYXAuaGVpZ2h0O1xuICAgIH1cblxuICAgIC8vIFJlc2l6ZSBiYXNlZCBvbiB0aGUgc2NyZWVuIGRpbWVuc2lvbnMgb25seSBpZiBib3RoIHdpZHRoIGFuZCBoZWlnaHQgYXJlIG1pc21hdGNoZWRcbiAgICAvLyBzaW5jZSBleGNlcHQgZm9yIHRoYXQsIGl0IG1pZ2h0IGJlIGEgc2l0dWF0aW9uIHdoaWNoIGlzIGRpZmZlcmVudCB3aW5kb3cgcmVjdCBhbmRcbiAgICAvLyBzY3JlZW5zaG90IHNpemUgbGlrZSBgQGRyaXZlci53aW5kb3dfcmVjdCAjPT54PTAsIHk9MCwgd2lkdGg9MTA4MCwgaGVpZ2h0PTE3OTRgIGFuZFxuICAgIC8vIGBcImRldmljZVNjcmVlblNpemVcIj0+XCIxMDgweDE5MjBcImBcbiAgICBpZiAoc2NyZWVuV2lkdGggIT09IHNob3RXaWR0aCAmJiBzY3JlZW5IZWlnaHQgIT09IHNob3RIZWlnaHQpIHtcbiAgICAgIGxvZy5pbmZvKGBTY2FsaW5nIHNjcmVlbnNob3QgZnJvbSAke3Nob3RXaWR0aH14JHtzaG90SGVpZ2h0fSB0byBtYXRjaCBgICtcbiAgICAgICAgICAgICAgIGBzY3JlZW4gYXQgJHtzY3JlZW5XaWR0aH14JHtzY3JlZW5IZWlnaHR9YCk7XG4gICAgICBpbWdPYmogPSBpbWdPYmoucmVzaXplKHNjcmVlbldpZHRoLCBzY3JlZW5IZWlnaHQpO1xuXG4gICAgICBzY2FsZS54U2NhbGUgKj0gKDEuMCAqIHNjcmVlbldpZHRoKSAvIHNob3RXaWR0aDtcbiAgICAgIHNjYWxlLnlTY2FsZSAqPSAoMS4wICogc2NyZWVuSGVpZ2h0KSAvIHNob3RIZWlnaHQ7XG4gICAgfVxuXG4gICAgYjY0U2NyZWVuc2hvdCA9IChhd2FpdCBpbWdPYmouZ2V0QnVmZmVyKGltYWdlVXRpbC5NSU1FX1BORykpLnRvU3RyaW5nKCdiYXNlNjQnKTtcbiAgICByZXR1cm4ge2I2NFNjcmVlbnNob3QsIHNjYWxlfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAdHlwZWRlZiBJbWFnZVRlbXBsYXRlU2V0dGluZ3NcbiAgICogQHByb3BlcnR5IHtib29sZWFufSBmaXhJbWFnZVRlbXBsYXRlU2NhbGUgLSBmaXhJbWFnZVRlbXBsYXRlU2NhbGUgaW4gZGV2aWNlLXNldHRpbmdzXG4gICAqIEBwcm9wZXJ0eSB7ZmxvYXR9IGRlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGUgLSBkZWZhdWx0SW1hZ2VUZW1wbGF0ZVNjYWxlIGluIGRldmljZS1zZXR0aW5nc1xuICAgKiBAcHJvcGVydHkge2Jvb2xlYW59IGlnbm9yZURlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGUgLSBJZ25vcmUgZGVmYXVsdEltYWdlVGVtcGxhdGVTY2FsZSBpZiBpdCBoYXMgdHJ1ZS5cbiAgICogSWYgYjY0VGVtcGxhdGUgaGFzIGJlZW4gc2NhbGVkIHRvIGRlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGUgb3Igc2hvdWxkIGlnbm9yZSB0aGUgc2NhbGUsXG4gICAqIHRoaXMgcGFyYW1ldGVyIHNob3VsZCBiZSB0cnVlLiBlLmcuIGNsaWNrIGluIGltYWdlLWVsZW1lbnQgbW9kdWxlXG4gICAqIEBwcm9wZXJ0eSB7ZmxvYXR9IHhTY2FsZSAtIFNjYWxlIHJhdGlvIGZvciB3aWR0aFxuICAgKiBAcHJvcGVydHkge2Zsb2F0fSB5U2NhbGUgLSBTY2FsZSByYXRpbyBmb3IgaGVpZ2h0XG5cbiAgICovXG4gIC8qKlxuICAgKiBHZXQgYSBpbWFnZSB0aGF0IHdpbGwgYmUgdXNlZCBmb3IgdGVtcGxhdGUgbWFjaGluZy5cbiAgICogUmV0dXJucyBzY2FsZWQgaW1hZ2UgaWYgc2NhbGUgcmF0aW8gaXMgcHJvdmlkZWQuXG4gICAqXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBiNjRUZW1wbGF0ZSAtIGJhc2U2NC1lbmNvZGVkIGltYWdlIHVzZWQgYXMgYSB0ZW1wbGF0ZSB0byBiZVxuICAgKiBtYXRjaGVkIGluIHRoZSBzY3JlZW5zaG90XG4gICAqIEBwYXJhbSB7SW1hZ2VUZW1wbGF0ZVNldHRpbmdzfSBvcHRzIC0gSW1hZ2UgdGVtcGxhdGUgc2NhbGUgcmVsYXRlZCBvcHRpb25zXG4gICAqXG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IGJhc2U2NC1lbmNvZGVkIHNjYWxlZCB0ZW1wbGF0ZSBzY3JlZW5zaG90XG4gICAqL1xuICBhc3luYyBmaXhJbWFnZVRlbXBsYXRlU2NhbGUgKGI2NFRlbXBsYXRlLCBvcHRzID0ge30pIHtcbiAgICBpZiAoIW9wdHMpIHtcbiAgICAgIHJldHVybiBiNjRUZW1wbGF0ZTtcbiAgICB9XG5cbiAgICBsZXQge1xuICAgICAgZml4SW1hZ2VUZW1wbGF0ZVNjYWxlID0gZmFsc2UsXG4gICAgICBkZWZhdWx0SW1hZ2VUZW1wbGF0ZVNjYWxlID0gREVGQVVMVF9URU1QTEFURV9JTUFHRV9TQ0FMRSxcbiAgICAgIGlnbm9yZURlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGUgPSBmYWxzZSxcbiAgICAgIHhTY2FsZSA9IERFRkFVTFRfRklYX0lNQUdFX1RFTVBMQVRFX1NDQUxFLFxuICAgICAgeVNjYWxlID0gREVGQVVMVF9GSVhfSU1BR0VfVEVNUExBVEVfU0NBTEVcbiAgICB9ID0gb3B0cztcblxuICAgIGlmIChpZ25vcmVEZWZhdWx0SW1hZ2VUZW1wbGF0ZVNjYWxlKSB7XG4gICAgICBkZWZhdWx0SW1hZ2VUZW1wbGF0ZVNjYWxlID0gREVGQVVMVF9URU1QTEFURV9JTUFHRV9TQ0FMRTtcbiAgICB9XG5cbiAgICAvLyBEZWZhdWx0XG4gICAgaWYgKGRlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGUgPT09IERFRkFVTFRfVEVNUExBVEVfSU1BR0VfU0NBTEUgJiYgIWZpeEltYWdlVGVtcGxhdGVTY2FsZSkge1xuICAgICAgcmV0dXJuIGI2NFRlbXBsYXRlO1xuICAgIH1cblxuICAgIC8vIENhbGN1bGF0ZSB4U2NhbGUgYW5kIHlTY2FsZSBBcHBpdW0gc2hvdWxkIHNjYWxlXG4gICAgaWYgKGZpeEltYWdlVGVtcGxhdGVTY2FsZSkge1xuICAgICAgeFNjYWxlICo9IGRlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGU7XG4gICAgICB5U2NhbGUgKj0gZGVmYXVsdEltYWdlVGVtcGxhdGVTY2FsZTtcbiAgICB9IGVsc2Uge1xuICAgICAgeFNjYWxlID0geVNjYWxlID0gMSAqIGRlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGU7XG4gICAgfVxuXG4gICAgLy8geFNjYWxlIGFuZCB5U2NhbGUgY2FuIGJlIE5hTiBpZiBkZWZhdWx0SW1hZ2VUZW1wbGF0ZVNjYWxlIGlzIHN0cmluZywgZm9yIGV4YW1wbGVcbiAgICBpZiAoIXBhcnNlRmxvYXQoeFNjYWxlKSB8fCAhcGFyc2VGbG9hdCh5U2NhbGUpKSB7XG4gICAgICByZXR1cm4gYjY0VGVtcGxhdGU7XG4gICAgfVxuXG4gICAgLy8gUmV0dXJuIGlmIHRoZSBzY2FsZSBpcyBkZWZhdWx0LCAxLCB2YWx1ZVxuICAgIGlmIChNYXRoLnJvdW5kKHhTY2FsZSAqIEZMT0FUX1BSRUNJU0lPTikgPT09IE1hdGgucm91bmQoREVGQVVMVF9GSVhfSU1BR0VfVEVNUExBVEVfU0NBTEUgKiBGTE9BVF9QUkVDSVNJT04pXG4gICAgICAgICYmIE1hdGgucm91bmQoeVNjYWxlICogRkxPQVRfUFJFQ0lTSU9OID09PSBNYXRoLnJvdW5kKERFRkFVTFRfRklYX0lNQUdFX1RFTVBMQVRFX1NDQUxFICogRkxPQVRfUFJFQ0lTSU9OKSkpIHtcbiAgICAgIHJldHVybiBiNjRUZW1wbGF0ZTtcbiAgICB9XG5cbiAgICBsZXQgaW1nVGVtcE9iaiA9IGF3YWl0IGltYWdlVXRpbC5nZXRKaW1wSW1hZ2UoYjY0VGVtcGxhdGUpO1xuICAgIGxldCB7d2lkdGg6IGJhc2VUZW1wV2lkdGgsIGhlaWdodDogYmFzZVRlbXBIZWlnaH0gPSBpbWdUZW1wT2JqLmJpdG1hcDtcblxuICAgIGNvbnN0IHNjYWxlZFdpZHRoID0gYmFzZVRlbXBXaWR0aCAqIHhTY2FsZTtcbiAgICBjb25zdCBzY2FsZWRIZWlnaHQgPSBiYXNlVGVtcEhlaWdoICogeVNjYWxlO1xuICAgIGxvZy5pbmZvKGBTY2FsaW5nIHRlbXBsYXRlIGltYWdlIGZyb20gJHtiYXNlVGVtcFdpZHRofXgke2Jhc2VUZW1wSGVpZ2h9YCArXG4gICAgICAgICAgICAgIGAgdG8gJHtzY2FsZWRXaWR0aH14JHtzY2FsZWRIZWlnaHR9YCk7XG4gICAgbG9nLmluZm8oYFRoZSByYXRpbyBpcyAke3hTY2FsZX0gYW5kICR7eVNjYWxlfWApO1xuICAgIGltZ1RlbXBPYmogPSBhd2FpdCBpbWdUZW1wT2JqLnJlc2l6ZShzY2FsZWRXaWR0aCwgc2NhbGVkSGVpZ2h0KTtcbiAgICByZXR1cm4gKGF3YWl0IGltZ1RlbXBPYmouZ2V0QnVmZmVyKGltYWdlVXRpbC5NSU1FX1BORykpLnRvU3RyaW5nKCdiYXNlNjQnKTtcbiAgfVxufVxuXG5leHBvcnQgeyBXM0NfRUxFTUVOVF9LRVksIE1KU09OV1BfRUxFTUVOVF9LRVksIERFRkFVTFRfU0VUVElOR1MsIERFRkFVTFRfRklYX0lNQUdFX1RFTVBMQVRFX1NDQUxFIH07XG4iXX0=
|