earcut 2.2.3 → 3.0.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.
@@ -1,32 +1,32 @@
1
- (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.earcut = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
2
- 'use strict';
1
+ (function (global, factory) {
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3
+ typeof define === 'function' && define.amd ? define(['exports'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.earcut = {}));
5
+ })(this, (function (exports) { 'use strict';
3
6
 
4
- module.exports = earcut;
5
- module.exports.default = earcut;
7
+ function earcut(data, holeIndices, dim = 2) {
6
8
 
7
- function earcut(data, holeIndices, dim) {
8
-
9
- dim = dim || 2;
10
-
11
- var hasHoles = holeIndices && holeIndices.length,
12
- outerLen = hasHoles ? holeIndices[0] * dim : data.length,
13
- outerNode = linkedList(data, 0, outerLen, dim, true),
14
- triangles = [];
9
+ const hasHoles = holeIndices && holeIndices.length;
10
+ const outerLen = hasHoles ? holeIndices[0] * dim : data.length;
11
+ let outerNode = linkedList(data, 0, outerLen, dim, true);
12
+ const triangles = [];
15
13
 
16
14
  if (!outerNode || outerNode.next === outerNode.prev) return triangles;
17
15
 
18
- var minX, minY, maxX, maxY, x, y, invSize;
16
+ let minX, minY, invSize;
19
17
 
20
18
  if (hasHoles) outerNode = eliminateHoles(data, holeIndices, outerNode, dim);
21
19
 
22
20
  // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
23
21
  if (data.length > 80 * dim) {
24
- minX = maxX = data[0];
25
- minY = maxY = data[1];
26
-
27
- for (var i = dim; i < outerLen; i += dim) {
28
- x = data[i];
29
- y = data[i + 1];
22
+ minX = Infinity;
23
+ minY = Infinity;
24
+ let maxX = -Infinity;
25
+ let maxY = -Infinity;
26
+
27
+ for (let i = dim; i < outerLen; i += dim) {
28
+ const x = data[i];
29
+ const y = data[i + 1];
30
30
  if (x < minX) minX = x;
31
31
  if (y < minY) minY = y;
32
32
  if (x > maxX) maxX = x;
@@ -35,22 +35,22 @@ function earcut(data, holeIndices, dim) {
35
35
 
36
36
  // minX, minY and invSize are later used to transform coords into integers for z-order calculation
37
37
  invSize = Math.max(maxX - minX, maxY - minY);
38
- invSize = invSize !== 0 ? 1 / invSize : 0;
38
+ invSize = invSize !== 0 ? 32767 / invSize : 0;
39
39
  }
40
40
 
41
- earcutLinked(outerNode, triangles, dim, minX, minY, invSize);
41
+ earcutLinked(outerNode, triangles, dim, minX, minY, invSize, 0);
42
42
 
43
43
  return triangles;
44
44
  }
45
45
 
46
46
  // create a circular doubly linked list from polygon points in the specified winding order
47
47
  function linkedList(data, start, end, dim, clockwise) {
48
- var i, last;
48
+ let last;
49
49
 
50
50
  if (clockwise === (signedArea(data, start, end, dim) > 0)) {
51
- for (i = start; i < end; i += dim) last = insertNode(i, data[i], data[i + 1], last);
51
+ for (let i = start; i < end; i += dim) last = insertNode(i / dim | 0, data[i], data[i + 1], last);
52
52
  } else {
53
- for (i = end - dim; i >= start; i -= dim) last = insertNode(i, data[i], data[i + 1], last);
53
+ for (let i = end - dim; i >= start; i -= dim) last = insertNode(i / dim | 0, data[i], data[i + 1], last);
54
54
  }
55
55
 
56
56
  if (last && equals(last, last.next)) {
@@ -66,7 +66,7 @@ function filterPoints(start, end) {
66
66
  if (!start) return start;
67
67
  if (!end) end = start;
68
68
 
69
- var p = start,
69
+ let p = start,
70
70
  again;
71
71
  do {
72
72
  again = false;
@@ -92,19 +92,15 @@ function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) {
92
92
  // interlink polygon nodes in z-order
93
93
  if (!pass && invSize) indexCurve(ear, minX, minY, invSize);
94
94
 
95
- var stop = ear,
96
- prev, next;
95
+ let stop = ear;
97
96
 
98
97
  // iterate through ears, slicing them one by one
99
98
  while (ear.prev !== ear.next) {
100
- prev = ear.prev;
101
- next = ear.next;
99
+ const prev = ear.prev;
100
+ const next = ear.next;
102
101
 
103
102
  if (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear)) {
104
- // cut off the triangle
105
- triangles.push(prev.i / dim);
106
- triangles.push(ear.i / dim);
107
- triangles.push(next.i / dim);
103
+ triangles.push(prev.i, ear.i, next.i); // cut off the triangle
108
104
 
109
105
  removeNode(ear);
110
106
 
@@ -125,7 +121,7 @@ function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) {
125
121
 
126
122
  // if this didn't work, try curing all small self-intersections locally
127
123
  } else if (pass === 1) {
128
- ear = cureLocalIntersections(filterPoints(ear), triangles, dim);
124
+ ear = cureLocalIntersections(filterPoints(ear), triangles);
129
125
  earcutLinked(ear, triangles, dim, minX, minY, invSize, 2);
130
126
 
131
127
  // as a last resort, try splitting the remaining polygon into two
@@ -140,17 +136,25 @@ function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) {
140
136
 
141
137
  // check whether a polygon node forms a valid ear with adjacent nodes
142
138
  function isEar(ear) {
143
- var a = ear.prev,
139
+ const a = ear.prev,
144
140
  b = ear,
145
141
  c = ear.next;
146
142
 
147
143
  if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
148
144
 
149
145
  // now make sure we don't have other points inside the potential ear
150
- var p = ear.next.next;
146
+ const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y;
151
147
 
152
- while (p !== ear.prev) {
153
- if (pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
148
+ // triangle bbox; min & max are calculated like this for speed
149
+ const x0 = ax < bx ? (ax < cx ? ax : cx) : (bx < cx ? bx : cx),
150
+ y0 = ay < by ? (ay < cy ? ay : cy) : (by < cy ? by : cy),
151
+ x1 = ax > bx ? (ax > cx ? ax : cx) : (bx > cx ? bx : cx),
152
+ y1 = ay > by ? (ay > cy ? ay : cy) : (by > cy ? by : cy);
153
+
154
+ let p = c.next;
155
+ while (p !== a) {
156
+ if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 &&
157
+ pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) &&
154
158
  area(p.prev, p, p.next) >= 0) return false;
155
159
  p = p.next;
156
160
  }
@@ -159,51 +163,49 @@ function isEar(ear) {
159
163
  }
160
164
 
161
165
  function isEarHashed(ear, minX, minY, invSize) {
162
- var a = ear.prev,
166
+ const a = ear.prev,
163
167
  b = ear,
164
168
  c = ear.next;
165
169
 
166
170
  if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
167
171
 
172
+ const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y;
173
+
168
174
  // triangle bbox; min & max are calculated like this for speed
169
- var minTX = a.x < b.x ? (a.x < c.x ? a.x : c.x) : (b.x < c.x ? b.x : c.x),
170
- minTY = a.y < b.y ? (a.y < c.y ? a.y : c.y) : (b.y < c.y ? b.y : c.y),
171
- maxTX = a.x > b.x ? (a.x > c.x ? a.x : c.x) : (b.x > c.x ? b.x : c.x),
172
- maxTY = a.y > b.y ? (a.y > c.y ? a.y : c.y) : (b.y > c.y ? b.y : c.y);
175
+ const x0 = ax < bx ? (ax < cx ? ax : cx) : (bx < cx ? bx : cx),
176
+ y0 = ay < by ? (ay < cy ? ay : cy) : (by < cy ? by : cy),
177
+ x1 = ax > bx ? (ax > cx ? ax : cx) : (bx > cx ? bx : cx),
178
+ y1 = ay > by ? (ay > cy ? ay : cy) : (by > cy ? by : cy);
173
179
 
174
180
  // z-order range for the current triangle bbox;
175
- var minZ = zOrder(minTX, minTY, minX, minY, invSize),
176
- maxZ = zOrder(maxTX, maxTY, minX, minY, invSize);
181
+ const minZ = zOrder(x0, y0, minX, minY, invSize),
182
+ maxZ = zOrder(x1, y1, minX, minY, invSize);
177
183
 
178
- var p = ear.prevZ,
184
+ let p = ear.prevZ,
179
185
  n = ear.nextZ;
180
186
 
181
187
  // look for points inside the triangle in both directions
182
188
  while (p && p.z >= minZ && n && n.z <= maxZ) {
183
- if (p !== ear.prev && p !== ear.next &&
184
- pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
185
- area(p.prev, p, p.next) >= 0) return false;
189
+ if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c &&
190
+ pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
186
191
  p = p.prevZ;
187
192
 
188
- if (n !== ear.prev && n !== ear.next &&
189
- pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y) &&
190
- area(n.prev, n, n.next) >= 0) return false;
193
+ if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c &&
194
+ pointInTriangle(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
191
195
  n = n.nextZ;
192
196
  }
193
197
 
194
198
  // look for remaining points in decreasing z-order
195
199
  while (p && p.z >= minZ) {
196
- if (p !== ear.prev && p !== ear.next &&
197
- pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
198
- area(p.prev, p, p.next) >= 0) return false;
200
+ if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c &&
201
+ pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
199
202
  p = p.prevZ;
200
203
  }
201
204
 
202
205
  // look for remaining points in increasing z-order
203
206
  while (n && n.z <= maxZ) {
204
- if (n !== ear.prev && n !== ear.next &&
205
- pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y) &&
206
- area(n.prev, n, n.next) >= 0) return false;
207
+ if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c &&
208
+ pointInTriangle(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
207
209
  n = n.nextZ;
208
210
  }
209
211
 
@@ -211,17 +213,15 @@ function isEarHashed(ear, minX, minY, invSize) {
211
213
  }
212
214
 
213
215
  // go through all polygon nodes and cure small local self-intersections
214
- function cureLocalIntersections(start, triangles, dim) {
215
- var p = start;
216
+ function cureLocalIntersections(start, triangles) {
217
+ let p = start;
216
218
  do {
217
- var a = p.prev,
219
+ const a = p.prev,
218
220
  b = p.next.next;
219
221
 
220
222
  if (!equals(a, b) && intersects(a, p, p.next, b) && locallyInside(a, b) && locallyInside(b, a)) {
221
223
 
222
- triangles.push(a.i / dim);
223
- triangles.push(p.i / dim);
224
- triangles.push(b.i / dim);
224
+ triangles.push(a.i, p.i, b.i);
225
225
 
226
226
  // remove two nodes involved
227
227
  removeNode(p);
@@ -238,21 +238,21 @@ function cureLocalIntersections(start, triangles, dim) {
238
238
  // try splitting polygon into two and triangulate them independently
239
239
  function splitEarcut(start, triangles, dim, minX, minY, invSize) {
240
240
  // look for a valid diagonal that divides the polygon into two
241
- var a = start;
241
+ let a = start;
242
242
  do {
243
- var b = a.next.next;
243
+ let b = a.next.next;
244
244
  while (b !== a.prev) {
245
245
  if (a.i !== b.i && isValidDiagonal(a, b)) {
246
246
  // split the polygon in two by the diagonal
247
- var c = splitPolygon(a, b);
247
+ let c = splitPolygon(a, b);
248
248
 
249
249
  // filter colinear points around the cuts
250
250
  a = filterPoints(a, a.next);
251
251
  c = filterPoints(c, c.next);
252
252
 
253
253
  // run earcut on each half
254
- earcutLinked(a, triangles, dim, minX, minY, invSize);
255
- earcutLinked(c, triangles, dim, minX, minY, invSize);
254
+ earcutLinked(a, triangles, dim, minX, minY, invSize, 0);
255
+ earcutLinked(c, triangles, dim, minX, minY, invSize, 0);
256
256
  return;
257
257
  }
258
258
  b = b.next;
@@ -263,13 +263,12 @@ function splitEarcut(start, triangles, dim, minX, minY, invSize) {
263
263
 
264
264
  // link every hole into the outer loop, producing a single-ring polygon without holes
265
265
  function eliminateHoles(data, holeIndices, outerNode, dim) {
266
- var queue = [],
267
- i, len, start, end, list;
266
+ const queue = [];
268
267
 
269
- for (i = 0, len = holeIndices.length; i < len; i++) {
270
- start = holeIndices[i] * dim;
271
- end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
272
- list = linkedList(data, start, end, dim, false);
268
+ for (let i = 0, len = holeIndices.length; i < len; i++) {
269
+ const start = holeIndices[i] * dim;
270
+ const end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
271
+ const list = linkedList(data, start, end, dim, false);
273
272
  if (list === list.next) list.steiner = true;
274
273
  queue.push(getLeftmost(list));
275
274
  }
@@ -277,9 +276,8 @@ function eliminateHoles(data, holeIndices, outerNode, dim) {
277
276
  queue.sort(compareX);
278
277
 
279
278
  // process holes from left to right
280
- for (i = 0; i < queue.length; i++) {
279
+ for (let i = 0; i < queue.length; i++) {
281
280
  outerNode = eliminateHole(queue[i], outerNode);
282
- outerNode = filterPoints(outerNode, outerNode.next);
283
281
  }
284
282
 
285
283
  return outerNode;
@@ -291,41 +289,35 @@ function compareX(a, b) {
291
289
 
292
290
  // find a bridge between vertices that connects hole with an outer ring and and link it
293
291
  function eliminateHole(hole, outerNode) {
294
- var bridge = findHoleBridge(hole, outerNode);
292
+ const bridge = findHoleBridge(hole, outerNode);
295
293
  if (!bridge) {
296
294
  return outerNode;
297
295
  }
298
296
 
299
- var bridgeReverse = splitPolygon(bridge, hole);
297
+ const bridgeReverse = splitPolygon(bridge, hole);
300
298
 
301
299
  // filter collinear points around the cuts
302
- var filteredBridge = filterPoints(bridge, bridge.next);
303
300
  filterPoints(bridgeReverse, bridgeReverse.next);
304
-
305
- // Check if input node was removed by the filtering
306
- return outerNode === bridge ? filteredBridge : outerNode;
301
+ return filterPoints(bridge, bridge.next);
307
302
  }
308
303
 
309
304
  // David Eberly's algorithm for finding a bridge between hole and outer polygon
310
305
  function findHoleBridge(hole, outerNode) {
311
- var p = outerNode,
312
- hx = hole.x,
313
- hy = hole.y,
314
- qx = -Infinity,
315
- m;
306
+ let p = outerNode;
307
+ const hx = hole.x;
308
+ const hy = hole.y;
309
+ let qx = -Infinity;
310
+ let m;
316
311
 
317
312
  // find a segment intersected by a ray from the hole's leftmost point to the left;
318
313
  // segment's endpoint with lesser x will be potential connection point
319
314
  do {
320
315
  if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) {
321
- var x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);
316
+ const x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);
322
317
  if (x <= hx && x > qx) {
323
318
  qx = x;
324
- if (x === hx) {
325
- if (hy === p.y) return p;
326
- if (hy === p.next.y) return p.next;
327
- }
328
319
  m = p.x < p.next.x ? p : p.next;
320
+ if (x === hx) return m; // hole touches outer segment; pick leftmost endpoint
329
321
  }
330
322
  }
331
323
  p = p.next;
@@ -333,17 +325,14 @@ function findHoleBridge(hole, outerNode) {
333
325
 
334
326
  if (!m) return null;
335
327
 
336
- if (hx === qx) return m; // hole touches outer segment; pick leftmost endpoint
337
-
338
328
  // look for points inside the triangle of hole point, segment intersection and endpoint;
339
329
  // if there are no points found, we have a valid connection;
340
330
  // otherwise choose the point of the minimum angle with the ray as connection point
341
331
 
342
- var stop = m,
343
- mx = m.x,
344
- my = m.y,
345
- tanMin = Infinity,
346
- tan;
332
+ const stop = m;
333
+ const mx = m.x;
334
+ const my = m.y;
335
+ let tanMin = Infinity;
347
336
 
348
337
  p = m;
349
338
 
@@ -351,7 +340,7 @@ function findHoleBridge(hole, outerNode) {
351
340
  if (hx >= p.x && p.x >= mx && hx !== p.x &&
352
341
  pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) {
353
342
 
354
- tan = Math.abs(hy - p.y) / (hx - p.x); // tangential
343
+ const tan = Math.abs(hy - p.y) / (hx - p.x); // tangential
355
344
 
356
345
  if (locallyInside(p, hole) &&
357
346
  (tan < tanMin || (tan === tanMin && (p.x > m.x || (p.x === m.x && sectorContainsSector(m, p)))))) {
@@ -373,9 +362,9 @@ function sectorContainsSector(m, p) {
373
362
 
374
363
  // interlink polygon nodes in z-order
375
364
  function indexCurve(start, minX, minY, invSize) {
376
- var p = start;
365
+ let p = start;
377
366
  do {
378
- if (p.z === null) p.z = zOrder(p.x, p.y, minX, minY, invSize);
367
+ if (p.z === 0) p.z = zOrder(p.x, p.y, minX, minY, invSize);
379
368
  p.prevZ = p.prev;
380
369
  p.nextZ = p.next;
381
370
  p = p.next;
@@ -390,25 +379,26 @@ function indexCurve(start, minX, minY, invSize) {
390
379
  // Simon Tatham's linked list merge sort algorithm
391
380
  // http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
392
381
  function sortLinked(list) {
393
- var i, p, q, e, tail, numMerges, pSize, qSize,
394
- inSize = 1;
382
+ let numMerges;
383
+ let inSize = 1;
395
384
 
396
385
  do {
397
- p = list;
386
+ let p = list;
387
+ let e;
398
388
  list = null;
399
- tail = null;
389
+ let tail = null;
400
390
  numMerges = 0;
401
391
 
402
392
  while (p) {
403
393
  numMerges++;
404
- q = p;
405
- pSize = 0;
406
- for (i = 0; i < inSize; i++) {
394
+ let q = p;
395
+ let pSize = 0;
396
+ for (let i = 0; i < inSize; i++) {
407
397
  pSize++;
408
398
  q = q.nextZ;
409
399
  if (!q) break;
410
400
  }
411
- qSize = inSize;
401
+ let qSize = inSize;
412
402
 
413
403
  while (pSize > 0 || (qSize > 0 && q)) {
414
404
 
@@ -443,8 +433,8 @@ function sortLinked(list) {
443
433
  // z-order of a point given coords and inverse of the longer side of data bbox
444
434
  function zOrder(x, y, minX, minY, invSize) {
445
435
  // coords are transformed into non-negative 15-bit integer range
446
- x = 32767 * (x - minX) * invSize;
447
- y = 32767 * (y - minY) * invSize;
436
+ x = (x - minX) * invSize | 0;
437
+ y = (y - minY) * invSize | 0;
448
438
 
449
439
  x = (x | (x << 8)) & 0x00FF00FF;
450
440
  x = (x | (x << 4)) & 0x0F0F0F0F;
@@ -461,7 +451,7 @@ function zOrder(x, y, minX, minY, invSize) {
461
451
 
462
452
  // find the leftmost node of a polygon ring
463
453
  function getLeftmost(start) {
464
- var p = start,
454
+ let p = start,
465
455
  leftmost = start;
466
456
  do {
467
457
  if (p.x < leftmost.x || (p.x === leftmost.x && p.y < leftmost.y)) leftmost = p;
@@ -473,9 +463,9 @@ function getLeftmost(start) {
473
463
 
474
464
  // check if a point lies within a convex triangle
475
465
  function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {
476
- return (cx - px) * (ay - py) - (ax - px) * (cy - py) >= 0 &&
477
- (ax - px) * (by - py) - (bx - px) * (ay - py) >= 0 &&
478
- (bx - px) * (cy - py) - (cx - px) * (by - py) >= 0;
466
+ return (cx - px) * (ay - py) >= (ax - px) * (cy - py) &&
467
+ (ax - px) * (by - py) >= (bx - px) * (ay - py) &&
468
+ (bx - px) * (cy - py) >= (cx - px) * (by - py);
479
469
  }
480
470
 
481
471
  // check if a diagonal between two polygon nodes is valid (lies in polygon interior)
@@ -498,10 +488,10 @@ function equals(p1, p2) {
498
488
 
499
489
  // check if two segments intersect
500
490
  function intersects(p1, q1, p2, q2) {
501
- var o1 = sign(area(p1, q1, p2));
502
- var o2 = sign(area(p1, q1, q2));
503
- var o3 = sign(area(p2, q2, p1));
504
- var o4 = sign(area(p2, q2, q1));
491
+ const o1 = sign(area(p1, q1, p2));
492
+ const o2 = sign(area(p1, q1, q2));
493
+ const o3 = sign(area(p2, q2, p1));
494
+ const o4 = sign(area(p2, q2, q1));
505
495
 
506
496
  if (o1 !== o2 && o3 !== o4) return true; // general case
507
497
 
@@ -524,7 +514,7 @@ function sign(num) {
524
514
 
525
515
  // check if a polygon diagonal intersects any polygon segments
526
516
  function intersectsPolygon(a, b) {
527
- var p = a;
517
+ let p = a;
528
518
  do {
529
519
  if (p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i &&
530
520
  intersects(p, p.next, a, b)) return true;
@@ -543,10 +533,10 @@ function locallyInside(a, b) {
543
533
 
544
534
  // check if the middle point of a polygon diagonal is inside the polygon
545
535
  function middleInside(a, b) {
546
- var p = a,
547
- inside = false,
548
- px = (a.x + b.x) / 2,
549
- py = (a.y + b.y) / 2;
536
+ let p = a;
537
+ let inside = false;
538
+ const px = (a.x + b.x) / 2;
539
+ const py = (a.y + b.y) / 2;
550
540
  do {
551
541
  if (((p.y > py) !== (p.next.y > py)) && p.next.y !== p.y &&
552
542
  (px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x))
@@ -560,8 +550,8 @@ function middleInside(a, b) {
560
550
  // link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;
561
551
  // if one belongs to the outer ring and another to a hole, it merges it into a single ring
562
552
  function splitPolygon(a, b) {
563
- var a2 = new Node(a.i, a.x, a.y),
564
- b2 = new Node(b.i, b.x, b.y),
553
+ const a2 = createNode(a.i, a.x, a.y),
554
+ b2 = createNode(b.i, b.x, b.y),
565
555
  an = a.next,
566
556
  bp = b.prev;
567
557
 
@@ -582,7 +572,7 @@ function splitPolygon(a, b) {
582
572
 
583
573
  // create a node and optionally link it with previous one (in a circular doubly linked list)
584
574
  function insertNode(i, x, y, last) {
585
- var p = new Node(i, x, y);
575
+ const p = createNode(i, x, y);
586
576
 
587
577
  if (!last) {
588
578
  p.prev = p;
@@ -605,49 +595,39 @@ function removeNode(p) {
605
595
  if (p.nextZ) p.nextZ.prevZ = p.prevZ;
606
596
  }
607
597
 
608
- function Node(i, x, y) {
609
- // vertex index in coordinates array
610
- this.i = i;
611
-
612
- // vertex coordinates
613
- this.x = x;
614
- this.y = y;
615
-
616
- // previous and next vertex nodes in a polygon ring
617
- this.prev = null;
618
- this.next = null;
619
-
620
- // z-order curve value
621
- this.z = null;
622
-
623
- // previous and next nodes in z-order
624
- this.prevZ = null;
625
- this.nextZ = null;
626
-
627
- // indicates whether this is a steiner point
628
- this.steiner = false;
598
+ function createNode(i, x, y) {
599
+ return {
600
+ i, // vertex index in coordinates array
601
+ x, y, // vertex coordinates
602
+ prev: null, // previous and next vertex nodes in a polygon ring
603
+ next: null,
604
+ z: 0, // z-order curve value
605
+ prevZ: null, // previous and next nodes in z-order
606
+ nextZ: null,
607
+ steiner: false // indicates whether this is a steiner point
608
+ };
629
609
  }
630
610
 
631
611
  // return a percentage difference between the polygon area and its triangulation area;
632
612
  // used to verify correctness of triangulation
633
- earcut.deviation = function (data, holeIndices, dim, triangles) {
634
- var hasHoles = holeIndices && holeIndices.length;
635
- var outerLen = hasHoles ? holeIndices[0] * dim : data.length;
613
+ function deviation(data, holeIndices, dim, triangles) {
614
+ const hasHoles = holeIndices && holeIndices.length;
615
+ const outerLen = hasHoles ? holeIndices[0] * dim : data.length;
636
616
 
637
- var polygonArea = Math.abs(signedArea(data, 0, outerLen, dim));
617
+ let polygonArea = Math.abs(signedArea(data, 0, outerLen, dim));
638
618
  if (hasHoles) {
639
- for (var i = 0, len = holeIndices.length; i < len; i++) {
640
- var start = holeIndices[i] * dim;
641
- var end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
619
+ for (let i = 0, len = holeIndices.length; i < len; i++) {
620
+ const start = holeIndices[i] * dim;
621
+ const end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
642
622
  polygonArea -= Math.abs(signedArea(data, start, end, dim));
643
623
  }
644
624
  }
645
625
 
646
- var trianglesArea = 0;
647
- for (i = 0; i < triangles.length; i += 3) {
648
- var a = triangles[i] * dim;
649
- var b = triangles[i + 1] * dim;
650
- var c = triangles[i + 2] * dim;
626
+ let trianglesArea = 0;
627
+ for (let i = 0; i < triangles.length; i += 3) {
628
+ const a = triangles[i] * dim;
629
+ const b = triangles[i + 1] * dim;
630
+ const c = triangles[i + 2] * dim;
651
631
  trianglesArea += Math.abs(
652
632
  (data[a] - data[c]) * (data[b + 1] - data[a + 1]) -
653
633
  (data[a] - data[b]) * (data[c + 1] - data[a + 1]));
@@ -655,11 +635,11 @@ earcut.deviation = function (data, holeIndices, dim, triangles) {
655
635
 
656
636
  return polygonArea === 0 && trianglesArea === 0 ? 0 :
657
637
  Math.abs((trianglesArea - polygonArea) / polygonArea);
658
- };
638
+ }
659
639
 
660
640
  function signedArea(data, start, end, dim) {
661
- var sum = 0;
662
- for (var i = start, j = end - dim; i < end; i += dim) {
641
+ let sum = 0;
642
+ for (let i = start, j = end - dim; i < end; i += dim) {
663
643
  sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
664
644
  j = i;
665
645
  }
@@ -667,24 +647,30 @@ function signedArea(data, start, end, dim) {
667
647
  }
668
648
 
669
649
  // turn a polygon in a multi-dimensional array form (e.g. as in GeoJSON) into a form Earcut accepts
670
- earcut.flatten = function (data) {
671
- var dim = data[0][0].length,
672
- result = {vertices: [], holes: [], dimensions: dim},
673
- holeIndex = 0;
674
-
675
- for (var i = 0; i < data.length; i++) {
676
- for (var j = 0; j < data[i].length; j++) {
677
- for (var d = 0; d < dim; d++) result.vertices.push(data[i][j][d]);
650
+ function flatten(data) {
651
+ const vertices = [];
652
+ const holes = [];
653
+ const dimensions = data[0][0].length;
654
+ let holeIndex = 0;
655
+ let prevLen = 0;
656
+
657
+ for (const ring of data) {
658
+ for (const p of ring) {
659
+ for (let d = 0; d < dimensions; d++) vertices.push(p[d]);
678
660
  }
679
- if (i > 0) {
680
- holeIndex += data[i - 1].length;
681
- result.holes.push(holeIndex);
661
+ if (prevLen) {
662
+ holeIndex += prevLen;
663
+ holes.push(holeIndex);
682
664
  }
665
+ prevLen = ring.length;
683
666
  }
684
- return result;
685
- };
667
+ return {vertices, holes, dimensions};
668
+ }
669
+
670
+ exports.default = earcut;
671
+ exports.deviation = deviation;
672
+ exports.flatten = flatten;
686
673
 
687
- },{}]},{},[1])(1)
688
- });
674
+ Object.defineProperty(exports, '__esModule', { value: true });
689
675
 
690
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJzcmMvZWFyY3V0LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbigpe2Z1bmN0aW9uIHIoZSxuLHQpe2Z1bmN0aW9uIG8oaSxmKXtpZighbltpXSl7aWYoIWVbaV0pe3ZhciBjPVwiZnVuY3Rpb25cIj09dHlwZW9mIHJlcXVpcmUmJnJlcXVpcmU7aWYoIWYmJmMpcmV0dXJuIGMoaSwhMCk7aWYodSlyZXR1cm4gdShpLCEwKTt2YXIgYT1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK2krXCInXCIpO3Rocm93IGEuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixhfXZhciBwPW5baV09e2V4cG9ydHM6e319O2VbaV1bMF0uY2FsbChwLmV4cG9ydHMsZnVuY3Rpb24ocil7dmFyIG49ZVtpXVsxXVtyXTtyZXR1cm4gbyhufHxyKX0scCxwLmV4cG9ydHMscixlLG4sdCl9cmV0dXJuIG5baV0uZXhwb3J0c31mb3IodmFyIHU9XCJmdW5jdGlvblwiPT10eXBlb2YgcmVxdWlyZSYmcmVxdWlyZSxpPTA7aTx0Lmxlbmd0aDtpKyspbyh0W2ldKTtyZXR1cm4gb31yZXR1cm4gcn0pKCkiLCIndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZWFyY3V0O1xubW9kdWxlLmV4cG9ydHMuZGVmYXVsdCA9IGVhcmN1dDtcblxuZnVuY3Rpb24gZWFyY3V0KGRhdGEsIGhvbGVJbmRpY2VzLCBkaW0pIHtcblxuICAgIGRpbSA9IGRpbSB8fCAyO1xuXG4gICAgdmFyIGhhc0hvbGVzID0gaG9sZUluZGljZXMgJiYgaG9sZUluZGljZXMubGVuZ3RoLFxuICAgICAgICBvdXRlckxlbiA9IGhhc0hvbGVzID8gaG9sZUluZGljZXNbMF0gKiBkaW0gOiBkYXRhLmxlbmd0aCxcbiAgICAgICAgb3V0ZXJOb2RlID0gbGlua2VkTGlzdChkYXRhLCAwLCBvdXRlckxlbiwgZGltLCB0cnVlKSxcbiAgICAgICAgdHJpYW5nbGVzID0gW107XG5cbiAgICBpZiAoIW91dGVyTm9kZSB8fCBvdXRlck5vZGUubmV4dCA9PT0gb3V0ZXJOb2RlLnByZXYpIHJldHVybiB0cmlhbmdsZXM7XG5cbiAgICB2YXIgbWluWCwgbWluWSwgbWF4WCwgbWF4WSwgeCwgeSwgaW52U2l6ZTtcblxuICAgIGlmIChoYXNIb2xlcykgb3V0ZXJOb2RlID0gZWxpbWluYXRlSG9sZXMoZGF0YSwgaG9sZUluZGljZXMsIG91dGVyTm9kZSwgZGltKTtcblxuICAgIC8vIGlmIHRoZSBzaGFwZSBpcyBub3QgdG9vIHNpbXBsZSwgd2UnbGwgdXNlIHotb3JkZXIgY3VydmUgaGFzaCBsYXRlcjsgY2FsY3VsYXRlIHBvbHlnb24gYmJveFxuICAgIGlmIChkYXRhLmxlbmd0aCA+IDgwICogZGltKSB7XG4gICAgICAgIG1pblggPSBtYXhYID0gZGF0YVswXTtcbiAgICAgICAgbWluWSA9IG1heFkgPSBkYXRhWzFdO1xuXG4gICAgICAgIGZvciAodmFyIGkgPSBkaW07IGkgPCBvdXRlckxlbjsgaSArPSBkaW0pIHtcbiAgICAgICAgICAgIHggPSBkYXRhW2ldO1xuICAgICAgICAgICAgeSA9IGRhdGFbaSArIDFdO1xuICAgICAgICAgICAgaWYgKHggPCBtaW5YKSBtaW5YID0geDtcbiAgICAgICAgICAgIGlmICh5IDwgbWluWSkgbWluWSA9IHk7XG4gICAgICAgICAgICBpZiAoeCA+IG1heFgpIG1heFggPSB4O1xuICAgICAgICAgICAgaWYgKHkgPiBtYXhZKSBtYXhZID0geTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIG1pblgsIG1pblkgYW5kIGludlNpemUgYXJlIGxhdGVyIHVzZWQgdG8gdHJhbnNmb3JtIGNvb3JkcyBpbnRvIGludGVnZXJzIGZvciB6LW9yZGVyIGNhbGN1bGF0aW9uXG4gICAgICAgIGludlNpemUgPSBNYXRoLm1heChtYXhYIC0gbWluWCwgbWF4WSAtIG1pblkpO1xuICAgICAgICBpbnZTaXplID0gaW52U2l6ZSAhPT0gMCA/IDEgLyBpbnZTaXplIDogMDtcbiAgICB9XG5cbiAgICBlYXJjdXRMaW5rZWQob3V0ZXJOb2RlLCB0cmlhbmdsZXMsIGRpbSwgbWluWCwgbWluWSwgaW52U2l6ZSk7XG5cbiAgICByZXR1cm4gdHJpYW5nbGVzO1xufVxuXG4vLyBjcmVhdGUgYSBjaXJjdWxhciBkb3VibHkgbGlua2VkIGxpc3QgZnJvbSBwb2x5Z29uIHBvaW50cyBpbiB0aGUgc3BlY2lmaWVkIHdpbmRpbmcgb3JkZXJcbmZ1bmN0aW9uIGxpbmtlZExpc3QoZGF0YSwgc3RhcnQsIGVuZCwgZGltLCBjbG9ja3dpc2UpIHtcbiAgICB2YXIgaSwgbGFzdDtcblxuICAgIGlmIChjbG9ja3dpc2UgPT09IChzaWduZWRBcmVhKGRhdGEsIHN0YXJ0LCBlbmQsIGRpbSkgPiAwKSkge1xuICAgICAgICBmb3IgKGkgPSBzdGFydDsgaSA8IGVuZDsgaSArPSBkaW0pIGxhc3QgPSBpbnNlcnROb2RlKGksIGRhdGFbaV0sIGRhdGFbaSArIDFdLCBsYXN0KTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBmb3IgKGkgPSBlbmQgLSBkaW07IGkgPj0gc3RhcnQ7IGkgLT0gZGltKSBsYXN0ID0gaW5zZXJ0Tm9kZShpLCBkYXRhW2ldLCBkYXRhW2kgKyAxXSwgbGFzdCk7XG4gICAgfVxuXG4gICAgaWYgKGxhc3QgJiYgZXF1YWxzKGxhc3QsIGxhc3QubmV4dCkpIHtcbiAgICAgICAgcmVtb3ZlTm9kZShsYXN0KTtcbiAgICAgICAgbGFzdCA9IGxhc3QubmV4dDtcbiAgICB9XG5cbiAgICByZXR1cm4gbGFzdDtcbn1cblxuLy8gZWxpbWluYXRlIGNvbGluZWFyIG9yIGR1cGxpY2F0ZSBwb2ludHNcbmZ1bmN0aW9uIGZpbHRlclBvaW50cyhzdGFydCwgZW5kKSB7XG4gICAgaWYgKCFzdGFydCkgcmV0dXJuIHN0YXJ0O1xuICAgIGlmICghZW5kKSBlbmQgPSBzdGFydDtcblxuICAgIHZhciBwID0gc3RhcnQsXG4gICAgICAgIGFnYWluO1xuICAgIGRvIHtcbiAgICAgICAgYWdhaW4gPSBmYWxzZTtcblxuICAgICAgICBpZiAoIXAuc3RlaW5lciAmJiAoZXF1YWxzKHAsIHAubmV4dCkgfHwgYXJlYShwLnByZXYsIHAsIHAubmV4dCkgPT09IDApKSB7XG4gICAgICAgICAgICByZW1vdmVOb2RlKHApO1xuICAgICAgICAgICAgcCA9IGVuZCA9IHAucHJldjtcbiAgICAgICAgICAgIGlmIChwID09PSBwLm5leHQpIGJyZWFrO1xuICAgICAgICAgICAgYWdhaW4gPSB0cnVlO1xuXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBwID0gcC5uZXh0O1xuICAgICAgICB9XG4gICAgfSB3aGlsZSAoYWdhaW4gfHwgcCAhPT0gZW5kKTtcblxuICAgIHJldHVybiBlbmQ7XG59XG5cbi8vIG1haW4gZWFyIHNsaWNpbmcgbG9vcCB3aGljaCB0cmlhbmd1bGF0ZXMgYSBwb2x5Z29uIChnaXZlbiBhcyBhIGxpbmtlZCBsaXN0KVxuZnVuY3Rpb24gZWFyY3V0TGlua2VkKGVhciwgdHJpYW5nbGVzLCBkaW0sIG1pblgsIG1pblksIGludlNpemUsIHBhc3MpIHtcbiAgICBpZiAoIWVhcikgcmV0dXJuO1xuXG4gICAgLy8gaW50ZXJsaW5rIHBvbHlnb24gbm9kZXMgaW4gei1vcmRlclxuICAgIGlmICghcGFzcyAmJiBpbnZTaXplKSBpbmRleEN1cnZlKGVhciwgbWluWCwgbWluWSwgaW52U2l6ZSk7XG5cbiAgICB2YXIgc3RvcCA9IGVhcixcbiAgICAgICAgcHJldiwgbmV4dDtcblxuICAgIC8vIGl0ZXJhdGUgdGhyb3VnaCBlYXJzLCBzbGljaW5nIHRoZW0gb25lIGJ5IG9uZVxuICAgIHdoaWxlIChlYXIucHJldiAhPT0gZWFyLm5leHQpIHtcbiAgICAgICAgcHJldiA9IGVhci5wcmV2O1xuICAgICAgICBuZXh0ID0gZWFyLm5leHQ7XG5cbiAgICAgICAgaWYgKGludlNpemUgPyBpc0Vhckhhc2hlZChlYXIsIG1pblgsIG1pblksIGludlNpemUpIDogaXNFYXIoZWFyKSkge1xuICAgICAgICAgICAgLy8gY3V0IG9mZiB0aGUgdHJpYW5nbGVcbiAgICAgICAgICAgIHRyaWFuZ2xlcy5wdXNoKHByZXYuaSAvIGRpbSk7XG4gICAgICAgICAgICB0cmlhbmdsZXMucHVzaChlYXIuaSAvIGRpbSk7XG4gICAgICAgICAgICB0cmlhbmdsZXMucHVzaChuZXh0LmkgLyBkaW0pO1xuXG4gICAgICAgICAgICByZW1vdmVOb2RlKGVhcik7XG5cbiAgICAgICAgICAgIC8vIHNraXBwaW5nIHRoZSBuZXh0IHZlcnRleCBsZWFkcyB0byBsZXNzIHNsaXZlciB0cmlhbmdsZXNcbiAgICAgICAgICAgIGVhciA9IG5leHQubmV4dDtcbiAgICAgICAgICAgIHN0b3AgPSBuZXh0Lm5leHQ7XG5cbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgZWFyID0gbmV4dDtcblxuICAgICAgICAvLyBpZiB3ZSBsb29wZWQgdGhyb3VnaCB0aGUgd2hvbGUgcmVtYWluaW5nIHBvbHlnb24gYW5kIGNhbid0IGZpbmQgYW55IG1vcmUgZWFyc1xuICAgICAgICBpZiAoZWFyID09PSBzdG9wKSB7XG4gICAgICAgICAgICAvLyB0cnkgZmlsdGVyaW5nIHBvaW50cyBhbmQgc2xpY2luZyBhZ2FpblxuICAgICAgICAgICAgaWYgKCFwYXNzKSB7XG4gICAgICAgICAgICAgICAgZWFyY3V0TGlua2VkKGZpbHRlclBvaW50cyhlYXIpLCB0cmlhbmdsZXMsIGRpbSwgbWluWCwgbWluWSwgaW52U2l6ZSwgMSk7XG5cbiAgICAgICAgICAgIC8vIGlmIHRoaXMgZGlkbid0IHdvcmssIHRyeSBjdXJpbmcgYWxsIHNtYWxsIHNlbGYtaW50ZXJzZWN0aW9ucyBsb2NhbGx5XG4gICAgICAgICAgICB9IGVsc2UgaWYgKHBhc3MgPT09IDEpIHtcbiAgICAgICAgICAgICAgICBlYXIgPSBjdXJlTG9jYWxJbnRlcnNlY3Rpb25zKGZpbHRlclBvaW50cyhlYXIpLCB0cmlhbmdsZXMsIGRpbSk7XG4gICAgICAgICAgICAgICAgZWFyY3V0TGlua2VkKGVhciwgdHJpYW5nbGVzLCBkaW0sIG1pblgsIG1pblksIGludlNpemUsIDIpO1xuXG4gICAgICAgICAgICAvLyBhcyBhIGxhc3QgcmVzb3J0LCB0cnkgc3BsaXR0aW5nIHRoZSByZW1haW5pbmcgcG9seWdvbiBpbnRvIHR3b1xuICAgICAgICAgICAgfSBlbHNlIGlmIChwYXNzID09PSAyKSB7XG4gICAgICAgICAgICAgICAgc3BsaXRFYXJjdXQoZWFyLCB0cmlhbmdsZXMsIGRpbSwgbWluWCwgbWluWSwgaW52U2l6ZSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgfVxufVxuXG4vLyBjaGVjayB3aGV0aGVyIGEgcG9seWdvbiBub2RlIGZvcm1zIGEgdmFsaWQgZWFyIHdpdGggYWRqYWNlbnQgbm9kZXNcbmZ1bmN0aW9uIGlzRWFyKGVhcikge1xuICAgIHZhciBhID0gZWFyLnByZXYsXG4gICAgICAgIGIgPSBlYXIsXG4gICAgICAgIGMgPSBlYXIubmV4dDtcblxuICAgIGlmIChhcmVhKGEsIGIsIGMpID49IDApIHJldHVybiBmYWxzZTsgLy8gcmVmbGV4LCBjYW4ndCBiZSBhbiBlYXJcblxuICAgIC8vIG5vdyBtYWtlIHN1cmUgd2UgZG9uJ3QgaGF2ZSBvdGhlciBwb2ludHMgaW5zaWRlIHRoZSBwb3RlbnRpYWwgZWFyXG4gICAgdmFyIHAgPSBlYXIubmV4dC5uZXh0O1xuXG4gICAgd2hpbGUgKHAgIT09IGVhci5wcmV2KSB7XG4gICAgICAgIGlmIChwb2ludEluVHJpYW5nbGUoYS54LCBhLnksIGIueCwgYi55LCBjLngsIGMueSwgcC54LCBwLnkpICYmXG4gICAgICAgICAgICBhcmVhKHAucHJldiwgcCwgcC5uZXh0KSA+PSAwKSByZXR1cm4gZmFsc2U7XG4gICAgICAgIHAgPSBwLm5leHQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7XG59XG5cbmZ1bmN0aW9uIGlzRWFySGFzaGVkKGVhciwgbWluWCwgbWluWSwgaW52U2l6ZSkge1xuICAgIHZhciBhID0gZWFyLnByZXYsXG4gICAgICAgIGIgPSBlYXIsXG4gICAgICAgIGMgPSBlYXIubmV4dDtcblxuICAgIGlmIChhcmVhKGEsIGIsIGMpID49IDApIHJldHVybiBmYWxzZTsgLy8gcmVmbGV4LCBjYW4ndCBiZSBhbiBlYXJcblxuICAgIC8vIHRyaWFuZ2xlIGJib3g7IG1pbiAmIG1heCBhcmUgY2FsY3VsYXRlZCBsaWtlIHRoaXMgZm9yIHNwZWVkXG4gICAgdmFyIG1pblRYID0gYS54IDwgYi54ID8gKGEueCA8IGMueCA/IGEueCA6IGMueCkgOiAoYi54IDwgYy54ID8gYi54IDogYy54KSxcbiAgICAgICAgbWluVFkgPSBhLnkgPCBiLnkgPyAoYS55IDwgYy55ID8gYS55IDogYy55KSA6IChiLnkgPCBjLnkgPyBiLnkgOiBjLnkpLFxuICAgICAgICBtYXhUWCA9IGEueCA+IGIueCA/IChhLnggPiBjLnggPyBhLnggOiBjLngpIDogKGIueCA+IGMueCA/IGIueCA6IGMueCksXG4gICAgICAgIG1heFRZID0gYS55ID4gYi55ID8gKGEueSA+IGMueSA/IGEueSA6IGMueSkgOiAoYi55ID4gYy55ID8gYi55IDogYy55KTtcblxuICAgIC8vIHotb3JkZXIgcmFuZ2UgZm9yIHRoZSBjdXJyZW50IHRyaWFuZ2xlIGJib3g7XG4gICAgdmFyIG1pblogPSB6T3JkZXIobWluVFgsIG1pblRZLCBtaW5YLCBtaW5ZLCBpbnZTaXplKSxcbiAgICAgICAgbWF4WiA9IHpPcmRlcihtYXhUWCwgbWF4VFksIG1pblgsIG1pblksIGludlNpemUpO1xuXG4gICAgdmFyIHAgPSBlYXIucHJldlosXG4gICAgICAgIG4gPSBlYXIubmV4dFo7XG5cbiAgICAvLyBsb29rIGZvciBwb2ludHMgaW5zaWRlIHRoZSB0cmlhbmdsZSBpbiBib3RoIGRpcmVjdGlvbnNcbiAgICB3aGlsZSAocCAmJiBwLnogPj0gbWluWiAmJiBuICYmIG4ueiA8PSBtYXhaKSB7XG4gICAgICAgIGlmIChwICE9PSBlYXIucHJldiAmJiBwICE9PSBlYXIubmV4dCAmJlxuICAgICAgICAgICAgcG9pbnRJblRyaWFuZ2xlKGEueCwgYS55LCBiLngsIGIueSwgYy54LCBjLnksIHAueCwgcC55KSAmJlxuICAgICAgICAgICAgYXJlYShwLnByZXYsIHAsIHAubmV4dCkgPj0gMCkgcmV0dXJuIGZhbHNlO1xuICAgICAgICBwID0gcC5wcmV2WjtcblxuICAgICAgICBpZiAobiAhPT0gZWFyLnByZXYgJiYgbiAhPT0gZWFyLm5leHQgJiZcbiAgICAgICAgICAgIHBvaW50SW5UcmlhbmdsZShhLngsIGEueSwgYi54LCBiLnksIGMueCwgYy55LCBuLngsIG4ueSkgJiZcbiAgICAgICAgICAgIGFyZWEobi5wcmV2LCBuLCBuLm5leHQpID49IDApIHJldHVybiBmYWxzZTtcbiAgICAgICAgbiA9IG4ubmV4dFo7XG4gICAgfVxuXG4gICAgLy8gbG9vayBmb3IgcmVtYWluaW5nIHBvaW50cyBpbiBkZWNyZWFzaW5nIHotb3JkZXJcbiAgICB3aGlsZSAocCAmJiBwLnogPj0gbWluWikge1xuICAgICAgICBpZiAocCAhPT0gZWFyLnByZXYgJiYgcCAhPT0gZWFyLm5leHQgJiZcbiAgICAgICAgICAgIHBvaW50SW5UcmlhbmdsZShhLngsIGEueSwgYi54LCBiLnksIGMueCwgYy55LCBwLngsIHAueSkgJiZcbiAgICAgICAgICAgIGFyZWEocC5wcmV2LCBwLCBwLm5leHQpID49IDApIHJldHVybiBmYWxzZTtcbiAgICAgICAgcCA9IHAucHJldlo7XG4gICAgfVxuXG4gICAgLy8gbG9vayBmb3IgcmVtYWluaW5nIHBvaW50cyBpbiBpbmNyZWFzaW5nIHotb3JkZXJcbiAgICB3aGlsZSAobiAmJiBuLnogPD0gbWF4Wikge1xuICAgICAgICBpZiAobiAhPT0gZWFyLnByZXYgJiYgbiAhPT0gZWFyLm5leHQgJiZcbiAgICAgICAgICAgIHBvaW50SW5UcmlhbmdsZShhLngsIGEueSwgYi54LCBiLnksIGMueCwgYy55LCBuLngsIG4ueSkgJiZcbiAgICAgICAgICAgIGFyZWEobi5wcmV2LCBuLCBuLm5leHQpID49IDApIHJldHVybiBmYWxzZTtcbiAgICAgICAgbiA9IG4ubmV4dFo7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7XG59XG5cbi8vIGdvIHRocm91Z2ggYWxsIHBvbHlnb24gbm9kZXMgYW5kIGN1cmUgc21hbGwgbG9jYWwgc2VsZi1pbnRlcnNlY3Rpb25zXG5mdW5jdGlvbiBjdXJlTG9jYWxJbnRlcnNlY3Rpb25zKHN0YXJ0LCB0cmlhbmdsZXMsIGRpbSkge1xuICAgIHZhciBwID0gc3RhcnQ7XG4gICAgZG8ge1xuICAgICAgICB2YXIgYSA9IHAucHJldixcbiAgICAgICAgICAgIGIgPSBwLm5leHQubmV4dDtcblxuICAgICAgICBpZiAoIWVxdWFscyhhLCBiKSAmJiBpbnRlcnNlY3RzKGEsIHAsIHAubmV4dCwgYikgJiYgbG9jYWxseUluc2lkZShhLCBiKSAmJiBsb2NhbGx5SW5zaWRlKGIsIGEpKSB7XG5cbiAgICAgICAgICAgIHRyaWFuZ2xlcy5wdXNoKGEuaSAvIGRpbSk7XG4gICAgICAgICAgICB0cmlhbmdsZXMucHVzaChwLmkgLyBkaW0pO1xuICAgICAgICAgICAgdHJpYW5nbGVzLnB1c2goYi5pIC8gZGltKTtcblxuICAgICAgICAgICAgLy8gcmVtb3ZlIHR3byBub2RlcyBpbnZvbHZlZFxuICAgICAgICAgICAgcmVtb3ZlTm9kZShwKTtcbiAgICAgICAgICAgIHJlbW92ZU5vZGUocC5uZXh0KTtcblxuICAgICAgICAgICAgcCA9IHN0YXJ0ID0gYjtcbiAgICAgICAgfVxuICAgICAgICBwID0gcC5uZXh0O1xuICAgIH0gd2hpbGUgKHAgIT09IHN0YXJ0KTtcblxuICAgIHJldHVybiBmaWx0ZXJQb2ludHMocCk7XG59XG5cbi8vIHRyeSBzcGxpdHRpbmcgcG9seWdvbiBpbnRvIHR3byBhbmQgdHJpYW5ndWxhdGUgdGhlbSBpbmRlcGVuZGVudGx5XG5mdW5jdGlvbiBzcGxpdEVhcmN1dChzdGFydCwgdHJpYW5nbGVzLCBkaW0sIG1pblgsIG1pblksIGludlNpemUpIHtcbiAgICAvLyBsb29rIGZvciBhIHZhbGlkIGRpYWdvbmFsIHRoYXQgZGl2aWRlcyB0aGUgcG9seWdvbiBpbnRvIHR3b1xuICAgIHZhciBhID0gc3RhcnQ7XG4gICAgZG8ge1xuICAgICAgICB2YXIgYiA9IGEubmV4dC5uZXh0O1xuICAgICAgICB3aGlsZSAoYiAhPT0gYS5wcmV2KSB7XG4gICAgICAgICAgICBpZiAoYS5pICE9PSBiLmkgJiYgaXNWYWxpZERpYWdvbmFsKGEsIGIpKSB7XG4gICAgICAgICAgICAgICAgLy8gc3BsaXQgdGhlIHBvbHlnb24gaW4gdHdvIGJ5IHRoZSBkaWFnb25hbFxuICAgICAgICAgICAgICAgIHZhciBjID0gc3BsaXRQb2x5Z29uKGEsIGIpO1xuXG4gICAgICAgICAgICAgICAgLy8gZmlsdGVyIGNvbGluZWFyIHBvaW50cyBhcm91bmQgdGhlIGN1dHNcbiAgICAgICAgICAgICAgICBhID0gZmlsdGVyUG9pbnRzKGEsIGEubmV4dCk7XG4gICAgICAgICAgICAgICAgYyA9IGZpbHRlclBvaW50cyhjLCBjLm5leHQpO1xuXG4gICAgICAgICAgICAgICAgLy8gcnVuIGVhcmN1dCBvbiBlYWNoIGhhbGZcbiAgICAgICAgICAgICAgICBlYXJjdXRMaW5rZWQoYSwgdHJpYW5nbGVzLCBkaW0sIG1pblgsIG1pblksIGludlNpemUpO1xuICAgICAgICAgICAgICAgIGVhcmN1dExpbmtlZChjLCB0cmlhbmdsZXMsIGRpbSwgbWluWCwgbWluWSwgaW52U2l6ZSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYiA9IGIubmV4dDtcbiAgICAgICAgfVxuICAgICAgICBhID0gYS5uZXh0O1xuICAgIH0gd2hpbGUgKGEgIT09IHN0YXJ0KTtcbn1cblxuLy8gbGluayBldmVyeSBob2xlIGludG8gdGhlIG91dGVyIGxvb3AsIHByb2R1Y2luZyBhIHNpbmdsZS1yaW5nIHBvbHlnb24gd2l0aG91dCBob2xlc1xuZnVuY3Rpb24gZWxpbWluYXRlSG9sZXMoZGF0YSwgaG9sZUluZGljZXMsIG91dGVyTm9kZSwgZGltKSB7XG4gICAgdmFyIHF1ZXVlID0gW10sXG4gICAgICAgIGksIGxlbiwgc3RhcnQsIGVuZCwgbGlzdDtcblxuICAgIGZvciAoaSA9IDAsIGxlbiA9IGhvbGVJbmRpY2VzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgICAgIHN0YXJ0ID0gaG9sZUluZGljZXNbaV0gKiBkaW07XG4gICAgICAgIGVuZCA9IGkgPCBsZW4gLSAxID8gaG9sZUluZGljZXNbaSArIDFdICogZGltIDogZGF0YS5sZW5ndGg7XG4gICAgICAgIGxpc3QgPSBsaW5rZWRMaXN0KGRhdGEsIHN0YXJ0LCBlbmQsIGRpbSwgZmFsc2UpO1xuICAgICAgICBpZiAobGlzdCA9PT0gbGlzdC5uZXh0KSBsaXN0LnN0ZWluZXIgPSB0cnVlO1xuICAgICAgICBxdWV1ZS5wdXNoKGdldExlZnRtb3N0KGxpc3QpKTtcbiAgICB9XG5cbiAgICBxdWV1ZS5zb3J0KGNvbXBhcmVYKTtcblxuICAgIC8vIHByb2Nlc3MgaG9sZXMgZnJvbSBsZWZ0IHRvIHJpZ2h0XG4gICAgZm9yIChpID0gMDsgaSA8IHF1ZXVlLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIG91dGVyTm9kZSA9IGVsaW1pbmF0ZUhvbGUocXVldWVbaV0sIG91dGVyTm9kZSk7XG4gICAgICAgIG91dGVyTm9kZSA9IGZpbHRlclBvaW50cyhvdXRlck5vZGUsIG91dGVyTm9kZS5uZXh0KTtcbiAgICB9XG5cbiAgICByZXR1cm4gb3V0ZXJOb2RlO1xufVxuXG5mdW5jdGlvbiBjb21wYXJlWChhLCBiKSB7XG4gICAgcmV0dXJuIGEueCAtIGIueDtcbn1cblxuLy8gZmluZCBhIGJyaWRnZSBiZXR3ZWVuIHZlcnRpY2VzIHRoYXQgY29ubmVjdHMgaG9sZSB3aXRoIGFuIG91dGVyIHJpbmcgYW5kIGFuZCBsaW5rIGl0XG5mdW5jdGlvbiBlbGltaW5hdGVIb2xlKGhvbGUsIG91dGVyTm9kZSkge1xuICAgIHZhciBicmlkZ2UgPSBmaW5kSG9sZUJyaWRnZShob2xlLCBvdXRlck5vZGUpO1xuICAgIGlmICghYnJpZGdlKSB7XG4gICAgICAgIHJldHVybiBvdXRlck5vZGU7XG4gICAgfVxuXG4gICAgdmFyIGJyaWRnZVJldmVyc2UgPSBzcGxpdFBvbHlnb24oYnJpZGdlLCBob2xlKTtcblxuICAgIC8vIGZpbHRlciBjb2xsaW5lYXIgcG9pbnRzIGFyb3VuZCB0aGUgY3V0c1xuICAgIHZhciBmaWx0ZXJlZEJyaWRnZSA9IGZpbHRlclBvaW50cyhicmlkZ2UsIGJyaWRnZS5uZXh0KTtcbiAgICBmaWx0ZXJQb2ludHMoYnJpZGdlUmV2ZXJzZSwgYnJpZGdlUmV2ZXJzZS5uZXh0KTtcblxuICAgIC8vIENoZWNrIGlmIGlucHV0IG5vZGUgd2FzIHJlbW92ZWQgYnkgdGhlIGZpbHRlcmluZ1xuICAgIHJldHVybiBvdXRlck5vZGUgPT09IGJyaWRnZSA/IGZpbHRlcmVkQnJpZGdlIDogb3V0ZXJOb2RlO1xufVxuXG4vLyBEYXZpZCBFYmVybHkncyBhbGdvcml0aG0gZm9yIGZpbmRpbmcgYSBicmlkZ2UgYmV0d2VlbiBob2xlIGFuZCBvdXRlciBwb2x5Z29uXG5mdW5jdGlvbiBmaW5kSG9sZUJyaWRnZShob2xlLCBvdXRlck5vZGUpIHtcbiAgICB2YXIgcCA9IG91dGVyTm9kZSxcbiAgICAgICAgaHggPSBob2xlLngsXG4gICAgICAgIGh5ID0gaG9sZS55LFxuICAgICAgICBxeCA9IC1JbmZpbml0eSxcbiAgICAgICAgbTtcblxuICAgIC8vIGZpbmQgYSBzZWdtZW50IGludGVyc2VjdGVkIGJ5IGEgcmF5IGZyb20gdGhlIGhvbGUncyBsZWZ0bW9zdCBwb2ludCB0byB0aGUgbGVmdDtcbiAgICAvLyBzZWdtZW50J3MgZW5kcG9pbnQgd2l0aCBsZXNzZXIgeCB3aWxsIGJlIHBvdGVudGlhbCBjb25uZWN0aW9uIHBvaW50XG4gICAgZG8ge1xuICAgICAgICBpZiAoaHkgPD0gcC55ICYmIGh5ID49IHAubmV4dC55ICYmIHAubmV4dC55ICE9PSBwLnkpIHtcbiAgICAgICAgICAgIHZhciB4ID0gcC54ICsgKGh5IC0gcC55KSAqIChwLm5leHQueCAtIHAueCkgLyAocC5uZXh0LnkgLSBwLnkpO1xuICAgICAgICAgICAgaWYgKHggPD0gaHggJiYgeCA+IHF4KSB7XG4gICAgICAgICAgICAgICAgcXggPSB4O1xuICAgICAgICAgICAgICAgIGlmICh4ID09PSBoeCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoaHkgPT09IHAueSkgcmV0dXJuIHA7XG4gICAgICAgICAgICAgICAgICAgIGlmIChoeSA9PT0gcC5uZXh0LnkpIHJldHVybiBwLm5leHQ7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIG0gPSBwLnggPCBwLm5leHQueCA/IHAgOiBwLm5leHQ7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcCA9IHAubmV4dDtcbiAgICB9IHdoaWxlIChwICE9PSBvdXRlck5vZGUpO1xuXG4gICAgaWYgKCFtKSByZXR1cm4gbnVsbDtcblxuICAgIGlmIChoeCA9PT0gcXgpIHJldHVybiBtOyAvLyBob2xlIHRvdWNoZXMgb3V0ZXIgc2VnbWVudDsgcGljayBsZWZ0bW9zdCBlbmRwb2ludFxuXG4gICAgLy8gbG9vayBmb3IgcG9pbnRzIGluc2lkZSB0aGUgdHJpYW5nbGUgb2YgaG9sZSBwb2ludCwgc2VnbWVudCBpbnRlcnNlY3Rpb24gYW5kIGVuZHBvaW50O1xuICAgIC8vIGlmIHRoZXJlIGFyZSBubyBwb2ludHMgZm91bmQsIHdlIGhhdmUgYSB2YWxpZCBjb25uZWN0aW9uO1xuICAgIC8vIG90aGVyd2lzZSBjaG9vc2UgdGhlIHBvaW50IG9mIHRoZSBtaW5pbXVtIGFuZ2xlIHdpdGggdGhlIHJheSBhcyBjb25uZWN0aW9uIHBvaW50XG5cbiAgICB2YXIgc3RvcCA9IG0sXG4gICAgICAgIG14ID0gbS54LFxuICAgICAgICBteSA9IG0ueSxcbiAgICAgICAgdGFuTWluID0gSW5maW5pdHksXG4gICAgICAgIHRhbjtcblxuICAgIHAgPSBtO1xuXG4gICAgZG8ge1xuICAgICAgICBpZiAoaHggPj0gcC54ICYmIHAueCA+PSBteCAmJiBoeCAhPT0gcC54ICYmXG4gICAgICAgICAgICAgICAgcG9pbnRJblRyaWFuZ2xlKGh5IDwgbXkgPyBoeCA6IHF4LCBoeSwgbXgsIG15LCBoeSA8IG15ID8gcXggOiBoeCwgaHksIHAueCwgcC55KSkge1xuXG4gICAgICAgICAgICB0YW4gPSBNYXRoLmFicyhoeSAtIHAueSkgLyAoaHggLSBwLngpOyAvLyB0YW5nZW50aWFsXG5cbiAgICAgICAgICAgIGlmIChsb2NhbGx5SW5zaWRlKHAsIGhvbGUpICYmXG4gICAgICAgICAgICAgICAgKHRhbiA8IHRhbk1pbiB8fCAodGFuID09PSB0YW5NaW4gJiYgKHAueCA+IG0ueCB8fCAocC54ID09PSBtLnggJiYgc2VjdG9yQ29udGFpbnNTZWN0b3IobSwgcCkpKSkpKSB7XG4gICAgICAgICAgICAgICAgbSA9IHA7XG4gICAgICAgICAgICAgICAgdGFuTWluID0gdGFuO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcCA9IHAubmV4dDtcbiAgICB9IHdoaWxlIChwICE9PSBzdG9wKTtcblxuICAgIHJldHVybiBtO1xufVxuXG4vLyB3aGV0aGVyIHNlY3RvciBpbiB2ZXJ0ZXggbSBjb250YWlucyBzZWN0b3IgaW4gdmVydGV4IHAgaW4gdGhlIHNhbWUgY29vcmRpbmF0ZXNcbmZ1bmN0aW9uIHNlY3RvckNvbnRhaW5zU2VjdG9yKG0sIHApIHtcbiAgICByZXR1cm4gYXJlYShtLnByZXYsIG0sIHAucHJldikgPCAwICYmIGFyZWEocC5uZXh0LCBtLCBtLm5leHQpIDwgMDtcbn1cblxuLy8gaW50ZXJsaW5rIHBvbHlnb24gbm9kZXMgaW4gei1vcmRlclxuZnVuY3Rpb24gaW5kZXhDdXJ2ZShzdGFydCwgbWluWCwgbWluWSwgaW52U2l6ZSkge1xuICAgIHZhciBwID0gc3RhcnQ7XG4gICAgZG8ge1xuICAgICAgICBpZiAocC56ID09PSBudWxsKSBwLnogPSB6T3JkZXIocC54LCBwLnksIG1pblgsIG1pblksIGludlNpemUpO1xuICAgICAgICBwLnByZXZaID0gcC5wcmV2O1xuICAgICAgICBwLm5leHRaID0gcC5uZXh0O1xuICAgICAgICBwID0gcC5uZXh0O1xuICAgIH0gd2hpbGUgKHAgIT09IHN0YXJ0KTtcblxuICAgIHAucHJldloubmV4dFogPSBudWxsO1xuICAgIHAucHJldlogPSBudWxsO1xuXG4gICAgc29ydExpbmtlZChwKTtcbn1cblxuLy8gU2ltb24gVGF0aGFtJ3MgbGlua2VkIGxpc3QgbWVyZ2Ugc29ydCBhbGdvcml0aG1cbi8vIGh0dHA6Ly93d3cuY2hpYXJrLmdyZWVuZW5kLm9yZy51ay9+c2d0YXRoYW0vYWxnb3JpdGhtcy9saXN0c29ydC5odG1sXG5mdW5jdGlvbiBzb3J0TGlua2VkKGxpc3QpIHtcbiAgICB2YXIgaSwgcCwgcSwgZSwgdGFpbCwgbnVtTWVyZ2VzLCBwU2l6ZSwgcVNpemUsXG4gICAgICAgIGluU2l6ZSA9IDE7XG5cbiAgICBkbyB7XG4gICAgICAgIHAgPSBsaXN0O1xuICAgICAgICBsaXN0ID0gbnVsbDtcbiAgICAgICAgdGFpbCA9IG51bGw7XG4gICAgICAgIG51bU1lcmdlcyA9IDA7XG5cbiAgICAgICAgd2hpbGUgKHApIHtcbiAgICAgICAgICAgIG51bU1lcmdlcysrO1xuICAgICAgICAgICAgcSA9IHA7XG4gICAgICAgICAgICBwU2l6ZSA9IDA7XG4gICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgaW5TaXplOyBpKyspIHtcbiAgICAgICAgICAgICAgICBwU2l6ZSsrO1xuICAgICAgICAgICAgICAgIHEgPSBxLm5leHRaO1xuICAgICAgICAgICAgICAgIGlmICghcSkgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBxU2l6ZSA9IGluU2l6ZTtcblxuICAgICAgICAgICAgd2hpbGUgKHBTaXplID4gMCB8fCAocVNpemUgPiAwICYmIHEpKSB7XG5cbiAgICAgICAgICAgICAgICBpZiAocFNpemUgIT09IDAgJiYgKHFTaXplID09PSAwIHx8ICFxIHx8IHAueiA8PSBxLnopKSB7XG4gICAgICAgICAgICAgICAgICAgIGUgPSBwO1xuICAgICAgICAgICAgICAgICAgICBwID0gcC5uZXh0WjtcbiAgICAgICAgICAgICAgICAgICAgcFNpemUtLTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBlID0gcTtcbiAgICAgICAgICAgICAgICAgICAgcSA9IHEubmV4dFo7XG4gICAgICAgICAgICAgICAgICAgIHFTaXplLS07XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKHRhaWwpIHRhaWwubmV4dFogPSBlO1xuICAgICAgICAgICAgICAgIGVsc2UgbGlzdCA9IGU7XG5cbiAgICAgICAgICAgICAgICBlLnByZXZaID0gdGFpbDtcbiAgICAgICAgICAgICAgICB0YWlsID0gZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcCA9IHE7XG4gICAgICAgIH1cblxuICAgICAgICB0YWlsLm5leHRaID0gbnVsbDtcbiAgICAgICAgaW5TaXplICo9IDI7XG5cbiAgICB9IHdoaWxlIChudW1NZXJnZXMgPiAxKTtcblxuICAgIHJldHVybiBsaXN0O1xufVxuXG4vLyB6LW9yZGVyIG9mIGEgcG9pbnQgZ2l2ZW4gY29vcmRzIGFuZCBpbnZlcnNlIG9mIHRoZSBsb25nZXIgc2lkZSBvZiBkYXRhIGJib3hcbmZ1bmN0aW9uIHpPcmRlcih4LCB5LCBtaW5YLCBtaW5ZLCBpbnZTaXplKSB7XG4gICAgLy8gY29vcmRzIGFyZSB0cmFuc2Zvcm1lZCBpbnRvIG5vbi1uZWdhdGl2ZSAxNS1iaXQgaW50ZWdlciByYW5nZVxuICAgIHggPSAzMjc2NyAqICh4IC0gbWluWCkgKiBpbnZTaXplO1xuICAgIHkgPSAzMjc2NyAqICh5IC0gbWluWSkgKiBpbnZTaXplO1xuXG4gICAgeCA9ICh4IHwgKHggPDwgOCkpICYgMHgwMEZGMDBGRjtcbiAgICB4ID0gKHggfCAoeCA8PCA0KSkgJiAweDBGMEYwRjBGO1xuICAgIHggPSAoeCB8ICh4IDw8IDIpKSAmIDB4MzMzMzMzMzM7XG4gICAgeCA9ICh4IHwgKHggPDwgMSkpICYgMHg1NTU1NTU1NTtcblxuICAgIHkgPSAoeSB8ICh5IDw8IDgpKSAmIDB4MDBGRjAwRkY7XG4gICAgeSA9ICh5IHwgKHkgPDwgNCkpICYgMHgwRjBGMEYwRjtcbiAgICB5ID0gKHkgfCAoeSA8PCAyKSkgJiAweDMzMzMzMzMzO1xuICAgIHkgPSAoeSB8ICh5IDw8IDEpKSAmIDB4NTU1NTU1NTU7XG5cbiAgICByZXR1cm4geCB8ICh5IDw8IDEpO1xufVxuXG4vLyBmaW5kIHRoZSBsZWZ0bW9zdCBub2RlIG9mIGEgcG9seWdvbiByaW5nXG5mdW5jdGlvbiBnZXRMZWZ0bW9zdChzdGFydCkge1xuICAgIHZhciBwID0gc3RhcnQsXG4gICAgICAgIGxlZnRtb3N0ID0gc3RhcnQ7XG4gICAgZG8ge1xuICAgICAgICBpZiAocC54IDwgbGVmdG1vc3QueCB8fCAocC54ID09PSBsZWZ0bW9zdC54ICYmIHAueSA8IGxlZnRtb3N0LnkpKSBsZWZ0bW9zdCA9IHA7XG4gICAgICAgIHAgPSBwLm5leHQ7XG4gICAgfSB3aGlsZSAocCAhPT0gc3RhcnQpO1xuXG4gICAgcmV0dXJuIGxlZnRtb3N0O1xufVxuXG4vLyBjaGVjayBpZiBhIHBvaW50IGxpZXMgd2l0aGluIGEgY29udmV4IHRyaWFuZ2xlXG5mdW5jdGlvbiBwb2ludEluVHJpYW5nbGUoYXgsIGF5LCBieCwgYnksIGN4LCBjeSwgcHgsIHB5KSB7XG4gICAgcmV0dXJuIChjeCAtIHB4KSAqIChheSAtIHB5KSAtIChheCAtIHB4KSAqIChjeSAtIHB5KSA+PSAwICYmXG4gICAgICAgICAgIChheCAtIHB4KSAqIChieSAtIHB5KSAtIChieCAtIHB4KSAqIChheSAtIHB5KSA+PSAwICYmXG4gICAgICAgICAgIChieCAtIHB4KSAqIChjeSAtIHB5KSAtIChjeCAtIHB4KSAqIChieSAtIHB5KSA+PSAwO1xufVxuXG4vLyBjaGVjayBpZiBhIGRpYWdvbmFsIGJldHdlZW4gdHdvIHBvbHlnb24gbm9kZXMgaXMgdmFsaWQgKGxpZXMgaW4gcG9seWdvbiBpbnRlcmlvcilcbmZ1bmN0aW9uIGlzVmFsaWREaWFnb25hbChhLCBiKSB7XG4gICAgcmV0dXJuIGEubmV4dC5pICE9PSBiLmkgJiYgYS5wcmV2LmkgIT09IGIuaSAmJiAhaW50ZXJzZWN0c1BvbHlnb24oYSwgYikgJiYgLy8gZG9uZXMndCBpbnRlcnNlY3Qgb3RoZXIgZWRnZXNcbiAgICAgICAgICAgKGxvY2FsbHlJbnNpZGUoYSwgYikgJiYgbG9jYWxseUluc2lkZShiLCBhKSAmJiBtaWRkbGVJbnNpZGUoYSwgYikgJiYgLy8gbG9jYWxseSB2aXNpYmxlXG4gICAgICAgICAgICAoYXJlYShhLnByZXYsIGEsIGIucHJldikgfHwgYXJlYShhLCBiLnByZXYsIGIpKSB8fCAvLyBkb2VzIG5vdCBjcmVhdGUgb3Bwb3NpdGUtZmFjaW5nIHNlY3RvcnNcbiAgICAgICAgICAgIGVxdWFscyhhLCBiKSAmJiBhcmVhKGEucHJldiwgYSwgYS5uZXh0KSA+IDAgJiYgYXJlYShiLnByZXYsIGIsIGIubmV4dCkgPiAwKTsgLy8gc3BlY2lhbCB6ZXJvLWxlbmd0aCBjYXNlXG59XG5cbi8vIHNpZ25lZCBhcmVhIG9mIGEgdHJpYW5nbGVcbmZ1bmN0aW9uIGFyZWEocCwgcSwgcikge1xuICAgIHJldHVybiAocS55IC0gcC55KSAqIChyLnggLSBxLngpIC0gKHEueCAtIHAueCkgKiAoci55IC0gcS55KTtcbn1cblxuLy8gY2hlY2sgaWYgdHdvIHBvaW50cyBhcmUgZXF1YWxcbmZ1bmN0aW9uIGVxdWFscyhwMSwgcDIpIHtcbiAgICByZXR1cm4gcDEueCA9PT0gcDIueCAmJiBwMS55ID09PSBwMi55O1xufVxuXG4vLyBjaGVjayBpZiB0d28gc2VnbWVudHMgaW50ZXJzZWN0XG5mdW5jdGlvbiBpbnRlcnNlY3RzKHAxLCBxMSwgcDIsIHEyKSB7XG4gICAgdmFyIG8xID0gc2lnbihhcmVhKHAxLCBxMSwgcDIpKTtcbiAgICB2YXIgbzIgPSBzaWduKGFyZWEocDEsIHExLCBxMikpO1xuICAgIHZhciBvMyA9IHNpZ24oYXJlYShwMiwgcTIsIHAxKSk7XG4gICAgdmFyIG80ID0gc2lnbihhcmVhKHAyLCBxMiwgcTEpKTtcblxuICAgIGlmIChvMSAhPT0gbzIgJiYgbzMgIT09IG80KSByZXR1cm4gdHJ1ZTsgLy8gZ2VuZXJhbCBjYXNlXG5cbiAgICBpZiAobzEgPT09IDAgJiYgb25TZWdtZW50KHAxLCBwMiwgcTEpKSByZXR1cm4gdHJ1ZTsgLy8gcDEsIHExIGFuZCBwMiBhcmUgY29sbGluZWFyIGFuZCBwMiBsaWVzIG9uIHAxcTFcbiAgICBpZiAobzIgPT09IDAgJiYgb25TZWdtZW50KHAxLCBxMiwgcTEpKSByZXR1cm4gdHJ1ZTsgLy8gcDEsIHExIGFuZCBxMiBhcmUgY29sbGluZWFyIGFuZCBxMiBsaWVzIG9uIHAxcTFcbiAgICBpZiAobzMgPT09IDAgJiYgb25TZWdtZW50KHAyLCBwMSwgcTIpKSByZXR1cm4gdHJ1ZTsgLy8gcDIsIHEyIGFuZCBwMSBhcmUgY29sbGluZWFyIGFuZCBwMSBsaWVzIG9uIHAycTJcbiAgICBpZiAobzQgPT09IDAgJiYgb25TZWdtZW50KHAyLCBxMSwgcTIpKSByZXR1cm4gdHJ1ZTsgLy8gcDIsIHEyIGFuZCBxMSBhcmUgY29sbGluZWFyIGFuZCBxMSBsaWVzIG9uIHAycTJcblxuICAgIHJldHVybiBmYWxzZTtcbn1cblxuLy8gZm9yIGNvbGxpbmVhciBwb2ludHMgcCwgcSwgciwgY2hlY2sgaWYgcG9pbnQgcSBsaWVzIG9uIHNlZ21lbnQgcHJcbmZ1bmN0aW9uIG9uU2VnbWVudChwLCBxLCByKSB7XG4gICAgcmV0dXJuIHEueCA8PSBNYXRoLm1heChwLngsIHIueCkgJiYgcS54ID49IE1hdGgubWluKHAueCwgci54KSAmJiBxLnkgPD0gTWF0aC5tYXgocC55LCByLnkpICYmIHEueSA+PSBNYXRoLm1pbihwLnksIHIueSk7XG59XG5cbmZ1bmN0aW9uIHNpZ24obnVtKSB7XG4gICAgcmV0dXJuIG51bSA+IDAgPyAxIDogbnVtIDwgMCA/IC0xIDogMDtcbn1cblxuLy8gY2hlY2sgaWYgYSBwb2x5Z29uIGRpYWdvbmFsIGludGVyc2VjdHMgYW55IHBvbHlnb24gc2VnbWVudHNcbmZ1bmN0aW9uIGludGVyc2VjdHNQb2x5Z29uKGEsIGIpIHtcbiAgICB2YXIgcCA9IGE7XG4gICAgZG8ge1xuICAgICAgICBpZiAocC5pICE9PSBhLmkgJiYgcC5uZXh0LmkgIT09IGEuaSAmJiBwLmkgIT09IGIuaSAmJiBwLm5leHQuaSAhPT0gYi5pICYmXG4gICAgICAgICAgICAgICAgaW50ZXJzZWN0cyhwLCBwLm5leHQsIGEsIGIpKSByZXR1cm4gdHJ1ZTtcbiAgICAgICAgcCA9IHAubmV4dDtcbiAgICB9IHdoaWxlIChwICE9PSBhKTtcblxuICAgIHJldHVybiBmYWxzZTtcbn1cblxuLy8gY2hlY2sgaWYgYSBwb2x5Z29uIGRpYWdvbmFsIGlzIGxvY2FsbHkgaW5zaWRlIHRoZSBwb2x5Z29uXG5mdW5jdGlvbiBsb2NhbGx5SW5zaWRlKGEsIGIpIHtcbiAgICByZXR1cm4gYXJlYShhLnByZXYsIGEsIGEubmV4dCkgPCAwID9cbiAgICAgICAgYXJlYShhLCBiLCBhLm5leHQpID49IDAgJiYgYXJlYShhLCBhLnByZXYsIGIpID49IDAgOlxuICAgICAgICBhcmVhKGEsIGIsIGEucHJldikgPCAwIHx8IGFyZWEoYSwgYS5uZXh0LCBiKSA8IDA7XG59XG5cbi8vIGNoZWNrIGlmIHRoZSBtaWRkbGUgcG9pbnQgb2YgYSBwb2x5Z29uIGRpYWdvbmFsIGlzIGluc2lkZSB0aGUgcG9seWdvblxuZnVuY3Rpb24gbWlkZGxlSW5zaWRlKGEsIGIpIHtcbiAgICB2YXIgcCA9IGEsXG4gICAgICAgIGluc2lkZSA9IGZhbHNlLFxuICAgICAgICBweCA9IChhLnggKyBiLngpIC8gMixcbiAgICAgICAgcHkgPSAoYS55ICsgYi55KSAvIDI7XG4gICAgZG8ge1xuICAgICAgICBpZiAoKChwLnkgPiBweSkgIT09IChwLm5leHQueSA+IHB5KSkgJiYgcC5uZXh0LnkgIT09IHAueSAmJlxuICAgICAgICAgICAgICAgIChweCA8IChwLm5leHQueCAtIHAueCkgKiAocHkgLSBwLnkpIC8gKHAubmV4dC55IC0gcC55KSArIHAueCkpXG4gICAgICAgICAgICBpbnNpZGUgPSAhaW5zaWRlO1xuICAgICAgICBwID0gcC5uZXh0O1xuICAgIH0gd2hpbGUgKHAgIT09IGEpO1xuXG4gICAgcmV0dXJuIGluc2lkZTtcbn1cblxuLy8gbGluayB0d28gcG9seWdvbiB2ZXJ0aWNlcyB3aXRoIGEgYnJpZGdlOyBpZiB0aGUgdmVydGljZXMgYmVsb25nIHRvIHRoZSBzYW1lIHJpbmcsIGl0IHNwbGl0cyBwb2x5Z29uIGludG8gdHdvO1xuLy8gaWYgb25lIGJlbG9uZ3MgdG8gdGhlIG91dGVyIHJpbmcgYW5kIGFub3RoZXIgdG8gYSBob2xlLCBpdCBtZXJnZXMgaXQgaW50byBhIHNpbmdsZSByaW5nXG5mdW5jdGlvbiBzcGxpdFBvbHlnb24oYSwgYikge1xuICAgIHZhciBhMiA9IG5ldyBOb2RlKGEuaSwgYS54LCBhLnkpLFxuICAgICAgICBiMiA9IG5ldyBOb2RlKGIuaSwgYi54LCBiLnkpLFxuICAgICAgICBhbiA9IGEubmV4dCxcbiAgICAgICAgYnAgPSBiLnByZXY7XG5cbiAgICBhLm5leHQgPSBiO1xuICAgIGIucHJldiA9IGE7XG5cbiAgICBhMi5uZXh0ID0gYW47XG4gICAgYW4ucHJldiA9IGEyO1xuXG4gICAgYjIubmV4dCA9IGEyO1xuICAgIGEyLnByZXYgPSBiMjtcblxuICAgIGJwLm5leHQgPSBiMjtcbiAgICBiMi5wcmV2ID0gYnA7XG5cbiAgICByZXR1cm4gYjI7XG59XG5cbi8vIGNyZWF0ZSBhIG5vZGUgYW5kIG9wdGlvbmFsbHkgbGluayBpdCB3aXRoIHByZXZpb3VzIG9uZSAoaW4gYSBjaXJjdWxhciBkb3VibHkgbGlua2VkIGxpc3QpXG5mdW5jdGlvbiBpbnNlcnROb2RlKGksIHgsIHksIGxhc3QpIHtcbiAgICB2YXIgcCA9IG5ldyBOb2RlKGksIHgsIHkpO1xuXG4gICAgaWYgKCFsYXN0KSB7XG4gICAgICAgIHAucHJldiA9IHA7XG4gICAgICAgIHAubmV4dCA9IHA7XG5cbiAgICB9IGVsc2Uge1xuICAgICAgICBwLm5leHQgPSBsYXN0Lm5leHQ7XG4gICAgICAgIHAucHJldiA9IGxhc3Q7XG4gICAgICAgIGxhc3QubmV4dC5wcmV2ID0gcDtcbiAgICAgICAgbGFzdC5uZXh0ID0gcDtcbiAgICB9XG4gICAgcmV0dXJuIHA7XG59XG5cbmZ1bmN0aW9uIHJlbW92ZU5vZGUocCkge1xuICAgIHAubmV4dC5wcmV2ID0gcC5wcmV2O1xuICAgIHAucHJldi5uZXh0ID0gcC5uZXh0O1xuXG4gICAgaWYgKHAucHJldlopIHAucHJldloubmV4dFogPSBwLm5leHRaO1xuICAgIGlmIChwLm5leHRaKSBwLm5leHRaLnByZXZaID0gcC5wcmV2Wjtcbn1cblxuZnVuY3Rpb24gTm9kZShpLCB4LCB5KSB7XG4gICAgLy8gdmVydGV4IGluZGV4IGluIGNvb3JkaW5hdGVzIGFycmF5XG4gICAgdGhpcy5pID0gaTtcblxuICAgIC8vIHZlcnRleCBjb29yZGluYXRlc1xuICAgIHRoaXMueCA9IHg7XG4gICAgdGhpcy55ID0geTtcblxuICAgIC8vIHByZXZpb3VzIGFuZCBuZXh0IHZlcnRleCBub2RlcyBpbiBhIHBvbHlnb24gcmluZ1xuICAgIHRoaXMucHJldiA9IG51bGw7XG4gICAgdGhpcy5uZXh0ID0gbnVsbDtcblxuICAgIC8vIHotb3JkZXIgY3VydmUgdmFsdWVcbiAgICB0aGlzLnogPSBudWxsO1xuXG4gICAgLy8gcHJldmlvdXMgYW5kIG5leHQgbm9kZXMgaW4gei1vcmRlclxuICAgIHRoaXMucHJldlogPSBudWxsO1xuICAgIHRoaXMubmV4dFogPSBudWxsO1xuXG4gICAgLy8gaW5kaWNhdGVzIHdoZXRoZXIgdGhpcyBpcyBhIHN0ZWluZXIgcG9pbnRcbiAgICB0aGlzLnN0ZWluZXIgPSBmYWxzZTtcbn1cblxuLy8gcmV0dXJuIGEgcGVyY2VudGFnZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHBvbHlnb24gYXJlYSBhbmQgaXRzIHRyaWFuZ3VsYXRpb24gYXJlYTtcbi8vIHVzZWQgdG8gdmVyaWZ5IGNvcnJlY3RuZXNzIG9mIHRyaWFuZ3VsYXRpb25cbmVhcmN1dC5kZXZpYXRpb24gPSBmdW5jdGlvbiAoZGF0YSwgaG9sZUluZGljZXMsIGRpbSwgdHJpYW5nbGVzKSB7XG4gICAgdmFyIGhhc0hvbGVzID0gaG9sZUluZGljZXMgJiYgaG9sZUluZGljZXMubGVuZ3RoO1xuICAgIHZhciBvdXRlckxlbiA9IGhhc0hvbGVzID8gaG9sZUluZGljZXNbMF0gKiBkaW0gOiBkYXRhLmxlbmd0aDtcblxuICAgIHZhciBwb2x5Z29uQXJlYSA9IE1hdGguYWJzKHNpZ25lZEFyZWEoZGF0YSwgMCwgb3V0ZXJMZW4sIGRpbSkpO1xuICAgIGlmIChoYXNIb2xlcykge1xuICAgICAgICBmb3IgKHZhciBpID0gMCwgbGVuID0gaG9sZUluZGljZXMubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcbiAgICAgICAgICAgIHZhciBzdGFydCA9IGhvbGVJbmRpY2VzW2ldICogZGltO1xuICAgICAgICAgICAgdmFyIGVuZCA9IGkgPCBsZW4gLSAxID8gaG9sZUluZGljZXNbaSArIDFdICogZGltIDogZGF0YS5sZW5ndGg7XG4gICAgICAgICAgICBwb2x5Z29uQXJlYSAtPSBNYXRoLmFicyhzaWduZWRBcmVhKGRhdGEsIHN0YXJ0LCBlbmQsIGRpbSkpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgdmFyIHRyaWFuZ2xlc0FyZWEgPSAwO1xuICAgIGZvciAoaSA9IDA7IGkgPCB0cmlhbmdsZXMubGVuZ3RoOyBpICs9IDMpIHtcbiAgICAgICAgdmFyIGEgPSB0cmlhbmdsZXNbaV0gKiBkaW07XG4gICAgICAgIHZhciBiID0gdHJpYW5nbGVzW2kgKyAxXSAqIGRpbTtcbiAgICAgICAgdmFyIGMgPSB0cmlhbmdsZXNbaSArIDJdICogZGltO1xuICAgICAgICB0cmlhbmdsZXNBcmVhICs9IE1hdGguYWJzKFxuICAgICAgICAgICAgKGRhdGFbYV0gLSBkYXRhW2NdKSAqIChkYXRhW2IgKyAxXSAtIGRhdGFbYSArIDFdKSAtXG4gICAgICAgICAgICAoZGF0YVthXSAtIGRhdGFbYl0pICogKGRhdGFbYyArIDFdIC0gZGF0YVthICsgMV0pKTtcbiAgICB9XG5cbiAgICByZXR1cm4gcG9seWdvbkFyZWEgPT09IDAgJiYgdHJpYW5nbGVzQXJlYSA9PT0gMCA/IDAgOlxuICAgICAgICBNYXRoLmFicygodHJpYW5nbGVzQXJlYSAtIHBvbHlnb25BcmVhKSAvIHBvbHlnb25BcmVhKTtcbn07XG5cbmZ1bmN0aW9uIHNpZ25lZEFyZWEoZGF0YSwgc3RhcnQsIGVuZCwgZGltKSB7XG4gICAgdmFyIHN1bSA9IDA7XG4gICAgZm9yICh2YXIgaSA9IHN0YXJ0LCBqID0gZW5kIC0gZGltOyBpIDwgZW5kOyBpICs9IGRpbSkge1xuICAgICAgICBzdW0gKz0gKGRhdGFbal0gLSBkYXRhW2ldKSAqIChkYXRhW2kgKyAxXSArIGRhdGFbaiArIDFdKTtcbiAgICAgICAgaiA9IGk7XG4gICAgfVxuICAgIHJldHVybiBzdW07XG59XG5cbi8vIHR1cm4gYSBwb2x5Z29uIGluIGEgbXVsdGktZGltZW5zaW9uYWwgYXJyYXkgZm9ybSAoZS5nLiBhcyBpbiBHZW9KU09OKSBpbnRvIGEgZm9ybSBFYXJjdXQgYWNjZXB0c1xuZWFyY3V0LmZsYXR0ZW4gPSBmdW5jdGlvbiAoZGF0YSkge1xuICAgIHZhciBkaW0gPSBkYXRhWzBdWzBdLmxlbmd0aCxcbiAgICAgICAgcmVzdWx0ID0ge3ZlcnRpY2VzOiBbXSwgaG9sZXM6IFtdLCBkaW1lbnNpb25zOiBkaW19LFxuICAgICAgICBob2xlSW5kZXggPSAwO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBkYXRhLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgZGF0YVtpXS5sZW5ndGg7IGorKykge1xuICAgICAgICAgICAgZm9yICh2YXIgZCA9IDA7IGQgPCBkaW07IGQrKykgcmVzdWx0LnZlcnRpY2VzLnB1c2goZGF0YVtpXVtqXVtkXSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGkgPiAwKSB7XG4gICAgICAgICAgICBob2xlSW5kZXggKz0gZGF0YVtpIC0gMV0ubGVuZ3RoO1xuICAgICAgICAgICAgcmVzdWx0LmhvbGVzLnB1c2goaG9sZUluZGV4KTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xufTtcbiJdfQ==
676
+ }));