UNPKG

@esotericsoftware/spine-core

Version:
242 lines 40.1 kB
/****************************************************************************** * 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