<!-- NEW3 — TEST 3 · THE RIVER'S JOURNEY · part 250 -->
onError( new Error( 'THREE.ObjectLoader: Can\'t load ' + url ) );

				error( 'ObjectLoader: Can\'t load ' + url );
				return;

			}

			scope.parse( json, onLoad );

		}, onProgress, onError );

	}

	/**
	 * Async version of {@link ObjectLoader#load}.
	 *
	 * @async
	 * @param {string} url - The path/URL of the file to be loaded. This can also be a data URI.
	 * @param {onProgressCallback} onProgress - Executed while the loading is in progress.
	 * @return {Promise<Object3D>} A Promise that resolves with the loaded 3D object.
	 */
	async loadAsync( url, onProgress ) {

		const scope = this;

		const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path;
		this.resourcePath = this.resourcePath || path;

		const loader = new FileLoader( this.manager );
		loader.setPath( this.path );
		loader.setRequestHeader( this.requestHeader );
		loader.setWithCredentials( this.withCredentials );

		const text = await loader.loadAsync( url, onProgress );

		let json;

		try {

			json = JSON.parse( text );

		} catch ( e ) {

			throw new Error( 'THREE.ObjectLoader: Can\'t parse ' + url + '. ' + e.message );

		}

		const metadata = json.metadata;

		if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) {

			throw new Error( 'THREE.ObjectLoader: Can\'t load ' + url );

		}

		return await scope.parseAsync( json );

	}

	/**
	 * Parses the given JSON. This is used internally by {@link ObjectLoader#load}
	 * but can also be used directly to parse a previously loaded JSON structure.
	 *
	 * @param {Object} json - The serialized 3D object.
	 * @param {onLoad} onLoad - Executed when all resources (e.g. textures) have been fully loaded.
	 * @return {Object3D} The parsed 3D object.
	 */
	parse( json, onLoad ) {

		const animations = this.parseAnimations( json.animations );
		const shapes = this.parseShapes( json.shapes );
		const geometries = this.parseGeometries( json.geometries, shapes );

		const images = this.parseImages( json.images, function () {

			if ( onLoad !== undefined ) onLoad( object );

		} );

		const textures = this.parseTextures( json.textures, images );
		const materials = this.parseMaterials( json.materials, textures );

		const object = this.parseObject( json.object, geometries, materials, textures, animations );
		const skeletons = this.parseSkeletons( json.skeletons, object );

		this.bindSkeletons( object, skeletons );
		this.bindLightTargets( object );

		//

		if ( onLoad !== undefined ) {

			let hasImages = false;

			for ( const uuid in images ) {

				if ( images[ uuid ].data instanceof HTMLImageElement ) {

					hasImages = true;
					break;

				}

			}

			if ( hasImages === false ) onLoad( object );

		}

		return object;

	}

	/**
	 * Async version of {@link ObjectLoader#parse}.
	 *
	 * @param {Object} json - The serialized 3D object.
	 * @return {Promise<Object3D>} A Promise that resolves with the parsed 3D object.
	 */
	async parseAsync( json ) {

		const animations = this.parseAnimations( json.animations );
		const shapes = this.parseShapes( json.shapes );
		const geometries = this.parseGeometries( json.geometries, shapes );

		const images = await this.parseImagesAsync( json.images );

		const textures = this.parseTextures( json.textures, images );
		const materials = this.parseMaterials( json.materials, textures );

		const object = this.parseObject( json.object, geometries, materials, textures, animations );
		const skeletons = this.parseSkeletons( json.skeletons, object );

		this.bindSkeletons( object, skeletons );
		this.bindLightTargets( object );

		return object;

	}

	/**
	 * Registers the given geometry at the internal
	 * geometry library.
	 *
	 * @static
	 * @param {string} type - The geometry type.
	 * @param {BufferGeometry.constructor} geometryClass - The geometry class.
	 */
	static registerGeometry( type, geometryClass ) {

		_customGeometries[ type ] = geometryClass;

	}

	// internals

	parseShapes( json ) {

		const shapes = {};

		if ( json !== undefined ) {

			for ( let i = 0, l = json.length; i < l; i ++ ) {

				const shape = new Shape().fromJSON( json[ i ] );

				shapes[ shape.uuid ] = shape;

			}

		}

		return shapes;

	}

	parseSkeletons( json, object ) {

		const skeletons = {};
		const bones = {};

		// generate bone lookup table

		object.traverse( function ( child ) {

			if ( child.isBone ) bones[ child.uuid ] = child;

		} );

		// create skeletons

		if ( json !== undefined ) {

			for ( let i = 0, l = json.length; i < l; i ++ ) {

				const skeleton = new Skeleton().fromJSON( json[ i ], bones );

				skeletons[ skeleton.uuid ] = skeleton;

			}

		}

		return skeletons;

	}

	parseGeometries( json, shapes ) {

		const geometries = {};

		if ( json !== undefined ) {

			const bufferGeometryLoader = new BufferGeometryLoader();

			for ( let i = 0, l = json.length; i < l; i ++ ) {

				let geometry;
				const data = json[