<!-- SOLIDIVISM · part 239 -->
 return p;
}

function removeNode(p) {
    p.next.prev = p.prev;
    p.prev.next = p.next;

    if (p.prevZ) p.prevZ.nextZ = p.nextZ;
    if (p.nextZ) p.nextZ.prevZ = p.prevZ;
}

function createNode(i, x, y) {
    return {
        i, // vertex index in coordinates array
        x, y, // vertex coordinates
        prev: null, // previous and next vertex nodes in a polygon ring
        next: null,
        z: 0, // z-order curve value
        prevZ: null, // previous and next nodes in z-order
        nextZ: null,
        steiner: false // indicates whether this is a steiner point
    };
}

function signedArea(data, start, end, dim) {
    let sum = 0;
    for (let i = start, j = end - dim; i < end; i += dim) {
        sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
        j = i;
    }
    return sum;
}

/**
 * An implementation of the earcut polygon triangulation algorithm.
 * The code is a port of [mapbox/earcut](https://github.com/mapbox/earcut).
 *
 * @see https://github.com/mapbox/earcut
 */
class Earcut {

	/**
	 * Triangulates the given shape definition by returning an array of triangles.
	 *
	 * @param {Array<number>} data - An array with 2D points.
	 * @param {Array<number>} holeIndices - An array with indices defining holes.
	 * @param {number} [dim=2] - The number of coordinates per vertex in the input array.
	 * @return {Array<number>} An array representing the triangulated faces. Each face is defined by three consecutive numbers
	 * representing vertex indices.
	 */
	static triangulate( data, holeIndices, dim = 2 ) {

		return earcut( data, holeIndices, dim );

	}

}

/**
 * A class containing utility functions for shapes.
 *
 * @hideconstructor
 */
class ShapeUtils {

	/**
	 * Calculate area of a ( 2D ) contour polygon.
	 *
	 * @param {Array<Vector2>} contour - An array of 2D points.
	 * @return {number} The area.
	 */
	static area( contour ) {

		const n = contour.length;
		let a = 0.0;

		for ( let p = n - 1, q = 0; q < n; p = q ++ ) {

			a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y;

		}

		return a * 0.5;

	}

	/**
	 * Returns `true` if the given contour uses a clockwise winding order.
	 *
	 * @param {Array<Vector2>} pts - An array of 2D points defining a polygon.
	 * @return {boolean} Whether the given contour uses a clockwise winding order or not.
	 */
	static isClockWise( pts ) {

		return ShapeUtils.area( pts ) < 0;

	}

	/**
	 * Triangulates the given shape definition.
	 *
	 * @param {Array<Vector2>} contour - An array of 2D points defining the contour.
	 * @param {Array<Array<Vector2>>} holes - An array that holds arrays of 2D points defining the holes.
	 * @return {Array<Array<number>>} An array that holds for each face definition an array with three indices.
	 */
	static triangulateShape( contour, holes ) {

		const vertices = []; // flat array of vertices like [ x0,y0, x1,y1, x2,y2, ... ]
		const holeIndices = []; // array of hole indices
		const faces = []; // final array of vertex indices like [ [ a,b,d ], [ b,c,d ] ]

		removeDupEndPts( contour );
		addContour( vertices, contour );

		//

		let holeIndex = contour.length;

		holes.forEach( removeDupEndPts );

		for ( let i = 0; i < holes.length; i ++ ) {

			holeIndices.push( holeIndex );
			holeIndex += holes[ i ].length;
			addContour( vertices, holes[ i ] );

		}

		//

		const triangles = Earcut.triangulate( vertices, holeIndices );

		//

		for ( let i = 0; i < triangles.length; i += 3 ) {

			faces.push( triangles.slice( i, i + 3 ) );

		}

		return faces;

	}

}

function removeDupEndPts( points ) {

	const l = points.length;

	if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) {

		points.pop();

	}

}

function addContour( vertices, contour ) {

	for ( let i = 0; i < contour.length; i ++ ) {

		vertices.push( contour[ i ].x );
		vertices.push( contour[ i ].y );

	}

}

/**
 * Creates extruded geometry from a path shape.
 *
 * ```js
 * const length = 12, width = 8;
 *
 * const shape = new THREE.Shape();
 * shape.moveTo( 0,0 );
 * shape.lineTo( 0, width );
 * shape.lineTo( length, width );
 * shape.lineTo( length, 0 );
 * shape.lineTo( 0, 0 );
 *
 * const geometry = new THREE.ExtrudeGeometry( shape );
 * const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
 * const mesh = new THREE.Mesh( geometry, material ) ;
 * scene.add( mesh );
 * ```
 *
 * @augments BufferGeometry
 * @demo scenes/geometry-browser.html#ExtrudeGeometry
 */
class ExtrudeGeometry extends BufferGeometry {

	/**
	 * Constructs a new extrude geometry.
	 *
	 * @param {Shape|Array<Shape>} [shapes] - A shape or an array of shapes.
	 * @param {ExtrudeGeometry~Options} [options] - The extrude settings.
	 */
	constructor( shapes = new Shape( [ new Vector2( 0.5, 0.5 ), new Vector2( -0.5, 0.5 ), new Vector2( -0.5, -0.5 ), new Vector2( 0.5, -0.5 ) ] ), options = {} ) {

		super();

		this.type = 'ExtrudeGeometry';

		/**
		 * Holds the constructor parameters that have been
		 * use