@esotericsoftware/spine-core
Version:
The official Spine Runtimes for the web.
226 lines • 38.3 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 = [];
convexPolygonsIndices = [];
indicesArray = [];
isConcaveArray = [];
triangles = [];
polygonPool = new Pool(() => {
return [];
});
polygonIndicesPool = new Pool(() => {
return [];
});
triangulate(verticesArray) {
const vertices = verticesArray;
let vertexCount = verticesArray.length >> 1;
const indices = this.indicesArray;
indices.length = 0;
for (let i = 0; i < vertexCount; i++)
indices[i] = i;
const isConcave = this.isConcaveArray;
isConcave.length = 0;
for (let i = 0; i < vertexCount; i++)
isConcave[i] = Triangulator.isConcave(i, vertexCount, vertices, indices);
const triangles = this.triangles;
triangles.length = 0;
while (vertexCount > 3) {
// Find ear tip.
let previous = vertexCount - 1, i = 0, next = 1;
while (true) {
// biome-ignore lint/suspicious/noConfusingLabels: reference runtime
outer: if (!isConcave[i]) {
const p1 = indices[previous] << 1, p2 = indices[i] << 1, p3 = indices[next] << 1;
const p1x = vertices[p1], p1y = vertices[p1 + 1];
const p2x = vertices[p2], p2y = vertices[p2 + 1];
const p3x = vertices[p3], p3y = vertices[p3 + 1];
for (let ii = next + 1 < vertexCount ? next + 1 : 0; ii !== previous;) {
if (isConcave[ii]) {
const v = indices[ii] << 1;
const vx = vertices[v], vy = vertices[v + 1];
if (Triangulator.positiveArea(p3x, p3y, p1x, p1y, vx, vy) //
&& Triangulator.positiveArea(p1x, p1y, p2x, p2y, vx, vy) //
&& Triangulator.positiveArea(p2x, p2y, p3x, p3y, vx, vy))
break outer;
}
if (++ii === vertexCount)
ii = 0;
}
break;
}
if (next === 0) {
do {
if (!isConcave[i])
break;
i--;
} while (i > 0);
previous = i > 0 ? i - 1 : vertexCount - 1;
next = i + 1 < vertexCount ? i + 1 : 0;
break;
}
previous = i;
i = next;
if (++next === vertexCount)
next = 0;
}
// Cut ear tip.
triangles.push(indices[previous], indices[i], indices[next]);
indices.splice(i, 1);
isConcave.splice(i, 1);
vertexCount--;
const previousIndex = i > 0 ? i - 1 : vertexCount - 1;
const nextIndex = i < vertexCount ? i : 0;
isConcave[previousIndex] = Triangulator.isConcave(previousIndex, vertexCount, vertices, indices);
isConcave[nextIndex] = Triangulator.isConcave(nextIndex, vertexCount, vertices, indices);
}
if (vertexCount === 3)
triangles.push(indices[2], indices[0], indices[1]);
return triangles;
}
decompose(verticesArray, triangles) {
const vertices = verticesArray;
const convexPolygons = this.convexPolygons;
this.polygonPool.freeAll(convexPolygons);
convexPolygons.length = 0;
const 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) {
const t1 = triangles[i] << 1, t2 = triangles[i + 1] << 1, t3 = triangles[i + 2] << 1;
const x1 = vertices[t1], y1 = vertices[t1 + 1];
const x2 = vertices[t2], y2 = vertices[t2 + 1];
const 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).
if (fanBaseIndex === t1) {
const o = polygon.length - 4;
if (Triangulator.winding(polygon[o], polygon[o + 1], polygon[o + 2], polygon[o + 3], x3, y3) === lastWinding
&& Triangulator.winding(x3, y3, polygon[0], polygon[1], polygon[2], polygon[3]) === lastWinding) {
polygon.push(x3, y3);
polygonIndices.push(t3);
continue;
}
}
// Otherwise make this triangle the new base.
if (polygon.length > 0) {
convexPolygons.push(polygon);
convexPolygonsIndices.push(polygonIndices);
polygon = this.polygonPool.obtain();
polygonIndices = this.polygonIndicesPool.obtain();
}
polygon.length = 0;
polygon.push(x1, y1, x2, y2);
polygon.push(x3, y3);
polygonIndices.length = 0;
polygonIndices.push(t1, t2, t3);
lastWinding = Triangulator.winding(x1, y1, x2, y2, x3, y3);
fanBaseIndex = t1;
}
if (polygon.length > 0) {
convexPolygons.push(polygon);
convexPolygonsIndices.push(polygonIndices);
}
// Merge 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;
const firstIndex = polygonIndices[0];
let lastIndex = polygonIndices[polygonIndices.length - 1];
polygon = convexPolygons[i];
const o = polygon.length - 4;
let prevPrevX = polygon[o], prevPrevY = polygon[o + 1];
let prevX = polygon[o + 2], prevY = polygon[o + 3];
const firstX = polygon[0], firstY = polygon[1];
const secondX = polygon[2], secondY = polygon[3];
const winding = Triangulator.winding(prevPrevX, prevPrevY, prevX, prevY, firstX, firstY);
for (let ii = 0; ii < n; ii++) {
if (ii === i)
continue;
const otherIndices = convexPolygonsIndices[ii];
if (otherIndices.length !== 3)
continue;
const otherFirstIndex = otherIndices[0];
const otherSecondIndex = otherIndices[1];
const otherLastIndex = otherIndices[2];
const otherPoly = convexPolygons[ii];
const x3 = otherPoly[otherPoly.length - 2], y3 = otherPoly[otherPoly.length - 1];
if (otherFirstIndex !== firstIndex || otherSecondIndex !== lastIndex)
continue;
if (Triangulator.winding(prevPrevX, prevPrevY, prevX, prevY, x3, y3) === winding
&& Triangulator.winding(x3, y3, firstX, firstY, secondX, secondY) === winding) {
otherPoly.length = 0;
otherIndices.length = 0;
polygon.push(x3, y3);
polygonIndices.push(otherLastIndex);
lastIndex = otherLastIndex;
prevPrevX = prevX;
prevPrevY = prevY;
prevX = x3;
prevY = y3;
ii = -1;
}
}
}
// Remove empty polygons 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);
}
else
polygon.push(polygon[0], polygon[1]);
}
return convexPolygons;
}
static isConcave(index, vertexCount, vertices, indices) {
const previous = indices[index > 0 ? index - 1 : vertexCount - 1] << 1;
const current = indices[index] << 1;
const next = indices[index + 1 < vertexCount ? index + 1 : 0] << 1;
return !Triangulator.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) {
return p1x * (p3y - p2y) + p2x * (p1y - p3y) + p3x * (p2y - p1y) >= 0 ? 1 : -1;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVHJpYW5ndWxhdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL1RyaWFuZ3VsYXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OytFQTJCK0U7QUFFL0UsT0FBTyxFQUF3QixJQUFJLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFFeEQsTUFBTSxPQUFPLFlBQVk7SUFDaEIsY0FBYyxHQUFHLEVBQXFCLENBQUM7SUFDdkMscUJBQXFCLEdBQUcsRUFBcUIsQ0FBQztJQUU5QyxZQUFZLEdBQUcsRUFBYyxDQUFDO0lBQzlCLGNBQWMsR0FBRyxFQUFlLENBQUM7SUFDakMsU0FBUyxHQUFHLEVBQWMsQ0FBQztJQUUzQixXQUFXLEdBQUcsSUFBSSxJQUFJLENBQWdCLEdBQUcsRUFBRTtRQUNsRCxPQUFPLEVBQWMsQ0FBQztJQUN2QixDQUFDLENBQUMsQ0FBQztJQUVLLGtCQUFrQixHQUFHLElBQUksSUFBSSxDQUFnQixHQUFHLEVBQUU7UUFDekQsT0FBTyxFQUFjLENBQUM7SUFDdkIsQ0FBQyxDQUFDLENBQUM7SUFFSSxXQUFXLENBQUUsYUFBOEI7UUFDakQsTUFBTSxRQUFRLEdBQUcsYUFBYSxDQUFDO1FBQy9CLElBQUksV0FBVyxHQUFHLGFBQWEsQ0FBQyxNQUFNLElBQUksQ0FBQyxDQUFDO1FBRTVDLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUM7UUFDbEMsT0FBTyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7UUFDbkIsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLFdBQVcsRUFBRSxDQUFDLEVBQUU7WUFDbkMsT0FBTyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUVoQixNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDO1FBQ3RDLFNBQVMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDO1FBQ3JCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxXQUFXLEVBQUUsQ0FBQyxFQUFFO1lBQ25DLFNBQVMsQ0FBQyxDQUFDLENBQUMsR0FBRyxZQUFZLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxXQUFXLEVBQUUsUUFBUSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBRTFFLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUM7UUFDakMsU0FBUyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7UUFFckIsT0FBTyxXQUFXLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDeEIsZ0JBQWdCO1lBQ2hCLElBQUksUUFBUSxHQUFHLFdBQVcsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxJQUFJLEdBQUcsQ0FBQyxDQUFDO1lBQ2hELE9BQU8sSUFBSSxFQUFFLENBQUM7Z0JBQ2Isb0VBQW9FO2dCQUNwRSxLQUFLLEVBQ0wsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO29CQUNuQixNQUFNLEVBQUUsR0FBRyxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUUsR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUUsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO29CQUNqRixNQUFNLEdBQUcsR0FBRyxRQUFRLENBQUMsRUFBRSxDQUFDLEVBQUUsR0FBRyxHQUFHLFFBQVEsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUM7b0JBQ2pELE1BQU0sR0FBRyxHQUFHLFFBQVEsQ0FBQyxFQUFFLENBQUMsRUFBRSxHQUFHLEdBQUcsUUFBUSxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQztvQkFDakQsTUFBTSxHQUFHLEdBQUcsUUFBUSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEdBQUcsR0FBRyxRQUFRLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDO29CQUNqRCxLQUFLLElBQUksRUFBRSxHQUFHLElBQUksR0FBRyxDQUFDLEdBQUcsV0FBVyxDQUFDLENBQUMsQ0FBQyxJQUFJLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxLQUFLLFFBQVEsR0FBRyxDQUFDO3dCQUN2RSxJQUFJLFNBQVMsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDOzRCQUNuQixNQUFNLENBQUMsR0FBRyxPQUFPLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDOzRCQUMzQixNQUFNLEVBQUUsR0FBRyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxHQUFHLFFBQVEsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7NEJBQzdDLElBQUksWUFBWSxDQUFDLFlBQVksQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUU7bUNBQ3hELFlBQVksQ0FBQyxZQUFZLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQyxFQUFFO21DQUN4RCxZQUFZLENBQUMsWUFBWSxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDO2dDQUFFLE1BQU0sS0FBSyxDQUFDO3dCQUN4RSxDQUFDO3dCQUNELElBQUksRUFBRSxFQUFFLEtBQUssV0FBVzs0QkFBRSxFQUFFLEdBQUcsQ0FBQyxDQUFDO29CQUVsQyxDQUFDO29CQUNELE1BQU07Z0JBQ1AsQ0FBQztnQkFFRCxJQUFJLElBQUksS0FBSyxDQUFDLEVBQUUsQ0FBQztvQkFDaEIsR0FBRyxDQUFDO3dCQUNILElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDOzRCQUFFLE1BQU07d0JBQ3pCLENBQUMsRUFBRSxDQUFDO29CQUNMLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFO29CQUNoQixRQUFRLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsV0FBVyxHQUFHLENBQUMsQ0FBQztvQkFDM0MsSUFBSSxHQUFHLENBQUMsR0FBRyxDQUFDLEdBQUcsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7b0JBQ3ZDLE1BQU07Z0JBQ1AsQ0FBQztnQkFFRCxRQUFRLEdBQUcsQ0FBQyxDQUFDO2dCQUNiLENBQUMsR0FBRyxJQUFJLENBQUM7Z0JBQ1QsSUFBSSxFQUFFLElBQUksS0FBSyxXQUFXO29CQUFFLElBQUksR0FBRyxDQUFDLENBQUM7WUFDdEMsQ0FBQztZQUVELGVBQWU7WUFDZixTQUFTLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7WUFDN0QsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFDckIsU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFDdkIsV0FBVyxFQUFFLENBQUM7WUFFZCxNQUFNLGFBQWEsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxXQUFXLEdBQUcsQ0FBQyxDQUFDO1lBQ3RELE1BQU0sU0FBUyxHQUFHLENBQUMsR0FBRyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQzFDLFNBQVMsQ0FBQyxhQUFhLENBQUMsR0FBRyxZQUFZLENBQUMsU0FBUyxDQUFDLGFBQWEsRUFBRSxXQUFXLEVBQUUsUUFBUSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1lBQ2pHLFNBQVMsQ0FBQyxTQUFTLENBQUMsR0FBRyxZQUFZLENBQUMsU0FBUyxDQUFDLFNBQVMsRUFBRSxXQUFXLEVBQUUsUUFBUSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQzFGLENBQUM7UUFDRCxJQUFJLFdBQVcsS0FBSyxDQUFDO1lBQUUsU0FBUyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzFFLE9BQU8sU0FBUyxDQUFDO0lBQ2xCLENBQUM7SUFFRCxTQUFTLENBQUUsYUFBNEIsRUFBRSxTQUF3QjtRQUNoRSxNQUFNLFFBQVEsR0FBRyxhQUFhLENBQUM7UUFDL0IsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQztRQUMzQyxJQUFJLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUMsQ0FBQztRQUN6QyxjQUFjLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQztRQUUxQixNQUFNLHFCQUFxQixHQUFHLElBQUksQ0FBQyxxQkFBcUIsQ0FBQztRQUN6RCxJQUFJLENBQUMsa0JBQWtCLENBQUMsT0FBTyxDQUFDLHFCQUFxQixDQUFDLENBQUM7UUFDdkQscUJBQXFCLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQztRQUVqQyxJQUFJLGNBQWMsR0FBRyxJQUFJLENBQUMsa0JBQWtCLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDdEQsY0FBYyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7UUFFMUIsSUFBSSxPQUFPLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUN4QyxPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQztRQUVuQiwwREFBMEQ7UUFDMUQsSUFBSSxZQUFZLEdBQUcsQ0FBQyxDQUFDLEVBQUUsV0FBVyxHQUFHLENBQUMsQ0FBQztRQUN2QyxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsU0FBUyxDQUFDLE1BQU0sRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztZQUNyRCxNQUFNLEVBQUUsR0FBRyxTQUFTLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUUsR0FBRyxTQUFTLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxFQUFFLEdBQUcsU0FBUyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDckYsTUFBTSxFQUFFLEdBQUcsUUFBUSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsR0FBRyxRQUFRLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDO1lBQy9DLE1BQU0sRUFBRSxHQUFHLFFBQVEsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLEdBQUcsUUFBUSxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQztZQUMvQyxNQUFNLEVBQUUsR0FBRyxRQUFRLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxHQUFHLFFBQVEsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUM7WUFFL0MscUhBQXFIO1lBQ3JILElBQUksWUFBWSxLQUFLLEVBQUUsRUFBRSxDQUFDO2dCQUN6QixNQUFNLENBQUMsR0FBRyxPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQztnQkFDN0IsSUFBSSxZQUFZLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxPQUFPLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLE9BQU8sQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsT0FBTyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDLEtBQUssV0FBVzt1QkFDeEcsWUFBWSxDQUFDLE9BQU8sQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLFdBQVcsRUFBRSxDQUFDO29CQUNsRyxPQUFPLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQztvQkFDckIsY0FBYyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztvQkFDeEIsU0FBUztnQkFDVixDQUFDO1lBQ0YsQ0FBQztZQUVELDZDQUE2QztZQUM3QyxJQUFJLE9BQU8sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQ3hCLGNBQWMsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7Z0JBQzdCLHFCQUFxQixDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsQ0FBQztnQkFDM0MsT0FBTyxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsTUFBTSxFQUFFLENBQUM7Z0JBQ3BDLGNBQWMsR0FBRyxJQUFJLENBQUMsa0JBQWtCLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDbkQsQ0FBQztZQUNELE9BQU8sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDO1lBQ25CLE9BQU8sQ0FBQyxJQUFJLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUM7WUFDN0IsT0FBTyxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUM7WUFDckIsY0FBYyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7WUFDMUIsY0FBYyxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBQ2hDLFdBQVcsR0FBRyxZQUFZLENBQUMsT0FBTyxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUM7WUFDM0QsWUFBWSxHQUFHLEVBQUUsQ0FBQztRQUNuQixDQUFDO1FBRUQsSUFBSSxPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3hCLGNBQWMsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDN0IscUJBQXFCLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFDO1FBQzVDLENBQUM7UUFFRCwwREFBMEQ7UUFDMUQsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLGNBQWMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO1lBQ3ZELGNBQWMsR0FBRyxxQkFBcUIsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUMxQyxJQUFJLGNBQWMsQ0FBQyxNQUFNLEtBQUssQ0FBQztnQkFBRSxTQUFTO1lBQzFDLE1BQU0sVUFBVSxHQUFHLGNBQWMsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUNyQyxJQUFJLFNBQVMsR0FBRyxjQUFjLENBQUMsY0FBYyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQztZQUUxRCxPQUFPLEdBQUcsY0FBYyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQzVCLE1BQU0sQ0FBQyxHQUFHLE9BQU8sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDO1lBQzdCLElBQUksU0FBUyxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxTQUFTLEdBQUcsT0FBTyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztZQUN2RCxJQUFJLEtBQUssR0FBRyxPQUFPLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEtBQUssR0FBRyxPQUFPLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1lBQ25ELE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxNQUFNLEdBQUcsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQy9DLE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxPQUFPLEdBQUcsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ2pELE1BQU0sT0FBTyxHQUFHLFlBQVksQ0FBQyxPQUFPLENBQUMsU0FBUyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FBQztZQUV6RixLQUFLLElBQUksRUFBRSxHQUFHLENBQUMsRUFBRSxFQUFFLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUM7Z0JBQy9CLElBQUksRUFBRSxLQUFLLENBQUM7b0JBQUUsU0FBUztnQkFDdkIsTUFBTSxZQUFZLEdBQUcscUJBQXFCLENBQUMsRUFBRSxDQUFDLENBQUM7Z0JBQy9DLElBQUksWUFBWSxDQUFDLE1BQU0sS0FBSyxDQUFDO29CQUFFLFNBQVM7Z0JBQ3hDLE1BQU0sZUFBZSxHQUFHLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFDeEMsTUFBTSxnQkFBZ0IsR0FBRyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUM7Z0JBQ3pDLE1BQU0sY0FBYyxHQUFHLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFFdkMsTUFBTSxTQUFTLEdBQUcsY0FBYyxDQUFDLEVBQUUsQ0FBQyxDQUFDO2dCQUNyQyxNQUFNLEVBQUUsR0FBRyxTQUFTLENBQUMsU0FBUyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLEdBQUcsU0FBUyxDQUFDLFNBQVMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUM7Z0JBRWpGLElBQUksZUFBZSxLQUFLLFVBQVUsSUFBSSxnQkFBZ0IsS0FBSyxTQUFTO29CQUFFLFNBQVM7Z0JBQy9FLElBQUksWUFBWSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFLEVBQUUsQ0FBQyxLQUFLLE9BQU87dUJBQzVFLFlBQVksQ0FBQyxPQUFPLENBQUMsRUFBRSxFQUFFLEVBQUUsRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxPQUFPLENBQUMsS0FBSyxPQUFPLEVBQUUsQ0FBQztvQkFDaEYsU0FBUyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7b0JBQ3JCLFlBQVksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDO29CQUN4QixPQUFPLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQztvQkFDckIsY0FBYyxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsQ0FBQztvQkFDcEMsU0FBUyxHQUFHLGNBQWMsQ0FBQztvQkFDM0IsU0FBUyxHQUFHLEtBQUssQ0FBQztvQkFDbEIsU0FBUyxHQUFHLEtBQUssQ0FBQztvQkFDbEIsS0FBSyxHQUFHLEVBQUUsQ0FBQztvQkFDWCxLQUFLLEdBQUcsRUFBRSxDQUFDO29CQUNYLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQztnQkFDVCxDQUFDO1lBQ0YsQ0FBQztRQUNGLENBQUM7UUFFRCxtREFBbUQ7UUFDbkQsS0FBSyxJQUFJLENBQUMsR0FBRyxjQUFjLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDckQsT0FBTyxHQUFHLGNBQWMsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUM1QixJQUFJLE9BQU8sQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7Z0JBQzFCLGNBQWMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO2dCQUM1QixJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztnQkFDL0IsY0FBYyxHQUFHLHFCQUFxQixDQUFDLENBQUMsQ0FBQyxDQUFBO2dCQUN6QyxxQkFBcUIsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFBO2dCQUNsQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFDO1lBQzlDLENBQUM7O2dCQUNBLE9BQU8sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3ZDLENBQUM7UUFFRCxPQUFPLGNBQWMsQ0FBQztJQUN2QixDQUFDO0lBRU8sTUFBTSxDQUFDLFNBQVMsQ0FBRSxLQUFhLEVBQUUsV0FBbUIsRUFBRSxRQUF5QixFQUFFLE9BQXdCO1FBQ2hILE1BQU0sUUFBUSxHQUFHLE9BQU8sQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxXQUFXLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3ZFLE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDcEMsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLEtBQUssR0FBRyxDQUFDLEdBQUcsV0FBVyxDQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDbkUsT0FBTyxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxFQUFFLFFBQVEsQ0FBQyxRQUFRLEdBQUcsQ0FBQyxDQUFDLEVBQUUsUUFBUSxDQUFDLE9BQU8sQ0FBQyxFQUFFLFFBQVEsQ0FBQyxPQUFPLEdBQUcsQ0FBQyxDQUFDLEVBQUUsUUFBUSxDQUFDLElBQUksQ0FBQyxFQUNySSxRQUFRLENBQUMsSUFBSSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDdEIsQ0FBQztJQUVPLE1BQU0sQ0FBQyxZQUFZLENBQUUsR0FBVyxFQUFFLEdBQVcsRUFBRSxHQUFXLEVBQUUsR0FBVyxFQUFFLEdBQVcsRUFBRSxHQUFXO1FBQ3hHLE9BQU8sR0FBRyxHQUFHLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3ZFLENBQUM7SUFFTyxNQUFNLENBQUMsT0FBTyxDQUFFLEdBQVcsRUFBRSxHQUFXLEVBQUUsR0FBVyxFQUFFLEdBQVcsRUFBRSxHQUFXLEVBQUUsR0FBVztRQUNuRyxPQUFPLEdBQUcsR0FBRyxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNoRixDQUFDO0NBQ0QiLCJzb3VyY2VzQ29udGVudCI6WyIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG4gKiBTcGluZSBSdW50aW1lcyBMaWNlbnNlIEFncmVlbWVudFxuICogTGFzdCB1cGRhdGVkIEFwcmlsIDUsIDIwMjUuIFJlcGxhY2VzIGFsbCBwcmlvciB2ZXJzaW9ucy5cbiAqXG4gKiBDb3B5cmlnaHQgKGMpIDIwMTMtMjAyNSwgRXNvdGVyaWMgU29mdHdhcmUgTExDXG4gKlxuICogSW50ZWdyYXRpb24gb2YgdGhlIFNwaW5lIFJ1bnRpbWVzIGludG8gc29mdHdhcmUgb3Igb3RoZXJ3aXNlIGNyZWF0aW5nXG4gKiBkZXJpdmF0aXZlIHdvcmtzIG9mIHRoZSBTcGluZSBSdW50aW1lcyBpcyBwZXJtaXR0ZWQgdW5kZXIgdGhlIHRlcm1zIGFuZFxuICogY29uZGl0aW9ucyBvZiBTZWN0aW9uIDIgb2YgdGhlIFNwaW5lIEVkaXRvciBMaWNlbnNlIEFncmVlbWVudDpcbiAqIGh0dHA6Ly9lc290ZXJpY3NvZnR3YXJlLmNvbS9zcGluZS1lZGl0b3ItbGljZW5zZVxuICpcbiAqIE90aGVyd2lzZSwgaXQgaXMgcGVybWl0dGVkIHRvIGludGVncmF0ZSB0aGUgU3BpbmUgUnVudGltZXMgaW50byBzb2Z0d2FyZVxuICogb3Igb3RoZXJ3aXNlIGNyZWF0ZSBkZXJpdmF0aXZlIHdvcmtzIG9mIHRoZSBTcGluZSBSdW50aW1lcyAoY29sbGVjdGl2ZWx5LFxuICogXCJQcm9kdWN0c1wiKSwgcHJvdmlkZWQgdGhhdCBlYWNoIHVzZXIgb2YgdGhlIFByb2R1Y3RzIG11c3Qgb2J0YWluIHRoZWlyIG93blxuICogU3BpbmUgRWRpdG9yIGxpY2Vuc2UgYW5kIHJlZGlzdHJpYnV0aW9uIG9mIHRoZSBQcm9kdWN0cyBpbiBhbnkgZm9ybSBtdXN0XG4gKiBpbmNsdWRlIHRoaXMgbGljZW5zZSBhbmQgY29weXJpZ2h0IG5vdGljZS5cbiAqXG4gKiBUSEUgU1BJTkUgUlVOVElNRVMgQVJFIFBST1ZJREVEIEJZIEVTT1RFUklDIFNPRlRXQVJFIExMQyBcIkFTIElTXCIgQU5EIEFOWVxuICogRVhQUkVTUyBPUiBJTVBMSUVEIFdBUlJBTlRJRVMsIElOQ0xVRElORywgQlVUIE5PVCBMSU1JVEVEIFRPLCBUSEUgSU1QTElFRFxuICogV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFkgQU5EIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFSRVxuICogRElTQ0xBSU1FRC4gSU4gTk8gRVZFTlQgU0hBTEwgRVNPVEVSSUMgU09GVFdBUkUgTExDIEJFIExJQUJMRSBGT1IgQU5ZXG4gKiBESVJFQ1QsIElORElSRUNULCBJTkNJREVOVEFMLCBTUEVDSUFMLCBFWEVNUExBUlksIE9SIENPTlNFUVVFTlRJQUwgREFNQUdFU1xuICogKElOQ0xVRElORywgQlVUIE5PVCBMSU1JVEVEIFRPLCBQUk9DVVJFTUVOVCBPRiBTVUJTVElUVVRFIEdPT0RTIE9SIFNFUlZJQ0VTLFxuICogQlVTSU5FU1MgSU5URVJSVVBUSU9OLCBPUiBMT1NTIE9GIFVTRSwgREFUQSwgT1IgUFJPRklUUykgSE9XRVZFUiBDQVVTRUQgQU5EXG4gKiBPTiBBTlkgVEhFT1JZIE9GIExJQUJJTElUWSwgV0hFVEhFUiBJTiBDT05UUkFDVCwgU1RSSUNUIExJQUJJTElUWSwgT1IgVE9SVFxuICogKElOQ0xVRElORyBORUdMSUdFTkNFIE9SIE9USEVSV0lTRSkgQVJJU0lORyBJTiBBTlkgV0FZIE9VVCBPRiBUSEUgVVNFIE9GXG4gKiBUSEUgU1BJTkUgUlVOVElNRVMsIEVWRU4gSUYgQURWSVNFRCBPRiBUSEUgUE9TU0lCSUxJVFkgT0YgU1VDSCBEQU1BR0UuXG4gKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCB7IHR5cGUgTnVtYmVyQXJyYXlMaWtlLCBQb29sIH0gZnJvbSBcIi4vVXRpbHMuanNcIjtcblxuZXhwb3J0IGNsYXNzIFRyaWFuZ3VsYXRvciB7XG5cdHByaXZhdGUgY29udmV4UG9seWdvbnMgPSBbXSBhcyBBcnJheTxudW1iZXI+W107XG5cdHByaXZhdGUgY29udmV4UG9seWdvbnNJbmRpY2VzID0gW10gYXMgQXJyYXk8bnVtYmVyPltdO1xuXG5cdHByaXZhdGUgaW5kaWNlc0FycmF5ID0gW10gYXMgbnVtYmVyW107XG5cdHByaXZhdGUgaXNDb25jYXZlQXJyYXkgPSBbXSBhcyBib29sZWFuW107XG5cdHByaXZhdGUgdHJpYW5nbGVzID0gW10gYXMgbnVtYmVyW107XG5cblx0cHJpdmF0ZSBwb2x5Z29uUG9vbCA9IG5ldyBQb29sPEFycmF5PG51bWJlcj4+KCgpID0+IHtcblx0XHRyZXR1cm4gW10gYXMgbnVtYmVyW107XG5cdH0pO1xuXG5cdHByaXZhdGUgcG9seWdvbkluZGljZXNQb29sID0gbmV3IFBvb2w8QXJyYXk8bnVtYmVyPj4oKCkgPT4ge1xuXHRcdHJldHVybiBbXSBhcyBudW1iZXJbXTtcblx0fSk7XG5cblx0cHVibGljIHRyaWFuZ3VsYXRlICh2ZXJ0aWNlc0FycmF5OiBOdW1iZXJBcnJheUxpa2UpOiBBcnJheTxudW1iZXI+IHtcblx0XHRjb25zdCB2ZXJ0aWNlcyA9IHZlcnRpY2VzQXJyYXk7XG5cdFx0bGV0IHZlcnRleENvdW50ID0gdmVydGljZXNBcnJheS5sZW5ndGggPj4gMTtcblxuXHRcdGNvbnN0IGluZGljZXMgPSB0aGlzLmluZGljZXNBcnJheTtcblx0XHRpbmRpY2VzLmxlbmd0aCA9IDA7XG5cdFx0Zm9yIChsZXQgaSA9IDA7IGkgPCB2ZXJ0ZXhDb3VudDsgaSsrKVxuXHRcdFx0aW5kaWNlc1tpXSA9IGk7XG5cblx0XHRjb25zdCBpc0NvbmNhdmUgPSB0aGlzLmlzQ29uY2F2ZUFycmF5O1xuXHRcdGlzQ29uY2F2ZS5sZW5ndGggPSAwO1xuXHRcdGZvciAobGV0IGkgPSAwOyBpIDwgdmVydGV4Q291bnQ7IGkrKylcblx0XHRcdGlzQ29uY2F2ZVtpXSA9IFRyaWFuZ3VsYXRvci5pc0NvbmNhdmUoaSwgdmVydGV4Q291bnQsIHZlcnRpY2VzLCBpbmRpY2VzKTtcblxuXHRcdGNvbnN0IHRyaWFuZ2xlcyA9IHRoaXMudHJpYW5nbGVzO1xuXHRcdHRyaWFuZ2xlcy5sZW5ndGggPSAwO1xuXG5cdFx0d2hpbGUgKHZlcnRleENvdW50ID4gMykge1xuXHRcdFx0Ly8gRmluZCBlYXIgdGlwLlxuXHRcdFx0bGV0IHByZXZpb3VzID0gdmVydGV4Q291bnQgLSAxLCBpID0gMCwgbmV4dCA9IDE7XG5cdFx0XHR3aGlsZSAodHJ1ZSkge1xuXHRcdFx0XHQvLyBiaW9tZS1pZ25vcmUgbGludC9zdXNwaWNpb3VzL25vQ29uZnVzaW5nTGFiZWxzOiByZWZlcmVuY2UgcnVudGltZVxuXHRcdFx0XHRvdXRlcjpcblx0XHRcdFx0aWYgKCFpc0NvbmNhdmVbaV0pIHtcblx0XHRcdFx0XHRjb25zdCBwMSA9IGluZGljZXNbcHJldmlvdXNdIDw8IDEsIHAyID0gaW5kaWNlc1tpXSA8PCAxLCBwMyA9IGluZGljZXNbbmV4dF0gPDwgMTtcblx0XHRcdFx0XHRjb25zdCBwMXggPSB2ZXJ0aWNlc1twMV0sIHAxeSA9IHZlcnRpY2VzW3AxICsgMV07XG5cdFx0XHRcdFx0Y29uc3QgcDJ4ID0gdmVydGljZXNbcDJdLCBwMnkgPSB2ZXJ0aWNlc1twMiArIDFdO1xuXHRcdFx0XHRcdGNvbnN0IHAzeCA9IHZlcnRpY2VzW3AzXSwgcDN5ID0gdmVydGljZXNbcDMgKyAxXTtcblx0XHRcdFx0XHRmb3IgKGxldCBpaSA9IG5leHQgKyAxIDwgdmVydGV4Q291bnQgPyBuZXh0ICsgMSA6IDA7IGlpICE9PSBwcmV2aW91czspIHtcblx0XHRcdFx0XHRcdGlmIChpc0NvbmNhdmVbaWldKSB7XG5cdFx0XHRcdFx0XHRcdGNvbnN0IHYgPSBpbmRpY2VzW2lpXSA8PCAxO1xuXHRcdFx0XHRcdFx0XHRjb25zdCB2eCA9IHZlcnRpY2VzW3ZdLCB2eSA9IHZlcnRpY2VzW3YgKyAxXTtcblx0XHRcdFx0XHRcdFx0aWYgKFRyaWFuZ3VsYXRvci5wb3NpdGl2ZUFyZWEocDN4LCBwM3ksIHAxeCwgcDF5LCB2eCwgdnkpIC8vXG5cdFx0XHRcdFx0XHRcdFx0JiYgVHJpYW5ndWxhdG9yLnBvc2l0aXZlQXJlYShwMXgsIHAxeSwgcDJ4LCBwMnksIHZ4LCB2eSkgLy9cblx0XHRcdFx0XHRcdFx0XHQmJiBUcmlhbmd1bGF0b3IucG9zaXRpdmVBcmVhKHAyeCwgcDJ5LCBwM3gsIHAzeSwgdngsIHZ5KSkgYnJlYWsgb3V0ZXI7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRpZiAoKytpaSA9PT0gdmVydGV4Q291bnQpIGlpID0gMDtcblxuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmIChuZXh0ID09PSAwKSB7XG5cdFx0XHRcdFx0ZG8ge1xuXHRcdFx0XHRcdFx0aWYgKCFpc0NvbmNhdmVbaV0pIGJyZWFrO1xuXHRcdFx0XHRcdFx0aS0tO1xuXHRcdFx0XHRcdH0gd2hpbGUgKGkgPiAwKTtcblx0XHRcdFx0XHRwcmV2aW91cyA9IGkgPiAwID8gaSAtIDEgOiB2ZXJ0ZXhDb3VudCAtIDE7XG5cdFx0XHRcdFx0bmV4dCA9IGkgKyAxIDwgdmVydGV4Q291bnQgPyBpICsgMSA6IDA7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRwcmV2aW91cyA9IGk7XG5cdFx0XHRcdGkgPSBuZXh0O1xuXHRcdFx0XHRpZiAoKytuZXh0ID09PSB2ZXJ0ZXhDb3VudCkgbmV4dCA9IDA7XG5cdFx0XHR9XG5cblx0XHRcdC8vIEN1dCBlYXIgdGlwLlxuXHRcdFx0dHJpYW5nbGVzLnB1c2goaW5kaWNlc1twcmV2aW91c10sIGluZGljZXNbaV0sIGluZGljZXNbbmV4dF0pO1xuXHRcdFx0aW5kaWNlcy5zcGxpY2UoaSwgMSk7XG5cdFx0XHRpc0NvbmNhdmUuc3BsaWNlKGksIDEpO1xuXHRcdFx0dmVydGV4Q291bnQtLTtcblxuXHRcdFx0Y29uc3QgcHJldmlvdXNJbmRleCA9IGkgPiAwID8gaSAtIDEgOiB2ZXJ0ZXhDb3VudCAtIDE7XG5cdFx0XHRjb25zdCBuZXh0SW5kZXggPSBpIDwgdmVydGV4Q291bnQgPyBpIDogMDtcblx0XHRcdGlzQ29uY2F2ZVtwcmV2aW91c0luZGV4XSA9IFRyaWFuZ3VsYXRvci5pc0NvbmNhdmUocHJldmlvdXNJbmRleCwgdmVydGV4Q291bnQsIHZlcnRpY2VzLCBpbmRpY2VzKTtcblx0XHRcdGlzQ29uY2F2ZVtuZXh0SW5kZXhdID0gVHJpYW5ndWxhdG9yLmlzQ29uY2F2ZShuZXh0SW5kZXgsIHZlcnRleENvdW50LCB2ZXJ0aWNlcywgaW5kaWNlcyk7XG5cdFx0fVxuXHRcdGlmICh2ZXJ0ZXhDb3VudCA9PT0gMykgdHJpYW5nbGVzLnB1c2goaW5kaWNlc1syXSwgaW5kaWNlc1swXSwgaW5kaWNlc1sxXSk7XG5cdFx0cmV0dXJuIHRyaWFuZ2xlcztcblx0fVxuXG5cdGRlY29tcG9zZSAodmVydGljZXNBcnJheTogQXJyYXk8bnVtYmVyPiwgdHJpYW5nbGVzOiBBcnJheTxudW1iZXI+KTogQXJyYXk8QXJyYXk8bnVtYmVyPj4ge1xuXHRcdGNvbnN0IHZlcnRpY2VzID0gdmVydGljZXNBcnJheTtcblx0XHRjb25zdCBjb252ZXhQb2x5Z29ucyA9IHRoaXMuY29udmV4UG9seWdvbnM7XG5cdFx0dGhpcy5wb2x5Z29uUG9vbC5mcmVlQWxsKGNvbnZleFBvbHlnb25zKTtcblx0XHRjb252ZXhQb2x5Z29ucy5sZW5ndGggPSAwO1xuXG5cdFx0Y29uc3QgY29udmV4UG9seWdvbnNJbmRpY2VzID0gdGhpcy5jb252ZXhQb2x5Z29uc0luZGljZXM7XG5cdFx0dGhpcy5wb2x5Z29uSW5kaWNlc1Bvb2wuZnJlZUFsbChjb252ZXhQb2x5Z29uc0luZGljZXMpO1xuXHRcdGNvbnZleFBvbHlnb25zSW5kaWNlcy5sZW5ndGggPSAwO1xuXG5cdFx0bGV0IHBvbHlnb25JbmRpY2VzID0gdGhpcy5wb2x5Z29uSW5kaWNlc1Bvb2wub2J0YWluKCk7XG5cdFx0cG9seWdvbkluZGljZXMubGVuZ3RoID0gMDtcblxuXHRcdGxldCBwb2x5Z29uID0gdGhpcy5wb2x5Z29uUG9vbC5vYnRhaW4oKTtcblx0XHRwb2x5Z29uLmxlbmd0aCA9IDA7XG5cblx0XHQvLyBNZXJnZSBzdWJzZXF1ZW50IHRyaWFuZ2xlcyBpZiB0aGV5IGZvcm0gYSB0cmlhbmdsZSBmYW4uXG5cdFx0bGV0IGZhbkJhc2VJbmRleCA9IC0xLCBsYXN0V2luZGluZyA9IDA7XG5cdFx0Zm9yIChsZXQgaSA9IDAsIG4gPSB0cmlhbmdsZXMubGVuZ3RoOyBpIDwgbjsgaSArPSAzKSB7XG5cdFx0XHRjb25zdCB0MSA9IHRyaWFuZ2xlc1tpXSA8PCAxLCB0MiA9IHRyaWFuZ2xlc1tpICsgMV0gPDwgMSwgdDMgPSB0cmlhbmdsZXNbaSArIDJdIDw8IDE7XG5cdFx0XHRjb25zdCB4MSA9IHZlcnRpY2VzW3QxXSwgeTEgPSB2ZXJ0aWNlc1t0MSArIDFdO1xuXHRcdFx0Y29uc3QgeDIgPSB2ZXJ0aWNlc1t0Ml0sIHkyID0gdmVydGljZXNbdDIgKyAxXTtcblx0XHRcdGNvbnN0IHgzID0gdmVydGljZXNbdDNdLCB5MyA9IHZlcnRpY2VzW3QzICsgMV07XG5cblx0XHRcdC8vIElmIHRoZSBiYXNlIG9mIHRoZSBsYXN0IHRyaWFuZ2xlIGlzIHRoZSBzYW1lIGFzIHRoaXMgdHJpYW5nbGUsIGNoZWNrIGlmIHRoZXkgZm9ybSBhIGNvbnZleCBwb2x5Z29uICh0cmlhbmdsZSBmYW4pLlxuXHRcdFx0aWYgKGZhbkJhc2VJbmRleCA9PT0gdDEpIHtcblx0XHRcdFx0Y29uc3QgbyA9IHBvbHlnb24ubGVuZ3RoIC0gNDtcblx0XHRcdFx0aWYgKFRyaWFuZ3VsYXRvci53aW5kaW5nKHBvbHlnb25bb10sIHBvbHlnb25bbyArIDFdLCBwb2x5Z29uW28gKyAyXSwgcG9seWdvbltvICsgM10sIHgzLCB5MykgPT09IGxhc3RXaW5kaW5nXG5cdFx0XHRcdFx0JiYgVHJpYW5ndWxhdG9yLndpbmRpbmcoeDMsIHkzLCBwb2x5Z29uWzBdLCBwb2x5Z29uWzFdLCBwb2x5Z29uWzJdLCBwb2x5Z29uWzNdKSA9PT0gbGFzdFdpbmRpbmcpIHtcblx0XHRcdFx0XHRwb2x5Z29uLnB1c2goeDMsIHkzKTtcblx0XHRcdFx0XHRwb2x5Z29uSW5kaWNlcy5wdXNoKHQzKTtcblx0XHRcdFx0XHRjb250aW51ZTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHQvLyBPdGhlcndpc2UgbWFrZSB0aGlzIHRyaWFuZ2xlIHRoZSBuZXcgYmFzZS5cblx0XHRcdGlmIChwb2x5Z29uLmxlbmd0aCA+IDApIHtcblx0XHRcdFx0Y29udmV4UG9seWdvbnMucHVzaChwb2x5Z29uKTtcblx0XHRcdFx0Y29udmV4UG9seWdvbnNJbmRpY2VzLnB1c2gocG9seWdvbkluZGljZXMpO1xuXHRcdFx0XHRwb2x5Z29uID0gdGhpcy5wb2x5Z29uUG9vbC5vYnRhaW4oKTtcblx0XHRcdFx0cG9seWdvbkluZGljZXMgPSB0aGlzLnBvbHlnb25JbmRpY2VzUG9vbC5vYnRhaW4oKTtcblx0XHRcdH1cblx0XHRcdHBvbHlnb24ubGVuZ3RoID0gMDtcblx0XHRcdHBvbHlnb24ucHVzaCh4MSwgeTEsIHgyLCB5Mik7XG5cdFx0XHRwb2x5Z29uLnB1c2goeDMsIHkzKTtcblx0XHRcdHBvbHlnb25JbmRpY2VzLmxlbmd0aCA9IDA7XG5cdFx0XHRwb2x5Z29uSW5kaWNlcy5wdXNoKHQxLCB0MiwgdDMpO1xuXHRcdFx0bGFzdFdpbmRpbmcgPSBUcmlhbmd1bGF0b3Iud2luZGluZyh4MSwgeTEsIHgyLCB5MiwgeDMsIHkzKTtcblx0XHRcdGZhbkJhc2VJbmRleCA9IHQxO1xuXHRcdH1cblxuXHRcdGlmIChwb2x5Z29uLmxlbmd0aCA+IDApIHtcblx0XHRcdGNvbnZleFBvbHlnb25zLnB1c2gocG9seWdvbik7XG5cdFx0XHRjb252ZXhQb2x5Z29uc0luZGljZXMucHVzaChwb2x5Z29uSW5kaWNlcyk7XG5cdFx0fVxuXG5cdFx0Ly8gTWVyZ2UgcmVtYWluaW5nIHRyaWFuZ2xlcyB3aXRoIHRoZSBmb3VuZCB0cmlhbmdsZSBmYW5zLlxuXHRcdGZvciAobGV0IGkgPSAwLCBuID0gY29udmV4UG9seWdvbnMubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XG5cdFx0XHRwb2x5Z29uSW5kaWNlcyA9IGNvbnZleFBvbHlnb25zSW5kaWNlc1tpXTtcblx0XHRcdGlmIChwb2x5Z29uSW5kaWNlcy5sZW5ndGggPT09IDApIGNvbnRpbnVlO1xuXHRcdFx0Y29uc3QgZmlyc3RJbmRleCA9IHBvbHlnb25JbmRpY2VzWzBdO1xuXHRcdFx0bGV0IGxhc3RJbmRleCA9IHBvbHlnb25JbmRpY2VzW3BvbHlnb25JbmRpY2VzLmxlbmd0aCAtIDFdO1xuXG5cdFx0XHRwb2x5Z29uID0gY29udmV4UG9seWdvbnNbaV07XG5cdFx0XHRjb25zdCBvID0gcG9seWdvbi5sZW5ndGggLSA0O1xuXHRcdFx0bGV0IHByZXZQcmV2WCA9IHBvbHlnb25bb10sIHByZXZQcmV2WSA9IHBvbHlnb25bbyArIDFdO1xuXHRcdFx0bGV0IHByZXZYID0gcG9seWdvbltvICsgMl0sIHByZXZZID0gcG9seWdvbltvICsgM107XG5cdFx0XHRjb25zdCBmaXJzdFggPSBwb2x5Z29uWzBdLCBmaXJzdFkgPSBwb2x5Z29uWzFdO1xuXHRcdFx0Y29uc3Qgc2Vjb25kWCA9IHBvbHlnb25bMl0sIHNlY29uZFkgPSBwb2x5Z29uWzNdO1xuXHRcdFx0Y29uc3Qgd2luZGluZyA9IFRyaWFuZ3VsYXRvci53aW5kaW5nKHByZXZQcmV2WCwgcHJldlByZXZZLCBwcmV2WCwgcHJldlksIGZpcnN0WCwgZmlyc3RZKTtcblxuXHRcdFx0Zm9yIChsZXQgaWkgPSAwOyBpaSA8IG47IGlpKyspIHtcblx0XHRcdFx0aWYgKGlpID09PSBpKSBjb250aW51ZTtcblx0XHRcdFx0Y29uc3Qgb3RoZXJJbmRpY2VzID0gY29udmV4UG9seWdvbnNJbmRpY2VzW2lpXTtcblx0XHRcdFx0aWYgKG90aGVySW5kaWNlcy5sZW5ndGggIT09IDMpIGNvbnRpbnVlO1xuXHRcdFx0XHRjb25zdCBvdGhlckZpcnN0SW5kZXggPSBvdGhlckluZGljZXNbMF07XG5cdFx0XHRcdGNvbnN0IG90aGVyU2Vjb25kSW5kZXggPSBvdGhlckluZGljZXNbMV07XG5cdFx0XHRcdGNvbnN0IG90aGVyTGFzdEluZGV4ID0gb3RoZXJJbmRpY2VzWzJdO1xuXG5cdFx0XHRcdGNvbnN0IG90aGVyUG9seSA9IGNvbnZleFBvbHlnb25zW2lpXTtcblx0XHRcdFx0Y29uc3QgeDMgPSBvdGhlclBvbHlbb3RoZXJQb2x5Lmxlbmd0aCAtIDJdLCB5MyA9IG90aGVyUG9seVtvdGhlclBvbHkubGVuZ3RoIC0gMV07XG5cblx0XHRcdFx0aWYgKG90aGVyRmlyc3RJbmRleCAhPT0gZmlyc3RJbmRleCB8fCBvdGhlclNlY29uZEluZGV4ICE9PSBsYXN0SW5kZXgpIGNvbnRpbnVlO1xuXHRcdFx0XHRpZiAoVHJpYW5ndWxhdG9yLndpbmRpbmcocHJldlByZXZYLCBwcmV2UHJldlksIHByZXZYLCBwcmV2WSwgeDMsIHkzKSA9PT0gd2luZGluZ1xuXHRcdFx0XHRcdCYmIFRyaWFuZ3VsYXRvci53aW5kaW5nKHgzLCB5MywgZmlyc3RYLCBmaXJzdFksIHNlY29uZFgsIHNlY29uZFkpID09PSB3aW5kaW5nKSB7XG5cdFx0XHRcdFx0b3RoZXJQb2x5Lmxlbmd0aCA9IDA7XG5cdFx0XHRcdFx0b3RoZXJJbmRpY2VzLmxlbmd0aCA9IDA7XG5cdFx0XHRcdFx0cG9seWdvbi5wdXNoKHgzLCB5Myk7XG5cdFx0XHRcdFx0cG9seWdvbkluZGljZXMucHVzaChvdGhlckxhc3RJbmRleCk7XG5cdFx0XHRcdFx0bGFzdEluZGV4ID0gb3RoZXJMYXN0SW5kZXg7XG5cdFx0XHRcdFx0cHJldlByZXZYID0gcHJldlg7XG5cdFx0XHRcdFx0cHJldlByZXZZID0gcHJldlk7XG5cdFx0XHRcdFx0cHJldlggPSB4Mztcblx0XHRcdFx0XHRwcmV2WSA9IHkzO1xuXHRcdFx0XHRcdGlpID0gLTE7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBSZW1vdmUgZW1wdHkgcG9seWdvbnMgZnJvbSB0aGUgbWVyZ2Ugc3RlcCBhYm92ZS5cblx0XHRmb3IgKGxldCBpID0gY29udmV4UG9seWdvbnMubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pIHtcblx0XHRcdHBvbHlnb24gPSBjb252ZXhQb2x5Z29uc1tpXTtcblx0XHRcdGlmIChwb2x5Z29uLmxlbmd0aCA9PT0gMCkge1xuXHRcdFx0XHRjb252ZXhQb2x5Z29ucy5zcGxpY2UoaSwgMSk7XG5cdFx0XHRcdHRoaXMucG9seWdvblBvb2wuZnJlZShwb2x5Z29uKTtcblx0XHRcdFx0cG9seWdvbkluZGljZXMgPSBjb252ZXhQb2x5Z29uc0luZGljZXNbaV1cblx0XHRcdFx0Y29udmV4UG9seWdvbnNJbmRpY2VzLnNwbGljZShpLCAxKVxuXHRcdFx0XHR0aGlzLnBvbHlnb25JbmRpY2VzUG9vbC5mcmVlKHBvbHlnb25JbmRpY2VzKTtcblx0XHRcdH0gZWxzZVxuXHRcdFx0XHRwb2x5Z29uLnB1c2gocG9seWdvblswXSwgcG9seWdvblsxXSk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGNvbnZleFBvbHlnb25zO1xuXHR9XG5cblx0cHJpdmF0ZSBzdGF0aWMgaXNDb25jYXZlIChpbmRleDogbnVtYmVyLCB2ZXJ0ZXhDb3VudDogbnVtYmVyLCB2ZXJ0aWNlczogTnVtYmVyQXJyYXlMaWtlLCBpbmRpY2VzOiBOdW1iZXJBcnJheUxpa2UpOiBib29sZWFuIHtcblx0XHRjb25zdCBwcmV2aW91cyA9IGluZGljZXNbaW5kZXggPiAwID8gaW5kZXggLSAxIDogdmVydGV4Q291bnQgLSAxXSA8PCAxO1xuXHRcdGNvbnN0IGN1cnJlbnQgPSBpbmRpY2VzW2luZGV4XSA8PCAxO1xuXHRcdGNvbnN0IG5leHQgPSBpbmRpY2VzW2luZGV4ICsgMSA8IHZlcnRleENvdW50ID8gaW5kZXggKyAxIDogMF0gPDwgMTtcblx0XHRyZXR1cm4gIVRyaWFuZ3VsYXRvci5wb3NpdGl2ZUFyZWEodmVydGljZXNbcHJldmlvdXNdLCB2ZXJ0aWNlc1twcmV2aW91cyArIDFdLCB2ZXJ0aWNlc1tjdXJyZW50XSwgdmVydGljZXNbY3VycmVudCArIDFdLCB2ZXJ0aWNlc1tuZXh0XSxcblx0XHRcdHZlcnRpY2VzW25leHQgKyAxXSk7XG5cdH1cblxuXHRwcml2YXRlIHN0YXRpYyBwb3NpdGl2ZUFyZWEgKHAxeDogbnVtYmVyLCBwMXk6IG51bWJlciwgcDJ4OiBudW1iZXIsIHAyeTogbnVtYmVyLCBwM3g6IG51bWJlciwgcDN5OiBudW1iZXIpOiBib29sZWFuIHtcblx0XHRyZXR1cm4gcDF4ICogKHAzeSAtIHAyeSkgKyBwMnggKiAocDF5IC0gcDN5KSArIHAzeCAqIChwMnkgLSBwMXkpID49IDA7XG5cdH1cblxuXHRwcml2YXRlIHN0YXRpYyB3aW5kaW5nIChwMXg6IG51bWJlciwgcDF5OiBudW1iZXIsIHAyeDogbnVtYmVyLCBwMnk6IG51bWJlciwgcDN4OiBudW1iZXIsIHAzeTogbnVtYmVyKTogbnVtYmVyIHtcblx0XHRyZXR1cm4gcDF4ICogKHAzeSAtIHAyeSkgKyBwMnggKiAocDF5IC0gcDN5KSArIHAzeCAqIChwMnkgLSBwMXkpID49IDAgPyAxIDogLTE7XG5cdH1cbn1cbiJdfQ==