@esotericsoftware/spine-core
Version:
The official Spine Runtimes for the web.
242 lines • 40.1 kB
JavaScript
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated April 5, 2025. Replaces all prior versions.
*
* Copyright (c) 2013-2025, Esoteric Software LLC
*
* Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license
*
* Otherwise, it is permitted to integrate the Spine Runtimes into software
* or otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice.
*
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/
import { Pool } from "./Utils.js";
export class Triangulator {
convexPolygons = new Array();
convexPolygonsIndices = new Array();
indicesArray = new Array();
isConcaveArray = new Array();
triangles = new Array();
polygonPool = new Pool(() => {
return new Array();
});
polygonIndicesPool = new Pool(() => {
return new Array();
});
triangulate(verticesArray) {
let vertices = verticesArray;
let vertexCount = verticesArray.length >> 1;
let indices = this.indicesArray;
indices.length = 0;
for (let i = 0; i < vertexCount; i++)
indices[i] = i;
let isConcave = this.isConcaveArray;
isConcave.length = 0;
for (let i = 0, n = vertexCount; i < n; ++i)
isConcave[i] = Triangulator.isConcave(i, vertexCount, vertices, indices);
let triangles = this.triangles;
triangles.length = 0;
while (vertexCount > 3) {
// Find ear tip.
let previous = vertexCount - 1, i = 0, next = 1;
while (true) {
outer: if (!isConcave[i]) {
let p1 = indices[previous] << 1, p2 = indices[i] << 1, p3 = indices[next] << 1;
let p1x = vertices[p1], p1y = vertices[p1 + 1];
let p2x = vertices[p2], p2y = vertices[p2 + 1];
let p3x = vertices[p3], p3y = vertices[p3 + 1];
for (let ii = (next + 1) % vertexCount; ii != previous; ii = (ii + 1) % vertexCount) {
if (!isConcave[ii])
continue;
let v = indices[ii] << 1;
let vx = vertices[v], vy = vertices[v + 1];
if (Triangulator.positiveArea(p3x, p3y, p1x, p1y, vx, vy)) {
if (Triangulator.positiveArea(p1x, p1y, p2x, p2y, vx, vy)) {
if (Triangulator.positiveArea(p2x, p2y, p3x, p3y, vx, vy))
break outer;
}
}
}
break;
}
if (next == 0) {
do {
if (!isConcave[i])
break;
i--;
} while (i > 0);
break;
}
previous = i;
i = next;
next = (next + 1) % vertexCount;
}
// Cut ear tip.
triangles.push(indices[(vertexCount + i - 1) % vertexCount]);
triangles.push(indices[i]);
triangles.push(indices[(i + 1) % vertexCount]);
indices.splice(i, 1);
isConcave.splice(i, 1);
vertexCount--;
let previousIndex = (vertexCount + i - 1) % vertexCount;
let nextIndex = i == vertexCount ? 0 : i;
isConcave[previousIndex] = Triangulator.isConcave(previousIndex, vertexCount, vertices, indices);
isConcave[nextIndex] = Triangulator.isConcave(nextIndex, vertexCount, vertices, indices);
}
if (vertexCount == 3) {
triangles.push(indices[2]);
triangles.push(indices[0]);
triangles.push(indices[1]);
}
return triangles;
}
decompose(verticesArray, triangles) {
let vertices = verticesArray;
let convexPolygons = this.convexPolygons;
this.polygonPool.freeAll(convexPolygons);
convexPolygons.length = 0;
let convexPolygonsIndices = this.convexPolygonsIndices;
this.polygonIndicesPool.freeAll(convexPolygonsIndices);
convexPolygonsIndices.length = 0;
let polygonIndices = this.polygonIndicesPool.obtain();
polygonIndices.length = 0;
let polygon = this.polygonPool.obtain();
polygon.length = 0;
// Merge subsequent triangles if they form a triangle fan.
let fanBaseIndex = -1, lastWinding = 0;
for (let i = 0, n = triangles.length; i < n; i += 3) {
let t1 = triangles[i] << 1, t2 = triangles[i + 1] << 1, t3 = triangles[i + 2] << 1;
let x1 = vertices[t1], y1 = vertices[t1 + 1];
let x2 = vertices[t2], y2 = vertices[t2 + 1];
let x3 = vertices[t3], y3 = vertices[t3 + 1];
// If the base of the last triangle is the same as this triangle, check if they form a convex polygon (triangle fan).
let merged = false;
if (fanBaseIndex == t1) {
let o = polygon.length - 4;
let winding1 = Triangulator.winding(polygon[o], polygon[o + 1], polygon[o + 2], polygon[o + 3], x3, y3);
let winding2 = Triangulator.winding(x3, y3, polygon[0], polygon[1], polygon[2], polygon[3]);
if (winding1 == lastWinding && winding2 == lastWinding) {
polygon.push(x3);
polygon.push(y3);
polygonIndices.push(t3);
merged = true;
}
}
// Otherwise make this triangle the new base.
if (!merged) {
if (polygon.length > 0) {
convexPolygons.push(polygon);
convexPolygonsIndices.push(polygonIndices);
}
else {
this.polygonPool.free(polygon);
this.polygonIndicesPool.free(polygonIndices);
}
polygon = this.polygonPool.obtain();
polygon.length = 0;
polygon.push(x1);
polygon.push(y1);
polygon.push(x2);
polygon.push(y2);
polygon.push(x3);
polygon.push(y3);
polygonIndices = this.polygonIndicesPool.obtain();
polygonIndices.length = 0;
polygonIndices.push(t1);
polygonIndices.push(t2);
polygonIndices.push(t3);
lastWinding = Triangulator.winding(x1, y1, x2, y2, x3, y3);
fanBaseIndex = t1;
}
}
if (polygon.length > 0) {
convexPolygons.push(polygon);
convexPolygonsIndices.push(polygonIndices);
}
// Go through the list of polygons and try to merge the remaining triangles with the found triangle fans.
for (let i = 0, n = convexPolygons.length; i < n; i++) {
polygonIndices = convexPolygonsIndices[i];
if (polygonIndices.length == 0)
continue;
let firstIndex = polygonIndices[0];
let lastIndex = polygonIndices[polygonIndices.length - 1];
polygon = convexPolygons[i];
let o = polygon.length - 4;
let prevPrevX = polygon[o], prevPrevY = polygon[o + 1];
let prevX = polygon[o + 2], prevY = polygon[o + 3];
let firstX = polygon[0], firstY = polygon[1];
let secondX = polygon[2], secondY = polygon[3];
let winding = Triangulator.winding(prevPrevX, prevPrevY, prevX, prevY, firstX, firstY);
for (let ii = 0; ii < n; ii++) {
if (ii == i)
continue;
let otherIndices = convexPolygonsIndices[ii];
if (otherIndices.length != 3)
continue;
let otherFirstIndex = otherIndices[0];
let otherSecondIndex = otherIndices[1];
let otherLastIndex = otherIndices[2];
let otherPoly = convexPolygons[ii];
let x3 = otherPoly[otherPoly.length - 2], y3 = otherPoly[otherPoly.length - 1];
if (otherFirstIndex != firstIndex || otherSecondIndex != lastIndex)
continue;
let winding1 = Triangulator.winding(prevPrevX, prevPrevY, prevX, prevY, x3, y3);
let winding2 = Triangulator.winding(x3, y3, firstX, firstY, secondX, secondY);
if (winding1 == winding && winding2 == winding) {
otherPoly.length = 0;
otherIndices.length = 0;
polygon.push(x3);
polygon.push(y3);
polygonIndices.push(otherLastIndex);
prevPrevX = prevX;
prevPrevY = prevY;
prevX = x3;
prevY = y3;
ii = 0;
}
}
}
// Remove empty polygons that resulted from the merge step above.
for (let i = convexPolygons.length - 1; i >= 0; i--) {
polygon = convexPolygons[i];
if (polygon.length == 0) {
convexPolygons.splice(i, 1);
this.polygonPool.free(polygon);
polygonIndices = convexPolygonsIndices[i];
convexPolygonsIndices.splice(i, 1);
this.polygonIndicesPool.free(polygonIndices);
}
}
return convexPolygons;
}
static isConcave(index, vertexCount, vertices, indices) {
let previous = indices[(vertexCount + index - 1) % vertexCount] << 1;
let current = indices[index] << 1;
let next = indices[(index + 1) % vertexCount] << 1;
return !this.positiveArea(vertices[previous], vertices[previous + 1], vertices[current], vertices[current + 1], vertices[next], vertices[next + 1]);
}
static positiveArea(p1x, p1y, p2x, p2y, p3x, p3y) {
return p1x * (p3y - p2y) + p2x * (p1y - p3y) + p3x * (p2y - p1y) >= 0;
}
static winding(p1x, p1y, p2x, p2y, p3x, p3y) {
let px = p2x - p1x, py = p2y - p1y;
return p3x * py - p3y * px + px * p1y - p1x * py >= 0 ? 1 : -1;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVHJpYW5ndWxhdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL1RyaWFuZ3VsYXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OytFQTJCK0U7QUFFL0UsT0FBTyxFQUFtQixJQUFJLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFFbkQsTUFBTSxPQUFPLFlBQVk7SUFDaEIsY0FBYyxHQUFHLElBQUksS0FBSyxFQUFpQixDQUFDO0lBQzVDLHFCQUFxQixHQUFHLElBQUksS0FBSyxFQUFpQixDQUFDO0lBRW5ELFlBQVksR0FBRyxJQUFJLEtBQUssRUFBVSxDQUFDO0lBQ25DLGNBQWMsR0FBRyxJQUFJLEtBQUssRUFBVyxDQUFDO0lBQ3RDLFNBQVMsR0FBRyxJQUFJLEtBQUssRUFBVSxDQUFDO0lBRWhDLFdBQVcsR0FBRyxJQUFJLElBQUksQ0FBZ0IsR0FBRyxFQUFFO1FBQ2xELE9BQU8sSUFBSSxLQUFLLEVBQVUsQ0FBQztJQUM1QixDQUFDLENBQUMsQ0FBQztJQUVLLGtCQUFrQixHQUFHLElBQUksSUFBSSxDQUFnQixHQUFHLEVBQUU7UUFDekQsT0FBTyxJQUFJLEtBQUssRUFBVSxDQUFDO0lBQzVCLENBQUMsQ0FBQyxDQUFDO0lBRUksV0FBVyxDQUFFLGFBQThCO1FBQ2pELElBQUksUUFBUSxHQUFHLGFBQWEsQ0FBQztRQUM3QixJQUFJLFdBQVcsR0FBRyxhQUFhLENBQUMsTUFBTSxJQUFJLENBQUMsQ0FBQztRQUU1QyxJQUFJLE9BQU8sR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDO1FBQ2hDLE9BQU8sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDO1FBQ25CLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxXQUFXLEVBQUUsQ0FBQyxFQUFFO1lBQ25DLE9BQU8sQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7UUFFaEIsSUFBSSxTQUFTLEdBQUcsSUFB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UUFBUSxDQUFDLElBQUksQ0FBQyxFQUM3SCxRQUFRLENBQUMsSUFBSSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDdEIsQ0FBQztJQUVPLE1BQU0sQ0FBQyxZQUFZLENBQUUsR0FBVyxFQUFFLEdBQVcsRUFBRSxHQUFXLEVBQUUsR0FBVyxFQUFFLEdBQVcsRUFBRSxHQUFXO1FBQ3hHLE9BQU8sR0FBRyxHQUFHLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3ZFLENBQUM7SUFFTyxNQUFNLENBQUMsT0FBTyxDQUFFLEdBQVcsRUFBRSxHQUFXLEVBQUUsR0FBVyxFQUFFLEdBQVcsRUFBRSxHQUFXLEVBQUUsR0FBVztRQUNuRyxJQUFJLEVBQUUsR0FBRyxHQUFHLEdBQUcsR0FBRyxFQUFFLEVBQUUsR0FBRyxHQUFHLEdBQUcsR0FBRyxDQUFDO1FBQ25DLE9BQU8sR0FBRyxHQUFHLEVBQUUsR0FBRyxHQUFHLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxHQUFHLEdBQUcsR0FBRyxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDaEUsQ0FBQztDQUNEIiwic291cmNlc0NvbnRlbnQiOlsiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuICogU3BpbmUgUnVudGltZXMgTGljZW5zZSBBZ3JlZW1lbnRcbiAqIExhc3QgdXBkYXRlZCBBcHJpbCA1LCAyMDI1LiBSZXBsYWNlcyBhbGwgcHJpb3IgdmVyc2lvbnMuXG4gKlxuICogQ29weXJpZ2h0IChjKSAyMDEzLTIwMjUsIEVzb3RlcmljIFNvZnR3YXJlIExMQ1xuICpcbiAqIEludGVncmF0aW9uIG9mIHRoZSBTcGluZSBSdW50aW1lcyBpbnRvIHNvZnR3YXJlIG9yIG90aGVyd2lzZSBjcmVhdGluZ1xuICogZGVyaXZhdGl2ZSB3b3JrcyBvZiB0aGUgU3BpbmUgUnVudGltZXMgaXMgcGVybWl0dGVkIHVuZGVyIHRoZSB0ZXJtcyBhbmRcbiAqIGNvbmRpdGlvbnMgb2YgU2VjdGlvbiAyIG9mIHRoZSBTcGluZSBFZGl0b3IgTGljZW5zZSBBZ3JlZW1lbnQ6XG4gKiBodHRwOi8vZXNvdGVyaWNzb2Z0d2FyZS5jb20vc3BpbmUtZWRpdG9yLWxpY2Vuc2VcbiAqXG4gKiBPdGhlcndpc2UsIGl0IGlzIHBlcm1pdHRlZCB0byBpbnRlZ3JhdGUgdGhlIFNwaW5lIFJ1bnRpbWVzIGludG8gc29mdHdhcmVcbiAqIG9yIG90aGVyd2lzZSBjcmVhdGUgZGVyaXZhdGl2ZSB3b3JrcyBvZiB0aGUgU3BpbmUgUnVudGltZXMgKGNvbGxlY3RpdmVseSxcbiAqIFwiUHJvZHVjdHNcIiksIHByb3ZpZGVkIHRoYXQgZWFjaCB1c2VyIG9mIHRoZSBQcm9kdWN0cyBtdXN0IG9idGFpbiB0aGVpciBvd25cbiAqIFNwaW5lIEVkaXRvciBsaWNlbnNlIGFuZCByZWRpc3RyaWJ1dGlvbiBvZiB0aGUgUHJvZHVjdHMgaW4gYW55IGZvcm0gbXVzdFxuICogaW5jbHVkZSB0aGlzIGxpY2Vuc2UgYW5kIGNvcHlyaWdodCBub3RpY2UuXG4gKlxuICogVEhFIFNQSU5FIFJVTlRJTUVTIEFSRSBQUk9WSURFRCBCWSBFU09URVJJQyBTT0ZUV0FSRSBMTEMgXCJBUyBJU1wiIEFORCBBTllcbiAqIEVYUFJFU1MgT1IgSU1QTElFRCBXQVJSQU5USUVTLCBJTkNMVURJTkcsIEJVVCBOT1QgTElNSVRFRCBUTywgVEhFIElNUExJRURcbiAqIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZIEFORCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBUkVcbiAqIERJU0NMQUlNRUQuIElOIE5PIEVWRU5UIFNIQUxMIEVTT1RFUklDIFNPRlRXQVJFIExMQyBCRSBMSUFCTEUgRk9SIEFOWVxuICogRElSRUNULCBJTkRJUkVDVCwgSU5DSURFTlRBTCwgU1BFQ0lBTCwgRVhFTVBMQVJZLCBPUiBDT05TRVFVRU5USUFMIERBTUFHRVNcbiAqIChJTkNMVURJTkcsIEJVVCBOT1QgTElNSVRFRCBUTywgUFJPQ1VSRU1FTlQgT0YgU1VCU1RJVFVURSBHT09EUyBPUiBTRVJWSUNFUyxcbiAqIEJVU0lORVNTIElOVEVSUlVQVElPTiwgT1IgTE9TUyBPRiBVU0UsIERBVEEsIE9SIFBST0ZJVFMpIEhPV0VWRVIgQ0FVU0VEIEFORFxuICogT04gQU5ZIFRIRU9SWSBPRiBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQ09OVFJBQ1QsIFNUUklDVCBMSUFCSUxJVFksIE9SIFRPUlRcbiAqIChJTkNMVURJTkcgTkVHTElHRU5DRSBPUiBPVEhFUldJU0UpIEFSSVNJTkcgSU4gQU5ZIFdBWSBPVVQgT0YgVEhFIFVTRSBPRlxuICogVEhFIFNQSU5FIFJVTlRJTUVTLCBFVkVOIElGIEFEVklTRUQgT0YgVEhFIFBPU1NJQklMSVRZIE9GIFNVQ0ggREFNQUdFLlxuICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyBOdW1iZXJBcnJheUxpa2UsIFBvb2wgfSBmcm9tIFwiLi9VdGlscy5qc1wiO1xuXG5leHBvcnQgY2xhc3MgVHJpYW5ndWxhdG9yIHtcblx0cHJpdmF0ZSBjb252ZXhQb2x5Z29ucyA9IG5ldyBBcnJheTxBcnJheTxudW1iZXI+PigpO1xuXHRwcml2YXRlIGNvbnZleFBvbHlnb25zSW5kaWNlcyA9IG5ldyBBcnJheTxBcnJheTxudW1iZXI+PigpO1xuXG5cdHByaXZhdGUgaW5kaWNlc0FycmF5ID0gbmV3IEFycmF5PG51bWJlcj4oKTtcblx0cHJpdmF0ZSBpc0NvbmNhdmVBcnJheSA9IG5ldyBBcnJheTxib29sZWFuPigpO1xuXHRwcml2YXRlIHRyaWFuZ2xlcyA9IG5ldyBBcnJheTxudW1iZXI+KCk7XG5cblx0cHJpdmF0ZSBwb2x5Z29uUG9vbCA9IG5ldyBQb29sPEFycmF5PG51bWJlcj4+KCgpID0+IHtcblx0XHRyZXR1cm4gbmV3IEFycmF5PG51bWJlcj4oKTtcblx0fSk7XG5cblx0cHJpdmF0ZSBwb2x5Z29uSW5kaWNlc1Bvb2wgPSBuZXcgUG9vbDxBcnJheTxudW1iZXI+PigoKSA9PiB7XG5cdFx0cmV0dXJuIG5ldyBBcnJheTxudW1iZXI+KCk7XG5cdH0pO1xuXG5cdHB1YmxpYyB0cmlhbmd1bGF0ZSAodmVydGljZXNBcnJheTogTnVtYmVyQXJyYXlMaWtlKTogQXJyYXk8bnVtYmVyPiB7XG5cdFx0bGV0IHZlcnRpY2VzID0gdmVydGljZXNBcnJheTtcblx0XHRsZXQgdmVydGV4Q291bnQgPSB2ZXJ0aWNlc0FycmF5Lmxlbmd0aCA+PiAxO1xuXG5cdFx0bGV0IGluZGljZXMgPSB0aGlzLmluZGljZXNBcnJheTtcblx0XHRpbmRpY2VzLmxlbmd0aCA9IDA7XG5cdFx0Zm9yIChsZXQgaSA9IDA7IGkgPCB2ZXJ0ZXhDb3VudDsgaSsrKVxuXHRcdFx0aW5kaWNlc1tpXSA9IGk7XG5cblx0XHRsZXQgaXNDb25jYXZlID0gdGhpcy5pc0NvbmNhdmVBcnJheTtcblx0XHRpc0NvbmNhdmUubGVuZ3RoID0gMDtcblx0XHRmb3IgKGxldCBpID0gMCwgbiA9IHZlcnRleENvdW50OyBpIDwgbjsgKytpKVxuXHRcdFx0aXNDb25jYXZlW2ldID0gVHJpYW5ndWxhdG9yLmlzQ29uY2F2ZShpLCB2ZXJ0ZXhDb3VudCwgdmVydGljZXMsIGluZGljZXMpO1xuXG5cdFx0bGV0IHRyaWFuZ2xlcyA9IHRoaXMudHJpYW5nbGVzO1xuXHRcdHRyaWFuZ2xlcy5sZW5ndGggPSAwO1xuXG5cdFx0d2hpbGUgKHZlcnRleENvdW50ID4gMykge1xuXHRcdFx0Ly8gRmluZCBlYXIgdGlwLlxuXHRcdFx0bGV0IHByZXZpb3VzID0gdmVydGV4Q291bnQgLSAxLCBpID0gMCwgbmV4dCA9IDE7XG5cdFx0XHR3aGlsZSAodHJ1ZSkge1xuXHRcdFx0XHRvdXRlcjpcblx0XHRcdFx0aWYgKCFpc0NvbmNhdmVbaV0pIHtcblx0XHRcdFx0XHRsZXQgcDEgPSBpbmRpY2VzW3ByZXZpb3VzXSA8PCAxLCBwMiA9IGluZGljZXNbaV0gPDwgMSwgcDMgPSBpbmRpY2VzW25leHRdIDw8IDE7XG5cdFx0XHRcdFx0bGV0IHAxeCA9IHZlcnRpY2VzW3AxXSwgcDF5ID0gdmVydGljZXNbcDEgKyAxXTtcblx0XHRcdFx0XHRsZXQgcDJ4ID0gdmVydGljZXNbcDJdLCBwMnkgPSB2ZXJ0aWNlc1twMiArIDFdO1xuXHRcdFx0XHRcdGxldCBwM3ggPSB2ZXJ0aWNlc1twM10sIHAzeSA9IHZlcnRpY2VzW3AzICsgMV07XG5cdFx0XHRcdFx0Zm9yIChsZXQgaWkgPSAobmV4dCArIDEpICUgdmVydGV4Q291bnQ7IGlpICE9IHByZXZpb3VzOyBpaSA9IChpaSArIDEpICUgdmVydGV4Q291bnQpIHtcblx0XHRcdFx0XHRcdGlmICghaXNDb25jYXZlW2lpXSkgY29udGludWU7XG5cdFx0XHRcdFx0XHRsZXQgdiA9IGluZGljZXNbaWldIDw8IDE7XG5cdFx0XHRcdFx0XHRsZXQgdnggPSB2ZXJ0aWNlc1t2XSwgdnkgPSB2ZXJ0aWNlc1t2ICsgMV07XG5cdFx0XHRcdFx0XHRpZiAoVHJpYW5ndWxhdG9yLnBvc2l0aXZlQXJlYShwM3gsIHAzeSwgcDF4LCBwMXksIHZ4LCB2eSkpIHtcblx0XHRcdFx0XHRcdFx0aWYgKFRyaWFuZ3VsYXRvci5wb3NpdGl2ZUFyZWEocDF4LCBwMXksIHAyeCwgcDJ5LCB2eCwgdnkpKSB7XG5cdFx0XHRcdFx0XHRcdFx0aWYgKFRyaWFuZ3VsYXRvci5wb3NpdGl2ZUFyZWEocDJ4LCBwMnksIHAzeCwgcDN5LCB2eCwgdnkpKSBicmVhayBvdXRlcjtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmIChuZXh0ID09IDApIHtcblx0XHRcdFx0XHRkbyB7XG5cdFx0XHRcdFx0XHRpZiAoIWlzQ29uY2F2ZVtpXSkgYnJlYWs7XG5cdFx0XHRcdFx0XHRpLS07XG5cdFx0XHRcdFx0fSB3aGlsZSAoaSA+IDApO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0cHJldmlvdXMgPSBpO1xuXHRcdFx0XHRpID0gbmV4dDtcblx0XHRcdFx0bmV4dCA9IChuZXh0ICsgMSkgJSB2ZXJ0ZXhDb3VudDtcblx0XHRcdH1cblxuXHRcdFx0Ly8gQ3V0IGVhciB0aXAuXG5cdFx0XHR0cmlhbmdsZXMucHVzaChpbmRpY2VzWyh2ZXJ0ZXhDb3VudCArIGkgLSAxKSAlIHZlcnRleENvdW50XSk7XG5cdFx0XHR0cmlhbmdsZXMucHVzaChpbmRpY2VzW2ldKTtcblx0XHRcdHRyaWFuZ2xlcy5wdXNoKGluZGljZXNbKGkgKyAxKSAlIHZlcnRleENvdW50XSk7XG5cdFx0XHRpbmRpY2VzLnNwbGljZShpLCAxKTtcblx0XHRcdGlzQ29uY2F2ZS5zcGxpY2UoaSwgMSk7XG5cdFx0XHR2ZXJ0ZXhDb3VudC0tO1xuXG5cdFx0XHRsZXQgcHJldmlvdXNJbmRleCA9ICh2ZXJ0ZXhDb3VudCArIGkgLSAxKSAlIHZlcnRleENvdW50O1xuXHRcdFx0bGV0IG5leHRJbmRleCA9IGkgPT0gdmVydGV4Q291bnQgPyAwIDogaTtcblx0XHRcdGlzQ29uY2F2ZVtwcmV2aW91c0luZGV4XSA9IFRyaWFuZ3VsYXRvci5pc0NvbmNhdmUocHJldmlvdXNJbmRleCwgdmVydGV4Q291bnQsIHZlcnRpY2VzLCBpbmRpY2VzKTtcblx0XHRcdGlzQ29uY2F2ZVtuZXh0SW5kZXhdID0gVHJpYW5ndWxhdG9yLmlzQ29uY2F2ZShuZXh0SW5kZXgsIHZlcnRleENvdW50LCB2ZXJ0aWNlcywgaW5kaWNlcyk7XG5cdFx0fVxuXG5cdFx0aWYgKHZlcnRleENvdW50ID09IDMpIHtcblx0XHRcdHRyaWFuZ2xlcy5wdXNoKGluZGljZXNbMl0pO1xuXHRcdFx0dHJpYW5nbGVzLnB1c2goaW5kaWNlc1swXSk7XG5cdFx0XHR0cmlhbmdsZXMucHVzaChpbmRpY2VzWzFdKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gdHJpYW5nbGVzO1xuXHR9XG5cblx0ZGVjb21wb3NlICh2ZXJ0aWNlc0FycmF5OiBBcnJheTxudW1iZXI+LCB0cmlhbmdsZXM6IEFycmF5PG51bWJlcj4pOiBBcnJheTxBcnJheTxudW1iZXI+PiB7XG5cdFx0bGV0IHZlcnRpY2VzID0gdmVydGljZXNBcnJheTtcblx0XHRsZXQgY29udmV4UG9seWdvbnMgPSB0aGlzLmNvbnZleFBvbHlnb25zO1xuXHRcdHRoaXMucG9seWdvblBvb2wuZnJlZUFsbChjb252ZXhQb2x5Z29ucyk7XG5cdFx0Y29udmV4UG9seWdvbnMubGVuZ3RoID0gMDtcblxuXHRcdGxldCBjb252ZXhQb2x5Z29uc0luZGljZXMgPSB0aGlzLmNvbnZleFBvbHlnb25zSW5kaWNlcztcblx0XHR0aGlzLnBvbHlnb25JbmRpY2VzUG9vbC5mcmVlQWxsKGNvbnZleFBvbHlnb25zSW5kaWNlcyk7XG5cdFx0Y29udmV4UG9seWdvbnNJbmRpY2VzLmxlbmd0aCA9IDA7XG5cblx0XHRsZXQgcG9seWdvbkluZGljZXMgPSB0aGlzLnBvbHlnb25JbmRpY2VzUG9vbC5vYnRhaW4oKTtcblx0XHRwb2x5Z29uSW5kaWNlcy5sZW5ndGggPSAwO1xuXG5cdFx0bGV0IHBvbHlnb24gPSB0aGlzLnBvbHlnb25Qb29sLm9idGFpbigpO1xuXHRcdHBvbHlnb24ubGVuZ3RoID0gMDtcblxuXHRcdC8vIE1lcmdlIHN1YnNlcXVlbnQgdHJpYW5nbGVzIGlmIHRoZXkgZm9ybSBhIHRyaWFuZ2xlIGZhbi5cblx0XHRsZXQgZmFuQmFzZUluZGV4ID0gLTEsIGxhc3RXaW5kaW5nID0gMDtcblx0XHRmb3IgKGxldCBpID0gMCwgbiA9IHRyaWFuZ2xlcy5sZW5ndGg7IGkgPCBuOyBpICs9IDMpIHtcblx0XHRcdGxldCB0MSA9IHRyaWFuZ2xlc1tpXSA8PCAxLCB0MiA9IHRyaWFuZ2xlc1tpICsgMV0gPDwgMSwgdDMgPSB0cmlhbmdsZXNbaSArIDJdIDw8IDE7XG5cdFx0XHRsZXQgeDEgPSB2ZXJ0aWNlc1t0MV0sIHkxID0gdmVydGljZXNbdDEgKyAxXTtcblx0XHRcdGxldCB4MiA9IHZlcnRpY2VzW3QyXSwgeTIgPSB2ZXJ0aWNlc1t0MiArIDFdO1xuXHRcdFx0bGV0IHgzID0gdmVydGljZXNbdDNdLCB5MyA9IHZlcnRpY2VzW3QzICsgMV07XG5cblx0XHRcdC8vIElmIHRoZSBiYXNlIG9mIHRoZSBsYXN0IHRyaWFuZ2xlIGlzIHRoZSBzYW1lIGFzIHRoaXMgdHJpYW5nbGUsIGNoZWNrIGlmIHRoZXkgZm9ybSBhIGNvbnZleCBwb2x5Z29uICh0cmlhbmdsZSBmYW4pLlxuXHRcdFx0bGV0IG1lcmdlZCA9IGZhbHNlO1xuXHRcdFx0aWYgKGZhbkJhc2VJbmRleCA9PSB0MSkge1xuXHRcdFx0XHRsZXQgbyA9IHBvbHlnb24ubGVuZ3RoIC0gNDtcblx0XHRcdFx0bGV0IHdpbmRpbmcxID0gVHJpYW5ndWxhdG9yLndpbmRpbmcocG9seWdvbltvXSwgcG9seWdvbltvICsgMV0sIHBvbHlnb25bbyArIDJdLCBwb2x5Z29uW28gKyAzXSwgeDMsIHkzKTtcblx0XHRcdFx0bGV0IHdpbmRpbmcyID0gVHJpYW5ndWxhdG9yLndpbmRpbmcoeDMsIHkzLCBwb2x5Z29uWzBdLCBwb2x5Z29uWzFdLCBwb2x5Z29uWzJdLCBwb2x5Z29uWzNdKTtcblx0XHRcdFx0aWYgKHdpbmRpbmcxID09IGxhc3RXaW5kaW5nICYmIHdpbmRpbmcyID09IGxhc3RXaW5kaW5nKSB7XG5cdFx0XHRcdFx0cG9seWdvbi5wdXNoKHgzKTtcblx0XHRcdFx0XHRwb2x5Z29uLnB1c2goeTMpO1xuXHRcdFx0XHRcdHBvbHlnb25JbmRpY2VzLnB1c2godDMpO1xuXHRcdFx0XHRcdG1lcmdlZCA9IHRydWU7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0Ly8gT3RoZXJ3aXNlIG1ha2UgdGhpcyB0cmlhbmdsZSB0aGUgbmV3IGJhc2UuXG5cdFx0XHRpZiAoIW1lcmdlZCkge1xuXHRcdFx0XHRpZiAocG9seWdvbi5sZW5ndGggPiAwKSB7XG5cdFx0XHRcdFx0Y29udmV4UG9seWdvbnMucHVzaChwb2x5Z29uKTtcblx0XHRcdFx0XHRjb252ZXhQb2x5Z29uc0luZGljZXMucHVzaChwb2x5Z29uSW5kaWNlcyk7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0dGhpcy5wb2x5Z29uUG9vbC5mcmVlKHBvbHlnb24pXG5cdFx0XHRcdFx0dGhpcy5wb2x5Z29uSW5kaWNlc1Bvb2wuZnJlZShwb2x5Z29uSW5kaWNlcyk7XG5cdFx0XHRcdH1cblx0XHRcdFx0cG9seWdvbiA9IHRoaXMucG9seWdvblBvb2wub2J0YWluKCk7XG5cdFx0XHRcdHBvbHlnb24ubGVuZ3RoID0gMDtcblx0XHRcdFx0cG9seWdvbi5wdXNoKHgxKTtcblx0XHRcdFx0cG9seWdvbi5wdXNoKHkxKTtcblx0XHRcdFx0cG9seWdvbi5wdXNoKHgyKTtcblx0XHRcdFx0cG9seWdvbi5wdXNoKHkyKTtcblx0XHRcdFx0cG9seWdvbi5wdXNoKHgzKTtcblx0XHRcdFx0cG9seWdvbi5wdXNoKHkzKTtcblx0XHRcdFx0cG9seWdvbkluZGljZXMgPSB0aGlzLnBvbHlnb25JbmRpY2VzUG9vbC5vYnRhaW4oKTtcblx0XHRcdFx0cG9seWdvbkluZGljZXMubGVuZ3RoID0gMDtcblx0XHRcdFx0cG9seWdvbkluZGljZXMucHVzaCh0MSk7XG5cdFx0XHRcdHBvbHlnb25JbmRpY2VzLnB1c2godDIpO1xuXHRcdFx0XHRwb2x5Z29uSW5kaWNlcy5wdXNoKHQzKTtcblx0XHRcdFx0bGFzdFdpbmRpbmcgPSBUcmlhbmd1bGF0b3Iud2luZGluZyh4MSwgeTEsIHgyLCB5MiwgeDMsIHkzKTtcblx0XHRcdFx0ZmFuQmFzZUluZGV4ID0gdDE7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWYgKHBvbHlnb24ubGVuZ3RoID4gMCkge1xuXHRcdFx0Y29udmV4UG9seWdvbnMucHVzaChwb2x5Z29uKTtcblx0XHRcdGNvbnZleFBvbHlnb25zSW5kaWNlcy5wdXNoKHBvbHlnb25JbmRpY2VzKTtcblx0XHR9XG5cblx0XHQvLyBHbyB0aHJvdWdoIHRoZSBsaXN0IG9mIHBvbHlnb25zIGFuZCB0cnkgdG8gbWVyZ2UgdGhlIHJlbWFpbmluZyB0cmlhbmdsZXMgd2l0aCB0aGUgZm91bmQgdHJpYW5nbGUgZmFucy5cblx0XHRmb3IgKGxldCBpID0gMCwgbiA9IGNvbnZleFBvbHlnb25zLmxlbmd0aDsgaSA8IG47IGkrKykge1xuXHRcdFx0cG9seWdvbkluZGljZXMgPSBjb252ZXhQb2x5Z29uc0luZGljZXNbaV07XG5cdFx0XHRpZiAocG9seWdvbkluZGljZXMubGVuZ3RoID09IDApIGNvbnRpbnVlO1xuXHRcdFx0bGV0IGZpcnN0SW5kZXggPSBwb2x5Z29uSW5kaWNlc1swXTtcblx0XHRcdGxldCBsYXN0SW5kZXggPSBwb2x5Z29uSW5kaWNlc1twb2x5Z29uSW5kaWNlcy5sZW5ndGggLSAxXTtcblxuXHRcdFx0cG9seWdvbiA9IGNvbnZleFBvbHlnb25zW2ldO1xuXHRcdFx0bGV0IG8gPSBwb2x5Z29uLmxlbmd0aCAtIDQ7XG5cdFx0XHRsZXQgcHJldlByZXZYID0gcG9seWdvbltvXSwgcHJldlByZXZZID0gcG9seWdvbltvICsgMV07XG5cdFx0XHRsZXQgcHJldlggPSBwb2x5Z29uW28gKyAyXSwgcHJldlkgPSBwb2x5Z29uW28gKyAzXTtcblx0XHRcdGxldCBmaXJzdFggPSBwb2x5Z29uWzBdLCBmaXJzdFkgPSBwb2x5Z29uWzFdO1xuXHRcdFx0bGV0IHNlY29uZFggPSBwb2x5Z29uWzJdLCBzZWNvbmRZID0gcG9seWdvblszXTtcblx0XHRcdGxldCB3aW5kaW5nID0gVHJpYW5ndWxhdG9yLndpbmRpbmcocHJldlByZXZYLCBwcmV2UHJldlksIHByZXZYLCBwcmV2WSwgZmlyc3RYLCBmaXJzdFkpO1xuXG5cdFx0XHRmb3IgKGxldCBpaSA9IDA7IGlpIDwgbjsgaWkrKykge1xuXHRcdFx0XHRpZiAoaWkgPT0gaSkgY29udGludWU7XG5cdFx0XHRcdGxldCBvdGhlckluZGljZXMgPSBjb252ZXhQb2x5Z29uc0luZGljZXNbaWldO1xuXHRcdFx0XHRpZiAob3RoZXJJbmRpY2VzLmxlbmd0aCAhPSAzKSBjb250aW51ZTtcblx0XHRcdFx0bGV0IG90aGVyRmlyc3RJbmRleCA9IG90aGVySW5kaWNlc1swXTtcblx0XHRcdFx0bGV0IG90aGVyU2Vjb25kSW5kZXggPSBvdGhlckluZGljZXNbMV07XG5cdFx0XHRcdGxldCBvdGhlckxhc3RJbmRleCA9IG90aGVySW5kaWNlc1syXTtcblxuXHRcdFx0XHRsZXQgb3RoZXJQb2x5ID0gY29udmV4UG9seWdvbnNbaWldO1xuXHRcdFx0XHRsZXQgeDMgPSBvdGhlclBvbHlbb3RoZXJQb2x5Lmxlbmd0aCAtIDJdLCB5MyA9IG90aGVyUG9seVtvdGhlclBvbHkubGVuZ3RoIC0gMV07XG5cblx0XHRcdFx0aWYgKG90aGVyRmlyc3RJbmRleCAhPSBmaXJzdEluZGV4IHx8IG90aGVyU2Vjb25kSW5kZXggIT0gbGFzdEluZGV4KSBjb250aW51ZTtcblx0XHRcdFx0bGV0IHdpbmRpbmcxID0gVHJpYW5ndWxhdG9yLndpbmRpbmcocHJldlByZXZYLCBwcmV2UHJldlksIHByZXZYLCBwcmV2WSwgeDMsIHkzKTtcblx0XHRcdFx0bGV0IHdpbmRpbmcyID0gVHJpYW5ndWxhdG9yLndpbmRpbmcoeDMsIHkzLCBmaXJzdFgsIGZpcnN0WSwgc2Vjb25kWCwgc2Vjb25kWSk7XG5cdFx0XHRcdGlmICh3aW5kaW5nMSA9PSB3aW5kaW5nICYmIHdpbmRpbmcyID09IHdpbmRpbmcpIHtcblx0XHRcdFx0XHRvdGhlclBvbHkubGVuZ3RoID0gMDtcblx0XHRcdFx0XHRvdGhlckluZGljZXMubGVuZ3RoID0gMDtcblx0XHRcdFx0XHRwb2x5Z29uLnB1c2goeDMpO1xuXHRcdFx0XHRcdHBvbHlnb24ucHVzaCh5Myk7XG5cdFx0XHRcdFx0cG9seWdvbkluZGljZXMucHVzaChvdGhlckxhc3RJbmRleCk7XG5cdFx0XHRcdFx0cHJldlByZXZYID0gcHJldlg7XG5cdFx0XHRcdFx0cHJldlByZXZZID0gcHJldlk7XG5cdFx0XHRcdFx0cHJldlggPSB4Mztcblx0XHRcdFx0XHRwcmV2WSA9IHkzO1xuXHRcdFx0XHRcdGlpID0gMDtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vIFJlbW92ZSBlbXB0eSBwb2x5Z29ucyB0aGF0IHJlc3VsdGVkIGZyb20gdGhlIG1lcmdlIHN0ZXAgYWJvdmUuXG5cdFx0Zm9yIChsZXQgaSA9IGNvbnZleFBvbHlnb25zLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7XG5cdFx0XHRwb2x5Z29uID0gY29udmV4UG9seWdvbnNbaV07XG5cdFx0XHRpZiAocG9seWdvbi5sZW5ndGggPT0gMCkge1xuXHRcdFx0XHRjb252ZXhQb2x5Z29ucy5zcGxpY2UoaSwgMSk7XG5cdFx0XHRcdHRoaXMucG9seWdvblBvb2wuZnJlZShwb2x5Z29uKTtcblx0XHRcdFx0cG9seWdvbkluZGljZXMgPSBjb252ZXhQb2x5Z29uc0luZGljZXNbaV1cblx0XHRcdFx0Y29udmV4UG9seWdvbnNJbmRpY2VzLnNwbGljZShpLCAxKVxuXHRcdFx0XHR0aGlzLnBvbHlnb25JbmRpY2VzUG9vbC5mcmVlKHBvbHlnb25JbmRpY2VzKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRyZXR1cm4gY29udmV4UG9seWdvbnM7XG5cdH1cblxuXHRwcml2YXRlIHN0YXRpYyBpc0NvbmNhdmUgKGluZGV4OiBudW1iZXIsIHZlcnRleENvdW50OiBudW1iZXIsIHZlcnRpY2VzOiBOdW1iZXJBcnJheUxpa2UsIGluZGljZXM6IE51bWJlckFycmF5TGlrZSk6IGJvb2xlYW4ge1xuXHRcdGxldCBwcmV2aW91cyA9IGluZGljZXNbKHZlcnRleENvdW50ICsgaW5kZXggLSAxKSAlIHZlcnRleENvdW50XSA8PCAxO1xuXHRcdGxldCBjdXJyZW50ID0gaW5kaWNlc1tpbmRleF0gPDwgMTtcblx0XHRsZXQgbmV4dCA9IGluZGljZXNbKGluZGV4ICsgMSkgJSB2ZXJ0ZXhDb3VudF0gPDwgMTtcblx0XHRyZXR1cm4gIXRoaXMucG9zaXRpdmVBcmVhKHZlcnRpY2VzW3ByZXZpb3VzXSwgdmVydGljZXNbcHJldmlvdXMgKyAxXSwgdmVydGljZXNbY3VycmVudF0sIHZlcnRpY2VzW2N1cnJlbnQgKyAxXSwgdmVydGljZXNbbmV4dF0sXG5cdFx0XHR2ZXJ0aWNlc1tuZXh0ICsgMV0pO1xuXHR9XG5cblx0cHJpdmF0ZSBzdGF0aWMgcG9zaXRpdmVBcmVhIChwMXg6IG51bWJlciwgcDF5OiBudW1iZXIsIHAyeDogbnVtYmVyLCBwMnk6IG51bWJlciwgcDN4OiBudW1iZXIsIHAzeTogbnVtYmVyKTogYm9vbGVhbiB7XG5cdFx0cmV0dXJuIHAxeCAqIChwM3kgLSBwMnkpICsgcDJ4ICogKHAxeSAtIHAzeSkgKyBwM3ggKiAocDJ5IC0gcDF5KSA+PSAwO1xuXHR9XG5cblx0cHJpdmF0ZSBzdGF0aWMgd2luZGluZyAocDF4OiBudW1iZXIsIHAxeTogbnVtYmVyLCBwMng6IG51bWJlciwgcDJ5OiBudW1iZXIsIHAzeDogbnVtYmVyLCBwM3k6IG51bWJlcik6IG51bWJlciB7XG5cdFx0bGV0IHB4ID0gcDJ4IC0gcDF4LCBweSA9IHAyeSAtIHAxeTtcblx0XHRyZXR1cm4gcDN4ICogcHkgLSBwM3kgKiBweCArIHB4ICogcDF5IC0gcDF4ICogcHkgPj0gMCA/IDEgOiAtMTtcblx0fVxufVxuIl19