<!-- NEW4 — TEST 4 · THE QUILT · part 279 -->
instance of {@link AnimationAction} for the passed clip.
	 *
	 * If an action fitting the clip and root parameters doesn't yet exist, it
	 * will be created by this method. Calling this method several times with the
	 * same clip and root parameters always returns the same action.
	 *
	 * @param {AnimationClip|string} clip - An animation clip or alternatively the name of the animation clip.
	 * @param {Object3D} [optionalRoot] - An alternative root object.
	 * @param {(NormalAnimationBlendMode|AdditiveAnimationBlendMode)} [blendMode] - The blend mode.
	 * @return {?AnimationAction} The animation action.
	 */
	clipAction( clip, optionalRoot, blendMode ) {

		const root = optionalRoot || this._root,
			rootUuid = root.uuid;

		let clipObject = typeof clip === 'string' ? AnimationClip.findByName( root, clip ) : clip;

		const clipUuid = clipObject !== null ? clipObject.uuid : clip;

		const actionsForClip = this._actionsByClip[ clipUuid ];
		let prototypeAction = null;

		if ( blendMode === undefined ) {

			if ( clipObject !== null ) {

				blendMode = clipObject.blendMode;

			} else {

				blendMode = NormalAnimationBlendMode;

			}

		}

		if ( actionsForClip !== undefined ) {

			const existingAction = actionsForClip.actionByRoot[ rootUuid ];

			if ( existingAction !== undefined && existingAction.blendMode === blendMode ) {

				return existingAction;

			}

			// we know the clip, so we don't have to parse all
			// the bindings again but can just copy
			prototypeAction = actionsForClip.knownActions[ 0 ];

			// also, take the clip from the prototype action
			if ( clipObject === null )
				clipObject = prototypeAction._clip;

		}

		// clip must be known when specified via string
		if ( clipObject === null ) return null;

		// allocate all resources required to run it
		const newAction = new AnimationAction( this, clipObject, optionalRoot, blendMode );

		this._bindAction( newAction, prototypeAction );

		// and make the action known to the memory manager
		this._addInactiveAction( newAction, clipUuid, rootUuid );

		return newAction;

	}

	/**
	 * Returns an existing animation action for the passed clip.
	 *
	 * @param {AnimationClip|string} clip - An animation clip or alternatively the name of the animation clip.
	 * @param {Object3D} [optionalRoot] - An alternative root object.
	 * @return {?AnimationAction} The animation action. Returns `null` if no action was found.
	 */
	existingAction( clip, optionalRoot ) {

		const root = optionalRoot || this._root,
			rootUuid = root.uuid,

			clipObject = typeof clip === 'string' ?
				AnimationClip.findByName( root, clip ) : clip,

			clipUuid = clipObject ? clipObject.uuid : clip,

			actionsForClip = this._actionsByClip[ clipUuid ];

		if ( actionsForClip !== undefined ) {

			return actionsForClip.actionByRoot[ rootUuid ] || null;

		}

		return null;

	}

	/**
	 * Deactivates all previously scheduled actions on this mixer.
	 *
	 * @return {AnimationMixer} A reference to this animation mixer.
	 */
	stopAllAction() {

		const actions = this._actions,
			nActions = this._nActiveActions;

		for ( let i = nActions - 1; i >= 0; -- i ) {

			actions[ i ].stop();

		}

		return this;

	}

	/**
	 * Advances the global mixer time and updates the animation.
	 *
	 * This is usually done in the render loop by passing the delta
	 * time from {@link Clock} or {@link Timer}.
	 *
	 * @param {number} deltaTime - The delta time in seconds.
	 * @return {AnimationMixer} A reference to this animation mixer.
	 */
	update( deltaTime ) {

		deltaTime *= this.timeScale;

		const actions = this._actions,
			nActions = this._nActiveActions,

			time = this.time += deltaTime,
			timeDirection = Math.sign( deltaTime ),

			accuIndex = this._accuIndex ^= 1;

		// run active actions

		for ( let i = 0; i !== nActions; ++ i ) {

			const action = actions[ i ];

			action._update( time, deltaTime, timeDirection, accuIndex );

		}

		// update scene graph

		const bindings = this._bindings,
			nBindings = this._nActiveBindings;

		for ( let i = 0; i !== nBindings; ++ i ) {

			bindings[ i ].apply( accuIndex );

		}

		return this;

	}

	/**
	 * Sets the global mixer to a specific time and updates the animation accordingly.
	 *
	 * This is useful when you need to jump to an exact time in an animation. The
	 * input parameter will be scaled by {@link AnimationMixer#timeScale}
	 *
	 * @param {number} time - The time to set in seconds.
	 * @return {AnimationMixer} A reference to this animation mixer.
	 */
	setTime( time ) {

		this.time = 0; // Zero out time attribute for AnimationMixer object;
		for ( let i = 0; i < this._actions.length; i ++ ) {

			this._actions[ i ].time = 0; // Zero out time attribute for all associated AnimationAction objects.

		}

		return this.update( time ); // Update used to set exact time. Returns "this" AnimationMixer object.

	}

	/**
	 * Returns this mixer's root object.
	 *
	 * @return {Object3D} The mixer's ro