image-util.js
71.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.cropBase64Image = cropBase64Image;
exports.base64ToImage = base64ToImage;
exports.imageToBase64 = imageToBase64;
exports.cropImage = cropImage;
exports.getImagesMatches = getImagesMatches;
exports.getImagesSimilarity = getImagesSimilarity;
exports.getImageOccurrence = getImageOccurrence;
exports.getJimpImage = getJimpImage;
exports.MIME_BMP = exports.MIME_PNG = exports.MIME_JPEG = void 0;
require("source-map-support/register");
var _lodash = _interopRequireDefault(require("lodash"));
var _jimp = _interopRequireDefault(require("jimp"));
var _buffer = require("buffer");
var _pngjs = require("pngjs");
var _bluebird = _interopRequireDefault(require("bluebird"));
var _util = require("./util");
var _logger = _interopRequireDefault(require("./logger"));
var _node = require("./node");
const {
MIME_JPEG,
MIME_PNG,
MIME_BMP
} = _jimp.default;
exports.MIME_BMP = MIME_BMP;
exports.MIME_PNG = MIME_PNG;
exports.MIME_JPEG = MIME_JPEG;
let cv = null;
const BYTES_IN_PIXEL_BLOCK = 4;
const SCANLINE_FILTER_METHOD = 4;
const DEFAULT_MATCH_THRESHOLD = 0.5;
const MATCH_NEIGHBOUR_THRESHOLD = 10;
const AVAILABLE_DETECTORS = ['AKAZE', 'AGAST', 'BRISK', 'FAST', 'GFTT', 'KAZE', 'MSER', 'SIFT', 'ORB'];
const AVAILABLE_MATCHING_FUNCTIONS = ['FlannBased', 'BruteForce', 'BruteForceL1', 'BruteForceHamming', 'BruteForceHammingLut', 'BruteForceSL2'];
const MATCHING_METHODS = ['TM_CCOEFF', 'TM_CCOEFF_NORMED', 'TM_CCORR', 'TM_CCORR_NORMED', 'TM_SQDIFF', 'TM_SQDIFF_NORMED'];
const DEFAULT_MATCHING_METHOD = 'TM_CCOEFF_NORMED';
function toMatchingMethod(name) {
if (!MATCHING_METHODS.includes(name)) {
throw new Error(`The matching method '${name}' is unknown. ` + `Only the following matching methods are supported: ${MATCHING_METHODS}`);
}
return cv[name];
}
async function getJimpImage(data) {
return await new _bluebird.default((resolve, reject) => {
if (!_lodash.default.isString(data) && !_lodash.default.isBuffer(data)) {
return reject(new Error('Must initialize jimp object with string or buffer'));
}
if (_lodash.default.isString(data)) {
data = _buffer.Buffer.from(data, 'base64');
}
new _jimp.default(data, (err, imgObj) => {
if (err) {
return reject(err);
}
if (!imgObj) {
return reject(new Error('Could not create jimp image from that data'));
}
imgObj._getBuffer = imgObj.getBuffer.bind(imgObj);
imgObj.getBuffer = _bluebird.default.promisify(imgObj._getBuffer, {
context: imgObj
});
resolve(imgObj);
});
});
}
async function initOpenCV() {
if (cv) {
return;
}
_logger.default.debug(`Initializing opencv`);
try {
cv = await (0, _node.requirePackage)('opencv4nodejs');
} catch (err) {
_logger.default.warn(`Unable to load 'opencv4nodejs': ${err.message}`);
}
if (!cv) {
throw new Error(`'opencv4nodejs' module is required to use OpenCV features. ` + `Please install it first ('npm i -g opencv4nodejs') and restart Appium. ` + 'Read https://github.com/justadudewhohacks/opencv4nodejs#how-to-install for more details on this topic.');
}
}
async function detectAndCompute(img, detector) {
const keyPoints = await detector.detectAsync(img);
const descriptor = await detector.computeAsync(img, keyPoints);
return {
keyPoints,
descriptor
};
}
function calculateMatchedRect(matchedPoints) {
if (matchedPoints.length < 2) {
return {
x: 0,
y: 0,
width: 0,
height: 0
};
}
const pointsSortedByDistance = matchedPoints.map(point => [Math.sqrt(point.x * point.x + point.y * point.y), point]).sort((pair1, pair2) => pair1[0] >= pair2[0]).map(pair => pair[1]);
const firstPoint = _lodash.default.head(pointsSortedByDistance);
const lastPoint = _lodash.default.last(pointsSortedByDistance);
const topLeftPoint = {
x: firstPoint.x <= lastPoint.x ? firstPoint.x : lastPoint.x,
y: firstPoint.y <= lastPoint.y ? firstPoint.y : lastPoint.y
};
const bottomRightPoint = {
x: firstPoint.x >= lastPoint.x ? firstPoint.x : lastPoint.x,
y: firstPoint.y >= lastPoint.y ? firstPoint.y : lastPoint.y
};
return {
x: topLeftPoint.x,
y: topLeftPoint.y,
width: bottomRightPoint.x - topLeftPoint.x,
height: bottomRightPoint.y - topLeftPoint.y
};
}
function highlightRegion(mat, region) {
if (region.width <= 0 || region.height <= 0) {
return;
}
const color = new cv.Vec(0, 0, 255);
const thickness = 2;
mat.drawRectangle(new cv.Rect(region.x, region.y, region.width, region.height), color, thickness, cv.LINE_8);
return mat;
}
async function getImagesMatches(img1Data, img2Data, options = {}) {
await initOpenCV();
const {
detectorName = 'ORB',
visualize = false,
goodMatchesFactor,
matchFunc = 'BruteForce'
} = options;
if (!_lodash.default.includes(AVAILABLE_DETECTORS, detectorName)) {
throw new Error(`'${detectorName}' detector is unknown. ` + `Only ${JSON.stringify(AVAILABLE_DETECTORS)} detectors are supported.`);
}
if (!_lodash.default.includes(AVAILABLE_MATCHING_FUNCTIONS, matchFunc)) {
throw new Error(`'${matchFunc}' matching function is unknown. ` + `Only ${JSON.stringify(AVAILABLE_MATCHING_FUNCTIONS)} matching functions are supported.`);
}
const detector = new cv[`${detectorName}Detector`]();
const [img1, img2] = await _bluebird.default.all([cv.imdecodeAsync(img1Data), cv.imdecodeAsync(img2Data)]);
const [result1, result2] = await _bluebird.default.all([detectAndCompute(img1, detector), detectAndCompute(img2, detector)]);
let matches = [];
try {
matches = await cv[`match${matchFunc}Async`](result1.descriptor, result2.descriptor);
} catch (e) {
throw new Error(`Cannot find any matches between the given images. Try another detection algorithm. ` + ` Original error: ${e}`);
}
const totalCount = matches.length;
if ((0, _util.hasValue)(goodMatchesFactor)) {
if (_lodash.default.isFunction(goodMatchesFactor)) {
const distances = matches.map(match => match.distance);
const minDistance = _lodash.default.min(distances);
const maxDistance = _lodash.default.max(distances);
matches = matches.filter(match => goodMatchesFactor(match.distance, minDistance, maxDistance));
} else {
if (matches.length > goodMatchesFactor) {
matches = matches.sort((match1, match2) => match1.distance - match2.distance).slice(0, goodMatchesFactor);
}
}
}
const extractPoint = (keyPoints, indexPropertyName) => match => {
const {
pt,
point
} = keyPoints[match[indexPropertyName]];
return pt || point;
};
const points1 = matches.map(extractPoint(result1.keyPoints, 'queryIdx'));
const rect1 = calculateMatchedRect(points1);
const points2 = matches.map(extractPoint(result2.keyPoints, 'trainIdx'));
const rect2 = calculateMatchedRect(points2);
const result = {
points1,
rect1,
points2,
rect2,
totalCount,
count: matches.length
};
if (visualize) {
const visualization = cv.drawMatches(img1, img2, result1.keyPoints, result2.keyPoints, matches);
highlightRegion(visualization, rect1);
highlightRegion(visualization, {
x: img1.cols + rect2.x,
y: rect2.y,
width: rect2.width,
height: rect2.height
});
result.visualization = await cv.imencodeAsync('.png', visualization);
}
return result;
}
async function getImagesSimilarity(img1Data, img2Data, options = {}) {
await initOpenCV();
const {
method = DEFAULT_MATCHING_METHOD,
visualize = false
} = options;
let [template, reference] = await _bluebird.default.all([cv.imdecodeAsync(img1Data), cv.imdecodeAsync(img2Data)]);
if (template.rows !== reference.rows || template.cols !== reference.cols) {
throw new Error('Both images are expected to have the same size in order to ' + 'calculate the similarity score.');
}
[template, reference] = await _bluebird.default.all([template.convertToAsync(cv.CV_8UC3), reference.convertToAsync(cv.CV_8UC3)]);
let matched;
try {
matched = await reference.matchTemplateAsync(template, toMatchingMethod(method));
} catch (e) {
throw new Error(`The reference image did not match to the template one. Original error: ${e.message}`);
}
const minMax = await matched.minMaxLocAsync();
const result = {
score: minMax.maxVal
};
if (visualize) {
const resultMat = new cv.Mat(template.rows, template.cols * 2, cv.CV_8UC3);
await _bluebird.default.all([reference.copyToAsync(resultMat.getRegion(new cv.Rect(0, 0, reference.cols, reference.rows))), template.copyToAsync(resultMat.getRegion(new cv.Rect(reference.cols, 0, template.cols, template.rows)))]);
let mask = reference.absdiff(template);
mask = await mask.cvtColorAsync(cv.COLOR_BGR2GRAY);
let contours = [];
try {
mask = await mask.thresholdAsync(128, 255, cv.THRESH_BINARY | cv.THRESH_OTSU);
contours = await mask.findContoursAsync(cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE);
} catch (ign) {}
for (const contour of contours) {
const boundingRect = contour.boundingRect();
highlightRegion(resultMat, boundingRect);
highlightRegion(resultMat, {
x: reference.cols + boundingRect.x,
y: boundingRect.y,
width: boundingRect.width,
height: boundingRect.height
});
}
result.visualization = await cv.imencodeAsync('.png', resultMat);
}
return result;
}
async function getImageOccurrence(fullImgData, partialImgData, options = {}) {
await initOpenCV();
const {
visualize = false,
threshold = DEFAULT_MATCH_THRESHOLD,
multiple = false,
matchNeighbourThreshold = MATCH_NEIGHBOUR_THRESHOLD,
method = DEFAULT_MATCHING_METHOD
} = options;
const [fullImg, partialImg] = await _bluebird.default.all([cv.imdecodeAsync(fullImgData), cv.imdecodeAsync(partialImgData)]);
const results = [];
let visualization = null;
try {
const matched = await fullImg.matchTemplateAsync(partialImg, toMatchingMethod(method));
const minMax = await matched.minMaxLocAsync();
if (multiple) {
const nonZeroMatchResults = matched.threshold(threshold, 1, cv.THRESH_BINARY).convertTo(cv.CV_8U).findNonZero();
const matches = filterNearMatches(nonZeroMatchResults, matchNeighbourThreshold);
for (const {
x,
y
} of matches) {
results.push({
score: matched.at(y, x),
rect: {
x,
y,
width: partialImg.cols,
height: partialImg.rows
}
});
}
} else if (minMax.maxVal >= threshold) {
const {
x,
y
} = method.includes('SQDIFF') ? minMax.minLoc : minMax.maxLoc;
results.push({
score: minMax.maxVal,
rect: {
x,
y,
width: partialImg.cols,
height: partialImg.rows
}
});
}
if (_lodash.default.isEmpty(results)) {
throw new Error(`Match threshold: ${threshold}. Highest match value ` + `found was ${minMax.maxVal}`);
}
} catch (e) {
throw new Error(`Cannot find any occurrences of the partial image in the full image. ` + `Original error: ${e.message}`);
}
if (visualize) {
const fullHighlightedImage = fullImg.copy();
for (const result of results) {
const singleHighlightedImage = fullImg.copy();
highlightRegion(singleHighlightedImage, result.rect);
highlightRegion(fullHighlightedImage, result.rect);
result.visualization = await cv.imencodeAsync('.png', singleHighlightedImage);
}
visualization = await cv.imencodeAsync('.png', fullHighlightedImage);
}
return {
rect: results[0].rect,
score: results[0].score,
visualization,
multiple: results
};
}
function filterNearMatches(nonZeroMatchResults, matchNeighbourThreshold) {
return nonZeroMatchResults.reduce((acc, element) => {
if (!acc.some(match => distance(match, element) <= matchNeighbourThreshold)) {
acc.push(element);
}
return acc;
}, []);
}
function distance(point1, point2) {
const a2 = Math.pow(point1.x - point2.x, 2);
const b2 = Math.pow(point1.y - point2.y, 2);
return Math.sqrt(a2 + b2);
}
async function cropBase64Image(base64Image, rect) {
const image = await base64ToImage(base64Image);
cropImage(image, rect);
return await imageToBase64(image);
}
async function base64ToImage(base64Image) {
const imageBuffer = _buffer.Buffer.from(base64Image, 'base64');
return await new _bluebird.default((resolve, reject) => {
const image = new _pngjs.PNG({
filterType: SCANLINE_FILTER_METHOD
});
image.parse(imageBuffer, (err, image) => {
if (err) {
return reject(err);
}
resolve(image);
});
});
}
async function imageToBase64(image) {
return await new _bluebird.default((resolve, reject) => {
const chunks = [];
image.pack().on('data', chunk => chunks.push(chunk)).on('end', () => {
resolve(_buffer.Buffer.concat(chunks).toString('base64'));
}).on('error', err => {
reject(err);
});
});
}
function cropImage(image, rect) {
const imageRect = {
width: image.width,
height: image.height
};
const interRect = getRectIntersection(rect, imageRect);
if (interRect.width < rect.width || interRect.height < rect.height) {
throw new Error(`Cannot crop ${JSON.stringify(rect)} from ${JSON.stringify(imageRect)} because the intersection between them was not the size of the rect`);
}
const firstVerticalPixel = interRect.top;
const lastVerticalPixel = interRect.top + interRect.height;
const firstHorizontalPixel = interRect.left;
const lastHorizontalPixel = interRect.left + interRect.width;
const croppedArray = [];
for (let y = firstVerticalPixel; y < lastVerticalPixel; y++) {
for (let x = firstHorizontalPixel; x < lastHorizontalPixel; x++) {
const firstByteIdxInPixelBlock = imageRect.width * y + x << 2;
for (let byteIdx = 0; byteIdx < BYTES_IN_PIXEL_BLOCK; byteIdx++) {
croppedArray.push(image.data[firstByteIdxInPixelBlock + byteIdx]);
}
}
}
image.data = _buffer.Buffer.from(croppedArray);
image.width = interRect.width;
image.height = interRect.height;
return image;
}
function getRectIntersection(rect, imageSize) {
const left = rect.left >= imageSize.width ? imageSize.width : rect.left;
const top = rect.top >= imageSize.height ? imageSize.height : rect.top;
const width = imageSize.width >= left + rect.width ? rect.width : imageSize.width - left;
const height = imageSize.height >= top + rect.height ? rect.height : imageSize.height - top;
return {
left,
top,
width,
height
};
}require('source-map-support').install();
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImxpYi9pbWFnZS11dGlsLmpzIl0sIm5hbWVzIjpbIk1JTUVfSlBFRyIsIk1JTUVfUE5HIiwiTUlNRV9CTVAiLCJKaW1wIiwiY3YiLCJCWVRFU19JTl9QSVhFTF9CTE9DSyIsIlNDQU5MSU5FX0ZJTFRFUl9NRVRIT0QiLCJERUZBVUxUX01BVENIX1RIUkVTSE9MRCIsIk1BVENIX05FSUdIQk9VUl9USFJFU0hPTEQiLCJBVkFJTEFCTEVfREVURUNUT1JTIiwiQVZBSUxBQkxFX01BVENISU5HX0ZVTkNUSU9OUyIsIk1BVENISU5HX01FVEhPRFMiLCJERUZBVUxUX01BVENISU5HX01FVEhPRCIsInRvTWF0Y2hpbmdNZXRob2QiLCJuYW1lIiwiaW5jbHVkZXMiLCJFcnJvciIsImdldEppbXBJbWFnZSIsImRhdGEiLCJCIiwicmVzb2x2ZSIsInJlamVjdCIsIl8iLCJpc1N0cmluZyIsImlzQnVmZmVyIiwiQnVmZmVyIiwiZnJvbSIsImVyciIsImltZ09iaiIsIl9nZXRCdWZmZXIiLCJnZXRCdWZmZXIiLCJiaW5kIiwicHJvbWlzaWZ5IiwiY29udGV4dCIsImluaXRPcGVuQ1YiLCJsb2ciLCJkZWJ1ZyIsIndhcm4iLCJtZXNzYWdlIiwiZGV0ZWN0QW5kQ29tcHV0ZSIsImltZyIsImRldGVjdG9yIiwia2V5UG9pbnRzIiwiZGV0ZWN0QXN5bmMiLCJkZXNjcmlwdG9yIiwiY29tcHV0ZUFzeW5jIiwiY2FsY3VsYXRlTWF0Y2hlZFJlY3QiLCJtYXRjaGVkUG9pbnRzIiwibGVuZ3RoIiwieCIsInkiLCJ3aWR0aCIsImhlaWdodCIsInBvaW50c1NvcnRlZEJ5RGlzdGFuY2UiLCJtYXAiLCJwb2ludCIsIk1hdGgiLCJzcXJ0Iiwic29ydCIsInBhaXIxIiwicGFpcjIiLCJwYWlyIiwiZmlyc3RQb2ludCIsImhlYWQiLCJsYXN0UG9pbnQiLCJsYXN0IiwidG9wTGVmdFBvaW50IiwiYm90dG9tUmlnaHRQb2ludCIsImhpZ2hsaWdodFJlZ2lvbiIsIm1hdCIsInJlZ2lvbiIsImNvbG9yIiwiVmVjIiwidGhpY2tuZXNzIiwiZHJhd1JlY3RhbmdsZSIsIlJlY3QiLCJMSU5FXzgiLCJnZXRJbWFnZXNNYXRjaGVzIiwiaW1nMURhdGEiLCJpbWcyRGF0YSIsIm9wdGlvbnMiLCJkZXRlY3Rvck5hbWUiLCJ2aXN1YWxpemUiLCJnb29kTWF0Y2hlc0ZhY3RvciIsIm1hdGNoRnVuYyIsIkpTT04iLCJzdHJpbmdpZnkiLCJpbWcxIiwiaW1nMiIsImFsbCIsImltZGVjb2RlQXN5bmMiLCJyZXN1bHQxIiwicmVzdWx0MiIsIm1hdGNoZXMiLCJlIiwidG90YWxDb3VudCIsImlzRnVuY3Rpb24iLCJkaXN0YW5jZXMiLCJtYXRjaCIsImRpc3RhbmNlIiwibWluRGlzdGFuY2UiLCJtaW4iLCJtYXhEaXN0YW5jZSIsIm1heCIsImZpbHRlciIsIm1hdGNoMSIsIm1hdGNoMiIsInNsaWNlIiwiZXh0cmFjdFBvaW50IiwiaW5kZXhQcm9wZXJ0eU5hbWUiLCJwdCIsInBvaW50czEiLCJyZWN0MSIsInBvaW50czIiLCJyZWN0MiIsInJlc3VsdCIsImNvdW50IiwidmlzdWFsaXphdGlvbiIsImRyYXdNYXRjaGVzIiwiY29scyIsImltZW5jb2RlQXN5bmMiLCJnZXRJbWFnZXNTaW1pbGFyaXR5IiwibWV0aG9kIiwidGVtcGxhdGUiLCJyZWZlcmVuY2UiLCJyb3dzIiwiY29udmVydFRvQXN5bmMiLCJDVl84VUMzIiwibWF0Y2hlZCIsIm1hdGNoVGVtcGxhdGVBc3luYyIsIm1pbk1heCIsIm1pbk1heExvY0FzeW5jIiwic2NvcmUiLCJtYXhWYWwiLCJyZXN1bHRNYXQiLCJNYXQiLCJjb3B5VG9Bc3luYyIsImdldFJlZ2lvbiIsIm1hc2siLCJhYnNkaWZmIiwiY3Z0Q29sb3JBc3luYyIsIkNPTE9SX0JHUjJHUkFZIiwiY29udG91cnMiLCJ0aHJlc2hvbGRBc3luYyIsIlRIUkVTSF9CSU5BUlkiLCJUSFJFU0hfT1RTVSIsImZpbmRDb250b3Vyc0FzeW5jIiwiUkVUUl9FWFRFUk5BTCIsIkNIQUlOX0FQUFJPWF9TSU1QTEUiLCJpZ24iLCJjb250b3VyIiwiYm91bmRpbmdSZWN0IiwiZ2V0SW1hZ2VPY2N1cnJlbmNlIiwiZnVsbEltZ0RhdGEiLCJwYXJ0aWFsSW1nRGF0YSIsInRocmVzaG9sZCIsIm11bHRpcGxlIiwibWF0Y2hOZWlnaGJvdXJUaHJlc2hvbGQiLCJmdWxsSW1nIiwicGFydGlhbEltZyIsInJlc3VsdHMiLCJub25aZXJvTWF0Y2hSZXN1bHRzIiwiY29udmVydFRvIiwiQ1ZfOFUiLCJmaW5kTm9uWmVybyIsImZpbHRlck5lYXJNYXRjaGVzIiwicHVzaCIsImF0IiwicmVjdCIsIm1pbkxvYyIsIm1heExvYyIsImlzRW1wdHkiLCJmdWxsSGlnaGxpZ2h0ZWRJbWFnZSIsImNvcHkiLCJzaW5nbGVIaWdobGlnaHRlZEltYWdlIiwicmVkdWNlIiwiYWNjIiwiZWxlbWVudCIsInNvbWUiLCJwb2ludDEiLCJwb2ludDIiLCJhMiIsInBvdyIsImIyIiwiY3JvcEJhc2U2NEltYWdlIiwiYmFzZTY0SW1hZ2UiLCJpbWFnZSIsImJhc2U2NFRvSW1hZ2UiLCJjcm9wSW1hZ2UiLCJpbWFnZVRvQmFzZTY0IiwiaW1hZ2VCdWZmZXIiLCJQTkciLCJmaWx0ZXJUeXBlIiwicGFyc2UiLCJjaHVua3MiLCJwYWNrIiwib24iLCJjaHVuayIsImNvbmNhdCIsInRvU3RyaW5nIiwiaW1hZ2VSZWN0IiwiaW50ZXJSZWN0IiwiZ2V0UmVjdEludGVyc2VjdGlvbiIsImZpcnN0VmVydGljYWxQaXhlbCIsInRvcCIsImxhc3RWZXJ0aWNhbFBpeGVsIiwiZmlyc3RIb3Jpem9udGFsUGl4ZWwiLCJsZWZ0IiwibGFzdEhvcml6b250YWxQaXhlbCIsImNyb3BwZWRBcnJheSIsImZpcnN0Qnl0ZUlkeEluUGl4ZWxCbG9jayIsImJ5dGVJZHgiLCJpbWFnZVNpemUiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFHQSxNQUFNO0FBQUVBLEVBQUFBLFNB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QUNySixNQUF6QjtBQUNBLFNBQU9zSSxLQUFQO0FBQ0Q7O0FBRUQsU0FBU2dCLG1CQUFULENBQThCbEMsSUFBOUIsRUFBb0M0QyxTQUFwQyxFQUErQztBQUM3QyxRQUFNTCxJQUFJLEdBQUd2QyxJQUFJLENBQUN1QyxJQUFMLElBQWFLLFNBQVMsQ0FBQ2pLLEtBQXZCLEdBQStCaUssU0FBUyxDQUFDakssS0FBekMsR0FBaURxSCxJQUFJLENBQUN1QyxJQUFuRTtBQUNBLFFBQU1ILEdBQUcsR0FBR3BDLElBQUksQ0FBQ29DLEdBQUwsSUFBWVEsU0FBUyxDQUFDaEssTUFBdEIsR0FBK0JnSyxTQUFTLENBQUNoSyxNQUF6QyxHQUFrRG9ILElBQUksQ0FBQ29DLEdBQW5FO0FBQ0EsUUFBTXpKLEtBQUssR0FBR2lLLFNBQVMsQ0FBQ2pLLEtBQVYsSUFBb0I0SixJQUFJLEdBQUd2QyxJQUFJLENBQUNySCxLQUFoQyxHQUF5Q3FILElBQUksQ0FBQ3JILEtBQTlDLEdBQXVEaUssU0FBUyxDQUFDakssS0FBVixHQUFrQjRKLElBQXZGO0FBQ0EsUUFBTTNKLE1BQU0sR0FBR2dLLFNBQVMsQ0FBQ2hLLE1BQVYsSUFBcUJ3SixHQUFHLEdBQUdwQyxJQUFJLENBQUNwSCxNQUFoQyxHQUEwQ29ILElBQUksQ0FBQ3BILE1BQS9DLEdBQXlEZ0ssU0FBUyxDQUFDaEssTUFBVixHQUFtQndKLEdBQTNGO0FBQ0EsU0FBTztBQUFDRyxJQUFBQSxJQUFEO0FBQU9ILElBQUFBLEdBQVA7QUFBWXpKLElBQUFBLEtBQVo7QUFBbUJDLElBQUFBO0FBQW5CLEdBQVA7QUFDRCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBfIGZyb20gJ2xvZGFzaCc7XG5pbXBvcnQgSmltcCBmcm9tICdqaW1wJztcbmltcG9ydCB7IEJ1ZmZlciB9IGZyb20gJ2J1ZmZlcic7XG5pbXBvcnQgeyBQTkcgfSBmcm9tICdwbmdqcyc7XG5pbXBvcnQgQiBmcm9tICdibHVlYmlyZCc7XG5pbXBvcnQgeyBoYXNWYWx1ZSB9IGZyb20gJy4vdXRpbCc7XG5pbXBvcnQgbG9nIGZyb20gJy4vbG9nZ2VyJztcbmltcG9ydCB7IHJlcXVpcmVQYWNrYWdlIH0gZnJvbSAnLi9ub2RlJztcblxuXG5jb25zdCB7IE1JTUVfSlBFRywgTUlNRV9QTkcsIE1JTUVfQk1QIH0gPSBKaW1wO1xubGV0IGN2ID0gbnVsbDtcblxuLyoqXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBSZWdpb25cbiAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBsZWZ0IC0gVGhlIG9mZnNldCBmcm9tIHRoZSBsZWZ0IHNpZGVcbiAqIEBwcm9wZXJ0eSB7bnVtYmVyfSB0b3AgLSBUaGUgb2Zmc2V0IGZyb20gdGhlIHRvcFxuICogQHByb3BlcnR5IHtudW1iZXJ9IHdpZHRoIC0gVGhlIHdpZHRoXG4gKiBAcHJvcGVydHkge251bWJlcn0gaGVpZ2h0IC0gVGhlIGhlaWdodFxuICovXG5cbi8qKlxuICogQHR5cGVkZWYge09iamVjdH0gUG9pbnRcbiAqIEBwcm9wZXJ0eSB7bnVtYmVyfSB4IC0gVGhlIHggY29vcmRpbmF0ZVxuICogQHByb3BlcnR5IHtudW1iZXJ9IHkgLSBUaGUgeSBjb29yZGluYXRlXG4gKi9cblxuLyoqXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBSZWN0XG4gKiBAcHJvcGVydHkge251bWJlcn0geCAtIFRoZSB0b3AgbGVmdCBjb29yZGluYXRlXG4gKiBAcHJvcGVydHkge251bWJlcn0geSAtIFRoZSBib3R0b20gcmlnaHQgY29vcmRpbmF0ZVxuICogQHByb3BlcnR5IHtudW1iZXJ9IHdpZHRoIC0gVGhlIHdpZHRoXG4gKiBAcHJvcGVydHkge251bWJlcn0gaGVpZ2h0IC0gVGhlIGhlaWdodFxuICovXG5cbmNvbnN0IEJZVEVTX0lOX1BJWEVMX0JMT0NLID0gNDtcbmNvbnN0IFNDQU5MSU5FX0ZJTFRFUl9NRVRIT0QgPSA0O1xuY29uc3QgREVGQVVMVF9NQVRDSF9USFJFU0hPTEQgPSAwLjU7XG5jb25zdCBNQVRDSF9ORUlHSEJPVVJfVEhSRVNIT0xEID0gMTA7XG5cbmNvbnN0IEFWQUlMQUJMRV9ERVRFQ1RPUlMgPSBbXG4gICdBS0FaRScsXG4gICdBR0FTVCcsXG4gICdCUklTSycsXG4gICdGQVNUJyxcbiAgJ0dGVFQnLFxuICAnS0FaRScsXG4gICdNU0VSJyxcbiAgJ1NJRlQnLFxuICAnT1JCJyxcbl07XG5cbmNvbnN0IEFWQUlMQUJMRV9NQVRDSElOR19GVU5DVElPTlMgPSBbXG4gICdGbGFubkJhc2VkJyxcbiAgJ0JydXRlRm9yY2UnLFxuICAnQnJ1dGVGb3JjZUwxJyxcbiAgJ0JydXRlRm9yY2VIYW1taW5nJyxcbiAgJ0JydXRlRm9yY2VIYW1taW5nTHV0JyxcbiAgJ0JydXRlRm9yY2VTTDInLFxuXTtcblxuY29uc3QgTUFUQ0hJTkdfTUVUSE9EUyA9IFtcbiAgJ1RNX0NDT0VGRicsXG4gICdUTV9DQ09FRkZfTk9STUVEJyxcbiAgJ1RNX0NDT1JSJyxcbiAgJ1RNX0NDT1JSX05PUk1FRCcsXG4gICdUTV9TUURJRkYnLFxuICAnVE1fU1FESUZGX05PUk1FRCcsXG5dO1xuY29uc3QgREVGQVVMVF9NQVRDSElOR19NRVRIT0QgPSAnVE1fQ0NPRUZGX05PUk1FRCc7XG5cbi8qKlxuICogVHJhbnNmb3JtcyBtYXRjaGluZyBtZXRob2QgbmFtZSB0byB0aGUgYWN0dWFsXG4gKiBjb25zdGFudCB2YWx1ZSBmcm9tIE9wZW5DViBsaWJyYXJ5XG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgT25lIG9mIHN1cHBvcnRlZCBtZXRob2QgbmFtZXNcbiAqIChzZWUgTUFUQ0hJTkdfTUVUSE9EUyBhcnJheSBhYm92ZSlcbiAqIEByZXR1cm5zIHtudW1iZXJ9IFRoZSBtZXRob2QgdmFsdWVcbiAqIEB0aHJvd3Mge0Vycm9yfSBpZiBhbiB1bnN1cHBvcnRlZCBtZXRob2QgbmFtZSBpcyBnaXZlblxuICovXG5mdW5jdGlvbiB0b01hdGNoaW5nTWV0aG9kIChuYW1lKSB7XG4gIGlmICghTUFUQ0hJTkdfTUVUSE9EUy5pbmNsdWRlcyhuYW1lKSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgVGhlIG1hdGNoaW5nIG1ldGhvZCAnJHtuYW1lfScgaXMgdW5rbm93bi4gYCArXG4gICAgICBgT25seSB0aGUgZm9sbG93aW5nIG1hdGNoaW5nIG1ldGhvZHMgYXJlIHN1cHBvcnRlZDogJHtNQVRDSElOR19NRVRIT0RTfWApO1xuICB9XG4gIHJldHVybiBjdltuYW1lXTtcbn1cblxuLyoqXG4gKiBVdGlsaXR5IGZ1bmN0aW9uIHRvIGdldCBhIEppbXAgaW1hZ2Ugb2JqZWN0IGZyb20gYnVmZmVyIG9yIGJhc2U2NCBkYXRhLiBKaW1wXG4gKiBpcyBhIGdyZWF0IGxpYnJhcnkgaG93ZXZlciBpdCBkb2VzIElPIGluIHRoZSBjb25zdHJ1Y3RvciBzbyBpdCdzIG5vdFxuICogY29udmVuaWVudCBmb3Igb3VyIGFzeW5jL2F3YWl0IG1vZGVsLlxuICpcbiAqIEBwYXJhbSB7QnVmZmVyfHN0cmluZ30gZGF0YSAtIGJpbmFyeSBpbWFnZSBidWZmZXIgb3IgYmFzZTY0LWVuY29kZWQgaW1hZ2VcbiAqIHN0cmluZ1xuICogQHJldHVybnMge0ppbXB9IC0gdGhlIGppbXAgaW1hZ2Ugb2JqZWN0XG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGdldEppbXBJbWFnZSAoZGF0YSkge1xuICByZXR1cm4gYXdhaXQgbmV3IEIoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIGlmICghXy5pc1N0cmluZyhkYXRhKSAmJiAhXy5pc0J1ZmZlcihkYXRhKSkge1xuICAgICAgcmV0dXJuIHJlamVjdChuZXcgRXJyb3IoJ011c3QgaW5pdGlhbGl6ZSBqaW1wIG9iamVjdCB3aXRoIHN0cmluZyBvciBidWZmZXInKSk7XG4gICAgfVxuICAgIC8vIGlmIGRhdGEgaXMgYSBzdHJpbmcsIGFzc3VtZSBpdCBpcyBhIGJhc2U2NC1lbmNvZGVkIGltYWdlXG4gICAgaWYgKF8uaXNTdHJpbmcoZGF0YSkpIHtcbiAgICAgIGRhdGEgPSBCdWZmZXIuZnJvbShkYXRhLCAnYmFzZTY0Jyk7XG4gICAgfVxuICAgIG5ldyBKaW1wKGRhdGEsIChlcnIsIGltZ09iaikgPT4ge1xuICAgICAgaWYgKGVycikge1xuICAgICAgICByZXR1cm4gcmVqZWN0KGVycik7XG4gICAgICB9XG4gICAgICBpZiAoIWltZ09iaikge1xuICAgICAgICByZXR1cm4gcmVqZWN0KG5ldyBFcnJvcignQ291bGQgbm90IGNyZWF0ZSBqaW1wIGltYWdlIGZyb20gdGhhdCBkYXRhJykpO1xuICAgICAgfVxuICAgICAgaW1nT2JqLl9nZXRCdWZmZXIgPSBpbWdPYmouZ2V0QnVmZmVyLmJpbmQoaW1nT2JqKTtcbiAgICAgIGltZ09iai5nZXRCdWZmZXIgPSBCLnByb21pc2lmeShpbWdPYmouX2dldEJ1ZmZlciwge2NvbnRleHQ6IGltZ09ian0pO1xuICAgICAgcmVzb2x2ZShpbWdPYmopO1xuICAgIH0pO1xuICB9KTtcbn1cblxuLyoqXG4gKiBAdGhyb3dzIHtFcnJvcn0gSWYgb3BlbmN2NG5vZGVqcyBtb2R1bGUgaXMgbm90IGluc3RhbGxlZCBvciBjYW5ub3QgYmUgbG9hZGVkXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGluaXRPcGVuQ1YgKCkge1xuICBpZiAoY3YpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICBsb2cuZGVidWcoYEluaXRpYWxpemluZyBvcGVuY3ZgKTtcbiAgdHJ5IHtcbiAgICBjdiA9IGF3YWl0IHJlcXVpcmVQYWNrYWdlKCdvcGVuY3Y0bm9kZWpzJyk7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGxvZy53YXJuKGBVbmFibGUgdG8gbG9hZCAnb3BlbmN2NG5vZGVqcyc6ICR7ZXJyLm1lc3NhZ2V9YCk7XG4gIH1cblxuICBpZiAoIWN2KSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGAnb3BlbmN2NG5vZGVqcycgbW9kdWxlIGlzIHJlcXVpcmVkIHRvIHVzZSBPcGVuQ1YgZmVhdHVyZXMuIGAgK1xuICAgICAgICAgICAgICAgICAgICBgUGxlYXNlIGluc3RhbGwgaXQgZmlyc3QgKCducG0gaSAtZyBvcGVuY3Y0bm9kZWpzJykgYW5kIHJlc3RhcnQgQXBwaXVtLiBgICtcbiAgICAgICAgICAgICAgICAgICAgJ1JlYWQgaHR0cHM6Ly9naXRodWIuY29tL2p1c3RhZHVkZXdob2hhY2tzL29wZW5jdjRub2RlanMjaG93LXRvLWluc3RhbGwgZm9yIG1vcmUgZGV0YWlscyBvbiB0aGlzIHRvcGljLicpO1xuICB9XG59XG5cbi8qKlxuICogQHR5cGVkZWYge09iamVjdH0gTWF0Y2hDb21wdXRhdGlvblJlc3VsdFxuICogQHByb3BlcnR5IHtjdi5EZXNjcmlwdG9yTWF0Y2h9IGRlc2NpcHRvciAtIE9wZW5DViBtYXRjaCBkZXNjcmlwdG9yXG4gKiBAcHJvcGVydHkge0FycmF5PGN2LktleVBvaW50Pn0ga2V5UG9pbnRzIC0gVGhlIGFycmF5IG9mIGtleSBwb2ludHNcbiAqL1xuXG4vKipcbiAqIENhbGN1bGF0ZXMgYW4gT3BlbkNWIG1hdGNoIGRlc2NyaXB0b3Igb2YgYW4gaW1hZ2UsIHdoaWNoIGNhbiBiZSB1c2VkXG4gKiBmb3IgYnJ1dGUtZm9yY2UgbWF0Y2hpbmcuXG4gKiBSZWFkIGh0dHBzOi8vZG9jcy5vcGVuY3Yub3JnLzMuMC1iZXRhL2RvYy9weV90dXRvcmlhbHMvcHlfZmVhdHVyZTJkL3B5X21hdGNoZXIvcHlfbWF0Y2hlci5odG1sXG4gKiBmb3IgbW9yZSBkZXRhaWxzLlxuICpcbiAqIEBwYXJhbSB7Y3YuTWF0fSBpbWcgSW1hZ2UgZGF0YVxuICogQHBhcmFtIHtjdi5GZWF0dXJlRGV0ZWN0b3J9IGRldGVjdG9yIE9wZW5DViBmZWF0dXJlIGRldGVjdG9yIGluc3RhbmNlXG4gKlxuICogQHJldHVybnMge01hdGNoQ29tcHV0YXRpb25SZXN1bHR9XG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGRldGVjdEFuZENvbXB1dGUgKGltZywgZGV0ZWN0b3IpIHtcbiAgY29uc3Qga2V5UG9pbnRzID0gYXdhaXQgZGV0ZWN0b3IuZGV0ZWN0QXN5bmMoaW1nKTtcbiAgY29uc3QgZGVzY3JpcHRvciA9IGF3YWl0IGRldGVjdG9yLmNvbXB1dGVBc3luYyhpbWcsIGtleVBvaW50cyk7XG4gIHJldHVybiB7XG4gICAga2V5UG9pbnRzLFxuICAgIGRlc2NyaXB0b3JcbiAgfTtcbn1cblxuLyoqXG4gKiBDYWxjdWxhdGVkIHRoZSBib3VuZGluZyByZWN0IGNvb3JkaW5hdGVzIGZvciB0aGUgYXJyYXkgb2YgbWF0Y2hpbmcgcG9pbnRzXG4gKlxuICogQHBhcmFtIHtBcnJheTxQb2ludD59IG1hdGNoZWRQb2ludHMgQXJyYXkgb2YgbWF0Y2hpbmcgcG9pbnRzXG4gKiBAcmV0dXJucyB7UmVjdH0gVGhlIG1hdGNoaW5nIGJvdW5kaW5nIHJlY3Qgb3IgYSB6ZXJvIHJlY3QgaWYgbm8gbWF0Y2hcbiAqIGNhbiBiZSBmb3VuZC5cbiAqL1xuZnVuY3Rpb24gY2FsY3VsYXRlTWF0Y2hlZFJlY3QgKG1hdGNoZWRQb2ludHMpIHtcbiAgaWYgKG1hdGNoZWRQb2ludHMubGVuZ3RoIDwgMikge1xuICAgIHJldHVybiB7XG4gICAgICB4OiAwLFxuICAgICAgeTogMCxcbiAgICAgIHdpZHRoOiAwLFxuICAgICAgaGVpZ2h0OiAwXG4gICAgfTtcbiAgfVxuXG4gIGNvbnN0IHBvaW50c1NvcnRlZEJ5RGlzdGFuY2UgPSBtYXRjaGVkUG9pbnRzXG4gICAgLm1hcCgocG9pbnQpID0+IFtNYXRoLnNxcnQocG9pbnQueCAqIHBvaW50LnggKyBwb2ludC55ICogcG9pbnQueSksIHBvaW50XSlcbiAgICAuc29ydCgocGFpcjEsIHBhaXIyKSA9PiBwYWlyMVswXSA+PSBwYWlyMlswXSlcbiAgICAubWFwKChwYWlyKSA9PiBwYWlyWzFdKTtcbiAgY29uc3QgZmlyc3RQb2ludCA9IF8uaGVhZChwb2ludHNTb3J0ZWRCeURpc3RhbmNlKTtcbiAgY29uc3QgbGFzdFBvaW50ID0gXy5sYXN0KHBvaW50c1NvcnRlZEJ5RGlzdGFuY2UpO1xuICBjb25zdCB0b3BMZWZ0UG9pbnQgPSB7XG4gICAgeDogZmlyc3RQb2ludC54IDw9IGxhc3RQb2ludC54ID8gZmlyc3RQb2ludC54IDogbGFzdFBvaW50LngsXG4gICAgeTogZmlyc3RQb2ludC55IDw9IGxhc3RQb2ludC55ID8gZmlyc3RQb2ludC55IDogbGFzdFBvaW50LnksXG4gIH07XG4gIGNvbnN0IGJvdHRvbVJpZ2h0UG9pbnQgPSB7XG4gICAgeDogZmlyc3RQb2ludC54ID49IGxhc3RQb2ludC54ID8gZmlyc3RQb2ludC54IDogbGFzdFBvaW50LngsXG4gICAgeTogZmlyc3RQb2ludC55ID49IGxhc3RQb2ludC55ID8gZmlyc3RQb2ludC55IDogbGFzdFBvaW50LnksXG4gIH07XG4gIHJldHVybiB7XG4gICAgeDogdG9wTGVmdFBvaW50LngsXG4gICAgeTogdG9wTGVmdFBvaW50LnksXG4gICAgd2lkdGg6IGJvdHRvbVJpZ2h0UG9pbnQueCAtIHRvcExlZnRQb2ludC54LFxuICAgIGhlaWdodDogYm90dG9tUmlnaHRQb2ludC55IC0gdG9wTGVmdFBvaW50LnlcbiAgfTtcbn1cblxuLyoqXG4gKiBEcmF3cyBhIHJlY3Rhbm5nbGUgb24gdGhlIGdpdmVuIGltYWdlIG1hdHJpeFxuICpcbiAqIEBwYXJhbSB7Y3YuTWF0fSBtYXQgVGhlIHNvdXJjZSBpbWFnZVxuICogQHBhcmFtIHtSZWN0fSByZWdpb24gVGhlIHJlZ2lvbiB0byBoaWdobGlnaHRcbiAqXG4gKiBAcmV0dXJucyB7Y3YuTWF0fSBUaGUgc2FtZSBpbWFnZSB3aXRoIHRoZSByZWN0YW5nbGUgb24gaXRcbiAqL1xuZnVuY3Rpb24gaGlnaGxpZ2h0UmVnaW9uIChtYXQsIHJlZ2lvbikge1xuICBpZiAocmVnaW9uLndpZHRoIDw9IDAgfHwgcmVnaW9uLmhlaWdodCA8PSAwKSB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgLy8gaGlnaGxpZ2h0IGluIHJlZFxuICBjb25zdCBjb2xvciA9IG5ldyBjdi5WZWMoMCwgMCwgMjU1KTtcbiAgY29uc3QgdGhpY2tuZXNzID0gMjtcbiAgbWF0LmRyYXdSZWN0YW5nbGUobmV3IGN2LlJlY3QocmVnaW9uLngsIHJlZ2lvbi55LCByZWdpb24ud2lkdGgsIHJlZ2lvbi5oZWlnaHQpLCBjb2xvciwgdGhpY2tuZXNzLCBjdi5MSU5FXzgpO1xuICByZXR1cm4gbWF0O1xufVxuXG4vKipcbiAqIEB0eXBlZGVmIHtPYmplY3R9IE1hdGNoaW5nT3B0aW9uc1xuICogQHByb3BlcnR5IHs/c3RyaW5nfSBkZXRlY3Rvck5hbWUgWydPUkInXSBPbmUgb2YgcG9zc2libGUgT3BlbkNWIGZlYXR1cmUgZGV0ZWN0b3IgbmFtZXNcbiAqIGZyb20gYEFWQUlMQUJMRV9ERVRFQ1RPUlNgIGFycmF5LlxuICogU29tZSBvZiB0aGVzZSBtZXRob2RzIChGQVNULCBBR0FTVCwgR0ZUVCwgRkFTVCwgU0lGVCBhbmQgTVNFUikgYXJlIG5vdCBhdmFpbGFibGVcbiAqIGluIHRoZSBkZWZhdWx0IE9wZW5DViBpbnN0YWxsYXRpb24gYW5kIGhhdmUgdG8gYmUgZW5hYmxlZCBtYW51YWxseSBiZWZvcmVcbiAqIGxpYnJhcnkgY29tcGlsYXRpb24uXG4gKiBAcHJvcGVydHkgez9zdHJpbmd9IG1hdGNoRnVuYyBbJ0JydXRlRm9yY2UnXSBUaGUgbmFtZSBvZiB0aGUgbWF0Y2hpbmcgZnVuY3Rpb24uXG4gKiBTaG91bGQgYmUgb25lIG9mIGBBVkFJTEFCTEVfTUFUQ0hJTkdfRlVOQ1RJT05TYCBhcnJheS5cbiAqIEBwcm9wZXJ0eSB7P251bWJlcnxGdW5jdGlvbn0gZ29vZE1hdGNoZXNGYWN0b3IgVGhlIG1heGltdW0gY291bnQgb2YgXCJnb29kXCIgbWF0Y2hlc1xuICogKGUuIGcuIHdpdGggbWluaW1hbCBkaXN0YW5jZXMpIG9yIGEgZnVuY3Rpb24sIHdoaWNoIGFjY2VwdHMgMyBhcmd1bWVudHM6IHRoZSBjdXJyZW50IGRpc3RhbmNlLFxuICogbWluaW1hbCBkaXN0YW5jZSwgbWF4aW11bSBkaXN0YW5jZSBhbmQgcmV0dXJucyB0cnVlIG9yIGZhbHNlIHRvIGluY2x1ZGUgb3IgZXhjbHVkZSB0aGUgbWF0Y2guXG4gKiBAcHJvcGVydHkgez9ib29sZWFufSB2aXN1YWxpemUgW2ZhbHNlXSBXaGV0aGVyIHRvIHJldHVybiB0aGUgcmVzdWx0aW5nIHZpc2FsaXphdGlvblxuICogYXMgYW4gaW1hZ2UgKHVzZWZ1bCBmb3IgZGVidWdnaW5nIHB1cnBvc2VzKVxuICovXG5cbi8qKlxuICogQHR5cGVkZWYge09iamVjdH0gTWF0Y2hpbmdSZXN1bHRcbiAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBjb3VudCBUaGUgY291bnQgb2YgbWF0Y2hlZCBlZGdlcyBvbiBib3RoIGltYWdlcy5cbiAqIFRoZSBtb3JlIG1hdGNoaW5nIGVkZ2VzIHRoZXJlIGFyZSBubyBib3RoIGltYWdlcyB0aGUgbW9yZSBzaW1pbGFyIHRoZXkgYXJlLlxuICogQHByb3BlcnR5IHtudW1iZXJ9IHRvdGFsQ291bnQgVGhlIHRvdGFsIGNvdW50IG9mIG1hdGNoZWQgZWRnZXMgb24gYm90aCBpbWFnZXMuXG4gKiBJdCBpcyBlcXVhbCB0byBgY291bnRgIGlmIGBnb29kTWF0Y2hlc0ZhY3RvcmAgZG9lcyBub3QgbGltaXQgdGhlIG1hdGNoZXMsXG4gKiBvdGhlcndpc2UgaXQgY29udGFpbnMgdGhlIHRvdGFsIGNvdW50IG9mIG1hdGNoZXMgYmVmb3JlIGBnb29kTWF0Y2hlc0ZhY3RvcmAgaXNcbiAqIGFwcGxpZWQuXG4gKiBAcHJvcGVydHkgez9CdWZmZXJ9IHZpc3VhbGl6YXRpb24gVGhlIHZpc3VhbGl6YXRpb24gb2YgdGhlIG1hdGNoaW5nIHJlc3VsdFxuICogcmVwcmVzZW50ZWQgYXMgUE5HIGltYWdlIGJ1ZmZlci4gVGhpcyB2aXN1YWxpemF0aW9uIGxvb2tzIGxpa2VcbiAqIGh0dHBzOi8vdXNlci1pbWFnZXMuZ2l0aHVidXNlcmNvbnRlbnQuY29tLzMxMTI1NTIxLzI5NzAyNzMxLWM3OWUzMTQyLTg5NzItMTFlNy05NDdlLWRiMTA5ZDQxNTQ2OS5qcGdcbiAqIEBwcm9wZXJ0eSB7QXJyYXk8UG9pbnQ+fSBwb2ludHMxIFRoZSBhcnJheSBvZiBtYXRjaGluZyBwb2ludHMgb24gdGhlIGZpcnN0IGltYWdlXG4gKiBAcHJvcGVydHkge1JlY3R9IHJlY3QxIFRoZSBib3VuZGluZyByZWN0IGZvciB0aGUgYG1hdGNoZWRQb2ludHMxYCBzZXQgb3IgYSB6ZXJvIHJlY3RcbiAqIGlmIG5vdCBlbm91Z2ggbWF0Y2hpbmcgcG9pbnRzIGFyZSBmb3VuZFxuICogQHByb3BlcnR5IHtBcnJheTxQb2ludD59IHBvaW50czIgVGhlIGFycmF5IG9mIG1hdGNoaW5nIHBvaW50cyBvbiB0aGUgc2Vjb25kIGltYWdlXG4gKiBAcHJvcGVydHkge1JlY3R9IHJlY3QyIFRoZSBib3VuZGluZyByZWN0IGZvciB0aGUgYG1hdGNoZWRQb2ludHMyYCBzZXQgb3IgYSB6ZXJvIHJlY3RcbiAqIGlmIG5vdCBlbm91Z2ggbWF0Y2hpbmcgcG9pbnRzIGFyZSBmb3VuZFxuICovXG5cbi8qKlxuICogQ2FsY3VsYXRlcyB0aGUgY291bnQgb2YgY29tbW9uIGVkZ2VzIGJldHdlZW4gdHdvIGltYWdlcy5cbiAqIFRoZSBpbWFnZXMgbWlnaHQgYmUgcm90YXRlZCBvciByZXNpemVkIHJlbGF0aXZlbHkgdG8gZWFjaCBvdGhlci5cbiAqXG4gKiBAcGFyYW0ge0J1ZmZlcn0gaW1nMURhdGEgVGhlIGRhdGEgb2YgdGhlIGZpcnN0IGltYWdlIHBhY2tlZCBpbnRvIGEgTm9kZUpTIGJ1ZmZlclxuICogQHBhcmFtIHtCdWZmZXJ9IGltZzJEYXRhIFRoZSBkYXRhIG9mIHRoZSBzZWNvbmQgaW1hZ2UgcGFja2VkIGludG8gYSBOb2RlSlMgYnVmZmVyXG4gKiBAcGFyYW0gez9NYXRjaGluZ09wdGlvbnN9IG9wdGlvbnMgW3t9XSBTZXQgb2YgbWF0Y2hpbmcgb3B0aW9uc1xuICpcbiAqIEByZXR1cm5zIHtNYXRjaGluZ1Jlc3VsdH0gTWFjaGluZyByZXN1bHRcbiAqIEB0aHJvd3Mge0Vycm9yfSBJZiBgZGV0ZWN0b3JOYW1lYCB2YWx1ZSBpcyB1bmtub3duLlxuICovXG5hc3luYyBmdW5jdGlvbiBnZXRJbWFnZXNNYXRjaGVzIChpbWcxRGF0YSwgaW1nMkRhdGEsIG9wdGlvbnMgPSB7fSkge1xuICBhd2FpdCBpbml0T3BlbkNWKCk7XG5cbiAgY29uc3Qge2RldGVjdG9yTmFtZSA9ICdPUkInLCB2aXN1YWxpemUgPSBmYWxzZSxcbiAgICAgICAgIGdvb2RNYXRjaGVzRmFjdG9yLCBtYXRjaEZ1bmMgPSAnQnJ1dGVGb3JjZSd9ID0gb3B0aW9ucztcbiAgaWYgKCFfLmluY2x1ZGVzKEFWQUlMQUJMRV9ERVRFQ1RPUlMsIGRldGVjdG9yTmFtZSkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYCcke2RldGVjdG9yTmFtZX0nIGRldGVjdG9yIGlzIHVua25vd24uIGAgK1xuICAgICAgICAgICAgICAgICAgICBgT25seSAke0pTT04uc3RyaW5naWZ5KEFWQUlMQUJMRV9ERVRFQ1RPUlMpfSBkZXRlY3RvcnMgYXJlIHN1cHBvcnRlZC5gKTtcbiAgfVxuICBpZiAoIV8uaW5jbHVkZXMoQVZBSUxBQkxFX01BVENISU5HX0ZVTkNUSU9OUywgbWF0Y2hGdW5jKSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgJyR7bWF0Y2hGdW5jfScgbWF0Y2hpbmcgZnVuY3Rpb24gaXMgdW5rbm93bi4gYCArXG4gICAgICAgICAgICAgICAgICAgIGBPbmx5ICR7SlNPTi5zdHJpbmdpZnkoQVZBSUxBQkxFX01BVENISU5HX0ZVTkNUSU9OUyl9IG1hdGNoaW5nIGZ1bmN0aW9ucyBhcmUgc3VwcG9ydGVkLmApO1xuICB9XG5cbiAgY29uc3QgZGV0ZWN0b3IgPSBuZXcgY3ZbYCR7ZGV0ZWN0b3JOYW1lfURldGVjdG9yYF0oKTtcbiAgY29uc3QgW2ltZzEsIGltZzJdID0gYXdhaXQgQi5hbGwoW1xuICAgIGN2LmltZGVjb2RlQXN5bmMoaW1nMURhdGEpLFxuICAgIGN2LmltZGVjb2RlQXN5bmMoaW1nMkRhdGEpXG4gIF0pO1xuICBjb25zdCBbcmVzdWx0MSwgcmVzdWx0Ml0gPSBhd2FpdCBCLmFsbChbXG4gICAgZGV0ZWN0QW5kQ29tcHV0ZShpbWcxLCBkZXRlY3RvciksXG4gICAgZGV0ZWN0QW5kQ29tcHV0ZShpbWcyLCBkZXRlY3RvcilcbiAgXSk7XG4gIGxldCBtYXRjaGVzID0gW107XG4gIHRyeSB7XG4gICAgbWF0Y2hlcyA9IGF3YWl0IGN2W2BtYXRjaCR7bWF0Y2hGdW5jfUFzeW5jYF0ocmVzdWx0MS5kZXNjcmlwdG9yLCByZXN1bHQyLmRlc2NyaXB0b3IpO1xuICB9IGNhdGNoIChlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBDYW5ub3QgZmluZCBhbnkgbWF0Y2hlcyBiZXR3ZWVuIHRoZSBnaXZlbiBpbWFnZXMuIFRyeSBhbm90aGVyIGRldGVjdGlvbiBhbGdvcml0aG0uIGAgK1xuICAgICAgICAgICAgICAgICAgICBgIE9yaWdpbmFsIGVycm9yOiAke2V9YCk7XG4gIH1cbiAgY29uc3QgdG90YWxDb3VudCA9IG1hdGNoZXMubGVuZ3RoO1xuICBpZiAoaGFzVmFsdWUoZ29vZE1hdGNoZXNGYWN0b3IpKSB7XG4gICAgaWYgKF8uaXNGdW5jdGlvbihnb29kTWF0Y2hlc0ZhY3RvcikpIHtcbiAgICAgIGNvbnN0IGRpc3RhbmNlcyA9IG1hdGNoZXMubWFwKChtYXRjaCkgPT4gbWF0Y2guZGlzdGFuY2UpO1xuICAgICAgY29uc3QgbWluRGlzdGFuY2UgPSBfLm1pbihkaXN0YW5jZXMpO1xuICAgICAgY29uc3QgbWF4RGlzdGFuY2UgPSBfLm1heChkaXN0YW5jZXMpO1xuICAgICAgbWF0Y2hlcyA9IG1hdGNoZXNcbiAgICAgICAgLmZpbHRlcigobWF0Y2gpID0+IGdvb2RNYXRjaGVzRmFjdG9yKG1hdGNoLmRpc3RhbmNlLCBtaW5EaXN0YW5jZSwgbWF4RGlzdGFuY2UpKTtcbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKG1hdGNoZXMubGVuZ3RoID4gZ29vZE1hdGNoZXNGYWN0b3IpIHtcbiAgICAgICAgbWF0Y2hlcyA9IG1hdGNoZXNcbiAgICAgICAgICAuc29ydCgobWF0Y2gxLCBtYXRjaDIpID0+IG1hdGNoMS5kaXN0YW5jZSAtIG1hdGNoMi5kaXN0YW5jZSlcbiAgICAgICAgICAuc2xpY2UoMCwgZ29vZE1hdGNoZXNGYWN0b3IpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGNvbnN0IGV4dHJhY3RQb2ludCA9IChrZXlQb2ludHMsIGluZGV4UHJvcGVydHlOYW1lKSA9PiAobWF0Y2gpID0+IHtcbiAgICBjb25zdCB7cHQsIHBvaW50fSA9IGtleVBvaW50c1ttYXRjaFtpbmRleFByb3BlcnR5TmFtZV1dO1xuICAgIC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9qdXN0YWR1ZGV3aG9oYWNrcy9vcGVuY3Y0bm9kZWpzL2lzc3Vlcy81ODRcbiAgICByZXR1cm4gKHB0IHx8IHBvaW50KTtcbiAgfTtcbiAgY29uc3QgcG9pbnRzMSA9IG1hdGNoZXMubWFwKGV4dHJhY3RQb2ludChyZXN1bHQxLmtleVBvaW50cywgJ3F1ZXJ5SWR4JykpO1xuICBjb25zdCByZWN0MSA9IGNhbGN1bGF0ZU1hdGNoZWRSZWN0KHBvaW50czEpO1xuICBjb25zdCBwb2ludHMyID0gbWF0Y2hlcy5tYXAoZXh0cmFjdFBvaW50KHJlc3VsdDIua2V5UG9pbnRzLCAndHJhaW5JZHgnKSk7XG4gIGNvbnN0IHJlY3QyID0gY2FsY3VsYXRlTWF0Y2hlZFJlY3QocG9pbnRzMik7XG5cbiAgY29uc3QgcmVzdWx0ID0ge1xuICAgIHBvaW50czEsXG4gICAgcmVjdDEsXG4gICAgcG9pbnRzMixcbiAgICByZWN0MixcbiAgICB0b3RhbENvdW50LFxuICAgIGNvdW50OiBtYXRjaGVzLmxlbmd0aCxcbiAgfTtcbiAgaWYgKHZpc3VhbGl6ZSkge1xuICAgIGNvbnN0IHZpc3VhbGl6YXRpb24gPSBjdi5kcmF3TWF0Y2hlcyhpbWcxLCBpbWcyLCByZXN1bHQxLmtleVBvaW50cywgcmVzdWx0Mi5rZXlQb2ludHMsIG1hdGNoZXMpO1xuICAgIGhpZ2hsaWdodFJlZ2lvbih2aXN1YWxpemF0aW9uLCByZWN0MSk7XG4gICAgaGlnaGxpZ2h0UmVnaW9uKHZpc3VhbGl6YXRpb24sIHtcbiAgICAgIHg6IGltZzEuY29scyArIHJlY3QyLngsXG4gICAgICB5OiByZWN0Mi55LFxuICAgICAgd2lkdGg6IHJlY3QyLndpZHRoLFxuICAgICAgaGVpZ2h0OiByZWN0Mi5oZWlnaHRcbiAgICB9KTtcbiAgICByZXN1bHQudmlzdWFsaXphdGlvbiA9IGF3YWl0IGN2LmltZW5jb2RlQXN5bmMoJy5wbmcnLCB2aXN1YWxpemF0aW9uKTtcbiAgfVxuICByZXR1cm4gcmVzdWx0O1xufVxuXG4vKipcbiAqIEB0eXBlZGVmIHtPYmplY3R9IFNpbWlsYXJpdHlPcHRpb25zXG4gKiBAcHJvcGVydHkgez9ib29sZWFufSB2aXN1YWxpemUgW2ZhbHNlXSBXaGV0aGVyIHRvIHJldHVybiB0aGUgcmVzdWx0aW5nIHZpc2FsaXphdGlvblxuICogYXMgYW4gaW1hZ2UgKHVzZWZ1bCBmb3IgZGVidWdnaW5nIHB1cnBvc2VzKVxuICogQHByb3BlcnR5IHtzdHJpbmd9IG1ldGhvZCBbVE1fQ0NPRUZGX05PUk1FRF0gVGhlIG5hbWUgb2YgdGhlIHRlbXBsYXRlIG1hdGNoaW5nIG1ldGhvZC5cbiAqIEFjY2VwdGFibGUgdmFsdWVzIGFyZTpcbiAqIC0gVE1fQ0NPRUZGXG4gKiAtIFRNX0NDT0VGRl9OT1JNRUQgKGRlZmF1bHQpXG4gKiAtIFRNX0NDT1JSXG4gKiAtIFRNX0NDT1JSX05PUk1FRFxuICogLSBUTV9TUURJRkZcbiAqIC0gVE1fU1FESUZGX05PUk1FRFxuICogUmVhZCBodHRwczovL2RvY3Mub3BlbmN2Lm9yZy8zLjAtYmV0YS9kb2MvcHlfdHV0b3JpYWxzL3B5X2ltZ3Byb2MvcHlfdGVtcGxhdGVfbWF0Y2hpbmcvcHlfdGVtcGxhdGVfbWF0Y2hpbmcuaHRtbFxuICogZm9yIG1vcmUgZGV0YWlscy5cbiAqL1xuXG4vKipcbiAqIEB0eXBlZGVmIHtPYmplY3R9IFNpbWlsYXJpdHlSZXN1bHRcbiAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBzY29yZSBUaGUgc2ltaWxhcml0eSBzY29yZSBhcyBhIGZsb2F0IG51bWJlciBpbiByYW5nZSBbMC4wLCAxLjBdLlxuICogMS4wIGlzIHRoZSBoaWdoZXN0IHNjb3JlIChtZWFucyBib3RoIGltYWdlcyBhcmUgdG90YWxseSBlcXVhbCkuXG4gKiBAcHJvcGVydHkgez9CdWZmZXJ9IHZpc3VhbGl6YXRpb24gVGhlIHZpc3VhbGl6YXRpb24gb2YgdGhlIG1hdGNoaW5nIHJlc3VsdFxuICogcmVwcmVzZW50ZWQgYXMgUE5HIGltYWdlIGJ1ZmZlci4gVGhpcyBpbWFnZSBpbmNsdWRlcyBib3RoIGlucHV0IHBpY3R1cmVzIHdoZXJlXG4gKiBkaWZmZXJlbmNlIHJlZ2lvbnMgYXJlIGhpZ2hsaWdodGVkIHdpdGggcmVjdGFuZ2xlcy5cbiAqL1xuXG4vKipcbiAqIENhbGN1bGF0ZXMgdGhlIHNpbWlsYXJpdHkgc2NvcmUgYmV0d2VlbiB0d28gaW1hZ2VzLlxuICogSXQgaXMgZXhwZWN0ZWQsIHRoYXQgYm90aCBpbWFnZXMgaGF2ZSB0aGUgc2FtZSByZXNvbHV0aW9uLlxuICpcbiAqIEBwYXJhbSB7QnVmZmVyfSBpbWcxRGF0YSBUaGUgZGF0YSBvZiB0aGUgZmlyc3QgaW1hZ2UgcGFja2VkIGludG8gYSBOb2RlSlMgYnVmZmVyXG4gKiBAcGFyYW0ge0J1ZmZlcn0gaW1nMkRhdGEgVGhlIGRhdGEgb2YgdGhlIHNlY29uZCBpbWFnZSBwYWNrZWQgaW50byBhIE5vZGVKUyBidWZmZXJcbiAqIEBwYXJhbSB7P1NpbWlsYXJpdHlPcHRpb25zfSBvcHRpb25zIFt7fV0gU2V0IG9mIHNpbWlsYXJpdHkgY2FsY3VsYXRpb24gb3B0aW9uc1xuICpcbiAqIEByZXR1cm5zIHtTaW1pbGFyaXR5UmVzdWx0fSBUaGUgY2FsY3VsYXRpb24gcmVzdWx0XG4gKiBAdGhyb3dzIHtFcnJvcn0gSWYgdGhlIGdpdmVuIGltYWdlcyBoYXZlIGRpZmZlcmVudCByZXNvbHV0aW9uLlxuICovXG5hc3luYyBmdW5jdGlvbiBnZXRJbWFnZXNTaW1pbGFyaXR5IChpbWcxRGF0YSwgaW1nMkRhdGEsIG9wdGlvbnMgPSB7fSkge1xuICBhd2FpdCBpbml0T3BlbkNWKCk7XG5cbiAgY29uc3Qge1xuICAgIG1ldGhvZCA9IERFRkFVTFRfTUFUQ0hJTkdfTUVUSE9ELFxuICAgIHZpc3VhbGl6ZSA9IGZhbHNlLFxuICB9ID0gb3B0aW9ucztcbiAgbGV0IFt0ZW1wbGF0ZSwgcmVmZXJlbmNlXSA9IGF3YWl0IEIuYWxsKFtcbiAgICBjdi5pbWRlY29kZUFzeW5jKGltZzFEYXRhKSxcbiAgICBjdi5pbWRlY29kZUFzeW5jKGltZzJEYXRhKVxuICBdKTtcbiAgaWYgKHRlbXBsYXRlLnJvd3MgIT09IHJlZmVyZW5jZS5yb3dzIHx8IHRlbXBsYXRlLmNvbHMgIT09IHJlZmVyZW5jZS5jb2xzKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdCb3RoIGltYWdlcyBhcmUgZXhwZWN0ZWQgdG8gaGF2ZSB0aGUgc2FtZSBzaXplIGluIG9yZGVyIHRvICcgK1xuICAgICAgICAgICAgICAgICAgICAnY2FsY3VsYXRlIHRoZSBzaW1pbGFyaXR5IHNjb3JlLicpO1xuICB9XG4gIFt0ZW1wbGF0ZSwgcmVmZXJlbmNlXSA9IGF3YWl0IEIuYWxsKFtcbiAgICB0ZW1wbGF0ZS5jb252ZXJ0VG9Bc3luYyhjdi5DVl84VUMzKSxcbiAgICByZWZlcmVuY2UuY29udmVydFRvQXN5bmMoY3YuQ1ZfOFVDMylcbiAgXSk7XG5cbiAgbGV0IG1hdGNoZWQ7XG4gIHRyeSB7XG4gICAgbWF0Y2hlZCA9IGF3YWl0IHJlZmVyZW5jZS5tYXRjaFRlbXBsYXRlQXN5bmModGVtcGxhdGUsIHRvTWF0Y2hpbmdNZXRob2QobWV0aG9kKSk7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYFRoZSByZWZlcmVuY2UgaW1hZ2UgZGlkIG5vdCBtYXRjaCB0byB0aGUgdGVtcGxhdGUgb25lLiBPcmlnaW5hbCBlcnJvcjogJHtlLm1lc3NhZ2V9YCk7XG4gIH1cbiAgY29uc3QgbWluTWF4ID0gYXdhaXQgbWF0Y2hlZC5taW5NYXhMb2NBc3luYygpO1xuICBjb25zdCByZXN1bHQgPSB7XG4gICAgc2NvcmU6IG1pbk1heC5tYXhWYWxcbiAgfTtcbiAgaWYgKHZpc3VhbGl6ZSkge1xuICAgIGNvbnN0IHJlc3VsdE1hdCA9IG5ldyBjdi5NYXQodGVtcGxhdGUucm93cywgdGVtcGxhdGUuY29scyAqIDIsIGN2LkNWXzhVQzMpO1xuICAgIGF3YWl0IEIuYWxsKFtcbiAgICAgIHJlZmVyZW5jZS5jb3B5VG9Bc3luYyhcbiAgICAgICAgcmVzdWx0TWF0LmdldFJlZ2lvbihuZXcgY3YuUmVjdCgwLCAwLCByZWZlcmVuY2UuY29scywgcmVmZXJlbmNlLnJvd3MpKSksXG4gICAgICB0ZW1wbGF0ZS5jb3B5VG9Bc3luYyhcbiAgICAgICAgcmVzdWx0TWF0LmdldFJlZ2lvbihuZXcgY3YuUmVjdChyZWZlcmVuY2UuY29scywgMCwgdGVtcGxhdGUuY29scywgdGVtcGxhdGUucm93cykpKVxuICAgIF0pO1xuICAgIGxldCBtYXNrID0gcmVmZXJlbmNlLmFic2RpZmYodGVtcGxhdGUpO1xuICAgIG1hc2sgPSBhd2FpdCBtYXNrLmN2dENvbG9yQXN5bmMoY3YuQ09MT1JfQkdSMkdSQVkpO1xuICAgIGxldCBjb250b3VycyA9IFtdO1xuICAgIHRyeSB7XG4gICAgICBtYXNrID0gYXdhaXQgbWFzay50aHJlc2hvbGRBc3luYygxMjgsIDI1NSwgY3YuVEhSRVNIX0JJTkFSWSB8IGN2LlRIUkVTSF9PVFNVKTtcbiAgICAgIGNvbnRvdXJzID0gYXdhaXQgbWFzay5maW5kQ29udG91cnNBc3luYyhjdi5SRVRSX0VYVEVSTkFMLCBjdi5DSEFJTl9BUFBST1hfU0lNUExFKTtcbiAgICB9IGNhdGNoIChpZ24pIHtcbiAgICAgIC8vIE5vIGNvbnRvdXJzIGNhbiBiZSBmb3VuZCwgd2hpY2ggbWVhbnMsIG1vc3QgbGlrZWx5LCB0aGF0IGltYWdlcyBhcmUgZXF1YWxcbiAgICB9XG4gICAgZm9yIChjb25zdCBjb250b3VyIG9mIGNvbnRvdXJzKSB7XG4gICAgICBjb25zdCBib3VuZGluZ1JlY3QgPSBjb250b3VyLmJvdW5kaW5nUmVjdCgpO1xuICAgICAgaGlnaGxpZ2h0UmVnaW9uKHJlc3VsdE1hdCwgYm91bmRpbmdSZWN0KTtcbiAgICAgIGhpZ2hsaWdodFJlZ2lvbihyZXN1bHRNYXQsIHtcbiAgICAgICAgeDogcmVmZXJlbmNlLmNvbHMgKyBib3VuZGluZ1JlY3QueCxcbiAgICAgICAgeTogYm91bmRpbmdSZWN0LnksXG4gICAgICAgIHdpZHRoOiBib3VuZGluZ1JlY3Qud2lkdGgsXG4gICAgICAgIGhlaWdodDogYm91bmRpbmdSZWN0LmhlaWdodFxuICAgICAgfSk7XG4gICAgfVxuICAgIHJlc3VsdC52aXN1YWxpemF0aW9uID0gYXdhaXQgY3YuaW1lbmNvZGVBc3luYygnLnBuZycsIHJlc3VsdE1hdCk7XG4gIH1cbiAgcmV0dXJuIHJlc3VsdDtcbn1cblxuLyoqXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBPY2N1cnJlbmNlT3B0aW9uc1xuICogQHByb3BlcnR5IHs/Ym9vbGVhbn0gdmlzdWFsaXplIFtmYWxzZV0gV2hldGhlciB0byByZXR1cm4gdGhlIHJlc3VsdGluZyB2aXNhbGl6YXRpb25cbiAqIGFzIGFuIGltYWdlICh1c2VmdWwgZm9yIGRlYnVnZ2luZyBwdXJwb3NlcylcbiAqIEBwcm9wZXJ0eSB7P2Zsb2F0fSB0aHJlc2hvbGQgWzAuNV0gQXQgd2hhdCBub3JtYWxpemVkIHRocmVzaG9sZCB0byByZWplY3RcbiAqIGEgbWF0Y2hcbiAqIEBwcm9wZXJ0eSB7P2Zsb2F0fSBtdWx0aXBsZSBbZmFsc2VdIGZpbmQgbXVsdGlwbGUgbWF0Y2hlcyBpbiB0aGUgaW1hZ2VcbiAqIEBwcm9wZXJ0eSB7P251bWJlcn0gbWF0Y2hOZWlnaGJvdXJUaHJlc2hvbGQgWzEwXSBUaGUgcGl4ZWwgZGlzdGFuY2UgYmV0d2VlbiBtYXRjaGVzIHdlIGNvbnNpZGVyXG4gKiB0byBiZSBwYXJ0IG9mIHRoZSBzYW1lIHRlbXBsYXRlIG1hdGNoXG4gKi9cblxuLyoqXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBPY2N1cnJlbmNlUmVzdWx0XG4gKiBAcHJvcGVydHkge1JlY3R9IHJlY3QgVGhlIHJlZ2lvbiBvZiB0aGUgcGFydGlhbCBpbWFnZSBvY2N1cmVuY2VcbiAqIG9uIHRoZSBmdWxsIGltYWdlXG4gKiBAcHJvcGVydHkgez9CdWZmZXJ9IHZpc3VhbGl6YXRpb24gVGhlIHZpc3VhbGl6YXRpb24gb2YgdGhlIG1hdGNoaW5nIHJlc3VsdFxuICogcmVwcmVzZW50ZWQgYXMgUE5HIGltYWdlIGJ1ZmZlci4gT24gdGhpcyBpbWFnZSB0aGUgbWF0Y2hpbmdcbiAqIHJlZ2lvbiBpcyBoaWdobGlnaHRlZCB3aXRoIGEgcmVjdGFuZ2xlLiBJZiB0aGUgbXVsdGlwbGUgb3B0aW9uIGlzIHBhc3NlZCxcbiAqIGFsbCByZXN1bHRzIGFyZSBoaWdobGlnaHRlZCBoZXJlLlxuICogQHByb3BlcnR5IHtudW1iZXJ9IHNjb3JlIFRoZSBzaW1pbGFyaXR5IHNjb3JlIGFzIGEgZmxvYXQgbnVtYmVyIGluIHJhbmdlIFswLjAsIDEuMF0uXG4gKiAxLjAgaXMgdGhlIGhpZ2hlc3Qgc2NvcmUgKG1lYW5zIGJvdGggaW1hZ2VzIGFyZSB0b3RhbGx5IGVxdWFsKS5cbiAqIEBwcm9wZXJ0eSB7QXJyYXk8T2NjdXJyZW5jZVJlc3VsdD59IG11bHRpcGxlIFRoZSBhcnJheSBvZiBtYXRjaGluZyBPY2N1cmVuY2VSZXN1bHRzXG4gKiAtIG9ubHkgd2hlbiBtdWx0aXBsZSBvcHRpb24gaXMgcGFzc2VkXG4gKiBAcHJvcGVydHkge3N0cmluZ30gbWV0aG9kIFtUTV9DQ09FRkZfTk9STUVEXSBUaGUgbmFtZSBvZiB0aGUgdGVtcGxhdGUgbWF0Y2hpbmcgbWV0aG9kLlxuICogQWNjZXB0YWJsZSB2YWx1ZXMgYXJlOlxuICogLSBUTV9DQ09FRkZcbiAqIC0gVE1fQ0NPRUZGX05PUk1FRCAoZGVmYXVsdClcbiAqIC0gVE1fQ0NPUlJcbiAqIC0gVE1fQ0NPUlJfTk9STUVEXG4gKiAtIFRNX1NRRElGRlxuICogLSBUTV9TUURJRkZfTk9STUVEXG4gKiBSZWFkIGh0dHBzOi8vZG9jcy5vcGVuY3Yub3JnLzMuMC1iZXRhL2RvYy9weV90dXRvcmlhbHMvcHlfaW1ncHJvYy9weV90ZW1wbGF0ZV9tYXRjaGluZy9weV90ZW1wbGF0ZV9tYXRjaGluZy5odG1sXG4gKiBmb3IgbW9yZSBkZXRhaWxzLlxuICovXG5cbi8qKlxuICogQ2FsY3VsYXRlcyB0aGUgb2NjdXJyZW5jZSBwb3NpdGlvbiBvZiBhIHBhcnRpYWwgaW1hZ2UgaW4gdGhlIGZ1bGxcbiAqIGltYWdlLlxuICpcbiAqIEBwYXJhbSB7QnVmZmVyfSBmdWxsSW1nRGF0YSBUaGUgZGF0YSBvZiB0aGUgZnVsbCBpbWFnZSBwYWNrZWQgaW50byBhIE5vZGVKUyBidWZmZXJcbiAqIEBwYXJhbSB7QnVmZmVyfSBwYXJ0aWFsSW1nRGF0YSBUaGUgZGF0YSBvZiB0aGUgcGFydGlhbCBpbWFnZSBwYWNrZWQgaW50byBhIE5vZGVKUyBidWZmZXJcbiAqIEBwYXJhbSB7P09jY3VycmVuY2VPcHRpb25zfSBvcHRpb25zIFt7fV0gU2V0IG9mIG9jY3VycmVuY2UgY2FsY3VsYXRpb24gb3B0aW9uc1xuICpcbiAqIEByZXR1cm5zIHtPY2N1cnJlbmNlUmVzdWx0fVxuICogQHRocm93cyB7RXJyb3J9IElmIG5vIG9jY3VycmVuY2VzIG9mIHRoZSBwYXJ0aWFsIGltYWdlIGNhbiBiZSBmb3VuZCBpbiB0aGUgZnVsbCBpbWFnZVxuICovXG5hc3luYyBmdW5jdGlvbiBnZXRJbWFnZU9jY3VycmVuY2UgKGZ1bGxJbWdEYXRhLCBwYXJ0aWFsSW1nRGF0YSwgb3B0aW9ucyA9IHt9KSB7XG4gIGF3YWl0IGluaXRPcGVuQ1YoKTtcblxuICBjb25zdCB7XG4gICAgdmlzdWFsaXplID0gZmFsc2UsXG4gICAgdGhyZXNob2xkID0gREVGQVVMVF9NQVRDSF9USFJFU0hPTEQsXG4gICAgbXVsdGlwbGUgPSBmYWxzZSxcbiAgICBtYXRjaE5laWdoYm91clRocmVzaG9sZCA9IE1BVENIX05FSUdIQk9VUl9USFJFU0hPTEQsXG4gICAgbWV0aG9kID0gREVGQVVMVF9NQVRDSElOR19NRVRIT0QsXG4gIH0gPSBvcHRpb25zO1xuXG4gIGNvbnN0IFtmdWxsSW1nLCBwYXJ0aWFsSW1nXSA9IGF3YWl0IEIuYWxsKFtcbiAgICBjdi5pbWRlY29kZUFzeW5jKGZ1bGxJbWdEYXRhKSxcbiAgICBjdi5pbWRlY29kZUFzeW5jKHBhcnRpYWxJbWdEYXRhKVxuICBdKTtcbiAgY29uc3QgcmVzdWx0cyA9IFtdO1xuICBsZXQgdmlzdWFsaXphdGlvbiA9IG51bGw7XG5cbiAgdHJ5IHtcbiAgICBjb25zdCBtYXRjaGVkID0gYXdhaXQgZnVsbEltZy5tYXRjaFRlbXBsYXRlQXN5bmMocGFydGlhbEltZywgdG9NYXRjaGluZ01ldGhvZChtZXRob2QpKTtcbiAgICBjb25zdCBtaW5NYXggPSBhd2FpdCBtYXRjaGVkLm1pbk1heExvY0FzeW5jKCk7XG5cbiAgICBpZiAobXVsdGlwbGUpIHtcbiAgICAgIGNvbnN0IG5vblplcm9NYXRjaFJlc3VsdHMgPSBtYXRjaGVkLnRocmVzaG9sZCh0aHJlc2hvbGQsIDEsIGN2LlRIUkVTSF9CSU5BUlkpXG4gICAgICAgIC5jb252ZXJ0VG8oY3YuQ1ZfOFUpXG4gICAgICAgIC5maW5kTm9uWmVybygpO1xuICAgICAgY29uc3QgbWF0Y2hlcyA9IGZpbHRlck5lYXJNYXRjaGVzKG5vblplcm9NYXRjaFJlc3VsdHMsIG1hdGNoTmVpZ2hib3VyVGhyZXNob2xkKTtcblxuICAgICAgZm9yIChjb25zdCB7eCwgeX0gb2YgbWF0Y2hlcykge1xuICAgICAgICByZXN1bHRzLnB1c2goe1xuICAgICAgICAgIHNjb3JlOiBtYXRjaGVkLmF0KHksIHgpLFxuICAgICAgICAgIHJlY3Q6IHtcbiAgICAgICAgICAgIHgsIHksXG4gICAgICAgICAgICB3aWR0aDogcGFydGlhbEltZy5jb2xzLFxuICAgICAgICAgICAgaGVpZ2h0OiBwYXJ0aWFsSW1nLnJvd3NcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAobWluTWF4Lm1heFZhbCA+PSB0aHJlc2hvbGQpIHtcbiAgICAgIGNvbnN0IHt4LCB5fSA9IG1ldGhvZC5pbmNsdWRlcygnU1FESUZGJykgPyBtaW5NYXgubWluTG9jIDogbWluTWF4Lm1heExvYztcbiAgICAgIHJlc3VsdHMucHVzaCh7XG4gICAgICAgIHNjb3JlOiBtaW5NYXgubWF4VmFsLFxuICAgICAgICByZWN0OiB7XG4gICAgICAgICAgeCwgeSxcbiAgICAgICAgICB3aWR0aDogcGFydGlhbEltZy5jb2xzLFxuICAgICAgICAgIGhlaWdodDogcGFydGlhbEltZy5yb3dzXG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmIChfLmlzRW1wdHkocmVzdWx0cykpIHtcbiAgICAgIC8vIEJlbG93IGVycm9yIG1lc3NhZ2UsIGBDYW5ub3QgZmluZCBhbnkgb2NjdXJyZW5jZXNgIGlzIHJlZmVyZW5jZWQgaW4gZmluZCBieSBpbWFnZVxuICAgICAgdGhyb3cgbmV3IEVycm9yKGBNYXRjaCB0aHJlc2hvbGQ6ICR7dGhyZXNob2xkfS4gSGlnaGVzdCBtYXRjaCB2YWx1ZSBgICtcbiAgICAgICAgICAgICAgICAgICAgICBgZm91bmQgd2FzICR7bWluTWF4Lm1heFZhbH1gKTtcbiAgICB9XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICAvLyBCZWxvdyBlcnJvciBtZXNzYWdlLCBgQ2Fubm90IGZpbmQgYW55IG9jY3VycmVuY2VzYCBpcyByZWZlcmVuY2VkIGluIGZpbmQgYnkgaW1hZ2VcbiAgICB0aHJvdyBuZXcgRXJyb3IoYENhbm5vdCBmaW5kIGFueSBvY2N1cnJlbmNlcyBvZiB0aGUgcGFydGlhbCBpbWFnZSBpbiB0aGUgZnVsbCBpbWFnZS4gYCArXG4gICAgICBgT3JpZ2luYWwgZXJyb3I6ICR7ZS5tZXNzYWdlfWApO1xuICB9XG5cbiAgaWYgKHZpc3VhbGl6ZSkge1xuICAgIGNvbnN0IGZ1bGxIaWdobGlnaHRlZEltYWdlID0gZnVsbEltZy5jb3B5KCk7XG5cbiAgICBmb3IgKGNvbnN0IHJlc3VsdCBvZiByZXN1bHRzKSB7XG4gICAgICBjb25zdCBzaW5nbGVIaWdobGlnaHRlZEltYWdlID0gZnVsbEltZy5jb3B5KCk7XG5cbiAgICAgIGhpZ2hsaWdodFJlZ2lvbihzaW5nbGVIaWdobGlnaHRlZEltYWdlLCByZXN1bHQucmVjdCk7XG4gICAgICBoaWdobGlnaHRSZWdpb24oZnVsbEhpZ2hsaWdodGVkSW1hZ2UsIHJlc3VsdC5yZWN0KTtcbiAgICAgIHJlc3VsdC52aXN1YWxpemF0aW9uID0gYXdhaXQgY3YuaW1lbmNvZGVBc3luYygnLnBuZycsIHNpbmdsZUhpZ2hsaWdodGVkSW1hZ2UpO1xuICAgIH1cbiAgICB2aXN1YWxpemF0aW9uID0gYXdhaXQgY3YuaW1lbmNvZGVBc3luYygnLnBuZycsIGZ1bGxIaWdobGlnaHRlZEltYWdlKTtcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgcmVjdDogcmVzdWx0c1swXS5yZWN0LFxuICAgIHNjb3JlOiByZXN1bHRzWzBdLnNjb3JlLFxuICAgIHZpc3VhbGl6YXRpb24sXG4gICAgbXVsdGlwbGU6IHJlc3VsdHNcbiAgfTtcbn1cblxuLyoqXG4gKiBGaWx0ZXIgb3V0IG1hdGNoIHJlc3VsdHMgd2hpY2ggaGF2ZSBhIG1hdGNoZWQgbmVpZ2hib3VyXG4gKlxuICogQHBhcmFtIHtBcnJheTxQb2ludD59IG5vblplcm9NYXRjaFJlc3VsdHMgbWF0cml4IG9mIGltYWdlIG1hdGNoIHJlc3VsdHNcbiAqIEBwYXJhbSB7bnVtYmVyfSBtYXRjaE5laWdoYm91clRocmVzaG9sZCBUaGUgcGl4ZWwgZGlzdGFuY2Ugd2l0aGluIHdoaWNoIHdlXG4gKiBjb25zaWRlciBhbiBlbGVtZW50IGJlaW5nIGEgbmVpZ2hib3VyIG9mIGFuIGV4aXN0aW5nIG1hdGNoXG4gKiBAcmV0dXJuIHtBcnJheTxQb2ludD59IHRoZSBmaWx0ZXJlZCBhcnJheSBvZiBtYXRjaGVkIHBvaW50c1xuICovXG5mdW5jdGlvbiBmaWx0ZXJOZWFyTWF0Y2hlcyAobm9uWmVyb01hdGNoUmVzdWx0cywgbWF0Y2hOZWlnaGJvdXJUaHJlc2hvbGQpIHtcbiAgcmV0dXJuIG5vblplcm9NYXRjaFJlc3VsdHMucmVkdWNlKChhY2MsIGVsZW1lbnQpID0+IHtcbiAgICBpZiAoIWFjYy5zb21lKChtYXRjaCkgPT4gZGlzdGFuY2UobWF0Y2gsIGVsZW1lbnQpIDw9IG1hdGNoTmVpZ2hib3VyVGhyZXNob2xkKSkge1xuICAgICAgYWNjLnB1c2goZWxlbWVudCk7XG4gICAgfVxuICAgIHJldHVybiBhY2M7XG4gIH0sIFtdKTtcbn1cblxuLyoqXG4gKiBGaW5kIHRoZSBkaXN0YW5jZSBiZXR3ZWVuIHR3byBwb2ludHNcbiAqXG4gKiBAcGFyYW0ge1BvaW50fSBwb2ludDEgVGhlIGZpcnN0IHBvaW50XG4gKiBAcGFyYW0ge1BvaW50fSBwb2ludDIgVGhlIHNlY29uZCBwb2ludFxuICogQHJldHVybiB7bnVtYmVyfSB0aGUgZGlzdGFuY2VcbiAqL1xuZnVuY3Rpb24gZGlzdGFuY2UgKHBvaW50MSwgcG9pbnQyKSB7XG4gIGNvbnN0IGEyID0gTWF0aC5wb3coKHBvaW50MS54IC0gcG9pbnQyLngpLCAyKTtcbiAgY29uc3QgYjIgPSBNYXRoLnBvdygocG9pbnQxLnkgLSBwb2ludDIueSksIDIpO1xuICByZXR1cm4gTWF0aC5zcXJ0KGEyICsgYjIpO1xufVxuXG4vKipcbiAqIENyb3AgdGhlIGltYWdlIGJ5IGdpdmVuIHJlY3RhbmdsZSAodXNlIGJhc2U2NCBzdHJpbmcgYXMgaW5wdXQgYW5kIG91dHB1dClcbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gYmFzZTY0SW1hZ2UgVGhlIHN0cmluZyB3aXRoIGJhc2U2NCBlbmNvZGVkIGltYWdlXG4gKiBAcGFyYW0ge1JlZ2lvbn0gcmVjdCBUaGUgc2VsZWN0ZWQgcmVnaW9uIG9mIGltYWdlXG4gKiBAcmV0dXJuIHtzdHJpbmd9IGJhc2U2NCBlbmNvZGVkIHN0cmluZyBvZiBjcm9wcGVkIGltYWdlXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGNyb3BCYXNlNjRJbWFnZSAoYmFzZTY0SW1hZ2UsIHJlY3QpIHtcbiAgY29uc3QgaW1hZ2UgPSBhd2FpdCBiYXNlNjRUb0ltYWdlKGJhc2U2NEltYWdlKTtcbiAgY3JvcEltYWdlKGltYWdlLCByZWN0KTtcbiAgcmV0dXJuIGF3YWl0IGltYWdlVG9CYXNlNjQoaW1hZ2UpO1xufVxuXG4vKipcbiAqIENyZWF0ZSBhIHBuZ2pzIGltYWdlIGZyb20gZ2l2ZW4gYmFzZTY0IGltYWdlXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGJhc2U2NEltYWdlIFRoZSBzdHJpbmcgd2l0aCBiYXNlNjQgZW5jb2RlZCBpbWFnZVxuICogQHJldHVybiB7UE5HfSBUaGUgaW1hZ2Ugb2JqZWN0XG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGJhc2U2NFRvSW1hZ2UgKGJhc2U2NEltYWdlKSB7XG4gIGNvbnN0IGltYWdlQnVmZmVyID0gQnVmZmVyLmZyb20oYmFzZTY0SW1hZ2UsICdiYXNlNjQnKTtcbiAgcmV0dXJuIGF3YWl0IG5ldyBCKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICBjb25zdCBpbWFnZSA9IG5ldyBQTkcoe2ZpbHRlclR5cGU6IFNDQU5MSU5FX0ZJTFRFUl9NRVRIT0R9KTtcbiAgICBpbWFnZS5wYXJzZShpbWFnZUJ1ZmZlciwgKGVyciwgaW1hZ2UpID0+IHsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBwcm9taXNlL3ByZWZlci1hd2FpdC10by1jYWxsYmFja3NcbiAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgcmV0dXJuIHJlamVjdChlcnIpO1xuICAgICAgfVxuICAgICAgcmVzb2x2ZShpbWFnZSk7XG4gICAgfSk7XG4gIH0pO1xufVxuXG4vKipcbiAqIENyZWF0ZSBhIGJhc2U2NCBzdHJpbmcgZm9yIGdpdmVuIGltYWdlIG9iamVjdFxuICpcbiAqIEBwYXJhbSB7UE5HfSBpbWFnZSBUaGUgaW1hZ2Ugb2JqZWN0XG4gKiBAcmV0dXJuIHtzdHJpbmd9IFRoZSBzdHJpbmcgd2l0aCBiYXNlNjQgZW5jb2RlZCBpbWFnZVxuICovXG5hc3luYyBmdW5jdGlvbiBpbWFnZVRvQmFzZTY0IChpbWFnZSkge1xuICByZXR1cm4gYXdhaXQgbmV3IEIoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIGNvbnN0IGNodW5rcyA9IFtdO1xuICAgIGltYWdlLnBhY2soKVxuICAgIC5vbignZGF0YScsIChjaHVuaykgPT4gY2h1bmtzLnB1c2goY2h1bmspKS5vbignZW5kJywgKCkgPT4ge1xuICAgICAgcmVzb2x2ZShCdWZmZXIuY29uY2F0KGNodW5rcykudG9TdHJpbmcoJ2Jhc2U2NCcpKTtcbiAgICB9KVxuICAgIC5vbignZXJyb3InLCAoZXJyKSA9PiB7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgcHJvbWlzZS9wcmVmZXItYXdhaXQtdG8tY2FsbGJhY2tzXG4gICAgICByZWplY3QoZXJyKTtcbiAgICB9KTtcbiAgfSk7XG59XG5cbi8qKlxuICogQ3JvcCB0aGUgaW1hZ2UgYnkgZ2l2ZW4gcmVjdGFuZ2xlXG4gKlxuICogQHBhcmFtIHtQTkd9IGltYWdlIFRoZSBpbWFnZSB0byBtdXRhdGUgYnkgY3JvcHBpbmdcbiAqIEBwYXJhbSB7UmVnaW9ufSByZWN0IFRoZSBzZWxlY3RlZCByZWdpb24gb2YgaW1hZ2VcbiAqL1xuZnVuY3Rpb24gY3JvcEltYWdlIChpbWFnZSwgcmVjdCkge1xuICBjb25zdCBpbWFnZVJlY3QgPSB7d2lkdGg6IGltYWdlLndpZHRoLCBoZWlnaHQ6IGltYWdlLmhlaWdodH07XG4gIGNvbnN0IGludGVyUmVjdCA9IGdldFJlY3RJbnRlcnNlY3Rpb24ocmVjdCwgaW1hZ2VSZWN0KTtcbiAgaWYgKGludGVyUmVjdC53aWR0aCA8IHJlY3Qud2lkdGggfHwgaW50ZXJSZWN0LmhlaWdodCA8IHJlY3QuaGVpZ2h0KSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBDYW5ub3QgY3JvcCAke0pTT04uc3RyaW5naWZ5KHJlY3QpfSBmcm9tICR7SlNPTi5zdHJpbmdpZnkoaW1hZ2VSZWN0KX0gYmVjYXVzZSB0aGUgaW50ZXJzZWN0aW9uIGJldHdlZW4gdGhlbSB3YXMgbm90IHRoZSBzaXplIG9mIHRoZSByZWN0YCk7XG4gIH1cblxuICBjb25zdCBmaXJzdFZlcnRpY2FsUGl4ZWwgPSBpbnRlclJlY3QudG9wO1xuICBjb25zdCBsYXN0VmVydGljYWxQaXhlbCA9IGludGVyUmVjdC50b3AgKyBpbnRlclJlY3QuaGVpZ2h0O1xuXG4gIGNvbnN0IGZpcnN0SG9yaXpvbnRhbFBpeGVsID0gaW50ZXJSZWN0LmxlZnQ7XG4gIGNvbnN0IGxhc3RIb3Jpem9udGFsUGl4ZWwgPSBpbnRlclJlY3QubGVmdCArIGludGVyUmVjdC53aWR0aDtcblxuICBjb25zdCBjcm9wcGVkQXJyYXkgPSBbXTtcbiAgZm9yIChsZXQgeSA9IGZpcnN0VmVydGljYWxQaXhlbDsgeSA8IGxhc3RWZXJ0aWNhbFBpeGVsOyB5KyspIHtcbiAgICBmb3IgKGxldCB4ID0gZmlyc3RIb3Jpem9udGFsUGl4ZWw7IHggPCBsYXN0SG9yaXpvbnRhbFBpeGVsOyB4KyspIHtcbiAgICAgIGNvbnN0IGZpcnN0Qnl0ZUlkeEluUGl4ZWxCbG9jayA9IChpbWFnZVJlY3Qud2lkdGggKiB5ICsgeCkgPDwgMjtcbiAgICAgIGZvciAobGV0IGJ5dGVJZHggPSAwOyBieXRlSWR4IDwgQllURVNfSU5fUElYRUxfQkxPQ0s7IGJ5dGVJZHgrKykge1xuICAgICAgICBjcm9wcGVkQXJyYXkucHVzaChpbWFnZS5kYXRhW2ZpcnN0Qnl0ZUlkeEluUGl4ZWxCbG9jayArIGJ5dGVJZHhdKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBpbWFnZS5kYXRhID0gQnVmZmVyLmZyb20oY3JvcHBlZEFycmF5KTtcbiAgaW1hZ2Uud2lkdGggPSBpbnRlclJlY3Qud2lkdGg7XG4gIGltYWdlLmhlaWdodCA9IGludGVyUmVjdC5oZWlnaHQ7XG4gIHJldHVybiBpbWFnZTtcbn1cblxuZnVuY3Rpb24gZ2V0UmVjdEludGVyc2VjdGlvbiAocmVjdCwgaW1hZ2VTaXplKSB7XG4gIGNvbnN0IGxlZnQgPSByZWN0LmxlZnQgPj0gaW1hZ2VTaXplLndpZHRoID8gaW1hZ2VTaXplLndpZHRoIDogcmVjdC5sZWZ0O1xuICBjb25zdCB0b3AgPSByZWN0LnRvcCA+PSBpbWFnZVNpemUuaGVpZ2h0ID8gaW1hZ2VTaXplLmhlaWdodCA6IHJlY3QudG9wO1xuICBjb25zdCB3aWR0aCA9IGltYWdlU2l6ZS53aWR0aCA+PSAobGVmdCArIHJlY3Qud2lkdGgpID8gcmVjdC53aWR0aCA6IChpbWFnZVNpemUud2lkdGggLSBsZWZ0KTtcbiAgY29uc3QgaGVpZ2h0ID0gaW1hZ2VTaXplLmhlaWdodCA+PSAodG9wICsgcmVjdC5oZWlnaHQpID8gcmVjdC5oZWlnaHQgOiAoaW1hZ2VTaXplLmhlaWdodCAtIHRvcCk7XG4gIHJldHVybiB7bGVmdCwgdG9wLCB3aWR0aCwgaGVpZ2h0fTtcbn1cblxuZXhwb3J0IHtcbiAgY3JvcEJhc2U2NEltYWdlLCBiYXNlNjRUb0ltYWdlLCBpbWFnZVRvQmFzZTY0LCBjcm9wSW1hZ2UsIGdldEltYWdlc01hdGNoZXMsXG4gIGdldEltYWdlc1NpbWlsYXJpdHksIGdldEltYWdlT2NjdXJyZW5jZSwgZ2V0SmltcEltYWdlLCBNSU1FX0pQRUcsIE1JTUVfUE5HLFxuICBNSU1FX0JNUCxcbn07XG4iXSwiZmlsZSI6ImxpYi9pbWFnZS11dGlsLmpzIiwic291cmNlUm9vdCI6Ii4uLy4uIn0=