@foblex/2d
Version:
An Angular library for 2D geometric computations, providing classes and utilities for manipulating points, lines, vectors, rectangles, arcs, and transformations.
180 lines • 26.7 kB
JavaScript
import { PointExtensions } from './point';
import { Arc } from './arc';
import { Line } from './line';
import { ShapeParser } from './shape-parser';
import { VectorExtensions } from './vector';
/**
* The GetIntersections class is designed to find intersection points between
* line segments and various geometric shapes. Currently, it supports rectangles,
* circles, and ellipses. In the future, support for additional shapes will be added.
*/
export class GetIntersections {
/**
* Finds the guaranteed intersection points between a line segment and a rounded rectangle.
* @param from - Starting point of the line segment.
* @param to - Ending point of the line segment.
* @param rect - The rect to check for intersections.
* @returns An array of intersection points.
*/
static getRoundedRectIntersections(from, to, rect) {
const segments = ShapeParser.parseRoundedRect(rect);
for (const segment of segments) {
if (segment instanceof Arc) {
const intersections = this.intersectArcWithLine(segment, from, to);
if (intersections.length > 0) {
return intersections;
}
}
else if (segment instanceof Line) {
const intersection = this.intersectLineSegments(from, to, segment.point1, segment.point2);
if (intersection) {
return [intersection];
}
}
}
return [];
}
/**
* Finds the intersection points between a line segment and an SVG path.
* @param path - The SVG path to check for intersections.
* @param rect - The rect to check for intersections.
* @returns An array of intersection points.
*/
static getRoundedRectIntersectionsWithSVGPath(path, rect) {
const pathLength = path.getTotalLength();
const points = [];
for (let i = 0; i <= pathLength; i += 1) {
const point = path.getPointAtLength(i);
points.push({ x: point.x, y: point.y });
}
for (let i = 1; i < points.length; i++) {
const intersections = this.getRoundedRectIntersections(points[i - 1], points[i], rect);
if (intersections.length > 0) {
return intersections;
}
}
return [];
}
/**
* Finds the intersection points between an arc and a line segment.
* @param arc - The arc to check for intersections.
* @param from - Starting point of the line segment.
* @param to - Ending point of the line segment.
* @returns An array of intersection points.
*/
static intersectArcWithLine(arc, from, to) {
return this.filterPointsWithinArc(this.findEllipseLineIntersections(arc.center, arc.radiusX, arc.radiusY, from, to), arc);
}
/**
* Finds the intersection point between two line segments.
* @param p1 - Starting point of the first line segment.
* @param p2 - Ending point of the first line segment.
* @param p3 - Starting point of the second line segment.
* @param p4 - Ending point of the second line segment.
* @returns The intersection point or null if there is no intersection.
*/
static intersectLineSegments(p1, p2, p3, p4) {
const s1_x = p2.x - p1.x;
const s1_y = p2.y - p1.y;
const s2_x = p4.x - p3.x;
const s2_y = p4.y - p3.y;
const s = (-s1_y * (p1.x - p3.x) + s1_x * (p1.y - p3.y)) / (-s2_x * s1_y + s1_x * s2_y);
const t = (s2_x * (p1.y - p3.y) - s2_y * (p1.x - p3.x)) / (-s2_x * s1_y + s1_x * s2_y);
if (s >= 0 && s <= 1 && t >= 0 && t <= 1) {
return { x: p1.x + (t * s1_x), y: p1.y + (t * s1_y) };
}
return null;
}
/**
* Filters intersection points to retain only those within the given arc.
* @param points - The points to filter.
* @param arc - The arc to check against.
* @returns An array of points within the arc.
*/
static filterPointsWithinArc(points, arc) {
let { center, startAngle, endAngle } = arc;
if (points.length === 0) {
return points;
}
if (endAngle < startAngle) {
[startAngle, endAngle] = [endAngle, startAngle];
}
if (startAngle < 0 || endAngle < 0) {
startAngle += 2.0 * Math.PI;
endAngle += 2.0 * Math.PI;
}
const filteredPoints = [];
for (const point of points) {
let angle = this.normalizeAngle(VectorExtensions.angle(VectorExtensions.initialize(1, 0), VectorExtensions.initialize(point.x - center.x, point.y - center.y)));
if (angle < startAngle) {
angle += 2.0 * Math.PI;
}
if (startAngle <= angle && angle <= endAngle) {
filteredPoints.push(point);
}
}
return filteredPoints;
}
/**
* Normalizes an angle to be within the range 0 to 2π.
* @param radians - The angle in radians.
* @returns The normalized angle.
*/
static normalizeAngle(radians) {
const normal = radians % (2.0 * Math.PI);
return normal < 0.0 ? (normal + (2.0 * Math.PI)) : normal;
}
/**
* Finds the intersection points between an ellipse and a line segment.
* @param center - Center of the ellipse.
* @param radiusX - X radius of the ellipse.
* @param radiusY - Y radius of the ellipse.
* @param pointA - Starting point of the line segment.
* @param pointB - Ending point of the line segment.
* @returns An array of intersection points.
*/
static findEllipseLineIntersections(center, radiusX, radiusY, pointA, pointB) {
const origin = VectorExtensions.initialize(pointA.x, pointA.y);
const direction = VectorExtensions.fromPoints(pointA, pointB);
const ellipseCenter = VectorExtensions.initialize(center.x, center.y);
const diff = VectorExtensions.subtract(origin, ellipseCenter);
const scaledDir = VectorExtensions.initialize(direction.x / (radiusX * radiusX), direction.y / (radiusY * radiusY));
const scaledDiff = VectorExtensions.initialize(diff.x / (radiusX * radiusX), diff.y / (radiusY * radiusY));
const a = VectorExtensions.dotProduct(direction, scaledDir);
const b = VectorExtensions.dotProduct(direction, scaledDiff);
const c = VectorExtensions.dotProduct(diff, scaledDiff) - 1.0;
const discriminant = b * b - a * c;
return discriminant < 0 ? [] : this.calculateIntersectionPoints(discriminant, a, b, pointA, pointB);
}
/**
* Calculates the intersection points based on the discriminant.
* @param discriminant - The discriminant value.
* @param a - Coefficient 'a' in the quadratic equation.
* @param b - Coefficient 'b' in the quadratic equation.
* @param pointA - Starting point of the line segment.
* @param pointB - Ending point of the line segment.
* @returns An array of intersection points.
*/
static calculateIntersectionPoints(discriminant, a, b, pointA, pointB) {
const points = [];
if (discriminant > 0) {
const root = Math.sqrt(discriminant);
const t1 = (-b - root) / a;
const t2 = (-b + root) / a;
if (t1 >= 0 && t1 <= 1) {
points.push(PointExtensions.interpolatePoints(pointA, pointB, t1));
}
if (t2 >= 0 && t2 <= 1) {
points.push(PointExtensions.interpolatePoints(pointA, pointB, t2));
}
}
else {
const t = -b / a;
if (t >= 0 && t <= 1) {
points.push(PointExtensions.interpolatePoints(pointA, pointB, t));
}
}
return points;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2V0LWludGVyc2VjdGlvbnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9wcm9qZWN0cy9mb2JsZXgyZC9zcmMvZ2V0LWludGVyc2VjdGlvbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFVLGVBQWUsRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUVsRCxPQUFPLEVBQUUsR0FBRyxFQUFRLE1BQU0sT0FBTyxDQUFDO0FBQ2xDLE9BQU8sRUFBUyxJQUFJLEVBQUUsTUFBTSxRQUFRLENBQUM7QUFDckMsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzdDLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUc1Qzs7OztHQUlHO0FBQ0gsTUFBTSxPQUFPLGdCQUFnQjtJQUUzQjs7Ozs7O09BTUc7SUFDSSxNQUFNLENBQUMsMkJBQTJCLENBQUMsSUFBWSxFQUFFLEVBQVUsRUFBRSxJQUFrQjtRQUNwRixNQUFNLFFBQVEsR0FBbUIsV0FBVyxDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxDQUFDO1FBRXBFLEtBQUssTUFBTSxPQUFPLElBQUksUUFBUSxFQUFFO1lBQzlCLElBQUksT0FBTyxZQUFZLEdBQUcsRUFBRTtnQkFDMUIsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLG9CQUFvQixDQUFDLE9BQU8sRUFBRSxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUM7Z0JBQ25FLElBQUksYUFBYSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUU7b0JBQzVCLE9BQU8sYUFBYSxDQUFDO2lCQUN0QjthQUNGO2lCQUFNLElBQUksT0FBTyxZQUFZLElBQUksRUFBRTtnQkFDbEMsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLHFCQUFxQixDQUFDLElBQUksRUFBRSxFQUFFLEVBQUUsT0FBTyxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUM7Z0JBQzFGLElBQUksWUFBWSxF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LElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQztZQUNyQyxNQUFNLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUMzQixNQUFNLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUUzQixJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsRUFBRTtnQkFDdEIsTUFBTSxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsaUJBQWlCLENBQUMsTUFBTSxFQUFFLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO2FBQ3BFO1lBQ0QsSUFBSSxFQUFFLElBQUksQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLEVBQUU7Z0JBQ3RCLE1BQU0sQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLGlCQUFpQixDQUFDLE1BQU0sRUFBRSxNQUFNLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQzthQUNwRTtTQUNGO2FBQU07WUFDTCxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDakIsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUU7Z0JBQ3BCLE1BQU0sQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLGlCQUFpQixDQUFDLE1BQU0sRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQzthQUNuRTtTQUNGO1FBRUQsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSVBvaW50LCBQb2ludEV4dGVuc2lvbnMgfSBmcm9tICcuL3BvaW50JztcbmltcG9ydCB7IElSb3VuZGVkUmVjdCB9IGZyb20gJy4vcm91bmRlZC1yZWN0JztcbmltcG9ydCB7IEFyYywgSUFyYyB9IGZyb20gJy4vYXJjJztcbmltcG9ydCB7IElMaW5lLCBMaW5lIH0gZnJvbSAnLi9saW5lJztcbmltcG9ydCB7IFNoYXBlUGFyc2VyIH0gZnJvbSAnLi9zaGFwZS1wYXJzZXInO1xuaW1wb3J0IHsgVmVjdG9yRXh0ZW5zaW9ucyB9IGZyb20gJy4vdmVjdG9yJztcblxuXG4vKipcbiAqIFRoZSBHZXRJbnRlcnNlY3Rpb25zIGNsYXNzIGlzIGRlc2lnbmVkIHRvIGZpbmQgaW50ZXJzZWN0aW9uIHBvaW50cyBiZXR3ZWVuXG4gKiBsaW5lIHNlZ21lbnRzIGFuZCB2YXJpb3VzIGdlb21ldHJpYyBzaGFwZXMuIEN1cnJlbnRseSwgaXQgc3VwcG9ydHMgcmVjdGFuZ2xlcyxcbiAqIGNpcmNsZXMsIGFuZCBlbGxpcHNlcy4gSW4gdGhlIGZ1dHVyZSwgc3VwcG9ydCBmb3IgYWRkaXRpb25hbCBzaGFwZXMgd2lsbCBiZSBhZGRlZC5cbiAqL1xuZXhwb3J0IGNsYXNzIEdldEludGVyc2VjdGlvbnMge1xuXG4gIC8qKlxuICAgKiBGaW5kcyB0aGUgZ3VhcmFudGVlZCBpbnRlcnNlY3Rpb24gcG9pbnRzIGJldHdlZW4gYSBsaW5lIHNlZ21lbnQgYW5kIGEgcm91bmRlZCByZWN0YW5nbGUuXG4gICAqIEBwYXJhbSBmcm9tIC0gU3RhcnRpbmcgcG9pbnQgb2YgdGhlIGxpbmUgc2VnbWVudC5cbiAgICogQHBhcmFtIHRvIC0gRW5kaW5nIHBvaW50IG9mIHRoZSBsaW5lIHNlZ21lbnQuXG4gICAqIEBwYXJhbSByZWN0IC0gVGhlIHJlY3QgdG8gY2hlY2sgZm9yIGludGVyc2VjdGlvbnMuXG4gICAqIEByZXR1cm5zIEFuIGFycmF5IG9mIGludGVyc2VjdGlvbiBwb2ludHMuXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGdldFJvdW5kZWRSZWN0SW50ZXJzZWN0aW9ucyhmcm9tOiBJUG9pbnQsIHRvOiBJUG9pbnQsIHJlY3Q6IElSb3VuZGVkUmVjdCk6IElQb2ludFtdIHtcbiAgICBjb25zdCBzZWdtZW50czogKEFyYyB8IExpbmUpW10gPSBTaGFwZVBhcnNlci5wYXJzZVJvdW5kZWRSZWN0KHJlY3QpO1xuXG4gICAgZm9yIChjb25zdCBzZWdtZW50IG9mIHNlZ21lbnRzKSB7XG4gICAgICBpZiAoc2VnbWVudCBpbnN0YW5jZW9mIEFyYykge1xuICAgICAgICBjb25zdCBpbnRlcnNlY3Rpb25zID0gdGhpcy5pbnRlcnNlY3RBcmNXaXRoTGluZShzZWdtZW50LCBmcm9tLCB0byk7XG4gICAgICAgIGlmIChpbnRlcnNlY3Rpb25zLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICByZXR1cm4gaW50ZXJzZWN0aW9ucztcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmIChzZWdtZW50IGluc3RhbmNlb2YgTGluZSkge1xuICAgICAgICBjb25zdCBpbnRlcnNlY3Rpb24gPSB0aGlzLmludGVyc2VjdExpbmVTZWdtZW50cyhmcm9tLCB0bywgc2VnbWVudC5wb2ludDEsIHNlZ21lbnQucG9pbnQyKTtcbiAgICAgICAgaWYgKGludGVyc2VjdGlvbikge1xuICAgICAgICAgIHJldHVybiBbIGludGVyc2VjdGlvbiBdO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIFtdO1xuICB9XG5cbiAgLyoqXG4gICAqIEZpbmRzIHRoZSBpbnRlcnNlY3Rpb24gcG9pbnRzIGJldHdlZW4gYSBsaW5lIHNlZ21lbnQgYW5kIGFuIFNWRyBwYXRoLlxuICAgKiBAcGFyYW0gcGF0aCAtIFRoZSBTVkcgcGF0aCB0byBjaGVjayBmb3IgaW50ZXJzZWN0aW9ucy5cbiAgICogQHBhcmFtIHJlY3QgLSBUaGUgcmVjdCB0byBjaGVjayBmb3IgaW50ZXJzZWN0aW9ucy5cbiAgICogQHJldHVybnMgQW4gYXJyYXkgb2YgaW50ZXJzZWN0aW9uIHBvaW50cy5cbiAgICovXG5cbiAgcHVibGljIHN0YXRpYyBnZXRSb3VuZGVkUmVjdEludGVyc2VjdGlvbnNXaXRoU1ZHUGF0aChwYXRoOiBTVkdQYXRoRWxlbWVudCwgcmVjdDogSVJvdW5kZWRSZWN0KTogSVBvaW50W10ge1xuICAgIGNvbnN0IHBhdGhMZW5ndGggPSBwYXRoLmdldFRvdGFsTGVuZ3RoKCk7XG4gICAgY29uc3QgcG9pbnRzID0gW107XG5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8PSBwYXRoTGVuZ3RoOyBpICs9IDEpIHtcbiAgICAgIGNvbnN0IHBvaW50ID0gcGF0aC5nZXRQb2ludEF0TGVuZ3RoKGkpO1xuICAgICAgcG9pbnRzLnB1c2goeyB4OiBwb2ludC54LCB5OiBwb2ludC55IH0pO1xuICAgIH1cblxuICAgIGZvciAobGV0IGkgPSAxOyBpIDwgcG9pbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBpbnRlcnNlY3Rpb25zID0gdGhpcy5nZXRSb3VuZGVkUmVjdEludGVyc2VjdGlvbnMocG9pbnRzW2kgLSAxXSwgcG9pbnRzW2ldLCByZWN0KTtcbiAgICAgIGlmIChpbnRlcnNlY3Rpb25zLmxlbmd0aCA+IDApIHtcbiAgICAgICAgcmV0dXJuIGludGVyc2VjdGlvbnM7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBbXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGaW5kcyB0aGUgaW50ZXJzZWN0aW9uIHBvaW50cyBiZXR3ZWVuIGFuIGFyYyBhbmQgYSBsaW5lIHNlZ21lbnQuXG4gICAqIEBwYXJhbSBhcmMgLSBUaGUgYXJjIHRvIGNoZWNrIGZvciBpbnRlcnNlY3Rpb25zLlxuICAgKiBAcGFyYW0gZnJvbSAtIFN0YXJ0aW5nIHBvaW50IG9mIHRoZSBsaW5lIHNlZ21lbnQuXG4gICAqIEBwYXJhbSB0byAtIEVuZGluZyBwb2ludCBvZiB0aGUgbGluZSBzZWdtZW50LlxuICAgKiBAcmV0dXJucyBBbiBhcnJheSBvZiBpbnRlcnNlY3Rpb24gcG9pbnRzLlxuICAgKi9cbiAgcHJpdmF0ZSBzdGF0aWMgaW50ZXJzZWN0QXJjV2l0aExpbmUoYXJjOiBJQXJjLCBmcm9tOiBJUG9pbnQsIHRvOiBJUG9pbnQpOiBJUG9pbnRbXSB7XG4gICAgcmV0dXJuIHRoaXMuZmlsdGVyUG9pbnRzV2l0aGluQXJjKFxuICAgICAgdGhpcy5maW5kRWxsaXBzZUxpbmVJbnRlcnNlY3Rpb25zKGFyYy5jZW50ZXIsIGFyYy5yYWRpdXNYLCBhcmMucmFkaXVzWSwgZnJvbSwgdG8pLFxuICAgICAgYXJjXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGaW5kcyB0aGUgaW50ZXJzZWN0aW9uIHBvaW50IGJldHdlZW4gdHdvIGxpbmUgc2VnbWVudHMuXG4gICAqIEBwYXJhbSBwMSAtIFN0YXJ0aW5nIHBvaW50IG9mIHRoZSBmaXJzdCBsaW5lIHNlZ21lbnQuXG4gICAqIEBwYXJhbSBwMiAtIEVuZGluZyBwb2ludCBvZiB0aGUgZmlyc3QgbGluZSBzZWdtZW50LlxuICAgKiBAcGFyYW0gcDMgLSBTdGFydGluZyBwb2ludCBvZiB0aGUgc2Vjb25kIGxpbmUgc2VnbWVudC5cbiAgICogQHBhcmFtIHA0IC0gRW5kaW5nIHBvaW50IG9mIHRoZSBzZWNvbmQgbGluZSBzZWdtZW50LlxuICAgKiBAcmV0dXJucyBUaGUgaW50ZXJzZWN0aW9uIHBvaW50IG9yIG51bGwgaWYgdGhlcmUgaXMgbm8gaW50ZXJzZWN0aW9uLlxuICAgKi9cbiAgcHJpdmF0ZSBzdGF0aWMgaW50ZXJzZWN0TGluZVNlZ21lbnRzKHAxOiBJUG9pbnQsIHAyOiBJUG9pbnQsIHAzOiBJUG9pbnQsIHA0OiBJUG9pbnQpOiBJUG9pbnQgfCBudWxsIHtcbiAgICBjb25zdCBzMV94ID0gcDIueCAtIHAxLng7XG4gICAgY29uc3QgczFfeSA9IHAyLnkgLSBwMS55O1xuICAgIGNvbnN0IHMyX3ggPSBwNC54IC0gcDMueDtcbiAgICBjb25zdCBzMl95ID0gcDQueSAtIHAzLnk7XG5cbiAgICBjb25zdCBzID0gKC1zMV95ICogKHAxLnggLSBwMy54KSArIHMxX3ggKiAocDEueSAtIHAzLnkpKSAvICgtczJfeCAqIHMxX3kgKyBzMV94ICogczJfeSk7XG4gICAgY29uc3QgdCA9IChzMl94ICogKHAxLnkgLSBwMy55KSAtIHMyX3kgKiAocDEueCAtIHAzLngpKSAvICgtczJfeCAqIHMxX3kgKyBzMV94ICogczJfeSk7XG5cbiAgICBpZiAocyA+PSAwICYmIHMgPD0gMSAmJiB0ID49IDAgJiYgdCA8PSAxKSB7XG4gICAgICByZXR1cm4geyB4OiBwMS54ICsgKHQgKiBzMV94KSwgeTogcDEueSArICh0ICogczFfeSkgfTtcbiAgICB9XG5cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBGaWx0ZXJzIGludGVyc2VjdGlvbiBwb2ludHMgdG8gcmV0YWluIG9ubHkgdGhvc2Ugd2l0aGluIHRoZSBnaXZlbiBhcmMuXG4gICAqIEBwYXJhbSBwb2ludHMgLSBUaGUgcG9pbnRzIHRvIGZpbHRlci5cbiAgICogQHBhcmFtIGFyYyAtIFRoZSBhcmMgdG8gY2hlY2sgYWdhaW5zdC5cbiAgICogQHJldHVybnMgQW4gYXJyYXkgb2YgcG9pbnRzIHdpdGhpbiB0aGUgYXJjLlxuICAgKi9cbiAgcHJpdmF0ZSBzdGF0aWMgZmlsdGVyUG9pbnRzV2l0aGluQXJjKHBvaW50czogSVBvaW50W10sIGFyYzogSUFyYyk6IElQb2ludFtdIHtcbiAgICBsZXQgeyBjZW50ZXIsIHN0YXJ0QW5nbGUsIGVuZEFuZ2xlIH0gPSBhcmM7XG5cbiAgICBpZiAocG9pbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuIHBvaW50cztcbiAgICB9XG5cbiAgICBpZiAoZW5kQW5nbGUgPCBzdGFydEFuZ2xlKSB7XG4gICAgICBbIHN0YXJ0QW5nbGUsIGVuZEFuZ2xlIF0gPSBbIGVuZEFuZ2xlLCBzdGFydEFuZ2xlIF07XG4gICAgfVxuXG4gICAgaWYgKHN0YXJ0QW5nbGUgPCAwIHx8IGVuZEFuZ2xlIDwgMCkge1xuICAgICAgc3RhcnRBbmdsZSArPSAyLjAgKiBNYXRoLlBJO1xuICAgICAgZW5kQW5nbGUgKz0gMi4wICogTWF0aC5QSTtcbiAgICB9XG5cbiAgICBjb25zdCBmaWx0ZXJlZFBvaW50czogSVBvaW50W10gPSBbXTtcblxuICAgIGZvciAoY29uc3QgcG9pbnQgb2YgcG9pbnRzKSB7XG4gICAgICBsZXQgYW5nbGUgPSB0aGlzLm5vcm1hbGl6ZUFuZ2xlKFxuICAgICAgICBWZWN0b3JFeHRlbnNpb25zLmFuZ2xlKFxuICAgICAgICAgIFZlY3RvckV4dGVuc2lvbnMuaW5pdGlhbGl6ZSgxLCAwKSxcbiAgICAgICAgICBWZWN0b3JFeHRlbnNpb25zLmluaXRpYWxpemUocG9pbnQueCAtIGNlbnRlci54LCBwb2ludC55IC0gY2VudGVyLnkpXG4gICAgICAgIClcbiAgICAgICk7XG5cbiAgICAgIGlmIChhbmdsZSA8IHN0YXJ0QW5nbGUpIHtcbiAgICAgICAgYW5nbGUgKz0gMi4wICogTWF0aC5QSTtcbiAgICAgIH1cblxuICAgICAgaWYgKHN0YXJ0QW5nbGUgPD0gYW5nbGUgJiYgYW5nbGUgPD0gZW5kQW5nbGUpIHtcbiAgICAgICAgZmlsdGVyZWRQb2ludHMucHVzaChwb2ludCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGZpbHRlcmVkUG9pbnRzO1xuICB9XG5cbiAgLyoqXG4gICAqIE5vcm1hbGl6ZXMgYW4gYW5nbGUgdG8gYmUgd2l0aGluIHRoZSByYW5nZSAwIHRvIDLPgC5cbiAgICogQHBhcmFtIHJhZGlhbnMgLSBUaGUgYW5nbGUgaW4gcmFkaWFucy5cbiAgICogQHJldHVybnMgVGhlIG5vcm1hbGl6ZWQgYW5nbGUuXG4gICAqL1xuICBwcml2YXRlIHN0YXRpYyBub3JtYWxpemVBbmdsZShyYWRpYW5zOiBudW1iZXIpOiBudW1iZXIge1xuICAgIGNvbnN0IG5vcm1hbCA9IHJhZGlhbnMgJSAoMi4wICogTWF0aC5QSSk7XG4gICAgcmV0dXJuIG5vcm1hbCA8IDAuMCA/IChub3JtYWwgKyAoMi4wICogTWF0aC5QSSkpIDogbm9ybWFsO1xuICB9XG5cbiAgLyoqXG4gICAqIEZpbmRzIHRoZSBpbnRlcnNlY3Rpb24gcG9pbnRzIGJldHdlZW4gYW4gZWxsaXBzZSBhbmQgYSBsaW5lIHNlZ21lbnQuXG4gICAqIEBwYXJhbSBjZW50ZXIgLSBDZW50ZXIgb2YgdGhlIGVsbGlwc2UuXG4gICAqIEBwYXJhbSByYWRpdXNYIC0gWCByYWRpdXMgb2YgdGhlIGVsbGlwc2UuXG4gICAqIEBwYXJhbSByYWRpdXNZIC0gWSByYWRpdXMgb2YgdGhlIGVsbGlwc2UuXG4gICAqIEBwYXJhbSBwb2ludEEgLSBTdGFydGluZyBwb2ludCBvZiB0aGUgbGluZSBzZWdtZW50LlxuICAgKiBAcGFyYW0gcG9pbnRCIC0gRW5kaW5nIHBvaW50IG9mIHRoZSBsaW5lIHNlZ21lbnQuXG4gICAqIEByZXR1cm5zIEFuIGFycmF5IG9mIGludGVyc2VjdGlvbiBwb2ludHMuXG4gICAqL1xuICBwcml2YXRlIHN0YXRpYyBmaW5kRWxsaXBzZUxpbmVJbnRlcnNlY3Rpb25zKGNlbnRlcjogSVBvaW50LCByYWRpdXNYOiBudW1iZXIsIHJhZGl1c1k6IG51bWJlciwgcG9pbnRBOiBJUG9pbnQsIHBvaW50QjogSVBvaW50KTogSVBvaW50W10ge1xuICAgIGNvbnN0IG9yaWdpbiA9IFZlY3RvckV4dGVuc2lvbnMuaW5pdGlhbGl6ZShwb2ludEEueCwgcG9pbnRBLnkpO1xuICAgIGNvbnN0IGRpcmVjdGlvbiA9IFZlY3RvckV4dGVuc2lvbnMuZnJvbVBvaW50cyhwb2ludEEsIHBvaW50Qik7XG4gICAgY29uc3QgZWxsaXBzZUNlbnRlciA9IFZlY3RvckV4dGVuc2lvbnMuaW5pdGlhbGl6ZShjZW50ZXIueCwgY2VudGVyLnkpO1xuICAgIGNvbnN0IGRpZmYgPSBWZWN0b3JFeHRlbnNpb25zLnN1YnRyYWN0KG9yaWdpbiwgZWxsaXBzZUNlbnRlcik7XG4gICAgY29uc3Qgc2NhbGVkRGlyID0gVmVjdG9yRXh0ZW5zaW9ucy5pbml0aWFsaXplKGRpcmVjdGlvbi54IC8gKHJhZGl1c1ggKiByYWRpdXNYKSwgZGlyZWN0aW9uLnkgLyAocmFkaXVzWSAqIHJhZGl1c1kpKTtcbiAgICBjb25zdCBzY2FsZWREaWZmID0gVmVjdG9yRXh0ZW5zaW9ucy5pbml0aWFsaXplKGRpZmYueCAvIChyYWRpdXNYICogcmFkaXVzWCksIGRpZmYueSAvIChyYWRpdXNZICogcmFkaXVzWSkpO1xuXG4gICAgY29uc3QgYSA9IFZlY3RvckV4dGVuc2lvbnMuZG90UHJvZHVjdChkaXJlY3Rpb24sIHNjYWxlZERpcik7XG4gICAgY29uc3QgYiA9IFZlY3RvckV4dGVuc2lvbnMuZG90UHJvZHVjdChkaXJlY3Rpb24sIHNjYWxlZERpZmYpO1xuICAgIGNvbnN0IGMgPSBWZWN0b3JFeHRlbnNpb25zLmRvdFByb2R1Y3QoZGlmZiwgc2NhbGVkRGlmZikgLSAxLjA7XG4gICAgY29uc3QgZGlzY3JpbWluYW50ID0gYiAqIGIgLSBhICogYztcblxuICAgIHJldHVybiBkaXNjcmltaW5hbnQgPCAwID8gW10gOiB0aGlzLmNhbGN1bGF0ZUludGVyc2VjdGlvblBvaW50cyhkaXNjcmltaW5hbnQsIGEsIGIsIHBvaW50QSwgcG9pbnRCKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDYWxjdWxhdGVzIHRoZSBpbnRlcnNlY3Rpb24gcG9pbnRzIGJhc2VkIG9uIHRoZSBkaXNjcmltaW5hbnQuXG4gICAqIEBwYXJhbSBkaXNjcmltaW5hbnQgLSBUaGUgZGlzY3JpbWluYW50IHZhbHVlLlxuICAgKiBAcGFyYW0gYSAtIENvZWZmaWNpZW50ICdhJyBpbiB0aGUgcXVhZHJhdGljIGVxdWF0aW9uLlxuICAgKiBAcGFyYW0gYiAtIENvZWZmaWNpZW50ICdiJyBpbiB0aGUgcXVhZHJhdGljIGVxdWF0aW9uLlxuICAgKiBAcGFyYW0gcG9pbnRBIC0gU3RhcnRpbmcgcG9pbnQgb2YgdGhlIGxpbmUgc2VnbWVudC5cbiAgICogQHBhcmFtIHBvaW50QiAtIEVuZGluZyBwb2ludCBvZiB0aGUgbGluZSBzZWdtZW50LlxuICAgKiBAcmV0dXJucyBBbiBhcnJheSBvZiBpbnRlcnNlY3Rpb24gcG9pbnRzLlxuICAgKi9cbiAgcHJpdmF0ZSBzdGF0aWMgY2FsY3VsYXRlSW50ZXJzZWN0aW9uUG9pbnRzKGRpc2NyaW1pbmFudDogbnVtYmVyLCBhOiBudW1iZXIsIGI6IG51bWJlciwgcG9pbnRBOiBJUG9pbnQsIHBvaW50QjogSVBvaW50KTogSVBvaW50W10ge1xuICAgIGNvbnN0IHBvaW50czogSVBvaW50W10gPSBbXTtcblxuICAgIGlmIChkaXNjcmltaW5hbnQgPiAwKSB7XG4gICAgICBjb25zdCByb290ID0gTWF0aC5zcXJ0KGRpc2NyaW1pbmFudCk7XG4gICAgICBjb25zdCB0MSA9ICgtYiAtIHJvb3QpIC8gYTtcbiAgICAgIGNvbnN0IHQyID0gKC1iICsgcm9vdCkgLyBhO1xuXG4gICAgICBpZiAodDEgPj0gMCAmJiB0MSA8PSAxKSB7XG4gICAgICAgIHBvaW50cy5wdXNoKFBvaW50RXh0ZW5zaW9ucy5pbnRlcnBvbGF0ZVBvaW50cyhwb2ludEEsIHBvaW50QiwgdDEpKTtcbiAgICAgIH1cbiAgICAgIGlmICh0MiA+PSAwICYmIHQyIDw9IDEpIHtcbiAgICAgICAgcG9pbnRzLnB1c2goUG9pbnRFeHRlbnNpb25zLmludGVycG9sYXRlUG9pbnRzKHBvaW50QSwgcG9pbnRCLCB0MikpO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCB0ID0gLWIgLyBhO1xuICAgICAgaWYgKHQgPj0gMCAmJiB0IDw9IDEpIHtcbiAgICAgICAgcG9pbnRzLnB1c2goUG9pbnRFeHRlbnNpb25zLmludGVycG9sYXRlUG9pbnRzKHBvaW50QSwgcG9pbnRCLCB0KSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHBvaW50cztcbiAgfVxufVxuIl19