<!-- NEW4 — TEST 4 · THE QUILT · part 280 -->
ot object.
	 */
	getRoot() {

		return this._root;

	}

	/**
	 * Deallocates all memory resources for a clip. Before using this method make
	 * sure to call {@link AnimationAction#stop} for all related actions.
	 *
	 * @param {AnimationClip} clip - The clip to uncache.
	 */
	uncacheClip( clip ) {

		const actions = this._actions,
			clipUuid = clip.uuid,
			actionsByClip = this._actionsByClip,
			actionsForClip = actionsByClip[ clipUuid ];

		if ( actionsForClip !== undefined ) {

			// note: just calling _removeInactiveAction would mess up the
			// iteration state and also require updating the state we can
			// just throw away

			const actionsToRemove = actionsForClip.knownActions;

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

				const action = actionsToRemove[ i ];

				this._deactivateAction( action );

				const cacheIndex = action._cacheIndex,
					lastInactiveAction = actions[ actions.length - 1 ];

				action._cacheIndex = null;
				action._byClipCacheIndex = null;

				lastInactiveAction._cacheIndex = cacheIndex;
				actions[ cacheIndex ] = lastInactiveAction;
				actions.pop();

				this._removeInactiveBindingsForAction( action );

			}

			delete actionsByClip[ clipUuid ];

		}

	}

	/**
	 * Deallocates all memory resources for a root object. Before using this
	 * method make sure to call {@link AnimationAction#stop} for all related
	 * actions or alternatively {@link AnimationMixer#stopAllAction} when the
	 * mixer operates on a single root.
	 *
	 * @param {Object3D} root - The root object to uncache.
	 */
	uncacheRoot( root ) {

		const rootUuid = root.uuid,
			actionsByClip = this._actionsByClip;

		for ( const clipUuid in actionsByClip ) {

			const actionByRoot = actionsByClip[ clipUuid ].actionByRoot,
				action = actionByRoot[ rootUuid ];

			if ( action !== undefined ) {

				this._deactivateAction( action );
				this._removeInactiveAction( action );

			}

		}

		const bindingsByRoot = this._bindingsByRootAndName,
			bindingByName = bindingsByRoot[ rootUuid ];

		if ( bindingByName !== undefined ) {

			for ( const trackName in bindingByName ) {

				const binding = bindingByName[ trackName ];
				binding.restoreOriginalState();
				this._removeInactiveBinding( binding );

			}

		}

	}

	/**
	 * Deallocates all memory resources for an action. The action is identified by the
	 * given clip and an optional root object. Before using this method make
	 * sure to call {@link AnimationAction#stop} to deactivate the action.
	 *
	 * @param {AnimationClip|string} clip - An animation clip or alternatively the name of the animation clip.
	 * @param {Object3D} [optionalRoot] - An alternative root object.
	 */
	uncacheAction( clip, optionalRoot ) {

		const action = this.existingAction( clip, optionalRoot );

		if ( action !== null ) {

			this._deactivateAction( action );
			this._removeInactiveAction( action );

		}

	}

}

/**
 * Represents a 3D render target.
 *
 * @augments RenderTarget
 */
class RenderTarget3D extends RenderTarget {

	/**
	 * Constructs a new 3D render target.
	 *
	 * @param {number} [width=1] - The width of the render target.
	 * @param {number} [height=1] - The height of the render target.
	 * @param {number} [depth=1] - The height of the render target.
	 * @param {RenderTarget~Options} [options] - The configuration object.
	 */
	constructor( width = 1, height = 1, depth = 1, options = {} ) {

		super( width, height, options );

		/**
		 * This flag can be used for type testing.
		 *
		 * @type {boolean}
		 * @readonly
		 * @default true
		 */
		this.isRenderTarget3D = true;

		this.depth = depth;

		// overwrite attachments with 3D textures

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

			const texture = new Data3DTexture( null, width, height, depth );
			texture.isRenderTargetTexture = true;
			texture.renderTarget = this;

			this.textures[ i ] = texture;

		}

		this._setTextureOptions( options );

	}

}

/**
 * Represents a uniform which is a global shader variable. They are passed to shader programs.
 *
 * When declaring a uniform of a {@link ShaderMaterial}, it is declared by value or by object.
 * ```js
 * uniforms: {
 * 	time: { value: 1.0 },
 * 	resolution: new Uniform( new Vector2() )
 * };
 * ```
 * Since this class can only be used in context of {@link ShaderMaterial}, it is only supported
 * in {@link WebGLRenderer}.
 */
class Uniform {

	/**
	 * Constructs a new uniform.
	 *
	 * @param {any} value - The uniform value.
	 */
	constructor( value ) {

		/**
		 * The uniform value.
		 *
		 * @type {any}
		 */
		this.value = value;

	}

	/**
	 * Returns a new uniform with copied values from this instance.
	 * If the value has a `clone()` method, the value is cloned as well.
	 *
	 * @return {Uniform} A clone of this instance.
	 */
	clone() {

		return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() );

	}

}

let _id = 0;

/**
 * A class for managing multi