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