@appium/images-plugin 1.1.4 → 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.
@@ -1,384 +1,342 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
- Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.DEFAULT_FIX_IMAGE_TEMPLATE_SCALE = exports.DEFAULT_SETTINGS = exports.MJSONWP_ELEMENT_KEY = exports.W3C_ELEMENT_KEY = void 0;
16
- const lru_cache_1 = __importDefault(require("lru-cache"));
17
- const appium_support_1 = require("appium-support");
18
- const appium_base_driver_1 = require("appium-base-driver");
19
- const image_element_1 = require("./image-element");
20
- const compare_1 = require("./compare");
21
- const logger_1 = __importDefault(require("./logger"));
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 = appium_support_1.util.W3C_WEB_ELEMENT_IDENTIFIER;
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; // 40mb
33
+ const MAX_CACHE_SIZE = 1024 * 1024 * 40;
32
34
  const DEFAULT_SETTINGS = {
33
- // value between 0 and 1 representing match strength, below which an image
34
- // element will not be found
35
- imageMatchThreshold: compare_1.DEFAULT_MATCH_THRESHOLD,
36
- // if the image returned by getScreenshot differs in size or aspect ratio
37
- // from the screen, attempt to fix it automatically
38
- fixImageFindScreenshotDims: true,
39
- // whether Appium should ensure that an image template sent in during image
40
- // element find should have its size adjusted so the match algorithm will not
41
- // complain
42
- fixImageTemplateSize: false,
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
- constructor(driver, max = MAX_CACHE_SIZE) {
73
- this.driver = driver;
74
- this.imgElCache = new lru_cache_1.default({
75
- max,
76
- length: (el) => el.template.length,
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
- setDriver(driver) {
80
- this.driver = driver;
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
- registerImageElement(imgEl) {
83
- this.imgElCache.set(imgEl.id, imgEl);
84
- const protoKey = this.driver.isW3CProtocol() ? W3C_ELEMENT_KEY : MJSONWP_ELEMENT_KEY;
85
- return imgEl.asElement(protoKey);
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
- * @typedef {Object} FindByImageOptions
89
- * @property {boolean} [shouldCheckStaleness=false] - whether this call to find an
90
- * image is merely to check staleness. If so we can bypass a lot of logic
91
- * @property {boolean} [multiple=false] - Whether we are finding one element or
92
- * multiple
93
- * @property {boolean} [ignoreDefaultImageTemplateScale=false] - Whether we
94
- * ignore defaultImageTemplateScale. It can be used when you would like to
95
- * scale b64Template with defaultImageTemplateScale setting.
96
- */
97
- /**
98
- * Find a screen rect represented by an ImageElement corresponding to an image
99
- * template sent in by the client
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
- * Ensure that the image template sent in for a find is of a suitable size
188
- *
189
- * @param {string} b64Template - base64-encoded image
190
- * @param {int} screenWidth - width of screen
191
- * @param {int} screenHeight - height of screen
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
- * @typedef {Object} Screenshot
213
- * @property {string} b64Screenshot - base64 based screenshot string
214
- */
215
- /**
216
- * @typedef {Object} ScreenshotScale
217
- * @property {float} xScale - Scale ratio for width
218
- * @property {float} yScale - Scale ratio for height
219
- */
220
- /**
221
- * Get the screenshot image that will be used for find by element, potentially
222
- * altering it in various ways based on user-requested settings
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
- * @typedef {Object} ImageTemplateSettings
321
- * @property {boolean} fixImageTemplateScale - fixImageTemplateScale in device-settings
322
- * @property {float} defaultImageTemplateScale - defaultImageTemplateScale in device-settings
323
- * @property {boolean} ignoreDefaultImageTemplateScale - Ignore defaultImageTemplateScale if it has true.
324
- * If b64Template has been scaled to defaultImageTemplateScale or should ignore the scale,
325
- * this parameter should be true. e.g. click in image-element module
326
- * @property {float} xScale - Scale ratio for width
327
- * @property {float} yScale - Scale ratio for height
328
-
329
- */
330
- /**
331
- * Get a image that will be used for template maching.
332
- * Returns scaled image if scale ratio is provided.
333
- *
334
- *
335
- * @param {string} b64Template - base64-encoded image used as a template to be
336
- * matched in the screenshot
337
- * @param {ImageTemplateSettings} opts - Image template scale related options
338
- *
339
- * @returns {string} base64-encoded scaled template screenshot
340
- */
341
- fixImageTemplateScale(b64Template, opts = {}) {
342
- return __awaiter(this, void 0, void 0, function* () {
343
- if (!opts) {
344
- return b64Template;
345
- }
346
- let { fixImageTemplateScale = false, defaultImageTemplateScale = image_element_1.DEFAULT_TEMPLATE_IMAGE_SCALE, ignoreDefaultImageTemplateScale = false, xScale = DEFAULT_FIX_IMAGE_TEMPLATE_SCALE, yScale = DEFAULT_FIX_IMAGE_TEMPLATE_SCALE } = opts;
347
- if (ignoreDefaultImageTemplateScale) {
348
- defaultImageTemplateScale = image_element_1.DEFAULT_TEMPLATE_IMAGE_SCALE;
349
- }
350
- // Default
351
- if (defaultImageTemplateScale === image_element_1.DEFAULT_TEMPLATE_IMAGE_SCALE && !fixImageTemplateScale) {
352
- return b64Template;
353
- }
354
- // Calculate xScale and yScale Appium should scale
355
- if (fixImageTemplateScale) {
356
- xScale *= defaultImageTemplateScale;
357
- yScale *= defaultImageTemplateScale;
358
- }
359
- else {
360
- xScale = yScale = 1 * defaultImageTemplateScale;
361
- }
362
- // xScale and yScale can be NaN if defaultImageTemplateScale is string, for example
363
- if (!parseFloat(xScale) || !parseFloat(yScale)) {
364
- return b64Template;
365
- }
366
- // Return if the scale is default, 1, value
367
- if (Math.round(xScale * FLOAT_PRECISION) === Math.round(DEFAULT_FIX_IMAGE_TEMPLATE_SCALE * FLOAT_PRECISION)
368
- && Math.round(yScale * FLOAT_PRECISION === Math.round(DEFAULT_FIX_IMAGE_TEMPLATE_SCALE * FLOAT_PRECISION))) {
369
- return b64Template;
370
- }
371
- let imgTempObj = yield appium_support_1.imageUtil.getJimpImage(b64Template);
372
- let { width: baseTempWidth, height: baseTempHeigh } = imgTempObj.bitmap;
373
- const scaledWidth = baseTempWidth * xScale;
374
- const scaledHeight = baseTempHeigh * yScale;
375
- logger_1.default.info(`Scaling template image from ${baseTempWidth}x${baseTempHeigh}` +
376
- ` to ${scaledWidth}x${scaledHeight}`);
377
- logger_1.default.info(`The ratio is ${xScale} and ${yScale}`);
378
- imgTempObj = yield imgTempObj.resize(scaledWidth, scaledHeight);
379
- return (yield imgTempObj.getBuffer(appium_support_1.imageUtil.MIME_PNG)).toString('base64');
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,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL2xpYi9maW5kZXIuanMiXSwibmFtZXMiOlsiTUpTT05XUF9FTEVNRU5UX0tFWSIsIlczQ19FTEVNRU5UX0tFWSIsInV0aWwiLCJXM0NfV0VCX0VMRU1FTlRfSURFTlRJRklFUiIsIkRFRkFVTFRfRklYX0lNQUdFX1RFTVBMQVRFX1NDQUxFIiwiRkxPQVRfUFJFQ0lTSU9OIiwiTUFYX0NBQ0hFX1NJWkUiLCJERUZBVUxUX1NFVFRJTkdTIiwiaW1hZ2VNYXRjaFRocmVzaG9sZCIsIkRFRkFVTFRfTUFUQ0hfVEhSRVNIT0xEIiwiaW1hZ2VNYXRjaE1ldGhvZCIsImZpeEltYWdlRmluZFNjcmVlbnNob3REaW1zIiwiZml4SW1hZ2VUZW1wbGF0ZVNpemUiLCJmaXhJbWFnZVRlbXBsYXRlU2NhbGUiLCJkZWZhdWx0SW1hZ2VUZW1wbGF0ZVNjYWxlIiwiREVGQVVMVF9URU1QTEFURV9JTUFHRV9TQ0FMRSIsImNoZWNrRm9ySW1hZ2VFbGVtZW50U3RhbGVuZXNzIiwiYXV0b1VwZGF0ZUltYWdlRWxlbWVudFBvc2l0aW9uIiwiaW1hZ2VFbGVtZW50VGFwU3RyYXRlZ3kiLCJJTUFHRV9FTF9UQVBfU1RSQVRFR1lfVzNDIiwiZ2V0TWF0Y2hlZEltYWdlUmVzdWx0IiwiSW1hZ2VFbGVtZW50RmluZGVyIiwiY29uc3RydWN0b3IiLCJkcml2ZXIiLCJtYXgiLCJpbWdFbENhY2hlIiwiTFJVIiwibGVuZ3RoIiwiZWwiLCJ0ZW1wbGF0ZSIsInNldERyaXZlciIsInJlZ2lzdGVySW1hZ2VFbGVtZW50IiwiaW1nRWwiLCJzZXQiLCJpZCIsInByb3RvS2V5IiwiaXNXM0NQcm90b2NvbCIsImFzRWxlbWVudCIsImZpbmRCeUltYWdlIiwiYjY0VGVtcGxhdGUiLCJzaG91bGRDaGVja1N0YWxlbmVzcyIsIm11bHRpcGxlIiwiaWdub3JlRGVmYXVsdEltYWdlVGVtcGxhdGVTY2FsZSIsIkVycm9yIiwic2V0dGluZ3MiLCJnZXRTZXR0aW5ncyIsInRocmVzaG9sZCIsInZpc3VhbGl6ZSIsImxvZyIsImluZm8iLCJnZXRXaW5kb3dTaXplIiwid2lkdGgiLCJzY3JlZW5XaWR0aCIsImhlaWdodCIsInNjcmVlbkhlaWdodCIsImVuc3VyZVRlbXBsYXRlU2l6ZSIsInJlc3VsdHMiLCJjb25kaXRpb24iLCJiNjRTY3JlZW5zaG90Iiwic2NhbGUiLCJnZXRTY3JlZW5zaG90Rm9ySW1hZ2VGaW5kIiwiY29tcGFyaXNvbk9wdHMiLCJtZXRob2QiLCJwdXNoIiwiTUFUQ0hfVEVNUExBVEVfTU9ERSIsImVyciIsIm1lc3NhZ2UiLCJtYXRjaCIsImltcGxpY2l0V2FpdEZvckNvbmRpdGlvbiIsIl8iLCJpc0VtcHR5IiwiZXJyb3JzIiwiTm9TdWNoRWxlbWVudEVycm9yIiwiZWxlbWVudHMiLCJtYXAiLCJyZWN0Iiwic2NvcmUiLCJ2aXN1YWxpemF0aW9uIiwiSlNPTiIsInN0cmluZ2lmeSIsIkltYWdlRWxlbWVudCIsInJlZ2lzdGVyZWRFbGVtZW50cyIsImltZ09iaiIsImltYWdlVXRpbCIsImdldEppbXBJbWFnZSIsInRwbFdpZHRoIiwidHBsSGVpZ2h0IiwiYml0bWFwIiwic2NhbGVUb0ZpdCIsImdldEJ1ZmZlciIsIk1JTUVfUE5HIiwidG9TdHJpbmciLCJnZXRTY3JlZW5zaG90IiwiT2JqZWN0IiwiYXNzaWduIiwid2FybiIsInNob3RXaWR0aCIsInNob3RIZWlnaHQiLCJ4U2NhbGUiLCJ5U2NhbGUiLCJzY3JlZW5BUiIsInNob3RBUiIsIk1hdGgiLCJyb3VuZCIsInNjYWxlRmFjdG9yIiwicmVzaXplIiwib3B0cyIsInBhcnNlRmxvYXQiLCJpbWdUZW1wT2JqIiwiYmFzZVRlbXBXaWR0aCIsImJhc2VUZW1wSGVpZ2giLCJzY2FsZWRXaWR0aCIsInNjYWxlZEhlaWdodCJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7QUFBQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFFQTs7QUFDQTs7QUFFQSxNQUFNQSxtQkFBbUIsR0FBRyxTQUE1Qjs7QUFDQSxNQUFNQyxlQUFlLEdBQUdDLGNBQUtDLDBCQUE3Qjs7QUFDQSxNQUFNQyxnQ0FBZ0MsR0FBRyxDQUF6Qzs7QUFHQSxNQUFNQyxlQUFlLEdBQUcsTUFBeEI7QUFDQSxNQUFNQyxjQUFjLEdBQUcsT0FBTyxJQUFQLEdBQWMsRUFBckM7QUFFQSxNQUFNQyxnQkFBZ0IsR0FBRztBQUd2QkMsRUFBQUEsbUJBQW1CLEVBQUVDLGdDQUhFO0FBU3ZCQyxFQUFBQSxnQkFBZ0IsRUFBRSxFQVRLO0FBYXZCQyxFQUFBQSwwQkFBMEIsRUFBRSxJQWJMO0FBa0J2QkMsRUFBQUEsb0JBQW9CLEVBQUUsS0FsQkM7QUEwQnZCQyxFQUFBQSxxQkFBcUIsRUFBRSxLQTFCQTtBQWtDdkJDLEVBQUFBLHlCQUF5QixFQUFFQywwQ0FsQ0o7QUFzQ3ZCQyxFQUFBQSw2QkFBNkIsRUFBRSxJQXRDUjtBQTBDdkJDLEVBQUFBLDhCQUE4QixFQUFFLEtBMUNUO0FBOEN2QkMsRUFBQUEsdUJBQXVCLEVBQUVDLHVDQTlDRjtBQWtEdkJDLEVBQUFBLHFCQUFxQixFQUFFO0FBbERBLENBQXpCOzs7QUFxRGUsTUFBTUMsa0JBQU4sQ0FBeUI7QUFDdENDLEVBQUFBLFdBQVcsQ0FBRUMsTUFBRixFQUFVQyxHQUFHLEdBQUdsQixjQUFoQixFQUFnQztBQUN6QyxTQUFLaUIsTUFBTCxHQUFjQSxNQUFkO0FBQ0EsU0FBS0UsVUFBTCxHQUFrQixJQUFJQyxpQkFBSixDQUFRO0FBQ3hCRixNQUFBQSxHQUR3QjtBQUV4QkcsTUFBQUEsTUFBTSxFQUFHQyxFQUFELElBQVFBLEVBQUUsQ0FBQ0MsUUFBSCxDQUFZRjtBQUZKLEtBQVIsQ0FBbEI7QUFJRDs7QUFFREcsRUFBQUEsU0FBUyxDQUFFUCxNQUFGLEVBQVU7QUFDakIsU0FBS0EsTUFBTCxHQUFjQSxNQUFkO0FBQ0Q7O0FBRURRLEVBQUFBLG9CQUFvQixDQUFFQyxLQUFGLEVBQVM7QUFDM0IsU0FBS1AsVUFBTCxDQUFnQlEsR0FBaEIsQ0FBb0JELEtBQUssQ0FBQ0UsRUFBMUIsRUFBOEJGLEtBQTlCO0FBQ0EsVUFBTUcsUUFBUSxHQUFHLEtBQUtaLE1BQUwsQ0FBWWEsYUFBWixLQUE4Qm5DLGVBQTlCLEdBQWdERCxtQkFBakU7QUFDQSxXQUFPZ0MsS0FBSyxDQUFDSyxTQUFOLENBQWdCRixRQUFoQixDQUFQO0FBQ0Q7O0FBdUJnQixRQUFYRyxXQUFXLENBQUVDLFdBQUYsRUFBZTtBQUM5QkMsSUFBQUEsb0JBQW9CLEdBQUcsS0FETztBQUU5QkMsSUFBQUEsUUFBUSxHQUFHLEtBRm1CO0FBRzlCQyxJQUFBQSwrQkFBK0IsR0FBRztBQUhKLEdBQWYsRUFJZDtBQUNELFFBQUksQ0FBQyxLQUFLbkIsTUFBVixFQUFrQjtBQUNoQixZQUFNLElBQUlvQixLQUFKLENBQVcsOEJBQVgsQ0FBTjtBQUNEOztBQUNELFVBQU1DLFFBQVEsR0FBRyxFQUFDLEdBQUdyQyxnQkFBSjtBQUFzQixTQUFHLEtBQUtnQixNQUFMLENBQVlxQixRQUFaLENBQXFCQyxXQUFyQjtBQUF6QixLQUFqQjtBQUNBLFVBQU07QUFDSnJDLE1BQUFBLG1CQUFtQixFQUFFc0MsU0FEakI7QUFFSnBDLE1BQUFBLGdCQUZJO0FBR0pFLE1BQUFBLG9CQUhJO0FBSUpDLE1BQUFBLHFCQUpJO0FBS0pDLE1BQUFBLHlCQUxJO0FBTUpNLE1BQUFBLHFCQUFxQixFQUFFMkI7QUFObkIsUUFPRkgsUUFQSjs7QUFTQUksb0JBQUlDLElBQUosQ0FBVSw4Q0FBNkNILFNBQVUsRUFBakU7O0FBQ0EsUUFBSSxDQUFDLEtBQUt2QixNQUFMLENBQVkyQixhQUFqQixFQUFnQztBQUM5QixZQUFNLElBQUlQLEtBQUosQ0FBVSxtRUFBVixDQUFOO0FBQ0Q7O0FBQ0QsVUFBTTtBQUFDUSxNQUFBQSxLQUFLLEVBQUVDLFdBQVI7QUFBcUJDLE1BQUFBLE1BQU0sRUFBRUM7QUFBN0IsUUFBNkMsTUFBTSxLQUFLL0IsTUFBTCxDQUFZMkIsYUFBWixFQUF6RDs7QUFNQSxRQUFJdEMsb0JBQUosRUFBMEI7QUFDeEIyQixNQUFBQSxXQUFXLEdBQUcsTUFBTSxLQUFLZ0Isa0JBQUwsQ0FBd0JoQixXQUF4QixFQUFxQ2EsV0FBckMsRUFDbEJFLFlBRGtCLENBQXBCO0FBRUQ7O0FBRUQsVUFBTUUsT0FBTyxHQUFHLEVBQWhCOztBQUNBLFVBQU1DLFNBQVMsR0FBRyxZQUFZO0FBQzVCLFVBQUk7QUFDRixjQUFNO0FBQUNDLFVBQUFBLGFBQUQ7QUFBZ0JDLFVBQUFBO0FBQWhCLFlBQXlCLE1BQU0sS0FBS0MseUJBQUwsQ0FBK0JSLFdBQS9CLEVBQTRDRSxZQUE1QyxDQUFyQztBQUVBZixRQUFBQSxXQUFXLEdBQUcsTUFBTSxLQUFLMUIscUJBQUwsQ0FBMkIwQixXQUEzQixFQUF3QztBQUMxRHpCLFVBQUFBLHlCQUQwRDtBQUMvQjRCLFVBQUFBLCtCQUQrQjtBQUUxRDdCLFVBQUFBLHFCQUYwRDtBQUVuQyxhQUFHOEM7QUFGZ0MsU0FBeEMsQ0FBcEI7QUFLQSxjQUFNRSxjQUFjLEdBQUc7QUFDckJmLFVBQUFBLFNBRHFCO0FBRXJCQyxVQUFBQSxTQUZxQjtBQUdyQk4sVUFBQUE7QUFIcUIsU0FBdkI7O0FBS0EsWUFBSS9CLGdCQUFKLEVBQXNCO0FBQ3BCbUQsVUFBQUEsY0FBYyxDQUFDQyxNQUFmLEdBQXdCcEQsZ0JBQXhCO0FBQ0Q7O0FBQ0QsWUFBSStCLFFBQUosRUFBYztBQUNaZSxVQUFBQSxPQUFPLENBQUNPLElBQVIsQ0FBYSxJQUFJLE1BQU0sNEJBQWNDLDRCQUFkLEVBQ2NOLGFBRGQsRUFFY25CLFdBRmQsRUFHY3NCLGNBSGQsQ0FBVixDQUFiO0FBSUQsU0FMRCxNQUtPO0FBQ0xMLFVBQUFBLE9BQU8sQ0FBQ08sSUFBUixDQUFhLE1BQU0sNEJBQWNDLDRCQUFkLEVBQ2NOLGFBRGQsRUFFY25CLFdBRmQsRUFHY3NCLGNBSGQsQ0FBbkI7QUFJRDs7QUFDRCxlQUFPLElBQVA7QUFFRCxPQTdCRCxDQTZCRSxPQUFPSSxHQUFQLEVBQVk7QUFLWixZQUFJQSxHQUFHLENBQUNDLE9BQUosQ0FBWUMsS0FBWixDQUFrQiw2QkFBbEIsQ0FBSixFQUFzRDtBQUNwRCxpQkFBTyxLQUFQO0FBQ0Q7O0FBQ0QsY0FBTUYsR0FBTjtBQUNEO0FBQ0YsS0F4Q0Q7O0FBMENBLFFBQUk7QUFDRixZQUFNLEtBQUsxQyxNQUFMLENBQVk2Qyx3QkFBWixDQUFxQ1gsU0FBckMsQ0FBTjtBQUNELEtBRkQsQ0FFRSxPQUFPUSxHQUFQLEVBQVk7QUFPWixVQUFJLENBQUNBLEdBQUcsQ0FBQ0MsT0FBSixDQUFZQyxLQUFaLENBQWtCLGlCQUFsQixDQUFMLEVBQTJDO0FBQ3pDLGNBQU1GLEdBQU47QUFDRDtBQUNGOztBQUVELFFBQUlJLGdCQUFFQyxPQUFGLENBQVVkLE9BQVYsQ0FBSixFQUF3QjtBQUN0QixVQUFJZixRQUFKLEVBQWM7QUFDWixlQUFPLEVBQVA7QUFDRDs7QUFDRCxZQUFNLElBQUk4QixtQkFBT0Msa0JBQVgsRUFBTjtBQUNEOztBQUVELFVBQU1DLFFBQVEsR0FBR2pCLE9BQU8sQ0FBQ2tCLEdBQVIsQ0FBWSxDQUFDO0FBQUNDLE1BQUFBLElBQUQ7QUFBT0MsTUFBQUEsS0FBUDtBQUFjQyxNQUFBQTtBQUFkLEtBQUQsS0FBa0M7QUFDN0Q3QixzQkFBSUMsSUFBSixDQUFVLDJCQUEwQjZCLElBQUksQ0FBQ0MsU0FBTCxDQUFlSixJQUFmLENBQXFCLEVBQXpEOztBQUNBLGFBQU8sSUFBSUssMEJBQUosQ0FBaUJ6QyxXQUFqQixFQUE4Qm9DLElBQTlCLEVBQW9DQyxLQUFwQyxFQUEyQ0MsYUFBM0MsRUFBMEQsSUFBMUQsQ0FBUDtBQUNELEtBSGdCLENBQWpCOztBQVFBLFFBQUlyQyxvQkFBSixFQUEwQjtBQUN4QixhQUFPaUMsUUFBUSxDQUFDLENBQUQsQ0FBZjtBQUNEOztBQUVELFVBQU1RLGtCQUFrQixHQUFHUixRQUFRLENBQUNDLEdBQVQsQ0FBYzFDLEtBQUQsSUFBVyxLQUFLRCxvQkFBTCxDQUEwQkMsS0FBMUIsQ0FBeEIsQ0FBM0I7QUFFQSxXQUFPUyxRQUFRLEdBQUd3QyxrQkFBSCxHQUF3QkEsa0JBQWtCLENBQUMsQ0FBRCxDQUF6RDtBQUNEOztBQVd1QixRQUFsQjFCLGtCQUFrQixDQUFFaEIsV0FBRixFQUFlYSxXQUFmLEVBQTRCRSxZQUE1QixFQUEwQztBQUNoRSxRQUFJNEIsTUFBTSxHQUFHLE1BQU1DLG1CQUFVQyxZQUFWLENBQXVCN0MsV0FBdkIsQ0FBbkI7QUFDQSxRQUFJO0FBQUNZLE1BQUFBLEtBQUssRUFBRWtDLFFBQVI7QUFBa0JoQyxNQUFBQSxNQUFNLEVBQUVpQztBQUExQixRQUF1Q0osTUFBTSxDQUFDSyxNQUFsRDs7QUFFQXZDLG9CQUFJQyxJQUFKLENBQVUscUJBQW9Cb0MsUUFBUyxJQUFHQyxTQUFVLG9CQUFtQmxDLFdBQVksSUFBR0UsWUFBYSxFQUFuRzs7QUFFQSxRQUFJK0IsUUFBUSxJQUFJakMsV0FBWixJQUEyQmtDLFNBQVMsSUFBSWhDLFlBQTVDLEVBQTBEO0FBQ3hELGFBQU9mLFdBQVA7QUFDRDs7QUFFRFMsb0JBQUlDLElBQUosQ0FBVSwrQkFBOEJvQyxRQUFTLElBQUdDLFNBQVUsWUFBckQsR0FDQyxhQUFZbEMsV0FBWSxJQUFHRSxZQUFhLEVBRGxEOztBQUdBNEIsSUFBQUEsTUFBTSxHQUFHQSxNQUFNLENBQUNNLFVBQVAsQ0FBa0JwQyxXQUFsQixFQUErQkUsWUFBL0IsQ0FBVDtBQUNBLFdBQU8sQ0FBQyxNQUFNNEIsTUFBTSxDQUFDTyxTQUFQLENBQWlCTixtQkFBVU8sUUFBM0IsQ0FBUCxFQUE2Q0MsUUFBN0MsQ0FBc0QsUUFBdEQsQ0FBUDtBQUNEOztBQW9COEIsUUFBekIvQix5QkFBeUIsQ0FBRVIsV0FBRixFQUFlRSxZQUFmLEVBQTZCO0FBQzFELFFBQUksQ0FBQyxLQUFLL0IsTUFBTCxDQUFZcUUsYUFBakIsRUFBZ0M7QUFDOUIsWUFBTSxJQUFJakQsS0FBSixDQUFVLG1FQUFWLENBQU47QUFDRDs7QUFDRCxVQUFNQyxRQUFRLEdBQUdpRCxNQUFNLENBQUNDLE1BQVAsQ0FBYyxFQUFkLEVBQWtCdkYsZ0JBQWxCLEVBQW9DLEtBQUtnQixNQUFMLENBQVlxQixRQUFaLENBQXFCQyxXQUFyQixFQUFwQyxDQUFqQjtBQUNBLFVBQU07QUFBQ2xDLE1BQUFBO0FBQUQsUUFBK0JpQyxRQUFyQztBQUVBLFFBQUljLGFBQWEsR0FBRyxNQUFNLEtBQUtuQyxNQUFMLENBQVlxRSxhQUFaLEVBQTFCOztBQUlBLFFBQUksQ0FBQ2pGLDBCQUFMLEVBQWlDO0FBQy9CcUMsc0JBQUlDLElBQUosQ0FBVSxrREFBVjs7QUFDQSxhQUFPO0FBQUNTLFFBQUFBO0FBQUQsT0FBUDtBQUNEOztBQUVELFFBQUlOLFdBQVcsR0FBRyxDQUFkLElBQW1CRSxZQUFZLEdBQUcsQ0FBdEMsRUFBeUM7QUFDdkNOLHNCQUFJK0MsSUFBSixDQUFVLDZCQUE0QjNDLFdBQVksSUFBR0UsWUFBYSxRQUF6RCxHQUNOLG9FQURIOztBQUVBLGFBQU87QUFBQ0ksUUFBQUE7QUFBRCxPQUFQO0FBQ0Q7O0FBSURWLG9CQUFJQyxJQUFKLENBQVMsNENBQVQ7O0FBRUEsUUFBSWlDLE1BQU0sR0FBRyxNQUFNQyxtQkFBVUMsWUFBVixDQUF1QjFCLGFBQXZCLENBQW5CO0FBQ0EsUUFBSTtBQUFDUCxNQUFBQSxLQUFLLEVBQUU2QyxTQUFSO0FBQW1CM0MsTUFBQUEsTUFBTSxFQUFFNEM7QUFBM0IsUUFBeUNmLE1BQU0sQ0FBQ0ssTUFBcEQ7O0FBRUEsUUFBSVMsU0FBUyxHQUFHLENBQVosSUFBaUJDLFVBQVUsR0FBRyxDQUFsQyxFQUFxQztBQUNuQ2pELHNCQUFJK0MsSUFBSixDQUFVLGlDQUFnQ0MsU0FBVSxJQUFHQyxVQUFXLFFBQXpELEdBQ04sb0VBREg7O0FBRUEsYUFBTztBQUFDdkMsUUFBQUE7QUFBRCxPQUFQO0FBQ0Q7O0FBRUQsUUFBSU4sV0FBVyxLQUFLNEMsU0FBaEIsSUFBNkIxQyxZQUFZLEtBQUsyQyxVQUFsRCxFQUE4RDtBQUc1RGpELHNCQUFJQyxJQUFKLENBQVMscUNBQVQ7O0FBQ0EsYUFBTztBQUFDUyxRQUFBQTtBQUFELE9BQVA7QUFDRDs7QUFRRCxVQUFNQyxLQUFLLEdBQUc7QUFBQ3VDLE1BQUFBLE1BQU0sRUFBRSxHQUFUO0FBQWNDLE1BQUFBLE1BQU0sRUFBRTtBQUF0QixLQUFkO0FBRUEsVUFBTUMsUUFBUSxHQUFHaEQsV0FBVyxHQUFHRSxZQUEvQjtBQUNBLFVBQU0rQyxNQUFNLEdBQUdMLFNBQVMsR0FBR0MsVUFBM0I7O0FBQ0EsUUFBSUssSUFBSSxDQUFDQyxLQUFMLENBQVdILFFBQVEsR0FBRy9GLGVBQXRCLE1BQTJDaUcsSUFBSSxDQUFDQyxLQUFMLENBQVdGLE1BQU0sR0FBR2hHLGVBQXBCLENBQS9DLEVBQXFGO0FBQ25GMkMsc0JBQUlDLElBQUosQ0FBVSw0QkFBMkJvRCxNQUFPLE1BQUtMLFNBQVUsSUFBR0MsVUFBVyxZQUFoRSxHQUNOLHdCQUF1QkcsUUFBUyxNQUFLaEQsV0FBWSxJQUFHRSxZQUFhLEdBRHBFO0FBRUQsS0FIRCxNQUdPO0FBQ0xOLHNCQUFJK0MsSUFBSixDQUFVLDZEQUFELEdBQ0MsaUVBREQsR0FFQyxNQUFLM0MsV0FBWSxJQUFHRSxZQUFhLHlCQUZsQyxHQUdDLEdBQUUwQyxTQUFVLElBQUdDLFVBQVcsR0FIcEM7O0FBZ0JBLFlBQU1DLE1BQU0sR0FBSSxNQUFNRixTQUFQLEdBQW9CNUMsV0FBbkM7QUFDQSxZQUFNK0MsTUFBTSxHQUFJLE1BQU1GLFVBQVAsR0FBcUIzQyxZQUFwQztBQUNBLFlBQU1rRCxXQUFXLEdBQUdOLE1BQU0sSUFBSUMsTUFBVixHQUFtQkEsTUFBbkIsR0FBNEJELE1BQWhEOztBQUVBbEQsc0JBQUkrQyxJQUFKLENBQVUsMEJBQXlCQyxTQUFTLEdBQUdRLFdBQVksSUFBR1AsVUFBVSxHQUFHTyxXQUFZLFlBQTlFLEdBQ0MsK0RBREQsR0FFQyxrQ0FGVjs7QUFHQXRCLE1BQUFBLE1BQU0sR0FBR0EsTUFBTSxDQUFDdUIsTUFBUCxDQUFjVCxTQUFTLEdBQUdRLFdBQTFCLEVBQXVDUCxVQUFVLEdBQUdPLFdBQXBELENBQVQ7QUFFQTdDLE1BQUFBLEtBQUssQ0FBQ3VDLE1BQU4sSUFBZ0JNLFdBQWhCO0FBQ0E3QyxNQUFBQSxLQUFLLENBQUN3QyxNQUFOLElBQWdCSyxXQUFoQjtBQUVBUixNQUFBQSxTQUFTLEdBQUdkLE1BQU0sQ0FBQ0ssTUFBUCxDQUFjcEMsS0FBMUI7QUFDQThDLE1BQUFBLFVBQVUsR0FBR2YsTUFBTSxDQUFDSyxNQUFQLENBQWNsQyxNQUEzQjtBQUNEOztBQU1ELFFBQUlELFdBQVcsS0FBSzRDLFNBQWhCLElBQTZCMUMsWUFBWSxLQUFLMkMsVUFBbEQsRUFBOEQ7QUFDNURqRCxzQkFBSUMsSUFBSixDQUFVLDJCQUEwQitDLFNBQVUsSUFBR0MsVUFBVyxZQUFuRCxHQUNDLGFBQVk3QyxXQUFZLElBQUdFLFlBQWEsRUFEbEQ7O0FBRUE0QixNQUFBQSxNQUFNLEdBQUdBLE1BQU0sQ0FBQ3VCLE1BQVAsQ0FBY3JELFdBQWQsRUFBMkJFLFlBQTNCLENBQVQ7QUFFQUssTUFBQUEsS0FBSyxDQUFDdUMsTUFBTixJQUFpQixNQUFNOUMsV0FBUCxHQUFzQjRDLFNBQXRDO0FBQ0FyQyxNQUFBQSxLQUFLLENBQUN3QyxNQUFOLElBQWlCLE1BQU03QyxZQUFQLEdBQXVCMkMsVUFBdkM7QUFDRDs7QUFFRHZDLElBQUFBLGFBQWEsR0FBRyxDQUFDLE1BQU13QixNQUFNLENBQUNPLFNBQVAsQ0FBaUJOLG1CQUFVTyxRQUEzQixDQUFQLEVBQTZDQyxRQUE3QyxDQUFzRCxRQUF0RCxDQUFoQjtBQUNBLFdBQU87QUFBQ2pDLE1BQUFBLGFBQUQ7QUFBZ0JDLE1BQUFBO0FBQWhCLEtBQVA7QUFDRDs7QUF3QjBCLFFBQXJCOUMscUJBQXFCLENBQUUwQixXQUFGLEVBQWVtRSxJQUFJLEdBQUcsRUFBdEIsRUFBMEI7QUFDbkQsUUFBSSxDQUFDQSxJQUFMLEVBQVc7QUFDVCxhQUFPbkUsV0FBUDtBQUNEOztBQUVELFFBQUk7QUFDRjFCLE1BQUFBLHFCQUFxQixHQUFHLEtBRHRCO0FBRUZDLE1BQUFBLHlCQUF5QixHQUFHQywwQ0FGMUI7QUFHRjJCLE1BQUFBLCtCQUErQixHQUFHLEtBSGhDO0FBSUZ3RCxNQUFBQSxNQUFNLEdBQUc5RixnQ0FKUDtBQUtGK0YsTUFBQUEsTUFBTSxHQUFHL0Y7QUFMUCxRQU1Bc0csSUFOSjs7QUFRQSxRQUFJaEUsK0JBQUosRUFBcUM7QUFDbkM1QixNQUFBQSx5QkFBeUIsR0FBR0MsMENBQTVCO0FBQ0Q7O0FBR0QsUUFBSUQseUJBQXlCLEtBQUtDLDBDQUE5QixJQUE4RCxDQUFDRixxQkFBbkUsRUFBMEY7QUFDeEYsYUFBTzBCLFdBQVA7QUFDRDs7QUFHRCxRQUFJMUIscUJBQUosRUFBMkI7QUFDekJxRixNQUFBQSxNQUFNLElBQUlwRix5QkFBVjtBQUNBcUYsTUFBQUEsTUFBTSxJQUFJckYseUJBQVY7QUFDRCxLQUhELE1BR087QUFDTG9GLE1BQUFBLE1BQU0sR0FBR0MsTUFBTSxHQUFHLElBQUlyRix5QkFBdEI7QUFDRDs7QUFHRCxRQUFJLENBQUM2RixVQUFVLENBQUNULE1BQUQsQ0FBWCxJQUF1QixDQUFDUyxVQUFVLENBQUNSLE1BQUQsQ0FBdEMsRUFBZ0Q7QUFDOUMsYUFBTzVELFdBQVA7QUFDRDs7QUFHRCxRQUFJK0QsSUFBSSxDQUFDQyxLQUFMLENBQVdMLE1BQU0sR0FBRzdGLGVBQXBCLE1BQXlDaUcsSUFBSSxDQUFDQyxLQUFMLENBQVduRyxnQ0FBZ0MsR0FBR0MsZUFBOUMsQ0FBekMsSUFDR2lHLElBQUksQ0FBQ0MsS0FBTCxDQUFXSixNQUFNLEdBQUc5RixlQUFULEtBQTZCaUcsSUFBSSxDQUFDQyxLQUFMLENBQVduRyxnQ0FBZ0MsR0FBR0MsZUFBOUMsQ0FBeEMsQ0FEUCxFQUNnSDtBQUM5RyxhQUFPa0MsV0FBUDtBQUNEOztBQUVELFFBQUlxRSxVQUFVLEdBQUcsTUFBTXpCLG1CQUFVQyxZQUFWLENBQXVCN0MsV0FBdkIsQ0FBdkI7QUFDQSxRQUFJO0FBQUNZLE1BQUFBLEtBQUssRUFBRTBELGFBQVI7QUFBdUJ4RCxNQUFBQSxNQUFNLEVBQUV5RDtBQUEvQixRQUFnREYsVUFBVSxDQUFDckIsTUFBL0Q7QUFFQSxVQUFNd0IsV0FBVyxHQUFHRixhQUFhLEdBQUdYLE1BQXBDO0FBQ0EsVUFBTWMsWUFBWSxHQUFHRixhQUFhLEdBQUdYLE1BQXJDOztBQUNBbkQsb0JBQUlDLElBQUosQ0FBVSwrQkFBOEI0RCxhQUFjLElBQUdDLGFBQWMsRUFBOUQsR0FDRSxPQUFNQyxXQUFZLElBQUdDLFlBQWEsRUFEN0M7O0FBRUFoRSxvQkFBSUMsSUFBSixDQUFVLGdCQUFlaUQsTUFBTyxRQUFPQyxNQUFPLEVBQTlDOztBQUNBUyxJQUFBQSxVQUFVLEdBQUcsTUFBTUEsVUFBVSxDQUFDSCxNQUFYLENBQWtCTSxXQUFsQixFQUErQkMsWUFBL0IsQ0FBbkI7QUFDQSxXQUFPLENBQUMsTUFBTUosVUFBVSxDQUFDbkIsU0FBWCxDQUFxQk4sbUJBQVVPLFFBQS9CLENBQVAsRUFBaURDLFFBQWpELENBQTBELFFBQTFELENBQVA7QUFDRDs7QUF4WHFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCBMUlUgZnJvbSAnbHJ1LWNhY2hlJztcbmltcG9ydCB7IGltYWdlVXRpbCwgdXRpbCB9IGZyb20gJ0BhcHBpdW0vc3VwcG9ydCc7XG5pbXBvcnQgeyBlcnJvcnMgfSBmcm9tICdAYXBwaXVtL2Jhc2UtZHJpdmVyJztcbmltcG9ydCB7IEltYWdlRWxlbWVudCwgREVGQVVMVF9URU1QTEFURV9JTUFHRV9TQ0FMRSxcbiAgICAgICAgIElNQUdFX0VMX1RBUF9TVFJBVEVHWV9XM0MgfSBmcm9tICcuL2ltYWdlLWVsZW1lbnQnO1xuaW1wb3J0IHsgTUFUQ0hfVEVNUExBVEVfTU9ERSwgY29tcGFyZUltYWdlcywgREVGQVVMVF9NQVRDSF9USFJFU0hPTEQgfSBmcm9tICcuL2NvbXBhcmUnO1xuaW1wb3J0IGxvZyBmcm9tICcuL2xvZ2dlcic7XG5cbmNvbnN0IE1KU09OV1BfRUxFTUVOVF9LRVkgPSAnRUxFTUVOVCc7XG5jb25zdCBXM0NfRUxFTUVOVF9LRVkgPSB1dGlsLlczQ19XRUJfRUxFTUVOVF9JREVOVElGSUVSO1xuY29uc3QgREVGQVVMVF9GSVhfSU1BR0VfVEVNUExBVEVfU0NBTEUgPSAxO1xuLy8gVXNlZCB0byBjb21wYXJlIHJhdGlvIGFuZCBzY3JlZW4gd2lkdGhcbi8vIFBpeGVsIGlzIGJhc2ljYWxseSB1bmRlciAxMDgwIGZvciBleGFtcGxlLiAxMDBLIGlzIHByb2JhYmx5IGVub3VnaCBmbyBhIHdoaWxlLlxuY29uc3QgRkxPQVRfUFJFQ0lTSU9OID0gMTAwMDAwO1xuY29uc3QgTUFYX0NBQ0hFX1NJWkUgPSAxMDI0ICogMTAyNCAqIDQwOyAvLyA0MG1iXG5cbmNvbnN0IERFRkFVTFRfU0VUVElOR1MgPSB7XG4gIC8vIHZhbHVlIGJldHdlZW4gMCBhbmQgMSByZXByZXNlbnRpbmcgbWF0Y2ggc3RyZW5ndGgsIGJlbG93IHdoaWNoIGFuIGltYWdlXG4gIC8vIGVsZW1lbnQgd2lsbCBub3QgYmUgZm91bmRcbiAgaW1hZ2VNYXRjaFRocmVzaG9sZDogREVGQVVMVF9NQVRDSF9USFJFU0hPTEQsXG5cbiAgLy8gT25lIG9mIHBvc3NpYmxlIGltYWdlIG1hdGNoaW5nIG1ldGhvZHMuXG4gIC8vIFJlYWQgaHR0cHM6Ly9kb2NzLm9wZW5jdi5vcmcvMy4wLWJldGEvZG9jL3B5X3R1dG9yaWFscy9weV9pbWdwcm9jL3B5X3RlbXBsYXRlX21hdGNoaW5nL3B5X3RlbXBsYXRlX21hdGNoaW5nLmh0bWxcbiAgLy8gZm9yIG1vcmUgZGV0YWlscy5cbiAgLy8gVE1fQ0NPRUZGX05PUk1FRCBieSBkZWZhdWx0XG4gIGltYWdlTWF0Y2hNZXRob2Q6ICcnLFxuXG4gIC8vIGlmIHRoZSBpbWFnZSByZXR1cm5lZCBieSBnZXRTY3JlZW5zaG90IGRpZmZlcnMgaW4gc2l6ZSBvciBhc3BlY3QgcmF0aW9cbiAgLy8gZnJvbSB0aGUgc2NyZWVuLCBhdHRlbXB0IHRvIGZpeCBpdCBhdXRvbWF0aWNhbGx5XG4gIGZpeEltYWdlRmluZFNjcmVlbnNob3REaW1zOiB0cnVlLFxuXG4gIC8vIHdoZXRoZXIgQXBwaXVtIHNob3VsZCBlbnN1cmUgdGhhdCBhbiBpbWFnZSB0ZW1wbGF0ZSBzZW50IGluIGR1cmluZyBpbWFnZVxuICAvLyBlbGVtZW50IGZpbmQgc2hvdWxkIGhhdmUgaXRzIHNpemUgYWRqdXN0ZWQgc28gdGhlIG1hdGNoIGFsZ29yaXRobSB3aWxsIG5vdFxuICAvLyBjb21wbGFpblxuICBmaXhJbWFnZVRlbXBsYXRlU2l6ZTogZmFsc2UsXG5cbiAgLy8gd2hldGhlciBBcHBpdW0gc2hvdWxkIGVuc3VyZSB0aGF0IGFuIGltYWdlIHRlbXBsYXRlIHNlbnQgaW4gZHVyaW5nIGltYWdlXG4gIC8vIGVsZW1lbnQgZmluZCBzaG91bGQgaGF2ZSBpdHMgc2NhbGUgYWRqdXN0ZWQgdG8gZGlzcGxheSBzaXplIHNvIHRoZSBtYXRjaFxuICAvLyBhbGdvcml0aG0gd2lsbCBub3QgY29tcGxhaW4uXG4gIC8vIGUuZy4gaU9TIGhhcyBgd2lkdGg9Mzc1LCBoZWlnaHQ9NjY3YCB3aW5kb3cgcmVjdCwgYnV0IGl0cyBzY3JlZW5zaG90IGlzXG4gIC8vICAgICAgYHdpZHRoPTc1MCDDlyBoZWlnaHQ9MTMzNGAgcGl4ZWxzLiBUaGlzIHNldHRpbmcgaGVscCB0byBhZGp1c3QgdGhlIHNjYWxlXG4gIC8vICAgICAgaWYgYSB1c2VyIHVzZSBgd2lkdGg9NzUwIMOXIGhlaWdodD0xMzM0YCBwaXhlbHMncyBiYXNlIHRlbXBsYXRlIGltYWdlLlxuICBmaXhJbWFnZVRlbXBsYXRlU2NhbGU6IGZhbHNlLFxuXG4gIC8vIFVzZXJzIG1pZ2h0IGhhdmUgc2NhbGVkIHRlbXBsYXRlIGltYWdlIHRvIHJlZHVjZSB0aGVpciBzdG9yYWdlIHNpemUuXG4gIC8vIFRoaXMgc2V0dGluZyBhbGxvd3MgdXNlcnMgdG8gc2NhbGUgYSB0ZW1wbGF0ZSBpbWFnZSB0aGV5IHNlbmQgdG8gQXBwaXVtIHNlcnZlclxuICAvLyBzbyB0aGF0IHRoZSBBcHBpdW0gc2VydmVyIGNvbXBhcmVzIHRoZSBhY3R1YWwgc2NhbGUgdXNlcnMgb3JpZ2luYWxseSBoYWQuXG4gIC8vIGUuZy4gSWYgYSB1c2VyIGhhcyBhbiBpbWFnZSBvZiAyNzAgeCAzMiBwaXhlbHMgd2hpY2ggd2FzIG9yaWdpbmFsbHkgMTA4MCB4IDEyNiBwaXhlbHMsXG4gIC8vICAgICAgdGhlIHVzZXIgY2FuIHNldCB7ZGVmYXVsdEltYWdlVGVtcGxhdGVTY2FsZTogNC4wfSB0byBzY2FsZSB0aGUgc21hbGwgaW1hZ2VcbiAgLy8gICAgICB0byB0aGUgb3JpZ2luYWwgb25lIHNvIHRoYXQgQXBwaXVtIGNhbiBjb21wYXJlIGl0IGFzIHRoZSBvcmlnaW5hbCBvbmUuXG4gIGRlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGU6IERFRkFVTFRfVEVNUExBVEVfSU1BR0VfU0NBTEUsXG5cbiAgLy8gd2hldGhlciBBcHBpdW0gc2hvdWxkIHJlLWNoZWNrIHRoYXQgYW4gaW1hZ2UgZWxlbWVudCBjYW4gYmUgbWF0Y2hlZFxuICAvLyBhZ2FpbnN0IHRoZSBjdXJyZW50IHNjcmVlbnNob3QgYmVmb3JlIGNsaWNraW5nIGl0XG4gIGNoZWNrRm9ySW1hZ2VFbGVtZW50U3RhbGVuZXNzOiB0cnVlLFxuXG4gIC8vIHdoZXRoZXIgYmVmb3JlIGNsaWNraW5nIG9uIGFuIGltYWdlIGVsZW1lbnQgQXBwaXVtIHNob3VsZCByZS1kZXRlcm1pbmUgdGhlXG4gIC8vIHBvc2l0aW9uIG9mIHRoZSBlbGVtZW50IG9uIHNjcmVlblxuICBhdXRvVXBkYXRlSW1hZ2VFbGVtZW50UG9zaXRpb246IGZhbHNlLFxuXG4gIC8vIHdoaWNoIG1ldGhvZCB0byB1c2UgZm9yIHRhcHBpbmcgYnkgY29vcmRpbmF0ZSBmb3IgaW1hZ2UgZWxlbWVudHMuIHRoZVxuICAvLyBvcHRpb25zIGFyZSAndzNjJyBvciAnbWpzb253cCdcbiAgaW1hZ2VFbGVtZW50VGFwU3RyYXRlZ3k6IElNQUdFX0VMX1RBUF9TVFJBVEVHWV9XM0MsXG5cbiAgLy8gd2hpY2ggbWV0aG9kIHRvIHVzZSB0byBzYXZlIHRoZSBtYXRjaGVkIGltYWdlIGFyZWEgaW4gSW1hZ2VFbGVtZW50IGNsYXNzLlxuICAvLyBJdCBpcyB1c2VkIGZvciBkZWJ1Z2dpbmcgcHVycG9zZS5cbiAgZ2V0TWF0Y2hlZEltYWdlUmVzdWx0OiBmYWxzZSxcbn07XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEltYWdlRWxlbWVudEZpbmRlciB7XG4gIGNvbnN0cnVjdG9yIChkcml2ZXIsIG1heCA9IE1BWF9DQUNIRV9TSVpFKSB7XG4gICAgdGhpcy5kcml2ZXIgPSBkcml2ZXI7XG4gICAgdGhpcy5pbWdFbENhY2hlID0gbmV3IExSVSh7XG4gICAgICBtYXgsXG4gICAgICBsZW5ndGg6IChlbCkgPT4gZWwudGVtcGxhdGUubGVuZ3RoLFxuICAgIH0pO1xuICB9XG5cbiAgc2V0RHJpdmVyIChkcml2ZXIpIHtcbiAgICB0aGlzLmRyaXZlciA9IGRyaXZlcjtcbiAgfVxuXG4gIHJlZ2lzdGVySW1hZ2VFbGVtZW50IChpbWdFbCkge1xuICAgIHRoaXMuaW1nRWxDYWNoZS5zZXQoaW1nRWwuaWQsIGltZ0VsKTtcbiAgICBjb25zdCBwcm90b0tleSA9IHRoaXMuZHJpdmVyLmlzVzNDUHJvdG9jb2woKSA/IFczQ19FTEVNRU5UX0tFWSA6IE1KU09OV1BfRUxFTUVOVF9LRVk7XG4gICAgcmV0dXJuIGltZ0VsLmFzRWxlbWVudChwcm90b0tleSk7XG4gIH1cblxuICAvKipcbiAgICogQHR5cGVkZWYgRmluZEJ5SW1hZ2VPcHRpb25zXG4gICAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0gW3Nob3VsZENoZWNrU3RhbGVuZXNzPWZhbHNlXSAtIHdoZXRoZXIgdGhpcyBjYWxsIHRvIGZpbmQgYW5cbiAgICogaW1hZ2UgaXMgbWVyZWx5IHRvIGNoZWNrIHN0YWxlbmVzcy4gSWYgc28gd2UgY2FuIGJ5cGFzcyBhIGxvdCBvZiBsb2dpY1xuICAgKiBAcHJvcGVydHkge2Jvb2xlYW59IFttdWx0aXBsZT1mYWxzZV0gLSBXaGV0aGVyIHdlIGFyZSBmaW5kaW5nIG9uZSBlbGVtZW50IG9yXG4gICAqIG11bHRpcGxlXG4gICAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0gW2lnbm9yZURlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGU9ZmFsc2VdIC0gV2hldGhlciB3ZVxuICAgKiBpZ25vcmUgZGVmYXVsdEltYWdlVGVtcGxhdGVTY2FsZS4gSXQgY2FuIGJlIHVzZWQgd2hlbiB5b3Ugd291bGQgbGlrZSB0b1xuICAgKiBzY2FsZSBiNjRUZW1wbGF0ZSB3aXRoIGRlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGUgc2V0dGluZy5cbiAgICovXG5cbiAgLyoqXG4gICAqIEZpbmQgYSBzY3JlZW4gcmVjdCByZXByZXNlbnRlZCBieSBhbiBJbWFnZUVsZW1lbnQgY29ycmVzcG9uZGluZyB0byBhbiBpbWFnZVxuICAgKiB0ZW1wbGF0ZSBzZW50IGluIGJ5IHRoZSBjbGllbnRcbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IGI2NFRlbXBsYXRlIC0gYmFzZTY0LWVuY29kZWQgaW1hZ2UgdXNlZCBhcyBhIHRlbXBsYXRlIHRvIGJlXG4gICAqIG1hdGNoZWQgaW4gdGhlIHNjcmVlbnNob3RcbiAgICogQHBhcmFtIHtGaW5kQnlJbWFnZU9wdGlvbnN9IC0gYWRkaXRpb25hbCBvcHRpb25zXG4gICAqXG4gICAqIEByZXR1cm5zIHtXZWJFbGVtZW50fSAtIFdlYkRyaXZlciBlbGVtZW50IHdpdGggYSBzcGVjaWFsIGlkIHByZWZpeFxuICAgKi9cbiAgYXN5bmMgZmluZEJ5SW1hZ2UgKGI2NFRlbXBsYXRlLCB7XG4gICAgc2hvdWxkQ2hlY2tTdGFsZW5lc3MgPSBmYWxzZSxcbiAgICBtdWx0aXBsZSA9IGZhbHNlLFxuICAgIGlnbm9yZURlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGUgPSBmYWxzZSxcbiAgfSkge1xuICAgIGlmICghdGhpcy5kcml2ZXIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgQ2FuJ3QgZmluZCB3aXRob3V0IGEgZHJpdmVyIWApO1xuICAgIH1cbiAgICBjb25zdCBzZXR0aW5ncyA9IHsuLi5ERUZBVUxUX1NFVFRJTkdTLCAuLi50aGlzLmRyaXZlci5zZXR0aW5ncy5nZXRTZXR0aW5ncygpfTtcbiAgICBjb25zdCB7XG4gICAgICBpbWFnZU1hdGNoVGhyZXNob2xkOiB0aHJlc2hvbGQsXG4gICAgICBpbWFnZU1hdGNoTWV0aG9kLFxuICAgICAgZml4SW1hZ2VUZW1wbGF0ZVNpemUsXG4gICAgICBmaXhJbWFnZVRlbXBsYXRlU2NhbGUsXG4gICAgICBkZWZhdWx0SW1hZ2VUZW1wbGF0ZVNjYWxlLFxuICAgICAgZ2V0TWF0Y2hlZEltYWdlUmVzdWx0OiB2aXN1YWxpemVcbiAgICB9ID0gc2V0dGluZ3M7XG5cbiAgICBsb2cuaW5mbyhgRmluZGluZyBpbWFnZSBlbGVtZW50IHdpdGggbWF0Y2ggdGhyZXNob2xkICR7dGhyZXNob2xkfWApO1xuICAgIGlmICghdGhpcy5kcml2ZXIuZ2V0V2luZG93U2l6ZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiVGhpcyBkcml2ZXIgZG9lcyBub3Qgc3VwcG9ydCB0aGUgcmVxdWlyZWQgJ2dldFdpbmRvd1NpemUnIGNvbW1hbmRcIik7XG4gICAgfVxuICAgIGNvbnN0IHt3aWR0aDogc2NyZWVuV2lkdGgsIGhlaWdodDogc2NyZWVuSGVpZ2h0fSA9IGF3YWl0IHRoaXMuZHJpdmVyLmdldFdpbmRvd1NpemUoKTtcblxuICAgIC8vIHNvbWVvbmUgbWlnaHQgaGF2ZSBzZW50IGluIGEgdGVtcGxhdGUgdGhhdCdzIGxhcmdlciB0aGFuIHRoZSBzY3JlZW5cbiAgICAvLyBkaW1lbnNpb25zLiBJZiBzbyBsZXQncyBjaGVjayBhbmQgY3V0IGl0IGRvd24gdG8gc2l6ZSBzaW5jZSB0aGUgYWxnb3JpdGhtXG4gICAgLy8gd2lsbCBub3Qgd29yayB1bmxlc3Mgd2UgZG8uIEJ1dCBiZWNhdXNlIGl0IHJlcXVpcmVzIHNvbWUgcG90ZW50aWFsbHlcbiAgICAvLyBleHBlbnNpdmUgY29tbWFuZHMsIG9ubHkgZG8gdGhpcyBpZiB0aGUgdXNlciBoYXMgcmVxdWVzdGVkIGl0IGluIHNldHRpbmdzLlxuICAgIGlmIChmaXhJbWFnZVRlbXBsYXRlU2l6ZSkge1xuICAgICAgYjY0VGVtcGxhdGUgPSBhd2FpdCB0aGlzLmVuc3VyZVRlbXBsYXRlU2l6ZShiNjRUZW1wbGF0ZSwgc2NyZWVuV2lkdGgsXG4gICAgICAgIHNjcmVlbkhlaWdodCk7XG4gICAgfVxuXG4gICAgY29uc3QgcmVzdWx0cyA9IFtdO1xuICAgIGNvbnN0IGNvbmRpdGlvbiA9IGFzeW5jICgpID0+IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHtiNjRTY3JlZW5zaG90LCBzY2FsZX0gPSBhd2FpdCB0aGlzLmdldFNjcmVlbnNob3RGb3JJbWFnZUZpbmQoc2NyZWVuV2lkdGgsIHNjcmVlbkhlaWdodCk7XG5cbiAgICAgICAgYjY0VGVtcGxhdGUgPSBhd2FpdCB0aGlzLmZpeEltYWdlVGVtcGxhdGVTY2FsZShiNjRUZW1wbGF0ZSwge1xuICAgICAgICAgIGRlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGUsIGlnbm9yZURlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGUsXG4gICAgICAgICAgZml4SW1hZ2VUZW1wbGF0ZVNjYWxlLCAuLi5zY2FsZVxuICAgICAgICB9KTtcblxuICAgICAgICBjb25zdCBjb21wYXJpc29uT3B0cyA9IHtcbiAgICAgICAgICB0aHJlc2hvbGQsXG4gICAgICAgICAgdmlzdWFsaXplLFxuICAgICAgICAgIG11bHRpcGxlLFxuICAgICAgICB9O1xuICAgICAgICBpZiAoaW1hZ2VNYXRjaE1ldGhvZCkge1xuICAgICAgICAgIGNvbXBhcmlzb25PcHRzLm1ldGhvZCA9IGltYWdlTWF0Y2hNZXRob2Q7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG11bHRpcGxlKSB7XG4gICAgICAgICAgcmVzdWx0cy5wdXNoKC4uLihhd2FpdCBjb21wYXJlSW1hZ2VzKE1BVENIX1RFTVBMQVRFX01PREUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGI2NFNjcmVlbnNob3QsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGI2NFRlbXBsYXRlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21wYXJpc29uT3B0cykpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICByZXN1bHRzLnB1c2goYXdhaXQgY29tcGFyZUltYWdlcyhNQVRDSF9URU1QTEFURV9NT0RFLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGI2NFNjcmVlbnNob3QsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYjY0VGVtcGxhdGUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tcGFyaXNvbk9wdHMpKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdHJ1ZTtcblxuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIC8vIGlmIGNvbXBhcmVJbWFnZXMgZmFpbHMsIHdlJ2xsIGdldCBhIHNwZWNpZmljIGVycm9yLCBidXQgd2Ugc2hvdWxkXG4gICAgICAgIC8vIHJldHJ5LCBzbyB0cmFwIHRoYXQgYW5kIGp1c3QgcmV0dXJuIGZhbHNlIHRvIHRyaWdnZXIgdGhlIG5leHQgcm91bmQgb2ZcbiAgICAgICAgLy8gaW1wbGljaXRseSB3YWl0aW5nLiBGb3Igb3RoZXIgZXJyb3JzLCB0aHJvdyB0aGVtIHRvIGdldCBvdXQgb2YgdGhlXG4gICAgICAgIC8vIGltcGxpY2l0IHdhaXQgbG9vcFxuICAgICAgICBpZiAoZXJyLm1lc3NhZ2UubWF0Y2goL0Nhbm5vdCBmaW5kIGFueSBvY2N1cnJlbmNlcy8pKSB7XG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIHRocm93IGVycjtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHRoaXMuZHJpdmVyLmltcGxpY2l0V2FpdEZvckNvbmRpdGlvbihjb25kaXRpb24pO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgLy8gdGhpcyBgaW1wbGljaXRXYWl0Rm9yQ29uZGl0aW9uYCBtZXRob2Qgd2lsbCB0aHJvdyBhICdDb25kaXRpb24gdW5tZXQnXG4gICAgICAvLyBlcnJvciBpZiBhbiBlbGVtZW50IGlzIG5vdCBmb3VuZCBldmVudHVhbGx5LiBJbiB0aGF0IGNhc2UsIHdlIHdpbGxcbiAgICAgIC8vIGhhbmRsZSB0aGUgZWxlbWVudCBub3QgZm91bmQgcmVzcG9uc2UgYmVsb3cuIEluIHRoZSBjYXNlIHdoZXJlIGdldCBzb21lXG4gICAgICAvLyBfb3RoZXJfIGtpbmQgb2YgZXJyb3IsIGl0IG1lYW5zIHNvbWV0aGluZyBibGV3IHVwIHRvdGFsbHkgYXBhcnQgZnJvbSB0aGVcbiAgICAgIC8vIGltcGxpY2l0IHdhaXQgdGltZW91dC4gV2Ugc2hvdWxkIG5vdCBtYXNrIHRoYXQgZXJyb3IgYW5kIGluc3RlYWQgdGhyb3dcbiAgICAgIC8vIGl0IHN0cmFpZ2h0YXdheVxuICAgICAgaWYgKCFlcnIubWVzc2FnZS5tYXRjaCgvQ29uZGl0aW9uIHVubWV0LykpIHtcbiAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChfLmlzRW1wdHkocmVzdWx0cykpIHtcbiAgICAgIGlmIChtdWx0aXBsZSkge1xuICAgICAgICByZXR1cm4gW107XG4gICAgICB9XG4gICAgICB0aHJvdyBuZXcgZXJyb3JzLk5vU3VjaEVsZW1lbnRFcnJvcigpO1xuICAgIH1cblxuICAgIGNvbnN0IGVsZW1lbnRzID0gcmVzdWx0cy5tYXAoKHtyZWN0LCBzY29yZSwgdmlzdWFsaXphdGlvbn0pID0+IHtcbiAgICAgIGxvZy5pbmZvKGBJbWFnZSB0ZW1wbGF0ZSBtYXRjaGVkOiAke0pTT04uc3RyaW5naWZ5KHJlY3QpfWApO1xuICAgICAgcmV0dXJuIG5ldyBJbWFnZUVsZW1lbnQoYjY0VGVtcGxhdGUsIHJlY3QsIHNjb3JlLCB2aXN1YWxpemF0aW9uLCB0aGlzKTtcbiAgICB9KTtcblxuICAgIC8vIGlmIHdlJ3JlIGp1c3QgY2hlY2tpbmcgc3RhbGVuZXNzLCByZXR1cm4gc3RyYWlnaHRhd2F5IHNvIHdlIGRvbid0IGFkZFxuICAgIC8vIGEgbmV3IGVsZW1lbnQgdG8gdGhlIGNhY2hlLiBzaG91bGRDaGVja1N0YWxlbmVzcyBkb2VzIG5vdCBzdXBwb3J0IG11bHRpcGxlXG4gICAgLy8gZWxlbWVudHMsIHNpbmNlIGl0IGlzIGEgcHVyZWx5IGludGVybmFsIG1lY2hhbmlzbVxuICAgIGlmIChzaG91bGRDaGVja1N0YWxlbmVzcykge1xuICAgICAgcmV0dXJuIGVsZW1lbnRzWzBdO1xuICAgIH1cblxuICAgIGNvbnN0IHJlZ2lzdGVyZWRFbGVtZW50cyA9IGVsZW1lbnRzLm1hcCgoaW1nRWwpID0+IHRoaXMucmVnaXN0ZXJJbWFnZUVsZW1lbnQoaW1nRWwpKTtcblxuICAgIHJldHVybiBtdWx0aXBsZSA/IHJlZ2lzdGVyZWRFbGVtZW50cyA6IHJlZ2lzdGVyZWRFbGVtZW50c1swXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFbnN1cmUgdGhhdCB0aGUgaW1hZ2UgdGVtcGxhdGUgc2VudCBpbiBmb3IgYSBmaW5kIGlzIG9mIGEgc3VpdGFibGUgc2l6ZVxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gYjY0VGVtcGxhdGUgLSBiYXNlNjQtZW5jb2RlZCBpbWFnZVxuICAgKiBAcGFyYW0ge2ludH0gc2NyZWVuV2lkdGggLSB3aWR0aCBvZiBzY3JlZW5cbiAgICogQHBhcmFtIHtpbnR9IHNjcmVlbkhlaWdodCAtIGhlaWdodCBvZiBzY3JlZW5cbiAgICpcbiAgICogQHJldHVybnMge3N0cmluZ30gYmFzZTY0LWVuY29kZWQgaW1hZ2UsIHBvdGVudGlhbGx5IHJlc2l6ZWRcbiAgICovXG4gIGFzeW5jIGVuc3VyZVRlbXBsYXRlU2l6ZSAoYjY0VGVtcGxhdGUsIHNjcmVlbldpZHRoLCBzY3JlZW5IZWlnaHQpIHtcbiAgICBsZXQgaW1nT2JqID0gYXdhaXQgaW1hZ2VVdGlsLmdldEppbXBJbWFnZShiNjRUZW1wbGF0ZSk7XG4gICAgbGV0IHt3aWR0aDogdHBsV2lkdGgsIGhlaWdodDogdHBsSGVpZ2h0fSA9IGltZ09iai5iaXRtYXA7XG5cbiAgICBsb2cuaW5mbyhgVGVtcGxhdGUgaW1hZ2UgaXMgJHt0cGxXaWR0aH14JHt0cGxIZWlnaHR9LiBTY3JlZW4gc2l6ZSBpcyAke3NjcmVlbldpZHRofXgke3NjcmVlbkhlaWdodH1gKTtcbiAgICAvLyBpZiB0aGUgdGVtcGxhdGUgZml0cyBpbnNpZGUgdGhlIHNjcmVlbiBkaW1lbnNpb25zLCB3ZSdyZSBnb29kXG4gICAgaWYgKHRwbFdpZHRoIDw9IHNjcmVlbldpZHRoICYmIHRwbEhlaWdodCA8PSBzY3JlZW5IZWlnaHQpIHtcbiAgICAgIHJldHVybiBiNjRUZW1wbGF0ZTtcbiAgICB9XG5cbiAgICBsb2cuaW5mbyhgU2NhbGluZyB0ZW1wbGF0ZSBpbWFnZSBmcm9tICR7dHBsV2lkdGh9eCR7dHBsSGVpZ2h0fSB0byBtYXRjaCBgICtcbiAgICAgICAgICAgICBgc2NyZWVuIGF0ICR7c2NyZWVuV2lkdGh9eCR7c2NyZWVuSGVpZ2h0fWApO1xuICAgIC8vIG90aGVyd2lzZSwgc2NhbGUgaXQgdG8gZml0IGluc2lkZSB0aGUgc2NyZWVuIGRpbWVuc2lvbnNcbiAgICBpbWdPYmogPSBpbWdPYmouc2NhbGVUb0ZpdChzY3JlZW5XaWR0aCwgc2NyZWVuSGVpZ2h0KTtcbiAgICByZXR1cm4gKGF3YWl0IGltZ09iai5nZXRCdWZmZXIoaW1hZ2VVdGlsLk1JTUVfUE5HKSkudG9TdHJpbmcoJ2Jhc2U2NCcpO1xuICB9XG5cbiAgLyoqXG4gICAqIEB0eXBlZGVmIFNjcmVlbnNob3RcbiAgICogQHByb3BlcnR5IHtzdHJpbmd9IGI2NFNjcmVlbnNob3QgLSBiYXNlNjQgYmFzZWQgc2NyZWVuc2hvdCBzdHJpbmdcbiAgICovXG4gIC8qKlxuICAgKiBAdHlwZWRlZiBTY3JlZW5zaG90U2NhbGVcbiAgICogQHByb3BlcnR5IHtmbG9hdH0geFNjYWxlIC0gU2NhbGUgcmF0aW8gZm9yIHdpZHRoXG4gICAqIEBwcm9wZXJ0eSB7ZmxvYXR9IHlTY2FsZSAtIFNjYWxlIHJhdGlvIGZvciBoZWlnaHRcbiAgICovXG4gIC8qKlxuICAgKiBHZXQgdGhlIHNjcmVlbnNob3QgaW1hZ2UgdGhhdCB3aWxsIGJlIHVzZWQgZm9yIGZpbmQgYnkgZWxlbWVudCwgcG90ZW50aWFsbHlcbiAgICogYWx0ZXJpbmcgaXQgaW4gdmFyaW91cyB3YXlzIGJhc2VkIG9uIHVzZXItcmVxdWVzdGVkIHNldHRpbmdzXG4gICAqXG4gICAqIEBwYXJhbSB7aW50fSBzY3JlZW5XaWR0aCAtIHdpZHRoIG9mIHNjcmVlblxuICAgKiBAcGFyYW0ge2ludH0gc2NyZWVuSGVpZ2h0IC0gaGVpZ2h0IG9mIHNjcmVlblxuICAgKlxuICAgKiBAcmV0dXJucyB7IHtiNjRTY3JlZW5zaG90OiBTY3JlZW5zaG90LCBzY2FsZTogU2NyZWVuc2hvdFNjYWxlPyB9IH0gYmFzZTY0LWVuY29kZWQgc2NyZWVuc2hvdCBhbmQgU2NyZWVuc2hvdFNjYWxlXG4gICAqL1xuICBhc3luYyBnZXRTY3JlZW5zaG90Rm9ySW1hZ2VGaW5kIChzY3JlZW5XaWR0aCwgc2NyZWVuSGVpZ2h0KSB7XG4gICAgaWYgKCF0aGlzLmRyaXZlci5nZXRTY3JlZW5zaG90KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJUaGlzIGRyaXZlciBkb2VzIG5vdCBzdXBwb3J0IHRoZSByZXF1aXJlZCAnZ2V0U2NyZWVuc2hvdCcgY29tbWFuZFwiKTtcbiAgICB9XG4gICAgY29uc3Qgc2V0dGluZ3MgPSBPYmplY3QuYXNzaWduKHt9LCBERUZBVUxUX1NFVFRJTkdTLCB0aGlzLmRyaXZlci5zZXR0aW5ncy5nZXRTZXR0aW5ncygpKTtcbiAgICBjb25zdCB7Zml4SW1hZ2VGaW5kU2NyZWVuc2hvdERpbXN9ID0gc2V0dGluZ3M7XG5cbiAgICBsZXQgYjY0U2NyZWVuc2hvdCA9IGF3YWl0IHRoaXMuZHJpdmVyLmdldFNjcmVlbnNob3QoKTtcblxuICAgIC8vIGlmIHRoZSB1c2VyIGhhcyByZXF1ZXN0ZWQgbm90IHRvIGNvcnJlY3QgZm9yIGFzcGVjdCBvciBzaXplIGRpZmZlcmVuY2VzXG4gICAgLy8gYmV0d2VlbiB0aGUgc2NyZWVuc2hvdCBhbmQgdGhlIHNjcmVlbiwganVzdCByZXR1cm4gdGhlIHNjcmVlbnNob3Qgbm93XG4gICAgaWYgKCFmaXhJbWFnZUZpbmRTY3JlZW5zaG90RGltcykge1xuICAgICAgbG9nLmluZm8oYE5vdCB2ZXJpZnlpbmcgc2NyZWVuc2hvdCBkaW1lbnNpb25zIG1hdGNoIHNjcmVlbmApO1xuICAgICAgcmV0dXJuIHtiNjRTY3JlZW5zaG90fTtcbiAgICB9XG5cbiAgICBpZiAoc2NyZWVuV2lkdGggPCAxIHx8IHNjcmVlbkhlaWdodCA8IDEpIHtcbiAgICAgIGxvZy53YXJuKGBUaGUgcmV0cmlldmVkIHNjcmVlbiBzaXplICR7c2NyZWVuV2lkdGh9eCR7c2NyZWVuSGVpZ2h0fSBkb2VzIGAgK1xuICAgICAgICBgbm90IHNlZW0gdG8gYmUgdmFsaWQuIE5vIGNoYW5nZXMgd2lsbCBiZSBhcHBsaWVkIHRvIHRoZSBzY3JlZW5zaG90YCk7XG4gICAgICByZXR1cm4ge2I2NFNjcmVlbnNob3R9O1xuICAgIH1cblxuICAgIC8vIG90aGVyd2lzZSwgZG8gc29tZSB2ZXJpZmljYXRpb24gb24gdGhlIHNjcmVlbnNob3QgdG8gbWFrZSBzdXJlIGl0IG1hdGNoZXNcbiAgICAvLyB0aGUgc2NyZWVuIHNpemUgYW5kIGFzcGVjdCByYXRpb1xuICAgIGxvZy5pbmZvKCdWZXJpZnlpbmcgc2NyZWVuc2hvdCBzaXplIGFuZCBhc3BlY3QgcmF0aW8nKTtcblxuICAgIGxldCBpbWdPYmogPSBhd2FpdCBpbWFnZVV0aWwuZ2V0SmltcEltYWdlKGI2NFNjcmVlbnNob3QpO1xuICAgIGxldCB7d2lkdGg6IHNob3RXaWR0aCwgaGVpZ2h0OiBzaG90SGVpZ2h0fSA9IGltZ09iai5iaXRtYXA7XG5cbiAgICBpZiAoc2hvdFdpZHRoIDwgMSB8fCBzaG90SGVpZ2h0IDwgMSkge1xuICAgICAgbG9nLndhcm4oYFRoZSByZXRyaWV2ZWQgc2NyZWVuc2hvdCBzaXplICR7c2hvdFdpZHRofXgke3Nob3RIZWlnaHR9IGRvZXMgYCArXG4gICAgICAgIGBub3Qgc2VlbSB0byBiZSB2YWxpZC4gTm8gY2hhbmdlcyB3aWxsIGJlIGFwcGxpZWQgdG8gdGhlIHNjcmVlbnNob3RgKTtcbiAgICAgIHJldHVybiB7YjY0U2NyZWVuc2hvdH07XG4gICAgfVxuXG4gICAgaWYgKHNjcmVlbldpZHRoID09PSBzaG90V2lkdGggJiYgc2NyZWVuSGVpZ2h0ID09PSBzaG90SGVpZ2h0KSB7XG4gICAgICAvLyB0aGUgaGVpZ2h0IGFuZCB3aWR0aCBvZiB0aGUgc2NyZWVuc2hvdCBhbmQgdGhlIGRldmljZSBzY3JlZW4gbWF0Y2gsIHdoaWNoXG4gICAgICAvLyBtZWFucyB3ZSBzaG91bGQgYmUgc2FmZSB3aGVuIGRvaW5nIHRlbXBsYXRlIG1hdGNoZXNcbiAgICAgIGxvZy5pbmZvKCdTY3JlZW5zaG90IHNpemUgbWF0Y2hlZCBzY3JlZW4gc2l6ZScpO1xuICAgICAgcmV0dXJuIHtiNjRTY3JlZW5zaG90fTtcbiAgICB9XG5cbiAgICAvLyBvdGhlcndpc2UsIGlmIHRoZXkgZG9uJ3QgbWF0Y2gsIGl0IGNvdWxkIHNwZWxsIHByb2JsZW1zIGZvciB0aGUgYWNjdXJhY3lcbiAgICAvLyBvZiBjb29yZGluYXRlcyByZXR1cm5lZCBieSB0aGUgaW1hZ2UgbWF0Y2ggYWxnb3JpdGhtLCBzaW5jZSB3ZSBtYXRjaCBiYXNlZFxuICAgIC8vIG9uIHRoZSBzY3JlZW5zaG90IGNvb3JkaW5hdGVzIG5vdCB0aGUgZGV2aWNlIGNvb3JkaW5hdGVzIHRoZW1zZWx2ZXMuIFRoZXJlXG4gICAgLy8gYXJlIHR3byBwb3RlbnRpYWwgdHlwZXMgb2YgbWlzbWF0Y2g6IGFzcGVjdCByYXRpbyBtaXNtYXRjaCBhbmQgc2NhbGVcbiAgICAvLyBtaXNtYXRjaC4gV2UgbmVlZCB0byBkZXRlY3QgYW5kIGZpeCBib3RoXG5cbiAgICBjb25zdCBzY2FsZSA9IHt4U2NhbGU6IDEuMCwgeVNjYWxlOiAxLjB9O1xuXG4gICAgY29uc3Qgc2NyZWVuQVIgPSBzY3JlZW5XaWR0aCAvIHNjcmVlbkhlaWdodDtcbiAgICBjb25zdCBzaG90QVIgPSBzaG90V2lkdGggLyBzaG90SGVpZ2h0O1xuICAgIGlmIChNYXRoLnJvdW5kKHNjcmVlbkFSICogRkxPQVRfUFJFQ0lTSU9OKSA9PT0gTWF0aC5yb3VuZChzaG90QVIgKiBGTE9BVF9QUkVDSVNJT04pKSB7XG4gICAgICBsb2cuaW5mbyhgU2NyZWVuc2hvdCBhc3BlY3QgcmF0aW8gJyR7c2hvdEFSfScgKCR7c2hvdFdpZHRofXgke3Nob3RIZWlnaHR9KSBtYXRjaGVkIGAgK1xuICAgICAgICBgc2NyZWVuIGFzcGVjdCByYXRpbyAnJHtzY3JlZW5BUn0nICgke3NjcmVlbldpZHRofXgke3NjcmVlbkhlaWdodH0pYCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGxvZy53YXJuKGBXaGVuIHRyeWluZyB0byBmaW5kIGFuIGVsZW1lbnQsIGRldGVybWluZWQgdGhhdCB0aGUgc2NyZWVuIGAgK1xuICAgICAgICAgICAgICAgYGFzcGVjdCByYXRpbyBhbmQgc2NyZWVuc2hvdCBhc3BlY3QgcmF0aW8gYXJlIGRpZmZlcmVudC4gU2NyZWVuIGAgK1xuICAgICAgICAgICAgICAgYGlzICR7c2NyZWVuV2lkdGh9eCR7c2NyZWVuSGVpZ2h0fSB3aGVyZWFzIHNjcmVlbnNob3QgaXMgYCArXG4gICAgICAgICAgICAgICBgJHtzaG90V2lkdGh9eCR7c2hvdEhlaWdodH0uYCk7XG5cbiAgICAgIC8vIEluIHRoZSBjYXNlIHdoZXJlIHRoZSB4LXNjYWxlIGFuZCB5LXNjYWxlIGFyZSBkaWZmZXJlbnQsIHdlIG5lZWQgdG8gZGVjaWRlXG4gICAgICAvLyB3aGljaCBvbmUgdG8gcmVzcGVjdCwgb3RoZXJ3aXNlIHRoZSBzY3JlZW5zaG90IGFuZCB0ZW1wbGF0ZSB3aWxsIGVuZCB1cFxuICAgICAgLy8gYmVpbmcgcmVzaXplZCBpbiBhIHdheSB0aGF0IGNoYW5nZXMgaXRzIGFzcGVjdCByYXRpbyAoZGlzdG9ydHMgaXQpLiBGb3IgZXhhbXBsZSwgbGV0J3Mgc2F5OlxuICAgICAgLy8gdGhpcy5nZXRTY3JlZW5zaG90KHNob3RXaWR0aCwgc2hvdEhlaWdodCkgaXMgNTQweDM5NyxcbiAgICAgIC8vIHRoaXMuZ2V0RGV2aWNlU2l6ZShzY3JlZW5XaWR0aCwgc2NyZWVuSGVpZ2h0KSBpcyAxMDgweDE5MjAuXG4gICAgICAvLyBUaGUgcmF0aW8gd291bGQgdGhlbiBiZSB7eFNjYWxlOiAwLjUsIHlTY2FsZTogMC4yfS5cbiAgICAgIC8vIEluIHRoaXMgY2FzZSwgd2UgbXVzdCBzaG91bGQgYHlTY2FsZTogMC4yYCBhcyBzY2FsZUZhY3RvciwgYmVjYXVzZVxuICAgICAgLy8gaWYgd2Ugc2VsZWN0IHRoZSB4U2NhbGUsIHRoZSBoZWlnaHQgd2lsbCBiZSBiaWdnZXIgdGhhbiByZWFsIHNjcmVlbnNob3Qgc2l6ZVxuICAgICAgLy8gd2hpY2ggaXMgdXNlZCB0byBpbWFnZSBjb21wYXJpc29uIGJ5IE9wZW5DViBhcyBhIGJhc2UgaW1hZ2UuXG4gICAgICAvLyBBbGwgb2YgdGhpcyBpcyBwcmltYXJpbHkgdXNlZnVsIHdoZW4gdGhlIHNjcmVlbnNob3QgaXMgYSBob3Jpem9udGFsIHNsaWNlIHRha2VuIG91dCBvZiB0aGVcbiAgICAgIC8vIHNjcmVlbiAoZm9yIGV4YW1wbGUgbm90IGluY2x1ZGluZyB0b3AvYm90dG9tIG5hdiBiYXJzKVxuICAgICAgY29uc3QgeFNjYWxlID0gKDEuMCAqIHNob3RXaWR0aCkgLyBzY3JlZW5XaWR0aDtcbiAgICAgIGNvbnN0IHlTY2FsZSA9ICgxLjAgKiBzaG90SGVpZ2h0KSAvIHNjcmVlbkhlaWdodDtcbiAgICAgIGNvbnN0IHNjYWxlRmFjdG9yID0geFNjYWxlID49IHlTY2FsZSA/IHlTY2FsZSA6IHhTY2FsZTtcblxuICAgICAgbG9nLndhcm4oYFJlc2l6aW5nIHNjcmVlbnNob3QgdG8gJHtzaG90V2lkdGggKiBzY2FsZUZhY3Rvcn14JHtzaG90SGVpZ2h0ICogc2NhbGVGYWN0b3J9IHRvIG1hdGNoIGAgK1xuICAgICAgICAgICAgICAgYHNjcmVlbiBhc3BlY3QgcmF0aW8gc28gdGhhdCBpbWFnZSBlbGVtZW50IGNvb3JkaW5hdGVzIGhhdmUgYSBgICtcbiAgICAgICAgICAgICAgIGBncmVhdGVyIGNoYW5jZSBvZiBiZWluZyBjb3JyZWN0LmApO1xuICAgICAgaW1nT2JqID0gaW1nT2JqLnJlc2l6ZShzaG90V2lkdGggKiBzY2FsZUZhY3Rvciwgc2hvdEhlaWdodCAqIHNjYWxlRmFjdG9yKTtcblxuICAgICAgc2NhbGUueFNjYWxlICo9IHNjYWxlRmFjdG9yO1xuICAgICAgc2NhbGUueVNjYWxlICo9IHNjYWxlRmFjdG9yO1xuXG4gICAgICBzaG90V2lkdGggPSBpbWdPYmouYml0bWFwLndpZHRoO1xuICAgICAgc2hvdEhlaWdodCA9IGltZ09iai5iaXRtYXAuaGVpZ2h0O1xuICAgIH1cblxuICAgIC8vIFJlc2l6ZSBiYXNlZCBvbiB0aGUgc2NyZWVuIGRpbWVuc2lvbnMgb25seSBpZiBib3RoIHdpZHRoIGFuZCBoZWlnaHQgYXJlIG1pc21hdGNoZWRcbiAgICAvLyBzaW5jZSBleGNlcHQgZm9yIHRoYXQsIGl0IG1pZ2h0IGJlIGEgc2l0dWF0aW9uIHdoaWNoIGlzIGRpZmZlcmVudCB3aW5kb3cgcmVjdCBhbmRcbiAgICAvLyBzY3JlZW5zaG90IHNpemUgbGlrZSBgQGRyaXZlci53aW5kb3dfcmVjdCAjPT54PTAsIHk9MCwgd2lkdGg9MTA4MCwgaGVpZ2h0PTE3OTRgIGFuZFxuICAgIC8vIGBcImRldmljZVNjcmVlblNpemVcIj0+XCIxMDgweDE5MjBcImBcbiAgICBpZiAoc2NyZWVuV2lkdGggIT09IHNob3RXaWR0aCAmJiBzY3JlZW5IZWlnaHQgIT09IHNob3RIZWlnaHQpIHtcbiAgICAgIGxvZy5pbmZvKGBTY2FsaW5nIHNjcmVlbnNob3QgZnJvbSAke3Nob3RXaWR0aH14JHtzaG90SGVpZ2h0fSB0byBtYXRjaCBgICtcbiAgICAgICAgICAgICAgIGBzY3JlZW4gYXQgJHtzY3JlZW5XaWR0aH14JHtzY3JlZW5IZWlnaHR9YCk7XG4gICAgICBpbWdPYmogPSBpbWdPYmoucmVzaXplKHNjcmVlbldpZHRoLCBzY3JlZW5IZWlnaHQpO1xuXG4gICAgICBzY2FsZS54U2NhbGUgKj0gKDEuMCAqIHNjcmVlbldpZHRoKSAvIHNob3RXaWR0aDtcbiAgICAgIHNjYWxlLnlTY2FsZSAqPSAoMS4wICogc2NyZWVuSGVpZ2h0KSAvIHNob3RIZWlnaHQ7XG4gICAgfVxuXG4gICAgYjY0U2NyZWVuc2hvdCA9IChhd2FpdCBpbWdPYmouZ2V0QnVmZmVyKGltYWdlVXRpbC5NSU1FX1BORykpLnRvU3RyaW5nKCdiYXNlNjQnKTtcbiAgICByZXR1cm4ge2I2NFNjcmVlbnNob3QsIHNjYWxlfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAdHlwZWRlZiBJbWFnZVRlbXBsYXRlU2V0dGluZ3NcbiAgICogQHByb3BlcnR5IHtib29sZWFufSBmaXhJbWFnZVRlbXBsYXRlU2NhbGUgLSBmaXhJbWFnZVRlbXBsYXRlU2NhbGUgaW4gZGV2aWNlLXNldHRpbmdzXG4gICAqIEBwcm9wZXJ0eSB7ZmxvYXR9IGRlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGUgLSBkZWZhdWx0SW1hZ2VUZW1wbGF0ZVNjYWxlIGluIGRldmljZS1zZXR0aW5nc1xuICAgKiBAcHJvcGVydHkge2Jvb2xlYW59IGlnbm9yZURlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGUgLSBJZ25vcmUgZGVmYXVsdEltYWdlVGVtcGxhdGVTY2FsZSBpZiBpdCBoYXMgdHJ1ZS5cbiAgICogSWYgYjY0VGVtcGxhdGUgaGFzIGJlZW4gc2NhbGVkIHRvIGRlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGUgb3Igc2hvdWxkIGlnbm9yZSB0aGUgc2NhbGUsXG4gICAqIHRoaXMgcGFyYW1ldGVyIHNob3VsZCBiZSB0cnVlLiBlLmcuIGNsaWNrIGluIGltYWdlLWVsZW1lbnQgbW9kdWxlXG4gICAqIEBwcm9wZXJ0eSB7ZmxvYXR9IHhTY2FsZSAtIFNjYWxlIHJhdGlvIGZvciB3aWR0aFxuICAgKiBAcHJvcGVydHkge2Zsb2F0fSB5U2NhbGUgLSBTY2FsZSByYXRpbyBmb3IgaGVpZ2h0XG5cbiAgICovXG4gIC8qKlxuICAgKiBHZXQgYSBpbWFnZSB0aGF0IHdpbGwgYmUgdXNlZCBmb3IgdGVtcGxhdGUgbWFjaGluZy5cbiAgICogUmV0dXJucyBzY2FsZWQgaW1hZ2UgaWYgc2NhbGUgcmF0aW8gaXMgcHJvdmlkZWQuXG4gICAqXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBiNjRUZW1wbGF0ZSAtIGJhc2U2NC1lbmNvZGVkIGltYWdlIHVzZWQgYXMgYSB0ZW1wbGF0ZSB0byBiZVxuICAgKiBtYXRjaGVkIGluIHRoZSBzY3JlZW5zaG90XG4gICAqIEBwYXJhbSB7SW1hZ2VUZW1wbGF0ZVNldHRpbmdzfSBvcHRzIC0gSW1hZ2UgdGVtcGxhdGUgc2NhbGUgcmVsYXRlZCBvcHRpb25zXG4gICAqXG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IGJhc2U2NC1lbmNvZGVkIHNjYWxlZCB0ZW1wbGF0ZSBzY3JlZW5zaG90XG4gICAqL1xuICBhc3luYyBmaXhJbWFnZVRlbXBsYXRlU2NhbGUgKGI2NFRlbXBsYXRlLCBvcHRzID0ge30pIHtcbiAgICBpZiAoIW9wdHMpIHtcbiAgICAgIHJldHVybiBiNjRUZW1wbGF0ZTtcbiAgICB9XG5cbiAgICBsZXQge1xuICAgICAgZml4SW1hZ2VUZW1wbGF0ZVNjYWxlID0gZmFsc2UsXG4gICAgICBkZWZhdWx0SW1hZ2VUZW1wbGF0ZVNjYWxlID0gREVGQVVMVF9URU1QTEFURV9JTUFHRV9TQ0FMRSxcbiAgICAgIGlnbm9yZURlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGUgPSBmYWxzZSxcbiAgICAgIHhTY2FsZSA9IERFRkFVTFRfRklYX0lNQUdFX1RFTVBMQVRFX1NDQUxFLFxuICAgICAgeVNjYWxlID0gREVGQVVMVF9GSVhfSU1BR0VfVEVNUExBVEVfU0NBTEVcbiAgICB9ID0gb3B0cztcblxuICAgIGlmIChpZ25vcmVEZWZhdWx0SW1hZ2VUZW1wbGF0ZVNjYWxlKSB7XG4gICAgICBkZWZhdWx0SW1hZ2VUZW1wbGF0ZVNjYWxlID0gREVGQVVMVF9URU1QTEFURV9JTUFHRV9TQ0FMRTtcbiAgICB9XG5cbiAgICAvLyBEZWZhdWx0XG4gICAgaWYgKGRlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGUgPT09IERFRkFVTFRfVEVNUExBVEVfSU1BR0VfU0NBTEUgJiYgIWZpeEltYWdlVGVtcGxhdGVTY2FsZSkge1xuICAgICAgcmV0dXJuIGI2NFRlbXBsYXRlO1xuICAgIH1cblxuICAgIC8vIENhbGN1bGF0ZSB4U2NhbGUgYW5kIHlTY2FsZSBBcHBpdW0gc2hvdWxkIHNjYWxlXG4gICAgaWYgKGZpeEltYWdlVGVtcGxhdGVTY2FsZSkge1xuICAgICAgeFNjYWxlICo9IGRlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGU7XG4gICAgICB5U2NhbGUgKj0gZGVmYXVsdEltYWdlVGVtcGxhdGVTY2FsZTtcbiAgICB9IGVsc2Uge1xuICAgICAgeFNjYWxlID0geVNjYWxlID0gMSAqIGRlZmF1bHRJbWFnZVRlbXBsYXRlU2NhbGU7XG4gICAgfVxuXG4gICAgLy8geFNjYWxlIGFuZCB5U2NhbGUgY2FuIGJlIE5hTiBpZiBkZWZhdWx0SW1hZ2VUZW1wbGF0ZVNjYWxlIGlzIHN0cmluZywgZm9yIGV4YW1wbGVcbiAgICBpZiAoIXBhcnNlRmxvYXQoeFNjYWxlKSB8fCAhcGFyc2VGbG9hdCh5U2NhbGUpKSB7XG4gICAgICByZXR1cm4gYjY0VGVtcGxhdGU7XG4gICAgfVxuXG4gICAgLy8gUmV0dXJuIGlmIHRoZSBzY2FsZSBpcyBkZWZhdWx0LCAxLCB2YWx1ZVxuICAgIGlmIChNYXRoLnJvdW5kKHhTY2FsZSAqIEZMT0FUX1BSRUNJU0lPTikgPT09IE1hdGgucm91bmQoREVGQVVMVF9GSVhfSU1BR0VfVEVNUExBVEVfU0NBTEUgKiBGTE9BVF9QUkVDSVNJT04pXG4gICAgICAgICYmIE1hdGgucm91bmQoeVNjYWxlICogRkxPQVRfUFJFQ0lTSU9OID09PSBNYXRoLnJvdW5kKERFRkFVTFRfRklYX0lNQUdFX1RFTVBMQVRFX1NDQUxFICogRkxPQVRfUFJFQ0lTSU9OKSkpIHtcbiAgICAgIHJldHVybiBiNjRUZW1wbGF0ZTtcbiAgICB9XG5cbiAgICBsZXQgaW1nVGVtcE9iaiA9IGF3YWl0IGltYWdlVXRpbC5nZXRKaW1wSW1hZ2UoYjY0VGVtcGxhdGUpO1xuICAgIGxldCB7d2lkdGg6IGJhc2VUZW1wV2lkdGgsIGhlaWdodDogYmFzZVRlbXBIZWlnaH0gPSBpbWdUZW1wT2JqLmJpdG1hcDtcblxuICAgIGNvbnN0IHNjYWxlZFdpZHRoID0gYmFzZVRlbXBXaWR0aCAqIHhTY2FsZTtcbiAgICBjb25zdCBzY2FsZWRIZWlnaHQgPSBiYXNlVGVtcEhlaWdoICogeVNjYWxlO1xuICAgIGxvZy5pbmZvKGBTY2FsaW5nIHRlbXBsYXRlIGltYWdlIGZyb20gJHtiYXNlVGVtcFdpZHRofXgke2Jhc2VUZW1wSGVpZ2h9YCArXG4gICAgICAgICAgICAgIGAgdG8gJHtzY2FsZWRXaWR0aH14JHtzY2FsZWRIZWlnaHR9YCk7XG4gICAgbG9nLmluZm8oYFRoZSByYXRpbyBpcyAke3hTY2FsZX0gYW5kICR7eVNjYWxlfWApO1xuICAgIGltZ1RlbXBPYmogPSBhd2FpdCBpbWdUZW1wT2JqLnJlc2l6ZShzY2FsZWRXaWR0aCwgc2NhbGVkSGVpZ2h0KTtcbiAgICByZXR1cm4gKGF3YWl0IGltZ1RlbXBPYmouZ2V0QnVmZmVyKGltYWdlVXRpbC5NSU1FX1BORykpLnRvU3RyaW5nKCdiYXNlNjQnKTtcbiAgfVxufVxuXG5leHBvcnQgeyBXM0NfRUxFTUVOVF9LRVksIE1KU09OV1BfRUxFTUVOVF9LRVksIERFRkFVTFRfU0VUVElOR1MsIERFRkFVTFRfRklYX0lNQUdFX1RFTVBMQVRFX1NDQUxFIH07XG4iXX0=