UNPKG

@esotericsoftware/spine-core

Version:
217 lines 33.7 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 { BoundingBoxAttachment } from "./attachments/BoundingBoxAttachment.js"; import { Pool, Utils } from "./Utils.js"; /** Collects each visible {@link BoundingBoxAttachment} and computes the world vertices for its polygon. The polygon vertices are * provided along with convenience methods for doing hit detection. */ export class SkeletonBounds { /** The left edge of the axis aligned bounding box. */ minX = 0; /** The bottom edge of the axis aligned bounding box. */ minY = 0; /** The right edge of the axis aligned bounding box. */ maxX = 0; /** The top edge of the axis aligned bounding box. */ maxY = 0; /** The visible bounding boxes. */ boundingBoxes = new Array(); /** The world vertices for the bounding box polygons. */ polygons = new Array(); polygonPool = new Pool(() => { return Utils.newFloatArray(16); }); /** Clears any previous polygons, finds all visible bounding box attachments, and computes the world vertices for each bounding * box's polygon. * @param updateAabb If true, the axis aligned bounding box containing all the polygons is computed. If false, the * SkeletonBounds AABB methods will always return true. */ update(skeleton, updateAabb) { if (!skeleton) throw new Error("skeleton cannot be null."); let boundingBoxes = this.boundingBoxes; let polygons = this.polygons; let polygonPool = this.polygonPool; let slots = skeleton.slots; let slotCount = slots.length; boundingBoxes.length = 0; polygonPool.freeAll(polygons); polygons.length = 0; for (let i = 0; i < slotCount; i++) { let slot = slots[i]; if (!slot.bone.active) continue; let attachment = slot.getAttachment(); if (attachment instanceof BoundingBoxAttachment) { let boundingBox = attachment; boundingBoxes.push(boundingBox); let polygon = polygonPool.obtain(); if (polygon.length != boundingBox.worldVerticesLength) { polygon = Utils.newFloatArray(boundingBox.worldVerticesLength); } polygons.push(polygon); boundingBox.computeWorldVertices(slot, 0, boundingBox.worldVerticesLength, polygon, 0, 2); } } if (updateAabb) { this.aabbCompute(); } else { this.minX = Number.POSITIVE_INFINITY; this.minY = Number.POSITIVE_INFINITY; this.maxX = Number.NEGATIVE_INFINITY; this.maxY = Number.NEGATIVE_INFINITY; } } aabbCompute() { let minX = Number.POSITIVE_INFINITY, minY = Number.POSITIVE_INFINITY, maxX = Number.NEGATIVE_INFINITY, maxY = Number.NEGATIVE_INFINITY; let polygons = this.polygons; for (let i = 0, n = polygons.length; i < n; i++) { let polygon = polygons[i]; let vertices = polygon; for (let ii = 0, nn = polygon.length; ii < nn; ii += 2) { let x = vertices[ii]; let y = vertices[ii + 1]; minX = Math.min(minX, x); minY = Math.min(minY, y); maxX = Math.max(maxX, x); maxY = Math.max(maxY, y); } } this.minX = minX; this.minY = minY; this.maxX = maxX; this.maxY = maxY; } /** Returns true if the axis aligned bounding box contains the point. */ aabbContainsPoint(x, y) { return x >= this.minX && x <= this.maxX && y >= this.minY && y <= this.maxY; } /** Returns true if the axis aligned bounding box intersects the line segment. */ aabbIntersectsSegment(x1, y1, x2, y2) { let minX = this.minX; let minY = this.minY; let maxX = this.maxX; let maxY = this.maxY; if ((x1 <= minX && x2 <= minX) || (y1 <= minY && y2 <= minY) || (x1 >= maxX && x2 >= maxX) || (y1 >= maxY && y2 >= maxY)) return false; let m = (y2 - y1) / (x2 - x1); let y = m * (minX - x1) + y1; if (y > minY && y < maxY) return true; y = m * (maxX - x1) + y1; if (y > minY && y < maxY) return true; let x = (minY - y1) / m + x1; if (x > minX && x < maxX) return true; x = (maxY - y1) / m + x1; if (x > minX && x < maxX) return true; return false; } /** Returns true if the axis aligned bounding box intersects the axis aligned bounding box of the specified bounds. */ aabbIntersectsSkeleton(bounds) { return this.minX < bounds.maxX && this.maxX > bounds.minX && this.minY < bounds.maxY && this.maxY > bounds.minY; } /** Returns the first bounding box attachment that contains the point, or null. When doing many checks, it is usually more * efficient to only call this method if {@link #aabbContainsPoint(float, float)} returns true. */ containsPoint(x, y) { let polygons = this.polygons; for (let i = 0, n = polygons.length; i < n; i++) if (this.containsPointPolygon(polygons[i], x, y)) return this.boundingBoxes[i]; return null; } /** Returns true if the polygon contains the point. */ containsPointPolygon(polygon, x, y) { let vertices = polygon; let nn = polygon.length; let prevIndex = nn - 2; let inside = false; for (let ii = 0; ii < nn; ii += 2) { let vertexY = vertices[ii + 1]; let prevY = vertices[prevIndex + 1]; if ((vertexY < y && prevY >= y) || (prevY < y && vertexY >= y)) { let vertexX = vertices[ii]; if (vertexX + (y - vertexY) / (prevY - vertexY) * (vertices[prevIndex] - vertexX) < x) inside = !inside; } prevIndex = ii; } return inside; } /** Returns the first bounding box attachment that contains any part of the line segment, or null. When doing many checks, it * is usually more efficient to only call this method if {@link #aabbIntersectsSegment()} returns * true. */ intersectsSegment(x1, y1, x2, y2) { let polygons = this.polygons; for (let i = 0, n = polygons.length; i < n; i++) if (this.intersectsSegmentPolygon(polygons[i], x1, y1, x2, y2)) return this.boundingBoxes[i]; return null; } /** Returns true if the polygon contains any part of the line segment. */ intersectsSegmentPolygon(polygon, x1, y1, x2, y2) { let vertices = polygon; let nn = polygon.length; let width12 = x1 - x2, height12 = y1 - y2; let det1 = x1 * y2 - y1 * x2; let x3 = vertices[nn - 2], y3 = vertices[nn - 1]; for (let ii = 0; ii < nn; ii += 2) { let x4 = vertices[ii], y4 = vertices[ii + 1]; let det2 = x3 * y4 - y3 * x4; let width34 = x3 - x4, height34 = y3 - y4; let det3 = width12 * height34 - height12 * width34; let x = (det1 * width34 - width12 * det2) / det3; if (((x >= x3 && x <= x4) || (x >= x4 && x <= x3)) && ((x >= x1 && x <= x2) || (x >= x2 && x <= x1))) { let y = (det1 * height34 - height12 * det2) / det3; if (((y >= y3 && y <= y4) || (y >= y4 && y <= y3)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))) return true; } x3 = x4; y3 = y4; } return false; } /** Returns the polygon for the specified bounding box, or null. */ getPolygon(boundingBox) { if (!boundingBox) throw new Error("boundingBox cannot be null."); let index = this.boundingBoxes.indexOf(boundingBox); return index == -1 ? null : this.polygons[index]; } /** The width of the axis aligned bounding box. */ getWidth() { return this.maxX - this.minX; } /** The height of the axis aligned bounding box. */ getHeight() { return this.maxY - this.minY; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2tlbGV0b25Cb3VuZHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvU2tlbGV0b25Cb3VuZHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OzsrRUEyQitFO0FBRS9FLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLHdDQUF3QyxDQUFDO0FBRS9FLE9BQU8sRUFBbUIsSUFBSSxFQUFFLEtBQUssRUFBRSxNQUFNLFlBQVksQ0FBQztBQUUxRDtzRUFDc0U7QUFDdEUsTUFBTSxPQUFPLGNBQWM7SUFFMUIsc0RBQXNEO0lBQ3RELElBQUksR0FBRyxDQUFDLENBQUM7SUFFVCx3REFBd0Q7SUFDeEQsSUFBSSxHQUFHLENBQUMsQ0FBQztJQUVULHVEQUF1RDtJQUN2RCxJQUFJLEdBQUcsQ0FBQyxDQUFDO0lBRVQscURBQXFEO0lBQ3JELElBQUksR0FBRyxDQUFDLENBQUM7SUFFVCxrQ0FBa0M7SUFDbEMsYUFBYSxHQUFHLElBQUksS0FBSyxFQUF5QixDQUFDO0lBRW5ELHdEQUF3RDtJQUN4RCxRQUFRLEdBQUcsSUFBSSxLQUFLLEVBQW1CLENBQUM7SUFFaEMsV0FBVyxHQUFHLElBQUksSUFBSSxDQUFrQixHQUFHLEVBQUU7UUFDcEQsT0FBTyxLQUFLLENBQUMsYUFBYSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ2hDLENBQUMsQ0FBQyxDQUFDO0lBRUg7Ozt3RUFHb0U7SUFDcEUsTUFBTSxDQUFFLFFBQWtCLEVBQUUsVUFBbUI7UUFDOUMsSUFBSSxDQUFDLFFBQVE7WUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLDBCQUEwQixDQUFDLENBQUM7UUFDM0QsSUFBSSxhQUFhLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQztRQUN2QyxJQUFJLFFBQVEsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDO1FBQzdCLElBQUksV0FBVyxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUM7UUFDbkMsSUFBSSxLQUFLLEdB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Q0FBQyxHQUFHLElBQUksQ0FBQztnQkFDbkQsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO29CQUFFLE9BQU8sSUFBSSxDQUFDO1lBQ25ILENBQUM7WUFDRCxFQUFFLEdBQUcsRUFBRSxDQUFDO1lBQ1IsRUFBRSxHQUFHLEVBQUUsQ0FBQztRQUNULENBQUM7UUFDRCxPQUFPLEtBQUssQ0FBQztJQUNkLENBQUM7SUFFRCxtRUFBbUU7SUFDbkUsVUFBVSxDQUFFLFdBQWtDO1FBQzdDLElBQUksQ0FBQyxXQUFXO1lBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQyw2QkFBNkIsQ0FBQyxDQUFDO1FBQ2pFLElBQUksS0FBSyxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsT0FBTyxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQ3BELE9BQU8sS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDbEQsQ0FBQztJQUVELGtEQUFrRDtJQUNsRCxRQUFRO1FBQ1AsT0FBTyxJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUM7SUFDOUIsQ0FBQztJQUVELG1EQUFtRDtJQUNuRCxTQUFTO1FBQ1IsT0FBTyxJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUM7SUFDOUIsQ0FBQztDQUNEIiwic291cmNlc0NvbnRlbnQiOlsiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuICogU3BpbmUgUnVudGltZXMgTGljZW5zZSBBZ3JlZW1lbnRcbiAqIExhc3QgdXBkYXRlZCBBcHJpbCA1LCAyMDI1LiBSZXBsYWNlcyBhbGwgcHJpb3IgdmVyc2lvbnMuXG4gKlxuICogQ29weXJpZ2h0IChjKSAyMDEzLTIwMjUsIEVzb3RlcmljIFNvZnR3YXJlIExMQ1xuICpcbiAqIEludGVncmF0aW9uIG9mIHRoZSBTcGluZSBSdW50aW1lcyBpbnRvIHNvZnR3YXJlIG9yIG90aGVyd2lzZSBjcmVhdGluZ1xuICogZGVyaXZhdGl2ZSB3b3JrcyBvZiB0aGUgU3BpbmUgUnVudGltZXMgaXMgcGVybWl0dGVkIHVuZGVyIHRoZSB0ZXJtcyBhbmRcbiAqIGNvbmRpdGlvbnMgb2YgU2VjdGlvbiAyIG9mIHRoZSBTcGluZSBFZGl0b3IgTGljZW5zZSBBZ3JlZW1lbnQ6XG4gKiBodHRwOi8vZXNvdGVyaWNzb2Z0d2FyZS5jb20vc3BpbmUtZWRpdG9yLWxpY2Vuc2VcbiAqXG4gKiBPdGhlcndpc2UsIGl0IGlzIHBlcm1pdHRlZCB0byBpbnRlZ3JhdGUgdGhlIFNwaW5lIFJ1bnRpbWVzIGludG8gc29mdHdhcmVcbiAqIG9yIG90aGVyd2lzZSBjcmVhdGUgZGVyaXZhdGl2ZSB3b3JrcyBvZiB0aGUgU3BpbmUgUnVudGltZXMgKGNvbGxlY3RpdmVseSxcbiAqIFwiUHJvZHVjdHNcIiksIHByb3ZpZGVkIHRoYXQgZWFjaCB1c2VyIG9mIHRoZSBQcm9kdWN0cyBtdXN0IG9idGFpbiB0aGVpciBvd25cbiAqIFNwaW5lIEVkaXRvciBsaWNlbnNlIGFuZCByZWRpc3RyaWJ1dGlvbiBvZiB0aGUgUHJvZHVjdHMgaW4gYW55IGZvcm0gbXVzdFxuICogaW5jbHVkZSB0aGlzIGxpY2Vuc2UgYW5kIGNvcHlyaWdodCBub3RpY2UuXG4gKlxuICogVEhFIFNQSU5FIFJVTlRJTUVTIEFSRSBQUk9WSURFRCBCWSBFU09URVJJQyBTT0ZUV0FSRSBMTEMgXCJBUyBJU1wiIEFORCBBTllcbiAqIEVYUFJFU1MgT1IgSU1QTElFRCBXQVJSQU5USUVTLCBJTkNMVURJTkcsIEJVVCBOT1QgTElNSVRFRCBUTywgVEhFIElNUExJRURcbiAqIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZIEFORCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBUkVcbiAqIERJU0NMQUlNRUQuIElOIE5PIEVWRU5UIFNIQUxMIEVTT1RFUklDIFNPRlRXQVJFIExMQyBCRSBMSUFCTEUgRk9SIEFOWVxuICogRElSRUNULCBJTkRJUkVDVCwgSU5DSURFTlRBTCwgU1BFQ0lBTCwgRVhFTVBMQVJZLCBPUiBDT05TRVFVRU5USUFMIERBTUFHRVNcbiAqIChJTkNMVURJTkcsIEJVVCBOT1QgTElNSVRFRCBUTywgUFJPQ1VSRU1FTlQgT0YgU1VCU1RJVFVURSBHT09EUyBPUiBTRVJWSUNFUyxcbiAqIEJVU0lORVNTIElOVEVSUlVQVElPTiwgT1IgTE9TUyBPRiBVU0UsIERBVEEsIE9SIFBST0ZJVFMpIEhPV0VWRVIgQ0FVU0VEIEFORFxuICogT04gQU5ZIFRIRU9SWSBPRiBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQ09OVFJBQ1QsIFNUUklDVCBMSUFCSUxJVFksIE9SIFRPUlRcbiAqIChJTkNMVURJTkcgTkVHTElHRU5DRSBPUiBPVEhFUldJU0UpIEFSSVNJTkcgSU4gQU5ZIFdBWSBPVVQgT0YgVEhFIFVTRSBPRlxuICogVEhFIFNQSU5FIFJVTlRJTUVTLCBFVkVOIElGIEFEVklTRUQgT0YgVEhFIFBPU1NJQklMSVRZIE9GIFNVQ0ggREFNQUdFLlxuICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyBCb3VuZGluZ0JveEF0dGFjaG1lbnQgfSBmcm9tIFwiLi9hdHRhY2htZW50cy9Cb3VuZGluZ0JveEF0dGFjaG1lbnQuanNcIjtcbmltcG9ydCB7IFNrZWxldG9uIH0gZnJvbSBcIi4vU2tlbGV0b24uanNcIjtcbmltcG9ydCB7IE51bWJlckFycmF5TGlrZSwgUG9vbCwgVXRpbHMgfSBmcm9tIFwiLi9VdGlscy5qc1wiO1xuXG4vKiogQ29sbGVjdHMgZWFjaCB2aXNpYmxlIHtAbGluayBCb3VuZGluZ0JveEF0dGFjaG1lbnR9IGFuZCBjb21wdXRlcyB0aGUgd29ybGQgdmVydGljZXMgZm9yIGl0cyBwb2x5Z29uLiBUaGUgcG9seWdvbiB2ZXJ0aWNlcyBhcmVcbiAqIHByb3ZpZGVkIGFsb25nIHdpdGggY29udmVuaWVuY2UgbWV0aG9kcyBmb3IgZG9pbmcgaGl0IGRldGVjdGlvbi4gKi9cbmV4cG9ydCBjbGFzcyBTa2VsZXRvbkJvdW5kcyB7XG5cblx0LyoqIFRoZSBsZWZ0IGVkZ2Ugb2YgdGhlIGF4aXMgYWxpZ25lZCBib3VuZGluZyBib3guICovXG5cdG1pblggPSAwO1xuXG5cdC8qKiBUaGUgYm90dG9tIGVkZ2Ugb2YgdGhlIGF4aXMgYWxpZ25lZCBib3VuZGluZyBib3guICovXG5cdG1pblkgPSAwO1xuXG5cdC8qKiBUaGUgcmlnaHQgZWRnZSBvZiB0aGUgYXhpcyBhbGlnbmVkIGJvdW5kaW5nIGJveC4gKi9cblx0bWF4WCA9IDA7XG5cblx0LyoqIFRoZSB0b3AgZWRnZSBvZiB0aGUgYXhpcyBhbGlnbmVkIGJvdW5kaW5nIGJveC4gKi9cblx0bWF4WSA9IDA7XG5cblx0LyoqIFRoZSB2aXNpYmxlIGJvdW5kaW5nIGJveGVzLiAqL1xuXHRib3VuZGluZ0JveGVzID0gbmV3IEFycmF5PEJvdW5kaW5nQm94QXR0YWNobWVudD4oKTtcblxuXHQvKiogVGhlIHdvcmxkIHZlcnRpY2VzIGZvciB0aGUgYm91bmRpbmcgYm94IHBvbHlnb25zLiAqL1xuXHRwb2x5Z29ucyA9IG5ldyBBcnJheTxOdW1iZXJBcnJheUxpa2U+KCk7XG5cblx0cHJpdmF0ZSBwb2x5Z29uUG9vbCA9IG5ldyBQb29sPE51bWJlckFycmF5TGlrZT4oKCkgPT4ge1xuXHRcdHJldHVybiBVdGlscy5uZXdGbG9hdEFycmF5KDE2KTtcblx0fSk7XG5cblx0LyoqIENsZWFycyBhbnkgcHJldmlvdXMgcG9seWdvbnMsIGZpbmRzIGFsbCB2aXNpYmxlIGJvdW5kaW5nIGJveCBhdHRhY2htZW50cywgYW5kIGNvbXB1dGVzIHRoZSB3b3JsZCB2ZXJ0aWNlcyBmb3IgZWFjaCBib3VuZGluZ1xuXHQgKiBib3gncyBwb2x5Z29uLlxuXHQgKiBAcGFyYW0gdXBkYXRlQWFiYiBJZiB0cnVlLCB0aGUgYXhpcyBhbGlnbmVkIGJvdW5kaW5nIGJveCBjb250YWluaW5nIGFsbCB0aGUgcG9seWdvbnMgaXMgY29tcHV0ZWQuIElmIGZhbHNlLCB0aGVcblx0ICogICAgICAgICAgIFNrZWxldG9uQm91bmRzIEFBQkIgbWV0aG9kcyB3aWxsIGFsd2F5cyByZXR1cm4gdHJ1ZS4gKi9cblx0dXBkYXRlIChza2VsZXRvbjogU2tlbGV0b24sIHVwZGF0ZUFhYmI6IGJvb2xlYW4pIHtcblx0XHRpZiAoIXNrZWxldG9uKSB0aHJvdyBuZXcgRXJyb3IoXCJza2VsZXRvbiBjYW5ub3QgYmUgbnVsbC5cIik7XG5cdFx0bGV0IGJvdW5kaW5nQm94ZXMgPSB0aGlzLmJvdW5kaW5nQm94ZXM7XG5cdFx0bGV0IHBvbHlnb25zID0gdGhpcy5wb2x5Z29ucztcblx0XHRsZXQgcG9seWdvblBvb2wgPSB0aGlzLnBvbHlnb25Qb29sO1xuXHRcdGxldCBzbG90cyA9IHNrZWxldG9uLnNsb3RzO1xuXHRcdGxldCBzbG90Q291bnQgPSBzbG90cy5sZW5ndGg7XG5cblx0XHRib3VuZGluZ0JveGVzLmxlbmd0aCA9IDA7XG5cdFx0cG9seWdvblBvb2wuZnJlZUFsbChwb2x5Z29ucyk7XG5cdFx0cG9seWdvbnMubGVuZ3RoID0gMDtcblxuXHRcdGZvciAobGV0IGkgPSAwOyBpIDwgc2xvdENvdW50OyBpKyspIHtcblx0XHRcdGxldCBzbG90ID0gc2xvdHNbaV07XG5cdFx0XHRpZiAoIXNsb3QuYm9uZS5hY3RpdmUpIGNvbnRpbnVlO1xuXHRcdFx0bGV0IGF0dGFjaG1lbnQgPSBzbG90LmdldEF0dGFjaG1lbnQoKTtcblx0XHRcdGlmIChhdHRhY2htZW50IGluc3RhbmNlb2YgQm91bmRpbmdCb3hBdHRhY2htZW50KSB7XG5cdFx0XHRcdGxldCBib3VuZGluZ0JveCA9IGF0dGFjaG1lbnQgYXMgQm91bmRpbmdCb3hBdHRhY2htZW50O1xuXHRcdFx0XHRib3VuZGluZ0JveGVzLnB1c2goYm91bmRpbmdCb3gpO1xuXG5cdFx0XHRcdGxldCBwb2x5Z29uID0gcG9seWdvblBvb2wub2J0YWluKCk7XG5cdFx0XHRcdGlmIChwb2x5Z29uLmxlbmd0aCAhPSBib3VuZGluZ0JveC53b3JsZFZlcnRpY2VzTGVuZ3RoKSB7XG5cdFx0XHRcdFx0cG9seWdvbiA9IFV0aWxzLm5ld0Zsb2F0QXJyYXkoYm91bmRpbmdCb3gud29ybGRWZXJ0aWNlc0xlbmd0aCk7XG5cdFx0XHRcdH1cblx0XHRcdFx0cG9seWdvbnMucHVzaChwb2x5Z29uKTtcblx0XHRcdFx0Ym91bmRpbmdCb3guY29tcHV0ZVdvcmxkVmVydGljZXMoc2xvdCwgMCwgYm91bmRpbmdCb3gud29ybGRWZXJ0aWNlc0xlbmd0aCwgcG9seWdvbiwgMCwgMik7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWYgKHVwZGF0ZUFhYmIpIHtcblx0XHRcdHRoaXMuYWFiYkNvbXB1dGUoKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5taW5YID0gTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZO1xuXHRcdFx0dGhpcy5taW5ZID0gTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZO1xuXHRcdFx0dGhpcy5tYXhYID0gTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZO1xuXHRcdFx0dGhpcy5tYXhZID0gTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZO1xuXHRcdH1cblx0fVxuXG5cdGFhYmJDb21wdXRlICgpIHtcblx0XHRsZXQgbWluWCA9IE51bWJlci5QT1NJVElWRV9JTkZJTklUWSwgbWluWSA9IE51bWJlci5QT1NJVElWRV9JTkZJTklUWSwgbWF4WCA9IE51bWJlci5ORUdBVElWRV9JTkZJTklUWSwgbWF4WSA9IE51bWJlci5ORUdBVElWRV9JTkZJTklUWTtcblx0XHRsZXQgcG9seWdvbnMgPSB0aGlzLnBvbHlnb25zO1xuXHRcdGZvciAobGV0IGkgPSAwLCBuID0gcG9seWdvbnMubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XG5cdFx0XHRsZXQgcG9seWdvbiA9IHBvbHlnb25zW2ldO1xuXHRcdFx0bGV0IHZlcnRpY2VzID0gcG9seWdvbjtcblx0XHRcdGZvciAobGV0IGlpID0gMCwgbm4gPSBwb2x5Z29uLmxlbmd0aDsgaWkgPCBubjsgaWkgKz0gMikge1xuXHRcdFx0XHRsZXQgeCA9IHZlcnRpY2VzW2lpXTtcblx0XHRcdFx0bGV0IHkgPSB2ZXJ0aWNlc1tpaSArIDFdO1xuXHRcdFx0XHRtaW5YID0gTWF0aC5taW4obWluWCwgeCk7XG5cdFx0XHRcdG1pblkgPSBNYXRoLm1pbihtaW5ZLCB5KTtcblx0XHRcdFx0bWF4WCA9IE1hdGgubWF4KG1heFgsIHgpO1xuXHRcdFx0XHRtYXhZID0gTWF0aC5tYXgobWF4WSwgeSk7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHRoaXMubWluWCA9IG1pblg7XG5cdFx0dGhpcy5taW5ZID0gbWluWTtcblx0XHR0aGlzLm1heFggPSBtYXhYO1xuXHRcdHRoaXMubWF4WSA9IG1heFk7XG5cdH1cblxuXHQvKiogUmV0dXJucyB0cnVlIGlmIHRoZSBheGlzIGFsaWduZWQgYm91bmRpbmcgYm94IGNvbnRhaW5zIHRoZSBwb2ludC4gKi9cblx0YWFiYkNvbnRhaW5zUG9pbnQgKHg6IG51bWJlciwgeTogbnVtYmVyKSB7XG5cdFx0cmV0dXJuIHggPj0gdGhpcy5taW5YICYmIHggPD0gdGhpcy5tYXhYICYmIHkgPj0gdGhpcy5taW5ZICYmIHkgPD0gdGhpcy5tYXhZO1xuXHR9XG5cblx0LyoqIFJldHVybnMgdHJ1ZSBpZiB0aGUgYXhpcyBhbGlnbmVkIGJvdW5kaW5nIGJveCBpbnRlcnNlY3RzIHRoZSBsaW5lIHNlZ21lbnQuICovXG5cdGFhYmJJbnRlcnNlY3RzU2VnbWVudCAoeDE6IG51bWJlciwgeTE6IG51bWJlciwgeDI6IG51bWJlciwgeTI6IG51bWJlcikge1xuXHRcdGxldCBtaW5YID0gdGhpcy5taW5YO1xuXHRcdGxldCBtaW5ZID0gdGhpcy5taW5ZO1xuXHRcdGxldCBtYXhYID0gdGhpcy5tYXhYO1xuXHRcdGxldCBtYXhZID0gdGhpcy5tYXhZO1xuXHRcdGlmICgoeDEgPD0gbWluWCAmJiB4MiA8PSBtaW5YKSB8fCAoeTEgPD0gbWluWSAmJiB5MiA8PSBtaW5ZKSB8fCAoeDEgPj0gbWF4WCAmJiB4MiA+PSBtYXhYKSB8fCAoeTEgPj0gbWF4WSAmJiB5MiA+PSBtYXhZKSlcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRsZXQgbSA9ICh5MiAtIHkxKSAvICh4MiAtIHgxKTtcblx0XHRsZXQgeSA9IG0gKiAobWluWCAtIHgxKSArIHkxO1xuXHRcdGlmICh5ID4gbWluWSAmJiB5IDwgbWF4WSkgcmV0dXJuIHRydWU7XG5cdFx0eSA9IG0gKiAobWF4WCAtIHgxKSArIHkxO1xuXHRcdGlmICh5ID4gbWluWSAmJiB5IDwgbWF4WSkgcmV0dXJuIHRydWU7XG5cdFx0bGV0IHggPSAobWluWSAtIHkxKSAvIG0gKyB4MTtcblx0XHRpZiAoeCA+IG1pblggJiYgeCA8IG1heFgpIHJldHVybiB0cnVlO1xuXHRcdHggPSAobWF4WSAtIHkxKSAvIG0gKyB4MTtcblx0XHRpZiAoeCA+IG1pblggJiYgeCA8IG1heFgpIHJldHVybiB0cnVlO1xuXHRcdHJldHVybiBmYWxzZTtcblx0fVxuXG5cdC8qKiBSZXR1cm5zIHRydWUgaWYgdGhlIGF4aXMgYWxpZ25lZCBib3VuZGluZyBib3ggaW50ZXJzZWN0cyB0aGUgYXhpcyBhbGlnbmVkIGJvdW5kaW5nIGJveCBvZiB0aGUgc3BlY2lmaWVkIGJvdW5kcy4gKi9cblx0YWFiYkludGVyc2VjdHNTa2VsZXRvbiAoYm91bmRzOiBTa2VsZXRvbkJvdW5kcykge1xuXHRcdHJldHVybiB0aGlzLm1pblggPCBib3VuZHMubWF4WCAmJiB0aGlzLm1heFggPiBib3VuZHMubWluWCAmJiB0aGlzLm1pblkgPCBib3VuZHMubWF4WSAmJiB0aGlzLm1heFkgPiBib3VuZHMubWluWTtcblx0fVxuXG5cdC8qKiBSZXR1cm5zIHRoZSBmaXJzdCBib3VuZGluZyBib3ggYXR0YWNobWVudCB0aGF0IGNvbnRhaW5zIHRoZSBwb2ludCwgb3IgbnVsbC4gV2hlbiBkb2luZyBtYW55IGNoZWNrcywgaXQgaXMgdXN1YWxseSBtb3JlXG5cdCAqIGVmZmljaWVudCB0byBvbmx5IGNhbGwgdGhpcyBtZXRob2QgaWYge0BsaW5rICNhYWJiQ29udGFpbnNQb2ludChmbG9hdCwgZmxvYXQpfSByZXR1cm5zIHRydWUuICovXG5cdGNvbnRhaW5zUG9pbnQgKHg6IG51bWJlciwgeTogbnVtYmVyKTogQm91bmRpbmdCb3hBdHRhY2htZW50IHwgbnVsbCB7XG5cdFx0bGV0IHBvbHlnb25zID0gdGhpcy5wb2x5Z29ucztcblx0XHRmb3IgKGxldCBpID0gMCwgbiA9IHBvbHlnb25zLmxlbmd0aDsgaSA8IG47IGkrKylcblx0XHRcdGlmICh0aGlzLmNvbnRhaW5zUG9pbnRQb2x5Z29uKHBvbHlnb25zW2ldLCB4LCB5KSkgcmV0dXJuIHRoaXMuYm91bmRpbmdCb3hlc1tpXTtcblx0XHRyZXR1cm4gbnVsbDtcblx0fVxuXG5cdC8qKiBSZXR1cm5zIHRydWUgaWYgdGhlIHBvbHlnb24gY29udGFpbnMgdGhlIHBvaW50LiAqL1xuXHRjb250YWluc1BvaW50UG9seWdvbiAocG9seWdvbjogTnVtYmVyQXJyYXlMaWtlLCB4OiBudW1iZXIsIHk6IG51bWJlcikge1xuXHRcdGxldCB2ZXJ0aWNlcyA9IHBvbHlnb247XG5cdFx0bGV0IG5uID0gcG9seWdvbi5sZW5ndGg7XG5cblx0XHRsZXQgcHJldkluZGV4ID0gbm4gLSAyO1xuXHRcdGxldCBpbnNpZGUgPSBmYWxzZTtcblx0XHRmb3IgKGxldCBpaSA9IDA7IGlpIDwgbm47IGlpICs9IDIpIHtcblx0XHRcdGxldCB2ZXJ0ZXhZID0gdmVydGljZXNbaWkgKyAxXTtcblx0XHRcdGxldCBwcmV2WSA9IHZlcnRpY2VzW3ByZXZJbmRleCArIDFdO1xuXHRcdFx0aWYgKCh2ZXJ0ZXhZIDwgeSAmJiBwcmV2WSA+PSB5KSB8fCAocHJldlkgPCB5ICYmIHZlcnRleFkgPj0geSkpIHtcblx0XHRcdFx0bGV0IHZlcnRleFggPSB2ZXJ0aWNlc1tpaV07XG5cdFx0XHRcdGlmICh2ZXJ0ZXhYICsgKHkgLSB2ZXJ0ZXhZKSAvIChwcmV2WSAtIHZlcnRleFkpICogKHZlcnRpY2VzW3ByZXZJbmRleF0gLSB2ZXJ0ZXhYKSA8IHgpIGluc2lkZSA9ICFpbnNpZGU7XG5cdFx0XHR9XG5cdFx0XHRwcmV2SW5kZXggPSBpaTtcblx0XHR9XG5cdFx0cmV0dXJuIGluc2lkZTtcblx0fVxuXG5cdC8qKiBSZXR1cm5zIHRoZSBmaXJzdCBib3VuZGluZyBib3ggYXR0YWNobWVudCB0aGF0IGNvbnRhaW5zIGFueSBwYXJ0IG9mIHRoZSBsaW5lIHNlZ21lbnQsIG9yIG51bGwuIFdoZW4gZG9pbmcgbWFueSBjaGVja3MsIGl0XG5cdCAqIGlzIHVzdWFsbHkgbW9yZSBlZmZpY2llbnQgdG8gb25seSBjYWxsIHRoaXMgbWV0aG9kIGlmIHtAbGluayAjYWFiYkludGVyc2VjdHNTZWdtZW50KCl9IHJldHVybnNcblx0ICogdHJ1ZS4gKi9cblx0aW50ZXJzZWN0c1NlZ21lbnQgKHgxOiBudW1iZXIsIHkxOiBudW1iZXIsIHgyOiBudW1iZXIsIHkyOiBudW1iZXIpIHtcblx0XHRsZXQgcG9seWdvbnMgPSB0aGlzLnBvbHlnb25zO1xuXHRcdGZvciAobGV0IGkgPSAwLCBuID0gcG9seWdvbnMubGVuZ3RoOyBpIDwgbjsgaSsrKVxuXHRcdFx0aWYgKHRoaXMuaW50ZXJzZWN0c1NlZ21lbnRQb2x5Z29uKHBvbHlnb25zW2ldLCB4MSwgeTEsIHgyLCB5MikpIHJldHVybiB0aGlzLmJvdW5kaW5nQm94ZXNbaV07XG5cdFx0cmV0dXJuIG51bGw7XG5cdH1cblxuXHQvKiogUmV0dXJucyB0cnVlIGlmIHRoZSBwb2x5Z29uIGNvbnRhaW5zIGFueSBwYXJ0IG9mIHRoZSBsaW5lIHNlZ21lbnQuICovXG5cdGludGVyc2VjdHNTZWdtZW50UG9seWdvbiAocG9seWdvbjogTnVtYmVyQXJyYXlMaWtlLCB4MTogbnVtYmVyLCB5MTogbnVtYmVyLCB4MjogbnVtYmVyLCB5MjogbnVtYmVyKSB7XG5cdFx0bGV0IHZlcnRpY2VzID0gcG9seWdvbjtcblx0XHRsZXQgbm4gPSBwb2x5Z29uLmxlbmd0aDtcblxuXHRcdGxldCB3aWR0aDEyID0geDEgLSB4MiwgaGVpZ2h0MTIgPSB5MSAtIHkyO1xuXHRcdGxldCBkZXQxID0geDEgKiB5MiAtIHkxICogeDI7XG5cdFx0bGV0IHgzID0gdmVydGljZXNbbm4gLSAyXSwgeTMgPSB2ZXJ0aWNlc1tubiAtIDFdO1xuXHRcdGZvciAobGV0IGlpID0gMDsgaWkgPCBubjsgaWkgKz0gMikge1xuXHRcdFx0bGV0IHg0ID0gdmVydGljZXNbaWldLCB5NCA9IHZlcnRpY2VzW2lpICsgMV07XG5cdFx0XHRsZXQgZGV0MiA9IHgzICogeTQgLSB5MyAqIHg0O1xuXHRcdFx0bGV0IHdpZHRoMzQgPSB4MyAtIHg0LCBoZWlnaHQzNCA9IHkzIC0geTQ7XG5cdFx0XHRsZXQgZGV0MyA9IHdpZHRoMTIgKiBoZWlnaHQzNCAtIGhlaWdodDEyICogd2lkdGgzNDtcblx0XHRcdGxldCB4ID0gKGRldDEgKiB3aWR0aDM0IC0gd2lkdGgxMiAqIGRldDIpIC8gZGV0Mztcblx0XHRcdGlmICgoKHggPj0geDMgJiYgeCA8PSB4NCkgfHwgKHggPj0geDQgJiYgeCA8PSB4MykpICYmICgoeCA+PSB4MSAmJiB4IDw9IHgyKSB8fCAoeCA+PSB4MiAmJiB4IDw9IHgxKSkpIHtcblx0XHRcdFx0bGV0IHkgPSAoZGV0MSAqIGhlaWdodDM0IC0gaGVpZ2h0MTIgKiBkZXQyKSAvIGRldDM7XG5cdFx0XHRcdGlmICgoKHkgPj0geTMgJiYgeSA8PSB5NCkgfHwgKHkgPj0geTQgJiYgeSA8PSB5MykpICYmICgoeSA+PSB5MSAmJiB5IDw9IHkyKSB8fCAoeSA+PSB5MiAmJiB5IDw9IHkxKSkpIHJldHVybiB0cnVlO1xuXHRcdFx0fVxuXHRcdFx0eDMgPSB4NDtcblx0XHRcdHkzID0geTQ7XG5cdFx0fVxuXHRcdHJldHVybiBmYWxzZTtcblx0fVxuXG5cdC8qKiBSZXR1cm5zIHRoZSBwb2x5Z29uIGZvciB0aGUgc3BlY2lmaWVkIGJvdW5kaW5nIGJveCwgb3IgbnVsbC4gKi9cblx0Z2V0UG9seWdvbiAoYm91bmRpbmdCb3g6IEJvdW5kaW5nQm94QXR0YWNobWVudCkge1xuXHRcdGlmICghYm91bmRpbmdCb3gpIHRocm93IG5ldyBFcnJvcihcImJvdW5kaW5nQm94IGNhbm5vdCBiZSBudWxsLlwiKTtcblx0XHRsZXQgaW5kZXggPSB0aGlzLmJvdW5kaW5nQm94ZXMuaW5kZXhPZihib3VuZGluZ0JveCk7XG5cdFx0cmV0dXJuIGluZGV4ID09IC0xID8gbnVsbCA6IHRoaXMucG9seWdvbnNbaW5kZXhdO1xuXHR9XG5cblx0LyoqIFRoZSB3aWR0aCBvZiB0aGUgYXhpcyBhbGlnbmVkIGJvdW5kaW5nIGJveC4gKi9cblx0Z2V0V2lkdGggKCkge1xuXHRcdHJldHVybiB0aGlzLm1heFggLSB0aGlzLm1pblg7XG5cdH1cblxuXHQvKiogVGhlIGhlaWdodCBvZiB0aGUgYXhpcyBhbGlnbmVkIGJvdW5kaW5nIGJveC4gKi9cblx0Z2V0SGVpZ2h0ICgpIHtcblx0XHRyZXR1cm4gdGhpcy5tYXhZIC0gdGhpcy5taW5ZO1xuXHR9XG59XG4iXX0=