@macrostrat/cesium-martini 1.1.1 → 1.2.0

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/dist/index.js CHANGED
@@ -1,7 +1,47 @@
1
1
  'use strict';
2
2
 
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
3
5
  var cesium = require('cesium');
4
6
 
7
+ function ownKeys(object, enumerableOnly) {
8
+ var keys = Object.keys(object);
9
+
10
+ if (Object.getOwnPropertySymbols) {
11
+ var symbols = Object.getOwnPropertySymbols(object);
12
+
13
+ if (enumerableOnly) {
14
+ symbols = symbols.filter(function (sym) {
15
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
16
+ });
17
+ }
18
+
19
+ keys.push.apply(keys, symbols);
20
+ }
21
+
22
+ return keys;
23
+ }
24
+
25
+ function _objectSpread2(target) {
26
+ for (var i = 1; i < arguments.length; i++) {
27
+ var source = arguments[i] != null ? arguments[i] : {};
28
+
29
+ if (i % 2) {
30
+ ownKeys(Object(source), true).forEach(function (key) {
31
+ _defineProperty(target, key, source[key]);
32
+ });
33
+ } else if (Object.getOwnPropertyDescriptors) {
34
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
35
+ } else {
36
+ ownKeys(Object(source)).forEach(function (key) {
37
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
38
+ });
39
+ }
40
+ }
41
+
42
+ return target;
43
+ }
44
+
5
45
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
6
46
  try {
7
47
  var info = gen[key](arg);
@@ -75,6 +115,117 @@ function _defineProperty(obj, key, value) {
75
115
  return obj;
76
116
  }
77
117
 
118
+ function _inherits(subClass, superClass) {
119
+ if (typeof superClass !== "function" && superClass !== null) {
120
+ throw new TypeError("Super expression must either be null or a function");
121
+ }
122
+
123
+ subClass.prototype = Object.create(superClass && superClass.prototype, {
124
+ constructor: {
125
+ value: subClass,
126
+ writable: true,
127
+ configurable: true
128
+ }
129
+ });
130
+ if (superClass) _setPrototypeOf(subClass, superClass);
131
+ }
132
+
133
+ function _getPrototypeOf(o) {
134
+ _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
135
+ return o.__proto__ || Object.getPrototypeOf(o);
136
+ };
137
+ return _getPrototypeOf(o);
138
+ }
139
+
140
+ function _setPrototypeOf(o, p) {
141
+ _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
142
+ o.__proto__ = p;
143
+ return o;
144
+ };
145
+
146
+ return _setPrototypeOf(o, p);
147
+ }
148
+
149
+ function _isNativeReflectConstruct() {
150
+ if (typeof Reflect === "undefined" || !Reflect.construct) return false;
151
+ if (Reflect.construct.sham) return false;
152
+ if (typeof Proxy === "function") return true;
153
+
154
+ try {
155
+ Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
156
+ return true;
157
+ } catch (e) {
158
+ return false;
159
+ }
160
+ }
161
+
162
+ function _assertThisInitialized(self) {
163
+ if (self === void 0) {
164
+ throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
165
+ }
166
+
167
+ return self;
168
+ }
169
+
170
+ function _possibleConstructorReturn(self, call) {
171
+ if (call && (typeof call === "object" || typeof call === "function")) {
172
+ return call;
173
+ } else if (call !== void 0) {
174
+ throw new TypeError("Derived constructors may only return object or undefined");
175
+ }
176
+
177
+ return _assertThisInitialized(self);
178
+ }
179
+
180
+ function _createSuper(Derived) {
181
+ var hasNativeReflectConstruct = _isNativeReflectConstruct();
182
+
183
+ return function _createSuperInternal() {
184
+ var Super = _getPrototypeOf(Derived),
185
+ result;
186
+
187
+ if (hasNativeReflectConstruct) {
188
+ var NewTarget = _getPrototypeOf(this).constructor;
189
+
190
+ result = Reflect.construct(Super, arguments, NewTarget);
191
+ } else {
192
+ result = Super.apply(this, arguments);
193
+ }
194
+
195
+ return _possibleConstructorReturn(this, result);
196
+ };
197
+ }
198
+
199
+ function _superPropBase(object, property) {
200
+ while (!Object.prototype.hasOwnProperty.call(object, property)) {
201
+ object = _getPrototypeOf(object);
202
+ if (object === null) break;
203
+ }
204
+
205
+ return object;
206
+ }
207
+
208
+ function _get() {
209
+ if (typeof Reflect !== "undefined" && Reflect.get) {
210
+ _get = Reflect.get;
211
+ } else {
212
+ _get = function _get(target, property, receiver) {
213
+ var base = _superPropBase(target, property);
214
+
215
+ if (!base) return;
216
+ var desc = Object.getOwnPropertyDescriptor(base, property);
217
+
218
+ if (desc.get) {
219
+ return desc.get.call(arguments.length < 3 ? target : receiver);
220
+ }
221
+
222
+ return desc.value;
223
+ };
224
+ }
225
+
226
+ return _get.apply(this, arguments);
227
+ }
228
+
78
229
  function _toConsumableArray(arr) {
79
230
  return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
80
231
  }
@@ -108,191 +259,193 @@ function _nonIterableSpread() {
108
259
  throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
109
260
  }
110
261
 
111
- class Martini {
112
- constructor(gridSize = 257) {
113
- this.gridSize = gridSize;
114
- const tileSize = gridSize - 1;
115
- if (tileSize & tileSize - 1) throw new Error(`Expected grid size to be 2^n+1, got ${gridSize}.`);
116
- this.numTriangles = tileSize * tileSize * 2 - 2;
117
- this.numParentTriangles = this.numTriangles - tileSize * tileSize;
118
- this.indices = new Uint32Array(this.gridSize * this.gridSize); // coordinates for all possible triangles in an RTIN tile
262
+ var loadImage = function loadImage(url) {
263
+ return new Promise(function (resolve, reject) {
264
+ var img = new Image();
265
+ img.addEventListener("load", function () {
266
+ return resolve(img);
267
+ });
268
+ img.addEventListener("error", function (err) {
269
+ return reject(err);
270
+ });
271
+ img.crossOrigin = "anonymous";
272
+ img.src = url;
273
+ });
274
+ };
119
275
 
120
- this.coords = new Uint16Array(this.numTriangles * 4); // get triangle coordinates from its index in an implicit binary tree
276
+ var DefaultHeightmapResource = /*#__PURE__*/function () {
277
+ function DefaultHeightmapResource() {
278
+ var _this = this,
279
+ _opts$skipOddLevels,
280
+ _opts$tileSize,
281
+ _opts$maxZoom;
121
282
 
122
- for (let i = 0; i < this.numTriangles; i++) {
123
- let id = i + 2;
124
- let ax = 0,
125
- ay = 0,
126
- bx = 0,
127
- by = 0,
128
- cx = 0,
129
- cy = 0;
283
+ var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
130
284
 
131
- if (id & 1) {
132
- bx = by = cx = tileSize; // bottom-left triangle
133
- } else {
134
- ax = ay = cy = tileSize; // top-right triangle
135
- }
285
+ _classCallCheck(this, DefaultHeightmapResource);
136
286
 
137
- while ((id >>= 1) > 1) {
138
- const mx = ax + bx >> 1;
139
- const my = ay + by >> 1;
287
+ _defineProperty(this, "resource", null);
140
288
 
141
- if (id & 1) {
142
- // left half
143
- bx = ax;
144
- by = ay;
145
- ax = cx;
146
- ay = cy;
147
- } else {
148
- // right half
149
- ax = bx;
150
- ay = by;
151
- bx = cx;
152
- by = cy;
153
- }
289
+ _defineProperty(this, "tileSize", 256);
154
290
 
155
- cx = mx;
156
- cy = my;
157
- }
291
+ _defineProperty(this, "maxZoom", void 0);
158
292
 
159
- const k = i * 4;
160
- this.coords[k + 0] = ax;
161
- this.coords[k + 1] = ay;
162
- this.coords[k + 2] = bx;
163
- this.coords[k + 3] = by;
164
- }
165
- }
293
+ _defineProperty(this, "skipOddLevels", false);
166
294
 
167
- createTile(terrain) {
168
- return new Tile(terrain, this);
169
- }
295
+ _defineProperty(this, "contextQueue", void 0);
170
296
 
171
- }
297
+ _defineProperty(this, "getTilePixels", /*#__PURE__*/function () {
298
+ var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(coords) {
299
+ var url, img;
300
+ return regeneratorRuntime.wrap(function _callee$(_context) {
301
+ while (1) {
302
+ switch (_context.prev = _context.next) {
303
+ case 0:
304
+ url = _this.buildTileURL(coords);
305
+ _context.next = 3;
306
+ return loadImage(url);
172
307
 
173
- class Tile {
174
- constructor(terrain, martini) {
175
- const size = martini.gridSize;
176
- if (terrain.length !== size * size) throw new Error(`Expected terrain data of length ${size * size} (${size} x ${size}), got ${terrain.length}.`);
177
- this.terrain = terrain;
178
- this.martini = martini;
179
- this.errors = new Float32Array(terrain.length);
180
- this.update();
181
- }
308
+ case 3:
309
+ img = _context.sent;
310
+ return _context.abrupt("return", _this.getPixels(img));
182
311
 
183
- update() {
184
- const {
185
- numTriangles,
186
- numParentTriangles,
187
- coords,
188
- gridSize: size
189
- } = this.martini;
190
- const {
191
- terrain,
192
- errors
193
- } = this; // iterate over all possible triangles, starting from the smallest level
312
+ case 5:
313
+ case "end":
314
+ return _context.stop();
315
+ }
316
+ }
317
+ }, _callee);
318
+ }));
194
319
 
195
- for (let i = numTriangles - 1; i >= 0; i--) {
196
- const k = i * 4;
197
- const ax = coords[k + 0];
198
- const ay = coords[k + 1];
199
- const bx = coords[k + 2];
200
- const by = coords[k + 3];
201
- const mx = ax + bx >> 1;
202
- const my = ay + by >> 1;
203
- const cx = mx + my - ay;
204
- const cy = my + ax - mx; // calculate error in the middle of the long edge of the triangle
320
+ return function (_x) {
321
+ return _ref.apply(this, arguments);
322
+ };
323
+ }());
205
324
 
206
- const interpolatedHeight = (terrain[ay * size + ax] + terrain[by * size + bx]) / 2;
207
- const middleIndex = my * size + mx;
208
- const middleError = Math.abs(interpolatedHeight - terrain[middleIndex]);
209
- errors[middleIndex] = Math.max(errors[middleIndex], middleError);
325
+ if (opts.url) {
326
+ this.resource = cesium.Resource.createIfNeeded(opts.url);
327
+ }
210
328
 
211
- if (i < numParentTriangles) {
212
- // bigger triangles; accumulate error with children
213
- const leftChildIndex = (ay + cy >> 1) * size + (ax + cx >> 1);
214
- const rightChildIndex = (by + cy >> 1) * size + (bx + cx >> 1);
215
- errors[middleIndex] = Math.max(errors[middleIndex], errors[leftChildIndex], errors[rightChildIndex]);
329
+ this.skipOddLevels = (_opts$skipOddLevels = opts.skipOddLevels) !== null && _opts$skipOddLevels !== void 0 ? _opts$skipOddLevels : false;
330
+ this.tileSize = (_opts$tileSize = opts.tileSize) !== null && _opts$tileSize !== void 0 ? _opts$tileSize : 256;
331
+ this.maxZoom = (_opts$maxZoom = opts.maxZoom) !== null && _opts$maxZoom !== void 0 ? _opts$maxZoom : 15;
332
+ this.contextQueue = [];
333
+ }
334
+
335
+ _createClass(DefaultHeightmapResource, [{
336
+ key: "getCanvas",
337
+ value: function getCanvas() {
338
+ var ctx = this.contextQueue.pop();
339
+
340
+ if (ctx == null) {
341
+ var canvas = document.createElement("canvas");
342
+ canvas.width = this.tileSize;
343
+ canvas.height = this.tileSize;
344
+ var context = canvas.getContext("2d");
345
+ ctx = {
346
+ canvas: canvas,
347
+ context: context
348
+ };
216
349
  }
350
+
351
+ return ctx;
217
352
  }
218
- }
353
+ }, {
354
+ key: "getPixels",
355
+ value: function getPixels(img) {
356
+ var canvasRef = this.getCanvas();
357
+ var context = canvasRef.context; //context.scale(1, -1);
358
+ // Chrome appears to vertically flip the image for reasons that are unclear
359
+ // We can make it work in Chrome by drawing the image upside-down at this step.
219
360
 
220
- getMesh(maxError = 0, maxLength = null) {
221
- const {
222
- gridSize: size,
223
- indices
224
- } = this.martini;
225
- const {
226
- errors
227
- } = this;
228
- let numVertices = 0;
229
- let numTriangles = 0;
230
- const max = size - 1; // The maxLength parameter will cause triangles to be generated until the legs are below this length
231
- // It is meant to support cases where a certain mesh density is required to do spherical math on digital globes
361
+ context.drawImage(img, 0, 0, this.tileSize, this.tileSize);
362
+ var pixels = context.getImageData(0, 0, this.tileSize, this.tileSize);
363
+ context.clearRect(0, 0, this.tileSize, this.tileSize);
364
+ this.contextQueue.push(canvasRef);
365
+ return pixels;
366
+ }
367
+ }, {
368
+ key: "buildTileURL",
369
+ value: function buildTileURL(tileCoords) {
370
+ var _this$resource;
371
+
372
+ // reverseY for TMS tiling (https://gist.github.com/tmcw/4954720)
373
+ // See tiling schemes here: https://www.maptiler.com/google-maps-coordinates-tile-bounds-projection/
374
+ var z = tileCoords.z,
375
+ y = tileCoords.y;
376
+ return (_this$resource = this.resource) === null || _this$resource === void 0 ? void 0 : _this$resource.getDerivedResource({
377
+ templateValues: _objectSpread2(_objectSpread2({}, tileCoords), {}, {
378
+ reverseY: Math.pow(2, z) - y - 1
379
+ }),
380
+ preserveQueryParameters: true
381
+ }).getUrlComponent(true);
382
+ }
383
+ }, {
384
+ key: "getTileDataAvailable",
385
+ value: function getTileDataAvailable(_ref2) {
386
+ var z = _ref2.z;
387
+ if (z == this.maxZoom) return true;
388
+ if (z % 2 == 1 && this.skipOddLevels) return false;
389
+ if (z > this.maxZoom) return false;
390
+ return true;
391
+ }
392
+ }]);
393
+
394
+ return DefaultHeightmapResource;
395
+ }();
396
+
397
+ var ImageFormat;
398
+
399
+ (function (ImageFormat) {
400
+ ImageFormat["WEBP"] = "webp";
401
+ ImageFormat["PNG"] = "png";
402
+ ImageFormat["PNGRAW"] = "pngraw";
403
+ })(ImageFormat || (ImageFormat = {}));
404
+
405
+ var MapboxTerrainResource = /*#__PURE__*/function (_DefaultHeightmapReso) {
406
+ _inherits(MapboxTerrainResource, _DefaultHeightmapReso);
407
+
408
+ var _super = _createSuper(MapboxTerrainResource);
409
+
410
+ function MapboxTerrainResource() {
411
+ var _opts$highResolution, _opts$imageFormat;
412
+
413
+ var _this;
414
+
415
+ var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
416
+
417
+ _classCallCheck(this, MapboxTerrainResource);
418
+
419
+ _this = _super.call(this, opts);
232
420
 
233
- const maxScale = maxLength || size; // use an index grid to keep track of vertices that were already used to avoid duplication
421
+ _defineProperty(_assertThisInitialized(_this), "resource", null);
234
422
 
235
- indices.fill(0); // retrieve mesh in two stages that both traverse the error map:
236
- // - countElements: find used vertices (and assign each an index), and count triangles (for minimum allocation)
237
- // - processTriangle: fill the allocated vertices & triangles typed arrays
423
+ var highResolution = (_opts$highResolution = opts.highResolution) !== null && _opts$highResolution !== void 0 ? _opts$highResolution : false;
424
+ var format = (_opts$imageFormat = opts.imageFormat) !== null && _opts$imageFormat !== void 0 ? _opts$imageFormat : ImageFormat.WEBP; // overrides based on highResolution flag
238
425
 
239
- function countElements(ax, ay, bx, by, cx, cy) {
240
- const mx = ax + bx >> 1;
241
- const my = ay + by >> 1;
242
- const legLength = Math.abs(ax - cx) + Math.abs(ay - cy);
426
+ if (highResolution) {
427
+ if (opts.maxZoom === undefined) {
428
+ _this.maxZoom = 14;
429
+ }
243
430
 
244
- if (legLength > 1 && errors[my * size + mx] > maxError || legLength > maxScale) {
245
- countElements(cx, cy, ax, ay, mx, my);
246
- countElements(bx, by, cx, cy, mx, my);
247
- } else {
248
- indices[ay * size + ax] = indices[ay * size + ax] || ++numVertices;
249
- indices[by * size + bx] = indices[by * size + bx] || ++numVertices;
250
- indices[cy * size + cx] = indices[cy * size + cx] || ++numVertices;
251
- numTriangles++;
431
+ if (opts.tileSize === undefined) {
432
+ _this.tileSize = 512;
252
433
  }
253
434
  }
254
435
 
255
- countElements(0, 0, max, max, max, 0);
256
- countElements(max, max, 0, 0, 0, max);
257
- const vertices = new Uint16Array(numVertices * 2);
258
- const triangles = new Uint32Array(numTriangles * 3);
259
- let triIndex = 0;
260
-
261
- function processTriangle(ax, ay, bx, by, cx, cy) {
262
- const mx = ax + bx >> 1;
263
- const my = ay + by >> 1;
264
- const legLength = Math.abs(ax - cx) + Math.abs(ay - cy);
436
+ _this.resource = cesium.Resource.createIfNeeded("https://api.mapbox.com/v4/mapbox.terrain-rgb/{z}/{x}/{y}".concat(highResolution ? "@2x" : "", ".").concat(format));
265
437
 
266
- if (legLength > 1 && errors[my * size + mx] > maxError || legLength > maxScale) {
267
- // triangle doesn't approximate the surface well enough; drill down further
268
- processTriangle(cx, cy, ax, ay, mx, my);
269
- processTriangle(bx, by, cx, cy, mx, my);
270
- } else {
271
- // add a triangle
272
- const a = indices[ay * size + ax] - 1;
273
- const b = indices[by * size + bx] - 1;
274
- const c = indices[cy * size + cx] - 1;
275
- vertices[2 * a] = ax;
276
- vertices[2 * a + 1] = ay;
277
- vertices[2 * b] = bx;
278
- vertices[2 * b + 1] = by;
279
- vertices[2 * c] = cx;
280
- vertices[2 * c + 1] = cy;
281
- triangles[triIndex++] = a;
282
- triangles[triIndex++] = b;
283
- triangles[triIndex++] = c;
284
- }
438
+ if (opts.accessToken) {
439
+ _this.resource.setQueryParameters({
440
+ access_token: opts.accessToken
441
+ });
285
442
  }
286
443
 
287
- processTriangle(0, 0, max, max, max, 0);
288
- processTriangle(max, max, 0, 0, 0, max);
289
- return {
290
- vertices,
291
- triangles
292
- };
444
+ return _this;
293
445
  }
294
446
 
295
- }
447
+ return MapboxTerrainResource;
448
+ }(DefaultHeightmapResource);
296
449
 
297
450
  function decodeBase64(base64, enableUnicode) {
298
451
  var binaryString = atob(base64);
@@ -324,7 +477,7 @@ function createBase64WorkerFactory(base64, sourcemapArg, enableUnicodeArg) {
324
477
  };
325
478
  }
326
479
 
327
- var WorkerFactory = createBase64WorkerFactory('Lyogcm9sbHVwLXBsdWdpbi13ZWItd29ya2VyLWxvYWRlciAqLwp2YXIgd29ya2VyX2NvZGUgPSAoZnVuY3Rpb24gKGV4cG9ydHMpIHsKICAndXNlIHN0cmljdCc7CgogIGZ1bmN0aW9uIF90b0NvbnN1bWFibGVBcnJheShhcnIpIHsKICAgIHJldHVybiBfYXJyYXlXaXRob3V0SG9sZXMoYXJyKSB8fCBfaXRlcmFibGVUb0FycmF5KGFycikgfHwgX3Vuc3VwcG9ydGVkSXRlcmFibGVUb0FycmF5KGFycikgfHwgX25vbkl0ZXJhYmxlU3ByZWFkKCk7CiAgfQoKICBmdW5jdGlvbiBfYXJyYXlXaXRob3V0SG9sZXMoYXJyKSB7CiAgICBpZiAoQXJyYXkuaXNBcnJheShhcnIpKSByZXR1cm4gX2FycmF5TGlrZVRvQXJyYXkoYXJyKTsKICB9CgogIGZ1bmN0aW9uIF9pdGVyYWJsZVRvQXJyYXkoaXRlcikgewogICAgaWYgKHR5cGVvZiBTeW1ib2wgIT09ICJ1bmRlZmluZWQiICYmIGl0ZXJbU3ltYm9sLml0ZXJhdG9yXSAhPSBudWxsIHx8IGl0ZXJbIkBAaXRlcmF0b3IiXSAhPSBudWxsKSByZXR1cm4gQXJyYXkuZnJvbShpdGVyKTsKICB9CgogIGZ1bmN0aW9uIF91bnN1cHBvcnRlZEl0ZXJhYmxlVG9BcnJheShvLCBtaW5MZW4pIHsKICAgIGlmICghbykgcmV0dXJuOwogICAgaWYgKHR5cGVvZiBvID09PSAic3RyaW5nIikgcmV0dXJuIF9hcnJheUxpa2VUb0FycmF5KG8sIG1pbkxlbik7CiAgICB2YXIgbiA9IE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChvKS5zbGljZSg4LCAtMSk7CiAgICBpZiAobiA9PT0gIk9iamVjdCIgJiYgby5jb25zdHJ1Y3RvcikgbiA9IG8uY29uc3RydWN0b3IubmFtZTsKICAgIGlmIChuID09PSAiTWFwIiB8fCBuID09PSAiU2V0IikgcmV0dXJuIEFycmF5LmZyb20obyk7CiAgICBpZiAobiA9PT0gIkFyZ3VtZW50cyIgfHwgL14oPzpVaXxJKW50KD86OHwxNnwzMikoPzpDbGFtcGVkKT9BcnJheSQvLnRlc3QobikpIHJldHVybiBfYXJyYXlMaWtlVG9BcnJheShvLCBtaW5MZW4pOwogIH0KCiAgZnVuY3Rpb24gX2FycmF5TGlrZVRvQXJyYXkoYXJyLCBsZW4pIHsKICAgIGlmIChsZW4gPT0gbnVsbCB8fCBsZW4gPiBhcnIubGVuZ3RoKSBsZW4gPSBhcnIubGVuZ3RoOwoKICAgIGZvciAodmFyIGkgPSAwLCBhcnIyID0gbmV3IEFycmF5KGxlbik7IGkgPCBsZW47IGkrKykgYXJyMltpXSA9IGFycltpXTsKCiAgICByZXR1cm4gYXJyMjsKICB9CgogIGZ1bmN0aW9uIF9ub25JdGVyYWJsZVNwcmVhZCgpIHsKICAgIHRocm93IG5ldyBUeXBlRXJyb3IoIkludmFsaWQgYXR0ZW1wdCB0byBzcHJlYWQgbm9uLWl0ZXJhYmxlIGluc3RhbmNlLlxuSW4gb3JkZXIgdG8gYmUgaXRlcmFibGUsIG5vbi1hcnJheSBvYmplY3RzIG11c3QgaGF2ZSBhIFtTeW1ib2wuaXRlcmF0b3JdKCkgbWV0aG9kLiIpOwogIH0KCiAgLy8gV2Ugc2hvdWxkIHNhdmUgdGhlc2UKICAvL2NvbnN0IGNhbnZhcyA9IG5ldyBPZmZzY3JlZW5DYW52YXMoMjU2LCAyNTYpOwogIC8vY29uc3QgY3R4ID0gY2FudmFzLmdldENvbnRleHQoIjJkIik7CiAgZnVuY3Rpb24gbWFwYm94VGVycmFpblRvR3JpZChwbmcpIHsKICAgIC8vIG1heWJlIHdlIHNob3VsZCBkbyB0aGlzIG9uIHRoZSBHUFUgdXNpbmcgUkVHTD8KICAgIC8vIGJ1dCB0aGF0IHdvdWxkIHJlcXVpcmUgR1BVIC0+IENQVSAtPiBHUFUKICAgIHZhciBncmlkU2l6ZSA9IHBuZy5zaGFwZVswXSArIDE7CiAgICB2YXIgdGVycmFpbiA9IG5ldyBGbG9hdDMyQXJyYXkoZ3JpZFNpemUgKiBncmlkU2l6ZSk7CiAgICB2YXIgdGlsZVNpemUgPSBwbmcuc2hhcGVbMF07IC8vIGRlY29kZSB0ZXJyYWluIHZhbHVlcwoKICAgIGZvciAodmFyIHkgPSAwOyB5IDwgdGlsZVNpemU7IHkrKykgewogICAgICBmb3IgKHZhciB4ID0gMDsgeCA8IHRpbGVTaXplOyB4KyspIHsKICAgICAgICB2YXIgeWMgPSB5OwogICAgICAgIHZhciByID0gcG5nLmdldCh4LCB5YywgMCk7CiAgICAgICAgdmFyIGcgPSBwbmcuZ2V0KHgsIHljLCAxKTsKICAgICAgICB2YXIgYiA9IHBuZy5nZXQoeCwgeWMsIDIpOwogICAgICAgIHRlcnJhaW5beSAqIGdyaWRTaXplICsgeF0gPSByICogMjU2ICogMjU2IC8gMTAuMCArIGcgKiAyNTYuMCAvIDEwLjAgKyBiIC8gMTAuMCAtIDEwMDAwLjA7CiAgICAgIH0KICAgIH0gLy8gYmFja2ZpbGwgcmlnaHQgYW5kIGJvdHRvbSBib3JkZXJzCgoKICAgIGZvciAodmFyIF94ID0gMDsgX3ggPCBncmlkU2l6ZSAtIDE7IF94KyspIHsKICAgICAgdGVycmFpbltncmlkU2l6ZSAqIChncmlkU2l6ZSAtIDEpICsgX3hdID0gdGVycmFpbltncmlkU2l6ZSAqIChncmlkU2l6ZSAtIDIpICsgX3hdOwogICAgfQoKICAgIGZvciAodmFyIF95ID0gMDsgX3kgPCBncmlkU2l6ZTsgX3krKykgewogICAgICB0ZXJyYWluW2dyaWRTaXplICogX3kgKyBncmlkU2l6ZSAtIDFdID0gdGVycmFpbltncmlkU2l6ZSAqIF95ICsgZ3JpZFNpemUgLSAyXTsKICAgIH0KCiAgICByZXR1cm4gdGVycmFpbjsKICB9CgogIGZ1bmN0aW9uIGNyZWF0ZVF1YW50aXplZE1lc2hEYXRhKHRpbGUsIG1lc2gpIHsKICAgIHZhciB0aWxlU2l6ZSA9IGFyZ3VtZW50cy5sZW5ndGggPiAyICYmIGFyZ3VtZW50c1syXSAhPT0gdW5kZWZpbmVkID8gYXJndW1lbnRzWzJdIDogMjU2OwogICAgdmFyIHh2YWxzID0gW107CiAgICB2YXIgeXZhbHMgPSBbXTsKICAgIHZhciBoZWlnaHRNZXRlcnMgPSBbXTsKICAgIHZhciBub3J0aEluZGljZXMgPSBbXTsKICAgIHZhciBzb3V0aEluZGljZXMgPSBbXTsKICAgIHZhciBlYXN0SW5kaWNlcyA9IFtdOwogICAgdmFyIHdlc3RJbmRpY2VzID0gW107CgogICAgZm9yICh2YXIgaXggPSAwOyBpeCA8IG1lc2gudmVydGljZXMubGVuZ3RoIC8gMjsgaXgrKykgewogICAgICB2YXIgdmVydGV4SXggPSBpeDsKICAgICAgdmFyIHB4ID0gbWVzaC52ZXJ0aWNlc1tpeCAqIDJdOwogICAgICB2YXIgcHkgPSBtZXNoLnZlcnRpY2VzW2l4ICogMiArIDFdOwogICAgICBoZWlnaHRNZXRlcnMucHVzaCh0aWxlLnRlcnJhaW5bcHkgKiAodGlsZVNpemUgKyAxKSArIHB4XSk7CiAgICAgIGlmIChweSA9PSAwKSBub3J0aEluZGljZXMucHVzaCh2ZXJ0ZXhJeCk7CiAgICAgIGlmIChweSA9PSB0aWxlU2l6ZSkgc291dGhJbmRpY2VzLnB1c2godmVydGV4SXgpOwogICAgICBpZiAocHggPT0gMCkgd2VzdEluZGljZXMucHVzaCh2ZXJ0ZXhJeCk7CiAgICAgIGlmIChweCA9PSB0aWxlU2l6ZSkgZWFzdEluZGljZXMucHVzaCh2ZXJ0ZXhJeCk7CiAgICAgIHZhciBzY2FsYXIgPSAzMjc2OC4wIC8gdGlsZVNpemU7CiAgICAgIHZhciB4diA9IHB4ICogc2NhbGFyOwogICAgICB2YXIgeXYgPSAodGlsZVNpemUgLSBweSkgKiBzY2FsYXI7CiAgICAgIHh2YWxzLnB1c2goeHYpOwogICAgICB5dmFscy5wdXNoKHl2KTsKICAgIH0KCiAgICB2YXIgbWF4SGVpZ2h0ID0gTWF0aC5tYXguYXBwbHkodGhpcywgaGVpZ2h0TWV0ZXJzKTsKICAgIHZhciBtaW5IZWlnaHQgPSBNYXRoLm1pbi5hcHBseSh0aGlzLCBoZWlnaHRNZXRlcnMpOwogICAgdmFyIGhlaWdodHMgPSBoZWlnaHRNZXRlcnMubWFwKGZ1bmN0aW9uIChkKSB7CiAgICAgIGlmIChtYXhIZWlnaHQgLSBtaW5IZWlnaHQgPCAxKSByZXR1cm4gMDsKICAgICAgcmV0dXJuIChkIC0gbWluSGVpZ2h0KSAqICgzMjc2Ny4wIC8gKG1heEhlaWdodCAtIG1pbkhlaWdodCkpOwogICAgfSk7CiAgICB2YXIgdHJpYW5nbGVzID0gbmV3IFVpbnQxNkFycmF5KG1lc2gudHJpYW5nbGVzKTsKICAgIHZhciBxdWFudGl6ZWRWZXJ0aWNlcyA9IG5ldyBVaW50MTZBcnJheSggLy92ZXJ0cwogICAgW10uY29uY2F0KHh2YWxzLCB5dmFscywgX3RvQ29uc3VtYWJsZUFycmF5KGhlaWdodHMpKSk7IC8vIFNFIE5XIE5FCiAgICAvLyBORSBOVyBTRQoKICAgIHJldHVybiB7CiAgICAgIG1pbmltdW1IZWlnaHQ6IG1pbkhlaWdodCwKICAgICAgbWF4aW11bUhlaWdodDogbWF4SGVpZ2h0LAogICAgICBxdWFudGl6ZWRWZXJ0aWNlczogcXVhbnRpemVkVmVydGljZXMsCiAgICAgIGluZGljZXM6IHRyaWFuZ2xlcywKICAgICAgd2VzdEluZGljZXM6IHdlc3RJbmRpY2VzLAogICAgICBzb3V0aEluZGljZXM6IHNvdXRoSW5kaWNlcywKICAgICAgZWFzdEluZGljZXM6IGVhc3RJbmRpY2VzLAogICAgICBub3J0aEluZGljZXM6IG5vcnRoSW5kaWNlcwogICAgfTsKICB9CgogIGZ1bmN0aW9uIGlvdGEobikgewogICAgdmFyIHJlc3VsdCA9IG5ldyBBcnJheShuKTsKICAgIGZvcih2YXIgaT0wOyBpPG47ICsraSkgewogICAgICByZXN1bHRbaV0gPSBpOwogICAgfQogICAgcmV0dXJuIHJlc3VsdAogIH0KCiAgdmFyIGlvdGFfMSA9IGlvdGE7CgogIC8qIQogICAqIERldGVybWluZSBpZiBhbiBvYmplY3QgaXMgYSBCdWZmZXIKICAgKgogICAqIEBhdXRob3IgICBGZXJvc3MgQWJvdWtoYWRpamVoIDxodHRwczovL2Zlcm9zcy5vcmc+CiAgICogQGxpY2Vuc2UgIE1JVAogICAqLwogIC8vIFRoZSBfaXNCdWZmZXIgY2hlY2sgaXMgZm9yIFNhZmFyaSA1LTcgc3VwcG9ydCwgYmVjYXVzZSBpdCdzIG1pc3NpbmcKICAvLyBPYmplY3QucHJvdG90eXBlLmNvbnN0cnVjdG9yLiBSZW1vdmUgdGhpcyBldmVudHVhbGx5CiAgdmFyIGlzQnVmZmVyXzEgPSBmdW5jdGlvbiAob2JqKSB7CiAgICByZXR1cm4gb2JqICE9IG51bGwgJiYgKGlzQnVmZmVyKG9iaikgfHwgaXNTbG93QnVmZmVyKG9iaikgfHwgISFvYmouX2lzQnVmZmVyKQogIH07CgogIGZ1bmN0aW9uIGlzQnVmZmVyIChvYmopIHsKICAgIHJldHVybiAhIW9iai5jb25zdHJ1Y3RvciAmJiB0eXBlb2Ygb2JqLmNvbnN0cnVjdG9yLmlzQnVmZmVyID09PSAnZnVuY3Rpb24nICYmIG9iai5jb25zdHJ1Y3Rvci5pc0J1ZmZlcihvYmopCiAgfQoKICAvLyBGb3IgTm9kZSB2MC4xMCBzdXBwb3J0LiBSZW1vdmUgdGhpcyBldmVudHVhbGx5LgogIGZ1bmN0aW9uIGlzU2xvd0J1ZmZlciAob2JqKSB7CiAgICByZXR1cm4gdHlwZW9mIG9iai5yZWFkRmxvYXRMRSA9PT0gJ2Z1bmN0aW9uJyAmJiB0eXBlb2Ygb2JqLnNsaWNlID09PSAnZnVuY3Rpb24nICYmIGlzQnVmZmVyKG9iai5zbGljZSgwLCAwKSkKICB9CgogIHZhciBoYXNUeXBlZEFycmF5cyAgPSAoKHR5cGVvZiBGbG9hdDY0QXJyYXkpICE9PSAidW5kZWZpbmVkIik7CgogIGZ1bmN0aW9uIGNvbXBhcmUxc3QoYSwgYikgewogICAgcmV0dXJuIGFbMF0gLSBiWzBdCiAgfQoKICBmdW5jdGlvbiBvcmRlcigpIHsKICAgIHZhciBzdHJpZGUgPSB0aGlzLnN0cmlkZTsKICAgIHZhciB0ZXJtcyA9IG5ldyBBcnJheShzdHJpZGUubGVuZ3RoKTsKICAgIHZhciBpOwogICAgZm9yKGk9MDsgaTx0ZXJtcy5sZW5ndGg7ICsraSkgewogICAgICB0ZXJtc1tpXSA9IFtNYXRoLmFicyhzdHJpZGVbaV0pLCBpXTsKICAgIH0KICAgIHRlcm1zLnNvcnQoY29tcGFyZTFzdCk7CiAgICB2YXIgcmVzdWx0ID0gbmV3IEFycmF5KHRlcm1zLmxlbmd0aCk7CiAgICBmb3IoaT0wOyBpPHJlc3VsdC5sZW5ndGg7ICsraSkgewogICAgICByZXN1bHRbaV0gPSB0ZXJtc1tpXVsxXTsKICAgIH0KICAgIHJldHVybiByZXN1bHQKICB9CgogIGZ1bmN0aW9uIGNvbXBpbGVDb25zdHJ1Y3RvcihkdHlwZSwgZGltZW5zaW9uKSB7CiAgICB2YXIgY2xhc3NOYW1lID0gWyJWaWV3IiwgZGltZW5zaW9uLCAiZCIsIGR0eXBlXS5qb2luKCIiKTsKICAgIGlmKGRpbWVuc2lvbiA8IDApIHsKICAgICAgY2xhc3NOYW1lID0gIlZpZXdfTmlsIiArIGR0eXBlOwogICAgfQogICAgdmFyIHVzZUdldHRlcnMgPSAoZHR5cGUgPT09ICJnZW5lcmljIik7CgogICAgaWYoZGltZW5zaW9uID09PSAtMSkgewogICAgICAvL1NwZWNpYWwgY2FzZSBmb3IgdHJpdmlhbCBhcnJheXMKICAgICAgdmFyIGNvZGUgPQogICAgICAgICJmdW5jdGlvbiAiK2NsYXNzTmFtZSsiKGEpe3RoaXMuZGF0YT1hO307XAp2YXIgcHJvdG89IitjbGFzc05hbWUrIi5wcm90b3R5cGU7XApwcm90by5kdHlwZT0nIitkdHlwZSsiJztcCnByb3RvLmluZGV4PWZ1bmN0aW9uKCl7cmV0dXJuIC0xfTtcCnByb3RvLnNpemU9MDtcCnByb3RvLmRpbWVuc2lvbj0tMTtcCnByb3RvLnNoYXBlPXByb3RvLnN0cmlkZT1wcm90by5vcmRlcj1bXTtcCnByb3RvLmxvPXByb3RvLmhpPXByb3RvLnRyYW5zcG9zZT1wcm90by5zdGVwPVwKZnVuY3Rpb24oKXtyZXR1cm4gbmV3ICIrY2xhc3NOYW1lKyIodGhpcy5kYXRhKTt9O1wKcHJvdG8uZ2V0PXByb3RvLnNldD1mdW5jdGlvbigpe307XApwcm90by5waWNrPWZ1bmN0aW9uKCl7cmV0dXJuIG51bGx9O1wKcmV0dXJuIGZ1bmN0aW9uIGNvbnN0cnVjdF8iK2NsYXNzTmFtZSsiKGEpe3JldHVybiBuZXcgIitjbGFzc05hbWUrIihhKTt9IjsKICAgICAgdmFyIHByb2NlZHVyZSA9IG5ldyBGdW5jdGlvbihjb2RlKTsKICAgICAgcmV0dXJuIHByb2NlZHVyZSgpCiAgICB9IGVsc2UgaWYoZGltZW5zaW9uID09PSAwKSB7CiAgICAgIC8vU3BlY2lhbCBjYXNlIGZvciAwZCBhcnJheXMKICAgICAgdmFyIGNvZGUgPQogICAgICAgICJmdW5jdGlvbiAiK2NsYXNzTmFtZSsiKGEsZCkge1wKdGhpcy5kYXRhID0gYTtcCnRoaXMub2Zmc2V0ID0gZFwKfTtcCnZhciBwcm90bz0iK2NsYXNzTmFtZSsiLnByb3RvdHlwZTtcCnByb3RvLmR0eXBlPSciK2R0eXBlKyInO1wKcHJvdG8uaW5kZXg9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5vZmZzZXR9O1wKcHJvdG8uZGltZW5zaW9uPTA7XApwcm90by5zaXplPTE7XApwcm90by5zaGFwZT1cCnByb3RvLnN0cmlkZT1cCnByb3RvLm9yZGVyPVtdO1wKcHJvdG8ubG89XApwcm90by5oaT1cCnByb3RvLnRyYW5zcG9zZT1cCnByb3RvLnN0ZXA9ZnVuY3Rpb24gIitjbGFzc05hbWUrIl9jb3B5KCkge1wKcmV0dXJuIG5ldyAiK2NsYXNzTmFtZSsiKHRoaXMuZGF0YSx0aGlzLm9mZnNldClcCn07XApwcm90by5waWNrPWZ1bmN0aW9uICIrY2xhc3NOYW1lKyJfcGljaygpe1wKcmV0dXJuIFRyaXZpYWxBcnJheSh0aGlzLmRhdGEpO1wKfTtcCnByb3RvLnZhbHVlT2Y9cHJvdG8uZ2V0PWZ1bmN0aW9uICIrY2xhc3NOYW1lKyJfZ2V0KCl7XApyZXR1cm4gIisodXNlR2V0dGVycyA/ICJ0aGlzLmRhdGEuZ2V0KHRoaXMub2Zmc2V0KSIgOiAidGhpcy5kYXRhW3RoaXMub2Zmc2V0XSIpKwogICJ9O1wKcHJvdG8uc2V0PWZ1bmN0aW9uICIrY2xhc3NOYW1lKyJfc2V0KHYpe1wKcmV0dXJuICIrKHVzZUdldHRlcnMgPyAidGhpcy5kYXRhLnNldCh0aGlzLm9mZnNldCx2KSIgOiAidGhpcy5kYXRhW3RoaXMub2Zmc2V0XT12IikrIlwKfTtcCnJldHVybiBmdW5jdGlvbiBjb25zdHJ1Y3RfIitjbGFzc05hbWUrIihhLGIsYyxkKXtyZXR1cm4gbmV3ICIrY2xhc3NOYW1lKyIoYSxkKX0iOwogICAgICB2YXIgcHJvY2VkdXJlID0gbmV3IEZ1bmN0aW9uKCJUcml2aWFsQXJyYXkiLCBjb2RlKTsKICAgICAgcmV0dXJuIHByb2NlZHVyZShDQUNIRURfQ09OU1RSVUNUT1JTW2R0eXBlXVswXSkKICAgIH0KCiAgICB2YXIgY29kZSA9IFsiJ3VzZSBzdHJpY3QnIl07CgogICAgLy9DcmVhdGUgY29uc3RydWN0b3IgZm9yIHZpZXcKICAgIHZhciBpbmRpY2VzID0gaW90YV8xKGRpbWVuc2lvbik7CiAgICB2YXIgYXJncyA9IGluZGljZXMubWFwKGZ1bmN0aW9uKGkpIHsgcmV0dXJuICJpIitpIH0pOwogICAgdmFyIGluZGV4X3N0ciA9ICJ0aGlzLm9mZnNldCsiICsgaW5kaWNlcy5tYXAoZnVuY3Rpb24oaSkgewogICAgICAgICAgcmV0dXJuICJ0aGlzLnN0cmlkZVsiICsgaSArICJdKmkiICsgaQogICAgICAgIH0pLmpvaW4oIisiKTsKICAgIHZhciBzaGFwZUFyZyA9IGluZGljZXMubWFwKGZ1bmN0aW9uKGkpIHsKICAgICAgICByZXR1cm4gImIiK2kKICAgICAgfSkuam9pbigiLCIpOwogICAgdmFyIHN0cmlkZUFyZyA9IGluZGljZXMubWFwKGZ1bmN0aW9uKGkpIHsKICAgICAgICByZXR1cm4gImMiK2kKICAgICAgfSkuam9pbigiLCIpOwogICAgY29kZS5wdXNoKAogICAgICAiZnVuY3Rpb24gIitjbGFzc05hbWUrIihhLCIgKyBzaGFwZUFyZyArICIsIiArIHN0cmlkZUFyZyArICIsZCl7dGhpcy5kYXRhPWEiLAogICAgICAgICJ0aGlzLnNoYXBlPVsiICsgc2hhcGVBcmcgKyAiXSIsCiAgICAgICAgInRoaXMuc3RyaWRlPVsiICsgc3RyaWRlQXJnICsgIl0iLAogICAgICAgICJ0aGlzLm9mZnNldD1kfDB9IiwKICAgICAgInZhciBwcm90bz0iK2NsYXNzTmFtZSsiLnByb3RvdHlwZSIsCiAgICAgICJwcm90by5kdHlwZT0nIitkdHlwZSsiJyIsCiAgICAgICJwcm90by5kaW1lbnNpb249IitkaW1lbnNpb24pOwoKICAgIC8vdmlldy5zaXplOgogICAgY29kZS5wdXNoKCJPYmplY3QuZGVmaW5lUHJvcGVydHkocHJvdG8sJ3NpemUnLHtnZXQ6ZnVuY3Rpb24gIitjbGFzc05hbWUrIl9zaXplKCl7XApyZXR1cm4gIitpbmRpY2VzLm1hcChmdW5jdGlvbihpKSB7IHJldHVybiAidGhpcy5zaGFwZVsiK2krIl0iIH0pLmpvaW4oIioiKSwKICAifX0pIik7CgogICAgLy92aWV3Lm9yZGVyOgogICAgaWYoZGltZW5zaW9uID09PSAxKSB7CiAgICAgIGNvZGUucHVzaCgicHJvdG8ub3JkZXI9WzBdIik7CiAgICB9IGVsc2UgewogICAgICBjb2RlLnB1c2goIk9iamVjdC5kZWZpbmVQcm9wZXJ0eShwcm90bywnb3JkZXInLHtnZXQ6Iik7CiAgICAgIGlmKGRpbWVuc2lvbiA8IDQpIHsKICAgICAgICBjb2RlLnB1c2goImZ1bmN0aW9uICIrY2xhc3NOYW1lKyJfb3JkZXIoKXsiKTsKICAgICAgICBpZihkaW1lbnNpb24gPT09IDIpIHsKICAgICAgICAgIGNvZGUucHVzaCgicmV0dXJuIChNYXRoLmFicyh0aGlzLnN0cmlkZVswXSk+TWF0aC5hYnModGhpcy5zdHJpZGVbMV0pKT9bMSwwXTpbMCwxXX19KSIpOwogICAgICAgIH0gZWxzZSBpZihkaW1lbnNpb24gPT09IDMpIHsKICAgICAgICAgIGNvZGUucHVzaCgKICAidmFyIHMwPU1hdGguYWJzKHRoaXMuc3RyaWRlWzBdKSxzMT1NYXRoLmFicyh0aGlzLnN0cmlkZVsxXSksczI9TWF0aC5hYnModGhpcy5zdHJpZGVbMl0pO1wKaWYoczA+czEpe1wKaWYoczE+czIpe1wKcmV0dXJuIFsyLDEsMF07XAp9ZWxzZSBpZihzMD5zMil7XApyZXR1cm4gWzEsMiwwXTtcCn1lbHNle1wKcmV0dXJuIFsxLDAsMl07XAp9XAp9ZWxzZSBpZihzMD5zMil7XApyZXR1cm4gWzIsMCwxXTtcCn1lbHNlIGlmKHMyPnMxKXtcCnJldHVybiBbMCwxLDJdO1wKfWVsc2V7XApyZXR1cm4gWzAsMiwxXTtcCn19fSkiKTsKICAgICAgICB9CiAgICAgIH0gZWxzZSB7CiAgICAgICAgY29kZS5wdXNoKCJPUkRFUn0pIik7CiAgICAgIH0KICAgIH0KCiAgICAvL3ZpZXcuc2V0KGkwLCAuLi4sIHYpOgogICAgY29kZS5wdXNoKAogICJwcm90by5zZXQ9ZnVuY3Rpb24gIitjbGFzc05hbWUrIl9zZXQoIithcmdzLmpvaW4oIiwiKSsiLHYpeyIpOwogICAgaWYodXNlR2V0dGVycykgewogICAgICBjb2RlLnB1c2goInJldHVybiB0aGlzLmRhdGEuc2V0KCIraW5kZXhfc3RyKyIsdil9Iik7CiAgICB9IGVsc2UgewogICAgICBjb2RlLnB1c2goInJldHVybiB0aGlzLmRhdGFbIitpbmRleF9zdHIrIl09dn0iKTsKICAgIH0KCiAgICAvL3ZpZXcuZ2V0KGkwLCAuLi4pOgogICAgY29kZS5wdXNoKCJwcm90by5nZXQ9ZnVuY3Rpb24gIitjbGFzc05hbWUrIl9nZXQoIithcmdzLmpvaW4oIiwiKSsiKXsiKTsKICAgIGlmKHVzZUdldHRlcnMpIHsKICAgICAgY29kZS5wdXNoKCJyZXR1cm4gdGhpcy5kYXRhLmdldCgiK2luZGV4X3N0cisiKX0iKTsKICAgIH0gZWxzZSB7CiAgICAgIGNvZGUucHVzaCgicmV0dXJuIHRoaXMuZGF0YVsiK2luZGV4X3N0cisiXX0iKTsKICAgIH0KCiAgICAvL3ZpZXcuaW5kZXg6CiAgICBjb2RlLnB1c2goCiAgICAgICJwcm90by5pbmRleD1mdW5jdGlvbiAiK2NsYXNzTmFtZSsiX2luZGV4KCIsIGFyZ3Muam9pbigpLCAiKXtyZXR1cm4gIitpbmRleF9zdHIrIn0iKTsKCiAgICAvL3ZpZXcuaGkoKToKICAgIGNvZGUucHVzaCgicHJvdG8uaGk9ZnVuY3Rpb24gIitjbGFzc05hbWUrIl9oaSgiK2FyZ3Muam9pbigiLCIpKyIpe3JldHVybiBuZXcgIitjbGFzc05hbWUrIih0aGlzLmRhdGEsIisKICAgICAgaW5kaWNlcy5tYXAoZnVuY3Rpb24oaSkgewogICAgICAgIHJldHVybiBbIih0eXBlb2YgaSIsaSwiIT09J251bWJlcid8fGkiLGksIjwwKT90aGlzLnNoYXBlWyIsIGksICJdOmkiLCBpLCJ8MCJdLmpvaW4oIiIpCiAgICAgIH0pLmpvaW4oIiwiKSsiLCIrCiAgICAgIGluZGljZXMubWFwKGZ1bmN0aW9uKGkpIHsKICAgICAgICByZXR1cm4gInRoaXMuc3RyaWRlWyIraSArICJdIgogICAgICB9KS5qb2luKCIsIikrIix0aGlzLm9mZnNldCl9Iik7CgogICAgLy92aWV3LmxvKCk6CiAgICB2YXIgYV92YXJzID0gaW5kaWNlcy5tYXAoZnVuY3Rpb24oaSkgeyByZXR1cm4gImEiK2krIj10aGlzLnNoYXBlWyIraSsiXSIgfSk7CiAgICB2YXIgY192YXJzID0gaW5kaWNlcy5tYXAoZnVuY3Rpb24oaSkgeyByZXR1cm4gImMiK2krIj10aGlzLnN0cmlkZVsiK2krIl0iIH0pOwogICAgY29kZS5wdXNoKCJwcm90by5sbz1mdW5jdGlvbiAiK2NsYXNzTmFtZSsiX2xvKCIrYXJncy5qb2luKCIsIikrIil7dmFyIGI9dGhpcy5vZmZzZXQsZD0wLCIrYV92YXJzLmpvaW4oIiwiKSsiLCIrY192YXJzLmpvaW4oIiwiKSk7CiAgICBmb3IodmFyIGk9MDsgaTxkaW1lbnNpb247ICsraSkgewogICAgICBjb2RlLnB1c2goCiAgImlmKHR5cGVvZiBpIitpKyI9PT0nbnVtYmVyJyYmaSIraSsiPj0wKXtcCmQ9aSIraSsifDA7XApiKz1jIitpKyIqZDtcCmEiK2krIi09ZH0iKTsKICAgIH0KICAgIGNvZGUucHVzaCgicmV0dXJuIG5ldyAiK2NsYXNzTmFtZSsiKHRoaXMuZGF0YSwiKwogICAgICBpbmRpY2VzLm1hcChmdW5jdGlvbihpKSB7CiAgICAgICAgcmV0dXJuICJhIitpCiAgICAgIH0pLmpvaW4oIiwiKSsiLCIrCiAgICAgIGluZGljZXMubWFwKGZ1bmN0aW9uKGkpIHsKICAgICAgICByZXR1cm4gImMiK2kKICAgICAgfSkuam9pbigiLCIpKyIsYil9Iik7CgogICAgLy92aWV3LnN0ZXAoKToKICAgIGNvZGUucHVzaCgicHJvdG8uc3RlcD1mdW5jdGlvbiAiK2NsYXNzTmFtZSsiX3N0ZXAoIithcmdzLmpvaW4oIiwiKSsiKXt2YXIgIisKICAgICAgaW5kaWNlcy5tYXAoZnVuY3Rpb24oaSkgewogICAgICAgIHJldHVybiAiYSIraSsiPXRoaXMuc2hhcGVbIitpKyJdIgogICAgICB9KS5qb2luKCIsIikrIiwiKwogICAgICBpbmRpY2VzLm1hcChmdW5jdGlvbihpKSB7CiAgICAgICAgcmV0dXJuICJiIitpKyI9dGhpcy5zdHJpZGVbIitpKyJdIgogICAgICB9KS5qb2luKCIsIikrIixjPXRoaXMub2Zmc2V0LGQ9MCxjZWlsPU1hdGguY2VpbCIpOwogICAgZm9yKHZhciBpPTA7IGk8ZGltZW5zaW9uOyArK2kpIHsKICAgICAgY29kZS5wdXNoKAogICJpZih0eXBlb2YgaSIraSsiPT09J251bWJlcicpe1wKZD1pIitpKyJ8MDtcCmlmKGQ8MCl7XApjKz1iIitpKyIqKGEiK2krIi0xKTtcCmEiK2krIj1jZWlsKC1hIitpKyIvZClcCn1lbHNle1wKYSIraSsiPWNlaWwoYSIraSsiL2QpXAp9XApiIitpKyIqPWRcCn0iKTsKICAgIH0KICAgIGNvZGUucHVzaCgicmV0dXJuIG5ldyAiK2NsYXNzTmFtZSsiKHRoaXMuZGF0YSwiKwogICAgICBpbmRpY2VzLm1hcChmdW5jdGlvbihpKSB7CiAgICAgICAgcmV0dXJuICJhIiArIGkKICAgICAgfSkuam9pbigiLCIpKyIsIisKICAgICAgaW5kaWNlcy5tYXAoZnVuY3Rpb24oaSkgewogICAgICAgIHJldHVybiAiYiIgKyBpCiAgICAgIH0pLmpvaW4oIiwiKSsiLGMpfSIpOwoKICAgIC8vdmlldy50cmFuc3Bvc2UoKToKICAgIHZhciB0U2hhcGUgPSBuZXcgQXJyYXkoZGltZW5zaW9uKTsKICAgIHZhciB0U3RyaWRlID0gbmV3IEFycmF5KGRpbWVuc2lvbik7CiAgICBmb3IodmFyIGk9MDsgaTxkaW1lbnNpb247ICsraSkgewogICAgICB0U2hhcGVbaV0gPSAiYVtpIitpKyJdIjsKICAgICAgdFN0cmlkZVtpXSA9ICJiW2kiK2krIl0iOwogICAgfQogICAgY29kZS5wdXNoKCJwcm90by50cmFuc3Bvc2U9ZnVuY3Rpb24gIitjbGFzc05hbWUrIl90cmFuc3Bvc2UoIithcmdzKyIpeyIrCiAgICAgIGFyZ3MubWFwKGZ1bmN0aW9uKG4saWR4KSB7IHJldHVybiBuICsgIj0oIiArIG4gKyAiPT09dW5kZWZpbmVkPyIgKyBpZHggKyAiOiIgKyBuICsgInwwKSJ9KS5qb2luKCI7IiksCiAgICAgICJ2YXIgYT10aGlzLnNoYXBlLGI9dGhpcy5zdHJpZGU7cmV0dXJuIG5ldyAiK2NsYXNzTmFtZSsiKHRoaXMuZGF0YSwiK3RTaGFwZS5qb2luKCIsIikrIiwiK3RTdHJpZGUuam9pbigiLCIpKyIsdGhpcy5vZmZzZXQpfSIpOwoKICAgIC8vdmlldy5waWNrKCk6CiAgICBjb2RlLnB1c2goInByb3RvLnBpY2s9ZnVuY3Rpb24gIitjbGFzc05hbWUrIl9waWNrKCIrYXJncysiKXt2YXIgYT1bXSxiPVtdLGM9dGhpcy5vZmZzZXQiKTsKICAgIGZvcih2YXIgaT0wOyBpPGRpbWVuc2lvbjsgKytpKSB7CiAgICAgIGNvZGUucHVzaCgiaWYodHlwZW9mIGkiK2krIj09PSdudW1iZXInJiZpIitpKyI+PTApe2M9KGMrdGhpcy5zdHJpZGVbIitpKyJdKmkiK2krIil8MH1lbHNle2EucHVzaCh0aGlzLnNoYXBlWyIraSsiXSk7Yi5wdXNoKHRoaXMuc3RyaWRlWyIraSsiXSl9Iik7CiAgICB9CiAgICBjb2RlLnB1c2goInZhciBjdG9yPUNUT1JfTElTVFthLmxlbmd0aCsxXTtyZXR1cm4gY3Rvcih0aGlzLmRhdGEsYSxiLGMpfSIpOwoKICAgIC8vQWRkIHJldHVybiBzdGF0ZW1lbnQKICAgIGNvZGUucHVzaCgicmV0dXJuIGZ1bmN0aW9uIGNvbnN0cnVjdF8iK2NsYXNzTmFtZSsiKGRhdGEsc2hhcGUsc3RyaWRlLG9mZnNldCl7cmV0dXJuIG5ldyAiK2NsYXNzTmFtZSsiKGRhdGEsIisKICAgICAgaW5kaWNlcy5tYXAoZnVuY3Rpb24oaSkgewogICAgICAgIHJldHVybiAic2hhcGVbIitpKyJdIgogICAgICB9KS5qb2luKCIsIikrIiwiKwogICAgICBpbmRpY2VzLm1hcChmdW5jdGlvbihpKSB7CiAgICAgICAgcmV0dXJuICJzdHJpZGVbIitpKyJdIgogICAgICB9KS5qb2luKCIsIikrIixvZmZzZXQpfSIpOwoKICAgIC8vQ29tcGlsZSBwcm9jZWR1cmUKICAgIHZhciBwcm9jZWR1cmUgPSBuZXcgRnVuY3Rpb24oIkNUT1JfTElTVCIsICJPUkRFUiIsIGNvZGUuam9pbigiXG4iKSk7CiAgICByZXR1cm4gcHJvY2VkdXJlKENBQ0hFRF9DT05TVFJVQ1RPUlNbZHR5cGVdLCBvcmRlcikKICB9CgogIGZ1bmN0aW9uIGFycmF5RFR5cGUoZGF0YSkgewogICAgaWYoaXNCdWZmZXJfMShkYXRhKSkgewogICAgICByZXR1cm4gImJ1ZmZlciIKICAgIH0KICAgIGlmKGhhc1R5cGVkQXJyYXlzKSB7CiAgICAgIHN3aXRjaChPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoZGF0YSkpIHsKICAgICAgICBjYXNlICJbb2JqZWN0IEZsb2F0NjRBcnJheV0iOgogICAgICAgICAgcmV0dXJuICJmbG9hdDY0IgogICAgICAgIGNhc2UgIltvYmplY3QgRmxvYXQzMkFycmF5XSI6CiAgICAgICAgICByZXR1cm4gImZsb2F0MzIiCiAgICAgICAgY2FzZSAiW29iamVjdCBJbnQ4QXJyYXldIjoKICAgICAgICAgIHJldHVybiAiaW50OCIKICAgICAgICBjYXNlICJbb2JqZWN0IEludDE2QXJyYXldIjoKICAgICAgICAgIHJldHVybiAiaW50MTYiCiAgICAgICAgY2FzZSAiW29iamVjdCBJbnQzMkFycmF5XSI6CiAgICAgICAgICByZXR1cm4gImludDMyIgogICAgICAgIGNhc2UgIltvYmplY3QgVWludDhBcnJheV0iOgogICAgICAgICAgcmV0dXJuICJ1aW50OCIKICAgICAgICBjYXNlICJbb2JqZWN0IFVpbnQxNkFycmF5XSI6CiAgICAgICAgICByZXR1cm4gInVpbnQxNiIKICAgICAgICBjYXNlICJbb2JqZWN0IFVpbnQzMkFycmF5XSI6CiAgICAgICAgICByZXR1cm4gInVpbnQzMiIKICAgICAgICBjYXNlICJbb2JqZWN0IFVpbnQ4Q2xhbXBlZEFycmF5XSI6CiAgICAgICAgICByZXR1cm4gInVpbnQ4X2NsYW1wZWQiCiAgICAgICAgY2FzZSAiW29iamVjdCBCaWdJbnQ2NEFycmF5XSI6CiAgICAgICAgICByZXR1cm4gImJpZ2ludDY0IgogICAgICAgIGNhc2UgIltvYmplY3QgQmlnVWludDY0QXJyYXldIjoKICAgICAgICAgIHJldHVybiAiYmlndWludDY0IgogICAgICB9CiAgICB9CiAgICBpZihBcnJheS5pc0FycmF5KGRhdGEpKSB7CiAgICAgIHJldHVybiAiYXJyYXkiCiAgICB9CiAgICByZXR1cm4gImdlbmVyaWMiCiAgfQoKICB2YXIgQ0FDSEVEX0NPTlNUUlVDVE9SUyA9IHsKICAgICJmbG9hdDMyIjpbXSwKICAgICJmbG9hdDY0IjpbXSwKICAgICJpbnQ4IjpbXSwKICAgICJpbnQxNiI6W10sCiAgICAiaW50MzIiOltdLAogICAgInVpbnQ4IjpbXSwKICAgICJ1aW50MTYiOltdLAogICAgInVpbnQzMiI6W10sCiAgICAiYXJyYXkiOltdLAogICAgInVpbnQ4X2NsYW1wZWQiOltdLAogICAgImJpZ2ludDY0IjogW10sCiAgICAiYmlndWludDY0IjogW10sCiAgICAiYnVmZmVyIjpbXSwKICAgICJnZW5lcmljIjpbXQogIH0KCiAgOwogIGZ1bmN0aW9uIHdyYXBwZWROREFycmF5Q3RvcihkYXRhLCBzaGFwZSwgc3RyaWRlLCBvZmZzZXQpIHsKICAgIGlmKGRhdGEgPT09IHVuZGVmaW5lZCkgewogICAgICB2YXIgY3RvciA9IENBQ0hFRF9DT05TVFJVQ1RPUlMuYXJyYXlbMF07CiAgICAgIHJldHVybiBjdG9yKFtdKQogICAgfSBlbHNlIGlmKHR5cGVvZiBkYXRhID09PSAibnVtYmVyIikgewogICAgICBkYXRhID0gW2RhdGFdOwogICAgfQogICAgaWYoc2hhcGUgPT09IHVuZGVmaW5lZCkgewogICAgICBzaGFwZSA9IFsgZGF0YS5sZW5ndGggXTsKICAgIH0KICAgIHZhciBkID0gc2hhcGUubGVuZ3RoOwogICAgaWYoc3RyaWRlID09PSB1bmRlZmluZWQpIHsKICAgICAgc3RyaWRlID0gbmV3IEFycmF5KGQpOwogICAgICBmb3IodmFyIGk9ZC0xLCBzej0xOyBpPj0wOyAtLWkpIHsKICAgICAgICBzdHJpZGVbaV0gPSBzejsKICAgICAgICBzeiAqPSBzaGFwZVtpXTsKICAgICAgfQogICAgfQogICAgaWYob2Zmc2V0ID09PSB1bmRlZmluZWQpIHsKICAgICAgb2Zmc2V0ID0gMDsKICAgICAgZm9yKHZhciBpPTA7IGk8ZDsgKytpKSB7CiAgICAgICAgaWYoc3RyaWRlW2ldIDwgMCkgewogICAgICAgICAgb2Zmc2V0IC09IChzaGFwZVtpXS0xKSpzdHJpZGVbaV07CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICB2YXIgZHR5cGUgPSBhcnJheURUeXBlKGRhdGEpOwogICAgdmFyIGN0b3JfbGlzdCA9IENBQ0hFRF9DT05TVFJVQ1RPUlNbZHR5cGVdOwogICAgd2hpbGUoY3Rvcl9saXN0Lmxlbmd0aCA8PSBkKzEpIHsKICAgICAgY3Rvcl9saXN0LnB1c2goY29tcGlsZUNvbnN0cnVjdG9yKGR0eXBlLCBjdG9yX2xpc3QubGVuZ3RoLTEpKTsKICAgIH0KICAgIHZhciBjdG9yID0gY3Rvcl9saXN0W2QrMV07CiAgICByZXR1cm4gY3RvcihkYXRhLCBzaGFwZSwgc3RyaWRlLCBvZmZzZXQpCiAgfQoKICB2YXIgbmRhcnJheSA9IHdyYXBwZWROREFycmF5Q3RvcjsKCiAgY2xhc3MgTWFydGluaSB7CiAgICBjb25zdHJ1Y3RvcihncmlkU2l6ZSA9IDI1NykgewogICAgICB0aGlzLmdyaWRTaXplID0gZ3JpZFNpemU7CiAgICAgIGNvbnN0IHRpbGVTaXplID0gZ3JpZFNpemUgLSAxOwogICAgICBpZiAodGlsZVNpemUgJiB0aWxlU2l6ZSAtIDEpIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQgZ3JpZCBzaXplIHRvIGJlIDJebisxLCBnb3QgJHtncmlkU2l6ZX0uYCk7CiAgICAgIHRoaXMubnVtVHJpYW5nbGVzID0gdGlsZVNpemUgKiB0aWxlU2l6ZSAqIDIgLSAyOwogICAgICB0aGlzLm51bVBhcmVudFRyaWFuZ2xlcyA9IHRoaXMubnVtVHJpYW5nbGVzIC0gdGlsZVNpemUgKiB0aWxlU2l6ZTsKICAgICAgdGhpcy5pbmRpY2VzID0gbmV3IFVpbnQzMkFycmF5KHRoaXMuZ3JpZFNpemUgKiB0aGlzLmdyaWRTaXplKTsgLy8gY29vcmRpbmF0ZXMgZm9yIGFsbCBwb3NzaWJsZSB0cmlhbmdsZXMgaW4gYW4gUlRJTiB0aWxlCgogICAgICB0aGlzLmNvb3JkcyA9IG5ldyBVaW50MTZBcnJheSh0aGlzLm51bVRyaWFuZ2xlcyAqIDQpOyAvLyBnZXQgdHJpYW5nbGUgY29vcmRpbmF0ZXMgZnJvbSBpdHMgaW5kZXggaW4gYW4gaW1wbGljaXQgYmluYXJ5IHRyZWUKCiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5udW1UcmlhbmdsZXM7IGkrKykgewogICAgICAgIGxldCBpZCA9IGkgKyAyOwogICAgICAgIGxldCBheCA9IDAsCiAgICAgICAgICAgIGF5ID0gMCwKICAgICAgICAgICAgYnggPSAwLAogICAgICAgICAgICBieSA9IDAsCiAgICAgICAgICAgIGN4ID0gMCwKICAgICAgICAgICAgY3kgPSAwOwoKICAgICAgICBpZiAoaWQgJiAxKSB7CiAgICAgICAgICBieCA9IGJ5ID0gY3ggPSB0aWxlU2l6ZTsgLy8gYm90dG9tLWxlZnQgdHJpYW5nbGUKICAgICAgICB9IGVsc2UgewogICAgICAgICAgYXggPSBheSA9IGN5ID0gdGlsZVNpemU7IC8vIHRvcC1yaWdodCB0cmlhbmdsZQogICAgICAgIH0KCiAgICAgICAgd2hpbGUgKChpZCA+Pj0gMSkgPiAxKSB7CiAgICAgICAgICBjb25zdCBteCA9IGF4ICsgYnggPj4gMTsKICAgICAgICAgIGNvbnN0IG15ID0gYXkgKyBieSA+PiAxOwoKICAgICAgICAgIGlmIChpZCAmIDEpIHsKICAgICAgICAgICAgLy8gbGVmdCBoYWxmCiAgICAgICAgICAgIGJ4ID0gYXg7CiAgICAgICAgICAgIGJ5ID0gYXk7CiAgICAgICAgICAgIGF4ID0gY3g7CiAgICAgICAgICAgIGF5ID0gY3k7CiAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAvLyByaWdodCBoYWxmCiAgICAgICAgICAgIGF4ID0gYng7CiAgICAgICAgICAgIGF5ID0gYnk7CiAgICAgICAgICAgIGJ4ID0gY3g7CiAgICAgICAgICAgIGJ5ID0gY3k7CiAgICAgICAgICB9CgogICAgICAgICAgY3ggPSBteDsKICAgICAgICAgIGN5ID0gbXk7CiAgICAgICAgfQoKICAgICAgICBjb25zdCBrID0gaSAqIDQ7CiAgICAgICAgdGhpcy5jb29yZHNbayArIDBdID0gYXg7CiAgICAgICAgdGhpcy5jb29yZHNbayArIDFdID0gYXk7CiAgICAgICAgdGhpcy5jb29yZHNbayArIDJdID0gYng7CiAgICAgICAgdGhpcy5jb29yZHNbayArIDNdID0gYnk7CiAgICAgIH0KICAgIH0KCiAgICBjcmVhdGVUaWxlKHRlcnJhaW4pIHsKICAgICAgcmV0dXJuIG5ldyBUaWxlKHRlcnJhaW4sIHRoaXMpOwogICAgfQoKICB9CgogIGNsYXNzIFRpbGUgewogICAgY29uc3RydWN0b3IodGVycmFpbiwgbWFydGluaSkgewogICAgICBjb25zdCBzaXplID0gbWFydGluaS5ncmlkU2l6ZTsKICAgICAgaWYgKHRlcnJhaW4ubGVuZ3RoICE9PSBzaXplICogc2l6ZSkgdGhyb3cgbmV3IEVycm9yKGBFeHBlY3RlZCB0ZXJyYWluIGRhdGEgb2YgbGVuZ3RoICR7c2l6ZSAqIHNpemV9ICgke3NpemV9IHggJHtzaXplfSksIGdvdCAke3RlcnJhaW4ubGVuZ3RofS5gKTsKICAgICAgdGhpcy50ZXJyYWluID0gdGVycmFpbjsKICAgICAgdGhpcy5tYXJ0aW5pID0gbWFydGluaTsKICAgICAgdGhpcy5lcnJvcnMgPSBuZXcgRmxvYXQzMkFycmF5KHRlcnJhaW4ubGVuZ3RoKTsKICAgICAgdGhpcy51cGRhdGUoKTsKICAgIH0KCiAgICB1cGRhdGUoKSB7CiAgICAgIGNvbnN0IHsKICAgICAgICBudW1UcmlhbmdsZXMsCiAgICAgICAgbnVtUGFyZW50VHJpYW5nbGVzLAogICAgICAgIGNvb3JkcywKICAgICAgICBncmlkU2l6ZTogc2l6ZQogICAgICB9ID0gdGhpcy5tYXJ0aW5pOwogICAgICBjb25zdCB7CiAgICAgICAgdGVycmFpbiwKICAgICAgICBlcnJvcnMKICAgICAgfSA9IHRoaXM7IC8vIGl0ZXJhdGUgb3ZlciBhbGwgcG9zc2libGUgdHJpYW5nbGVzLCBzdGFydGluZyBmcm9tIHRoZSBzbWFsbGVzdCBsZXZlbAoKICAgICAgZm9yIChsZXQgaSA9IG51bVRyaWFuZ2xlcyAtIDE7IGkgPj0gMDsgaS0tKSB7CiAgICAgICAgY29uc3QgayA9IGkgKiA0OwogICAgICAgIGNvbnN0IGF4ID0gY29vcmRzW2sgKyAwXTsKICAgICAgICBjb25zdCBheSA9IGNvb3Jkc1trICsgMV07CiAgICAgICAgY29uc3QgYnggPSBjb29yZHNbayArIDJdOwogICAgICAgIGNvbnN0IGJ5ID0gY29vcmRzW2sgKyAzXTsKICAgICAgICBjb25zdCBteCA9IGF4ICsgYnggPj4gMTsKICAgICAgICBjb25zdCBteSA9IGF5ICsgYnkgPj4gMTsKICAgICAgICBjb25zdCBjeCA9IG14ICsgbXkgLSBheTsKICAgICAgICBjb25zdCBjeSA9IG15ICsgYXggLSBteDsgLy8gY2FsY3VsYXRlIGVycm9yIGluIHRoZSBtaWRkbGUgb2YgdGhlIGxvbmcgZWRnZSBvZiB0aGUgdHJpYW5nbGUKCiAgICAgICAgY29uc3QgaW50ZXJwb2xhdGVkSGVpZ2h0ID0gKHRlcnJhaW5bYXkgKiBzaXplICsgYXhdICsgdGVycmFpbltieSAqIHNpemUgKyBieF0pIC8gMjsKICAgICAgICBjb25zdCBtaWRkbGVJbmRleCA9IG15ICogc2l6ZSArIG14OwogICAgICAgIGNvbnN0IG1pZGRsZUVycm9yID0gTWF0aC5hYnMoaW50ZXJwb2xhdGVkSGVpZ2h0IC0gdGVycmFpblttaWRkbGVJbmRleF0pOwogICAgICAgIGVycm9yc1ttaWRkbGVJbmRleF0gPSBNYXRoLm1heChlcnJvcnNbbWlkZGxlSW5kZXhdLCBtaWRkbGVFcnJvcik7CgogICAgICAgIGlmIChpIDwgbnVtUGFyZW50VHJpYW5nbGVzKSB7CiAgICAgICAgICAvLyBiaWdnZXIgdHJpYW5nbGVzOyBhY2N1bXVsYXRlIGVycm9yIHdpdGggY2hpbGRyZW4KICAgICAgICAgIGNvbnN0IGxlZnRDaGlsZEluZGV4ID0gKGF5ICsgY3kgPj4gMSkgKiBzaXplICsgKGF4ICsgY3ggPj4gMSk7CiAgICAgICAgICBjb25zdCByaWdodENoaWxkSW5kZXggPSAoYnkgKyBjeSA+PiAxKSAqIHNpemUgKyAoYnggKyBjeCA+PiAxKTsKICAgICAgICAgIGVycm9yc1ttaWRkbGVJbmRleF0gPSBNYXRoLm1heChlcnJvcnNbbWlkZGxlSW5kZXhdLCBlcnJvcnNbbGVmdENoaWxkSW5kZXhdLCBlcnJvcnNbcmlnaHRDaGlsZEluZGV4XSk7CiAgICAgICAgfQogICAgICB9CiAgICB9CgogICAgZ2V0TWVzaChtYXhFcnJvciA9IDAsIG1heExlbmd0aCA9IG51bGwpIHsKICAgICAgY29uc3QgewogICAgICAgIGdyaWRTaXplOiBzaXplLAogICAgICAgIGluZGljZXMKICAgICAgfSA9IHRoaXMubWFydGluaTsKICAgICAgY29uc3QgewogICAgICAgIGVycm9ycwogICAgICB9ID0gdGhpczsKICAgICAgbGV0IG51bVZlcnRpY2VzID0gMDsKICAgICAgbGV0IG51bVRyaWFuZ2xlcyA9IDA7CiAgICAgIGNvbnN0IG1heCA9IHNpemUgLSAxOyAvLyBUaGUgbWF4TGVuZ3RoIHBhcmFtZXRlciB3aWxsIGNhdXNlIHRyaWFuZ2xlcyB0byBiZSBnZW5lcmF0ZWQgdW50aWwgdGhlIGxlZ3MgYXJlIGJlbG93IHRoaXMgbGVuZ3RoCiAgICAgIC8vIEl0IGlzIG1lYW50IHRvIHN1cHBvcnQgY2FzZXMgd2hlcmUgYSBjZXJ0YWluIG1lc2ggZGVuc2l0eSBpcyByZXF1aXJlZCB0byBkbyBzcGhlcmljYWwgbWF0aCBvbiBkaWdpdGFsIGdsb2JlcwoKICAgICAgY29uc3QgbWF4U2NhbGUgPSBtYXhMZW5ndGggfHwgc2l6ZTsgLy8gdXNlIGFuIGluZGV4IGdyaWQgdG8ga2VlcCB0cmFjayBvZiB2ZXJ0aWNlcyB0aGF0IHdlcmUgYWxyZWFkeSB1c2VkIHRvIGF2b2lkIGR1cGxpY2F0aW9uCgogICAgICBpbmRpY2VzLmZpbGwoMCk7IC8vIHJldHJpZXZlIG1lc2ggaW4gdHdvIHN0YWdlcyB0aGF0IGJvdGggdHJhdmVyc2UgdGhlIGVycm9yIG1hcDoKICAgICAgLy8gLSBjb3VudEVsZW1lbnRzOiBmaW5kIHVzZWQgdmVydGljZXMgKGFuZCBhc3NpZ24gZWFjaCBhbiBpbmRleCksIGFuZCBjb3VudCB0cmlhbmdsZXMgKGZvciBtaW5pbXVtIGFsbG9jYXRpb24pCiAgICAgIC8vIC0gcHJvY2Vzc1RyaWFuZ2xlOiBmaWxsIHRoZSBhbGxvY2F0ZWQgdmVydGljZXMgJiB0cmlhbmdsZXMgdHlwZWQgYXJyYXlzCgogICAgICBmdW5jdGlvbiBjb3VudEVsZW1lbnRzKGF4LCBheSwgYngsIGJ5LCBjeCwgY3kpIHsKICAgICAgICBjb25zdCBteCA9IGF4ICsgYnggPj4gMTsKICAgICAgICBjb25zdCBteSA9IGF5ICsgYnkgPj4gMTsKICAgICAgICBjb25zdCBsZWdMZW5ndGggPSBNYXRoLmFicyhheCAtIGN4KSArIE1hdGguYWJzKGF5IC0gY3kpOwoKICAgICAgICBpZiAobGVnTGVuZ3RoID4gMSAmJiBlcnJvcnNbbXkgKiBzaXplICsgbXhdID4gbWF4RXJyb3IgfHwgbGVnTGVuZ3RoID4gbWF4U2NhbGUpIHsKICAgICAgICAgIGNvdW50RWxlbWVudHMoY3gsIGN5LCBheCwgYXksIG14LCBteSk7CiAgICAgICAgICBjb3VudEVsZW1lbnRzKGJ4LCBieSwgY3gsIGN5LCBteCwgbXkpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBpbmRpY2VzW2F5ICogc2l6ZSArIGF4XSA9IGluZGljZXNbYXkgKiBzaXplICsgYXhdIHx8ICsrbnVtVmVydGljZXM7CiAgICAgICAgICBpbmRpY2VzW2J5ICogc2l6ZSArIGJ4XSA9IGluZGljZXNbYnkgKiBzaXplICsgYnhdIHx8ICsrbnVtVmVydGljZXM7CiAgICAgICAgICBpbmRpY2VzW2N5ICogc2l6ZSArIGN4XSA9IGluZGljZXNbY3kgKiBzaXplICsgY3hdIHx8ICsrbnVtVmVydGljZXM7CiAgICAgICAgICBudW1UcmlhbmdsZXMrKzsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIGNvdW50RWxlbWVudHMoMCwgMCwgbWF4LCBtYXgsIG1heCwgMCk7CiAgICAgIGNvdW50RWxlbWVudHMobWF4LCBtYXgsIDAsIDAsIDAsIG1heCk7CiAgICAgIGNvbnN0IHZlcnRpY2VzID0gbmV3IFVpbnQxNkFycmF5KG51bVZlcnRpY2VzICogMik7CiAgICAgIGNvbnN0IHRyaWFuZ2xlcyA9IG5ldyBVaW50MzJBcnJheShudW1UcmlhbmdsZXMgKiAzKTsKICAgICAgbGV0IHRyaUluZGV4ID0gMDsKCiAgICAgIGZ1bmN0aW9uIHByb2Nlc3NUcmlhbmdsZShheCwgYXksIGJ4LCBieSwgY3gsIGN5KSB7CiAgICAgICAgY29uc3QgbXggPSBheCArIGJ4ID4+IDE7CiAgICAgICAgY29uc3QgbXkgPSBheSArIGJ5ID4+IDE7CiAgICAgICAgY29uc3QgbGVnTGVuZ3RoID0gTWF0aC5hYnMoYXggLSBjeCkgKyBNYXRoLmFicyhheSAtIGN5KTsKCiAgICAgICAgaWYgKGxlZ0xlbmd0aCA+IDEgJiYgZXJyb3JzW215ICogc2l6ZSArIG14XSA+IG1heEVycm9yIHx8IGxlZ0xlbmd0aCA+IG1heFNjYWxlKSB7CiAgICAgICAgICAvLyB0cmlhbmdsZSBkb2Vzbid0IGFwcHJveGltYXRlIHRoZSBzdXJmYWNlIHdlbGwgZW5vdWdoOyBkcmlsbCBkb3duIGZ1cnRoZXIKICAgICAgICAgIHByb2Nlc3NUcmlhbmdsZShjeCwgY3ksIGF4LCBheSwgbXgsIG15KTsKICAgICAgICAgIHByb2Nlc3NUcmlhbmdsZShieCwgYnksIGN4LCBjeSwgbXgsIG15KTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgLy8gYWRkIGEgdHJpYW5nbGUKICAgICAgICAgIGNvbnN0IGEgPSBpbmRpY2VzW2F5ICogc2l6ZSArIGF4XSAtIDE7CiAgICAgICAgICBjb25zdCBiID0gaW5kaWNlc1tieSAqIHNpemUgKyBieF0gLSAxOwogICAgICAgICAgY29uc3QgYyA9IGluZGljZXNbY3kgKiBzaXplICsgY3hdIC0gMTsKICAgICAgICAgIHZlcnRpY2VzWzIgKiBhXSA9IGF4OwogICAgICAgICAgdmVydGljZXNbMiAqIGEgKyAxXSA9IGF5OwogICAgICAgICAgdmVydGljZXNbMiAqIGJdID0gYng7CiAgICAgICAgICB2ZXJ0aWNlc1syICogYiArIDFdID0gYnk7CiAgICAgICAgICB2ZXJ0aWNlc1syICogY10gPSBjeDsKICAgICAgICAgIHZlcnRpY2VzWzIgKiBjICsgMV0gPSBjeTsKICAgICAgICAgIHRyaWFuZ2xlc1t0cmlJbmRleCsrXSA9IGE7CiAgICAgICAgICB0cmlhbmdsZXNbdHJpSW5kZXgrK10gPSBiOwogICAgICAgICAgdHJpYW5nbGVzW3RyaUluZGV4KytdID0gYzsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIHByb2Nlc3NUcmlhbmdsZSgwLCAwLCBtYXgsIG1heCwgbWF4LCAwKTsKICAgICAgcHJvY2Vzc1RyaWFuZ2xlKG1heCwgbWF4LCAwLCAwLCAwLCBtYXgpOwogICAgICByZXR1cm4gewogICAgICAgIHZlcnRpY2VzLAogICAgICAgIHRyaWFuZ2xlcwogICAgICB9OwogICAgfQoKICB9CgogIGZ1bmN0aW9uIGNyZWF0ZUNvbW1vbmpzTW9kdWxlKGZuKSB7CiAgICB2YXIgbW9kdWxlID0geyBleHBvcnRzOiB7fSB9OwogIAlyZXR1cm4gZm4obW9kdWxlLCBtb2R1bGUuZXhwb3J0cyksIG1vZHVsZS5leHBvcnRzOwogIH0KCiAgLyoqCiAgICogQ29weXJpZ2h0IChjKSAyMDE0LXByZXNlbnQsIEZhY2Vib29rLCBJbmMuCiAgICoKICAgKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZSBmb3VuZCBpbiB0aGUKICAgKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuCiAgICovCgogIGNyZWF0ZUNvbW1vbmpzTW9kdWxlKGZ1bmN0aW9uIChtb2R1bGUpIHsKICB2YXIgcnVudGltZSA9IChmdW5jdGlvbiAoZXhwb3J0cykgewoKICAgIHZhciBPcCA9IE9iamVjdC5wcm90b3R5cGU7CiAgICB2YXIgaGFzT3duID0gT3AuaGFzT3duUHJvcGVydHk7CiAgICB2YXIgdW5kZWZpbmVkJDE7IC8vIE1vcmUgY29tcHJlc3NpYmxlIHRoYW4gdm9pZCAwLgogICAgdmFyICRTeW1ib2wgPSB0eXBlb2YgU3ltYm9sID09PSAiZnVuY3Rpb24iID8gU3ltYm9sIDoge307CiAgICB2YXIgaXRlcmF0b3JTeW1ib2wgPSAkU3ltYm9sLml0ZXJhdG9yIHx8ICJAQGl0ZXJhdG9yIjsKICAgIHZhciBhc3luY0l0ZXJhdG9yU3ltYm9sID0gJFN5bWJvbC5hc3luY0l0ZXJhdG9yIHx8ICJAQGFzeW5jSXRlcmF0b3IiOwogICAgdmFyIHRvU3RyaW5nVGFnU3ltYm9sID0gJFN5bWJvbC50b1N0cmluZ1RhZyB8fCAiQEB0b1N0cmluZ1RhZyI7CgogICAgZnVuY3Rpb24gZGVmaW5lKG9iaiwga2V5LCB2YWx1ZSkgewogICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkob2JqLCBrZXksIHsKICAgICAgICB2YWx1ZTogdmFsdWUsCiAgICAgICAgZW51bWVyYWJsZTogdHJ1ZSwKICAgICAgICBjb25maWd1cmFibGU6IHRydWUsCiAgICAgICAgd3JpdGFibGU6IHRydWUKICAgICAgfSk7CiAgICAgIHJldHVybiBvYmpba2V5XTsKICAgIH0KICAgIHRyeSB7CiAgICAgIC8vIElFIDggaGFzIGEgYnJva2VuIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSB0aGF0IG9ubHkgd29ya3Mgb24gRE9NIG9iamVjdHMuCiAgICAgIGRlZmluZSh7fSwgIiIpOwogICAgfSBjYXRjaCAoZXJyKSB7CiAgICAgIGRlZmluZSA9IGZ1bmN0aW9uKG9iaiwga2V5LCB2YWx1ZSkgewogICAgICAgIHJldHVybiBvYmpba2V5XSA9IHZhbHVlOwogICAgICB9OwogICAgfQoKICAgIGZ1bmN0aW9uIHdyYXAoaW5uZXJGbiwgb3V0ZXJGbiwgc2VsZiwgdHJ5TG9jc0xpc3QpIHsKICAgICAgLy8gSWYgb3V0ZXJGbiBwcm92aWRlZCBhbmQgb3V0ZXJGbi5wcm90b3R5cGUgaXMgYSBHZW5lcmF0b3IsIHRoZW4gb3V0ZXJGbi5wcm90b3R5cGUgaW5zdGFuY2VvZiBHZW5lcmF0b3IuCiAgICAgIHZhciBwcm90b0dlbmVyYXRvciA9IG91dGVyRm4gJiYgb3V0ZXJGbi5wcm90b3R5cGUgaW5zdGFuY2VvZiBHZW5lcmF0b3IgPyBvdXRlckZuIDogR2VuZXJhdG9yOwogICAgICB2YXIgZ2VuZXJhdG9yID0gT2JqZWN0LmNyZWF0ZShwcm90b0dlbmVyYXRvci5wcm90b3R5cGUpOwogICAgICB2YXIgY29udGV4dCA9IG5ldyBDb250ZXh0KHRyeUxvY3NMaXN0IHx8IFtdKTsKCiAgICAgIC8vIFRoZSAuX2ludm9rZSBtZXRob2QgdW5pZmllcyB0aGUgaW1wbGVtZW50YXRpb25zIG9mIHRoZSAubmV4dCwKICAgICAgLy8gLnRocm93LCBhbmQgLnJldHVybiBtZXRob2RzLgogICAgICBnZW5lcmF0b3IuX2ludm9rZSA9IG1ha2VJbnZva2VNZXRob2QoaW5uZXJGbiwgc2VsZiwgY29udGV4dCk7CgogICAgICByZXR1cm4gZ2VuZXJhdG9yOwogICAgfQogICAgZXhwb3J0cy53cmFwID0gd3JhcDsKCiAgICAvLyBUcnkvY2F0Y2ggaGVscGVyIHRvIG1pbmltaXplIGRlb3B0aW1pemF0aW9ucy4gUmV0dXJucyBhIGNvbXBsZXRpb24KICAgIC8vIHJlY29yZCBsaWtlIGNvbnRleHQudHJ5RW50cmllc1tpXS5jb21wbGV0aW9uLiBUaGlzIGludGVyZmFjZSBjb3VsZAogICAgLy8gaGF2ZSBiZWVuIChhbmQgd2FzIHByZXZpb3VzbHkpIGRlc2lnbmVkIHRvIHRha2UgYSBjbG9zdXJlIHRvIGJlCiAgICAvLyBpbnZva2VkIHdpdGhvdXQgYXJndW1lbnRzLCBidXQgaW4gYWxsIHRoZSBjYXNlcyB3ZSBjYXJlIGFib3V0IHdlCiAgICAvLyBhbHJlYWR5IGhhdmUgYW4gZXhpc3RpbmcgbWV0aG9kIHdlIHdhbnQgdG8gY2FsbCwgc28gdGhlcmUncyBubyBuZWVkCiAgICAvLyB0byBjcmVhdGUgYSBuZXcgZnVuY3Rpb24gb2JqZWN0LiBXZSBjYW4gZXZlbiBnZXQgYXdheSB3aXRoIGFzc3VtaW5nCiAgICAvLyB0aGUgbWV0aG9kIHRha2VzIGV4YWN0bHkgb25lIGFyZ3VtZW50LCBzaW5jZSB0aGF0IGhhcHBlbnMgdG8gYmUgdHJ1ZQogICAgLy8gaW4gZXZlcnkgY2FzZSwgc28gd2UgZG9uJ3QgaGF2ZSB0byB0b3VjaCB0aGUgYXJndW1lbnRzIG9iamVjdC4gVGhlCiAgICAvLyBvbmx5IGFkZGl0aW9uYWwgYWxsb2NhdGlvbiByZXF1aXJlZCBpcyB0aGUgY29tcGxldGlvbiByZWNvcmQsIHdoaWNoCiAgICAvLyBoYXMgYSBzdGFibGUgc2hhcGUgYW5kIHNvIGhvcGVmdWxseSBzaG91bGQgYmUgY2hlYXAgdG8gYWxsb2NhdGUuCiAgICBmdW5jdGlvbiB0cnlDYXRjaChmbiwgb2JqLCBhcmcpIHsKICAgICAgdHJ5IHsKICAgICAgICByZXR1cm4geyB0eXBlOiAibm9ybWFsIiwgYXJnOiBmbi5jYWxsKG9iaiwgYXJnKSB9OwogICAgICB9IGNhdGNoIChlcnIpIHsKICAgICAgICByZXR1cm4geyB0eXBlOiAidGhyb3ciLCBhcmc6IGVyciB9OwogICAgICB9CiAgICB9CgogICAgdmFyIEdlblN0YXRlU3VzcGVuZGVkU3RhcnQgPSAic3VzcGVuZGVkU3RhcnQiOwogICAgdmFyIEdlblN0YXRlU3VzcGVuZGVkWWllbGQgPSAic3VzcGVuZGVkWWllbGQiOwogICAgdmFyIEdlblN0YXRlRXhlY3V0aW5nID0gImV4ZWN1dGluZyI7CiAgICB2YXIgR2VuU3RhdGVDb21wbGV0ZWQgPSAiY29tcGxldGVkIjsKCiAgICAvLyBSZXR1cm5pbmcgdGhpcyBvYmplY3QgZnJvbSB0aGUgaW5uZXJGbiBoYXMgdGhlIHNhbWUgZWZmZWN0IGFzCiAgICAvLyBicmVha2luZyBvdXQgb2YgdGhlIGRpc3BhdGNoIHN3aXRjaCBzdGF0ZW1lbnQuCiAgICB2YXIgQ29udGludWVTZW50aW5lbCA9IHt9OwoKICAgIC8vIER1bW15IGNvbnN0cnVjdG9yIGZ1bmN0aW9ucyB0aGF0IHdlIHVzZSBhcyB0aGUgLmNvbnN0cnVjdG9yIGFuZAogICAgLy8gLmNvbnN0cnVjdG9yLnByb3RvdHlwZSBwcm9wZXJ0aWVzIGZvciBmdW5jdGlvbnMgdGhhdCByZXR1cm4gR2VuZXJhdG9yCiAgICAvLyBvYmplY3RzLiBGb3IgZnVsbCBzcGVjIGNvbXBsaWFuY2UsIHlvdSBtYXkgd2lzaCB0byBjb25maWd1cmUgeW91cgogICAgLy8gbWluaWZpZXIgbm90IHRvIG1hbmdsZSB0aGUgbmFtZXMgb2YgdGhlc2UgdHdvIGZ1bmN0aW9ucy4KICAgIGZ1bmN0aW9uIEdlbmVyYXRvcigpIHt9CiAgICBmdW5jdGlvbiBHZW5lcmF0b3JGdW5jdGlvbigpIHt9CiAgICBmdW5jdGlvbiBHZW5lcmF0b3JGdW5jdGlvblByb3RvdHlwZSgpIHt9CgogICAgLy8gVGhpcyBpcyBhIHBvbHlmaWxsIGZvciAlSXRlcmF0b3JQcm90b3R5cGUlIGZvciBlbnZpcm9ubWVudHMgdGhhdAogICAgLy8gZG9uJ3QgbmF0aXZlbHkgc3VwcG9ydCBpdC4KICAgIHZhciBJdGVyYXRvclByb3RvdHlwZSA9IHt9OwogICAgSXRlcmF0b3JQcm90b3R5cGVbaXRlcmF0b3JTeW1ib2xdID0gZnVuY3Rpb24gKCkgewogICAgICByZXR1cm4gdGhpczsKICAgIH07CgogICAgdmFyIGdldFByb3RvID0gT2JqZWN0LmdldFByb3RvdHlwZU9mOwogICAgdmFyIE5hdGl2ZUl0ZXJhdG9yUHJvdG90eXBlID0gZ2V0UHJvdG8gJiYgZ2V0UHJvdG8oZ2V0UHJvdG8odmFsdWVzKFtdKSkpOwogICAgaWYgKE5hdGl2ZUl0ZXJhdG9yUHJvdG90eXBlICYmCiAgICAgICAgTmF0aXZlSXRlcmF0b3JQcm90b3R5cGUgIT09IE9wICYmCiAgICAgICAgaGFzT3duLmNhbGwoTmF0aXZlSXRlcmF0b3JQcm90b3R5cGUsIGl0ZXJhdG9yU3ltYm9sKSkgewogICAgICAvLyBUaGlzIGVudmlyb25tZW50IGhhcyBhIG5hdGl2ZSAlSXRlcmF0b3JQcm90b3R5cGUlOyB1c2UgaXQgaW5zdGVhZAogICAgICAvLyBvZiB0aGUgcG9seWZpbGwuCiAgICAgIEl0ZXJhdG9yUHJvdG90eXBlID0gTmF0aXZlSXRlcmF0b3JQcm90b3R5cGU7CiAgICB9CgogICAgdmFyIEdwID0gR2VuZXJhdG9yRnVuY3Rpb25Qcm90b3R5cGUucHJvdG90eXBlID0KICAgICAgR2VuZXJhdG9yLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoSXRlcmF0b3JQcm90b3R5cGUpOwogICAgR2VuZXJhdG9yRnVuY3Rpb24ucHJvdG90eXBlID0gR3AuY29uc3RydWN0b3IgPSBHZW5lcmF0b3JGdW5jdGlvblByb3RvdHlwZTsKICAgIEdlbmVyYXRvckZ1bmN0aW9uUHJvdG90eXBlLmNvbnN0cnVjdG9yID0gR2VuZXJhdG9yRnVuY3Rpb247CiAgICBHZW5lcmF0b3JGdW5jdGlvbi5kaXNwbGF5TmFtZSA9IGRlZmluZSgKICAgICAgR2VuZXJhdG9yRnVuY3Rpb25Qcm90b3R5cGUsCiAgICAgIHRvU3RyaW5nVGFnU3ltYm9sLAogICAgICAiR2VuZXJhdG9yRnVuY3Rpb24iCiAgICApOwoKICAgIC8vIEhlbHBlciBmb3IgZGVmaW5pbmcgdGhlIC5uZXh0LCAudGhyb3csIGFuZCAucmV0dXJuIG1ldGhvZHMgb2YgdGhlCiAgICAvLyBJdGVyYXRvciBpbnRlcmZhY2UgaW4gdGVybXMgb2YgYSBzaW5nbGUgLl9pbnZva2UgbWV0aG9kLgogICAgZnVuY3Rpb24gZGVmaW5lSXRlcmF0b3JNZXRob2RzKHByb3RvdHlwZSkgewogICAgICBbIm5leHQiLCAidGhyb3ciLCAicmV0dXJuIl0uZm9yRWFjaChmdW5jdGlvbihtZXRob2QpIHsKICAgICAgICBkZWZpbmUocHJvdG90eXBlLCBtZXRob2QsIGZ1bmN0aW9uKGFyZykgewogICAgICAgICAgcmV0dXJuIHRoaXMuX2ludm9rZShtZXRob2QsIGFyZyk7CiAgICAgICAgfSk7CiAgICAgIH0pOwogICAgfQoKICAgIGV4cG9ydHMuaXNHZW5lcmF0b3JGdW5jdGlvbiA9IGZ1bmN0aW9uKGdlbkZ1bikgewogICAgICB2YXIgY3RvciA9IHR5cGVvZiBnZW5GdW4gPT09ICJmdW5jdGlvbiIgJiYgZ2VuRnVuLmNvbnN0cnVjdG9yOwogICAgICByZXR1cm4gY3RvcgogICAgICAgID8gY3RvciA9PT0gR2VuZXJhdG9yRnVuY3Rpb24gfHwKICAgICAgICAgIC8vIEZvciB0aGUgbmF0aXZlIEdlbmVyYXRvckZ1bmN0aW9uIGNvbnN0cnVjdG9yLCB0aGUgYmVzdCB3ZSBjYW4KICAgICAgICAgIC8vIGRvIGlzIHRvIGNoZWNrIGl0cyAubmFtZSBwcm9wZXJ0eS4KICAgICAgICAgIChjdG9yLmRpc3BsYXlOYW1lIHx8IGN0b3IubmFtZSkgPT09ICJHZW5lcmF0b3JGdW5jdGlvbiIKICAgICAgICA6IGZhbHNlOwogICAgfTsKCiAgICBleHBvcnRzLm1hcmsgPSBmdW5jdGlvbihnZW5GdW4pIHsKICAgICAgaWYgKE9iamVjdC5zZXRQcm90b3R5cGVPZikgewogICAgICAgIE9iamVjdC5zZXRQcm90b3R5cGVPZihnZW5GdW4sIEdlbmVyYXRvckZ1bmN0aW9uUHJvdG90eXBlKTsKICAgICAgfSBlbHNlIHsKICAgICAgICBnZW5GdW4uX19wcm90b19fID0gR2VuZXJhdG9yRnVuY3Rpb25Qcm90b3R5cGU7CiAgICAgICAgZGVmaW5lKGdlbkZ1biwgdG9TdHJpbmdUYWdTeW1ib2wsICJHZW5lcmF0b3JGdW5jdGlvbiIpOwogICAgICB9CiAgICAgIGdlbkZ1bi5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKEdwKTsKICAgICAgcmV0dXJuIGdlbkZ1bjsKICAgIH07CgogICAgLy8gV2l0aGluIHRoZSBib2R5IG9mIGFueSBhc3luYyBmdW5jdGlvbiwgYGF3YWl0IHhgIGlzIHRyYW5zZm9ybWVkIHRvCiAgICAvLyBgeWllbGQgcmVnZW5lcmF0b3JSdW50aW1lLmF3cmFwKHgpYCwgc28gdGhhdCB0aGUgcnVudGltZSBjYW4gdGVzdAogICAgLy8gYGhhc093bi5jYWxsKHZhbHVlLCAiX19hd2FpdCIpYCB0byBkZXRlcm1pbmUgaWYgdGhlIHlpZWxkZWQgdmFsdWUgaXMKICAgIC8vIG1lYW50IHRvIGJlIGF3YWl0ZWQuCiAgICBleHBvcnRzLmF3cmFwID0gZnVuY3Rpb24oYXJnKSB7CiAgICAgIHJldHVybiB7IF9fYXdhaXQ6IGFyZyB9OwogICAgfTsKCiAgICBmdW5jdGlvbiBBc3luY0l0ZXJhdG9yKGdlbmVyYXRvciwgUHJvbWlzZUltcGwpIHsKICAgICAgZnVuY3Rpb24gaW52b2tlKG1ldGhvZCwgYXJnLCByZXNvbHZlLCByZWplY3QpIHsKICAgICAgICB2YXIgcmVjb3JkID0gdHJ5Q2F0Y2goZ2VuZXJhdG9yW21ldGhvZF0sIGdlbmVyYXRvciwgYXJnKTsKICAgICAgICBpZiAocmVjb3JkLnR5cGUgPT09ICJ0aHJvdyIpIHsKICAgICAgICAgIHJlamVjdChyZWNvcmQuYXJnKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgdmFyIHJlc3VsdCA9IHJlY29yZC5hcmc7CiAgICAgICAgICB2YXIgdmFsdWUgPSByZXN1bHQudmFsdWU7CiAgICAgICAgICBpZiAodmFsdWUgJiYKICAgICAgICAgICAgICB0eXBlb2YgdmFsdWUgPT09ICJvYmplY3QiICYmCiAgICAgICAgICAgICAgaGFzT3duLmNhbGwodmFsdWUsICJfX2F3YWl0IikpIHsKICAgICAgICAgICAgcmV0dXJuIFByb21pc2VJbXBsLnJlc29sdmUodmFsdWUuX19hd2FpdCkudGhlbihmdW5jdGlvbih2YWx1ZSkgewogICAgICAgICAgICAgIGludm9rZSgibmV4dCIsIHZhbHVlLCByZXNvbHZlLCByZWplY3QpOwogICAgICAgICAgICB9LCBmdW5jdGlvbihlcnIpIHsKICAgICAgICAgICAgICBpbnZva2UoInRocm93IiwgZXJyLCByZXNvbHZlLCByZWplY3QpOwogICAgICAgICAgICB9KTsKICAgICAgICAgIH0KCiAgICAgICAgICByZXR1cm4gUHJvbWlzZUltcGwucmVzb2x2ZSh2YWx1ZSkudGhlbihmdW5jdGlvbih1bndyYXBwZWQpIHsKICAgICAgICAgICAgLy8gV2hlbiBhIHlpZWxkZWQgUHJvbWlzZSBpcyByZXNvbHZlZCwgaXRzIGZpbmFsIHZhbHVlIGJlY29tZXMKICAgICAgICAgICAgLy8gdGhlIC52YWx1ZSBvZiB0aGUgUHJvbWlzZTx7dmFsdWUsZG9uZX0+IHJlc3VsdCBmb3IgdGhlCiAgICAgICAgICAgIC8vIGN1cnJlbnQgaXRlcmF0aW9uLgogICAgICAgICAgICByZXN1bHQudmFsdWUgPSB1bndyYXBwZWQ7CiAgICAgICAgICAgIHJlc29sdmUocmVzdWx0KTsKICAgICAgICAgIH0sIGZ1bmN0aW9uKGVycm9yKSB7CiAgICAgICAgICAgIC8vIElmIGEgcmVqZWN0ZWQgUHJvbWlzZSB3YXMgeWllbGRlZCwgdGhyb3cgdGhlIHJlamVjdGlvbiBiYWNrCiAgICAgICAgICAgIC8vIGludG8gdGhlIGFzeW5jIGdlbmVyYXRvciBmdW5jdGlvbiBzbyBpdCBjYW4gYmUgaGFuZGxlZCB0aGVyZS4KICAgICAgICAgICAgcmV0dXJuIGludm9rZSgidGhyb3ciLCBlcnJvciwgcmVzb2x2ZSwgcmVqZWN0KTsKICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgfQoKICAgICAgdmFyIHByZXZpb3VzUHJvbWlzZTsKCiAgICAgIGZ1bmN0aW9uIGVucXVldWUobWV0aG9kLCBhcmcpIHsKICAgICAgICBmdW5jdGlvbiBjYWxsSW52b2tlV2l0aE1ldGhvZEFuZEFyZygpIHsKICAgICAgICAgIHJldHVybiBuZXcgUHJvbWlzZUltcGwoZnVuY3Rpb24ocmVzb2x2ZSwgcmVqZWN0KSB7CiAgICAgICAgICAgIGludm9rZShtZXRob2QsIGFyZywgcmVzb2x2ZSwgcmVqZWN0KTsKICAgICAgICAgIH0pOwogICAgICAgIH0KCiAgICAgICAgcmV0dXJuIHByZXZpb3VzUHJvbWlzZSA9CiAgICAgICAgICAvLyBJZiBlbnF1ZXVlIGhhcyBiZWVuIGNhbGxlZCBiZWZvcmUsIHRoZW4gd2Ugd2FudCB0byB3YWl0IHVudGlsCiAgICAgICAgICAvLyBhbGwgcHJldmlvdXMgUHJvbWlzZXMgaGF2ZSBiZWVuIHJlc29sdmVkIGJlZm9yZSBjYWxsaW5nIGludm9rZSwKICAgICAgICAgIC8vIHNvIHRoYXQgcmVzdWx0cyBhcmUgYWx3YXlzIGRlbGl2ZXJlZCBpbiB0aGUgY29ycmVjdCBvcmRlci4gSWYKICAgICAgICAgIC8vIGVucXVldWUgaGFzIG5vdCBiZWVuIGNhbGxlZCBiZWZvcmUsIHRoZW4gaXQgaXMgaW1wb3J0YW50IHRvCiAgICAgICAgICAvLyBjYWxsIGludm9rZSBpbW1lZGlhdGVseSwgd2l0aG91dCB3YWl0aW5nIG9uIGEgY2FsbGJhY2sgdG8gZmlyZSwKICAgICAgICAgIC8vIHNvIHRoYXQgdGhlIGFzeW5jIGdlbmVyYXRvciBmdW5jdGlvbiBoYXMgdGhlIG9wcG9ydHVuaXR5IHRvIGRvCiAgICAgICAgICAvLyBhbnkgbmVjZXNzYXJ5IHNldHVwIGluIGEgcHJlZGljdGFibGUgd2F5LiBUaGlzIHByZWRpY3RhYmlsaXR5CiAgICAgICAgICAvLyBpcyB3aHkgdGhlIFByb21pc2UgY29uc3RydWN0b3Igc3luY2hyb25vdXNseSBpbnZva2VzIGl0cwogICAgICAgICAgLy8gZXhlY3V0b3IgY2FsbGJhY2ssIGFuZCB3aHkgYXN5bmMgZnVuY3Rpb25zIHN5bmNocm9ub3VzbHkKICAgICAgICAgIC8vIGV4ZWN1dGUgY29kZSBiZWZvcmUgdGhlIGZpcnN0IGF3YWl0LiBTaW5jZSB3ZSBpbXBsZW1lbnQgc2ltcGxlCiAgICAgICAgICAvLyBhc3luYyBmdW5jdGlvbnMgaW4gdGVybXMgb2YgYXN5bmMgZ2VuZXJhdG9ycywgaXQgaXMgZXNwZWNpYWxseQogICAgICAgICAgLy8gaW1wb3J0YW50IHRvIGdldCB0aGlzIHJpZ2h0LCBldmVuIHRob3VnaCBpdCByZXF1aXJlcyBjYXJlLgogICAgICAgICAgcHJldmlvdXNQcm9taXNlID8gcHJldmlvdXNQcm9taXNlLnRoZW4oCiAgICAgICAgICAgIGNhbGxJbnZva2VXaXRoTWV0aG9kQW5kQXJnLAogICAgICAgICAgICAvLyBBdm9pZCBwcm9wYWdhdGluZyBmYWlsdXJlcyB0byBQcm9taXNlcyByZXR1cm5lZCBieSBsYXRlcgogICAgICAgICAgICAvLyBpbnZvY2F0aW9ucyBvZiB0aGUgaXRlcmF0b3IuCiAgICAgICAgICAgIGNhbGxJbnZva2VXaXRoTWV0aG9kQW5kQXJnCiAgICAgICAgICApIDogY2FsbEludm9rZVdpdGhNZXRob2RBbmRBcmcoKTsKICAgICAgfQoKICAgICAgLy8gRGVmaW5lIHRoZSB1bmlmaWVkIGhlbHBlciBtZXRob2QgdGhhdCBpcyB1c2VkIHRvIGltcGxlbWVudCAubmV4dCwKICAgICAgLy8gLnRocm93LCBhbmQgLnJldHVybiAoc2VlIGRlZmluZUl0ZXJhdG9yTWV0aG9kcykuCiAgICAgIHRoaXMuX2ludm9rZSA9IGVucXVldWU7CiAgICB9CgogICAgZGVmaW5lSXRlcmF0b3JNZXRob2RzKEFzeW5jSXRlcmF0b3IucHJvdG90eXBlKTsKICAgIEFzeW5jSXRlcmF0b3IucHJvdG90eXBlW2FzeW5jSXRlcmF0b3JTeW1ib2xdID0gZnVuY3Rpb24gKCkgewogICAgICByZXR1cm4gdGhpczsKICAgIH07CiAgICBleHBvcnRzLkFzeW5jSXRlcmF0b3IgPSBBc3luY0l0ZXJhdG9yOwoKICAgIC8vIE5vdGUgdGhhdCBzaW1wbGUgYXN5bmMgZnVuY3Rpb25zIGFyZSBpbXBsZW1lbnRlZCBvbiB0b3Agb2YKICAgIC8vIEFzeW5jSXRlcmF0b3Igb2JqZWN0czsgdGhleSBqdXN0IHJldHVybiBhIFByb21pc2UgZm9yIHRoZSB2YWx1ZSBvZgogICAgLy8gdGhlIGZpbmFsIHJlc3VsdCBwcm9kdWNlZCBieSB0aGUgaXRlcmF0b3IuCiAgICBleHBvcnRzLmFzeW5jID0gZnVuY3Rpb24oaW5uZXJGbiwgb3V0ZXJGbiwgc2VsZiwgdHJ5TG9jc0xpc3QsIFByb21pc2VJbXBsKSB7CiAgICAgIGlmIChQcm9taXNlSW1wbCA9PT0gdm9pZCAwKSBQcm9taXNlSW1wbCA9IFByb21pc2U7CgogICAgICB2YXIgaXRlciA9IG5ldyBBc3luY0l0ZXJhdG9yKAogICAgICAgIHdyYXAoaW5uZXJGbiwgb3V0ZXJGbiwgc2VsZiwgdHJ5TG9jc0xpc3QpLAogICAgICAgIFByb21pc2VJbXBsCiAgICAgICk7CgogICAgICByZXR1cm4gZXhwb3J0cy5pc0dlbmVyYXRvckZ1bmN0aW9uKG91dGVyRm4pCiAgICAgICAgPyBpdGVyIC8vIElmIG91dGVyRm4gaXMgYSBnZW5lcmF0b3IsIHJldHVybiB0aGUgZnVsbCBpdGVyYXRvci4KICAgICAgICA6IGl0ZXIubmV4dCgpLnRoZW4oZnVuY3Rpb24ocmVzdWx0KSB7CiAgICAgICAgICAgIHJldHVybiByZXN1bHQuZG9uZSA/IHJlc3VsdC52YWx1ZSA6IGl0ZXIubmV4dCgpOwogICAgICAgICAgfSk7CiAgICB9OwoKICAgIGZ1bmN0aW9uIG1ha2VJbnZva2VNZXRob2QoaW5uZXJGbiwgc2VsZiwgY29udGV4dCkgewogICAgICB2YXIgc3RhdGUgPSBHZW5TdGF0ZVN1c3BlbmRlZFN0YXJ0OwoKICAgICAgcmV0dXJuIGZ1bmN0aW9uIGludm9rZShtZXRob2QsIGFyZykgewogICAgICAgIGlmIChzdGF0ZSA9PT0gR2VuU3RhdGVFeGVjdXRpbmcpIHsKICAgICAgICAgIHRocm93IG5ldyBFcnJvcigiR2VuZXJhdG9yIGlzIGFscmVhZHkgcnVubmluZyIpOwogICAgICAgIH0KCiAgICAgICAgaWYgKHN0YXRlID09PSBHZW5TdGF0ZUNvbXBsZXRlZCkgewogICAgICAgICAgaWYgKG1ldGhvZCA9PT0gInRocm93IikgewogICAgICAgICAgICB0aHJvdyBhcmc7CiAgICAgICAgICB9CgogICAgICAgICAgLy8gQmUgZm9yZ2l2aW5nLCBwZXIgMjUuMy4zLjMuMyBvZiB0aGUgc3BlYzoKICAgICAgICAgIC8vIGh0dHBzOi8vcGVvcGxlLm1vemlsbGEub3JnL35qb3JlbmRvcmZmL2VzNi1kcmFmdC5odG1sI3NlYy1nZW5lcmF0b3JyZXN1bWUKICAgICAgICAgIHJldHVybiBkb25lUmVzdWx0KCk7CiAgICAgICAgfQoKICAgICAgICBjb250ZXh0Lm1ldGhvZCA9IG1ldGhvZDsKICAgICAgICBjb250ZXh0LmFyZyA9IGFyZzsKCiAgICAgICAgd2hpbGUgKHRydWUpIHsKICAgICAgICAgIHZhciBkZWxlZ2F0ZSA9IGNvbnRleHQuZGVsZWdhdGU7CiAgICAgICAgICBpZiAoZGVsZWdhdGUpIHsKICAgICAgICAgICAgdmFyIGRlbGVnYXRlUmVzdWx0ID0gbWF5YmVJbnZva2VEZWxlZ2F0ZShkZWxlZ2F0ZSwgY29udGV4dCk7CiAgICAgICAgICAgIGlmIChkZWxlZ2F0ZVJlc3VsdCkgewogICAgICAgICAgICAgIGlmIChkZWxlZ2F0ZVJlc3VsdCA9PT0gQ29udGludWVTZW50aW5lbCkgY29udGludWU7CiAgICAgICAgICAgICAgcmV0dXJuIGRlbGVnYXRlUmVzdWx0OwogICAgICAgICAgICB9CiAgICAgICAgICB9CgogICAgICAgICAgaWYgKGNvbnRleHQubWV0aG9kID09PSAibmV4dCIpIHsKICAgICAgICAgICAgLy8gU2V0dGluZyBjb250ZXh0Ll9zZW50IGZvciBsZWdhY3kgc3VwcG9ydCBvZiBCYWJlbCdzCiAgICAgICAgICAgIC8vIGZ1bmN0aW9uLnNlbnQgaW1wbGVtZW50YXRpb24uCiAgICAgICAgICAgIGNvbnRleHQuc2VudCA9IGNvbnRleHQuX3NlbnQgPSBjb250ZXh0LmFyZzsKCiAgICAgICAgICB9IGVsc2UgaWYgKGNvbnRleHQubWV0aG9kID09PSAidGhyb3ciKSB7CiAgICAgICAgICAgIGlmIChzdGF0ZSA9PT0gR2VuU3RhdGVTdXNwZW5kZWRTdGFydCkgewogICAgICAgICAgICAgIHN0YXRlID0gR2VuU3RhdGVDb21wbGV0ZWQ7CiAgICAgICAgICAgICAgdGhyb3cgY29udGV4dC5hcmc7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGNvbnRleHQuZGlzcGF0Y2hFeGNlcHRpb24oY29udGV4dC5hcmcpOwoKICAgICAgICAgIH0gZWxzZSBpZiAoY29udGV4dC5tZXRob2QgPT09ICJyZXR1cm4iKSB7CiAgICAgICAgICAgIGNvbnRleHQuYWJydXB0KCJyZXR1cm4iLCBjb250ZXh0LmFyZyk7CiAgICAgICAgICB9CgogICAgICAgICAgc3RhdGUgPSBHZW5TdGF0ZUV4ZWN1dGluZzsKCiAgICAgICAgICB2YXIgcmVjb3JkID0gdHJ5Q2F0Y2goaW5uZXJGbiwgc2VsZiwgY29udGV4dCk7CiAgICAgICAgICBpZiAocmVjb3JkLnR5cGUgPT09ICJub3JtYWwiKSB7CiAgICAgICAgICAgIC8vIElmIGFuIGV4Y2VwdGlvbiBpcyB0aHJvd24gZnJvbSBpbm5lckZuLCB3ZSBsZWF2ZSBzdGF0ZSA9PT0KICAgICAgICAgICAgLy8gR2VuU3RhdGVFeGVjdXRpbmcgYW5kIGxvb3AgYmFjayBmb3IgYW5vdGhlciBpbnZvY2F0aW9uLgogICAgICAgICAgICBzdGF0ZSA9IGNvbnRleHQuZG9uZQogICAgICAgICAgICAgID8gR2VuU3RhdGVDb21wbGV0ZWQKICAgICAgICAgICAgICA6IEdlblN0YXRlU3VzcGVuZGVkWWllbGQ7CgogICAgICAgICAgICBpZiAocmVjb3JkLmFyZyA9PT0gQ29udGludWVTZW50aW5lbCkgewogICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICB9CgogICAgICAgICAgICByZXR1cm4gewogICAgICAgICAgICAgIHZhbHVlOiByZWNvcmQuYXJnLAogICAgICAgICAgICAgIGRvbmU6IGNvbnRleHQuZG9uZQogICAgICAgICAgICB9OwoKICAgICAgICAgIH0gZWxzZSBpZiAocmVjb3JkLnR5cGUgPT09ICJ0aHJvdyIpIHsKICAgICAgICAgICAgc3RhdGUgPSBHZW5TdGF0ZUNvbXBsZXRlZDsKICAgICAgICAgICAgLy8gRGlzcGF0Y2ggdGhlIGV4Y2VwdGlvbiBieSBsb29waW5nIGJhY2sgYXJvdW5kIHRvIHRoZQogICAgICAgICAgICAvLyBjb250ZXh0LmRpc3BhdGNoRXhjZXB0aW9uKGNvbnRleHQuYXJnKSBjYWxsIGFib3ZlLgogICAgICAgICAgICBjb250ZXh0Lm1ldGhvZCA9ICJ0aHJvdyI7CiAgICAgICAgICAgIGNvbnRleHQuYXJnID0gcmVjb3JkLmFyZzsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH07CiAgICB9CgogICAgLy8gQ2FsbCBkZWxlZ2F0ZS5pdGVyYXRvcltjb250ZXh0Lm1ldGhvZF0oY29udGV4dC5hcmcpIGFuZCBoYW5kbGUgdGhlCiAgICAvLyByZXN1bHQsIGVpdGhlciBieSByZXR1cm5pbmcgYSB7IHZhbHVlLCBkb25lIH0gcmVzdWx0IGZyb20gdGhlCiAgICAvLyBkZWxlZ2F0ZSBpdGVyYXRvciwgb3IgYnkgbW9kaWZ5aW5nIGNvbnRleHQubWV0aG9kIGFuZCBjb250ZXh0LmFyZywKICAgIC8vIHNldHRpbmcgY29udGV4dC5kZWxlZ2F0ZSB0byBudWxsLCBhbmQgcmV0dXJuaW5nIHRoZSBDb250aW51ZVNlbnRpbmVsLgogICAgZnVuY3Rpb24gbWF5YmVJbnZva2VEZWxlZ2F0ZShkZWxlZ2F0ZSwgY29udGV4dCkgewogICAgICB2YXIgbWV0aG9kID0gZGVsZWdhdGUuaXRlcmF0b3JbY29udGV4dC5tZXRob2RdOwogICAgICBpZiAobWV0aG9kID09PSB1bmRlZmluZWQkMSkgewogICAgICAgIC8vIEEgLnRocm93IG9yIC5yZXR1cm4gd2hlbiB0aGUgZGVsZWdhdGUgaXRlcmF0b3IgaGFzIG5vIC50aHJvdwogICAgICAgIC8vIG1ldGhvZCBhbHdheXMgdGVybWluYXRlcyB0aGUgeWllbGQqIGxvb3AuCiAgICAgICAgY29udGV4dC5kZWxlZ2F0ZSA9IG51bGw7CgogICAgICAgIGlmIChjb250ZXh0Lm1ldGhvZCA9PT0gInRocm93IikgewogICAgICAgICAgLy8gTm90ZTogWyJyZXR1cm4iXSBtdXN0IGJlIHVzZWQgZm9yIEVTMyBwYXJzaW5nIGNvbXBhdGliaWxpdHkuCiAgICAgICAgICBpZiAoZGVsZWdhdGUuaXRlcmF0b3JbInJldHVybiJdKSB7CiAgICAgICAgICAgIC8vIElmIHRoZSBkZWxlZ2F0ZSBpdGVyYXRvciBoYXMgYSByZXR1cm4gbWV0aG9kLCBnaXZlIGl0IGEKICAgICAgICAgICAgLy8gY2hhbmNlIHRvIGNsZWFuIHVwLgogICAgICAgICAgICBjb250ZXh0Lm1ldGhvZCA9ICJyZXR1cm4iOwogICAgICAgICAgICBjb250ZXh0LmFyZyA9IHVuZGVmaW5lZCQxOwogICAgICAgICAgICBtYXliZUludm9rZURlbGVnYXRlKGRlbGVnYXRlLCBjb250ZXh0KTsKCiAgICAgICAgICAgIGlmIChjb250ZXh0Lm1ldGhvZCA9PT0gInRocm93IikgewogICAgICAgICAgICAgIC8vIElmIG1heWJlSW52b2tlRGVsZWdhdGUoY29udGV4dCkgY2hhbmdlZCBjb250ZXh0Lm1ldGhvZCBmcm9tCiAgICAgICAgICAgICAgLy8gInJldHVybiIgdG8gInRocm93IiwgbGV0IHRoYXQgb3ZlcnJpZGUgdGhlIFR5cGVFcnJvciBiZWxvdy4KICAgICAgICAgICAgICByZXR1cm4gQ29udGludWVTZW50aW5lbDsKICAgICAgICAgICAgfQogICAgICAgICAgfQoKICAgICAgICAgIGNvbnRleHQubWV0aG9kID0gInRocm93IjsKICAgICAgICAgIGNvbnRleHQuYXJnID0gbmV3IFR5cGVFcnJvcigKICAgICAgICAgICAgIlRoZSBpdGVyYXRvciBkb2VzIG5vdCBwcm92aWRlIGEgJ3Rocm93JyBtZXRob2QiKTsKICAgICAgICB9CgogICAgICAgIHJldHVybiBDb250aW51ZVNlbnRpbmVsOwogICAgICB9CgogICAgICB2YXIgcmVjb3JkID0gdHJ5Q2F0Y2gobWV0aG9kLCBkZWxlZ2F0ZS5pdGVyYXRvciwgY29udGV4dC5hcmcpOwoKICAgICAgaWYgKHJlY29yZC50eXBlID09PSAidGhyb3ciKSB7CiAgICAgICAgY29udGV4dC5tZXRob2QgPSAidGhyb3ciOwogICAgICAgIGNvbnRleHQuYXJnID0gcmVjb3JkLmFyZzsKICAgICAgICBjb250ZXh0LmRlbGVnYXRlID0gbnVsbDsKICAgICAgICByZXR1cm4gQ29udGludWVTZW50aW5lbDsKICAgICAgfQoKICAgICAgdmFyIGluZm8gPSByZWNvcmQuYXJnOwoKICAgICAgaWYgKCEgaW5mbykgewogICAgICAgIGNvbnRleHQubWV0aG9kID0gInRocm93IjsKICAgICAgICBjb250ZXh0LmFyZyA9IG5ldyBUeXBlRXJyb3IoIml0ZXJhdG9yIHJlc3VsdCBpcyBub3QgYW4gb2JqZWN0Iik7CiAgICAgICAgY29udGV4dC5kZWxlZ2F0ZSA9IG51bGw7CiAgICAgICAgcmV0dXJuIENvbnRpbnVlU2VudGluZWw7CiAgICAgIH0KCiAgICAgIGlmIChpbmZvLmRvbmUpIHsKICAgICAgICAvLyBBc3NpZ24gdGhlIHJlc3VsdCBvZiB0aGUgZmluaXNoZWQgZGVsZWdhdGUgdG8gdGhlIHRlbXBvcmFyeQogICAgICAgIC8vIHZhcmlhYmxlIHNwZWNpZmllZCBieSBkZWxlZ2F0ZS5yZXN1bHROYW1lIChzZWUgZGVsZWdhdGVZaWVsZCkuCiAgICAgICAgY29udGV4dFtkZWxlZ2F0ZS5yZXN1bHROYW1lXSA9IGluZm8udmFsdWU7CgogICAgICAgIC8vIFJlc3VtZSBleGVjdXRpb24gYXQgdGhlIGRlc2lyZWQgbG9jYXRpb24gKHNlZSBkZWxlZ2F0ZVlpZWxkKS4KICAgICAgICBjb250ZXh0Lm5leHQgPSBkZWxlZ2F0ZS5uZXh0TG9jOwoKICAgICAgICAvLyBJZiBjb250ZXh0Lm1ldGhvZCB3YXMgInRocm93IiBidXQgdGhlIGRlbGVnYXRlIGhhbmRsZWQgdGhlCiAgICAgICAgLy8gZXhjZXB0aW9uLCBsZXQgdGhlIG91dGVyIGdlbmVyYXRvciBwcm9jZWVkIG5vcm1hbGx5LiBJZgogICAgICAgIC8vIGNvbnRleHQubWV0aG9kIHdhcyAibmV4dCIsIGZvcmdldCBjb250ZXh0LmFyZyBzaW5jZSBpdCBoYXMgYmVlbgogICAgICAgIC8vICJjb25zdW1lZCIgYnkgdGhlIGRlbGVnYXRlIGl0ZXJhdG9yLiBJZiBjb250ZXh0Lm1ldGhvZCB3YXMKICAgICAgICAvLyAicmV0dXJuIiwgYWxsb3cgdGhlIG9yaWdpbmFsIC5yZXR1cm4gY2FsbCB0byBjb250aW51ZSBpbiB0aGUKICAgICAgICAvLyBvdXRlciBnZW5lcmF0b3IuCiAgICAgICAgaWYgKGNvbnRleHQubWV0aG9kICE9PSAicmV0dXJuIikgewogICAgICAgICAgY29udGV4dC5tZXRob2QgPSAibmV4dCI7CiAgICAgICAgICBjb250ZXh0LmFyZyA9IHVuZGVmaW5lZCQxOwogICAgICAgIH0KCiAgICAgIH0gZWxzZSB7CiAgICAgICAgLy8gUmUteWllbGQgdGhlIHJlc3VsdCByZXR1cm5lZCBieSB0aGUgZGVsZWdhdGUgbWV0aG9kLgogICAgICAgIHJldHVybiBpbmZvOwogICAgICB9CgogICAgICAvLyBUaGUgZGVsZWdhdGUgaXRlcmF0b3IgaXMgZmluaXNoZWQsIHNvIGZvcmdldCBpdCBhbmQgY29udGludWUgd2l0aAogICAgICAvLyB0aGUgb3V0ZXIgZ2VuZXJhdG9yLgogICAgICBjb250ZXh0LmRlbGVnYXRlID0gbnVsbDsKICAgICAgcmV0dXJuIENvbnRpbnVlU2VudGluZWw7CiAgICB9CgogICAgLy8gRGVmaW5lIEdlbmVyYXRvci5wcm90b3R5cGUue25leHQsdGhyb3cscmV0dXJufSBpbiB0ZXJtcyBvZiB0aGUKICAgIC8vIHVuaWZpZWQgLl9pbnZva2UgaGVscGVyIG1ldGhvZC4KICAgIGRlZmluZUl0ZXJhdG9yTWV0aG9kcyhHcCk7CgogICAgZGVmaW5lKEdwLCB0b1N0cmluZ1RhZ1N5bWJvbCwgIkdlbmVyYXRvciIpOwoKICAgIC8vIEEgR2VuZXJhdG9yIHNob3VsZCBhbHdheXMgcmV0dXJuIGl0c2VsZiBhcyB0aGUgaXRlcmF0b3Igb2JqZWN0IHdoZW4gdGhlCiAgICAvLyBAQGl0ZXJhdG9yIGZ1bmN0aW9uIGlzIGNhbGxlZCBvbiBpdC4gU29tZSBicm93c2VycycgaW1wbGVtZW50YXRpb25zIG9mIHRoZQogICAgLy8gaXRlcmF0b3IgcHJvdG90eXBlIGNoYWluIGluY29ycmVjdGx5IGltcGxlbWVudCB0aGlzLCBjYXVzaW5nIHRoZSBHZW5lcmF0b3IKICAgIC8vIG9iamVjdCB0byBub3QgYmUgcmV0dXJuZWQgZnJvbSB0aGlzIGNhbGwuIFRoaXMgZW5zdXJlcyB0aGF0IGRvZXNuJ3QgaGFwcGVuLgogICAgLy8gU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9mYWNlYm9vay9yZWdlbmVyYXRvci9pc3N1ZXMvMjc0IGZvciBtb3JlIGRldGFpbHMuCiAgICBHcFtpdGVyYXRvclN5bWJvbF0gPSBmdW5jdGlvbigpIHsKICAgICAgcmV0dXJuIHRoaXM7CiAgICB9OwoKICAgIEdwLnRvU3RyaW5nID0gZnVuY3Rpb24oKSB7CiAgICAgIHJldHVybiAiW29iamVjdCBHZW5lcmF0b3JdIjsKICAgIH07CgogICAgZnVuY3Rpb24gcHVzaFRyeUVudHJ5KGxvY3MpIHsKICAgICAgdmFyIGVudHJ5ID0geyB0cnlMb2M6IGxvY3NbMF0gfTsKCiAgICAgIGlmICgxIGluIGxvY3MpIHsKICAgICAgICBlbnRyeS5jYXRjaExvYyA9IGxvY3NbMV07CiAgICAgIH0KCiAgICAgIGlmICgyIGluIGxvY3MpIHsKICAgICAgICBlbnRyeS5maW5hbGx5TG9jID0gbG9jc1syXTsKICAgICAgICBlbnRyeS5hZnRlckxvYyA9IGxvY3NbM107CiAgICAgIH0KCiAgICAgIHRoaXMudHJ5RW50cmllcy5wdXNoKGVudHJ5KTsKICAgIH0KCiAgICBmdW5jdGlvbiByZXNldFRyeUVudHJ5KGVudHJ5KSB7CiAgICAgIHZhciByZWNvcmQgPSBlbnRyeS5jb21wbGV0aW9uIHx8IHt9OwogICAgICByZWNvcmQudHlwZSA9ICJub3JtYWwiOwogICAgICBkZWxldGUgcmVjb3JkLmFyZzsKICAgICAgZW50cnkuY29tcGxldGlvbiA9IHJlY29yZDsKICAgIH0KCiAgICBmdW5jdGlvbiBDb250ZXh0KHRyeUxvY3NMaXN0KSB7CiAgICAgIC8vIFRoZSByb290IGVudHJ5IG9iamVjdCAoZWZmZWN0aXZlbHkgYSB0cnkgc3RhdGVtZW50IHdpdGhvdXQgYSBjYXRjaAogICAgICAvLyBvciBhIGZpbmFsbHkgYmxvY2spIGdpdmVzIHVzIGEgcGxhY2UgdG8gc3RvcmUgdmFsdWVzIHRocm93biBmcm9tCiAgICAgIC8vIGxvY2F0aW9ucyB3aGVyZSB0aGVyZSBpcyBubyBlbmNsb3NpbmcgdHJ5IHN0YXRlbWVudC4KICAgICAgdGhpcy50cnlFbnRyaWVzID0gW3sgdHJ5TG9jOiAicm9vdCIgfV07CiAgICAgIHRyeUxvY3NMaXN0LmZvckVhY2gocHVzaFRyeUVudHJ5LCB0aGlzKTsKICAgICAgdGhpcy5yZXNldCh0cnVlKTsKICAgIH0KCiAgICBleHBvcnRzLmtleXMgPSBmdW5jdGlvbihvYmplY3QpIHsKICAgICAgdmFyIGtleXMgPSBbXTsKICAgICAgZm9yICh2YXIga2V5IGluIG9iamVjdCkgewogICAgICAgIGtleXMucHVzaChrZXkpOwogICAgICB9CiAgICAgIGtleXMucmV2ZXJzZSgpOwoKICAgICAgLy8gUmF0aGVyIHRoYW4gcmV0dXJuaW5nIGFuIG9iamVjdCB3aXRoIGEgbmV4dCBtZXRob2QsIHdlIGtlZXAKICAgICAgLy8gdGhpbmdzIHNpbXBsZSBhbmQgcmV0dXJuIHRoZSBuZXh0IGZ1bmN0aW9uIGl0c2VsZi4KICAgICAgcmV0dXJuIGZ1bmN0aW9uIG5leHQoKSB7CiAgICAgICAgd2hpbGUgKGtleXMubGVuZ3RoKSB7CiAgICAgICAgICB2YXIga2V5ID0ga2V5cy5wb3AoKTsKICAgICAgICAgIGlmIChrZXkgaW4gb2JqZWN0KSB7CiAgICAgICAgICAgIG5leHQudmFsdWUgPSBrZXk7CiAgICAgICAgICAgIG5leHQuZG9uZSA9IGZhbHNlOwogICAgICAgICAgICByZXR1cm4gbmV4dDsKICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIC8vIFRvIGF2b2lkIGNyZWF0aW5nIGFuIGFkZGl0aW9uYWwgb2JqZWN0LCB3ZSBqdXN0IGhhbmcgdGhlIC52YWx1ZQogICAgICAgIC8vIGFuZCAuZG9uZSBwcm9wZXJ0aWVzIG9mZiB0aGUgbmV4dCBmdW5jdGlvbiBvYmplY3QgaXRzZWxmLiBUaGlzCiAgICAgICAgLy8gYWxzbyBlbnN1cmVzIHRoYXQgdGhlIG1pbmlmaWVyIHdpbGwgbm90IGFub255bWl6ZSB0aGUgZnVuY3Rpb24uCiAgICAgICAgbmV4dC5kb25lID0gdHJ1ZTsKICAgICAgICByZXR1cm4gbmV4dDsKICAgICAgfTsKICAgIH07CgogICAgZnVuY3Rpb24gdmFsdWVzKGl0ZXJhYmxlKSB7CiAgICAgIGlmIChpdGVyYWJsZSkgewogICAgICAgIHZhciBpdGVyYXRvck1ldGhvZCA9IGl0ZXJhYmxlW2l0ZXJhdG9yU3ltYm9sXTsKICAgICAgICBpZiAoaXRlcmF0b3JNZXRob2QpIHsKICAgICAgICAgIHJldHVybiBpdGVyYXRvck1ldGhvZC5jYWxsKGl0ZXJhYmxlKTsKICAgICAgICB9CgogICAgICAgIGlmICh0eXBlb2YgaXRlcmFibGUubmV4dCA9PT0gImZ1bmN0aW9uIikgewogICAgICAgICAgcmV0dXJuIGl0ZXJhYmxlOwogICAgICAgIH0KCiAgICAgICAgaWYgKCFpc05hTihpdGVyYWJsZS5sZW5ndGgpKSB7CiAgICAgICAgICB2YXIgaSA9IC0xLCBuZXh0ID0gZnVuY3Rpb24gbmV4dCgpIHsKICAgICAgICAgICAgd2hpbGUgKCsraSA8IGl0ZXJhYmxlLmxlbmd0aCkgewogICAgICAgICAgICAgIGlmIChoYXNPd24uY2FsbChpdGVyYWJsZSwgaSkpIHsKICAgICAgICAgICAgICAgIG5leHQudmFsdWUgPSBpdGVyYWJsZVtpXTsKICAgICAgICAgICAgICAgIG5leHQuZG9uZSA9IGZhbHNlOwogICAgICAgICAgICAgICAgcmV0dXJuIG5leHQ7CiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CgogICAgICAgICAgICBuZXh0LnZhbHVlID0gdW5kZWZpbmVkJDE7CiAgICAgICAgICAgIG5leHQuZG9uZSA9IHRydWU7CgogICAgICAgICAgICByZXR1cm4gbmV4dDsKICAgICAgICAgIH07CgogICAgICAgICAgcmV0dXJuIG5leHQubmV4dCA9IG5leHQ7CiAgICAgICAgfQogICAgICB9CgogICAgICAvLyBSZXR1cm4gYW4gaXRlcmF0b3Igd2l0aCBubyB2YWx1ZXMuCiAgICAgIHJldHVybiB7IG5leHQ6IGRvbmVSZXN1bHQgfTsKICAgIH0KICAgIGV4cG9ydHMudmFsdWVzID0gdmFsdWVzOwoKICAgIGZ1bmN0aW9uIGRvbmVSZXN1bHQoKSB7CiAgICAgIHJldHVybiB7IHZhbHVlOiB1bmRlZmluZWQkMSwgZG9uZTogdHJ1ZSB9OwogICAgfQoKICAgIENvbnRleHQucHJvdG90eXBlID0gewogICAgICBjb25zdHJ1Y3RvcjogQ29udGV4dCwKCiAgICAgIHJlc2V0OiBmdW5jdGlvbihza2lwVGVtcFJlc2V0KSB7CiAgICAgICAgdGhpcy5wcmV2ID0gMDsKICAgICAgICB0aGlzLm5leHQgPSAwOwogICAgICAgIC8vIFJlc2V0dGluZyBjb250ZXh0Ll9zZW50IGZvciBsZWdhY3kgc3VwcG9ydCBvZiBCYWJlbCdzCiAgICAgICAgLy8gZnVuY3Rpb24uc2VudCBpbXBsZW1lbnRhdGlvbi4KICAgICAgICB0aGlzLnNlbnQgPSB0aGlzLl9zZW50ID0gdW5kZWZpbmVkJDE7CiAgICAgICAgdGhpcy5kb25lID0gZmFsc2U7CiAgICAgICAgdGhpcy5kZWxlZ2F0ZSA9IG51bGw7CgogICAgICAgIHRoaXMubWV0aG9kID0gIm5leHQiOwogICAgICAgIHRoaXMuYXJnID0gdW5kZWZpbmVkJDE7CgogICAgICAgIHRoaXMudHJ5RW50cmllcy5mb3JFYWNoKHJlc2V0VHJ5RW50cnkpOwoKICAgICAgICBpZiAoIXNraXBUZW1wUmVzZXQpIHsKICAgICAgICAgIGZvciAodmFyIG5hbWUgaW4gdGhpcykgewogICAgICAgICAgICAvLyBOb3Qgc3VyZSBhYm91dCB0aGUgb3B0aW1hbCBvcmRlciBvZiB0aGVzZSBjb25kaXRpb25zOgogICAgICAgICAgICBpZiAobmFtZS5jaGFyQXQoMCkgPT09ICJ0IiAmJgogICAgICAgICAgICAgICAgaGFzT3duLmNhbGwodGhpcywgbmFtZSkgJiYKICAgICAgICAgICAgICAgICFpc05hTigrbmFtZS5zbGljZSgxKSkpIHsKICAgICAgICAgICAgICB0aGlzW25hbWVdID0gdW5kZWZpbmVkJDE7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0sCgogICAgICBzdG9wOiBmdW5jdGlvbigpIHsKICAgICAgICB0aGlzLmRvbmUgPSB0cnVlOwoKICAgICAgICB2YXIgcm9vdEVudHJ5ID0gdGhpcy50cnlFbnRyaWVzWzBdOwogICAgICAgIHZhciByb290UmVjb3JkID0gcm9vdEVudHJ5LmNvbXBsZXRpb247CiAgICAgICAgaWYgKHJvb3RSZWNvcmQudHlwZSA9PT0gInRocm93IikgewogICAgICAgICAgdGhyb3cgcm9vdFJlY29yZC5hcmc7CiAgICAgICAgfQoKICAgICAgICByZXR1cm4gdGhpcy5ydmFsOwogICAgICB9LAoKICAgICAgZGlzcGF0Y2hFeGNlcHRpb246IGZ1bmN0aW9uKGV4Y2VwdGlvbikgewogICAgICAgIGlmICh0aGlzLmRvbmUpIHsKICAgICAgICAgIHRocm93IGV4Y2VwdGlvbjsKICAgICAgICB9CgogICAgICAgIHZhciBjb250ZXh0ID0gdGhpczsKICAgICAgICBmdW5jdGlvbiBoYW5kbGUobG9jLCBjYXVnaHQpIHsKICAgICAgICAgIHJlY29yZC50eXBlID0gInRocm93IjsKICAgICAgICAgIHJlY29yZC5hcmcgPSBleGNlcHRpb247CiAgICAgICAgICBjb250ZXh0Lm5leHQgPSBsb2M7CgogICAgICAgICAgaWYgKGNhdWdodCkgewogICAgICAgICAgICAvLyBJZiB0aGUgZGlzcGF0Y2hlZCBleGNlcHRpb24gd2FzIGNhdWdodCBieSBhIGNhdGNoIGJsb2NrLAogICAgICAgICAgICAvLyB0aGVuIGxldCB0aGF0IGNhdGNoIGJsb2NrIGhhbmRsZSB0aGUgZXhjZXB0aW9uIG5vcm1hbGx5LgogICAgICAgICAgICBjb250ZXh0Lm1ldGhvZCA9ICJuZXh0IjsKICAgICAgICAgICAgY29udGV4dC5hcmcgPSB1bmRlZmluZWQkMTsKICAgICAgICAgIH0KCiAgICAgICAgICByZXR1cm4gISEgY2F1Z2h0OwogICAgICAgIH0KCiAgICAgICAgZm9yICh2YXIgaSA9IHRoaXMudHJ5RW50cmllcy5sZW5ndGggLSAxOyBpID49IDA7IC0taSkgewogICAgICAgICAgdmFyIGVudHJ5ID0gdGhpcy50cnlFbnRyaWVzW2ldOwogICAgICAgICAgdmFyIHJlY29yZCA9IGVudHJ5LmNvbXBsZXRpb247CgogICAgICAgICAgaWYgKGVudHJ5LnRyeUxvYyA9PT0gInJvb3QiKSB7CiAgICAgICAgICAgIC8vIEV4Y2VwdGlvbiB0aHJvd24gb3V0c2lkZSBvZiBhbnkgdHJ5IGJsb2NrIHRoYXQgY291bGQgaGFuZGxlCiAgICAgICAgICAgIC8vIGl0LCBzbyBzZXQgdGhlIGNvbXBsZXRpb24gdmFsdWUgb2YgdGhlIGVudGlyZSBmdW5jdGlvbiB0bwogICAgICAgICAgICAvLyB0aHJvdyB0aGUgZXhjZXB0aW9uLgogICAgICAgICAgICByZXR1cm4gaGFuZGxlKCJlbmQiKTsKICAgICAgICAgIH0KCiAgICAgICAgICBpZiAoZW50cnkudHJ5TG9jIDw9IHRoaXMucHJldikgewogICAgICAgICAgICB2YXIgaGFzQ2F0Y2ggPSBoYXNPd24uY2FsbChlbnRyeSwgImNhdGNoTG9jIik7CiAgICAgICAgICAgIHZhciBoYXNGaW5hbGx5ID0gaGFzT3duLmNhbGwoZW50cnksICJmaW5hbGx5TG9jIik7CgogICAgICAgICAgICBpZiAoaGFzQ2F0Y2ggJiYgaGFzRmluYWxseSkgewogICAgICAgICAgICAgIGlmICh0aGlzLnByZXYgPCBlbnRyeS5jYXRjaExvYykgewogICAgICAgICAgICAgICAgcmV0dXJuIGhhbmRsZShlbnRyeS5jYXRjaExvYywgdHJ1ZSk7CiAgICAgICAgICAgICAgfSBlbHNlIGlmICh0aGlzLnByZXYgPCBlbnRyeS5maW5hbGx5TG9jKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gaGFuZGxlKGVudHJ5LmZpbmFsbHlMb2MpOwogICAgICAgICAgICAgIH0KCiAgICAgICAgICAgIH0gZWxzZSBpZiAoaGFzQ2F0Y2gpIHsKICAgICAgICAgICAgICBpZiAodGhpcy5wcmV2IDwgZW50cnkuY2F0Y2hMb2MpIHsKICAgICAgICAgICAgICAgIHJldHVybiBoYW5kbGUoZW50cnkuY2F0Y2hMb2MsIHRydWUpOwogICAgICAgICAgICAgIH0KCiAgICAgICAgICAgIH0gZWxzZSBpZiAoaGFzRmluYWxseSkgewogICAgICAgICAgICAgIGlmICh0aGlzLnByZXYgPCBlbnRyeS5maW5hbGx5TG9jKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gaGFuZGxlKGVudHJ5LmZpbmFsbHlMb2MpOwogICAgICAgICAgICAgIH0KCiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCJ0cnkgc3RhdGVtZW50IHdpdGhvdXQgY2F0Y2ggb3IgZmluYWxseSIpOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9LAoKICAgICAgYWJydXB0OiBmdW5jdGlvbih0eXBlLCBhcmcpIHsKICAgICAgICBmb3IgKHZhciBpID0gdGhpcy50cnlFbnRyaWVzLmxlbmd0aCAtIDE7IGkgPj0gMDsgLS1pKSB7CiAgICAgICAgICB2YXIgZW50cnkgPSB0aGlzLnRyeUVudHJpZXNbaV07CiAgICAgICAgICBpZiAoZW50cnkudHJ5TG9jIDw9IHRoaXMucHJldiAmJgogICAgICAgICAgICAgIGhhc093bi5jYWxsKGVudHJ5LCAiZmluYWxseUxvYyIpICYmCiAgICAgICAgICAgICAgdGhpcy5wcmV2IDwgZW50cnkuZmluYWxseUxvYykgewogICAgICAgICAgICB2YXIgZmluYWxseUVudHJ5ID0gZW50cnk7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgfQogICAgICAgIH0KCiAgICAgICAgaWYgKGZpbmFsbHlFbnRyeSAmJgogICAgICAgICAgICAodHlwZSA9PT0gImJyZWFrIiB8fAogICAgICAgICAgICAgdHlwZSA9PT0gImNvbnRpbnVlIikgJiYKICAgICAgICAgICAgZmluYWxseUVudHJ5LnRyeUxvYyA8PSBhcmcgJiYKICAgICAgICAgICAgYXJnIDw9IGZpbmFsbHlFbnRyeS5maW5hbGx5TG9jKSB7CiAgICAgICAgICAvLyBJZ25vcmUgdGhlIGZpbmFsbHkgZW50cnkgaWYgY29udHJvbCBpcyBub3QganVtcGluZyB0byBhCiAgICAgICAgICAvLyBsb2NhdGlvbiBvdXRzaWRlIHRoZSB0cnkvY2F0Y2ggYmxvY2suCiAgICAgICAgICBmaW5hbGx5RW50cnkgPSBudWxsOwogICAgICAgIH0KCiAgICAgICAgdmFyIHJlY29yZCA9IGZpbmFsbHlFbnRyeSA/IGZpbmFsbHlFbnRyeS5jb21wbGV0aW9uIDoge307CiAgICAgICAgcmVjb3JkLnR5cGUgPSB0eXBlOwogICAgICAgIHJlY29yZC5hcmcgPSBhcmc7CgogICAgICAgIGlmIChmaW5hbGx5RW50cnkpIHsKICAgICAgICAgIHRoaXMubWV0aG9kID0gIm5leHQiOwogICAgICAgICAgdGhpcy5uZXh0ID0gZmluYWxseUVudHJ5LmZpbmFsbHlMb2M7CiAgICAgICAgICByZXR1cm4gQ29udGludWVTZW50aW5lbDsKICAgICAgICB9CgogICAgICAgIHJldHVybiB0aGlzLmNvbXBsZXRlKHJlY29yZCk7CiAgICAgIH0sCgogICAgICBjb21wbGV0ZTogZnVuY3Rpb24ocmVjb3JkLCBhZnRlckxvYykgewogICAgICAgIGlmIChyZWNvcmQudHlwZSA9PT0gInRocm93IikgewogICAgICAgICAgdGhyb3cgcmVjb3JkLmFyZzsKICAgICAgICB9CgogICAgICAgIGlmIChyZWNvcmQudHlwZSA9PT0gImJyZWFrIiB8fAogICAgICAgICAgICByZWNvcmQudHlwZSA9PT0gImNvbnRpbnVlIikgewogICAgICAgICAgdGhpcy5uZXh0ID0gcmVjb3JkLmFyZzsKICAgICAgICB9IGVsc2UgaWYgKHJlY29yZC50eXBlID09PSAicmV0dXJuIikgewogICAgICAgICAgdGhpcy5ydmFsID0gdGhpcy5hcmcgPSByZWNvcmQuYXJnOwogICAgICAgICAgdGhpcy5tZXRob2QgPSAicmV0dXJuIjsKICAgICAgICAgIHRoaXMubmV4dCA9ICJlbmQiOwogICAgICAgIH0gZWxzZSBpZiAocmVjb3JkLnR5cGUgPT09ICJub3JtYWwiICYmIGFmdGVyTG9jKSB7CiAgICAgICAgICB0aGlzLm5leHQgPSBhZnRlckxvYzsKICAgICAgICB9CgogICAgICAgIHJldHVybiBDb250aW51ZVNlbnRpbmVsOwogICAgICB9LAoKICAgICAgZmluaXNoOiBmdW5jdGlvbihmaW5hbGx5TG9jKSB7CiAgICAgICAgZm9yICh2YXIgaSA9IHRoaXMudHJ5RW50cmllcy5sZW5ndGggLSAxOyBpID49IDA7IC0taSkgewogICAgICAgICAgdmFyIGVudHJ5ID0gdGhpcy50cnlFbnRyaWVzW2ldOwogICAgICAgICAgaWYgKGVudHJ5LmZpbmFsbHlMb2MgPT09IGZpbmFsbHlMb2MpIHsKICAgICAgICAgICAgdGhpcy5jb21wbGV0ZShlbnRyeS5jb21wbGV0aW9uLCBlbnRyeS5hZnRlckxvYyk7CiAgICAgICAgICAgIHJlc2V0VHJ5RW50cnkoZW50cnkpOwogICAgICAgICAgICByZXR1cm4gQ29udGludWVTZW50aW5lbDsKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0sCgogICAgICAiY2F0Y2giOiBmdW5jdGlvbih0cnlMb2MpIHsKICAgICAgICBmb3IgKHZhciBpID0gdGhpcy50cnlFbnRyaWVzLmxlbmd0aCAtIDE7IGkgPj0gMDsgLS1pKSB7CiAgICAgICAgICB2YXIgZW50cnkgPSB0aGlzLnRyeUVudHJpZXNbaV07CiAgICAgICAgICBpZiAoZW50cnkudHJ5TG9jID09PSB0cnlMb2MpIHsKICAgICAgICAgICAgdmFyIHJlY29yZCA9IGVudHJ5LmNvbXBsZXRpb247CiAgICAgICAgICAgIGlmIChyZWNvcmQudHlwZSA9PT0gInRocm93IikgewogICAgICAgICAgICAgIHZhciB0aHJvd24gPSByZWNvcmQuYXJnOwogICAgICAgICAgICAgIHJlc2V0VHJ5RW50cnkoZW50cnkpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiB0aHJvd247CiAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICAvLyBUaGUgY29udGV4dC5jYXRjaCBtZXRob2QgbXVzdCBvbmx5IGJlIGNhbGxlZCB3aXRoIGEgbG9jYXRpb24KICAgICAgICAvLyBhcmd1bWVudCB0aGF0IGNvcnJlc3BvbmRzIHRvIGEga25vd24gY2F0Y2ggYmxvY2suCiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCJpbGxlZ2FsIGNhdGNoIGF0dGVtcHQiKTsKICAgICAgfSwKCiAgICAgIGRlbGVnYXRlWWllbGQ6IGZ1bmN0aW9uKGl0ZXJhYmxlLCByZXN1bHROYW1lLCBuZXh0TG9jKSB7CiAgICAgICAgdGhpcy5kZWxlZ2F0ZSA9IHsKICAgICAgICAgIGl0ZXJhdG9yOiB2YWx1ZXMoaXRlcmFibGUpLAogICAgICAgICAgcmVzdWx0TmFtZTogcmVzdWx0TmFtZSwKICAgICAgICAgIG5leHRMb2M6IG5leHRMb2MKICAgICAgICB9OwoKICAgICAgICBpZiAodGhpcy5tZXRob2QgPT09ICJuZXh0IikgewogICAgICAgICAgLy8gRGVsaWJlcmF0ZWx5IGZvcmdldCB0aGUgbGFzdCBzZW50IHZhbHVlIHNvIHRoYXQgd2UgZG9uJ3QKICAgICAgICAgIC8vIGFjY2lkZW50YWxseSBwYXNzIGl0IG9uIHRvIHRoZSBkZWxlZ2F0ZS4KICAgICAgICAgIHRoaXMuYXJnID0gdW5kZWZpbmVkJDE7CiAgICAgICAgfQoKICAgICAgICByZXR1cm4gQ29udGludWVTZW50aW5lbDsKICAgICAgfQogICAgfTsKCiAgICAvLyBSZWdhcmRsZXNzIG9mIHdoZXRoZXIgdGhpcyBzY3JpcHQgaXMgZXhlY3V0aW5nIGFzIGEgQ29tbW9uSlMgbW9kdWxlCiAgICAvLyBvciBub3QsIHJldHVybiB0aGUgcnVudGltZSBvYmplY3Qgc28gdGhhdCB3ZSBjYW4gZGVjbGFyZSB0aGUgdmFyaWFibGUKICAgIC8vIHJlZ2VuZXJhdG9yUnVudGltZSBpbiB0aGUgb3V0ZXIgc2NvcGUsIHdoaWNoIGFsbG93cyB0aGlzIG1vZHVsZSB0byBiZQogICAgLy8gaW5qZWN0ZWQgZWFzaWx5IGJ5IGBiaW4vcmVnZW5lcmF0b3IgLS1pbmNsdWRlLXJ1bnRpbWUgc2NyaXB0LmpzYC4KICAgIHJldHVybiBleHBvcnRzOwoKICB9KAogICAgLy8gSWYgdGhpcyBzY3JpcHQgaXMgZXhlY3V0aW5nIGFzIGEgQ29tbW9uSlMgbW9kdWxlLCB1c2UgbW9kdWxlLmV4cG9ydHMKICAgIC8vIGFzIHRoZSByZWdlbmVyYXRvclJ1bnRpbWUgbmFtZXNwYWNlLiBPdGhlcndpc2UgY3JlYXRlIGEgbmV3IGVtcHR5CiAgICAvLyBvYmplY3QuIEVpdGhlciB3YXksIHRoZSByZXN1bHRpbmcgb2JqZWN0IHdpbGwgYmUgdXNlZCB0byBpbml0aWFsaXplCiAgICAvLyB0aGUgcmVnZW5lcmF0b3JSdW50aW1lIHZhcmlhYmxlIGF0IHRoZSB0b3Agb2YgdGhpcyBmaWxlLgogICAgbW9kdWxlLmV4cG9ydHMgCiAgKSk7CgogIHRyeSB7CiAgICByZWdlbmVyYXRvclJ1bnRpbWUgPSBydW50aW1lOwogIH0gY2F0Y2ggKGFjY2lkZW50YWxTdHJpY3RNb2RlKSB7CiAgICAvLyBUaGlzIG1vZHVsZSBzaG91bGQgbm90IGJlIHJ1bm5pbmcgaW4gc3RyaWN0IG1vZGUsIHNvIHRoZSBhYm92ZQogICAgLy8gYXNzaWdubWVudCBzaG91bGQgYWx3YXlzIHdvcmsgdW5sZXNzIHNvbWV0aGluZyBpcyBtaXNjb25maWd1cmVkLiBKdXN0CiAgICAvLyBpbiBjYXNlIHJ1bnRpbWUuanMgYWNjaWRlbnRhbGx5IHJ1bnMgaW4gc3RyaWN0IG1vZGUsIHdlIGNhbiBlc2NhcGUKICAgIC8vIHN0cmljdCBtb2RlIHVzaW5nIGEgZ2xvYmFsIEZ1bmN0aW9uIGNhbGwuIFRoaXMgY291bGQgY29uY2VpdmFibHkgZmFpbAogICAgLy8gaWYgYSBDb250ZW50IFNlY3VyaXR5IFBvbGljeSBmb3JiaWRzIHVzaW5nIEZ1bmN0aW9uLCBidXQgaW4gdGhhdCBjYXNlCiAgICAvLyB0aGUgcHJvcGVyIHNvbHV0aW9uIGlzIHRvIGZpeCB0aGUgYWNjaWRlbnRhbCBzdHJpY3QgbW9kZSBwcm9ibGVtLiBJZgogICAgLy8geW91J3ZlIG1pc2NvbmZpZ3VyZWQgeW91ciBidW5kbGVyIHRvIGZvcmNlIHN0cmljdCBtb2RlIGFuZCBhcHBsaWVkIGEKICAgIC8vIENTUCB0byBmb3JiaWQgRnVuY3Rpb24sIGFuZCB5b3UncmUgbm90IHdpbGxpbmcgdG8gZml4IGVpdGhlciBvZiB0aG9zZQogICAgLy8gcHJvYmxlbXMsIHBsZWFzZSBkZXRhaWwgeW91ciB1bmlxdWUgcHJlZGljYW1lbnQgaW4gYSBHaXRIdWIgaXNzdWUuCiAgICBGdW5jdGlvbigiciIsICJyZWdlbmVyYXRvclJ1bnRpbWUgPSByIikocnVudGltZSk7CiAgfQogIH0pOwoKICBmdW5jdGlvbiBkZWNvZGVUZXJyYWluKHBhcmFtZXRlcnMsIHRyYW5zZmVyYWJsZU9iamVjdHMpIHsKICAgIHZhciBpbWFnZURhdGEgPSBwYXJhbWV0ZXJzLmltYWdlRGF0YSwKICAgICAgICBfcGFyYW1ldGVycyR0aWxlU2l6ZSA9IHBhcmFtZXRlcnMudGlsZVNpemUsCiAgICAgICAgdGlsZVNpemUgPSBfcGFyYW1ldGVycyR0aWxlU2l6ZSA9PT0gdm9pZCAwID8gMjU2IDogX3BhcmFtZXRlcnMkdGlsZVNpemUsCiAgICAgICAgZXJyb3JMZXZlbCA9IHBhcmFtZXRlcnMuZXJyb3JMZXZlbDsKICAgIHZhciBwaXhlbHMgPSBuZGFycmF5KG5ldyBVaW50OEFycmF5KGltYWdlRGF0YSksIFt0aWxlU2l6ZSwgdGlsZVNpemUsIDRdLCBbNCwgNCAqIHRpbGVTaXplLCAxXSwgMCk7CiAgICB2YXIgbWFydGluaSA9IG5ldyBNYXJ0aW5pKHRpbGVTaXplICsgMSk7CiAgICB2YXIgdGVycmFpbiA9IG1hcGJveFRlcnJhaW5Ub0dyaWQocGl4ZWxzKTsKICAgIHZhciB0aWxlID0gbWFydGluaS5jcmVhdGVUaWxlKHRlcnJhaW4pOyAvLyBnZXQgYSBtZXNoICh2ZXJ0aWNlcyBhbmQgdHJpYW5nbGVzIGluZGljZXMpIGZvciBhIDEwbSBlcnJvcgoKICAgIGNvbnNvbGUubG9nKCJFcnJvciBsZXZlbDogIi5jb25jYXQoZXJyb3JMZXZlbCkpOwogICAgdmFyIG1lc2ggPSB0aWxlLmdldE1lc2goZXJyb3JMZXZlbCwgcGFyYW1ldGVycy5tYXhMZW5ndGgpOwogICAgcmV0dXJuIGNyZWF0ZVF1YW50aXplZE1lc2hEYXRhKHRpbGUsIG1lc2gsIHRpbGVTaXplKTsKICB9CgogIHNlbGYub25tZXNzYWdlID0gZnVuY3Rpb24gKG1zZykgewogICAgdmFyIF9tc2ckZGF0YSA9IG1zZy5kYXRhLAogICAgICAgIGlkID0gX21zZyRkYXRhLmlkLAogICAgICAgIHBheWxvYWQgPSBfbXNnJGRhdGEucGF5bG9hZDsKICAgIGlmIChpZCA9PSBudWxsKSByZXR1cm47CiAgICBjb25zb2xlLmxvZygiV29ya2VyIHJlY2lldmVkIG1lc3NhZ2UiLCBtc2cuZGF0YSk7CiAgICB2YXIgb2JqZWN0cyA9IFtdOwoKICAgIHRyeSB7CiAgICAgIHZhciByZXMgPSBkZWNvZGVUZXJyYWluKHBheWxvYWQpOwogICAgICBvYmplY3RzLnB1c2gocmVzLmluZGljZXMuYnVmZmVyKTsKICAgICAgb2JqZWN0cy5wdXNoKHJlcy5xdWFudGl6ZWRWZXJ0aWNlcy5idWZmZXIpOwogICAgICBzZWxmLnBvc3RNZXNzYWdlKHsKICAgICAgICBpZDogaWQsCiAgICAgICAgcGF5bG9hZDogcmVzCiAgICAgIH0sIG9iamVjdHMpOwogICAgfSBjYXRjaCAoZXJyKSB7CiAgICAgIHNlbGYucG9zdE1lc3NhZ2UoewogICAgICAgIGlkOiBpZCwKICAgICAgICBlcnI6IGVyci50b1N0cmluZygpCiAgICAgIH0pOwogICAgfSBmaW5hbGx5IHsKICAgICAgb2JqZWN0cyA9IG51bGw7CiAgICB9CiAgfTsKCiAgZXhwb3J0cy5kZWNvZGVUZXJyYWluID0gZGVjb2RlVGVycmFpbjsKCiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsICdfX2VzTW9kdWxlJywgeyB2YWx1ZTogdHJ1ZSB9KTsKCiAgcmV0dXJuIGV4cG9ydHM7Cgp9KHt9KSk7Cgo=', null, false);
480
+ var WorkerFactory = createBase64WorkerFactory('Lyogcm9sbHVwLXBsdWdpbi13ZWItd29ya2VyLWxvYWRlciAqLwp2YXIgd29ya2VyX2NvZGUgPSAoZnVuY3Rpb24gKGV4cG9ydHMpIHsKICAndXNlIHN0cmljdCc7CgogIGZ1bmN0aW9uIF90b0NvbnN1bWFibGVBcnJheShhcnIpIHsKICAgIHJldHVybiBfYXJyYXlXaXRob3V0SG9sZXMoYXJyKSB8fCBfaXRlcmFibGVUb0FycmF5KGFycikgfHwgX3Vuc3VwcG9ydGVkSXRlcmFibGVUb0FycmF5KGFycikgfHwgX25vbkl0ZXJhYmxlU3ByZWFkKCk7CiAgfQoKICBmdW5jdGlvbiBfYXJyYXlXaXRob3V0SG9sZXMoYXJyKSB7CiAgICBpZiAoQXJyYXkuaXNBcnJheShhcnIpKSByZXR1cm4gX2FycmF5TGlrZVRvQXJyYXkoYXJyKTsKICB9CgogIGZ1bmN0aW9uIF9pdGVyYWJsZVRvQXJyYXkoaXRlcikgewogICAgaWYgKHR5cGVvZiBTeW1ib2wgIT09ICJ1bmRlZmluZWQiICYmIGl0ZXJbU3ltYm9sLml0ZXJhdG9yXSAhPSBudWxsIHx8IGl0ZXJbIkBAaXRlcmF0b3IiXSAhPSBudWxsKSByZXR1cm4gQXJyYXkuZnJvbShpdGVyKTsKICB9CgogIGZ1bmN0aW9uIF91bnN1cHBvcnRlZEl0ZXJhYmxlVG9BcnJheShvLCBtaW5MZW4pIHsKICAgIGlmICghbykgcmV0dXJuOwogICAgaWYgKHR5cGVvZiBvID09PSAic3RyaW5nIikgcmV0dXJuIF9hcnJheUxpa2VUb0FycmF5KG8sIG1pbkxlbik7CiAgICB2YXIgbiA9IE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChvKS5zbGljZSg4LCAtMSk7CiAgICBpZiAobiA9PT0gIk9iamVjdCIgJiYgby5jb25zdHJ1Y3RvcikgbiA9IG8uY29uc3RydWN0b3IubmFtZTsKICAgIGlmIChuID09PSAiTWFwIiB8fCBuID09PSAiU2V0IikgcmV0dXJuIEFycmF5LmZyb20obyk7CiAgICBpZiAobiA9PT0gIkFyZ3VtZW50cyIgfHwgL14oPzpVaXxJKW50KD86OHwxNnwzMikoPzpDbGFtcGVkKT9BcnJheSQvLnRlc3QobikpIHJldHVybiBfYXJyYXlMaWtlVG9BcnJheShvLCBtaW5MZW4pOwogIH0KCiAgZnVuY3Rpb24gX2FycmF5TGlrZVRvQXJyYXkoYXJyLCBsZW4pIHsKICAgIGlmIChsZW4gPT0gbnVsbCB8fCBsZW4gPiBhcnIubGVuZ3RoKSBsZW4gPSBhcnIubGVuZ3RoOwoKICAgIGZvciAodmFyIGkgPSAwLCBhcnIyID0gbmV3IEFycmF5KGxlbik7IGkgPCBsZW47IGkrKykgYXJyMltpXSA9IGFycltpXTsKCiAgICByZXR1cm4gYXJyMjsKICB9CgogIGZ1bmN0aW9uIF9ub25JdGVyYWJsZVNwcmVhZCgpIHsKICAgIHRocm93IG5ldyBUeXBlRXJyb3IoIkludmFsaWQgYXR0ZW1wdCB0byBzcHJlYWQgbm9uLWl0ZXJhYmxlIGluc3RhbmNlLlxuSW4gb3JkZXIgdG8gYmUgaXRlcmFibGUsIG5vbi1hcnJheSBvYmplY3RzIG11c3QgaGF2ZSBhIFtTeW1ib2wuaXRlcmF0b3JdKCkgbWV0aG9kLiIpOwogIH0KCiAgLy8gV2Ugc2hvdWxkIHNhdmUgdGhlc2UKICAvL2NvbnN0IGNhbnZhcyA9IG5ldyBPZmZzY3JlZW5DYW52YXMoMjU2LCAyNTYpOwogIC8vY29uc3QgY3R4ID0gY2FudmFzLmdldENvbnRleHQoIjJkIik7CiAgZnVuY3Rpb24gbWFwYm94VGVycmFpblRvR3JpZChwbmcsIGludGVydmFsLCBvZmZzZXQpIHsKICAgIHZhciBfaW50ZXJ2YWwsIF9vZmZzZXQ7CgogICAgLy8gbWF5YmUgd2Ugc2hvdWxkIGRvIHRoaXMgb24gdGhlIEdQVSB1c2luZyBSRUdMPwogICAgLy8gYnV0IHRoYXQgd291bGQgcmVxdWlyZSBHUFUgLT4gQ1BVIC0+IEdQVQogICAgdmFyIGdyaWRTaXplID0gcG5nLnNoYXBlWzBdICsgMTsKICAgIHZhciB0ZXJyYWluID0gbmV3IEZsb2F0MzJBcnJheShncmlkU2l6ZSAqIGdyaWRTaXplKTsKICAgIHZhciB0aWxlU2l6ZSA9IHBuZy5zaGFwZVswXTsKICAgIGludGVydmFsID0gKF9pbnRlcnZhbCA9IGludGVydmFsKSAhPT0gbnVsbCAmJiBfaW50ZXJ2YWwgIT09IHZvaWQgMCA/IF9pbnRlcnZhbCA6IDAuMTsKICAgIG9mZnNldCA9IChfb2Zmc2V0ID0gb2Zmc2V0KSAhPT0gbnVsbCAmJiBfb2Zmc2V0ICE9PSB2b2lkIDAgPyBfb2Zmc2V0IDogLTEwMDAwOyAvLyBkZWNvZGUgdGVycmFpbiB2YWx1ZXMKCiAgICBmb3IgKHZhciB5ID0gMDsgeSA8IHRpbGVTaXplOyB5KyspIHsKICAgICAgZm9yICh2YXIgeCA9IDA7IHggPCB0aWxlU2l6ZTsgeCsrKSB7CiAgICAgICAgdmFyIHljID0geTsKICAgICAgICB2YXIgciA9IHBuZy5nZXQoeCwgeWMsIDApOwogICAgICAgIHZhciBnID0gcG5nLmdldCh4LCB5YywgMSk7CiAgICAgICAgdmFyIGIgPSBwbmcuZ2V0KHgsIHljLCAyKTsKICAgICAgICB0ZXJyYWluW3kgKiBncmlkU2l6ZSArIHhdID0gciAqIDI1NiAqIDI1NiAqIGludGVydmFsICsgZyAqIDI1Ni4wICogaW50ZXJ2YWwgKyBiICogaW50ZXJ2YWwgKyBvZmZzZXQ7CiAgICAgIH0KICAgIH0gLy8gYmFja2ZpbGwgcmlnaHQgYW5kIGJvdHRvbSBib3JkZXJzCgoKICAgIGZvciAodmFyIF94ID0gMDsgX3ggPCBncmlkU2l6ZSAtIDE7IF94KyspIHsKICAgICAgdGVycmFpbltncmlkU2l6ZSAqIChncmlkU2l6ZSAtIDEpICsgX3hdID0gdGVycmFpbltncmlkU2l6ZSAqIChncmlkU2l6ZSAtIDIpICsgX3hdOwogICAgfQoKICAgIGZvciAodmFyIF95ID0gMDsgX3kgPCBncmlkU2l6ZTsgX3krKykgewogICAgICB0ZXJyYWluW2dyaWRTaXplICogX3kgKyBncmlkU2l6ZSAtIDFdID0gdGVycmFpbltncmlkU2l6ZSAqIF95ICsgZ3JpZFNpemUgLSAyXTsKICAgIH0KCiAgICByZXR1cm4gdGVycmFpbjsKICB9CgogIGZ1bmN0aW9uIGNyZWF0ZVF1YW50aXplZE1lc2hEYXRhKHRpbGUsIG1lc2gsIHRpbGVTaXplKSB7CiAgICB2YXIgeHZhbHMgPSBbXTsKICAgIHZhciB5dmFscyA9IFtdOwogICAgdmFyIGhlaWdodE1ldGVycyA9IFtdOwogICAgdmFyIG5vcnRoSW5kaWNlcyA9IFtdOwogICAgdmFyIHNvdXRoSW5kaWNlcyA9IFtdOwogICAgdmFyIGVhc3RJbmRpY2VzID0gW107CiAgICB2YXIgd2VzdEluZGljZXMgPSBbXTsKICAgIHZhciBtaW5pbXVtSGVpZ2h0ID0gSW5maW5pdHk7CiAgICB2YXIgbWF4aW11bUhlaWdodCA9IC1JbmZpbml0eTsKICAgIHZhciBzY2FsYXIgPSAzMjc2OC4wIC8gdGlsZVNpemU7CgogICAgZm9yICh2YXIgaXggPSAwOyBpeCA8IG1lc2gudmVydGljZXMubGVuZ3RoIC8gMjsgaXgrKykgewogICAgICB2YXIgdmVydGV4SXggPSBpeDsKICAgICAgdmFyIHB4ID0gbWVzaC52ZXJ0aWNlc1tpeCAqIDJdOwogICAgICB2YXIgcHkgPSBtZXNoLnZlcnRpY2VzW2l4ICogMiArIDFdOwogICAgICB2YXIgaGVpZ2h0ID0gdGlsZS50ZXJyYWluW3B5ICogKHRpbGVTaXplICsgMSkgKyBweF07CiAgICAgIGlmIChoZWlnaHQgPiBtYXhpbXVtSGVpZ2h0KSBtYXhpbXVtSGVpZ2h0ID0gaGVpZ2h0OwogICAgICBpZiAoaGVpZ2h0IDwgbWluaW11bUhlaWdodCkgbWluaW11bUhlaWdodCA9IGhlaWdodDsKICAgICAgaGVpZ2h0TWV0ZXJzLnB1c2goaGVpZ2h0KTsKICAgICAgaWYgKHB5ID09IDApIG5vcnRoSW5kaWNlcy5wdXNoKHZlcnRleEl4KTsKICAgICAgaWYgKHB5ID09IHRpbGVTaXplKSBzb3V0aEluZGljZXMucHVzaCh2ZXJ0ZXhJeCk7CiAgICAgIGlmIChweCA9PSAwKSB3ZXN0SW5kaWNlcy5wdXNoKHZlcnRleEl4KTsKICAgICAgaWYgKHB4ID09IHRpbGVTaXplKSBlYXN0SW5kaWNlcy5wdXNoKHZlcnRleEl4KTsKICAgICAgdmFyIHh2ID0gcHggKiBzY2FsYXI7CiAgICAgIHZhciB5diA9ICh0aWxlU2l6ZSAtIHB5KSAqIHNjYWxhcjsKICAgICAgeHZhbHMucHVzaCh4dik7CiAgICAgIHl2YWxzLnB1c2goeXYpOwogICAgfQoKICAgIHZhciBoZWlnaHRSYW5nZSA9IG1heGltdW1IZWlnaHQgLSBtaW5pbXVtSGVpZ2h0OwogICAgdmFyIGhlaWdodHMgPSBoZWlnaHRNZXRlcnMubWFwKGZ1bmN0aW9uIChkKSB7CiAgICAgIGlmIChoZWlnaHRSYW5nZSA8IDEpIHJldHVybiAwOwogICAgICByZXR1cm4gKGQgLSBtaW5pbXVtSGVpZ2h0KSAqICgzMjc2Ny4wIC8gaGVpZ2h0UmFuZ2UpOwogICAgfSk7CiAgICB2YXIgdHJpYW5nbGVzID0gbmV3IFVpbnQxNkFycmF5KG1lc2gudHJpYW5nbGVzKTsKICAgIHZhciBxdWFudGl6ZWRWZXJ0aWNlcyA9IG5ldyBVaW50MTZBcnJheSggLy92ZXJ0cwogICAgW10uY29uY2F0KHh2YWxzLCB5dmFscywgX3RvQ29uc3VtYWJsZUFycmF5KGhlaWdodHMpKSk7IC8vIFNFIE5XIE5FCiAgICAvLyBORSBOVyBTRQoKICAgIHJldHVybiB7CiAgICAgIG1pbmltdW1IZWlnaHQ6IG1pbmltdW1IZWlnaHQsCiAgICAgIG1heGltdW1IZWlnaHQ6IG1heGltdW1IZWlnaHQsCiAgICAgIHF1YW50aXplZFZlcnRpY2VzOiBxdWFudGl6ZWRWZXJ0aWNlcywKICAgICAgaW5kaWNlczogdHJpYW5nbGVzLAogICAgICB3ZXN0SW5kaWNlczogd2VzdEluZGljZXMsCiAgICAgIHNvdXRoSW5kaWNlczogc291dGhJbmRpY2VzLAogICAgICBlYXN0SW5kaWNlczogZWFzdEluZGljZXMsCiAgICAgIG5vcnRoSW5kaWNlczogbm9ydGhJbmRpY2VzCiAgICB9OwogIH0KCiAgZnVuY3Rpb24gaW90YShuKSB7CiAgICB2YXIgcmVzdWx0ID0gbmV3IEFycmF5KG4pOwogICAgZm9yKHZhciBpPTA7IGk8bjsgKytpKSB7CiAgICAgIHJlc3VsdFtpXSA9IGk7CiAgICB9CiAgICByZXR1cm4gcmVzdWx0CiAgfQoKICB2YXIgaW90YV8xID0gaW90YTsKCiAgLyohCiAgICogRGV0ZXJtaW5lIGlmIGFuIG9iamVjdCBpcyBhIEJ1ZmZlcgogICAqCiAgICogQGF1dGhvciAgIEZlcm9zcyBBYm91a2hhZGlqZWggPGh0dHBzOi8vZmVyb3NzLm9yZz4KICAgKiBAbGljZW5zZSAgTUlUCiAgICovCiAgLy8gVGhlIF9pc0J1ZmZlciBjaGVjayBpcyBmb3IgU2FmYXJpIDUtNyBzdXBwb3J0LCBiZWNhdXNlIGl0J3MgbWlzc2luZwogIC8vIE9iamVjdC5wcm90b3R5cGUuY29uc3RydWN0b3IuIFJlbW92ZSB0aGlzIGV2ZW50dWFsbHkKICB2YXIgaXNCdWZmZXJfMSA9IGZ1bmN0aW9uIChvYmopIHsKICAgIHJldHVybiBvYmogIT0gbnVsbCAmJiAoaXNCdWZmZXIob2JqKSB8fCBpc1Nsb3dCdWZmZXIob2JqKSB8fCAhIW9iai5faXNCdWZmZXIpCiAgfTsKCiAgZnVuY3Rpb24gaXNCdWZmZXIgKG9iaikgewogICAgcmV0dXJuICEhb2JqLmNvbnN0cnVjdG9yICYmIHR5cGVvZiBvYmouY29uc3RydWN0b3IuaXNCdWZmZXIgPT09ICdmdW5jdGlvbicgJiYgb2JqLmNvbnN0cnVjdG9yLmlzQnVmZmVyKG9iaikKICB9CgogIC8vIEZvciBOb2RlIHYwLjEwIHN1cHBvcnQuIFJlbW92ZSB0aGlzIGV2ZW50dWFsbHkuCiAgZnVuY3Rpb24gaXNTbG93QnVmZmVyIChvYmopIHsKICAgIHJldHVybiB0eXBlb2Ygb2JqLnJlYWRGbG9hdExFID09PSAnZnVuY3Rpb24nICYmIHR5cGVvZiBvYmouc2xpY2UgPT09ICdmdW5jdGlvbicgJiYgaXNCdWZmZXIob2JqLnNsaWNlKDAsIDApKQogIH0KCiAgdmFyIGhhc1R5cGVkQXJyYXlzICA9ICgodHlwZW9mIEZsb2F0NjRBcnJheSkgIT09ICJ1bmRlZmluZWQiKTsKCiAgZnVuY3Rpb24gY29tcGFyZTFzdChhLCBiKSB7CiAgICByZXR1cm4gYVswXSAtIGJbMF0KICB9CgogIGZ1bmN0aW9uIG9yZGVyKCkgewogICAgdmFyIHN0cmlkZSA9IHRoaXMuc3RyaWRlOwogICAgdmFyIHRlcm1zID0gbmV3IEFycmF5KHN0cmlkZS5sZW5ndGgpOwogICAgdmFyIGk7CiAgICBmb3IoaT0wOyBpPHRlcm1zLmxlbmd0aDsgKytpKSB7CiAgICAgIHRlcm1zW2ldID0gW01hdGguYWJzKHN0cmlkZVtpXSksIGldOwogICAgfQogICAgdGVybXMuc29ydChjb21wYXJlMXN0KTsKICAgIHZhciByZXN1bHQgPSBuZXcgQXJyYXkodGVybXMubGVuZ3RoKTsKICAgIGZvcihpPTA7IGk8cmVzdWx0Lmxlbmd0aDsgKytpKSB7CiAgICAgIHJlc3VsdFtpXSA9IHRlcm1zW2ldWzFdOwogICAgfQogICAgcmV0dXJuIHJlc3VsdAogIH0KCiAgZnVuY3Rpb24gY29tcGlsZUNvbnN0cnVjdG9yKGR0eXBlLCBkaW1lbnNpb24pIHsKICAgIHZhciBjbGFzc05hbWUgPSBbIlZpZXciLCBkaW1lbnNpb24sICJkIiwgZHR5cGVdLmpvaW4oIiIpOwogICAgaWYoZGltZW5zaW9uIDwgMCkgewogICAgICBjbGFzc05hbWUgPSAiVmlld19OaWwiICsgZHR5cGU7CiAgICB9CiAgICB2YXIgdXNlR2V0dGVycyA9IChkdHlwZSA9PT0gImdlbmVyaWMiKTsKCiAgICBpZihkaW1lbnNpb24gPT09IC0xKSB7CiAgICAgIC8vU3BlY2lhbCBjYXNlIGZvciB0cml2aWFsIGFycmF5cwogICAgICB2YXIgY29kZSA9CiAgICAgICAgImZ1bmN0aW9uICIrY2xhc3NOYW1lKyIoYSl7dGhpcy5kYXRhPWE7fTtcCnZhciBwcm90bz0iK2NsYXNzTmFtZSsiLnByb3RvdHlwZTtcCnByb3RvLmR0eXBlPSciK2R0eXBlKyInO1wKcHJvdG8uaW5kZXg9ZnVuY3Rpb24oKXtyZXR1cm4gLTF9O1wKcHJvdG8uc2l6ZT0wO1wKcHJvdG8uZGltZW5zaW9uPS0xO1wKcHJvdG8uc2hhcGU9cHJvdG8uc3RyaWRlPXByb3RvLm9yZGVyPVtdO1wKcHJvdG8ubG89cHJvdG8uaGk9cHJvdG8udHJhbnNwb3NlPXByb3RvLnN0ZXA9XApmdW5jdGlvbigpe3JldHVybiBuZXcgIitjbGFzc05hbWUrIih0aGlzLmRhdGEpO307XApwcm90by5nZXQ9cHJvdG8uc2V0PWZ1bmN0aW9uKCl7fTtcCnByb3RvLnBpY2s9ZnVuY3Rpb24oKXtyZXR1cm4gbnVsbH07XApyZXR1cm4gZnVuY3Rpb24gY29uc3RydWN0XyIrY2xhc3NOYW1lKyIoYSl7cmV0dXJuIG5ldyAiK2NsYXNzTmFtZSsiKGEpO30iOwogICAgICB2YXIgcHJvY2VkdXJlID0gbmV3IEZ1bmN0aW9uKGNvZGUpOwogICAgICByZXR1cm4gcHJvY2VkdXJlKCkKICAgIH0gZWxzZSBpZihkaW1lbnNpb24gPT09IDApIHsKICAgICAgLy9TcGVjaWFsIGNhc2UgZm9yIDBkIGFycmF5cwogICAgICB2YXIgY29kZSA9CiAgICAgICAgImZ1bmN0aW9uICIrY2xhc3NOYW1lKyIoYSxkKSB7XAp0aGlzLmRhdGEgPSBhO1wKdGhpcy5vZmZzZXQgPSBkXAp9O1wKdmFyIHByb3RvPSIrY2xhc3NOYW1lKyIucHJvdG90eXBlO1wKcHJvdG8uZHR5cGU9JyIrZHR5cGUrIic7XApwcm90by5pbmRleD1mdW5jdGlvbigpe3JldHVybiB0aGlzLm9mZnNldH07XApwcm90by5kaW1lbnNpb249MDtcCnByb3RvLnNpemU9MTtcCnByb3RvLnNoYXBlPVwKcHJvdG8uc3RyaWRlPVwKcHJvdG8ub3JkZXI9W107XApwcm90by5sbz1cCnByb3RvLmhpPVwKcHJvdG8udHJhbnNwb3NlPVwKcHJvdG8uc3RlcD1mdW5jdGlvbiAiK2NsYXNzTmFtZSsiX2NvcHkoKSB7XApyZXR1cm4gbmV3ICIrY2xhc3NOYW1lKyIodGhpcy5kYXRhLHRoaXMub2Zmc2V0KVwKfTtcCnByb3RvLnBpY2s9ZnVuY3Rpb24gIitjbGFzc05hbWUrIl9waWNrKCl7XApyZXR1cm4gVHJpdmlhbEFycmF5KHRoaXMuZGF0YSk7XAp9O1wKcHJvdG8udmFsdWVPZj1wcm90by5nZXQ9ZnVuY3Rpb24gIitjbGFzc05hbWUrIl9nZXQoKXtcCnJldHVybiAiKyh1c2VHZXR0ZXJzID8gInRoaXMuZGF0YS5nZXQodGhpcy5vZmZzZXQpIiA6ICJ0aGlzLmRhdGFbdGhpcy5vZmZzZXRdIikrCiAgIn07XApwcm90by5zZXQ9ZnVuY3Rpb24gIitjbGFzc05hbWUrIl9zZXQodil7XApyZXR1cm4gIisodXNlR2V0dGVycyA/ICJ0aGlzLmRhdGEuc2V0KHRoaXMub2Zmc2V0LHYpIiA6ICJ0aGlzLmRhdGFbdGhpcy5vZmZzZXRdPXYiKSsiXAp9O1wKcmV0dXJuIGZ1bmN0aW9uIGNvbnN0cnVjdF8iK2NsYXNzTmFtZSsiKGEsYixjLGQpe3JldHVybiBuZXcgIitjbGFzc05hbWUrIihhLGQpfSI7CiAgICAgIHZhciBwcm9jZWR1cmUgPSBuZXcgRnVuY3Rpb24oIlRyaXZpYWxBcnJheSIsIGNvZGUpOwogICAgICByZXR1cm4gcHJvY2VkdXJlKENBQ0hFRF9DT05TVFJVQ1RPUlNbZHR5cGVdWzBdKQogICAgfQoKICAgIHZhciBjb2RlID0gWyIndXNlIHN0cmljdCciXTsKCiAgICAvL0NyZWF0ZSBjb25zdHJ1Y3RvciBmb3IgdmlldwogICAgdmFyIGluZGljZXMgPSBpb3RhXzEoZGltZW5zaW9uKTsKICAgIHZhciBhcmdzID0gaW5kaWNlcy5tYXAoZnVuY3Rpb24oaSkgeyByZXR1cm4gImkiK2kgfSk7CiAgICB2YXIgaW5kZXhfc3RyID0gInRoaXMub2Zmc2V0KyIgKyBpbmRpY2VzLm1hcChmdW5jdGlvbihpKSB7CiAgICAgICAgICByZXR1cm4gInRoaXMuc3RyaWRlWyIgKyBpICsgIl0qaSIgKyBpCiAgICAgICAgfSkuam9pbigiKyIpOwogICAgdmFyIHNoYXBlQXJnID0gaW5kaWNlcy5tYXAoZnVuY3Rpb24oaSkgewogICAgICAgIHJldHVybiAiYiIraQogICAgICB9KS5qb2luKCIsIik7CiAgICB2YXIgc3RyaWRlQXJnID0gaW5kaWNlcy5tYXAoZnVuY3Rpb24oaSkgewogICAgICAgIHJldHVybiAiYyIraQogICAgICB9KS5qb2luKCIsIik7CiAgICBjb2RlLnB1c2goCiAgICAgICJmdW5jdGlvbiAiK2NsYXNzTmFtZSsiKGEsIiArIHNoYXBlQXJnICsgIiwiICsgc3RyaWRlQXJnICsgIixkKXt0aGlzLmRhdGE9YSIsCiAgICAgICAgInRoaXMuc2hhcGU9WyIgKyBzaGFwZUFyZyArICJdIiwKICAgICAgICAidGhpcy5zdHJpZGU9WyIgKyBzdHJpZGVBcmcgKyAiXSIsCiAgICAgICAgInRoaXMub2Zmc2V0PWR8MH0iLAogICAgICAidmFyIHByb3RvPSIrY2xhc3NOYW1lKyIucHJvdG90eXBlIiwKICAgICAgInByb3RvLmR0eXBlPSciK2R0eXBlKyInIiwKICAgICAgInByb3RvLmRpbWVuc2lvbj0iK2RpbWVuc2lvbik7CgogICAgLy92aWV3LnNpemU6CiAgICBjb2RlLnB1c2goIk9iamVjdC5kZWZpbmVQcm9wZXJ0eShwcm90bywnc2l6ZScse2dldDpmdW5jdGlvbiAiK2NsYXNzTmFtZSsiX3NpemUoKXtcCnJldHVybiAiK2luZGljZXMubWFwKGZ1bmN0aW9uKGkpIHsgcmV0dXJuICJ0aGlzLnNoYXBlWyIraSsiXSIgfSkuam9pbigiKiIpLAogICJ9fSkiKTsKCiAgICAvL3ZpZXcub3JkZXI6CiAgICBpZihkaW1lbnNpb24gPT09IDEpIHsKICAgICAgY29kZS5wdXNoKCJwcm90by5vcmRlcj1bMF0iKTsKICAgIH0gZWxzZSB7CiAgICAgIGNvZGUucHVzaCgiT2JqZWN0LmRlZmluZVByb3BlcnR5KHByb3RvLCdvcmRlcicse2dldDoiKTsKICAgICAgaWYoZGltZW5zaW9uIDwgNCkgewogICAgICAgIGNvZGUucHVzaCgiZnVuY3Rpb24gIitjbGFzc05hbWUrIl9vcmRlcigpeyIpOwogICAgICAgIGlmKGRpbWVuc2lvbiA9PT0gMikgewogICAgICAgICAgY29kZS5wdXNoKCJyZXR1cm4gKE1hdGguYWJzKHRoaXMuc3RyaWRlWzBdKT5NYXRoLmFicyh0aGlzLnN0cmlkZVsxXSkpP1sxLDBdOlswLDFdfX0pIik7CiAgICAgICAgfSBlbHNlIGlmKGRpbWVuc2lvbiA9PT0gMykgewogICAgICAgICAgY29kZS5wdXNoKAogICJ2YXIgczA9TWF0aC5hYnModGhpcy5zdHJpZGVbMF0pLHMxPU1hdGguYWJzKHRoaXMuc3RyaWRlWzFdKSxzMj1NYXRoLmFicyh0aGlzLnN0cmlkZVsyXSk7XAppZihzMD5zMSl7XAppZihzMT5zMil7XApyZXR1cm4gWzIsMSwwXTtcCn1lbHNlIGlmKHMwPnMyKXtcCnJldHVybiBbMSwyLDBdO1wKfWVsc2V7XApyZXR1cm4gWzEsMCwyXTtcCn1cCn1lbHNlIGlmKHMwPnMyKXtcCnJldHVybiBbMiwwLDFdO1wKfWVsc2UgaWYoczI+czEpe1wKcmV0dXJuIFswLDEsMl07XAp9ZWxzZXtcCnJldHVybiBbMCwyLDFdO1wKfX19KSIpOwogICAgICAgIH0KICAgICAgfSBlbHNlIHsKICAgICAgICBjb2RlLnB1c2goIk9SREVSfSkiKTsKICAgICAgfQogICAgfQoKICAgIC8vdmlldy5zZXQoaTAsIC4uLiwgdik6CiAgICBjb2RlLnB1c2goCiAgInByb3RvLnNldD1mdW5jdGlvbiAiK2NsYXNzTmFtZSsiX3NldCgiK2FyZ3Muam9pbigiLCIpKyIsdil7Iik7CiAgICBpZih1c2VHZXR0ZXJzKSB7CiAgICAgIGNvZGUucHVzaCgicmV0dXJuIHRoaXMuZGF0YS5zZXQoIitpbmRleF9zdHIrIix2KX0iKTsKICAgIH0gZWxzZSB7CiAgICAgIGNvZGUucHVzaCgicmV0dXJuIHRoaXMuZGF0YVsiK2luZGV4X3N0cisiXT12fSIpOwogICAgfQoKICAgIC8vdmlldy5nZXQoaTAsIC4uLik6CiAgICBjb2RlLnB1c2goInByb3RvLmdldD1mdW5jdGlvbiAiK2NsYXNzTmFtZSsiX2dldCgiK2FyZ3Muam9pbigiLCIpKyIpeyIpOwogICAgaWYodXNlR2V0dGVycykgewogICAgICBjb2RlLnB1c2goInJldHVybiB0aGlzLmRhdGEuZ2V0KCIraW5kZXhfc3RyKyIpfSIpOwogICAgfSBlbHNlIHsKICAgICAgY29kZS5wdXNoKCJyZXR1cm4gdGhpcy5kYXRhWyIraW5kZXhfc3RyKyJdfSIpOwogICAgfQoKICAgIC8vdmlldy5pbmRleDoKICAgIGNvZGUucHVzaCgKICAgICAgInByb3RvLmluZGV4PWZ1bmN0aW9uICIrY2xhc3NOYW1lKyJfaW5kZXgoIiwgYXJncy5qb2luKCksICIpe3JldHVybiAiK2luZGV4X3N0cisifSIpOwoKICAgIC8vdmlldy5oaSgpOgogICAgY29kZS5wdXNoKCJwcm90by5oaT1mdW5jdGlvbiAiK2NsYXNzTmFtZSsiX2hpKCIrYXJncy5qb2luKCIsIikrIil7cmV0dXJuIG5ldyAiK2NsYXNzTmFtZSsiKHRoaXMuZGF0YSwiKwogICAgICBpbmRpY2VzLm1hcChmdW5jdGlvbihpKSB7CiAgICAgICAgcmV0dXJuIFsiKHR5cGVvZiBpIixpLCIhPT0nbnVtYmVyJ3x8aSIsaSwiPDApP3RoaXMuc2hhcGVbIiwgaSwgIl06aSIsIGksInwwIl0uam9pbigiIikKICAgICAgfSkuam9pbigiLCIpKyIsIisKICAgICAgaW5kaWNlcy5tYXAoZnVuY3Rpb24oaSkgewogICAgICAgIHJldHVybiAidGhpcy5zdHJpZGVbIitpICsgIl0iCiAgICAgIH0pLmpvaW4oIiwiKSsiLHRoaXMub2Zmc2V0KX0iKTsKCiAgICAvL3ZpZXcubG8oKToKICAgIHZhciBhX3ZhcnMgPSBpbmRpY2VzLm1hcChmdW5jdGlvbihpKSB7IHJldHVybiAiYSIraSsiPXRoaXMuc2hhcGVbIitpKyJdIiB9KTsKICAgIHZhciBjX3ZhcnMgPSBpbmRpY2VzLm1hcChmdW5jdGlvbihpKSB7IHJldHVybiAiYyIraSsiPXRoaXMuc3RyaWRlWyIraSsiXSIgfSk7CiAgICBjb2RlLnB1c2goInByb3RvLmxvPWZ1bmN0aW9uICIrY2xhc3NOYW1lKyJfbG8oIithcmdzLmpvaW4oIiwiKSsiKXt2YXIgYj10aGlzLm9mZnNldCxkPTAsIithX3ZhcnMuam9pbigiLCIpKyIsIitjX3ZhcnMuam9pbigiLCIpKTsKICAgIGZvcih2YXIgaT0wOyBpPGRpbWVuc2lvbjsgKytpKSB7CiAgICAgIGNvZGUucHVzaCgKICAiaWYodHlwZW9mIGkiK2krIj09PSdudW1iZXInJiZpIitpKyI+PTApe1wKZD1pIitpKyJ8MDtcCmIrPWMiK2krIipkO1wKYSIraSsiLT1kfSIpOwogICAgfQogICAgY29kZS5wdXNoKCJyZXR1cm4gbmV3ICIrY2xhc3NOYW1lKyIodGhpcy5kYXRhLCIrCiAgICAgIGluZGljZXMubWFwKGZ1bmN0aW9uKGkpIHsKICAgICAgICByZXR1cm4gImEiK2kKICAgICAgfSkuam9pbigiLCIpKyIsIisKICAgICAgaW5kaWNlcy5tYXAoZnVuY3Rpb24oaSkgewogICAgICAgIHJldHVybiAiYyIraQogICAgICB9KS5qb2luKCIsIikrIixiKX0iKTsKCiAgICAvL3ZpZXcuc3RlcCgpOgogICAgY29kZS5wdXNoKCJwcm90by5zdGVwPWZ1bmN0aW9uICIrY2xhc3NOYW1lKyJfc3RlcCgiK2FyZ3Muam9pbigiLCIpKyIpe3ZhciAiKwogICAgICBpbmRpY2VzLm1hcChmdW5jdGlvbihpKSB7CiAgICAgICAgcmV0dXJuICJhIitpKyI9dGhpcy5zaGFwZVsiK2krIl0iCiAgICAgIH0pLmpvaW4oIiwiKSsiLCIrCiAgICAgIGluZGljZXMubWFwKGZ1bmN0aW9uKGkpIHsKICAgICAgICByZXR1cm4gImIiK2krIj10aGlzLnN0cmlkZVsiK2krIl0iCiAgICAgIH0pLmpvaW4oIiwiKSsiLGM9dGhpcy5vZmZzZXQsZD0wLGNlaWw9TWF0aC5jZWlsIik7CiAgICBmb3IodmFyIGk9MDsgaTxkaW1lbnNpb247ICsraSkgewogICAgICBjb2RlLnB1c2goCiAgImlmKHR5cGVvZiBpIitpKyI9PT0nbnVtYmVyJyl7XApkPWkiK2krInwwO1wKaWYoZDwwKXtcCmMrPWIiK2krIiooYSIraSsiLTEpO1wKYSIraSsiPWNlaWwoLWEiK2krIi9kKVwKfWVsc2V7XAphIitpKyI9Y2VpbChhIitpKyIvZClcCn1cCmIiK2krIio9ZFwKfSIpOwogICAgfQogICAgY29kZS5wdXNoKCJyZXR1cm4gbmV3ICIrY2xhc3NOYW1lKyIodGhpcy5kYXRhLCIrCiAgICAgIGluZGljZXMubWFwKGZ1bmN0aW9uKGkpIHsKICAgICAgICByZXR1cm4gImEiICsgaQogICAgICB9KS5qb2luKCIsIikrIiwiKwogICAgICBpbmRpY2VzLm1hcChmdW5jdGlvbihpKSB7CiAgICAgICAgcmV0dXJuICJiIiArIGkKICAgICAgfSkuam9pbigiLCIpKyIsYyl9Iik7CgogICAgLy92aWV3LnRyYW5zcG9zZSgpOgogICAgdmFyIHRTaGFwZSA9IG5ldyBBcnJheShkaW1lbnNpb24pOwogICAgdmFyIHRTdHJpZGUgPSBuZXcgQXJyYXkoZGltZW5zaW9uKTsKICAgIGZvcih2YXIgaT0wOyBpPGRpbWVuc2lvbjsgKytpKSB7CiAgICAgIHRTaGFwZVtpXSA9ICJhW2kiK2krIl0iOwogICAgICB0U3RyaWRlW2ldID0gImJbaSIraSsiXSI7CiAgICB9CiAgICBjb2RlLnB1c2goInByb3RvLnRyYW5zcG9zZT1mdW5jdGlvbiAiK2NsYXNzTmFtZSsiX3RyYW5zcG9zZSgiK2FyZ3MrIil7IisKICAgICAgYXJncy5tYXAoZnVuY3Rpb24obixpZHgpIHsgcmV0dXJuIG4gKyAiPSgiICsgbiArICI9PT11bmRlZmluZWQ/IiArIGlkeCArICI6IiArIG4gKyAifDApIn0pLmpvaW4oIjsiKSwKICAgICAgInZhciBhPXRoaXMuc2hhcGUsYj10aGlzLnN0cmlkZTtyZXR1cm4gbmV3ICIrY2xhc3NOYW1lKyIodGhpcy5kYXRhLCIrdFNoYXBlLmpvaW4oIiwiKSsiLCIrdFN0cmlkZS5qb2luKCIsIikrIix0aGlzLm9mZnNldCl9Iik7CgogICAgLy92aWV3LnBpY2soKToKICAgIGNvZGUucHVzaCgicHJvdG8ucGljaz1mdW5jdGlvbiAiK2NsYXNzTmFtZSsiX3BpY2soIithcmdzKyIpe3ZhciBhPVtdLGI9W10sYz10aGlzLm9mZnNldCIpOwogICAgZm9yKHZhciBpPTA7IGk8ZGltZW5zaW9uOyArK2kpIHsKICAgICAgY29kZS5wdXNoKCJpZih0eXBlb2YgaSIraSsiPT09J251bWJlcicmJmkiK2krIj49MCl7Yz0oYyt0aGlzLnN0cmlkZVsiK2krIl0qaSIraSsiKXwwfWVsc2V7YS5wdXNoKHRoaXMuc2hhcGVbIitpKyJdKTtiLnB1c2godGhpcy5zdHJpZGVbIitpKyJdKX0iKTsKICAgIH0KICAgIGNvZGUucHVzaCgidmFyIGN0b3I9Q1RPUl9MSVNUW2EubGVuZ3RoKzFdO3JldHVybiBjdG9yKHRoaXMuZGF0YSxhLGIsYyl9Iik7CgogICAgLy9BZGQgcmV0dXJuIHN0YXRlbWVudAogICAgY29kZS5wdXNoKCJyZXR1cm4gZnVuY3Rpb24gY29uc3RydWN0XyIrY2xhc3NOYW1lKyIoZGF0YSxzaGFwZSxzdHJpZGUsb2Zmc2V0KXtyZXR1cm4gbmV3ICIrY2xhc3NOYW1lKyIoZGF0YSwiKwogICAgICBpbmRpY2VzLm1hcChmdW5jdGlvbihpKSB7CiAgICAgICAgcmV0dXJuICJzaGFwZVsiK2krIl0iCiAgICAgIH0pLmpvaW4oIiwiKSsiLCIrCiAgICAgIGluZGljZXMubWFwKGZ1bmN0aW9uKGkpIHsKICAgICAgICByZXR1cm4gInN0cmlkZVsiK2krIl0iCiAgICAgIH0pLmpvaW4oIiwiKSsiLG9mZnNldCl9Iik7CgogICAgLy9Db21waWxlIHByb2NlZHVyZQogICAgdmFyIHByb2NlZHVyZSA9IG5ldyBGdW5jdGlvbigiQ1RPUl9MSVNUIiwgIk9SREVSIiwgY29kZS5qb2luKCJcbiIpKTsKICAgIHJldHVybiBwcm9jZWR1cmUoQ0FDSEVEX0NPTlNUUlVDVE9SU1tkdHlwZV0sIG9yZGVyKQogIH0KCiAgZnVuY3Rpb24gYXJyYXlEVHlwZShkYXRhKSB7CiAgICBpZihpc0J1ZmZlcl8xKGRhdGEpKSB7CiAgICAgIHJldHVybiAiYnVmZmVyIgogICAgfQogICAgaWYoaGFzVHlwZWRBcnJheXMpIHsKICAgICAgc3dpdGNoKE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChkYXRhKSkgewogICAgICAgIGNhc2UgIltvYmplY3QgRmxvYXQ2NEFycmF5XSI6CiAgICAgICAgICByZXR1cm4gImZsb2F0NjQiCiAgICAgICAgY2FzZSAiW29iamVjdCBGbG9hdDMyQXJyYXldIjoKICAgICAgICAgIHJldHVybiAiZmxvYXQzMiIKICAgICAgICBjYXNlICJbb2JqZWN0IEludDhBcnJheV0iOgogICAgICAgICAgcmV0dXJuICJpbnQ4IgogICAgICAgIGNhc2UgIltvYmplY3QgSW50MTZBcnJheV0iOgogICAgICAgICAgcmV0dXJuICJpbnQxNiIKICAgICAgICBjYXNlICJbb2JqZWN0IEludDMyQXJyYXldIjoKICAgICAgICAgIHJldHVybiAiaW50MzIiCiAgICAgICAgY2FzZSAiW29iamVjdCBVaW50OEFycmF5XSI6CiAgICAgICAgICByZXR1cm4gInVpbnQ4IgogICAgICAgIGNhc2UgIltvYmplY3QgVWludDE2QXJyYXldIjoKICAgICAgICAgIHJldHVybiAidWludDE2IgogICAgICAgIGNhc2UgIltvYmplY3QgVWludDMyQXJyYXldIjoKICAgICAgICAgIHJldHVybiAidWludDMyIgogICAgICAgIGNhc2UgIltvYmplY3QgVWludDhDbGFtcGVkQXJyYXldIjoKICAgICAgICAgIHJldHVybiAidWludDhfY2xhbXBlZCIKICAgICAgICBjYXNlICJbb2JqZWN0IEJpZ0ludDY0QXJyYXldIjoKICAgICAgICAgIHJldHVybiAiYmlnaW50NjQiCiAgICAgICAgY2FzZSAiW29iamVjdCBCaWdVaW50NjRBcnJheV0iOgogICAgICAgICAgcmV0dXJuICJiaWd1aW50NjQiCiAgICAgIH0KICAgIH0KICAgIGlmKEFycmF5LmlzQXJyYXkoZGF0YSkpIHsKICAgICAgcmV0dXJuICJhcnJheSIKICAgIH0KICAgIHJldHVybiAiZ2VuZXJpYyIKICB9CgogIHZhciBDQUNIRURfQ09OU1RSVUNUT1JTID0gewogICAgImZsb2F0MzIiOltdLAogICAgImZsb2F0NjQiOltdLAogICAgImludDgiOltdLAogICAgImludDE2IjpbXSwKICAgICJpbnQzMiI6W10sCiAgICAidWludDgiOltdLAogICAgInVpbnQxNiI6W10sCiAgICAidWludDMyIjpbXSwKICAgICJhcnJheSI6W10sCiAgICAidWludDhfY2xhbXBlZCI6W10sCiAgICAiYmlnaW50NjQiOiBbXSwKICAgICJiaWd1aW50NjQiOiBbXSwKICAgICJidWZmZXIiOltdLAogICAgImdlbmVyaWMiOltdCiAgfQoKICA7CiAgZnVuY3Rpb24gd3JhcHBlZE5EQXJyYXlDdG9yKGRhdGEsIHNoYXBlLCBzdHJpZGUsIG9mZnNldCkgewogICAgaWYoZGF0YSA9PT0gdW5kZWZpbmVkKSB7CiAgICAgIHZhciBjdG9yID0gQ0FDSEVEX0NPTlNUUlVDVE9SUy5hcnJheVswXTsKICAgICAgcmV0dXJuIGN0b3IoW10pCiAgICB9IGVsc2UgaWYodHlwZW9mIGRhdGEgPT09ICJudW1iZXIiKSB7CiAgICAgIGRhdGEgPSBbZGF0YV07CiAgICB9CiAgICBpZihzaGFwZSA9PT0gdW5kZWZpbmVkKSB7CiAgICAgIHNoYXBlID0gWyBkYXRhLmxlbmd0aCBdOwogICAgfQogICAgdmFyIGQgPSBzaGFwZS5sZW5ndGg7CiAgICBpZihzdHJpZGUgPT09IHVuZGVmaW5lZCkgewogICAgICBzdHJpZGUgPSBuZXcgQXJyYXkoZCk7CiAgICAgIGZvcih2YXIgaT1kLTEsIHN6PTE7IGk+PTA7IC0taSkgewogICAgICAgIHN0cmlkZVtpXSA9IHN6OwogICAgICAgIHN6ICo9IHNoYXBlW2ldOwogICAgICB9CiAgICB9CiAgICBpZihvZmZzZXQgPT09IHVuZGVmaW5lZCkgewogICAgICBvZmZzZXQgPSAwOwogICAgICBmb3IodmFyIGk9MDsgaTxkOyArK2kpIHsKICAgICAgICBpZihzdHJpZGVbaV0gPCAwKSB7CiAgICAgICAgICBvZmZzZXQgLT0gKHNoYXBlW2ldLTEpKnN0cmlkZVtpXTsKICAgICAgICB9CiAgICAgIH0KICAgIH0KICAgIHZhciBkdHlwZSA9IGFycmF5RFR5cGUoZGF0YSk7CiAgICB2YXIgY3Rvcl9saXN0ID0gQ0FDSEVEX0NPTlNUUlVDVE9SU1tkdHlwZV07CiAgICB3aGlsZShjdG9yX2xpc3QubGVuZ3RoIDw9IGQrMSkgewogICAgICBjdG9yX2xpc3QucHVzaChjb21waWxlQ29uc3RydWN0b3IoZHR5cGUsIGN0b3JfbGlzdC5sZW5ndGgtMSkpOwogICAgfQogICAgdmFyIGN0b3IgPSBjdG9yX2xpc3RbZCsxXTsKICAgIHJldHVybiBjdG9yKGRhdGEsIHNoYXBlLCBzdHJpZGUsIG9mZnNldCkKICB9CgogIHZhciBuZGFycmF5ID0gd3JhcHBlZE5EQXJyYXlDdG9yOwoKICBjbGFzcyBNYXJ0aW5pIHsKICAgIGNvbnN0cnVjdG9yKGdyaWRTaXplID0gMjU3KSB7CiAgICAgIHRoaXMuZ3JpZFNpemUgPSBncmlkU2l6ZTsKICAgICAgY29uc3QgdGlsZVNpemUgPSBncmlkU2l6ZSAtIDE7CiAgICAgIGlmICh0aWxlU2l6ZSAmIHRpbGVTaXplIC0gMSkgdGhyb3cgbmV3IEVycm9yKGBFeHBlY3RlZCBncmlkIHNpemUgdG8gYmUgMl5uKzEsIGdvdCAke2dyaWRTaXplfS5gKTsKICAgICAgdGhpcy5udW1UcmlhbmdsZXMgPSB0aWxlU2l6ZSAqIHRpbGVTaXplICogMiAtIDI7CiAgICAgIHRoaXMubnVtUGFyZW50VHJpYW5nbGVzID0gdGhpcy5udW1UcmlhbmdsZXMgLSB0aWxlU2l6ZSAqIHRpbGVTaXplOwogICAgICB0aGlzLmluZGljZXMgPSBuZXcgVWludDMyQXJyYXkodGhpcy5ncmlkU2l6ZSAqIHRoaXMuZ3JpZFNpemUpOyAvLyBjb29yZGluYXRlcyBmb3IgYWxsIHBvc3NpYmxlIHRyaWFuZ2xlcyBpbiBhbiBSVElOIHRpbGUKCiAgICAgIHRoaXMuY29vcmRzID0gbmV3IFVpbnQxNkFycmF5KHRoaXMubnVtVHJpYW5nbGVzICogNCk7IC8vIGdldCB0cmlhbmdsZSBjb29yZGluYXRlcyBmcm9tIGl0cyBpbmRleCBpbiBhbiBpbXBsaWNpdCBiaW5hcnkgdHJlZQoKICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLm51bVRyaWFuZ2xlczsgaSsrKSB7CiAgICAgICAgbGV0IGlkID0gaSArIDI7CiAgICAgICAgbGV0IGF4ID0gMCwKICAgICAgICAgICAgYXkgPSAwLAogICAgICAgICAgICBieCA9IDAsCiAgICAgICAgICAgIGJ5ID0gMCwKICAgICAgICAgICAgY3ggPSAwLAogICAgICAgICAgICBjeSA9IDA7CgogICAgICAgIGlmIChpZCAmIDEpIHsKICAgICAgICAgIGJ4ID0gYnkgPSBjeCA9IHRpbGVTaXplOyAvLyBib3R0b20tbGVmdCB0cmlhbmdsZQogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICBheCA9IGF5ID0gY3kgPSB0aWxlU2l6ZTsgLy8gdG9wLXJpZ2h0IHRyaWFuZ2xlCiAgICAgICAgfQoKICAgICAgICB3aGlsZSAoKGlkID4+PSAxKSA+IDEpIHsKICAgICAgICAgIGNvbnN0IG14ID0gYXggKyBieCA+PiAxOwogICAgICAgICAgY29uc3QgbXkgPSBheSArIGJ5ID4+IDE7CgogICAgICAgICAgaWYgKGlkICYgMSkgewogICAgICAgICAgICAvLyBsZWZ0IGhhbGYKICAgICAgICAgICAgYnggPSBheDsKICAgICAgICAgICAgYnkgPSBheTsKICAgICAgICAgICAgYXggPSBjeDsKICAgICAgICAgICAgYXkgPSBjeTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIC8vIHJpZ2h0IGhhbGYKICAgICAgICAgICAgYXggPSBieDsKICAgICAgICAgICAgYXkgPSBieTsKICAgICAgICAgICAgYnggPSBjeDsKICAgICAgICAgICAgYnkgPSBjeTsKICAgICAgICAgIH0KCiAgICAgICAgICBjeCA9IG14OwogICAgICAgICAgY3kgPSBteTsKICAgICAgICB9CgogICAgICAgIGNvbnN0IGsgPSBpICogNDsKICAgICAgICB0aGlzLmNvb3Jkc1trICsgMF0gPSBheDsKICAgICAgICB0aGlzLmNvb3Jkc1trICsgMV0gPSBheTsKICAgICAgICB0aGlzLmNvb3Jkc1trICsgMl0gPSBieDsKICAgICAgICB0aGlzLmNvb3Jkc1trICsgM10gPSBieTsKICAgICAgfQogICAgfQoKICAgIGNyZWF0ZVRpbGUodGVycmFpbikgewogICAgICByZXR1cm4gbmV3IFRpbGUodGVycmFpbiwgdGhpcyk7CiAgICB9CgogIH0KCiAgY2xhc3MgVGlsZSB7CiAgICBjb25zdHJ1Y3Rvcih0ZXJyYWluLCBtYXJ0aW5pKSB7CiAgICAgIGNvbnN0IHNpemUgPSBtYXJ0aW5pLmdyaWRTaXplOwogICAgICBpZiAodGVycmFpbi5sZW5ndGggIT09IHNpemUgKiBzaXplKSB0aHJvdyBuZXcgRXJyb3IoYEV4cGVjdGVkIHRlcnJhaW4gZGF0YSBvZiBsZW5ndGggJHtzaXplICogc2l6ZX0gKCR7c2l6ZX0geCAke3NpemV9KSwgZ290ICR7dGVycmFpbi5sZW5ndGh9LmApOwogICAgICB0aGlzLnRlcnJhaW4gPSB0ZXJyYWluOwogICAgICB0aGlzLm1hcnRpbmkgPSBtYXJ0aW5pOwogICAgICB0aGlzLmVycm9ycyA9IG5ldyBGbG9hdDMyQXJyYXkodGVycmFpbi5sZW5ndGgpOwogICAgICB0aGlzLnVwZGF0ZSgpOwogICAgfQoKICAgIHVwZGF0ZSgpIHsKICAgICAgY29uc3QgewogICAgICAgIG51bVRyaWFuZ2xlcywKICAgICAgICBudW1QYXJlbnRUcmlhbmdsZXMsCiAgICAgICAgY29vcmRzLAogICAgICAgIGdyaWRTaXplOiBzaXplCiAgICAgIH0gPSB0aGlzLm1hcnRpbmk7CiAgICAgIGNvbnN0IHsKICAgICAgICB0ZXJyYWluLAogICAgICAgIGVycm9ycwogICAgICB9ID0gdGhpczsgLy8gaXRlcmF0ZSBvdmVyIGFsbCBwb3NzaWJsZSB0cmlhbmdsZXMsIHN0YXJ0aW5nIGZyb20gdGhlIHNtYWxsZXN0IGxldmVsCgogICAgICBmb3IgKGxldCBpID0gbnVtVHJpYW5nbGVzIC0gMTsgaSA+PSAwOyBpLS0pIHsKICAgICAgICBjb25zdCBrID0gaSAqIDQ7CiAgICAgICAgY29uc3QgYXggPSBjb29yZHNbayArIDBdOwogICAgICAgIGNvbnN0IGF5ID0gY29vcmRzW2sgKyAxXTsKICAgICAgICBjb25zdCBieCA9IGNvb3Jkc1trICsgMl07CiAgICAgICAgY29uc3QgYnkgPSBjb29yZHNbayArIDNdOwogICAgICAgIGNvbnN0IG14ID0gYXggKyBieCA+PiAxOwogICAgICAgIGNvbnN0IG15ID0gYXkgKyBieSA+PiAxOwogICAgICAgIGNvbnN0IGN4ID0gbXggKyBteSAtIGF5OwogICAgICAgIGNvbnN0IGN5ID0gbXkgKyBheCAtIG14OyAvLyBjYWxjdWxhdGUgZXJyb3IgaW4gdGhlIG1pZGRsZSBvZiB0aGUgbG9uZyBlZGdlIG9mIHRoZSB0cmlhbmdsZQoKICAgICAgICBjb25zdCBpbnRlcnBvbGF0ZWRIZWlnaHQgPSAodGVycmFpbltheSAqIHNpemUgKyBheF0gKyB0ZXJyYWluW2J5ICogc2l6ZSArIGJ4XSkgLyAyOwogICAgICAgIGNvbnN0IG1pZGRsZUluZGV4ID0gbXkgKiBzaXplICsgbXg7CiAgICAgICAgY29uc3QgbWlkZGxlRXJyb3IgPSBNYXRoLmFicyhpbnRlcnBvbGF0ZWRIZWlnaHQgLSB0ZXJyYWluW21pZGRsZUluZGV4XSk7CiAgICAgICAgZXJyb3JzW21pZGRsZUluZGV4XSA9IE1hdGgubWF4KGVycm9yc1ttaWRkbGVJbmRleF0sIG1pZGRsZUVycm9yKTsKCiAgICAgICAgaWYgKGkgPCBudW1QYXJlbnRUcmlhbmdsZXMpIHsKICAgICAgICAgIC8vIGJpZ2dlciB0cmlhbmdsZXM7IGFjY3VtdWxhdGUgZXJyb3Igd2l0aCBjaGlsZHJlbgogICAgICAgICAgY29uc3QgbGVmdENoaWxkSW5kZXggPSAoYXkgKyBjeSA+PiAxKSAqIHNpemUgKyAoYXggKyBjeCA+PiAxKTsKICAgICAgICAgIGNvbnN0IHJpZ2h0Q2hpbGRJbmRleCA9IChieSArIGN5ID4+IDEpICogc2l6ZSArIChieCArIGN4ID4+IDEpOwogICAgICAgICAgZXJyb3JzW21pZGRsZUluZGV4XSA9IE1hdGgubWF4KGVycm9yc1ttaWRkbGVJbmRleF0sIGVycm9yc1tsZWZ0Q2hpbGRJbmRleF0sIGVycm9yc1tyaWdodENoaWxkSW5kZXhdKTsKICAgICAgICB9CiAgICAgIH0KICAgIH0KCiAgICBnZXRNZXNoKG1heEVycm9yID0gMCwgbWF4TGVuZ3RoID0gbnVsbCkgewogICAgICBjb25zdCB7CiAgICAgICAgZ3JpZFNpemU6IHNpemUsCiAgICAgICAgaW5kaWNlcwogICAgICB9ID0gdGhpcy5tYXJ0aW5pOwogICAgICBjb25zdCB7CiAgICAgICAgZXJyb3JzCiAgICAgIH0gPSB0aGlzOwogICAgICBsZXQgbnVtVmVydGljZXMgPSAwOwogICAgICBsZXQgbnVtVHJpYW5nbGVzID0gMDsKICAgICAgY29uc3QgbWF4ID0gc2l6ZSAtIDE7IC8vIFRoZSBtYXhMZW5ndGggcGFyYW1ldGVyIHdpbGwgY2F1c2UgdHJpYW5nbGVzIHRvIGJlIGdlbmVyYXRlZCB1bnRpbCB0aGUgbGVncyBhcmUgYmVsb3cgdGhpcyBsZW5ndGgKICAgICAgLy8gSXQgaXMgbWVhbnQgdG8gc3VwcG9ydCBjYXNlcyB3aGVyZSBhIGNlcnRhaW4gbWVzaCBkZW5zaXR5IGlzIHJlcXVpcmVkIHRvIGRvIHNwaGVyaWNhbCBtYXRoIG9uIGRpZ2l0YWwgZ2xvYmVzCgogICAgICBjb25zdCBtYXhTY2FsZSA9IG1heExlbmd0aCB8fCBzaXplOyAvLyB1c2UgYW4gaW5kZXggZ3JpZCB0byBrZWVwIHRyYWNrIG9mIHZlcnRpY2VzIHRoYXQgd2VyZSBhbHJlYWR5IHVzZWQgdG8gYXZvaWQgZHVwbGljYXRpb24KCiAgICAgIGluZGljZXMuZmlsbCgwKTsgLy8gcmV0cmlldmUgbWVzaCBpbiB0d28gc3RhZ2VzIHRoYXQgYm90aCB0cmF2ZXJzZSB0aGUgZXJyb3IgbWFwOgogICAgICAvLyAtIGNvdW50RWxlbWVudHM6IGZpbmQgdXNlZCB2ZXJ0aWNlcyAoYW5kIGFzc2lnbiBlYWNoIGFuIGluZGV4KSwgYW5kIGNvdW50IHRyaWFuZ2xlcyAoZm9yIG1pbmltdW0gYWxsb2NhdGlvbikKICAgICAgLy8gLSBwcm9jZXNzVHJpYW5nbGU6IGZpbGwgdGhlIGFsbG9jYXRlZCB2ZXJ0aWNlcyAmIHRyaWFuZ2xlcyB0eXBlZCBhcnJheXMKCiAgICAgIGZ1bmN0aW9uIGNvdW50RWxlbWVudHMoYXgsIGF5LCBieCwgYnksIGN4LCBjeSkgewogICAgICAgIGNvbnN0IG14ID0gYXggKyBieCA+PiAxOwogICAgICAgIGNvbnN0IG15ID0gYXkgKyBieSA+PiAxOwogICAgICAgIGNvbnN0IGxlZ0xlbmd0aCA9IE1hdGguYWJzKGF4IC0gY3gpICsgTWF0aC5hYnMoYXkgLSBjeSk7CgogICAgICAgIGlmIChsZWdMZW5ndGggPiAxICYmIGVycm9yc1tteSAqIHNpemUgKyBteF0gPiBtYXhFcnJvciB8fCBsZWdMZW5ndGggPiBtYXhTY2FsZSkgewogICAgICAgICAgY291bnRFbGVtZW50cyhjeCwgY3ksIGF4LCBheSwgbXgsIG15KTsKICAgICAgICAgIGNvdW50RWxlbWVudHMoYngsIGJ5LCBjeCwgY3ksIG14LCBteSk7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIGluZGljZXNbYXkgKiBzaXplICsgYXhdID0gaW5kaWNlc1theSAqIHNpemUgKyBheF0gfHwgKytudW1WZXJ0aWNlczsKICAgICAgICAgIGluZGljZXNbYnkgKiBzaXplICsgYnhdID0gaW5kaWNlc1tieSAqIHNpemUgKyBieF0gfHwgKytudW1WZXJ0aWNlczsKICAgICAgICAgIGluZGljZXNbY3kgKiBzaXplICsgY3hdID0gaW5kaWNlc1tjeSAqIHNpemUgKyBjeF0gfHwgKytudW1WZXJ0aWNlczsKICAgICAgICAgIG51bVRyaWFuZ2xlcysrOwogICAgICAgIH0KICAgICAgfQoKICAgICAgY291bnRFbGVtZW50cygwLCAwLCBtYXgsIG1heCwgbWF4LCAwKTsKICAgICAgY291bnRFbGVtZW50cyhtYXgsIG1heCwgMCwgMCwgMCwgbWF4KTsKICAgICAgY29uc3QgdmVydGljZXMgPSBuZXcgVWludDE2QXJyYXkobnVtVmVydGljZXMgKiAyKTsKICAgICAgY29uc3QgdHJpYW5nbGVzID0gbmV3IFVpbnQzMkFycmF5KG51bVRyaWFuZ2xlcyAqIDMpOwogICAgICBsZXQgdHJpSW5kZXggPSAwOwoKICAgICAgZnVuY3Rpb24gcHJvY2Vzc1RyaWFuZ2xlKGF4LCBheSwgYngsIGJ5LCBjeCwgY3kpIHsKICAgICAgICBjb25zdCBteCA9IGF4ICsgYnggPj4gMTsKICAgICAgICBjb25zdCBteSA9IGF5ICsgYnkgPj4gMTsKICAgICAgICBjb25zdCBsZWdMZW5ndGggPSBNYXRoLmFicyhheCAtIGN4KSArIE1hdGguYWJzKGF5IC0gY3kpOwoKICAgICAgICBpZiAobGVnTGVuZ3RoID4gMSAmJiBlcnJvcnNbbXkgKiBzaXplICsgbXhdID4gbWF4RXJyb3IgfHwgbGVnTGVuZ3RoID4gbWF4U2NhbGUpIHsKICAgICAgICAgIC8vIHRyaWFuZ2xlIGRvZXNuJ3QgYXBwcm94aW1hdGUgdGhlIHN1cmZhY2Ugd2VsbCBlbm91Z2g7IGRyaWxsIGRvd24gZnVydGhlcgogICAgICAgICAgcHJvY2Vzc1RyaWFuZ2xlKGN4LCBjeSwgYXgsIGF5LCBteCwgbXkpOwogICAgICAgICAgcHJvY2Vzc1RyaWFuZ2xlKGJ4LCBieSwgY3gsIGN5LCBteCwgbXkpOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAvLyBhZGQgYSB0cmlhbmdsZQogICAgICAgICAgY29uc3QgYSA9IGluZGljZXNbYXkgKiBzaXplICsgYXhdIC0gMTsKICAgICAgICAgIGNvbnN0IGIgPSBpbmRpY2VzW2J5ICogc2l6ZSArIGJ4XSAtIDE7CiAgICAgICAgICBjb25zdCBjID0gaW5kaWNlc1tjeSAqIHNpemUgKyBjeF0gLSAxOwogICAgICAgICAgdmVydGljZXNbMiAqIGFdID0gYXg7CiAgICAgICAgICB2ZXJ0aWNlc1syICogYSArIDFdID0gYXk7CiAgICAgICAgICB2ZXJ0aWNlc1syICogYl0gPSBieDsKICAgICAgICAgIHZlcnRpY2VzWzIgKiBiICsgMV0gPSBieTsKICAgICAgICAgIHZlcnRpY2VzWzIgKiBjXSA9IGN4OwogICAgICAgICAgdmVydGljZXNbMiAqIGMgKyAxXSA9IGN5OwogICAgICAgICAgdHJpYW5nbGVzW3RyaUluZGV4KytdID0gYTsKICAgICAgICAgIHRyaWFuZ2xlc1t0cmlJbmRleCsrXSA9IGI7CiAgICAgICAgICB0cmlhbmdsZXNbdHJpSW5kZXgrK10gPSBjOwogICAgICAgIH0KICAgICAgfQoKICAgICAgcHJvY2Vzc1RyaWFuZ2xlKDAsIDAsIG1heCwgbWF4LCBtYXgsIDApOwogICAgICBwcm9jZXNzVHJpYW5nbGUobWF4LCBtYXgsIDAsIDAsIDAsIG1heCk7CiAgICAgIHJldHVybiB7CiAgICAgICAgdmVydGljZXMsCiAgICAgICAgdHJpYW5nbGVzCiAgICAgIH07CiAgICB9CgogIH0KCiAgZnVuY3Rpb24gY3JlYXRlQ29tbW9uanNNb2R1bGUoZm4pIHsKICAgIHZhciBtb2R1bGUgPSB7IGV4cG9ydHM6IHt9IH07CiAgCXJldHVybiBmbihtb2R1bGUsIG1vZHVsZS5leHBvcnRzKSwgbW9kdWxlLmV4cG9ydHM7CiAgfQoKICAvKioKICAgKiBDb3B5cmlnaHQgKGMpIDIwMTQtcHJlc2VudCwgRmFjZWJvb2ssIEluYy4KICAgKgogICAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlIGZvdW5kIGluIHRoZQogICAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4KICAgKi8KCiAgY3JlYXRlQ29tbW9uanNNb2R1bGUoZnVuY3Rpb24gKG1vZHVsZSkgewogIHZhciBydW50aW1lID0gKGZ1bmN0aW9uIChleHBvcnRzKSB7CgogICAgdmFyIE9wID0gT2JqZWN0LnByb3RvdHlwZTsKICAgIHZhciBoYXNPd24gPSBPcC5oYXNPd25Qcm9wZXJ0eTsKICAgIHZhciB1bmRlZmluZWQkMTsgLy8gTW9yZSBjb21wcmVzc2libGUgdGhhbiB2b2lkIDAuCiAgICB2YXIgJFN5bWJvbCA9IHR5cGVvZiBTeW1ib2wgPT09ICJmdW5jdGlvbiIgPyBTeW1ib2wgOiB7fTsKICAgIHZhciBpdGVyYXRvclN5bWJvbCA9ICRTeW1ib2wuaXRlcmF0b3IgfHwgIkBAaXRlcmF0b3IiOwogICAgdmFyIGFzeW5jSXRlcmF0b3JTeW1ib2wgPSAkU3ltYm9sLmFzeW5jSXRlcmF0b3IgfHwgIkBAYXN5bmNJdGVyYXRvciI7CiAgICB2YXIgdG9TdHJpbmdUYWdTeW1ib2wgPSAkU3ltYm9sLnRvU3RyaW5nVGFnIHx8ICJAQHRvU3RyaW5nVGFnIjsKCiAgICBmdW5jdGlvbiBkZWZpbmUob2JqLCBrZXksIHZhbHVlKSB7CiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShvYmosIGtleSwgewogICAgICAgIHZhbHVlOiB2YWx1ZSwKICAgICAgICBlbnVtZXJhYmxlOiB0cnVlLAogICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSwKICAgICAgICB3cml0YWJsZTogdHJ1ZQogICAgICB9KTsKICAgICAgcmV0dXJuIG9ialtrZXldOwogICAgfQogICAgdHJ5IHsKICAgICAgLy8gSUUgOCBoYXMgYSBicm9rZW4gT2JqZWN0LmRlZmluZVByb3BlcnR5IHRoYXQgb25seSB3b3JrcyBvbiBET00gb2JqZWN0cy4KICAgICAgZGVmaW5lKHt9LCAiIik7CiAgICB9IGNhdGNoIChlcnIpIHsKICAgICAgZGVmaW5lID0gZnVuY3Rpb24ob2JqLCBrZXksIHZhbHVlKSB7CiAgICAgICAgcmV0dXJuIG9ialtrZXldID0gdmFsdWU7CiAgICAgIH07CiAgICB9CgogICAgZnVuY3Rpb24gd3JhcChpbm5lckZuLCBvdXRlckZuLCBzZWxmLCB0cnlMb2NzTGlzdCkgewogICAgICAvLyBJZiBvdXRlckZuIHByb3ZpZGVkIGFuZCBvdXRlckZuLnByb3RvdHlwZSBpcyBhIEdlbmVyYXRvciwgdGhlbiBvdXRlckZuLnByb3RvdHlwZSBpbnN0YW5jZW9mIEdlbmVyYXRvci4KICAgICAgdmFyIHByb3RvR2VuZXJhdG9yID0gb3V0ZXJGbiAmJiBvdXRlckZuLnByb3RvdHlwZSBpbnN0YW5jZW9mIEdlbmVyYXRvciA/IG91dGVyRm4gOiBHZW5lcmF0b3I7CiAgICAgIHZhciBnZW5lcmF0b3IgPSBPYmplY3QuY3JlYXRlKHByb3RvR2VuZXJhdG9yLnByb3RvdHlwZSk7CiAgICAgIHZhciBjb250ZXh0ID0gbmV3IENvbnRleHQodHJ5TG9jc0xpc3QgfHwgW10pOwoKICAgICAgLy8gVGhlIC5faW52b2tlIG1ldGhvZCB1bmlmaWVzIHRoZSBpbXBsZW1lbnRhdGlvbnMgb2YgdGhlIC5uZXh0LAogICAgICAvLyAudGhyb3csIGFuZCAucmV0dXJuIG1ldGhvZHMuCiAgICAgIGdlbmVyYXRvci5faW52b2tlID0gbWFrZUludm9rZU1ldGhvZChpbm5lckZuLCBzZWxmLCBjb250ZXh0KTsKCiAgICAgIHJldHVybiBnZW5lcmF0b3I7CiAgICB9CiAgICBleHBvcnRzLndyYXAgPSB3cmFwOwoKICAgIC8vIFRyeS9jYXRjaCBoZWxwZXIgdG8gbWluaW1pemUgZGVvcHRpbWl6YXRpb25zLiBSZXR1cm5zIGEgY29tcGxldGlvbgogICAgLy8gcmVjb3JkIGxpa2UgY29udGV4dC50cnlFbnRyaWVzW2ldLmNvbXBsZXRpb24uIFRoaXMgaW50ZXJmYWNlIGNvdWxkCiAgICAvLyBoYXZlIGJlZW4gKGFuZCB3YXMgcHJldmlvdXNseSkgZGVzaWduZWQgdG8gdGFrZSBhIGNsb3N1cmUgdG8gYmUKICAgIC8vIGludm9rZWQgd2l0aG91dCBhcmd1bWVudHMsIGJ1dCBpbiBhbGwgdGhlIGNhc2VzIHdlIGNhcmUgYWJvdXQgd2UKICAgIC8vIGFscmVhZHkgaGF2ZSBhbiBleGlzdGluZyBtZXRob2Qgd2Ugd2FudCB0byBjYWxsLCBzbyB0aGVyZSdzIG5vIG5lZWQKICAgIC8vIHRvIGNyZWF0ZSBhIG5ldyBmdW5jdGlvbiBvYmplY3QuIFdlIGNhbiBldmVuIGdldCBhd2F5IHdpdGggYXNzdW1pbmcKICAgIC8vIHRoZSBtZXRob2QgdGFrZXMgZXhhY3RseSBvbmUgYXJndW1lbnQsIHNpbmNlIHRoYXQgaGFwcGVucyB0byBiZSB0cnVlCiAgICAvLyBpbiBldmVyeSBjYXNlLCBzbyB3ZSBkb24ndCBoYXZlIHRvIHRvdWNoIHRoZSBhcmd1bWVudHMgb2JqZWN0LiBUaGUKICAgIC8vIG9ubHkgYWRkaXRpb25hbCBhbGxvY2F0aW9uIHJlcXVpcmVkIGlzIHRoZSBjb21wbGV0aW9uIHJlY29yZCwgd2hpY2gKICAgIC8vIGhhcyBhIHN0YWJsZSBzaGFwZSBhbmQgc28gaG9wZWZ1bGx5IHNob3VsZCBiZSBjaGVhcCB0byBhbGxvY2F0ZS4KICAgIGZ1bmN0aW9uIHRyeUNhdGNoKGZuLCBvYmosIGFyZykgewogICAgICB0cnkgewogICAgICAgIHJldHVybiB7IHR5cGU6ICJub3JtYWwiLCBhcmc6IGZuLmNhbGwob2JqLCBhcmcpIH07CiAgICAgIH0gY2F0Y2ggKGVycikgewogICAgICAgIHJldHVybiB7IHR5cGU6ICJ0aHJvdyIsIGFyZzogZXJyIH07CiAgICAgIH0KICAgIH0KCiAgICB2YXIgR2VuU3RhdGVTdXNwZW5kZWRTdGFydCA9ICJzdXNwZW5kZWRTdGFydCI7CiAgICB2YXIgR2VuU3RhdGVTdXNwZW5kZWRZaWVsZCA9ICJzdXNwZW5kZWRZaWVsZCI7CiAgICB2YXIgR2VuU3RhdGVFeGVjdXRpbmcgPSAiZXhlY3V0aW5nIjsKICAgIHZhciBHZW5TdGF0ZUNvbXBsZXRlZCA9ICJjb21wbGV0ZWQiOwoKICAgIC8vIFJldHVybmluZyB0aGlzIG9iamVjdCBmcm9tIHRoZSBpbm5lckZuIGhhcyB0aGUgc2FtZSBlZmZlY3QgYXMKICAgIC8vIGJyZWFraW5nIG91dCBvZiB0aGUgZGlzcGF0Y2ggc3dpdGNoIHN0YXRlbWVudC4KICAgIHZhciBDb250aW51ZVNlbnRpbmVsID0ge307CgogICAgLy8gRHVtbXkgY29uc3RydWN0b3IgZnVuY3Rpb25zIHRoYXQgd2UgdXNlIGFzIHRoZSAuY29uc3RydWN0b3IgYW5kCiAgICAvLyAuY29uc3RydWN0b3IucHJvdG90eXBlIHByb3BlcnRpZXMgZm9yIGZ1bmN0aW9ucyB0aGF0IHJldHVybiBHZW5lcmF0b3IKICAgIC8vIG9iamVjdHMuIEZvciBmdWxsIHNwZWMgY29tcGxpYW5jZSwgeW91IG1heSB3aXNoIHRvIGNvbmZpZ3VyZSB5b3VyCiAgICAvLyBtaW5pZmllciBub3QgdG8gbWFuZ2xlIHRoZSBuYW1lcyBvZiB0aGVzZSB0d28gZnVuY3Rpb25zLgogICAgZnVuY3Rpb24gR2VuZXJhdG9yKCkge30KICAgIGZ1bmN0aW9uIEdlbmVyYXRvckZ1bmN0aW9uKCkge30KICAgIGZ1bmN0aW9uIEdlbmVyYXRvckZ1bmN0aW9uUHJvdG90eXBlKCkge30KCiAgICAvLyBUaGlzIGlzIGEgcG9seWZpbGwgZm9yICVJdGVyYXRvclByb3RvdHlwZSUgZm9yIGVudmlyb25tZW50cyB0aGF0CiAgICAvLyBkb24ndCBuYXRpdmVseSBzdXBwb3J0IGl0LgogICAgdmFyIEl0ZXJhdG9yUHJvdG90eXBlID0ge307CiAgICBkZWZpbmUoSXRlcmF0b3JQcm90b3R5cGUsIGl0ZXJhdG9yU3ltYm9sLCBmdW5jdGlvbiAoKSB7CiAgICAgIHJldHVybiB0aGlzOwogICAgfSk7CgogICAgdmFyIGdldFByb3RvID0gT2JqZWN0LmdldFByb3RvdHlwZU9mOwogICAgdmFyIE5hdGl2ZUl0ZXJhdG9yUHJvdG90eXBlID0gZ2V0UHJvdG8gJiYgZ2V0UHJvdG8oZ2V0UHJvdG8odmFsdWVzKFtdKSkpOwogICAgaWYgKE5hdGl2ZUl0ZXJhdG9yUHJvdG90eXBlICYmCiAgICAgICAgTmF0aXZlSXRlcmF0b3JQcm90b3R5cGUgIT09IE9wICYmCiAgICAgICAgaGFzT3duLmNhbGwoTmF0aXZlSXRlcmF0b3JQcm90b3R5cGUsIGl0ZXJhdG9yU3ltYm9sKSkgewogICAgICAvLyBUaGlzIGVudmlyb25tZW50IGhhcyBhIG5hdGl2ZSAlSXRlcmF0b3JQcm90b3R5cGUlOyB1c2UgaXQgaW5zdGVhZAogICAgICAvLyBvZiB0aGUgcG9seWZpbGwuCiAgICAgIEl0ZXJhdG9yUHJvdG90eXBlID0gTmF0aXZlSXRlcmF0b3JQcm90b3R5cGU7CiAgICB9CgogICAgdmFyIEdwID0gR2VuZXJhdG9yRnVuY3Rpb25Qcm90b3R5cGUucHJvdG90eXBlID0KICAgICAgR2VuZXJhdG9yLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoSXRlcmF0b3JQcm90b3R5cGUpOwogICAgR2VuZXJhdG9yRnVuY3Rpb24ucHJvdG90eXBlID0gR2VuZXJhdG9yRnVuY3Rpb25Qcm90b3R5cGU7CiAgICBkZWZpbmUoR3AsICJjb25zdHJ1Y3RvciIsIEdlbmVyYXRvckZ1bmN0aW9uUHJvdG90eXBlKTsKICAgIGRlZmluZShHZW5lcmF0b3JGdW5jdGlvblByb3RvdHlwZSwgImNvbnN0cnVjdG9yIiwgR2VuZXJhdG9yRnVuY3Rpb24pOwogICAgR2VuZXJhdG9yRnVuY3Rpb24uZGlzcGxheU5hbWUgPSBkZWZpbmUoCiAgICAgIEdlbmVyYXRvckZ1bmN0aW9uUHJvdG90eXBlLAogICAgICB0b1N0cmluZ1RhZ1N5bWJvbCwKICAgICAgIkdlbmVyYXRvckZ1bmN0aW9uIgogICAgKTsKCiAgICAvLyBIZWxwZXIgZm9yIGRlZmluaW5nIHRoZSAubmV4dCwgLnRocm93LCBhbmQgLnJldHVybiBtZXRob2RzIG9mIHRoZQogICAgLy8gSXRlcmF0b3IgaW50ZXJmYWNlIGluIHRlcm1zIG9mIGEgc2luZ2xlIC5faW52b2tlIG1ldGhvZC4KICAgIGZ1bmN0aW9uIGRlZmluZUl0ZXJhdG9yTWV0aG9kcyhwcm90b3R5cGUpIHsKICAgICAgWyJuZXh0IiwgInRocm93IiwgInJldHVybiJdLmZvckVhY2goZnVuY3Rpb24obWV0aG9kKSB7CiAgICAgICAgZGVmaW5lKHByb3RvdHlwZSwgbWV0aG9kLCBmdW5jdGlvbihhcmcpIHsKICAgICAgICAgIHJldHVybiB0aGlzLl9pbnZva2UobWV0aG9kLCBhcmcpOwogICAgICAgIH0pOwogICAgICB9KTsKICAgIH0KCiAgICBleHBvcnRzLmlzR2VuZXJhdG9yRnVuY3Rpb24gPSBmdW5jdGlvbihnZW5GdW4pIHsKICAgICAgdmFyIGN0b3IgPSB0eXBlb2YgZ2VuRnVuID09PSAiZnVuY3Rpb24iICYmIGdlbkZ1bi5jb25zdHJ1Y3RvcjsKICAgICAgcmV0dXJuIGN0b3IKICAgICAgICA/IGN0b3IgPT09IEdlbmVyYXRvckZ1bmN0aW9uIHx8CiAgICAgICAgICAvLyBGb3IgdGhlIG5hdGl2ZSBHZW5lcmF0b3JGdW5jdGlvbiBjb25zdHJ1Y3RvciwgdGhlIGJlc3Qgd2UgY2FuCiAgICAgICAgICAvLyBkbyBpcyB0byBjaGVjayBpdHMgLm5hbWUgcHJvcGVydHkuCiAgICAgICAgICAoY3Rvci5kaXNwbGF5TmFtZSB8fCBjdG9yLm5hbWUpID09PSAiR2VuZXJhdG9yRnVuY3Rpb24iCiAgICAgICAgOiBmYWxzZTsKICAgIH07CgogICAgZXhwb3J0cy5tYXJrID0gZnVuY3Rpb24oZ2VuRnVuKSB7CiAgICAgIGlmIChPYmplY3Quc2V0UHJvdG90eXBlT2YpIHsKICAgICAgICBPYmplY3Quc2V0UHJvdG90eXBlT2YoZ2VuRnVuLCBHZW5lcmF0b3JGdW5jdGlvblByb3RvdHlwZSk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgZ2VuRnVuLl9fcHJvdG9fXyA9IEdlbmVyYXRvckZ1bmN0aW9uUHJvdG90eXBlOwogICAgICAgIGRlZmluZShnZW5GdW4sIHRvU3RyaW5nVGFnU3ltYm9sLCAiR2VuZXJhdG9yRnVuY3Rpb24iKTsKICAgICAgfQogICAgICBnZW5GdW4ucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShHcCk7CiAgICAgIHJldHVybiBnZW5GdW47CiAgICB9OwoKICAgIC8vIFdpdGhpbiB0aGUgYm9keSBvZiBhbnkgYXN5bmMgZnVuY3Rpb24sIGBhd2FpdCB4YCBpcyB0cmFuc2Zvcm1lZCB0bwogICAgLy8gYHlpZWxkIHJlZ2VuZXJhdG9yUnVudGltZS5hd3JhcCh4KWAsIHNvIHRoYXQgdGhlIHJ1bnRpbWUgY2FuIHRlc3QKICAgIC8vIGBoYXNPd24uY2FsbCh2YWx1ZSwgIl9fYXdhaXQiKWAgdG8gZGV0ZXJtaW5lIGlmIHRoZSB5aWVsZGVkIHZhbHVlIGlzCiAgICAvLyBtZWFudCB0byBiZSBhd2FpdGVkLgogICAgZXhwb3J0cy5hd3JhcCA9IGZ1bmN0aW9uKGFyZykgewogICAgICByZXR1cm4geyBfX2F3YWl0OiBhcmcgfTsKICAgIH07CgogICAgZnVuY3Rpb24gQXN5bmNJdGVyYXRvcihnZW5lcmF0b3IsIFByb21pc2VJbXBsKSB7CiAgICAgIGZ1bmN0aW9uIGludm9rZShtZXRob2QsIGFyZywgcmVzb2x2ZSwgcmVqZWN0KSB7CiAgICAgICAgdmFyIHJlY29yZCA9IHRyeUNhdGNoKGdlbmVyYXRvclttZXRob2RdLCBnZW5lcmF0b3IsIGFyZyk7CiAgICAgICAgaWYgKHJlY29yZC50eXBlID09PSAidGhyb3ciKSB7CiAgICAgICAgICByZWplY3QocmVjb3JkLmFyZyk7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHZhciByZXN1bHQgPSByZWNvcmQuYXJnOwogICAgICAgICAgdmFyIHZhbHVlID0gcmVzdWx0LnZhbHVlOwogICAgICAgICAgaWYgKHZhbHVlICYmCiAgICAgICAgICAgICAgdHlwZW9mIHZhbHVlID09PSAib2JqZWN0IiAmJgogICAgICAgICAgICAgIGhhc093bi5jYWxsKHZhbHVlLCAiX19hd2FpdCIpKSB7CiAgICAgICAgICAgIHJldHVybiBQcm9taXNlSW1wbC5yZXNvbHZlKHZhbHVlLl9fYXdhaXQpLnRoZW4oZnVuY3Rpb24odmFsdWUpIHsKICAgICAgICAgICAgICBpbnZva2UoIm5leHQiLCB2YWx1ZSwgcmVzb2x2ZSwgcmVqZWN0KTsKICAgICAgICAgICAgfSwgZnVuY3Rpb24oZXJyKSB7CiAgICAgICAgICAgICAgaW52b2tlKCJ0aHJvdyIsIGVyciwgcmVzb2x2ZSwgcmVqZWN0KTsKICAgICAgICAgICAgfSk7CiAgICAgICAgICB9CgogICAgICAgICAgcmV0dXJuIFByb21pc2VJbXBsLnJlc29sdmUodmFsdWUpLnRoZW4oZnVuY3Rpb24odW53cmFwcGVkKSB7CiAgICAgICAgICAgIC8vIFdoZW4gYSB5aWVsZGVkIFByb21pc2UgaXMgcmVzb2x2ZWQsIGl0cyBmaW5hbCB2YWx1ZSBiZWNvbWVzCiAgICAgICAgICAgIC8vIHRoZSAudmFsdWUgb2YgdGhlIFByb21pc2U8e3ZhbHVlLGRvbmV9PiByZXN1bHQgZm9yIHRoZQogICAgICAgICAgICAvLyBjdXJyZW50IGl0ZXJhdGlvbi4KICAgICAgICAgICAgcmVzdWx0LnZhbHVlID0gdW53cmFwcGVkOwogICAgICAgICAgICByZXNvbHZlKHJlc3VsdCk7CiAgICAgICAgICB9LCBmdW5jdGlvbihlcnJvcikgewogICAgICAgICAgICAvLyBJZiBhIHJlamVjdGVkIFByb21pc2Ugd2FzIHlpZWxkZWQsIHRocm93IHRoZSByZWplY3Rpb24gYmFjawogICAgICAgICAgICAvLyBpbnRvIHRoZSBhc3luYyBnZW5lcmF0b3IgZnVuY3Rpb24gc28gaXQgY2FuIGJlIGhhbmRsZWQgdGhlcmUuCiAgICAgICAgICAgIHJldHVybiBpbnZva2UoInRocm93IiwgZXJyb3IsIHJlc29sdmUsIHJlamVjdCk7CiAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgIH0KCiAgICAgIHZhciBwcmV2aW91c1Byb21pc2U7CgogICAgICBmdW5jdGlvbiBlbnF1ZXVlKG1ldGhvZCwgYXJnKSB7CiAgICAgICAgZnVuY3Rpb24gY2FsbEludm9rZVdpdGhNZXRob2RBbmRBcmcoKSB7CiAgICAgICAgICByZXR1cm4gbmV3IFByb21pc2VJbXBsKGZ1bmN0aW9uKHJlc29sdmUsIHJlamVjdCkgewogICAgICAgICAgICBpbnZva2UobWV0aG9kLCBhcmcsIHJlc29sdmUsIHJlamVjdCk7CiAgICAgICAgICB9KTsKICAgICAgICB9CgogICAgICAgIHJldHVybiBwcmV2aW91c1Byb21pc2UgPQogICAgICAgICAgLy8gSWYgZW5xdWV1ZSBoYXMgYmVlbiBjYWxsZWQgYmVmb3JlLCB0aGVuIHdlIHdhbnQgdG8gd2FpdCB1bnRpbAogICAgICAgICAgLy8gYWxsIHByZXZpb3VzIFByb21pc2VzIGhhdmUgYmVlbiByZXNvbHZlZCBiZWZvcmUgY2FsbGluZyBpbnZva2UsCiAgICAgICAgICAvLyBzbyB0aGF0IHJlc3VsdHMgYXJlIGFsd2F5cyBkZWxpdmVyZWQgaW4gdGhlIGNvcnJlY3Qgb3JkZXIuIElmCiAgICAgICAgICAvLyBlbnF1ZXVlIGhhcyBub3QgYmVlbiBjYWxsZWQgYmVmb3JlLCB0aGVuIGl0IGlzIGltcG9ydGFudCB0bwogICAgICAgICAgLy8gY2FsbCBpbnZva2UgaW1tZWRpYXRlbHksIHdpdGhvdXQgd2FpdGluZyBvbiBhIGNhbGxiYWNrIHRvIGZpcmUsCiAgICAgICAgICAvLyBzbyB0aGF0IHRoZSBhc3luYyBnZW5lcmF0b3IgZnVuY3Rpb24gaGFzIHRoZSBvcHBvcnR1bml0eSB0byBkbwogICAgICAgICAgLy8gYW55IG5lY2Vzc2FyeSBzZXR1cCBpbiBhIHByZWRpY3RhYmxlIHdheS4gVGhpcyBwcmVkaWN0YWJpbGl0eQogICAgICAgICAgLy8gaXMgd2h5IHRoZSBQcm9taXNlIGNvbnN0cnVjdG9yIHN5bmNocm9ub3VzbHkgaW52b2tlcyBpdHMKICAgICAgICAgIC8vIGV4ZWN1dG9yIGNhbGxiYWNrLCBhbmQgd2h5IGFzeW5jIGZ1bmN0aW9ucyBzeW5jaHJvbm91c2x5CiAgICAgICAgICAvLyBleGVjdXRlIGNvZGUgYmVmb3JlIHRoZSBmaXJzdCBhd2FpdC4gU2luY2Ugd2UgaW1wbGVtZW50IHNpbXBsZQogICAgICAgICAgLy8gYXN5bmMgZnVuY3Rpb25zIGluIHRlcm1zIG9mIGFzeW5jIGdlbmVyYXRvcnMsIGl0IGlzIGVzcGVjaWFsbHkKICAgICAgICAgIC8vIGltcG9ydGFudCB0byBnZXQgdGhpcyByaWdodCwgZXZlbiB0aG91Z2ggaXQgcmVxdWlyZXMgY2FyZS4KICAgICAgICAgIHByZXZpb3VzUHJvbWlzZSA/IHByZXZpb3VzUHJvbWlzZS50aGVuKAogICAgICAgICAgICBjYWxsSW52b2tlV2l0aE1ldGhvZEFuZEFyZywKICAgICAgICAgICAgLy8gQXZvaWQgcHJvcGFnYXRpbmcgZmFpbHVyZXMgdG8gUHJvbWlzZXMgcmV0dXJuZWQgYnkgbGF0ZXIKICAgICAgICAgICAgLy8gaW52b2NhdGlvbnMgb2YgdGhlIGl0ZXJhdG9yLgogICAgICAgICAgICBjYWxsSW52b2tlV2l0aE1ldGhvZEFuZEFyZwogICAgICAgICAgKSA6IGNhbGxJbnZva2VXaXRoTWV0aG9kQW5kQXJnKCk7CiAgICAgIH0KCiAgICAgIC8vIERlZmluZSB0aGUgdW5pZmllZCBoZWxwZXIgbWV0aG9kIHRoYXQgaXMgdXNlZCB0byBpbXBsZW1lbnQgLm5leHQsCiAgICAgIC8vIC50aHJvdywgYW5kIC5yZXR1cm4gKHNlZSBkZWZpbmVJdGVyYXRvck1ldGhvZHMpLgogICAgICB0aGlzLl9pbnZva2UgPSBlbnF1ZXVlOwogICAgfQoKICAgIGRlZmluZUl0ZXJhdG9yTWV0aG9kcyhBc3luY0l0ZXJhdG9yLnByb3RvdHlwZSk7CiAgICBkZWZpbmUoQXN5bmNJdGVyYXRvci5wcm90b3R5cGUsIGFzeW5jSXRlcmF0b3JTeW1ib2wsIGZ1bmN0aW9uICgpIHsKICAgICAgcmV0dXJuIHRoaXM7CiAgICB9KTsKICAgIGV4cG9ydHMuQXN5bmNJdGVyYXRvciA9IEFzeW5jSXRlcmF0b3I7CgogICAgLy8gTm90ZSB0aGF0IHNpbXBsZSBhc3luYyBmdW5jdGlvbnMgYXJlIGltcGxlbWVudGVkIG9uIHRvcCBvZgogICAgLy8gQXN5bmNJdGVyYXRvciBvYmplY3RzOyB0aGV5IGp1c3QgcmV0dXJuIGEgUHJvbWlzZSBmb3IgdGhlIHZhbHVlIG9mCiAgICAvLyB0aGUgZmluYWwgcmVzdWx0IHByb2R1Y2VkIGJ5IHRoZSBpdGVyYXRvci4KICAgIGV4cG9ydHMuYXN5bmMgPSBmdW5jdGlvbihpbm5lckZuLCBvdXRlckZuLCBzZWxmLCB0cnlMb2NzTGlzdCwgUHJvbWlzZUltcGwpIHsKICAgICAgaWYgKFByb21pc2VJbXBsID09PSB2b2lkIDApIFByb21pc2VJbXBsID0gUHJvbWlzZTsKCiAgICAgIHZhciBpdGVyID0gbmV3IEFzeW5jSXRlcmF0b3IoCiAgICAgICAgd3JhcChpbm5lckZuLCBvdXRlckZuLCBzZWxmLCB0cnlMb2NzTGlzdCksCiAgICAgICAgUHJvbWlzZUltcGwKICAgICAgKTsKCiAgICAgIHJldHVybiBleHBvcnRzLmlzR2VuZXJhdG9yRnVuY3Rpb24ob3V0ZXJGbikKICAgICAgICA/IGl0ZXIgLy8gSWYgb3V0ZXJGbiBpcyBhIGdlbmVyYXRvciwgcmV0dXJuIHRoZSBmdWxsIGl0ZXJhdG9yLgogICAgICAgIDogaXRlci5uZXh0KCkudGhlbihmdW5jdGlvbihyZXN1bHQpIHsKICAgICAgICAgICAgcmV0dXJuIHJlc3VsdC5kb25lID8gcmVzdWx0LnZhbHVlIDogaXRlci5uZXh0KCk7CiAgICAgICAgICB9KTsKICAgIH07CgogICAgZnVuY3Rpb24gbWFrZUludm9rZU1ldGhvZChpbm5lckZuLCBzZWxmLCBjb250ZXh0KSB7CiAgICAgIHZhciBzdGF0ZSA9IEdlblN0YXRlU3VzcGVuZGVkU3RhcnQ7CgogICAgICByZXR1cm4gZnVuY3Rpb24gaW52b2tlKG1ldGhvZCwgYXJnKSB7CiAgICAgICAgaWYgKHN0YXRlID09PSBHZW5TdGF0ZUV4ZWN1dGluZykgewogICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCJHZW5lcmF0b3IgaXMgYWxyZWFkeSBydW5uaW5nIik7CiAgICAgICAgfQoKICAgICAgICBpZiAoc3RhdGUgPT09IEdlblN0YXRlQ29tcGxldGVkKSB7CiAgICAgICAgICBpZiAobWV0aG9kID09PSAidGhyb3ciKSB7CiAgICAgICAgICAgIHRocm93IGFyZzsKICAgICAgICAgIH0KCiAgICAgICAgICAvLyBCZSBmb3JnaXZpbmcsIHBlciAyNS4zLjMuMy4zIG9mIHRoZSBzcGVjOgogICAgICAgICAgLy8gaHR0cHM6Ly9wZW9wbGUubW96aWxsYS5vcmcvfmpvcmVuZG9yZmYvZXM2LWRyYWZ0Lmh0bWwjc2VjLWdlbmVyYXRvcnJlc3VtZQogICAgICAgICAgcmV0dXJuIGRvbmVSZXN1bHQoKTsKICAgICAgICB9CgogICAgICAgIGNvbnRleHQubWV0aG9kID0gbWV0aG9kOwogICAgICAgIGNvbnRleHQuYXJnID0gYXJnOwoKICAgICAgICB3aGlsZSAodHJ1ZSkgewogICAgICAgICAgdmFyIGRlbGVnYXRlID0gY29udGV4dC5kZWxlZ2F0ZTsKICAgICAgICAgIGlmIChkZWxlZ2F0ZSkgewogICAgICAgICAgICB2YXIgZGVsZWdhdGVSZXN1bHQgPSBtYXliZUludm9rZURlbGVnYXRlKGRlbGVnYXRlLCBjb250ZXh0KTsKICAgICAgICAgICAgaWYgKGRlbGVnYXRlUmVzdWx0KSB7CiAgICAgICAgICAgICAgaWYgKGRlbGVnYXRlUmVzdWx0ID09PSBDb250aW51ZVNlbnRpbmVsKSBjb250aW51ZTsKICAgICAgICAgICAgICByZXR1cm4gZGVsZWdhdGVSZXN1bHQ7CiAgICAgICAgICAgIH0KICAgICAgICAgIH0KCiAgICAgICAgICBpZiAoY29udGV4dC5tZXRob2QgPT09ICJuZXh0IikgewogICAgICAgICAgICAvLyBTZXR0aW5nIGNvbnRleHQuX3NlbnQgZm9yIGxlZ2FjeSBzdXBwb3J0IG9mIEJhYmVsJ3MKICAgICAgICAgICAgLy8gZnVuY3Rpb24uc2VudCBpbXBsZW1lbnRhdGlvbi4KICAgICAgICAgICAgY29udGV4dC5zZW50ID0gY29udGV4dC5fc2VudCA9IGNvbnRleHQuYXJnOwoKICAgICAgICAgIH0gZWxzZSBpZiAoY29udGV4dC5tZXRob2QgPT09ICJ0aHJvdyIpIHsKICAgICAgICAgICAgaWYgKHN0YXRlID09PSBHZW5TdGF0ZVN1c3BlbmRlZFN0YXJ0KSB7CiAgICAgICAgICAgICAgc3RhdGUgPSBHZW5TdGF0ZUNvbXBsZXRlZDsKICAgICAgICAgICAgICB0aHJvdyBjb250ZXh0LmFyZzsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgY29udGV4dC5kaXNwYXRjaEV4Y2VwdGlvbihjb250ZXh0LmFyZyk7CgogICAgICAgICAgfSBlbHNlIGlmIChjb250ZXh0Lm1ldGhvZCA9PT0gInJldHVybiIpIHsKICAgICAgICAgICAgY29udGV4dC5hYnJ1cHQoInJldHVybiIsIGNvbnRleHQuYXJnKTsKICAgICAgICAgIH0KCiAgICAgICAgICBzdGF0ZSA9IEdlblN0YXRlRXhlY3V0aW5nOwoKICAgICAgICAgIHZhciByZWNvcmQgPSB0cnlDYXRjaChpbm5lckZuLCBzZWxmLCBjb250ZXh0KTsKICAgICAgICAgIGlmIChyZWNvcmQudHlwZSA9PT0gIm5vcm1hbCIpIHsKICAgICAgICAgICAgLy8gSWYgYW4gZXhjZXB0aW9uIGlzIHRocm93biBmcm9tIGlubmVyRm4sIHdlIGxlYXZlIHN0YXRlID09PQogICAgICAgICAgICAvLyBHZW5TdGF0ZUV4ZWN1dGluZyBhbmQgbG9vcCBiYWNrIGZvciBhbm90aGVyIGludm9jYXRpb24uCiAgICAgICAgICAgIHN0YXRlID0gY29udGV4dC5kb25lCiAgICAgICAgICAgICAgPyBHZW5TdGF0ZUNvbXBsZXRlZAogICAgICAgICAgICAgIDogR2VuU3RhdGVTdXNwZW5kZWRZaWVsZDsKCiAgICAgICAgICAgIGlmIChyZWNvcmQuYXJnID09PSBDb250aW51ZVNlbnRpbmVsKSB7CiAgICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIHJldHVybiB7CiAgICAgICAgICAgICAgdmFsdWU6IHJlY29yZC5hcmcsCiAgICAgICAgICAgICAgZG9uZTogY29udGV4dC5kb25lCiAgICAgICAgICAgIH07CgogICAgICAgICAgfSBlbHNlIGlmIChyZWNvcmQudHlwZSA9PT0gInRocm93IikgewogICAgICAgICAgICBzdGF0ZSA9IEdlblN0YXRlQ29tcGxldGVkOwogICAgICAgICAgICAvLyBEaXNwYXRjaCB0aGUgZXhjZXB0aW9uIGJ5IGxvb3BpbmcgYmFjayBhcm91bmQgdG8gdGhlCiAgICAgICAgICAgIC8vIGNvbnRleHQuZGlzcGF0Y2hFeGNlcHRpb24oY29udGV4dC5hcmcpIGNhbGwgYWJvdmUuCiAgICAgICAgICAgIGNvbnRleHQubWV0aG9kID0gInRocm93IjsKICAgICAgICAgICAgY29udGV4dC5hcmcgPSByZWNvcmQuYXJnOwogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfTsKICAgIH0KCiAgICAvLyBDYWxsIGRlbGVnYXRlLml0ZXJhdG9yW2NvbnRleHQubWV0aG9kXShjb250ZXh0LmFyZykgYW5kIGhhbmRsZSB0aGUKICAgIC8vIHJlc3VsdCwgZWl0aGVyIGJ5IHJldHVybmluZyBhIHsgdmFsdWUsIGRvbmUgfSByZXN1bHQgZnJvbSB0aGUKICAgIC8vIGRlbGVnYXRlIGl0ZXJhdG9yLCBvciBieSBtb2RpZnlpbmcgY29udGV4dC5tZXRob2QgYW5kIGNvbnRleHQuYXJnLAogICAgLy8gc2V0dGluZyBjb250ZXh0LmRlbGVnYXRlIHRvIG51bGwsIGFuZCByZXR1cm5pbmcgdGhlIENvbnRpbnVlU2VudGluZWwuCiAgICBmdW5jdGlvbiBtYXliZUludm9rZURlbGVnYXRlKGRlbGVnYXRlLCBjb250ZXh0KSB7CiAgICAgIHZhciBtZXRob2QgPSBkZWxlZ2F0ZS5pdGVyYXRvcltjb250ZXh0Lm1ldGhvZF07CiAgICAgIGlmIChtZXRob2QgPT09IHVuZGVmaW5lZCQxKSB7CiAgICAgICAgLy8gQSAudGhyb3cgb3IgLnJldHVybiB3aGVuIHRoZSBkZWxlZ2F0ZSBpdGVyYXRvciBoYXMgbm8gLnRocm93CiAgICAgICAgLy8gbWV0aG9kIGFsd2F5cyB0ZXJtaW5hdGVzIHRoZSB5aWVsZCogbG9vcC4KICAgICAgICBjb250ZXh0LmRlbGVnYXRlID0gbnVsbDsKCiAgICAgICAgaWYgKGNvbnRleHQubWV0aG9kID09PSAidGhyb3ciKSB7CiAgICAgICAgICAvLyBOb3RlOiBbInJldHVybiJdIG11c3QgYmUgdXNlZCBmb3IgRVMzIHBhcnNpbmcgY29tcGF0aWJpbGl0eS4KICAgICAgICAgIGlmIChkZWxlZ2F0ZS5pdGVyYXRvclsicmV0dXJuIl0pIHsKICAgICAgICAgICAgLy8gSWYgdGhlIGRlbGVnYXRlIGl0ZXJhdG9yIGhhcyBhIHJldHVybiBtZXRob2QsIGdpdmUgaXQgYQogICAgICAgICAgICAvLyBjaGFuY2UgdG8gY2xlYW4gdXAuCiAgICAgICAgICAgIGNvbnRleHQubWV0aG9kID0gInJldHVybiI7CiAgICAgICAgICAgIGNvbnRleHQuYXJnID0gdW5kZWZpbmVkJDE7CiAgICAgICAgICAgIG1heWJlSW52b2tlRGVsZWdhdGUoZGVsZWdhdGUsIGNvbnRleHQpOwoKICAgICAgICAgICAgaWYgKGNvbnRleHQubWV0aG9kID09PSAidGhyb3ciKSB7CiAgICAgICAgICAgICAgLy8gSWYgbWF5YmVJbnZva2VEZWxlZ2F0ZShjb250ZXh0KSBjaGFuZ2VkIGNvbnRleHQubWV0aG9kIGZyb20KICAgICAgICAgICAgICAvLyAicmV0dXJuIiB0byAidGhyb3ciLCBsZXQgdGhhdCBvdmVycmlkZSB0aGUgVHlwZUVycm9yIGJlbG93LgogICAgICAgICAgICAgIHJldHVybiBDb250aW51ZVNlbnRpbmVsOwogICAgICAgICAgICB9CiAgICAgICAgICB9CgogICAgICAgICAgY29udGV4dC5tZXRob2QgPSAidGhyb3ciOwogICAgICAgICAgY29udGV4dC5hcmcgPSBuZXcgVHlwZUVycm9yKAogICAgICAgICAgICAiVGhlIGl0ZXJhdG9yIGRvZXMgbm90IHByb3ZpZGUgYSAndGhyb3cnIG1ldGhvZCIpOwogICAgICAgIH0KCiAgICAgICAgcmV0dXJuIENvbnRpbnVlU2VudGluZWw7CiAgICAgIH0KCiAgICAgIHZhciByZWNvcmQgPSB0cnlDYXRjaChtZXRob2QsIGRlbGVnYXRlLml0ZXJhdG9yLCBjb250ZXh0LmFyZyk7CgogICAgICBpZiAocmVjb3JkLnR5cGUgPT09ICJ0aHJvdyIpIHsKICAgICAgICBjb250ZXh0Lm1ldGhvZCA9ICJ0aHJvdyI7CiAgICAgICAgY29udGV4dC5hcmcgPSByZWNvcmQuYXJnOwogICAgICAgIGNvbnRleHQuZGVsZWdhdGUgPSBudWxsOwogICAgICAgIHJldHVybiBDb250aW51ZVNlbnRpbmVsOwogICAgICB9CgogICAgICB2YXIgaW5mbyA9IHJlY29yZC5hcmc7CgogICAgICBpZiAoISBpbmZvKSB7CiAgICAgICAgY29udGV4dC5tZXRob2QgPSAidGhyb3ciOwogICAgICAgIGNvbnRleHQuYXJnID0gbmV3IFR5cGVFcnJvcigiaXRlcmF0b3IgcmVzdWx0IGlzIG5vdCBhbiBvYmplY3QiKTsKICAgICAgICBjb250ZXh0LmRlbGVnYXRlID0gbnVsbDsKICAgICAgICByZXR1cm4gQ29udGludWVTZW50aW5lbDsKICAgICAgfQoKICAgICAgaWYgKGluZm8uZG9uZSkgewogICAgICAgIC8vIEFzc2lnbiB0aGUgcmVzdWx0IG9mIHRoZSBmaW5pc2hlZCBkZWxlZ2F0ZSB0byB0aGUgdGVtcG9yYXJ5CiAgICAgICAgLy8gdmFyaWFibGUgc3BlY2lmaWVkIGJ5IGRlbGVnYXRlLnJlc3VsdE5hbWUgKHNlZSBkZWxlZ2F0ZVlpZWxkKS4KICAgICAgICBjb250ZXh0W2RlbGVnYXRlLnJlc3VsdE5hbWVdID0gaW5mby52YWx1ZTsKCiAgICAgICAgLy8gUmVzdW1lIGV4ZWN1dGlvbiBhdCB0aGUgZGVzaXJlZCBsb2NhdGlvbiAoc2VlIGRlbGVnYXRlWWllbGQpLgogICAgICAgIGNvbnRleHQubmV4dCA9IGRlbGVnYXRlLm5leHRMb2M7CgogICAgICAgIC8vIElmIGNvbnRleHQubWV0aG9kIHdhcyAidGhyb3ciIGJ1dCB0aGUgZGVsZWdhdGUgaGFuZGxlZCB0aGUKICAgICAgICAvLyBleGNlcHRpb24sIGxldCB0aGUgb3V0ZXIgZ2VuZXJhdG9yIHByb2NlZWQgbm9ybWFsbHkuIElmCiAgICAgICAgLy8gY29udGV4dC5tZXRob2Qgd2FzICJuZXh0IiwgZm9yZ2V0IGNvbnRleHQuYXJnIHNpbmNlIGl0IGhhcyBiZWVuCiAgICAgICAgLy8gImNvbnN1bWVkIiBieSB0aGUgZGVsZWdhdGUgaXRlcmF0b3IuIElmIGNvbnRleHQubWV0aG9kIHdhcwogICAgICAgIC8vICJyZXR1cm4iLCBhbGxvdyB0aGUgb3JpZ2luYWwgLnJldHVybiBjYWxsIHRvIGNvbnRpbnVlIGluIHRoZQogICAgICAgIC8vIG91dGVyIGdlbmVyYXRvci4KICAgICAgICBpZiAoY29udGV4dC5tZXRob2QgIT09ICJyZXR1cm4iKSB7CiAgICAgICAgICBjb250ZXh0Lm1ldGhvZCA9ICJuZXh0IjsKICAgICAgICAgIGNvbnRleHQuYXJnID0gdW5kZWZpbmVkJDE7CiAgICAgICAgfQoKICAgICAgfSBlbHNlIHsKICAgICAgICAvLyBSZS15aWVsZCB0aGUgcmVzdWx0IHJldHVybmVkIGJ5IHRoZSBkZWxlZ2F0ZSBtZXRob2QuCiAgICAgICAgcmV0dXJuIGluZm87CiAgICAgIH0KCiAgICAgIC8vIFRoZSBkZWxlZ2F0ZSBpdGVyYXRvciBpcyBmaW5pc2hlZCwgc28gZm9yZ2V0IGl0IGFuZCBjb250aW51ZSB3aXRoCiAgICAgIC8vIHRoZSBvdXRlciBnZW5lcmF0b3IuCiAgICAgIGNvbnRleHQuZGVsZWdhdGUgPSBudWxsOwogICAgICByZXR1cm4gQ29udGludWVTZW50aW5lbDsKICAgIH0KCiAgICAvLyBEZWZpbmUgR2VuZXJhdG9yLnByb3RvdHlwZS57bmV4dCx0aHJvdyxyZXR1cm59IGluIHRlcm1zIG9mIHRoZQogICAgLy8gdW5pZmllZCAuX2ludm9rZSBoZWxwZXIgbWV0aG9kLgogICAgZGVmaW5lSXRlcmF0b3JNZXRob2RzKEdwKTsKCiAgICBkZWZpbmUoR3AsIHRvU3RyaW5nVGFnU3ltYm9sLCAiR2VuZXJhdG9yIik7CgogICAgLy8gQSBHZW5lcmF0b3Igc2hvdWxkIGFsd2F5cyByZXR1cm4gaXRzZWxmIGFzIHRoZSBpdGVyYXRvciBvYmplY3Qgd2hlbiB0aGUKICAgIC8vIEBAaXRlcmF0b3IgZnVuY3Rpb24gaXMgY2FsbGVkIG9uIGl0LiBTb21lIGJyb3dzZXJzJyBpbXBsZW1lbnRhdGlvbnMgb2YgdGhlCiAgICAvLyBpdGVyYXRvciBwcm90b3R5cGUgY2hhaW4gaW5jb3JyZWN0bHkgaW1wbGVtZW50IHRoaXMsIGNhdXNpbmcgdGhlIEdlbmVyYXRvcgogICAgLy8gb2JqZWN0IHRvIG5vdCBiZSByZXR1cm5lZCBmcm9tIHRoaXMgY2FsbC4gVGhpcyBlbnN1cmVzIHRoYXQgZG9lc24ndCBoYXBwZW4uCiAgICAvLyBTZWUgaHR0cHM6Ly9naXRodWIuY29tL2ZhY2Vib29rL3JlZ2VuZXJhdG9yL2lzc3Vlcy8yNzQgZm9yIG1vcmUgZGV0YWlscy4KICAgIGRlZmluZShHcCwgaXRlcmF0b3JTeW1ib2wsIGZ1bmN0aW9uKCkgewogICAgICByZXR1cm4gdGhpczsKICAgIH0pOwoKICAgIGRlZmluZShHcCwgInRvU3RyaW5nIiwgZnVuY3Rpb24oKSB7CiAgICAgIHJldHVybiAiW29iamVjdCBHZW5lcmF0b3JdIjsKICAgIH0pOwoKICAgIGZ1bmN0aW9uIHB1c2hUcnlFbnRyeShsb2NzKSB7CiAgICAgIHZhciBlbnRyeSA9IHsgdHJ5TG9jOiBsb2NzWzBdIH07CgogICAgICBpZiAoMSBpbiBsb2NzKSB7CiAgICAgICAgZW50cnkuY2F0Y2hMb2MgPSBsb2NzWzFdOwogICAgICB9CgogICAgICBpZiAoMiBpbiBsb2NzKSB7CiAgICAgICAgZW50cnkuZmluYWxseUxvYyA9IGxvY3NbMl07CiAgICAgICAgZW50cnkuYWZ0ZXJMb2MgPSBsb2NzWzNdOwogICAgICB9CgogICAgICB0aGlzLnRyeUVudHJpZXMucHVzaChlbnRyeSk7CiAgICB9CgogICAgZnVuY3Rpb24gcmVzZXRUcnlFbnRyeShlbnRyeSkgewogICAgICB2YXIgcmVjb3JkID0gZW50cnkuY29tcGxldGlvbiB8fCB7fTsKICAgICAgcmVjb3JkLnR5cGUgPSAibm9ybWFsIjsKICAgICAgZGVsZXRlIHJlY29yZC5hcmc7CiAgICAgIGVudHJ5LmNvbXBsZXRpb24gPSByZWNvcmQ7CiAgICB9CgogICAgZnVuY3Rpb24gQ29udGV4dCh0cnlMb2NzTGlzdCkgewogICAgICAvLyBUaGUgcm9vdCBlbnRyeSBvYmplY3QgKGVmZmVjdGl2ZWx5IGEgdHJ5IHN0YXRlbWVudCB3aXRob3V0IGEgY2F0Y2gKICAgICAgLy8gb3IgYSBmaW5hbGx5IGJsb2NrKSBnaXZlcyB1cyBhIHBsYWNlIHRvIHN0b3JlIHZhbHVlcyB0aHJvd24gZnJvbQogICAgICAvLyBsb2NhdGlvbnMgd2hlcmUgdGhlcmUgaXMgbm8gZW5jbG9zaW5nIHRyeSBzdGF0ZW1lbnQuCiAgICAgIHRoaXMudHJ5RW50cmllcyA9IFt7IHRyeUxvYzogInJvb3QiIH1dOwogICAgICB0cnlMb2NzTGlzdC5mb3JFYWNoKHB1c2hUcnlFbnRyeSwgdGhpcyk7CiAgICAgIHRoaXMucmVzZXQodHJ1ZSk7CiAgICB9CgogICAgZXhwb3J0cy5rZXlzID0gZnVuY3Rpb24ob2JqZWN0KSB7CiAgICAgIHZhciBrZXlzID0gW107CiAgICAgIGZvciAodmFyIGtleSBpbiBvYmplY3QpIHsKICAgICAgICBrZXlzLnB1c2goa2V5KTsKICAgICAgfQogICAgICBrZXlzLnJldmVyc2UoKTsKCiAgICAgIC8vIFJhdGhlciB0aGFuIHJldHVybmluZyBhbiBvYmplY3Qgd2l0aCBhIG5leHQgbWV0aG9kLCB3ZSBrZWVwCiAgICAgIC8vIHRoaW5ncyBzaW1wbGUgYW5kIHJldHVybiB0aGUgbmV4dCBmdW5jdGlvbiBpdHNlbGYuCiAgICAgIHJldHVybiBmdW5jdGlvbiBuZXh0KCkgewogICAgICAgIHdoaWxlIChrZXlzLmxlbmd0aCkgewogICAgICAgICAgdmFyIGtleSA9IGtleXMucG9wKCk7CiAgICAgICAgICBpZiAoa2V5IGluIG9iamVjdCkgewogICAgICAgICAgICBuZXh0LnZhbHVlID0ga2V5OwogICAgICAgICAgICBuZXh0LmRvbmUgPSBmYWxzZTsKICAgICAgICAgICAgcmV0dXJuIG5leHQ7CiAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICAvLyBUbyBhdm9pZCBjcmVhdGluZyBhbiBhZGRpdGlvbmFsIG9iamVjdCwgd2UganVzdCBoYW5nIHRoZSAudmFsdWUKICAgICAgICAvLyBhbmQgLmRvbmUgcHJvcGVydGllcyBvZmYgdGhlIG5leHQgZnVuY3Rpb24gb2JqZWN0IGl0c2VsZi4gVGhpcwogICAgICAgIC8vIGFsc28gZW5zdXJlcyB0aGF0IHRoZSBtaW5pZmllciB3aWxsIG5vdCBhbm9ueW1pemUgdGhlIGZ1bmN0aW9uLgogICAgICAgIG5leHQuZG9uZSA9IHRydWU7CiAgICAgICAgcmV0dXJuIG5leHQ7CiAgICAgIH07CiAgICB9OwoKICAgIGZ1bmN0aW9uIHZhbHVlcyhpdGVyYWJsZSkgewogICAgICBpZiAoaXRlcmFibGUpIHsKICAgICAgICB2YXIgaXRlcmF0b3JNZXRob2QgPSBpdGVyYWJsZVtpdGVyYXRvclN5bWJvbF07CiAgICAgICAgaWYgKGl0ZXJhdG9yTWV0aG9kKSB7CiAgICAgICAgICByZXR1cm4gaXRlcmF0b3JNZXRob2QuY2FsbChpdGVyYWJsZSk7CiAgICAgICAgfQoKICAgICAgICBpZiAodHlwZW9mIGl0ZXJhYmxlLm5leHQgPT09ICJmdW5jdGlvbiIpIHsKICAgICAgICAgIHJldHVybiBpdGVyYWJsZTsKICAgICAgICB9CgogICAgICAgIGlmICghaXNOYU4oaXRlcmFibGUubGVuZ3RoKSkgewogICAgICAgICAgdmFyIGkgPSAtMSwgbmV4dCA9IGZ1bmN0aW9uIG5leHQoKSB7CiAgICAgICAgICAgIHdoaWxlICgrK2kgPCBpdGVyYWJsZS5sZW5ndGgpIHsKICAgICAgICAgICAgICBpZiAoaGFzT3duLmNhbGwoaXRlcmFibGUsIGkpKSB7CiAgICAgICAgICAgICAgICBuZXh0LnZhbHVlID0gaXRlcmFibGVbaV07CiAgICAgICAgICAgICAgICBuZXh0LmRvbmUgPSBmYWxzZTsKICAgICAgICAgICAgICAgIHJldHVybiBuZXh0OwogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQoKICAgICAgICAgICAgbmV4dC52YWx1ZSA9IHVuZGVmaW5lZCQxOwogICAgICAgICAgICBuZXh0LmRvbmUgPSB0cnVlOwoKICAgICAgICAgICAgcmV0dXJuIG5leHQ7CiAgICAgICAgICB9OwoKICAgICAgICAgIHJldHVybiBuZXh0Lm5leHQgPSBuZXh0OwogICAgICAgIH0KICAgICAgfQoKICAgICAgLy8gUmV0dXJuIGFuIGl0ZXJhdG9yIHdpdGggbm8gdmFsdWVzLgogICAgICByZXR1cm4geyBuZXh0OiBkb25lUmVzdWx0IH07CiAgICB9CiAgICBleHBvcnRzLnZhbHVlcyA9IHZhbHVlczsKCiAgICBmdW5jdGlvbiBkb25lUmVzdWx0KCkgewogICAgICByZXR1cm4geyB2YWx1ZTogdW5kZWZpbmVkJDEsIGRvbmU6IHRydWUgfTsKICAgIH0KCiAgICBDb250ZXh0LnByb3RvdHlwZSA9IHsKICAgICAgY29uc3RydWN0b3I6IENvbnRleHQsCgogICAgICByZXNldDogZnVuY3Rpb24oc2tpcFRlbXBSZXNldCkgewogICAgICAgIHRoaXMucHJldiA9IDA7CiAgICAgICAgdGhpcy5uZXh0ID0gMDsKICAgICAgICAvLyBSZXNldHRpbmcgY29udGV4dC5fc2VudCBmb3IgbGVnYWN5IHN1cHBvcnQgb2YgQmFiZWwncwogICAgICAgIC8vIGZ1bmN0aW9uLnNlbnQgaW1wbGVtZW50YXRpb24uCiAgICAgICAgdGhpcy5zZW50ID0gdGhpcy5fc2VudCA9IHVuZGVmaW5lZCQxOwogICAgICAgIHRoaXMuZG9uZSA9IGZhbHNlOwogICAgICAgIHRoaXMuZGVsZWdhdGUgPSBudWxsOwoKICAgICAgICB0aGlzLm1ldGhvZCA9ICJuZXh0IjsKICAgICAgICB0aGlzLmFyZyA9IHVuZGVmaW5lZCQxOwoKICAgICAgICB0aGlzLnRyeUVudHJpZXMuZm9yRWFjaChyZXNldFRyeUVudHJ5KTsKCiAgICAgICAgaWYgKCFza2lwVGVtcFJlc2V0KSB7CiAgICAgICAgICBmb3IgKHZhciBuYW1lIGluIHRoaXMpIHsKICAgICAgICAgICAgLy8gTm90IHN1cmUgYWJvdXQgdGhlIG9wdGltYWwgb3JkZXIgb2YgdGhlc2UgY29uZGl0aW9uczoKICAgICAgICAgICAgaWYgKG5hbWUuY2hhckF0KDApID09PSAidCIgJiYKICAgICAgICAgICAgICAgIGhhc093bi5jYWxsKHRoaXMsIG5hbWUpICYmCiAgICAgICAgICAgICAgICAhaXNOYU4oK25hbWUuc2xpY2UoMSkpKSB7CiAgICAgICAgICAgICAgdGhpc1tuYW1lXSA9IHVuZGVmaW5lZCQxOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9LAoKICAgICAgc3RvcDogZnVuY3Rpb24oKSB7CiAgICAgICAgdGhpcy5kb25lID0gdHJ1ZTsKCiAgICAgICAgdmFyIHJvb3RFbnRyeSA9IHRoaXMudHJ5RW50cmllc1swXTsKICAgICAgICB2YXIgcm9vdFJlY29yZCA9IHJvb3RFbnRyeS5jb21wbGV0aW9uOwogICAgICAgIGlmIChyb290UmVjb3JkLnR5cGUgPT09ICJ0aHJvdyIpIHsKICAgICAgICAgIHRocm93IHJvb3RSZWNvcmQuYXJnOwogICAgICAgIH0KCiAgICAgICAgcmV0dXJuIHRoaXMucnZhbDsKICAgICAgfSwKCiAgICAgIGRpc3BhdGNoRXhjZXB0aW9uOiBmdW5jdGlvbihleGNlcHRpb24pIHsKICAgICAgICBpZiAodGhpcy5kb25lKSB7CiAgICAgICAgICB0aHJvdyBleGNlcHRpb247CiAgICAgICAgfQoKICAgICAgICB2YXIgY29udGV4dCA9IHRoaXM7CiAgICAgICAgZnVuY3Rpb24gaGFuZGxlKGxvYywgY2F1Z2h0KSB7CiAgICAgICAgICByZWNvcmQudHlwZSA9ICJ0aHJvdyI7CiAgICAgICAgICByZWNvcmQuYXJnID0gZXhjZXB0aW9uOwogICAgICAgICAgY29udGV4dC5uZXh0ID0gbG9jOwoKICAgICAgICAgIGlmIChjYXVnaHQpIHsKICAgICAgICAgICAgLy8gSWYgdGhlIGRpc3BhdGNoZWQgZXhjZXB0aW9uIHdhcyBjYXVnaHQgYnkgYSBjYXRjaCBibG9jaywKICAgICAgICAgICAgLy8gdGhlbiBsZXQgdGhhdCBjYXRjaCBibG9jayBoYW5kbGUgdGhlIGV4Y2VwdGlvbiBub3JtYWxseS4KICAgICAgICAgICAgY29udGV4dC5tZXRob2QgPSAibmV4dCI7CiAgICAgICAgICAgIGNvbnRleHQuYXJnID0gdW5kZWZpbmVkJDE7CiAgICAgICAgICB9CgogICAgICAgICAgcmV0dXJuICEhIGNhdWdodDsKICAgICAgICB9CgogICAgICAgIGZvciAodmFyIGkgPSB0aGlzLnRyeUVudHJpZXMubGVuZ3RoIC0gMTsgaSA+PSAwOyAtLWkpIHsKICAgICAgICAgIHZhciBlbnRyeSA9IHRoaXMudHJ5RW50cmllc1tpXTsKICAgICAgICAgIHZhciByZWNvcmQgPSBlbnRyeS5jb21wbGV0aW9uOwoKICAgICAgICAgIGlmIChlbnRyeS50cnlMb2MgPT09ICJyb290IikgewogICAgICAgICAgICAvLyBFeGNlcHRpb24gdGhyb3duIG91dHNpZGUgb2YgYW55IHRyeSBibG9jayB0aGF0IGNvdWxkIGhhbmRsZQogICAgICAgICAgICAvLyBpdCwgc28gc2V0IHRoZSBjb21wbGV0aW9uIHZhbHVlIG9mIHRoZSBlbnRpcmUgZnVuY3Rpb24gdG8KICAgICAgICAgICAgLy8gdGhyb3cgdGhlIGV4Y2VwdGlvbi4KICAgICAgICAgICAgcmV0dXJuIGhhbmRsZSgiZW5kIik7CiAgICAgICAgICB9CgogICAgICAgICAgaWYgKGVudHJ5LnRyeUxvYyA8PSB0aGlzLnByZXYpIHsKICAgICAgICAgICAgdmFyIGhhc0NhdGNoID0gaGFzT3duLmNhbGwoZW50cnksICJjYXRjaExvYyIpOwogICAgICAgICAgICB2YXIgaGFzRmluYWxseSA9IGhhc093bi5jYWxsKGVudHJ5LCAiZmluYWxseUxvYyIpOwoKICAgICAgICAgICAgaWYgKGhhc0NhdGNoICYmIGhhc0ZpbmFsbHkpIHsKICAgICAgICAgICAgICBpZiAodGhpcy5wcmV2IDwgZW50cnkuY2F0Y2hMb2MpIHsKICAgICAgICAgICAgICAgIHJldHVybiBoYW5kbGUoZW50cnkuY2F0Y2hMb2MsIHRydWUpOwogICAgICAgICAgICAgIH0gZWxzZSBpZiAodGhpcy5wcmV2IDwgZW50cnkuZmluYWxseUxvYykgewogICAgICAgICAgICAgICAgcmV0dXJuIGhhbmRsZShlbnRyeS5maW5hbGx5TG9jKTsKICAgICAgICAgICAgICB9CgogICAgICAgICAgICB9IGVsc2UgaWYgKGhhc0NhdGNoKSB7CiAgICAgICAgICAgICAgaWYgKHRoaXMucHJldiA8IGVudHJ5LmNhdGNoTG9jKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gaGFuZGxlKGVudHJ5LmNhdGNoTG9jLCB0cnVlKTsKICAgICAgICAgICAgICB9CgogICAgICAgICAgICB9IGVsc2UgaWYgKGhhc0ZpbmFsbHkpIHsKICAgICAgICAgICAgICBpZiAodGhpcy5wcmV2IDwgZW50cnkuZmluYWxseUxvYykgewogICAgICAgICAgICAgICAgcmV0dXJuIGhhbmRsZShlbnRyeS5maW5hbGx5TG9jKTsKICAgICAgICAgICAgICB9CgogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcigidHJ5IHN0YXRlbWVudCB3aXRob3V0IGNhdGNoIG9yIGZpbmFsbHkiKTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfSwKCiAgICAgIGFicnVwdDogZnVuY3Rpb24odHlwZSwgYXJnKSB7CiAgICAgICAgZm9yICh2YXIgaSA9IHRoaXMudHJ5RW50cmllcy5sZW5ndGggLSAxOyBpID49IDA7IC0taSkgewogICAgICAgICAgdmFyIGVudHJ5ID0gdGhpcy50cnlFbnRyaWVzW2ldOwogICAgICAgICAgaWYgKGVudHJ5LnRyeUxvYyA8PSB0aGlzLnByZXYgJiYKICAgICAgICAgICAgICBoYXNPd24uY2FsbChlbnRyeSwgImZpbmFsbHlMb2MiKSAmJgogICAgICAgICAgICAgIHRoaXMucHJldiA8IGVudHJ5LmZpbmFsbHlMb2MpIHsKICAgICAgICAgICAgdmFyIGZpbmFsbHlFbnRyeSA9IGVudHJ5OwogICAgICAgICAgICBicmVhazsKICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIGlmIChmaW5hbGx5RW50cnkgJiYKICAgICAgICAgICAgKHR5cGUgPT09ICJicmVhayIgfHwKICAgICAgICAgICAgIHR5cGUgPT09ICJjb250aW51ZSIpICYmCiAgICAgICAgICAgIGZpbmFsbHlFbnRyeS50cnlMb2MgPD0gYXJnICYmCiAgICAgICAgICAgIGFyZyA8PSBmaW5hbGx5RW50cnkuZmluYWxseUxvYykgewogICAgICAgICAgLy8gSWdub3JlIHRoZSBmaW5hbGx5IGVudHJ5IGlmIGNvbnRyb2wgaXMgbm90IGp1bXBpbmcgdG8gYQogICAgICAgICAgLy8gbG9jYXRpb24gb3V0c2lkZSB0aGUgdHJ5L2NhdGNoIGJsb2NrLgogICAgICAgICAgZmluYWxseUVudHJ5ID0gbnVsbDsKICAgICAgICB9CgogICAgICAgIHZhciByZWNvcmQgPSBmaW5hbGx5RW50cnkgPyBmaW5hbGx5RW50cnkuY29tcGxldGlvbiA6IHt9OwogICAgICAgIHJlY29yZC50eXBlID0gdHlwZTsKICAgICAgICByZWNvcmQuYXJnID0gYXJnOwoKICAgICAgICBpZiAoZmluYWxseUVudHJ5KSB7CiAgICAgICAgICB0aGlzLm1ldGhvZCA9ICJuZXh0IjsKICAgICAgICAgIHRoaXMubmV4dCA9IGZpbmFsbHlFbnRyeS5maW5hbGx5TG9jOwogICAgICAgICAgcmV0dXJuIENvbnRpbnVlU2VudGluZWw7CiAgICAgICAgfQoKICAgICAgICByZXR1cm4gdGhpcy5jb21wbGV0ZShyZWNvcmQpOwogICAgICB9LAoKICAgICAgY29tcGxldGU6IGZ1bmN0aW9uKHJlY29yZCwgYWZ0ZXJMb2MpIHsKICAgICAgICBpZiAocmVjb3JkLnR5cGUgPT09ICJ0aHJvdyIpIHsKICAgICAgICAgIHRocm93IHJlY29yZC5hcmc7CiAgICAgICAgfQoKICAgICAgICBpZiAocmVjb3JkLnR5cGUgPT09ICJicmVhayIgfHwKICAgICAgICAgICAgcmVjb3JkLnR5cGUgPT09ICJjb250aW51ZSIpIHsKICAgICAgICAgIHRoaXMubmV4dCA9IHJlY29yZC5hcmc7CiAgICAgICAgfSBlbHNlIGlmIChyZWNvcmQudHlwZSA9PT0gInJldHVybiIpIHsKICAgICAgICAgIHRoaXMucnZhbCA9IHRoaXMuYXJnID0gcmVjb3JkLmFyZzsKICAgICAgICAgIHRoaXMubWV0aG9kID0gInJldHVybiI7CiAgICAgICAgICB0aGlzLm5leHQgPSAiZW5kIjsKICAgICAgICB9IGVsc2UgaWYgKHJlY29yZC50eXBlID09PSAibm9ybWFsIiAmJiBhZnRlckxvYykgewogICAgICAgICAgdGhpcy5uZXh0ID0gYWZ0ZXJMb2M7CiAgICAgICAgfQoKICAgICAgICByZXR1cm4gQ29udGludWVTZW50aW5lbDsKICAgICAgfSwKCiAgICAgIGZpbmlzaDogZnVuY3Rpb24oZmluYWxseUxvYykgewogICAgICAgIGZvciAodmFyIGkgPSB0aGlzLnRyeUVudHJpZXMubGVuZ3RoIC0gMTsgaSA+PSAwOyAtLWkpIHsKICAgICAgICAgIHZhciBlbnRyeSA9IHRoaXMudHJ5RW50cmllc1tpXTsKICAgICAgICAgIGlmIChlbnRyeS5maW5hbGx5TG9jID09PSBmaW5hbGx5TG9jKSB7CiAgICAgICAgICAgIHRoaXMuY29tcGxldGUoZW50cnkuY29tcGxldGlvbiwgZW50cnkuYWZ0ZXJMb2MpOwogICAgICAgICAgICByZXNldFRyeUVudHJ5KGVudHJ5KTsKICAgICAgICAgICAgcmV0dXJuIENvbnRpbnVlU2VudGluZWw7CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9LAoKICAgICAgImNhdGNoIjogZnVuY3Rpb24odHJ5TG9jKSB7CiAgICAgICAgZm9yICh2YXIgaSA9IHRoaXMudHJ5RW50cmllcy5sZW5ndGggLSAxOyBpID49IDA7IC0taSkgewogICAgICAgICAgdmFyIGVudHJ5ID0gdGhpcy50cnlFbnRyaWVzW2ldOwogICAgICAgICAgaWYgKGVudHJ5LnRyeUxvYyA9PT0gdHJ5TG9jKSB7CiAgICAgICAgICAgIHZhciByZWNvcmQgPSBlbnRyeS5jb21wbGV0aW9uOwogICAgICAgICAgICBpZiAocmVjb3JkLnR5cGUgPT09ICJ0aHJvdyIpIHsKICAgICAgICAgICAgICB2YXIgdGhyb3duID0gcmVjb3JkLmFyZzsKICAgICAgICAgICAgICByZXNldFRyeUVudHJ5KGVudHJ5KTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gdGhyb3duOwogICAgICAgICAgfQogICAgICAgIH0KCiAgICAgICAgLy8gVGhlIGNvbnRleHQuY2F0Y2ggbWV0aG9kIG11c3Qgb25seSBiZSBjYWxsZWQgd2l0aCBhIGxvY2F0aW9uCiAgICAgICAgLy8gYXJndW1lbnQgdGhhdCBjb3JyZXNwb25kcyB0byBhIGtub3duIGNhdGNoIGJsb2NrLgogICAgICAgIHRocm93IG5ldyBFcnJvcigiaWxsZWdhbCBjYXRjaCBhdHRlbXB0Iik7CiAgICAgIH0sCgogICAgICBkZWxlZ2F0ZVlpZWxkOiBmdW5jdGlvbihpdGVyYWJsZSwgcmVzdWx0TmFtZSwgbmV4dExvYykgewogICAgICAgIHRoaXMuZGVsZWdhdGUgPSB7CiAgICAgICAgICBpdGVyYXRvcjogdmFsdWVzKGl0ZXJhYmxlKSwKICAgICAgICAgIHJlc3VsdE5hbWU6IHJlc3VsdE5hbWUsCiAgICAgICAgICBuZXh0TG9jOiBuZXh0TG9jCiAgICAgICAgfTsKCiAgICAgICAgaWYgKHRoaXMubWV0aG9kID09PSAibmV4dCIpIHsKICAgICAgICAgIC8vIERlbGliZXJhdGVseSBmb3JnZXQgdGhlIGxhc3Qgc2VudCB2YWx1ZSBzbyB0aGF0IHdlIGRvbid0CiAgICAgICAgICAvLyBhY2NpZGVudGFsbHkgcGFzcyBpdCBvbiB0byB0aGUgZGVsZWdhdGUuCiAgICAgICAgICB0aGlzLmFyZyA9IHVuZGVmaW5lZCQxOwogICAgICAgIH0KCiAgICAgICAgcmV0dXJuIENvbnRpbnVlU2VudGluZWw7CiAgICAgIH0KICAgIH07CgogICAgLy8gUmVnYXJkbGVzcyBvZiB3aGV0aGVyIHRoaXMgc2NyaXB0IGlzIGV4ZWN1dGluZyBhcyBhIENvbW1vbkpTIG1vZHVsZQogICAgLy8gb3Igbm90LCByZXR1cm4gdGhlIHJ1bnRpbWUgb2JqZWN0IHNvIHRoYXQgd2UgY2FuIGRlY2xhcmUgdGhlIHZhcmlhYmxlCiAgICAvLyByZWdlbmVyYXRvclJ1bnRpbWUgaW4gdGhlIG91dGVyIHNjb3BlLCB3aGljaCBhbGxvd3MgdGhpcyBtb2R1bGUgdG8gYmUKICAgIC8vIGluamVjdGVkIGVhc2lseSBieSBgYmluL3JlZ2VuZXJhdG9yIC0taW5jbHVkZS1ydW50aW1lIHNjcmlwdC5qc2AuCiAgICByZXR1cm4gZXhwb3J0czsKCiAgfSgKICAgIC8vIElmIHRoaXMgc2NyaXB0IGlzIGV4ZWN1dGluZyBhcyBhIENvbW1vbkpTIG1vZHVsZSwgdXNlIG1vZHVsZS5leHBvcnRzCiAgICAvLyBhcyB0aGUgcmVnZW5lcmF0b3JSdW50aW1lIG5hbWVzcGFjZS4gT3RoZXJ3aXNlIGNyZWF0ZSBhIG5ldyBlbXB0eQogICAgLy8gb2JqZWN0LiBFaXRoZXIgd2F5LCB0aGUgcmVzdWx0aW5nIG9iamVjdCB3aWxsIGJlIHVzZWQgdG8gaW5pdGlhbGl6ZQogICAgLy8gdGhlIHJlZ2VuZXJhdG9yUnVudGltZSB2YXJpYWJsZSBhdCB0aGUgdG9wIG9mIHRoaXMgZmlsZS4KICAgIG1vZHVsZS5leHBvcnRzIAogICkpOwoKICB0cnkgewogICAgcmVnZW5lcmF0b3JSdW50aW1lID0gcnVudGltZTsKICB9IGNhdGNoIChhY2NpZGVudGFsU3RyaWN0TW9kZSkgewogICAgLy8gVGhpcyBtb2R1bGUgc2hvdWxkIG5vdCBiZSBydW5uaW5nIGluIHN0cmljdCBtb2RlLCBzbyB0aGUgYWJvdmUKICAgIC8vIGFzc2lnbm1lbnQgc2hvdWxkIGFsd2F5cyB3b3JrIHVubGVzcyBzb21ldGhpbmcgaXMgbWlzY29uZmlndXJlZC4gSnVzdAogICAgLy8gaW4gY2FzZSBydW50aW1lLmpzIGFjY2lkZW50YWxseSBydW5zIGluIHN0cmljdCBtb2RlLCBpbiBtb2Rlcm4gZW5naW5lcwogICAgLy8gd2UgY2FuIGV4cGxpY2l0bHkgYWNjZXNzIGdsb2JhbFRoaXMuIEluIG9sZGVyIGVuZ2luZXMgd2UgY2FuIGVzY2FwZQogICAgLy8gc3RyaWN0IG1vZGUgdXNpbmcgYSBnbG9iYWwgRnVuY3Rpb24gY2FsbC4gVGhpcyBjb3VsZCBjb25jZWl2YWJseSBmYWlsCiAgICAvLyBpZiBhIENvbnRlbnQgU2VjdXJpdHkgUG9saWN5IGZvcmJpZHMgdXNpbmcgRnVuY3Rpb24sIGJ1dCBpbiB0aGF0IGNhc2UKICAgIC8vIHRoZSBwcm9wZXIgc29sdXRpb24gaXMgdG8gZml4IHRoZSBhY2NpZGVudGFsIHN0cmljdCBtb2RlIHByb2JsZW0uIElmCiAgICAvLyB5b3UndmUgbWlzY29uZmlndXJlZCB5b3VyIGJ1bmRsZXIgdG8gZm9yY2Ugc3RyaWN0IG1vZGUgYW5kIGFwcGxpZWQgYQogICAgLy8gQ1NQIHRvIGZvcmJpZCBGdW5jdGlvbiwgYW5kIHlvdSdyZSBub3Qgd2lsbGluZyB0byBmaXggZWl0aGVyIG9mIHRob3NlCiAgICAvLyBwcm9ibGVtcywgcGxlYXNlIGRldGFpbCB5b3VyIHVuaXF1ZSBwcmVkaWNhbWVudCBpbiBhIEdpdEh1YiBpc3N1ZS4KICAgIGlmICh0eXBlb2YgZ2xvYmFsVGhpcyA9PT0gIm9iamVjdCIpIHsKICAgICAgZ2xvYmFsVGhpcy5yZWdlbmVyYXRvclJ1bnRpbWUgPSBydW50aW1lOwogICAgfSBlbHNlIHsKICAgICAgRnVuY3Rpb24oInIiLCAicmVnZW5lcmF0b3JSdW50aW1lID0gciIpKHJ1bnRpbWUpOwogICAgfQogIH0KICB9KTsKCiAgdmFyIG1hcnRpbmkgPSBudWxsOwoKICBmdW5jdGlvbiBkZWNvZGVUZXJyYWluKHBhcmFtZXRlcnMsIHRyYW5zZmVyYWJsZU9iamVjdHMpIHsKICAgIHZhciBfbWFydGluaTsKCiAgICB2YXIgaW1hZ2VEYXRhID0gcGFyYW1ldGVycy5pbWFnZURhdGEsCiAgICAgICAgX3BhcmFtZXRlcnMkdGlsZVNpemUgPSBwYXJhbWV0ZXJzLnRpbGVTaXplLAogICAgICAgIHRpbGVTaXplID0gX3BhcmFtZXRlcnMkdGlsZVNpemUgPT09IHZvaWQgMCA/IDI1NiA6IF9wYXJhbWV0ZXJzJHRpbGVTaXplLAogICAgICAgIGVycm9yTGV2ZWwgPSBwYXJhbWV0ZXJzLmVycm9yTGV2ZWwsCiAgICAgICAgaW50ZXJ2YWwgPSBwYXJhbWV0ZXJzLmludGVydmFsLAogICAgICAgIG9mZnNldCA9IHBhcmFtZXRlcnMub2Zmc2V0OwogICAgdmFyIHBpeGVscyA9IG5kYXJyYXkobmV3IFVpbnQ4QXJyYXkoaW1hZ2VEYXRhKSwgW3RpbGVTaXplLCB0aWxlU2l6ZSwgNF0sIFs0LCA0ICogdGlsZVNpemUsIDFdLCAwKTsgLy8gVGlsZSBzaXplIG11c3QgYmUgbWFpbnRhaW5lZCB0aHJvdWdoIHRoZSBsaWZlIG9mIHRoZSB3b3JrZXIKCiAgICAoX21hcnRpbmkgPSBtYXJ0aW5pKSAhPT0gbnVsbCAmJiBfbWFydGluaSAhPT0gdm9pZCAwID8gX21hcnRpbmkgOiBtYXJ0aW5pID0gbmV3IE1hcnRpbmkodGlsZVNpemUgKyAxKTsKICAgIHZhciB0ZXJyYWluID0gbWFwYm94VGVycmFpblRvR3JpZChwaXhlbHMsIGludGVydmFsLCBvZmZzZXQpOwogICAgdmFyIHRpbGUgPSBtYXJ0aW5pLmNyZWF0ZVRpbGUodGVycmFpbik7IC8vIGdldCBhIG1lc2ggKHZlcnRpY2VzIGFuZCB0cmlhbmdsZXMgaW5kaWNlcykgZm9yIGEgMTBtIGVycm9yCgogICAgdmFyIG1lc2ggPSB0aWxlLmdldE1lc2goZXJyb3JMZXZlbCwgcGFyYW1ldGVycy5tYXhMZW5ndGgpOwogICAgcmV0dXJuIGNyZWF0ZVF1YW50aXplZE1lc2hEYXRhKHRpbGUsIG1lc2gsIHRpbGVTaXplKTsKICB9CgogIHNlbGYub25tZXNzYWdlID0gZnVuY3Rpb24gKG1zZykgewogICAgdmFyIF9tc2ckZGF0YSA9IG1zZy5kYXRhLAogICAgICAgIGlkID0gX21zZyRkYXRhLmlkLAogICAgICAgIHBheWxvYWQgPSBfbXNnJGRhdGEucGF5bG9hZDsKICAgIGlmIChpZCA9PSBudWxsKSByZXR1cm47CiAgICB2YXIgb2JqZWN0cyA9IFtdOwogICAgdmFyIHJlcyA9IG51bGw7CgogICAgdHJ5IHsKICAgICAgcmVzID0gZGVjb2RlVGVycmFpbihwYXlsb2FkKTsKICAgICAgb2JqZWN0cy5wdXNoKHJlcy5pbmRpY2VzLmJ1ZmZlcik7CiAgICAgIG9iamVjdHMucHVzaChyZXMucXVhbnRpemVkVmVydGljZXMuYnVmZmVyKTsKICAgICAgc2VsZi5wb3N0TWVzc2FnZSh7CiAgICAgICAgaWQ6IGlkLAogICAgICAgIHBheWxvYWQ6IHJlcwogICAgICB9LCBvYmplY3RzKTsKICAgIH0gY2F0Y2ggKGVycikgewogICAgICBzZWxmLnBvc3RNZXNzYWdlKHsKICAgICAgICBpZDogaWQsCiAgICAgICAgZXJyOiBlcnIudG9TdHJpbmcoKQogICAgICB9KTsKICAgIH0gZmluYWxseSB7CiAgICAgIHJlcyA9IG51bGw7CiAgICAgIG9iamVjdHMgPSBudWxsOwogICAgfQogIH07CgogIGV4cG9ydHMuZGVjb2RlVGVycmFpbiA9IGRlY29kZVRlcnJhaW47CgogIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCAnX19lc01vZHVsZScsIHsgdmFsdWU6IHRydWUgfSk7CgogIHJldHVybiBleHBvcnRzOwoKfSkoe30pOwoK', null, false);
328
481
  /* eslint-enable */
329
482
 
330
483
  var resolves = {};
@@ -409,20 +562,17 @@ var WorkerFarm = /*#__PURE__*/function () {
409
562
  key: "scheduleTask",
410
563
  value: function () {
411
564
  var _scheduleTask = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(params, transferableObjects) {
412
- var res;
413
565
  return regeneratorRuntime.wrap(function _callee$(_context) {
414
566
  while (1) {
415
567
  switch (_context.prev = _context.next) {
416
568
  case 0:
417
- console.log(params);
418
- _context.next = 3;
569
+ _context.next = 2;
419
570
  return sendMessage(this.worker, params, transferableObjects);
420
571
 
421
- case 3:
422
- res = _context.sent;
423
- return _context.abrupt("return", res);
572
+ case 2:
573
+ return _context.abrupt("return", _context.sent);
424
574
 
425
- case 5:
575
+ case 3:
426
576
  case "end":
427
577
  return _context.stop();
428
578
  }
@@ -444,12 +594,16 @@ var WorkerFarm = /*#__PURE__*/function () {
444
594
  // We should save these
445
595
  //const canvas = new OffscreenCanvas(256, 256);
446
596
  //const ctx = canvas.getContext("2d");
447
- function mapboxTerrainToGrid(png) {
597
+ function mapboxTerrainToGrid(png, interval, offset) {
598
+ var _interval, _offset;
599
+
448
600
  // maybe we should do this on the GPU using REGL?
449
601
  // but that would require GPU -> CPU -> GPU
450
602
  var gridSize = png.shape[0] + 1;
451
603
  var terrain = new Float32Array(gridSize * gridSize);
452
- var tileSize = png.shape[0]; // decode terrain values
604
+ var tileSize = png.shape[0];
605
+ interval = (_interval = interval) !== null && _interval !== void 0 ? _interval : 0.1;
606
+ offset = (_offset = offset) !== null && _offset !== void 0 ? _offset : -10000; // decode terrain values
453
607
 
454
608
  for (var y = 0; y < tileSize; y++) {
455
609
  for (var x = 0; x < tileSize; x++) {
@@ -457,7 +611,7 @@ function mapboxTerrainToGrid(png) {
457
611
  var r = png.get(x, yc, 0);
458
612
  var g = png.get(x, yc, 1);
459
613
  var b = png.get(x, yc, 2);
460
- terrain[y * gridSize + x] = r * 256 * 256 / 10.0 + g * 256.0 / 10.0 + b / 10.0 - 10000.0;
614
+ terrain[y * gridSize + x] = r * 256 * 256 * interval + g * 256.0 * interval + b * interval + offset;
461
615
  }
462
616
  } // backfill right and bottom borders
463
617
 
@@ -473,8 +627,75 @@ function mapboxTerrainToGrid(png) {
473
627
  return terrain;
474
628
  }
475
629
 
476
- function createQuantizedMeshData(tile, mesh) {
477
- var tileSize = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 256;
630
+ function _emptyMesh(n) {
631
+ n = Math.max(n, 2);
632
+ var nTriangles = Math.pow(n - 1, 2) * 2;
633
+ var nVertices = Math.pow(n, 2);
634
+ var quantizedVertices = new Uint16Array(nVertices * 3);
635
+ var indices = new Uint16Array(nTriangles * 3);
636
+ var westIndices = [];
637
+ var southIndices = [];
638
+ var eastIndices = [];
639
+ var northIndices = [];
640
+ var tix = 0;
641
+
642
+ for (var i = 0; i < nVertices; i++) {
643
+ var rx = i % n; //* 32767) / (n - 1);
644
+
645
+ var ry = Math.floor(i / n); //* 32767) / (n - 1);
646
+
647
+ var ix = n * rx + ry;
648
+ quantizedVertices[ix] = rx * 32768 / (n - 1);
649
+ quantizedVertices[nVertices + ix] = ry * 32768 / (n - 1);
650
+ quantizedVertices[2 * nVertices + ix] = 0;
651
+ if (ry == 0) westIndices.push(ix);
652
+ if (rx == 0) southIndices.push(ix);
653
+ if (rx == n - 1) eastIndices.push(ix);
654
+ if (ry == n - 1) northIndices.push(ix); // Add triangles
655
+
656
+ var rix = i - ry * n;
657
+
658
+ if (rix != n - 1) {
659
+ indices[tix * 3] = i;
660
+ indices[tix * 3 + 1] = i + n + 1;
661
+ indices[tix * 3 + 2] = i + 1;
662
+ tix++;
663
+ }
664
+
665
+ if (rix != 0) {
666
+ indices[tix * 3] = i - 1;
667
+ indices[tix * 3 + 1] = i + n - 1;
668
+ indices[tix * 3 + 2] = i + n;
669
+ tix++;
670
+ }
671
+ }
672
+
673
+ return {
674
+ minimumHeight: 0,
675
+ maximumHeight: 0,
676
+ quantizedVertices: quantizedVertices,
677
+ indices: indices,
678
+ westIndices: westIndices,
679
+ southIndices: southIndices,
680
+ eastIndices: eastIndices,
681
+ northIndices: northIndices
682
+ };
683
+ }
684
+
685
+ var _meshCache = [];
686
+ function emptyMesh(n) {
687
+ // A memoized function to return empty meshes
688
+ if (n in _meshCache) {
689
+ return _meshCache[n];
690
+ } else {
691
+ var result = _emptyMesh(n);
692
+
693
+ _meshCache[n] = result;
694
+ return result;
695
+ }
696
+ }
697
+
698
+ function createQuantizedMeshData(tile, mesh, tileSize) {
478
699
  var xvals = [];
479
700
  var yvals = [];
480
701
  var heightMeters = [];
@@ -482,28 +703,32 @@ function createQuantizedMeshData(tile, mesh) {
482
703
  var southIndices = [];
483
704
  var eastIndices = [];
484
705
  var westIndices = [];
706
+ var minimumHeight = Infinity;
707
+ var maximumHeight = -Infinity;
708
+ var scalar = 32768.0 / tileSize;
485
709
 
486
710
  for (var ix = 0; ix < mesh.vertices.length / 2; ix++) {
487
711
  var vertexIx = ix;
488
712
  var px = mesh.vertices[ix * 2];
489
713
  var py = mesh.vertices[ix * 2 + 1];
490
- heightMeters.push(tile.terrain[py * (tileSize + 1) + px]);
714
+ var height = tile.terrain[py * (tileSize + 1) + px];
715
+ if (height > maximumHeight) maximumHeight = height;
716
+ if (height < minimumHeight) minimumHeight = height;
717
+ heightMeters.push(height);
491
718
  if (py == 0) northIndices.push(vertexIx);
492
719
  if (py == tileSize) southIndices.push(vertexIx);
493
720
  if (px == 0) westIndices.push(vertexIx);
494
721
  if (px == tileSize) eastIndices.push(vertexIx);
495
- var scalar = 32768.0 / tileSize;
496
722
  var xv = px * scalar;
497
723
  var yv = (tileSize - py) * scalar;
498
724
  xvals.push(xv);
499
725
  yvals.push(yv);
500
726
  }
501
727
 
502
- var maxHeight = Math.max.apply(this, heightMeters);
503
- var minHeight = Math.min.apply(this, heightMeters);
728
+ var heightRange = maximumHeight - minimumHeight;
504
729
  var heights = heightMeters.map(function (d) {
505
- if (maxHeight - minHeight < 1) return 0;
506
- return (d - minHeight) * (32767.0 / (maxHeight - minHeight));
730
+ if (heightRange < 1) return 0;
731
+ return (d - minimumHeight) * (32767.0 / heightRange);
507
732
  });
508
733
  var triangles = new Uint16Array(mesh.triangles);
509
734
  var quantizedVertices = new Uint16Array( //verts
@@ -511,8 +736,8 @@ function createQuantizedMeshData(tile, mesh) {
511
736
  // NE NW SE
512
737
 
513
738
  return {
514
- minimumHeight: minHeight,
515
- maximumHeight: maxHeight,
739
+ minimumHeight: minimumHeight,
740
+ maximumHeight: maximumHeight,
516
741
  quantizedVertices: quantizedVertices,
517
742
  indices: triangles,
518
743
  westIndices: westIndices,
@@ -834,66 +1059,252 @@ function arrayDType(data) {
834
1059
  return "biguint64"
835
1060
  }
836
1061
  }
837
- if(Array.isArray(data)) {
838
- return "array"
839
- }
840
- return "generic"
841
- }
1062
+ if(Array.isArray(data)) {
1063
+ return "array"
1064
+ }
1065
+ return "generic"
1066
+ }
1067
+
1068
+ var CACHED_CONSTRUCTORS = {
1069
+ "float32":[],
1070
+ "float64":[],
1071
+ "int8":[],
1072
+ "int16":[],
1073
+ "int32":[],
1074
+ "uint8":[],
1075
+ "uint16":[],
1076
+ "uint32":[],
1077
+ "array":[],
1078
+ "uint8_clamped":[],
1079
+ "bigint64": [],
1080
+ "biguint64": [],
1081
+ "buffer":[],
1082
+ "generic":[]
1083
+ }
1084
+
1085
+ ;
1086
+ function wrappedNDArrayCtor(data, shape, stride, offset) {
1087
+ if(data === undefined) {
1088
+ var ctor = CACHED_CONSTRUCTORS.array[0];
1089
+ return ctor([])
1090
+ } else if(typeof data === "number") {
1091
+ data = [data];
1092
+ }
1093
+ if(shape === undefined) {
1094
+ shape = [ data.length ];
1095
+ }
1096
+ var d = shape.length;
1097
+ if(stride === undefined) {
1098
+ stride = new Array(d);
1099
+ for(var i=d-1, sz=1; i>=0; --i) {
1100
+ stride[i] = sz;
1101
+ sz *= shape[i];
1102
+ }
1103
+ }
1104
+ if(offset === undefined) {
1105
+ offset = 0;
1106
+ for(var i=0; i<d; ++i) {
1107
+ if(stride[i] < 0) {
1108
+ offset -= (shape[i]-1)*stride[i];
1109
+ }
1110
+ }
1111
+ }
1112
+ var dtype = arrayDType(data);
1113
+ var ctor_list = CACHED_CONSTRUCTORS[dtype];
1114
+ while(ctor_list.length <= d+1) {
1115
+ ctor_list.push(compileConstructor(dtype, ctor_list.length-1));
1116
+ }
1117
+ var ctor = ctor_list[d+1];
1118
+ return ctor(data, shape, stride, offset)
1119
+ }
1120
+
1121
+ var ndarray = wrappedNDArrayCtor;
1122
+
1123
+ class Martini {
1124
+ constructor(gridSize = 257) {
1125
+ this.gridSize = gridSize;
1126
+ const tileSize = gridSize - 1;
1127
+ if (tileSize & tileSize - 1) throw new Error(`Expected grid size to be 2^n+1, got ${gridSize}.`);
1128
+ this.numTriangles = tileSize * tileSize * 2 - 2;
1129
+ this.numParentTriangles = this.numTriangles - tileSize * tileSize;
1130
+ this.indices = new Uint32Array(this.gridSize * this.gridSize); // coordinates for all possible triangles in an RTIN tile
1131
+
1132
+ this.coords = new Uint16Array(this.numTriangles * 4); // get triangle coordinates from its index in an implicit binary tree
1133
+
1134
+ for (let i = 0; i < this.numTriangles; i++) {
1135
+ let id = i + 2;
1136
+ let ax = 0,
1137
+ ay = 0,
1138
+ bx = 0,
1139
+ by = 0,
1140
+ cx = 0,
1141
+ cy = 0;
1142
+
1143
+ if (id & 1) {
1144
+ bx = by = cx = tileSize; // bottom-left triangle
1145
+ } else {
1146
+ ax = ay = cy = tileSize; // top-right triangle
1147
+ }
1148
+
1149
+ while ((id >>= 1) > 1) {
1150
+ const mx = ax + bx >> 1;
1151
+ const my = ay + by >> 1;
1152
+
1153
+ if (id & 1) {
1154
+ // left half
1155
+ bx = ax;
1156
+ by = ay;
1157
+ ax = cx;
1158
+ ay = cy;
1159
+ } else {
1160
+ // right half
1161
+ ax = bx;
1162
+ ay = by;
1163
+ bx = cx;
1164
+ by = cy;
1165
+ }
1166
+
1167
+ cx = mx;
1168
+ cy = my;
1169
+ }
1170
+
1171
+ const k = i * 4;
1172
+ this.coords[k + 0] = ax;
1173
+ this.coords[k + 1] = ay;
1174
+ this.coords[k + 2] = bx;
1175
+ this.coords[k + 3] = by;
1176
+ }
1177
+ }
1178
+
1179
+ createTile(terrain) {
1180
+ return new Tile(terrain, this);
1181
+ }
1182
+
1183
+ }
1184
+
1185
+ class Tile {
1186
+ constructor(terrain, martini) {
1187
+ const size = martini.gridSize;
1188
+ if (terrain.length !== size * size) throw new Error(`Expected terrain data of length ${size * size} (${size} x ${size}), got ${terrain.length}.`);
1189
+ this.terrain = terrain;
1190
+ this.martini = martini;
1191
+ this.errors = new Float32Array(terrain.length);
1192
+ this.update();
1193
+ }
1194
+
1195
+ update() {
1196
+ const {
1197
+ numTriangles,
1198
+ numParentTriangles,
1199
+ coords,
1200
+ gridSize: size
1201
+ } = this.martini;
1202
+ const {
1203
+ terrain,
1204
+ errors
1205
+ } = this; // iterate over all possible triangles, starting from the smallest level
1206
+
1207
+ for (let i = numTriangles - 1; i >= 0; i--) {
1208
+ const k = i * 4;
1209
+ const ax = coords[k + 0];
1210
+ const ay = coords[k + 1];
1211
+ const bx = coords[k + 2];
1212
+ const by = coords[k + 3];
1213
+ const mx = ax + bx >> 1;
1214
+ const my = ay + by >> 1;
1215
+ const cx = mx + my - ay;
1216
+ const cy = my + ax - mx; // calculate error in the middle of the long edge of the triangle
1217
+
1218
+ const interpolatedHeight = (terrain[ay * size + ax] + terrain[by * size + bx]) / 2;
1219
+ const middleIndex = my * size + mx;
1220
+ const middleError = Math.abs(interpolatedHeight - terrain[middleIndex]);
1221
+ errors[middleIndex] = Math.max(errors[middleIndex], middleError);
1222
+
1223
+ if (i < numParentTriangles) {
1224
+ // bigger triangles; accumulate error with children
1225
+ const leftChildIndex = (ay + cy >> 1) * size + (ax + cx >> 1);
1226
+ const rightChildIndex = (by + cy >> 1) * size + (bx + cx >> 1);
1227
+ errors[middleIndex] = Math.max(errors[middleIndex], errors[leftChildIndex], errors[rightChildIndex]);
1228
+ }
1229
+ }
1230
+ }
842
1231
 
843
- var CACHED_CONSTRUCTORS = {
844
- "float32":[],
845
- "float64":[],
846
- "int8":[],
847
- "int16":[],
848
- "int32":[],
849
- "uint8":[],
850
- "uint16":[],
851
- "uint32":[],
852
- "array":[],
853
- "uint8_clamped":[],
854
- "bigint64": [],
855
- "biguint64": [],
856
- "buffer":[],
857
- "generic":[]
858
- }
1232
+ getMesh(maxError = 0, maxLength = null) {
1233
+ const {
1234
+ gridSize: size,
1235
+ indices
1236
+ } = this.martini;
1237
+ const {
1238
+ errors
1239
+ } = this;
1240
+ let numVertices = 0;
1241
+ let numTriangles = 0;
1242
+ const max = size - 1; // The maxLength parameter will cause triangles to be generated until the legs are below this length
1243
+ // It is meant to support cases where a certain mesh density is required to do spherical math on digital globes
859
1244
 
860
- ;
861
- function wrappedNDArrayCtor(data, shape, stride, offset) {
862
- if(data === undefined) {
863
- var ctor = CACHED_CONSTRUCTORS.array[0];
864
- return ctor([])
865
- } else if(typeof data === "number") {
866
- data = [data];
867
- }
868
- if(shape === undefined) {
869
- shape = [ data.length ];
870
- }
871
- var d = shape.length;
872
- if(stride === undefined) {
873
- stride = new Array(d);
874
- for(var i=d-1, sz=1; i>=0; --i) {
875
- stride[i] = sz;
876
- sz *= shape[i];
1245
+ const maxScale = maxLength || size; // use an index grid to keep track of vertices that were already used to avoid duplication
1246
+
1247
+ indices.fill(0); // retrieve mesh in two stages that both traverse the error map:
1248
+ // - countElements: find used vertices (and assign each an index), and count triangles (for minimum allocation)
1249
+ // - processTriangle: fill the allocated vertices & triangles typed arrays
1250
+
1251
+ function countElements(ax, ay, bx, by, cx, cy) {
1252
+ const mx = ax + bx >> 1;
1253
+ const my = ay + by >> 1;
1254
+ const legLength = Math.abs(ax - cx) + Math.abs(ay - cy);
1255
+
1256
+ if (legLength > 1 && errors[my * size + mx] > maxError || legLength > maxScale) {
1257
+ countElements(cx, cy, ax, ay, mx, my);
1258
+ countElements(bx, by, cx, cy, mx, my);
1259
+ } else {
1260
+ indices[ay * size + ax] = indices[ay * size + ax] || ++numVertices;
1261
+ indices[by * size + bx] = indices[by * size + bx] || ++numVertices;
1262
+ indices[cy * size + cx] = indices[cy * size + cx] || ++numVertices;
1263
+ numTriangles++;
1264
+ }
877
1265
  }
878
- }
879
- if(offset === undefined) {
880
- offset = 0;
881
- for(var i=0; i<d; ++i) {
882
- if(stride[i] < 0) {
883
- offset -= (shape[i]-1)*stride[i];
1266
+
1267
+ countElements(0, 0, max, max, max, 0);
1268
+ countElements(max, max, 0, 0, 0, max);
1269
+ const vertices = new Uint16Array(numVertices * 2);
1270
+ const triangles = new Uint32Array(numTriangles * 3);
1271
+ let triIndex = 0;
1272
+
1273
+ function processTriangle(ax, ay, bx, by, cx, cy) {
1274
+ const mx = ax + bx >> 1;
1275
+ const my = ay + by >> 1;
1276
+ const legLength = Math.abs(ax - cx) + Math.abs(ay - cy);
1277
+
1278
+ if (legLength > 1 && errors[my * size + mx] > maxError || legLength > maxScale) {
1279
+ // triangle doesn't approximate the surface well enough; drill down further
1280
+ processTriangle(cx, cy, ax, ay, mx, my);
1281
+ processTriangle(bx, by, cx, cy, mx, my);
1282
+ } else {
1283
+ // add a triangle
1284
+ const a = indices[ay * size + ax] - 1;
1285
+ const b = indices[by * size + bx] - 1;
1286
+ const c = indices[cy * size + cx] - 1;
1287
+ vertices[2 * a] = ax;
1288
+ vertices[2 * a + 1] = ay;
1289
+ vertices[2 * b] = bx;
1290
+ vertices[2 * b + 1] = by;
1291
+ vertices[2 * c] = cx;
1292
+ vertices[2 * c + 1] = cy;
1293
+ triangles[triIndex++] = a;
1294
+ triangles[triIndex++] = b;
1295
+ triangles[triIndex++] = c;
884
1296
  }
885
1297
  }
1298
+
1299
+ processTriangle(0, 0, max, max, max, 0);
1300
+ processTriangle(max, max, 0, 0, 0, max);
1301
+ return {
1302
+ vertices,
1303
+ triangles
1304
+ };
886
1305
  }
887
- var dtype = arrayDType(data);
888
- var ctor_list = CACHED_CONSTRUCTORS[dtype];
889
- while(ctor_list.length <= d+1) {
890
- ctor_list.push(compileConstructor(dtype, ctor_list.length-1));
891
- }
892
- var ctor = ctor_list[d+1];
893
- return ctor(data, shape, stride, offset)
894
- }
895
1306
 
896
- var ndarray = wrappedNDArrayCtor;
1307
+ }
897
1308
 
898
1309
  function createCommonjsModule(fn) {
899
1310
  var module = { exports: {} };
@@ -988,9 +1399,9 @@ var runtime = (function (exports) {
988
1399
  // This is a polyfill for %IteratorPrototype% for environments that
989
1400
  // don't natively support it.
990
1401
  var IteratorPrototype = {};
991
- IteratorPrototype[iteratorSymbol] = function () {
1402
+ define(IteratorPrototype, iteratorSymbol, function () {
992
1403
  return this;
993
- };
1404
+ });
994
1405
 
995
1406
  var getProto = Object.getPrototypeOf;
996
1407
  var NativeIteratorPrototype = getProto && getProto(getProto(values([])));
@@ -1004,8 +1415,9 @@ var runtime = (function (exports) {
1004
1415
 
1005
1416
  var Gp = GeneratorFunctionPrototype.prototype =
1006
1417
  Generator.prototype = Object.create(IteratorPrototype);
1007
- GeneratorFunction.prototype = Gp.constructor = GeneratorFunctionPrototype;
1008
- GeneratorFunctionPrototype.constructor = GeneratorFunction;
1418
+ GeneratorFunction.prototype = GeneratorFunctionPrototype;
1419
+ define(Gp, "constructor", GeneratorFunctionPrototype);
1420
+ define(GeneratorFunctionPrototype, "constructor", GeneratorFunction);
1009
1421
  GeneratorFunction.displayName = define(
1010
1422
  GeneratorFunctionPrototype,
1011
1423
  toStringTagSymbol,
@@ -1119,9 +1531,9 @@ var runtime = (function (exports) {
1119
1531
  }
1120
1532
 
1121
1533
  defineIteratorMethods(AsyncIterator.prototype);
1122
- AsyncIterator.prototype[asyncIteratorSymbol] = function () {
1534
+ define(AsyncIterator.prototype, asyncIteratorSymbol, function () {
1123
1535
  return this;
1124
- };
1536
+ });
1125
1537
  exports.AsyncIterator = AsyncIterator;
1126
1538
 
1127
1539
  // Note that simple async functions are implemented on top of
@@ -1314,13 +1726,13 @@ var runtime = (function (exports) {
1314
1726
  // iterator prototype chain incorrectly implement this, causing the Generator
1315
1727
  // object to not be returned from this call. This ensures that doesn't happen.
1316
1728
  // See https://github.com/facebook/regenerator/issues/274 for more details.
1317
- Gp[iteratorSymbol] = function() {
1729
+ define(Gp, iteratorSymbol, function() {
1318
1730
  return this;
1319
- };
1731
+ });
1320
1732
 
1321
- Gp.toString = function() {
1733
+ define(Gp, "toString", function() {
1322
1734
  return "[object Generator]";
1323
- };
1735
+ });
1324
1736
 
1325
1737
  function pushTryEntry(locs) {
1326
1738
  var entry = { tryLoc: locs[0] };
@@ -1639,28 +2051,39 @@ try {
1639
2051
  } catch (accidentalStrictMode) {
1640
2052
  // This module should not be running in strict mode, so the above
1641
2053
  // assignment should always work unless something is misconfigured. Just
1642
- // in case runtime.js accidentally runs in strict mode, we can escape
2054
+ // in case runtime.js accidentally runs in strict mode, in modern engines
2055
+ // we can explicitly access globalThis. In older engines we can escape
1643
2056
  // strict mode using a global Function call. This could conceivably fail
1644
2057
  // if a Content Security Policy forbids using Function, but in that case
1645
2058
  // the proper solution is to fix the accidental strict mode problem. If
1646
2059
  // you've misconfigured your bundler to force strict mode and applied a
1647
2060
  // CSP to forbid Function, and you're not willing to fix either of those
1648
2061
  // problems, please detail your unique predicament in a GitHub issue.
1649
- Function("r", "regeneratorRuntime = r")(runtime);
2062
+ if (typeof globalThis === "object") {
2063
+ globalThis.regeneratorRuntime = runtime;
2064
+ } else {
2065
+ Function("r", "regeneratorRuntime = r")(runtime);
2066
+ }
1650
2067
  }
1651
2068
  });
1652
2069
 
2070
+ var martini = null;
2071
+
1653
2072
  function decodeTerrain(parameters, transferableObjects) {
2073
+ var _martini;
2074
+
1654
2075
  var imageData = parameters.imageData,
1655
2076
  _parameters$tileSize = parameters.tileSize,
1656
2077
  tileSize = _parameters$tileSize === void 0 ? 256 : _parameters$tileSize,
1657
- errorLevel = parameters.errorLevel;
1658
- var pixels = ndarray(new Uint8Array(imageData), [tileSize, tileSize, 4], [4, 4 * tileSize, 1], 0);
1659
- var martini = new Martini(tileSize + 1);
1660
- var terrain = mapboxTerrainToGrid(pixels);
2078
+ errorLevel = parameters.errorLevel,
2079
+ interval = parameters.interval,
2080
+ offset = parameters.offset;
2081
+ var pixels = ndarray(new Uint8Array(imageData), [tileSize, tileSize, 4], [4, 4 * tileSize, 1], 0); // Tile size must be maintained through the life of the worker
2082
+
2083
+ (_martini = martini) !== null && _martini !== void 0 ? _martini : martini = new Martini(tileSize + 1);
2084
+ var terrain = mapboxTerrainToGrid(pixels, interval, offset);
1661
2085
  var tile = martini.createTile(terrain); // get a mesh (vertices and triangles indices) for a 10m error
1662
2086
 
1663
- console.log("Error level: ".concat(errorLevel));
1664
2087
  var mesh = tile.getMesh(errorLevel, parameters.maxLength);
1665
2088
  return createQuantizedMeshData(tile, mesh, tileSize);
1666
2089
  }
@@ -1670,11 +2093,11 @@ self.onmessage = function (msg) {
1670
2093
  id = _msg$data.id,
1671
2094
  payload = _msg$data.payload;
1672
2095
  if (id == null) return;
1673
- console.log("Worker recieved message", msg.data);
1674
2096
  var objects = [];
2097
+ var res = null;
1675
2098
 
1676
2099
  try {
1677
- var res = decodeTerrain(payload);
2100
+ res = decodeTerrain(payload);
1678
2101
  objects.push(res.indices.buffer);
1679
2102
  objects.push(res.quantizedVertices.buffer);
1680
2103
  self.postMessage({
@@ -1687,45 +2110,52 @@ self.onmessage = function (msg) {
1687
2110
  err: err.toString()
1688
2111
  });
1689
2112
  } finally {
2113
+ res = null;
1690
2114
  objects = null;
1691
2115
  }
1692
2116
  };
1693
2117
 
1694
- require("ndarray");
1695
- // https://github.com/CesiumGS/cesium/blob/1.68/Source/Scene/MapboxImageryProvider.js#L42
1696
- var ImageFormat;
2118
+ var StretchedTilingScheme = /*#__PURE__*/function (_WebMercatorTilingSch) {
2119
+ _inherits(StretchedTilingScheme, _WebMercatorTilingSch);
1697
2120
 
1698
- (function (ImageFormat) {
1699
- ImageFormat["WEBP"] = "webp";
1700
- ImageFormat["PNG"] = "png";
1701
- ImageFormat["PNGRAW"] = "pngraw";
1702
- })(ImageFormat || (ImageFormat = {}));
2121
+ var _super = _createSuper(StretchedTilingScheme);
1703
2122
 
1704
- var loadImage = function loadImage(url) {
1705
- return new Promise(function (resolve, reject) {
1706
- var img = new Image();
1707
- img.addEventListener("load", function () {
1708
- return resolve(img);
1709
- });
1710
- img.addEventListener("error", function (err) {
1711
- return reject(err);
1712
- });
1713
- img.crossOrigin = "anonymous";
1714
- img.src = url;
1715
- });
1716
- };
2123
+ function StretchedTilingScheme() {
2124
+ _classCallCheck(this, StretchedTilingScheme);
2125
+
2126
+ return _super.apply(this, arguments);
2127
+ }
2128
+
2129
+ _createClass(StretchedTilingScheme, [{
2130
+ key: "tileXYToRectangle",
2131
+ value: function tileXYToRectangle(x, y, level, res) {
2132
+ var result = _get(_getPrototypeOf(StretchedTilingScheme.prototype), "tileXYToRectangle", this).call(this, x, y, level);
2133
+
2134
+ if (y == 0) {
2135
+ //console.log("Top row", res, y, level);
2136
+ result.north = Math.PI / 2;
2137
+ }
2138
+
2139
+ if (y + 1 == Math.pow(2, level)) {
2140
+ result.south = -Math.PI / 2;
2141
+ }
2142
+
2143
+ return result;
2144
+ }
2145
+ }]);
2146
+
2147
+ return StretchedTilingScheme;
2148
+ }(cesium.WebMercatorTilingScheme);
1717
2149
 
1718
2150
  var MartiniTerrainProvider = /*#__PURE__*/function () {
1719
2151
  // @ts-ignore
1720
2152
  function MartiniTerrainProvider() {
1721
- var _opts$highResolution, _opts$detailScalar, _opts$minimumErrorLev, _opts$ellipsoid, _opts$format;
2153
+ var _opts$interval, _opts$offset, _opts$maxWorkers, _opts$minZoomLevel, _opts$fillPoles, _opts$detailScalar, _opts$minimumErrorLev, _opts$ellipsoid;
1722
2154
 
1723
2155
  var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
1724
2156
 
1725
2157
  _classCallCheck(this, MartiniTerrainProvider);
1726
2158
 
1727
- _defineProperty(this, "martini", void 0);
1728
-
1729
2159
  _defineProperty(this, "hasWaterMask", false);
1730
2160
 
1731
2161
  _defineProperty(this, "hasVertexNormals", false);
@@ -1744,98 +2174,75 @@ var MartiniTerrainProvider = /*#__PURE__*/function () {
1744
2174
 
1745
2175
  _defineProperty(this, "ellipsoid", void 0);
1746
2176
 
1747
- _defineProperty(this, "accessToken", void 0);
2177
+ _defineProperty(this, "workerFarm", null);
1748
2178
 
1749
- _defineProperty(this, "format", void 0);
2179
+ _defineProperty(this, "inProgressWorkers", 0);
1750
2180
 
1751
- _defineProperty(this, "highResolution", void 0);
2181
+ _defineProperty(this, "levelOfDetailScalar", null);
1752
2182
 
1753
- _defineProperty(this, "tileSize", 256);
2183
+ _defineProperty(this, "maxWorkers", 5);
1754
2184
 
1755
- _defineProperty(this, "workerFarm", void 0);
2185
+ _defineProperty(this, "minError", 0.1);
1756
2186
 
1757
- _defineProperty(this, "inProgressWorkers", 0);
2187
+ _defineProperty(this, "minZoomLevel", void 0);
1758
2188
 
1759
- _defineProperty(this, "levelOfDetailScalar", null);
2189
+ _defineProperty(this, "fillPoles", true);
1760
2190
 
1761
- _defineProperty(this, "useWorkers", true);
2191
+ _defineProperty(this, "_errorAtMinZoom", 1000);
1762
2192
 
1763
- _defineProperty(this, "contextQueue", void 0);
2193
+ _defineProperty(this, "resource", null);
1764
2194
 
1765
- _defineProperty(this, "minError", 0.1);
2195
+ _defineProperty(this, "interval", void 0);
2196
+
2197
+ _defineProperty(this, "offset", void 0);
1766
2198
 
1767
2199
  _defineProperty(this, "RADIUS_SCALAR", 1.0);
1768
2200
 
1769
2201
  //this.martini = new Martini(257);
1770
- this.highResolution = (_opts$highResolution = opts.highResolution) !== null && _opts$highResolution !== void 0 ? _opts$highResolution : false;
1771
- this.tileSize = this.highResolution ? 512 : 256;
1772
- this.contextQueue = [];
2202
+ this.resource = opts.resource;
2203
+ this.interval = (_opts$interval = opts.interval) !== null && _opts$interval !== void 0 ? _opts$interval : 0.1;
2204
+ this.offset = (_opts$offset = opts.offset) !== null && _opts$offset !== void 0 ? _opts$offset : -10000;
2205
+ this.maxWorkers = (_opts$maxWorkers = opts.maxWorkers) !== null && _opts$maxWorkers !== void 0 ? _opts$maxWorkers : 5;
2206
+ this.minZoomLevel = (_opts$minZoomLevel = opts.minZoomLevel) !== null && _opts$minZoomLevel !== void 0 ? _opts$minZoomLevel : 3;
2207
+ this.fillPoles = (_opts$fillPoles = opts.fillPoles) !== null && _opts$fillPoles !== void 0 ? _opts$fillPoles : true;
1773
2208
  this.levelOfDetailScalar = ((_opts$detailScalar = opts.detailScalar) !== null && _opts$detailScalar !== void 0 ? _opts$detailScalar : 4.0) + cesium.Math.EPSILON5;
1774
- this.martini = new Martini(this.tileSize + 1);
1775
2209
  this.ready = true;
1776
2210
  this.readyPromise = Promise.resolve(true);
1777
- this.accessToken = opts.accessToken;
1778
2211
  this.minError = (_opts$minimumErrorLev = opts.minimumErrorLevel) !== null && _opts$minimumErrorLev !== void 0 ? _opts$minimumErrorLev : 0.1;
1779
2212
  this.errorEvent.addEventListener(console.log, this);
1780
2213
  this.ellipsoid = (_opts$ellipsoid = opts.ellipsoid) !== null && _opts$ellipsoid !== void 0 ? _opts$ellipsoid : cesium.Ellipsoid.WGS84;
1781
- this.format = (_opts$format = opts.format) !== null && _opts$format !== void 0 ? _opts$format : ImageFormat.WEBP;
1782
- this.workerFarm = new WorkerFarm();
1783
- this.tilingScheme = new cesium.WebMercatorTilingScheme({
2214
+
2215
+ if (this.maxWorkers > 0) {
2216
+ this.workerFarm = new WorkerFarm();
2217
+ }
2218
+
2219
+ var scheme = cesium.WebMercatorTilingScheme;
2220
+
2221
+ if (this.fillPoles) {
2222
+ scheme = StretchedTilingScheme;
2223
+ }
2224
+
2225
+ this.tilingScheme = new scheme({
1784
2226
  numberOfLevelZeroTilesX: 1,
1785
2227
  numberOfLevelZeroTilesY: 1,
1786
2228
  ellipsoid: this.ellipsoid
1787
2229
  });
2230
+ this._errorAtMinZoom = this.errorAtZoom(this.minZoomLevel);
1788
2231
  }
1789
2232
 
1790
2233
  _createClass(MartiniTerrainProvider, [{
1791
- key: "getCanvas",
1792
- value: function getCanvas() {
1793
- var ctx = this.contextQueue.pop();
1794
-
1795
- if (ctx == null) {
1796
- //console.log("Creating new canvas element");
1797
- var canvas = document.createElement("canvas");
1798
- canvas.width = this.tileSize;
1799
- canvas.height = this.tileSize;
1800
- var context = canvas.getContext("2d");
1801
- ctx = {
1802
- canvas: canvas,
1803
- context: context
1804
- };
1805
- }
1806
-
1807
- return ctx;
1808
- }
1809
- }, {
1810
- key: "getPixels",
1811
- value: function getPixels(img) {
1812
- var canvasRef = this.getCanvas();
1813
- var context = canvasRef.context; //context.scale(1, -1);
1814
- // Chrome appears to vertically flip the image for reasons that are unclear
1815
- // We can make it work in Chrome by drawing the image upside-down at this step.
1816
-
1817
- context.drawImage(img, 0, 0, this.tileSize, this.tileSize);
1818
- var pixels = context.getImageData(0, 0, this.tileSize, this.tileSize);
1819
- context.clearRect(0, 0, this.tileSize, this.tileSize);
1820
- this.contextQueue.push(canvasRef);
1821
- return pixels;
1822
- }
1823
- }, {
1824
- key: "buildTileURL",
1825
- value: function buildTileURL(tileCoords) {
1826
- var z = tileCoords.z,
1827
- x = tileCoords.x,
1828
- y = tileCoords.y;
1829
- var hires = this.highResolution ? "@2x" : ""; // https://api.mapbox.com/raster/v1/mapbox.mapbox-terrain-dem-v1/${z}/${x}/${y}${hires}.${this.format}?access_token=${this.accessToken}&sku=101EX9Btybqbj
1830
-
1831
- return "https://api.mapbox.com/v4/mapbox.terrain-rgb/".concat(z, "/").concat(x, "/").concat(y).concat(hires, ".").concat(this.format, "?access_token=").concat(this.accessToken);
1832
- }
1833
- }, {
1834
2234
  key: "requestTileGeometry",
1835
2235
  value: function requestTileGeometry(x, y, z, request) {
1836
2236
  var _this = this;
1837
2237
 
1838
- if (this.inProgressWorkers > 5) return undefined;
2238
+ // Look for tiles both below the zoom level and below the error threshold for the zoom level at the equator...
2239
+ if (z < this.minZoomLevel || this.scaledErrorForTile(x, y, z) > this._errorAtMinZoom) {
2240
+ // If we are below the minimum zoom level, we return empty heightmaps
2241
+ // to avoid unnecessary requests for low-resolution data.
2242
+ return Promise.resolve(this.emptyMesh(x, y, z));
2243
+ }
2244
+
2245
+ if (this.inProgressWorkers > this.maxWorkers) return undefined;
1839
2246
  this.inProgressWorkers += 1;
1840
2247
  return this.processTile(x, y, z)["finally"](function () {
1841
2248
  _this.inProgressWorkers -= 1;
@@ -1845,37 +2252,28 @@ var MartiniTerrainProvider = /*#__PURE__*/function () {
1845
2252
  key: "processTile",
1846
2253
  value: function () {
1847
2254
  var _processTile = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(x, y, z) {
1848
- var err, url, image, px, pixelData, tileRect, maxLength, params, res, tile, v;
2255
+ var _this$resource, tileSize, getTilePixels, px, pixelData, tileRect, err, maxLength, params, res;
2256
+
1849
2257
  return regeneratorRuntime.wrap(function _callee$(_context) {
1850
2258
  while (1) {
1851
2259
  switch (_context.prev = _context.next) {
1852
2260
  case 0:
1853
- // Something wonky about our tiling scheme, perhaps
1854
- // 12/2215/2293 @2x
1855
- //const url = `https://a.tiles.mapbox.com/v4/mapbox.terrain-rgb/${z}/${x}/${y}${hires}.${this.format}?access_token=${this.accessToken}`;
1856
- err = this.getErrorLevel(z);
1857
- this.highResolution ? "@2x" : "";
1858
- _context.prev = 2;
1859
- url = this.buildTileURL({
2261
+ _context.prev = 0;
2262
+ _this$resource = this.resource, tileSize = _this$resource.tileSize, getTilePixels = _this$resource.getTilePixels;
2263
+ _context.next = 4;
2264
+ return getTilePixels({
1860
2265
  x: x,
1861
2266
  y: y,
1862
2267
  z: z
1863
2268
  });
1864
- _context.next = 6;
1865
- return loadImage(url);
1866
2269
 
1867
- case 6:
1868
- image = _context.sent;
1869
- px = this.getPixels(image);
2270
+ case 4:
2271
+ px = _context.sent;
1870
2272
  pixelData = px.data;
1871
- tileRect = this.tilingScheme.tileXYToRectangle(x, y, z);
1872
- maxLength = null; // More than a degree or so
1873
-
1874
- if (tileRect.height > 0.01) {
1875
- // We need to be able to specify a minimum number of triangles...
1876
- maxLength = 20 * (z + 1);
1877
- }
2273
+ tileRect = this.tilingScheme.tileXYToRectangle(x, y, z); ///const center = Rectangle.center(tileRect);
1878
2274
 
2275
+ err = this.errorAtZoom(z);
2276
+ maxLength = this.maxVertexDistance(tileRect);
1879
2277
  params = {
1880
2278
  imageData: pixelData,
1881
2279
  maxLength: maxLength,
@@ -1884,43 +2282,44 @@ var MartiniTerrainProvider = /*#__PURE__*/function () {
1884
2282
  z: z,
1885
2283
  errorLevel: err,
1886
2284
  ellipsoidRadius: this.ellipsoid.maximumRadius,
1887
- tileSize: this.tileSize
2285
+ tileSize: tileSize,
2286
+ interval: this.interval,
2287
+ offset: this.offset
1888
2288
  };
1889
2289
 
1890
- if (!this.useWorkers) {
1891
- _context.next = 19;
2290
+ if (!(this.workerFarm != null)) {
2291
+ _context.next = 16;
1892
2292
  break;
1893
2293
  }
1894
2294
 
1895
- _context.next = 16;
2295
+ _context.next = 13;
1896
2296
  return this.workerFarm.scheduleTask(params, [pixelData.buffer]);
1897
2297
 
1898
- case 16:
2298
+ case 13:
1899
2299
  res = _context.sent;
1900
- _context.next = 20;
2300
+ _context.next = 17;
1901
2301
  break;
1902
2302
 
1903
- case 19:
2303
+ case 16:
1904
2304
  res = decodeTerrain(params);
1905
2305
 
1906
- case 20:
1907
- tile = this.createQuantizedMeshData(tileRect, err, res);
1908
- return _context.abrupt("return", tile);
1909
-
1910
- case 24:
1911
- _context.prev = 24;
1912
- _context.t0 = _context["catch"](2);
1913
- console.log(_context.t0); // return undefined
2306
+ case 17:
2307
+ pixelData = undefined;
2308
+ px = undefined;
2309
+ return _context.abrupt("return", this.createQuantizedMeshData(tileRect, err, res));
1914
2310
 
1915
- v = Math.max(32 - 4 * z, 4);
1916
- return _context.abrupt("return", this.emptyHeightmap(v));
2311
+ case 22:
2312
+ _context.prev = 22;
2313
+ _context.t0 = _context["catch"](0);
2314
+ console.log(_context.t0);
2315
+ return _context.abrupt("return", this.emptyMesh(x, y, z));
1917
2316
 
1918
- case 29:
2317
+ case 26:
1919
2318
  case "end":
1920
2319
  return _context.stop();
1921
2320
  }
1922
2321
  }
1923
- }, _callee, this, [[2, 24]]);
2322
+ }, _callee, this, [[0, 22]]);
1924
2323
  }));
1925
2324
 
1926
2325
  function processTile(_x, _x2, _x3) {
@@ -1930,58 +2329,69 @@ var MartiniTerrainProvider = /*#__PURE__*/function () {
1930
2329
  return processTile;
1931
2330
  }()
1932
2331
  }, {
1933
- key: "getErrorLevel",
1934
- value: function getErrorLevel(zoom) {
2332
+ key: "errorAtZoom",
2333
+ value: function errorAtZoom(zoom) {
1935
2334
  return Math.max(this.getLevelMaximumGeometricError(zoom) / this.levelOfDetailScalar, this.minError);
1936
2335
  }
2336
+ }, {
2337
+ key: "scaledErrorForTile",
2338
+ value: function scaledErrorForTile(x, y, z) {
2339
+ var tileRect = this.tilingScheme.tileXYToRectangle(x, y, z);
2340
+ var center = cesium.Rectangle.center(tileRect);
2341
+ return this.errorAtZoom(z) / (1 - Math.sin(center.latitude));
2342
+ }
2343
+ }, {
2344
+ key: "maxVertexDistance",
2345
+ value: function maxVertexDistance(tileRect) {
2346
+ return Math.round(5 / tileRect.height);
2347
+ }
2348
+ }, {
2349
+ key: "emptyMesh",
2350
+ value: function emptyMesh$1(x, y, z) {
2351
+ var tileRect = this.tilingScheme.tileXYToRectangle(x, y, z);
2352
+ var v = Math.max(Math.ceil(256 / this.maxVertexDistance(tileRect)), 4);
2353
+
2354
+ var output = emptyMesh(v);
2355
+
2356
+ var err = this.errorAtZoom(z);
2357
+ return this.createQuantizedMeshData(tileRect, err, output);
2358
+ }
1937
2359
  }, {
1938
2360
  key: "createQuantizedMeshData",
1939
2361
  value: function createQuantizedMeshData(tileRect, errorLevel, workerOutput) {
1940
- var minHeight = workerOutput.minimumHeight,
1941
- maxHeight = workerOutput.maximumHeight,
2362
+ var minimumHeight = workerOutput.minimumHeight,
2363
+ maximumHeight = workerOutput.maximumHeight,
1942
2364
  quantizedVertices = workerOutput.quantizedVertices,
1943
- triangles = workerOutput.indices,
2365
+ indices = workerOutput.indices,
1944
2366
  westIndices = workerOutput.westIndices,
1945
2367
  southIndices = workerOutput.southIndices,
1946
2368
  eastIndices = workerOutput.eastIndices,
1947
2369
  northIndices = workerOutput.northIndices;
1948
2370
  var err = errorLevel;
1949
- var skirtHeight = err * 5;
1950
- var tileCenter = cesium.Cartographic.toCartesian(cesium.Rectangle.center(tileRect)); // Need to get maximum distance at zoom level
1951
- // tileRect.width is given in radians
1952
- // cos of half-tile-width allows us to use right-triangle relationship
2371
+ var skirtHeight = err * 20;
2372
+ var center = cesium.Rectangle.center(tileRect); // Calculating occlusion height is kind of messy currently, but it definitely works
1953
2373
 
1954
- var cosWidth = Math.cos(tileRect.width / 2); // half tile width since our ref point is at the center
1955
- // scale max height to max ellipsoid radius
1956
- // ... it might be better to use the radius of the entire
2374
+ var halfAngle = tileRect.width / 2;
2375
+ var dr = Math.cos(halfAngle); // half tile width since our ref point is at the center
1957
2376
 
1958
- var ellipsoidHeight = maxHeight / this.ellipsoid.maximumRadius; // cosine relationship to scale height in ellipsoid-relative coordinates
2377
+ var occlusionHeight = dr * this.ellipsoid.maximumRadius + maximumHeight;
1959
2378
 
1960
- var occlusionHeight = (1 + ellipsoidHeight) / cosWidth;
1961
- var scaledCenter = this.ellipsoid.transformPositionToScaledSpace(tileCenter);
1962
- var horizonOcclusionPoint = new cesium.Cartesian3(scaledCenter.x, scaledCenter.y, occlusionHeight * Math.sign(tileCenter.z));
1963
- var orientedBoundingBox = null;
1964
- var boundingSphere;
1965
-
1966
- if (tileRect.width < cesium.Math.PI_OVER_TWO + cesium.Math.EPSILON5) {
1967
- // @ts-ignore
1968
- orientedBoundingBox = cesium.OrientedBoundingBox.fromRectangle(tileRect, minHeight, maxHeight); // @ts-ignore
1969
-
1970
- boundingSphere = cesium.BoundingSphere.fromOrientedBoundingBox(orientedBoundingBox);
1971
- } else {
1972
- // If our bounding rectangle spans >= 90º, we should use the entire globe as a bounding sphere.
1973
- boundingSphere = new cesium.BoundingSphere(cesium.Cartesian3.ZERO, // radius (seems to be max height of Earth terrain?)
1974
- 6379792.481506292);
2379
+ if (halfAngle > Math.PI / 4) {
2380
+ occlusionHeight = (1 + halfAngle) * this.ellipsoid.maximumRadius;
1975
2381
  }
1976
2382
 
1977
- console.log(orientedBoundingBox, boundingSphere); // SE NW NE
2383
+ var occlusionPoint = new cesium.Cartographic(center.longitude, center.latitude, occlusionHeight // Scaling factor of two just to be sure.
2384
+ );
2385
+ var horizonOcclusionPoint = this.ellipsoid.transformPositionToScaledSpace(cesium.Cartographic.toCartesian(occlusionPoint));
2386
+ var orientedBoundingBox = cesium.OrientedBoundingBox.fromRectangle(tileRect, minimumHeight, maximumHeight, this.tilingScheme.ellipsoid);
2387
+ var boundingSphere = cesium.BoundingSphere.fromOrientedBoundingBox(orientedBoundingBox); // SE NW NE
1978
2388
  // NE NW SE
1979
2389
 
1980
- return new cesium.QuantizedMeshTerrainData({
1981
- minimumHeight: minHeight,
1982
- maximumHeight: maxHeight,
2390
+ var result = new cesium.QuantizedMeshTerrainData({
2391
+ minimumHeight: minimumHeight,
2392
+ maximumHeight: maximumHeight,
1983
2393
  quantizedVertices: quantizedVertices,
1984
- indices: triangles,
2394
+ indices: indices,
1985
2395
  boundingSphere: boundingSphere,
1986
2396
  orientedBoundingBox: orientedBoundingBox,
1987
2397
  horizonOcclusionPoint: horizonOcclusionPoint,
@@ -1995,15 +2405,7 @@ var MartiniTerrainProvider = /*#__PURE__*/function () {
1995
2405
  northSkirtHeight: skirtHeight,
1996
2406
  childTileMask: 15
1997
2407
  });
1998
- }
1999
- }, {
2000
- key: "emptyHeightmap",
2001
- value: function emptyHeightmap(samples) {
2002
- return new cesium.HeightmapTerrainData({
2003
- buffer: new Uint8Array(Array(samples * samples).fill(0)),
2004
- width: samples,
2005
- height: samples
2006
- });
2408
+ return result;
2007
2409
  }
2008
2410
  }, {
2009
2411
  key: "getLevelMaximumGeometricError",
@@ -2011,19 +2413,44 @@ var MartiniTerrainProvider = /*#__PURE__*/function () {
2011
2413
  var levelZeroMaximumGeometricError = cesium.TerrainProvider.getEstimatedLevelZeroGeometricErrorForAHeightmap(this.tilingScheme.ellipsoid, 65, this.tilingScheme.getNumberOfXTilesAtLevel(0)); // Scalar to control overzooming
2012
2414
  // also seems to control zooming for imagery layers
2013
2415
 
2014
- var scalar = 1; // this.highResolution ? 8 : 4;
2015
-
2416
+ var scalar = this.resource.tileSize / 256;
2016
2417
  return levelZeroMaximumGeometricError / scalar / (1 << level);
2017
2418
  }
2018
2419
  }, {
2019
2420
  key: "getTileDataAvailable",
2020
2421
  value: function getTileDataAvailable(x, y, z) {
2021
- return z <= 15;
2422
+ return this.resource.getTileDataAvailable({
2423
+ x: x,
2424
+ y: y,
2425
+ z: z
2426
+ });
2022
2427
  }
2023
2428
  }]);
2024
2429
 
2025
2430
  return MartiniTerrainProvider;
2026
2431
  }();
2027
2432
 
2028
- module.exports = MartiniTerrainProvider;
2433
+ var MapboxTerrainProvider = /*#__PURE__*/function (_MartiniTerrainProvid) {
2434
+ _inherits(MapboxTerrainProvider, _MartiniTerrainProvid);
2435
+
2436
+ var _super2 = _createSuper(MapboxTerrainProvider);
2437
+
2438
+ function MapboxTerrainProvider() {
2439
+ var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
2440
+
2441
+ _classCallCheck(this, MapboxTerrainProvider);
2442
+
2443
+ var resource = new MapboxTerrainResource(opts);
2444
+ return _super2.call(this, _objectSpread2(_objectSpread2({}, opts), {}, {
2445
+ resource: resource
2446
+ }));
2447
+ }
2448
+
2449
+ return MapboxTerrainProvider;
2450
+ }(MartiniTerrainProvider);
2451
+
2452
+ exports.DefaultHeightmapResource = DefaultHeightmapResource;
2453
+ exports.MapboxTerrainResource = MapboxTerrainResource;
2454
+ exports.MartiniTerrainProvider = MartiniTerrainProvider;
2455
+ exports["default"] = MapboxTerrainProvider;
2029
2456
  //# sourceMappingURL=index.js.map