<!-- NEW4 — TEST 4 · THE QUILT · part 223 -->
keep ) {

				if ( i !== writeIndex ) {

					times[ writeIndex ] = times[ i ];

					const readOffset = i * stride,
						writeOffset = writeIndex * stride;

					for ( let j = 0; j !== stride; ++ j ) {

						values[ writeOffset + j ] = values[ readOffset + j ];

					}

				}

				++ writeIndex;

			}

		}

		// flush last keyframe (compaction looks ahead)

		if ( lastIndex > 0 ) {

			times[ writeIndex ] = times[ lastIndex ];

			for ( let readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) {

				values[ writeOffset + j ] = values[ readOffset + j ];

			}

			++ writeIndex;

		}

		if ( writeIndex !== times.length ) {

			this.times = times.slice( 0, writeIndex );
			this.values = values.slice( 0, writeIndex * stride );

		} else {

			this.times = times;
			this.values = values;

		}

		return this;

	}

	/**
	 * Returns a new keyframe track with copied values from this instance.
	 *
	 * @return {KeyframeTrack} A clone of this instance.
	 */
	clone() {

		const times = this.times.slice();
		const values = this.values.slice();

		const TypedKeyframeTrack = this.constructor;
		const track = new TypedKeyframeTrack( this.name, times, values );

		// Interpolant argument to constructor is not saved, so copy the factory method directly.
		track.createInterpolant = this.createInterpolant;

		if ( hasTangents( this.settings ) ) {

			track.settings = {
				inTangents: this.settings.inTangents.slice(),
				outTangents: this.settings.outTangents.slice()
			};

		}

		return track;

	}

}

function scaleTangentTimes( tangents, timeScale ) {

	// tangents are [ time, value ] pairs, so only every second entry is a time

	for ( let i = 0, n = tangents.length; i !== n; i += 2 ) {

		tangents[ i ] *= timeScale;

	}

}

/**
 * The value type name.
 *
 * @type {string}
 * @default ''
 */
KeyframeTrack.prototype.ValueTypeName = '';

/**
 * The time buffer type of this keyframe track.
 *
 * @type {TypedArray|Array}
 * @default Float32Array.constructor
 */
KeyframeTrack.prototype.TimeBufferType = Float32Array;

/**
 * The value buffer type of this keyframe track.
 *
 * @type {TypedArray|Array}
 * @default Float32Array.constructor
 */
KeyframeTrack.prototype.ValueBufferType = Float32Array;

/**
 * The default interpolation type of this keyframe track.
 *
 * @type {(InterpolateLinear|InterpolateDiscrete|InterpolateSmooth|InterpolateBezier)}
 * @default InterpolateLinear
 */
KeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear;

/**
 * A track for boolean keyframe values.
 *
 * @augments KeyframeTrack
 */
class BooleanKeyframeTrack extends KeyframeTrack {

	/**
	 * Constructs a new boolean keyframe track.
	 *
	 * This keyframe track type has no `interpolation` parameter because the
	 * interpolation is always discrete.
	 *
	 * @param {string} name - The keyframe track's name.
	 * @param {Array<number>} times - A list of keyframe times.
	 * @param {Array<boolean>} values - A list of keyframe values.
	 */
	constructor( name, times, values ) {

		super( name, times, values );

	}

}

/**
 * The value type name.
 *
 * @type {string}
 * @default 'bool'
 */
BooleanKeyframeTrack.prototype.ValueTypeName = 'bool';

/**
 * The value buffer type of this keyframe track.
 *
 * @type {TypedArray|Array}
 * @default Array.constructor
 */
BooleanKeyframeTrack.prototype.ValueBufferType = Array;

/**
 * The default interpolation type of this keyframe track.
 *
 * @type {(InterpolateLinear|InterpolateDiscrete|InterpolateSmooth)}
 * @default InterpolateDiscrete
 */
BooleanKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete;
BooleanKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined;
BooleanKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined;

/**
 * A track for color keyframe values.
 *
 * @augments KeyframeTrack
 */
class ColorKeyframeTrack extends KeyframeTrack {

	/**
	 * Constructs a new color keyframe track.
	 *
	 * @param {string} name - The keyframe track's name.
	 * @param {Array<number>} times - A list of keyframe times.
	 * @param {Array<number>} values - A list of keyframe values.
	 * @param {(InterpolateLinear|InterpolateDiscrete|InterpolateSmooth)} [interpolation] - The interpolation type.
	 */
	constructor( name, times, values, interpolation ) {

		super( name, times, values, interpolation );

	}

}

/**
 * The value type name.
 *
 * @type {string}
 * @default 'color'
 */
ColorKeyframeTrack.prototype.ValueTypeName = 'color';

/**
 * A track for numeric keyframe values.
 *
 * @augments KeyframeTrack
 */
class NumberKeyframeTrack extends KeyframeTrack {

	/**
	 * Constructs a new number keyframe track.
	 *
	 * @param {string} name - The keyframe track's name.
	 * @param {Array<number>} times - A list of keyframe times.
	 * @param {Array<number>} values - A list of keyframe values.
	 * @param {(InterpolateLinear|InterpolateDiscrete|InterpolateSmooth)} [interpolation] - The interpolation t