Checking in new webgl files. Note that the WebAssembly transcoder has gotten bloated with BC7 support, which I'm working on fixing right now. (The wasm went from ~200k to 900k, because of a transcoder macro configuration issue.)
diff --git a/webgl/README.md b/webgl/README.md
index edebd56..18aeb20 100644
--- a/webgl/README.md
+++ b/webgl/README.md
@@ -8,12 +8,15 @@
 
 Renders a single texture, using the transcoder (compiled to WASM with emscripten) to generate one of the following compressed texture formats:
 
-* BC1
+* ASTC
+* BC1 (no alpha)
 * BC3
+* ETC1 (no alpha)
+* PVRTC
 
 Please note that both Firefox and Chrome support BC1, but due to an implementation issue in the code it doesn't work on Firefox yet. (It doesn't test for the "WEBGL_compressed_texture_s3tc" extension.)
 
-On browsers that don't support BC1, there's a low-quality fallback code path for opaque textures (but no fallback for BC3 yet). Note that the fallback path only converts to 16-bit RGB images at the moment, so the quality isn't as good as it should be.
+On browsers that don't support any compressed texture format, there's a low-quality fallback code path for opaque textures. Note that the fallback path only converts to 16-bit RGB images at the moment, so the quality isn't as good as it should be.
 
 ![Screenshot showing a basis texture rendered as a 2D image in a webpage.](texture/preview.png)
 
@@ -23,11 +26,13 @@
 
 Renders a glTF 3D model with `.basis` texture files, transcoded into one of the following compressed texture formats:
 
-* DTX (BC1)
+* ASTC
+  * Tested in Chrome on Android, Pixel 3 XL.
+* DTX (BC1/BC3)
   * Tested in Chrome (Linux and macOS) and Firefox (macOS).
 * ETC1
   * Tested in Chrome on Android, Pixel 3 XL.
-* PVRTC (COMPRESSED_RGB_PVRTC_4BPPV1_IMG)
+* PVRTC
   * Tested in Chrome and Safari on iOS iPhone 6 Plus.
 
 The glTF model in this demo uses a hypothetical `GOOGLE_texture_basis` extension. That extension is defined for the sake of example only – the glTF format will officially embed Basis files within a KTX2 wrapper, through a new
diff --git a/webgl/gltf/BasisTextureLoader.js b/webgl/gltf/BasisTextureLoader.js
index 4f79545..46312bc 100644
--- a/webgl/gltf/BasisTextureLoader.js
+++ b/webgl/gltf/BasisTextureLoader.js
@@ -5,165 +5,487 @@
  */
 
 /**
- * An example three.js loader for Basis compressed textures.
+ * Loader for Basis Universal GPU Texture Codec.
+ *
+ * Basis Universal is a "supercompressed" GPU texture and texture video
+ * compression system that outputs a highly compressed intermediate file format
+ * (.basis) that can be quickly transcoded to a wide variety of GPU texture
+ * compression formats.
+ *
+ * This loader parallelizes the transcoding process across a configurable number
+ * of web workers, before transferring the transcoded compressed texture back
+ * to the main thread.
  */
-THREE.BasisTextureLoader = class BasisTextureLoader {
+THREE.BasisTextureLoader = function ( manager ) {
 
-  constructor () {
+	THREE.Loader.call( this, manager );
 
-    this.etcSupported = false;
-    this.dxtSupported = false;
-    this.pvrtcSupported = false;
+  this.useAlpha = true;
+	this.transcoderPath = '';
+	this.transcoderBinary = null;
+	this.transcoderPending = null;
 
-    this.format = null;
+	this.workerLimit = 4;
+	this.workerPool = [];
+	this.workerNextTaskID = 1;
+	this.workerSourceURL = '';
+	this.workerConfig = {
+    format: null,
+    useAlpha: true,
+    astcSupported: false,
+		etcSupported: false,
+		dxtSupported: false,
+    pvrtcSupported: false,
+	};
 
-  }
+};
 
-  detectSupport ( renderer ) {
+THREE.BasisTextureLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype ), {
 
-    const context = renderer.context;
+	constructor: THREE.BasisTextureLoader,
 
-    this.etcSupported = context.getExtension('WEBGL_compressed_texture_etc1');
-    this.dxtSupported = context.getExtension('WEBGL_compressed_texture_s3tc');
-    this.pvrtcSupported = context.getExtension('WEBGL_compressed_texture_pvrtc')
-      || context.getExtension('WEBKIT_WEBGL_compressed_texture_pvrtc');
+	setTranscoderPath: function ( path ) {
 
-    if ( ! this.etcSupported && ! this.dxtSupported && ! this.pvrtcSupported ) {
+		this.transcoderPath = path;
 
-      throw new Error( 'THREE.BasisTextureLoader: No suitable compressed texture format found.' );
+		return this;
 
-    }
+	},
 
-    this.format = this.etcSupported
-      ? BASIS_FORMAT.cTFETC1
-      : ( this.dxtSupported
-        ? BASIS_FORMAT.cTFBC1
-        : BASIS_FORMAT.cTFPVRTC1_4_OPAQUE_ONLY );
+	setWorkerLimit: function ( workerLimit ) {
 
-     return this;
+		this.workerLimit = workerLimit;
 
-  }
+		return this;
 
-  load ( url, onLoad, onProgress, onError ) {
+	},
 
-    fetch( url )
-      .then( ( res ) => res.arrayBuffer() )
-      .then( (arrayBuffer) => this._createTexture( arrayBuffer ) )
-      .then( onLoad )
-      .catch( onError );
+	detectSupport: function ( renderer ) {
 
-  }
+		var config = this.workerConfig;
 
-  _createTexture ( arrayBuffer ) {
+    config.astcSupported = !! renderer.extensions.get( 'WEBGL_compressed_texture_astc' );
+		config.etcSupported = !! renderer.extensions.get( 'WEBGL_compressed_texture_etc1' );
+		config.dxtSupported = !! renderer.extensions.get( 'WEBGL_compressed_texture_s3tc' );
+		config.pvrtcSupported = !! renderer.extensions.get( 'WEBGL_compressed_texture_pvrtc' )
+      || !! renderer.extensions.get( 'WEBKIT_WEBGL_compressed_texture_pvrtc' );
 
-    const BASIS_FORMAT = THREE.BasisTextureLoader.BASIS_FORMAT;
-    const DXT_FORMAT_MAP = THREE.BasisTextureLoader.DXT_FORMAT_MAP;
+    if (config.astcSupported) {
 
-    const basisFile = new BasisFile( new Uint8Array( arrayBuffer ) );
+      config.format = THREE.BasisTextureLoader.BASIS_FORMAT.cTFASTC_4x4;
 
-    const width = basisFile.getImageWidth( 0, 0 );
-    const height = basisFile.getImageHeight( 0, 0 );
-    const images = basisFile.getNumImages();
-    const levels = basisFile.getNumLevels( 0 );
+    } else if ( config.dxtSupported ) {
 
-    function cleanup () {
+			config.format = this.useAlpha ? THREE.BasisTextureLoader.BASIS_FORMAT.cTFBC3 : THREE.BasisTextureLoader.BASIS_FORMAT.cTFBC1;
 
-      basisFile.close();
-      basisFile.delete();
+		} else if ( config.pvrtcSupported ) {
 
-    }
+			config.format = this.useAlpha ? THREE.BasisTextureLoader.BASIS_FORMAT.cTFPVRTC1_4_RGBA : THREE.BasisTextureLoader.BASIS_FORMAT.cTFPVRTC1_4_RGB;
 
-    if ( ! width || ! height || ! images || ! levels ) {
+    } else if ( config.etcSupported ) {
 
-      cleanup();
-      throw new Error( 'THREE.BasisTextureLoader:  Invalid .basis file' );
+			config.format = THREE.BasisTextureLoader.BASIS_FORMAT.cTFETC1;
 
-    }
+		} else {
 
-    if ( ! basisFile.startTranscoding() ) {
+			throw new Error( 'THREE.BasisTextureLoader: No suitable compressed texture format found.' );
 
-      cleanup();
-      throw new Error( 'THREE.BasisTextureLoader: .startTranscoding failed' );
+		}
 
-    }
+		return this;
 
-    const dst = new Uint8Array( basisFile.getImageTranscodedSizeInBytes( 0, 0, this.format ) );
+	},
 
-    const startTime = performance.now();
+	load: function ( url, onLoad, onProgress, onError ) {
 
-    const status = basisFile.transcodeImage(
-      dst,
-      0,
-      0,
-      this.format,
-      this.etcSupported ? 0 : ( this.dxtSupported ? 1 : 0 ),
-      0
-    );
+		var loader = new THREE.FileLoader( this.manager );
 
-    console.log( `THREE.BasisTextureLoader: Transcode time: ${performance.now() - startTime}ms`, dst );
+		loader.setResponseType( 'arraybuffer' );
 
-    cleanup();
+		loader.load( url, ( buffer ) => {
 
-    if ( ! status ) {
+			this._createTexture( buffer )
+				.then( onLoad )
+				.catch( onError );
 
-      throw new Error( 'THREE.BasisTextureLoader: .transcodeImage failed.' );
+		}, onProgress, onError );
 
-    }
+	},
 
-    const mipmaps = [ { data: dst, width, height } ];
+	/**
+	 * @param  {ArrayBuffer} buffer
+	 * @return {Promise<THREE.CompressedTexture>}
+	 */
+	_createTexture: function ( buffer ) {
 
-    let texture;
+		var worker;
+		var taskID;
 
-    if ( this.etcSupported ) {
+		var texturePending = this._getWorker()
+			.then( ( _worker ) => {
 
-      texture = new THREE.CompressedTexture( mipmaps, width, height, THREE.RGB_ETC1_Format );
+				worker = _worker;
+				taskID = this.workerNextTaskID ++;
 
-    } else if ( this.dxtSupported ) {
+				return new Promise( ( resolve, reject ) => {
 
-      texture = new THREE.CompressedTexture( mipmaps, width, height, DXT_FORMAT_MAP[ this.format ], THREE.UnsignedByteType );
+					worker._callbacks[ taskID ] = { resolve, reject };
+					worker._taskCosts[ taskID ] = buffer.byteLength;
+					worker._taskLoad += worker._taskCosts[ taskID ];
 
-    } else if ( this.pvrtcSupported ) {
+					worker.postMessage( { type: 'transcode', id: taskID, buffer }, [ buffer ] );
 
-      texture = new THREE.CompressedTexture( mipmaps, width, height, THREE.RGB_PVRTC_4BPPV1_Format );
+				} );
 
-    } else {
+			} )
+			.then( ( message ) => {
 
-      throw new Error( 'THREE.BasisTextureLoader: No supported format available.' );
+				var config = this.workerConfig;
 
-    }
+				var { width, height, hasAlpha, mipmaps } = message;
 
-    texture.minFilter = THREE.LinearMipMapLinearFilter;
-    texture.magFilter = THREE.LinearFilter;
-    texture.encoding = THREE.sRGBEncoding;
-    texture.generateMipmaps = false;
-    texture.flipY = false;
-    texture.needsUpdate = true;
+				var texture;
 
-    return texture;
+        switch(config.format) {
+          case THREE.BasisTextureLoader.BASIS_FORMAT.cTFASTC_4x4:
+            texture = new THREE.CompressedTexture( mipmaps, width, height, THREE.BasisTextureLoader.COMPRESSED_RGBA_ASTC_4x4_KHR );
+            break;
+          case THREE.BasisTextureLoader.BASIS_FORMAT.cTFBC1:
+          case THREE.BasisTextureLoader.BASIS_FORMAT.cTFBC3:
+            texture = new THREE.CompressedTexture( mipmaps, width, height, THREE.BasisTextureLoader.DXT_FORMAT_MAP[ config.format ], THREE.UnsignedByteType );
+            break;
+          case THREE.BasisTextureLoader.BASIS_FORMAT.cTFETC1:
+            texture = new THREE.CompressedTexture( mipmaps, width, height, THREE.RGB_ETC1_Format );
+            break;
+          case THREE.BasisTextureLoader.BASIS_FORMAT.cTFPVRTC1_4_RGB:
+            texture = new THREE.CompressedTexture( mipmaps, width, height, THREE.RGB_PVRTC_4BPPV1_Format );
+            break;
+          case THREE.BasisTextureLoader.BASIS_FORMAT.cTFPVRTC1_4_RGBA:
+            texture = new THREE.CompressedTexture( mipmaps, width, height, THREE.RGBA_PVRTC_4BPPV1_Format );
+            break;
+          default:
+              throw new Error( 'THREE.BasisTextureLoader: No supported format available.' );
+        }
 
-  }
-}
+				texture.minFilter = mipmaps.length === 1 ? THREE.LinearFilter : THREE.LinearMipmapLinearFilter;
+				texture.magFilter = THREE.LinearFilter;
+				texture.generateMipmaps = false;
+				texture.needsUpdate = true;
 
-const BASIS_FORMAT = {
-  cTFETC1: 0,
-  cTFBC1: 1,
-  cTFBC4: 2,
-  cTFPVRTC1_4_OPAQUE_ONLY: 3,
-  cTFBC7_M6_OPAQUE_ONLY: 4,
-  cTFETC2: 5,
-  cTFBC3: 6,
-  cTFBC5: 7,
+				return texture;
+
+			} );
+
+		texturePending
+			.finally( () => {
+
+				if ( worker && taskID ) {
+
+					worker._taskLoad -= worker._taskCosts[ taskID ];
+					delete worker._callbacks[ taskID ];
+					delete worker._taskCosts[ taskID ];
+
+				}
+
+			} );
+
+		return texturePending;
+
+	},
+
+	_initTranscoder: function () {
+
+		if ( ! this.transcoderBinary ) {
+
+			// Load transcoder wrapper.
+			var jsLoader = new THREE.FileLoader( this.manager );
+			jsLoader.setPath( this.transcoderPath );
+			var jsContent = new Promise( ( resolve, reject ) => {
+
+				jsLoader.load( 'basis_transcoder.js', resolve, undefined, reject );
+
+			} );
+
+			// Load transcoder WASM binary.
+			var binaryLoader = new THREE.FileLoader( this.manager );
+			binaryLoader.setPath( this.transcoderPath );
+			binaryLoader.setResponseType( 'arraybuffer' );
+			var binaryContent = new Promise( ( resolve, reject ) => {
+
+				binaryLoader.load( 'basis_transcoder.wasm', resolve, undefined, reject );
+
+			} );
+
+			this.transcoderPending = Promise.all( [ jsContent, binaryContent ] )
+				.then( ( [ jsContent, binaryContent ] ) => {
+
+					var fn = THREE.BasisTextureLoader.BasisWorker.toString();
+
+					var body = [
+						'/* basis_transcoder.js */',
+						jsContent,
+						'/* worker */',
+						fn.substring( fn.indexOf( '{' ) + 1, fn.lastIndexOf( '}' ) )
+					].join( '\n' );
+
+					this.workerSourceURL = URL.createObjectURL( new Blob( [ body ] ) );
+					this.transcoderBinary = binaryContent;
+
+				} );
+
+		}
+
+		return this.transcoderPending;
+
+	},
+
+	_getWorker: function () {
+
+		return this._initTranscoder().then( () => {
+
+			if ( this.workerPool.length < this.workerLimit ) {
+
+				var worker = new Worker( this.workerSourceURL );
+
+				worker._callbacks = {};
+				worker._taskCosts = {};
+				worker._taskLoad = 0;
+
+        this.workerConfig.useAlpha = this.useAlpha;
+				worker.postMessage( {
+					type: 'init',
+					config: this.workerConfig,
+					transcoderBinary: this.transcoderBinary,
+				} );
+
+				worker.onmessage = function ( e ) {
+
+					var message = e.data;
+
+					switch ( message.type ) {
+
+						case 'transcode':
+							worker._callbacks[ message.id ].resolve( message );
+							break;
+
+						case 'error':
+							worker._callbacks[ message.id ].reject( message );
+							break;
+
+						default:
+							console.error( 'THREE.BasisTextureLoader: Unexpected message, "' + message.type + '"' );
+
+					}
+
+				};
+
+				this.workerPool.push( worker );
+
+			} else {
+
+				this.workerPool.sort( function ( a, b ) {
+
+					return a._taskLoad > b._taskLoad ? - 1 : 1;
+
+				} );
+
+			}
+
+			return this.workerPool[ this.workerPool.length - 1 ];
+
+		} );
+
+	},
+
+	dispose: function () {
+
+		for ( var i = 0; i < this.workerPool.length; i ++ ) {
+
+			this.workerPool[ i ].terminate();
+
+		}
+
+		this.workerPool.length = 0;
+
+		return this;
+
+	}
+
+} );
+
+/* CONSTANTS */
+
+THREE.BasisTextureLoader.BASIS_FORMAT = {
+	cTFETC1: 0,
+	cTFETC2: 1,
+	cTFBC1: 2,
+	cTFBC3: 3,
+	cTFBC4: 4,
+	cTFBC5: 5,
+	cTFBC7_M6_OPAQUE_ONLY: 6,
+  cTFBC7_M5: 7,
+  cTFPVRTC1_4_RGB: 8,
+  cTFPVRTC1_4_RGBA: 9,
+  cTFASTC_4x4: 10,
+  cTFATC_RGB: 11,
+  cTFATC_RGBA_INTERPOLATED_ALPHA: 12,
+  cTFRGBA32: 13,
+  cTFRGB565: 14,
+  cTFBGR565: 15,
+  cTFRGBA4444: 16,
 };
 
 // DXT formats, from:
 // http://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/
-const DXT_FORMAT_MAP = {};
-const COMPRESSED_RGB_S3TC_DXT1_EXT  = 0x83F0;
-const COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1;
-const COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2;
-const COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3;
-DXT_FORMAT_MAP[ BASIS_FORMAT.cTFBC1 ] = COMPRESSED_RGB_S3TC_DXT1_EXT;
-DXT_FORMAT_MAP[ BASIS_FORMAT.cTFBC3 ] = COMPRESSED_RGBA_S3TC_DXT5_EXT;
+THREE.BasisTextureLoader.DXT_FORMAT = {
+	COMPRESSED_RGB_S3TC_DXT1_EXT: 0x83F0,
+	COMPRESSED_RGBA_S3TC_DXT1_EXT: 0x83F1,
+	COMPRESSED_RGBA_S3TC_DXT3_EXT: 0x83F2,
+	COMPRESSED_RGBA_S3TC_DXT5_EXT: 0x83F3,
+};
+THREE.BasisTextureLoader.DXT_FORMAT_MAP = {};
+THREE.BasisTextureLoader.DXT_FORMAT_MAP[ THREE.BasisTextureLoader.BASIS_FORMAT.cTFBC1 ] =
+	THREE.BasisTextureLoader.DXT_FORMAT.COMPRESSED_RGB_S3TC_DXT1_EXT;
+THREE.BasisTextureLoader.DXT_FORMAT_MAP[ THREE.BasisTextureLoader.BASIS_FORMAT.cTFBC3 ] =
+  THREE.BasisTextureLoader.DXT_FORMAT.COMPRESSED_RGBA_S3TC_DXT5_EXT;
 
-THREE.BasisTextureLoader.BASIS_FORMAT = BASIS_FORMAT;
-THREE.BasisTextureLoader.DXT_FORMAT_MAP = DXT_FORMAT_MAP;
+// ASTC formats, from:
+// https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_astc/
+THREE.BasisTextureLoader.COMPRESSED_RGBA_ASTC_4x4_KHR = 0x93B0;
+
+/* WEB WORKER */
+
+THREE.BasisTextureLoader.BasisWorker = function () {
+
+	var config;
+	var transcoderPending;
+	var _BasisFile;
+
+	onmessage = function ( e ) {
+
+		var message = e.data;
+
+		switch ( message.type ) {
+
+			case 'init':
+				config = message.config;
+				init( message.transcoderBinary );
+				break;
+
+			case 'transcode':
+				transcoderPending.then( () => {
+
+					try {
+
+						var { width, height, hasAlpha, mipmaps } = transcode( message.buffer );
+
+						var buffers = [];
+
+						for ( var i = 0; i < mipmaps.length; ++ i ) {
+
+							buffers.push( mipmaps[ i ].data.buffer );
+
+						}
+
+						self.postMessage( { type: 'transcode', id: message.id, width, height, hasAlpha, mipmaps }, buffers );
+
+					} catch ( error ) {
+
+						console.error( error );
+
+						self.postMessage( { type: 'error', id: message.id, error: error.message } );
+
+					}
+
+				} );
+				break;
+
+		}
+
+	};
+
+	function init( wasmBinary ) {
+
+    var m;
+    transcoderPending = new Promise( ( resolve ) => {
+
+      m = { wasmBinary, onRuntimeInitialized: resolve };
+			BASIS(m);
+
+		} ).then( () => {
+
+      var { BasisFile, initializeBasis } = m;
+
+			_BasisFile = BasisFile;
+
+			initializeBasis();
+
+		} );
+
+	}
+
+	function transcode( buffer ) {
+
+		var basisFile = new _BasisFile( new Uint8Array( buffer ) );
+
+		var width = basisFile.getImageWidth( 0, 0 );
+		var height = basisFile.getImageHeight( 0, 0 );
+    var levels = basisFile.getNumLevels( 0 );
+    var hasAlpha = basisFile.getHasAlpha();
+
+		function cleanup() {
+
+			basisFile.close();
+			basisFile.delete();
+
+		}
+
+		if ( ! width || ! height || ! levels ) {
+
+			cleanup();
+			throw new Error( 'THREE.BasisTextureLoader:  Invalid .basis file' );
+
+		}
+
+		if ( ! basisFile.startTranscoding() ) {
+
+			cleanup();
+			throw new Error( 'THREE.BasisTextureLoader: .startTranscoding failed' );
+
+		}
+
+		var mipmaps = [];
+
+		for ( var mip = 0; mip < levels; mip ++ ) {
+
+			var mipWidth = basisFile.getImageWidth( 0, mip );
+			var mipHeight = basisFile.getImageHeight( 0, mip );
+			var dst = new Uint8Array( basisFile.getImageTranscodedSizeInBytes( 0, mip, config.format ) );
+
+			var status = basisFile.transcodeImage(
+				dst,
+				0,
+				mip,
+        config.format,
+        config.useAlpha,
+				0
+			);
+
+			if ( ! status ) {
+
+				cleanup();
+				throw new Error( 'THREE.BasisTextureLoader: .transcodeImage failed.' );
+
+			}
+
+			mipmaps.push( { data: dst, width: mipWidth, height: mipHeight } );
+
+		}
+
+		cleanup();
+
+		return { width, height, hasAlpha, mipmaps };
+
+	}
+
+};
\ No newline at end of file
diff --git a/webgl/gltf/GLTFLoader.js b/webgl/gltf/GLTFLoader.js
index 31bc8af..9e11b42 100644
--- a/webgl/gltf/GLTFLoader.js
+++ b/webgl/gltf/GLTFLoader.js
@@ -1,9 +1,4 @@
 /**
- * Copyright 2019 the three.js authors
- * SPDX-License-Identifier: MIT
- */
-
-/**
  * @author Rich Tibbett / https://github.com/richtr
  * @author mrdoob / http://mrdoob.com/
  * @author Tony Parisi / http://www.tonyparisi.com/
@@ -11,7 +6,7 @@
  * @author Don McCurdy / https://www.donmccurdy.com
  */
 
-/**
+ /**
  * A modified version of THREE.GLTFLoader, with support for the (hypothetical)
  * GOOGLE_texture_basis extension. This extension is defined for the sake of
  * example only – the glTF format will officially reference Basis files within
@@ -19,298 +14,311 @@
  */
 THREE.GLTFLoader = ( function () {
 
-  function GLTFLoader( manager ) {
+	function GLTFLoader( manager ) {
 
-    this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
-    this.dracoLoader = null;
+		this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
+		this.dracoLoader = null;
+		this.ddsLoader = null;
 
-  }
+	}
 
-  GLTFLoader.prototype = {
+	GLTFLoader.prototype = {
 
-    constructor: GLTFLoader,
+		constructor: GLTFLoader,
 
-    crossOrigin: 'anonymous',
+		crossOrigin: 'anonymous',
 
-    load: function ( url, onLoad, onProgress, onError ) {
+		load: function ( url, onLoad, onProgress, onError ) {
 
-      var scope = this;
+			var scope = this;
 
-      var resourcePath;
+			var resourcePath;
 
-      if ( this.resourcePath !== undefined ) {
+			if ( this.resourcePath !== undefined ) {
 
-        resourcePath = this.resourcePath;
+				resourcePath = this.resourcePath;
 
-      } else if ( this.path !== undefined ) {
+			} else if ( this.path !== undefined ) {
 
-        resourcePath = this.path;
+				resourcePath = this.path;
 
-      } else {
+			} else {
 
-        resourcePath = THREE.LoaderUtils.extractUrlBase( url );
+				resourcePath = THREE.LoaderUtils.extractUrlBase( url );
 
-      }
+			}
 
-      // Tells the LoadingManager to track an extra item, which resolves after
-      // the model is fully loaded. This means the count of items loaded will
-      // be incorrect, but ensures manager.onLoad() does not fire early.
-      scope.manager.itemStart( url );
+			// Tells the LoadingManager to track an extra item, which resolves after
+			// the model is fully loaded. This means the count of items loaded will
+			// be incorrect, but ensures manager.onLoad() does not fire early.
+			scope.manager.itemStart( url );
 
-      var _onError = function ( e ) {
+			var _onError = function ( e ) {
 
-        if ( onError ) {
+				if ( onError ) {
 
-          onError( e );
+					onError( e );
 
-        } else {
+				} else {
 
-          console.error( e );
+					console.error( e );
 
-        }
+				}
 
-        scope.manager.itemError( url );
-        scope.manager.itemEnd( url );
+				scope.manager.itemError( url );
+				scope.manager.itemEnd( url );
 
-      };
+			};
 
-      var loader = new THREE.FileLoader( scope.manager );
+			var loader = new THREE.FileLoader( scope.manager );
 
-      loader.setPath( this.path );
-      loader.setResponseType( 'arraybuffer' );
+			loader.setPath( this.path );
+			loader.setResponseType( 'arraybuffer' );
 
-      loader.load( url, function ( data ) {
+			if ( scope.crossOrigin === 'use-credentials' ) {
 
-        try {
+				loader.setWithCredentials( true );
 
-          scope.parse( data, resourcePath, function ( gltf ) {
+			}
 
-            onLoad( gltf );
+			loader.load( url, function ( data ) {
 
-            scope.manager.itemEnd( url );
+				try {
 
-          }, _onError );
+					scope.parse( data, resourcePath, function ( gltf ) {
 
-        } catch ( e ) {
+						onLoad( gltf );
 
-          _onError( e );
+						scope.manager.itemEnd( url );
 
-        }
+					}, _onError );
 
-      }, onProgress, _onError );
+				} catch ( e ) {
 
-    },
+					_onError( e );
 
-    setCrossOrigin: function ( value ) {
+				}
 
-      this.crossOrigin = value;
-      return this;
+			}, onProgress, _onError );
 
-    },
+		},
 
-    setPath: function ( value ) {
+		setCrossOrigin: function ( value ) {
+
+			this.crossOrigin = value;
+			return this;
+
+		},
+
+		setPath: function ( value ) {
+
+			this.path = value;
+			return this;
+
+		},
+
+		setResourcePath: function ( value ) {
 
-      this.path = value;
-      return this;
+			this.resourcePath = value;
+			return this;
 
-    },
+		},
 
-    setResourcePath: function ( value ) {
+		setDRACOLoader: function ( dracoLoader ) {
 
-      this.resourcePath = value;
-      return this;
+			this.dracoLoader = dracoLoader;
+			return this;
 
-    },
+		},
 
-    setDRACOLoader: function ( dracoLoader ) {
+		setDDSLoader: function ( ddsLoader ) {
 
-      this.dracoLoader = dracoLoader;
-      return this;
+			this.ddsLoader = ddsLoader;
+			return this;
 
-    },
+		},
 
-    parse: function ( data, path, onLoad, onError ) {
+		parse: function ( data, path, onLoad, onError ) {
 
-      var content;
-      var extensions = {};
+			var content;
+			var extensions = {};
 
-      if ( typeof data === 'string' ) {
+			if ( typeof data === 'string' ) {
 
-        content = data;
+				content = data;
 
-      } else {
+			} else {
 
-        var magic = THREE.LoaderUtils.decodeText( new Uint8Array( data, 0, 4 ) );
+				var magic = THREE.LoaderUtils.decodeText( new Uint8Array( data, 0, 4 ) );
 
-        if ( magic === BINARY_EXTENSION_HEADER_MAGIC ) {
+				if ( magic === BINARY_EXTENSION_HEADER_MAGIC ) {
 
-          try {
+					try {
 
-            extensions[ EXTENSIONS.KHR_BINARY_GLTF ] = new GLTFBinaryExtension( data );
+						extensions[ EXTENSIONS.KHR_BINARY_GLTF ] = new GLTFBinaryExtension( data );
 
-          } catch ( error ) {
+					} catch ( error ) {
 
-            if ( onError ) onError( error );
-            return;
+						if ( onError ) onError( error );
+						return;
 
-          }
+					}
 
-          content = extensions[ EXTENSIONS.KHR_BINARY_GLTF ].content;
+					content = extensions[ EXTENSIONS.KHR_BINARY_GLTF ].content;
 
-        } else {
+				} else {
 
-          content = THREE.LoaderUtils.decodeText( new Uint8Array( data ) );
+					content = THREE.LoaderUtils.decodeText( new Uint8Array( data ) );
 
-        }
+				}
 
-      }
+			}
 
-      var json = JSON.parse( content );
+			var json = JSON.parse( content );
 
-      if ( json.asset === undefined || json.asset.version[ 0 ] < 2 ) {
+			if ( json.asset === undefined || json.asset.version[ 0 ] < 2 ) {
 
-        if ( onError ) onError( new Error( 'THREE.GLTFLoader: Unsupported asset. glTF versions >=2.0 are supported. Use LegacyGLTFLoader instead.' ) );
-        return;
+				if ( onError ) onError( new Error( 'THREE.GLTFLoader: Unsupported asset. glTF versions >=2.0 are supported. Use LegacyGLTFLoader instead.' ) );
+				return;
 
-      }
+			}
 
-      if ( json.extensionsUsed ) {
+			if ( json.extensionsUsed ) {
 
-        for ( var i = 0; i < json.extensionsUsed.length; ++ i ) {
+				for ( var i = 0; i < json.extensionsUsed.length; ++ i ) {
 
-          var extensionName = json.extensionsUsed[ i ];
-          var extensionsRequired = json.extensionsRequired || [];
+					var extensionName = json.extensionsUsed[ i ];
+					var extensionsRequired = json.extensionsRequired || [];
 
-          switch ( extensionName ) {
+					switch ( extensionName ) {
 
-            case EXTENSIONS.KHR_LIGHTS_PUNCTUAL:
-              extensions[ extensionName ] = new GLTFLightsExtension( json );
-              break;
+						case EXTENSIONS.KHR_LIGHTS_PUNCTUAL:
+							extensions[ extensionName ] = new GLTFLightsExtension( json );
+							break;
 
-            case EXTENSIONS.KHR_MATERIALS_UNLIT:
-              extensions[ extensionName ] = new GLTFMaterialsUnlitExtension( json );
-              break;
+						case EXTENSIONS.KHR_MATERIALS_UNLIT:
+							extensions[ extensionName ] = new GLTFMaterialsUnlitExtension();
+							break;
 
-            case EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS:
-              extensions[ extensionName ] = new GLTFMaterialsPbrSpecularGlossinessExtension( json );
-              break;
+						case EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS:
+							extensions[ extensionName ] = new GLTFMaterialsPbrSpecularGlossinessExtension();
+							break;
 
-            case EXTENSIONS.KHR_DRACO_MESH_COMPRESSION:
-              extensions[ extensionName ] = new GLTFDracoMeshCompressionExtension( json, this.dracoLoader );
-              break;
+						case EXTENSIONS.KHR_DRACO_MESH_COMPRESSION:
+							extensions[ extensionName ] = new GLTFDracoMeshCompressionExtension( json, this.dracoLoader );
+							break;
 
-            case EXTENSIONS.MSFT_TEXTURE_DDS:
-              extensions[ EXTENSIONS.MSFT_TEXTURE_DDS ] = new GLTFTextureDDSExtension();
-              break;
+						case EXTENSIONS.MSFT_TEXTURE_DDS:
+							extensions[ EXTENSIONS.MSFT_TEXTURE_DDS ] = new GLTFTextureDDSExtension( this.ddsLoader );
+							break;
 
             case EXTENSIONS.GOOGLE_TEXTURE_BASIS:
               extensions[ EXTENSIONS.GOOGLE_TEXTURE_BASIS ] = new GLTFTextureBasisExtension();
               break;
+						case EXTENSIONS.KHR_TEXTURE_TRANSFORM:
+							extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] = new GLTFTextureTransformExtension();
+							break;
 
-            case EXTENSIONS.KHR_TEXTURE_TRANSFORM:
-              extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] = new GLTFTextureTransformExtension( json );
-              break;
+						default:
 
-            default:
+							if ( extensionsRequired.indexOf( extensionName ) >= 0 ) {
 
-              if ( extensionsRequired.indexOf( extensionName ) >= 0 ) {
+								console.warn( 'THREE.GLTFLoader: Unknown extension "' + extensionName + '".' );
 
-                console.warn( 'THREE.GLTFLoader: Unknown extension "' + extensionName + '".' );
+							}
 
-              }
+					}
 
-          }
+				}
 
-        }
+			}
 
-      }
+			var parser = new GLTFParser( json, extensions, {
 
-      var parser = new GLTFParser( json, extensions, {
+				path: path || this.resourcePath || '',
+				crossOrigin: this.crossOrigin,
+				manager: this.manager
 
-        path: path || this.resourcePath || '',
-        crossOrigin: this.crossOrigin,
-        manager: this.manager
+			} );
 
-      } );
+			parser.parse( onLoad, onError );
 
-      parser.parse( onLoad, onError );
+		}
 
-    }
+	};
 
-  };
+	/* GLTFREGISTRY */
 
-  /* GLTFREGISTRY */
+	function GLTFRegistry() {
 
-  function GLTFRegistry() {
+		var objects = {};
 
-    var objects = {};
+		return	{
 
-    return  {
+			get: function ( key ) {
 
-      get: function ( key ) {
+				return objects[ key ];
 
-        return objects[ key ];
+			},
 
-      },
+			add: function ( key, object ) {
 
-      add: function ( key, object ) {
+				objects[ key ] = object;
 
-        objects[ key ] = object;
+			},
 
-      },
+			remove: function ( key ) {
 
-      remove: function ( key ) {
+				delete objects[ key ];
 
-        delete objects[ key ];
+			},
 
-      },
+			removeAll: function () {
 
-      removeAll: function () {
+				objects = {};
 
-        objects = {};
+			}
 
-      }
+		};
 
-    };
+	}
 
-  }
+	/*********************************/
+	/********** EXTENSIONS ***********/
+	/*********************************/
 
-  /*********************************/
-  /********** EXTENSIONS ***********/
-  /*********************************/
-
-  var EXTENSIONS = {
-    KHR_BINARY_GLTF: 'KHR_binary_glTF',
-    KHR_DRACO_MESH_COMPRESSION: 'KHR_draco_mesh_compression',
-    KHR_LIGHTS_PUNCTUAL: 'KHR_lights_punctual',
-    KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS: 'KHR_materials_pbrSpecularGlossiness',
-    KHR_MATERIALS_UNLIT: 'KHR_materials_unlit',
-    KHR_TEXTURE_TRANSFORM: 'KHR_texture_transform',
+	var EXTENSIONS = {
+		KHR_BINARY_GLTF: 'KHR_binary_glTF',
+		KHR_DRACO_MESH_COMPRESSION: 'KHR_draco_mesh_compression',
+		KHR_LIGHTS_PUNCTUAL: 'KHR_lights_punctual',
+		KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS: 'KHR_materials_pbrSpecularGlossiness',
+		KHR_MATERIALS_UNLIT: 'KHR_materials_unlit',
+		KHR_TEXTURE_TRANSFORM: 'KHR_texture_transform',
     MSFT_TEXTURE_DDS: 'MSFT_texture_dds',
     GOOGLE_TEXTURE_BASIS: 'GOOGLE_texture_basis'
-  };
+	};
 
-  /**
-   * DDS Texture Extension
-   *
-   * Specification:
-   * https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_texture_dds
-   *
-   */
-  function GLTFTextureDDSExtension() {
+	/**
+	 * DDS Texture Extension
+	 *
+	 * Specification:
+	 * https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_texture_dds
+	 *
+	 */
+	function GLTFTextureDDSExtension( ddsLoader ) {
 
-    if ( ! THREE.DDSLoader ) {
+		if ( ! ddsLoader ) {
 
-      throw new Error( 'THREE.GLTFLoader: Attempting to load .dds texture without importing THREE.DDSLoader' );
+			throw new Error( 'THREE.GLTFLoader: Attempting to load .dds texture without importing THREE.DDSLoader' );
 
-    }
+		}
 
-    this.name = EXTENSIONS.MSFT_TEXTURE_DDS;
-    this.ddsLoader = new THREE.DDSLoader();
+		this.name = EXTENSIONS.MSFT_TEXTURE_DDS;
+		this.ddsLoader = ddsLoader;
 
-  }
+	}
 
-  /**
+    /**
    * Basis Texture Extension
    *
    */
@@ -320,2895 +328,2911 @@
 
   }
 
-  /**
-   * Lights Extension
-   *
-   * Specification: PENDING
-   */
-  function GLTFLightsExtension( json ) {
+	/**
+	 * Lights Extension
+	 *
+	 * Specification: PENDING
+	 */
+	function GLTFLightsExtension( json ) {
 
-    this.name = EXTENSIONS.KHR_LIGHTS_PUNCTUAL;
+		this.name = EXTENSIONS.KHR_LIGHTS_PUNCTUAL;
 
-    var extension = ( json.extensions && json.extensions[ EXTENSIONS.KHR_LIGHTS_PUNCTUAL ] ) || {};
-    this.lightDefs = extension.lights || [];
+		var extension = ( json.extensions && json.extensions[ EXTENSIONS.KHR_LIGHTS_PUNCTUAL ] ) || {};
+		this.lightDefs = extension.lights || [];
 
-  }
+	}
 
-  GLTFLightsExtension.prototype.loadLight = function ( lightIndex ) {
+	GLTFLightsExtension.prototype.loadLight = function ( lightIndex ) {
 
-    var lightDef = this.lightDefs[ lightIndex ];
-    var lightNode;
+		var lightDef = this.lightDefs[ lightIndex ];
+		var lightNode;
 
-    var color = new THREE.Color( 0xffffff );
-    if ( lightDef.color !== undefined ) color.fromArray( lightDef.color );
+		var color = new THREE.Color( 0xffffff );
+		if ( lightDef.color !== undefined ) color.fromArray( lightDef.color );
 
-    var range = lightDef.range !== undefined ? lightDef.range : 0;
+		var range = lightDef.range !== undefined ? lightDef.range : 0;
 
-    switch ( lightDef.type ) {
+		switch ( lightDef.type ) {
 
-      case 'directional':
-        lightNode = new THREE.DirectionalLight( color );
-        lightNode.target.position.set( 0, 0, - 1 );
-        lightNode.add( lightNode.target );
-        break;
+			case 'directional':
+				lightNode = new THREE.DirectionalLight( color );
+				lightNode.target.position.set( 0, 0, - 1 );
+				lightNode.add( lightNode.target );
+				break;
 
-      case 'point':
-        lightNode = new THREE.PointLight( color );
-        lightNode.distance = range;
-        break;
+			case 'point':
+				lightNode = new THREE.PointLight( color );
+				lightNode.distance = range;
+				break;
 
-      case 'spot':
-        lightNode = new THREE.SpotLight( color );
-        lightNode.distance = range;
-        // Handle spotlight properties.
-        lightDef.spot = lightDef.spot || {};
-        lightDef.spot.innerConeAngle = lightDef.spot.innerConeAngle !== undefined ? lightDef.spot.innerConeAngle : 0;
-        lightDef.spot.outerConeAngle = lightDef.spot.outerConeAngle !== undefined ? lightDef.spot.outerConeAngle : Math.PI / 4.0;
-        lightNode.angle = lightDef.spot.outerConeAngle;
-        lightNode.penumbra = 1.0 - lightDef.spot.innerConeAngle / lightDef.spot.outerConeAngle;
-        lightNode.target.position.set( 0, 0, - 1 );
-        lightNode.add( lightNode.target );
-        break;
+			case 'spot':
+				lightNode = new THREE.SpotLight( color );
+				lightNode.distance = range;
+				// Handle spotlight properties.
+				lightDef.spot = lightDef.spot || {};
+				lightDef.spot.innerConeAngle = lightDef.spot.innerConeAngle !== undefined ? lightDef.spot.innerConeAngle : 0;
+				lightDef.spot.outerConeAngle = lightDef.spot.outerConeAngle !== undefined ? lightDef.spot.outerConeAngle : Math.PI / 4.0;
+				lightNode.angle = lightDef.spot.outerConeAngle;
+				lightNode.penumbra = 1.0 - lightDef.spot.innerConeAngle / lightDef.spot.outerConeAngle;
+				lightNode.target.position.set( 0, 0, - 1 );
+				lightNode.add( lightNode.target );
+				break;
 
-      default:
-        throw new Error( 'THREE.GLTFLoader: Unexpected light type, "' + lightDef.type + '".' );
+			default:
+				throw new Error( 'THREE.GLTFLoader: Unexpected light type, "' + lightDef.type + '".' );
 
-    }
+		}
 
-    // Some lights (e.g. spot) default to a position other than the origin. Reset the position
-    // here, because node-level parsing will only override position if explicitly specified.
-    lightNode.position.set( 0, 0, 0 );
+		// Some lights (e.g. spot) default to a position other than the origin. Reset the position
+		// here, because node-level parsing will only override position if explicitly specified.
+		lightNode.position.set( 0, 0, 0 );
 
-    lightNode.decay = 2;
+		lightNode.decay = 2;
 
-    if ( lightDef.intensity !== undefined ) lightNode.intensity = lightDef.intensity;
+		if ( lightDef.intensity !== undefined ) lightNode.intensity = lightDef.intensity;
 
-    lightNode.name = lightDef.name || ( 'light_' + lightIndex );
+		lightNode.name = lightDef.name || ( 'light_' + lightIndex );
 
-    return Promise.resolve( lightNode );
+		return Promise.resolve( lightNode );
 
-  };
+	};
 
-  /**
-   * Unlit Materials Extension (pending)
-   *
-   * PR: https://github.com/KhronosGroup/glTF/pull/1163
-   */
-  function GLTFMaterialsUnlitExtension() {
+	/**
+	 * Unlit Materials Extension (pending)
+	 *
+	 * PR: https://github.com/KhronosGroup/glTF/pull/1163
+	 */
+	function GLTFMaterialsUnlitExtension() {
 
-    this.name = EXTENSIONS.KHR_MATERIALS_UNLIT;
+		this.name = EXTENSIONS.KHR_MATERIALS_UNLIT;
 
-  }
+	}
 
-  GLTFMaterialsUnlitExtension.prototype.getMaterialType = function () {
+	GLTFMaterialsUnlitExtension.prototype.getMaterialType = function () {
 
-    return THREE.MeshBasicMaterial;
+		return THREE.MeshBasicMaterial;
 
-  };
+	};
 
-  GLTFMaterialsUnlitExtension.prototype.extendParams = function ( materialParams, materialDef, parser ) {
+	GLTFMaterialsUnlitExtension.prototype.extendParams = function ( materialParams, materialDef, parser ) {
 
-    var pending = [];
+		var pending = [];
 
-    materialParams.color = new THREE.Color( 1.0, 1.0, 1.0 );
-    materialParams.opacity = 1.0;
+		materialParams.color = new THREE.Color( 1.0, 1.0, 1.0 );
+		materialParams.opacity = 1.0;
 
-    var metallicRoughness = materialDef.pbrMetallicRoughness;
+		var metallicRoughness = materialDef.pbrMetallicRoughness;
 
-    if ( metallicRoughness ) {
+		if ( metallicRoughness ) {
 
-      if ( Array.isArray( metallicRoughness.baseColorFactor ) ) {
+			if ( Array.isArray( metallicRoughness.baseColorFactor ) ) {
 
-        var array = metallicRoughness.baseColorFactor;
+				var array = metallicRoughness.baseColorFactor;
 
-        materialParams.color.fromArray( array );
-        materialParams.opacity = array[ 3 ];
+				materialParams.color.fromArray( array );
+				materialParams.opacity = array[ 3 ];
 
-      }
+			}
 
-      if ( metallicRoughness.baseColorTexture !== undefined ) {
+			if ( metallicRoughness.baseColorTexture !== undefined ) {
 
-        pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture ) );
+				pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture ) );
 
-      }
+			}
 
-    }
+		}
 
-    return Promise.all( pending );
+		return Promise.all( pending );
 
-  };
+	};
 
-  /* BINARY EXTENSION */
+	/* BINARY EXTENSION */
+	var BINARY_EXTENSION_HEADER_MAGIC = 'glTF';
+	var BINARY_EXTENSION_HEADER_LENGTH = 12;
+	var BINARY_EXTENSION_CHUNK_TYPES = { JSON: 0x4E4F534A, BIN: 0x004E4942 };
 
-  var BINARY_EXTENSION_BUFFER_NAME = 'binary_glTF';
-  var BINARY_EXTENSION_HEADER_MAGIC = 'glTF';
-  var BINARY_EXTENSION_HEADER_LENGTH = 12;
-  var BINARY_EXTENSION_CHUNK_TYPES = { JSON: 0x4E4F534A, BIN: 0x004E4942 };
+	function GLTFBinaryExtension( data ) {
 
-  function GLTFBinaryExtension( data ) {
+		this.name = EXTENSIONS.KHR_BINARY_GLTF;
+		this.content = null;
+		this.body = null;
 
-    this.name = EXTENSIONS.KHR_BINARY_GLTF;
-    this.content = null;
-    this.body = null;
+		var headerView = new DataView( data, 0, BINARY_EXTENSION_HEADER_LENGTH );
 
-    var headerView = new DataView( data, 0, BINARY_EXTENSION_HEADER_LENGTH );
+		this.header = {
+			magic: THREE.LoaderUtils.decodeText( new Uint8Array( data.slice( 0, 4 ) ) ),
+			version: headerView.getUint32( 4, true ),
+			length: headerView.getUint32( 8, true )
+		};
 
-    this.header = {
-      magic: THREE.LoaderUtils.decodeText( new Uint8Array( data.slice( 0, 4 ) ) ),
-      version: headerView.getUint32( 4, true ),
-      length: headerView.getUint32( 8, true )
-    };
+		if ( this.header.magic !== BINARY_EXTENSION_HEADER_MAGIC ) {
 
-    if ( this.header.magic !== BINARY_EXTENSION_HEADER_MAGIC ) {
+			throw new Error( 'THREE.GLTFLoader: Unsupported glTF-Binary header.' );
 
-      throw new Error( 'THREE.GLTFLoader: Unsupported glTF-Binary header.' );
+		} else if ( this.header.version < 2.0 ) {
 
-    } else if ( this.header.version < 2.0 ) {
+			throw new Error( 'THREE.GLTFLoader: Legacy binary file detected. Use LegacyGLTFLoader instead.' );
 
-      throw new Error( 'THREE.GLTFLoader: Legacy binary file detected. Use LegacyGLTFLoader instead.' );
+		}
 
-    }
+		var chunkView = new DataView( data, BINARY_EXTENSION_HEADER_LENGTH );
+		var chunkIndex = 0;
 
-    var chunkView = new DataView( data, BINARY_EXTENSION_HEADER_LENGTH );
-    var chunkIndex = 0;
+		while ( chunkIndex < chunkView.byteLength ) {
 
-    while ( chunkIndex < chunkView.byteLength ) {
+			var chunkLength = chunkView.getUint32( chunkIndex, true );
+			chunkIndex += 4;
 
-      var chunkLength = chunkView.getUint32( chunkIndex, true );
-      chunkIndex += 4;
+			var chunkType = chunkView.getUint32( chunkIndex, true );
+			chunkIndex += 4;
 
-      var chunkType = chunkView.getUint32( chunkIndex, true );
-      chunkIndex += 4;
+			if ( chunkType === BINARY_EXTENSION_CHUNK_TYPES.JSON ) {
 
-      if ( chunkType === BINARY_EXTENSION_CHUNK_TYPES.JSON ) {
+				var contentArray = new Uint8Array( data, BINARY_EXTENSION_HEADER_LENGTH + chunkIndex, chunkLength );
+				this.content = THREE.LoaderUtils.decodeText( contentArray );
 
-        var contentArray = new Uint8Array( data, BINARY_EXTENSION_HEADER_LENGTH + chunkIndex, chunkLength );
-        this.content = THREE.LoaderUtils.decodeText( contentArray );
+			} else if ( chunkType === BINARY_EXTENSION_CHUNK_TYPES.BIN ) {
 
-      } else if ( chunkType === BINARY_EXTENSION_CHUNK_TYPES.BIN ) {
+				var byteOffset = BINARY_EXTENSION_HEADER_LENGTH + chunkIndex;
+				this.body = data.slice( byteOffset, byteOffset + chunkLength );
 
-        var byteOffset = BINARY_EXTENSION_HEADER_LENGTH + chunkIndex;
-        this.body = data.slice( byteOffset, byteOffset + chunkLength );
+			}
 
-      }
+			// Clients must ignore chunks with unknown types.
 
-      // Clients must ignore chunks with unknown types.
+			chunkIndex += chunkLength;
 
-      chunkIndex += chunkLength;
+		}
 
-    }
+		if ( this.content === null ) {
 
-    if ( this.content === null ) {
+			throw new Error( 'THREE.GLTFLoader: JSON content not found.' );
 
-      throw new Error( 'THREE.GLTFLoader: JSON content not found.' );
+		}
 
-    }
+	}
 
-  }
+	/**
+	 * DRACO Mesh Compression Extension
+	 *
+	 * Specification: https://github.com/KhronosGroup/glTF/pull/874
+	 */
+	function GLTFDracoMeshCompressionExtension( json, dracoLoader ) {
 
-  /**
-   * DRACO Mesh Compression Extension
-   *
-   * Specification: https://github.com/KhronosGroup/glTF/pull/874
-   */
-  function GLTFDracoMeshCompressionExtension( json, dracoLoader ) {
+		if ( ! dracoLoader ) {
 
-    if ( ! dracoLoader ) {
+			throw new Error( 'THREE.GLTFLoader: No DRACOLoader instance provided.' );
 
-      throw new Error( 'THREE.GLTFLoader: No DRACOLoader instance provided.' );
+		}
 
-    }
+		this.name = EXTENSIONS.KHR_DRACO_MESH_COMPRESSION;
+		this.json = json;
+		this.dracoLoader = dracoLoader;
 
-    this.name = EXTENSIONS.KHR_DRACO_MESH_COMPRESSION;
-    this.json = json;
-    this.dracoLoader = dracoLoader;
+	}
 
-  }
+	GLTFDracoMeshCompressionExtension.prototype.decodePrimitive = function ( primitive, parser ) {
 
-  GLTFDracoMeshCompressionExtension.prototype.decodePrimitive = function ( primitive, parser ) {
+		var json = this.json;
+		var dracoLoader = this.dracoLoader;
+		var bufferViewIndex = primitive.extensions[ this.name ].bufferView;
+		var gltfAttributeMap = primitive.extensions[ this.name ].attributes;
+		var threeAttributeMap = {};
+		var attributeNormalizedMap = {};
+		var attributeTypeMap = {};
 
-    var json = this.json;
-    var dracoLoader = this.dracoLoader;
-    var bufferViewIndex = primitive.extensions[ this.name ].bufferView;
-    var gltfAttributeMap = primitive.extensions[ this.name ].attributes;
-    var threeAttributeMap = {};
-    var attributeNormalizedMap = {};
-    var attributeTypeMap = {};
+		for ( var attributeName in gltfAttributeMap ) {
 
-    for ( var attributeName in gltfAttributeMap ) {
+			var threeAttributeName = ATTRIBUTES[ attributeName ] || attributeName.toLowerCase();
 
-      var threeAttributeName = ATTRIBUTES[ attributeName ] || attributeName.toLowerCase();
+			threeAttributeMap[ threeAttributeName ] = gltfAttributeMap[ attributeName ];
 
-      threeAttributeMap[ threeAttributeName ] = gltfAttributeMap[ attributeName ];
+		}
 
-    }
+		for ( attributeName in primitive.attributes ) {
 
-    for ( attributeName in primitive.attributes ) {
+			var threeAttributeName = ATTRIBUTES[ attributeName ] || attributeName.toLowerCase();
 
-      var threeAttributeName = ATTRIBUTES[ attributeName ] || attributeName.toLowerCase();
+			if ( gltfAttributeMap[ attributeName ] !== undefined ) {
 
-      if ( gltfAttributeMap[ attributeName ] !== undefined ) {
+				var accessorDef = json.accessors[ primitive.attributes[ attributeName ] ];
+				var componentType = WEBGL_COMPONENT_TYPES[ accessorDef.componentType ];
 
-        var accessorDef = json.accessors[ primitive.attributes[ attributeName ] ];
-        var componentType = WEBGL_COMPONENT_TYPES[ accessorDef.componentType ];
+				attributeTypeMap[ threeAttributeName ] = componentType;
+				attributeNormalizedMap[ threeAttributeName ] = accessorDef.normalized === true;
 
-        attributeTypeMap[ threeAttributeName ] = componentType;
-        attributeNormalizedMap[ threeAttributeName ] = accessorDef.normalized === true;
+			}
 
-      }
+		}
 
-    }
+		return parser.getDependency( 'bufferView', bufferViewIndex ).then( function ( bufferView ) {
 
-    return parser.getDependency( 'bufferView', bufferViewIndex ).then( function ( bufferView ) {
+			return new Promise( function ( resolve ) {
 
-      return new Promise( function ( resolve ) {
+				dracoLoader.decodeDracoFile( bufferView, function ( geometry ) {
 
-        dracoLoader.decodeDracoFile( bufferView, function ( geometry ) {
+					for ( var attributeName in geometry.attributes ) {
 
-          for ( var attributeName in geometry.attributes ) {
+						var attribute = geometry.attributes[ attributeName ];
+						var normalized = attributeNormalizedMap[ attributeName ];
 
-            var attribute = geometry.attributes[ attributeName ];
-            var normalized = attributeNormalizedMap[ attributeName ];
+						if ( normalized !== undefined ) attribute.normalized = normalized;
 
-            if ( normalized !== undefined ) attribute.normalized = normalized;
+					}
 
-          }
+					resolve( geometry );
 
-          resolve( geometry );
+				}, threeAttributeMap, attributeTypeMap );
 
-        }, threeAttributeMap, attributeTypeMap );
+			} );
 
-      } );
+		} );
 
-    } );
+	};
 
-  };
+	/**
+	 * Texture Transform Extension
+	 *
+	 * Specification:
+	 */
+	function GLTFTextureTransformExtension() {
 
-  /**
-   * Texture Transform Extension
-   *
-   * Specification:
-   */
-  function GLTFTextureTransformExtension() {
+		this.name = EXTENSIONS.KHR_TEXTURE_TRANSFORM;
 
-    this.name = EXTENSIONS.KHR_TEXTURE_TRANSFORM;
+	}
 
-  }
+	GLTFTextureTransformExtension.prototype.extendTexture = function ( texture, transform ) {
 
-  GLTFTextureTransformExtension.prototype.extendTexture = function ( texture, transform ) {
+		texture = texture.clone();
 
-    texture = texture.clone();
+		if ( transform.offset !== undefined ) {
 
-    if ( transform.offset !== undefined ) {
+			texture.offset.fromArray( transform.offset );
 
-      texture.offset.fromArray( transform.offset );
+		}
 
-    }
+		if ( transform.rotation !== undefined ) {
 
-    if ( transform.rotation !== undefined ) {
+			texture.rotation = transform.rotation;
 
-      texture.rotation = transform.rotation;
+		}
 
-    }
+		if ( transform.scale !== undefined ) {
 
-    if ( transform.scale !== undefined ) {
+			texture.repeat.fromArray( transform.scale );
 
-      texture.repeat.fromArray( transform.scale );
+		}
 
-    }
+		if ( transform.texCoord !== undefined ) {
 
-    if ( transform.texCoord !== undefined ) {
+			console.warn( 'THREE.GLTFLoader: Custom UV sets in "' + this.name + '" extension not yet supported.' );
 
-      console.warn( 'THREE.GLTFLoader: Custom UV sets in "' + this.name + '" extension not yet supported.' );
+		}
 
-    }
+		texture.needsUpdate = true;
 
-    texture.needsUpdate = true;
+		return texture;
 
-    return texture;
+	};
 
-  };
+	/**
+	 * Specular-Glossiness Extension
+	 *
+	 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness
+	 */
+	function GLTFMaterialsPbrSpecularGlossinessExtension() {
 
-  /**
-   * Specular-Glossiness Extension
-   *
-   * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness
-   */
-  function GLTFMaterialsPbrSpecularGlossinessExtension() {
+		return {
 
-    return {
+			name: EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS,
 
-      name: EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS,
+			specularGlossinessParams: [
+				'color',
+				'map',
+				'lightMap',
+				'lightMapIntensity',
+				'aoMap',
+				'aoMapIntensity',
+				'emissive',
+				'emissiveIntensity',
+				'emissiveMap',
+				'bumpMap',
+				'bumpScale',
+				'normalMap',
+				'displacementMap',
+				'displacementScale',
+				'displacementBias',
+				'specularMap',
+				'specular',
+				'glossinessMap',
+				'glossiness',
+				'alphaMap',
+				'envMap',
+				'envMapIntensity',
+				'refractionRatio',
+			],
 
-      specularGlossinessParams: [
-        'color',
-        'map',
-        'lightMap',
-        'lightMapIntensity',
-        'aoMap',
-        'aoMapIntensity',
-        'emissive',
-        'emissiveIntensity',
-        'emissiveMap',
-        'bumpMap',
-        'bumpScale',
-        'normalMap',
-        'displacementMap',
-        'displacementScale',
-        'displacementBias',
-        'specularMap',
-        'specular',
-        'glossinessMap',
-        'glossiness',
-        'alphaMap',
-        'envMap',
-        'envMapIntensity',
-        'refractionRatio',
-      ],
+			getMaterialType: function () {
 
-      getMaterialType: function () {
+				return THREE.ShaderMaterial;
 
-        return THREE.ShaderMaterial;
+			},
 
-      },
+			extendParams: function ( materialParams, materialDef, parser ) {
 
-      extendParams: function ( materialParams, materialDef, parser ) {
+				var pbrSpecularGlossiness = materialDef.extensions[ this.name ];
 
-        var pbrSpecularGlossiness = materialDef.extensions[ this.name ];
+				var shader = THREE.ShaderLib[ 'standard' ];
 
-        var shader = THREE.ShaderLib[ 'standard' ];
+				var uniforms = THREE.UniformsUtils.clone( shader.uniforms );
 
-        var uniforms = THREE.UniformsUtils.clone( shader.uniforms );
+				var specularMapParsFragmentChunk = [
+					'#ifdef USE_SPECULARMAP',
+					'	uniform sampler2D specularMap;',
+					'#endif'
+				].join( '\n' );
 
-        var specularMapParsFragmentChunk = [
-          '#ifdef USE_SPECULARMAP',
-          '  uniform sampler2D specularMap;',
-          '#endif'
-        ].join( '\n' );
+				var glossinessMapParsFragmentChunk = [
+					'#ifdef USE_GLOSSINESSMAP',
+					'	uniform sampler2D glossinessMap;',
+					'#endif'
+				].join( '\n' );
 
-        var glossinessMapParsFragmentChunk = [
-          '#ifdef USE_GLOSSINESSMAP',
-          '  uniform sampler2D glossinessMap;',
-          '#endif'
-        ].join( '\n' );
+				var specularMapFragmentChunk = [
+					'vec3 specularFactor = specular;',
+					'#ifdef USE_SPECULARMAP',
+					'	vec4 texelSpecular = texture2D( specularMap, vUv );',
+					'	texelSpecular = sRGBToLinear( texelSpecular );',
+					'	// reads channel RGB, compatible with a glTF Specular-Glossiness (RGBA) texture',
+					'	specularFactor *= texelSpecular.rgb;',
+					'#endif'
+				].join( '\n' );
 
-        var specularMapFragmentChunk = [
-          'vec3 specularFactor = specular;',
-          '#ifdef USE_SPECULARMAP',
-          '  vec4 texelSpecular = texture2D( specularMap, vUv );',
-          '  texelSpecular = sRGBToLinear( texelSpecular );',
-          '  // reads channel RGB, compatible with a glTF Specular-Glossiness (RGBA) texture',
-          '  specularFactor *= texelSpecular.rgb;',
-          '#endif'
-        ].join( '\n' );
+				var glossinessMapFragmentChunk = [
+					'float glossinessFactor = glossiness;',
+					'#ifdef USE_GLOSSINESSMAP',
+					'	vec4 texelGlossiness = texture2D( glossinessMap, vUv );',
+					'	// reads channel A, compatible with a glTF Specular-Glossiness (RGBA) texture',
+					'	glossinessFactor *= texelGlossiness.a;',
+					'#endif'
+				].join( '\n' );
 
-        var glossinessMapFragmentChunk = [
-          'float glossinessFactor = glossiness;',
-          '#ifdef USE_GLOSSINESSMAP',
-          '  vec4 texelGlossiness = texture2D( glossinessMap, vUv );',
-          '  // reads channel A, compatible with a glTF Specular-Glossiness (RGBA) texture',
-          '  glossinessFactor *= texelGlossiness.a;',
-          '#endif'
-        ].join( '\n' );
+				var lightPhysicalFragmentChunk = [
+					'PhysicalMaterial material;',
+					'material.diffuseColor = diffuseColor.rgb;',
+					'material.specularRoughness = clamp( 1.0 - glossinessFactor, 0.04, 1.0 );',
+					'material.specularColor = specularFactor.rgb;',
+				].join( '\n' );
 
-        var lightPhysicalFragmentChunk = [
-          'PhysicalMaterial material;',
-          'material.diffuseColor = diffuseColor.rgb;',
-          'material.specularRoughness = clamp( 1.0 - glossinessFactor, 0.04, 1.0 );',
-          'material.specularColor = specularFactor.rgb;',
-        ].join( '\n' );
+				var fragmentShader = shader.fragmentShader
+					.replace( 'uniform float roughness;', 'uniform vec3 specular;' )
+					.replace( 'uniform float metalness;', 'uniform float glossiness;' )
+					.replace( '#include <roughnessmap_pars_fragment>', specularMapParsFragmentChunk )
+					.replace( '#include <metalnessmap_pars_fragment>', glossinessMapParsFragmentChunk )
+					.replace( '#include <roughnessmap_fragment>', specularMapFragmentChunk )
+					.replace( '#include <metalnessmap_fragment>', glossinessMapFragmentChunk )
+					.replace( '#include <lights_physical_fragment>', lightPhysicalFragmentChunk );
 
-        var fragmentShader = shader.fragmentShader
-          .replace( 'uniform float roughness;', 'uniform vec3 specular;' )
-          .replace( 'uniform float metalness;', 'uniform float glossiness;' )
-          .replace( '#include <roughnessmap_pars_fragment>', specularMapParsFragmentChunk )
-          .replace( '#include <metalnessmap_pars_fragment>', glossinessMapParsFragmentChunk )
-          .replace( '#include <roughnessmap_fragment>', specularMapFragmentChunk )
-          .replace( '#include <metalnessmap_fragment>', glossinessMapFragmentChunk )
-          .replace( '#include <lights_physical_fragment>', lightPhysicalFragmentChunk );
+				delete uniforms.roughness;
+				delete uniforms.metalness;
+				delete uniforms.roughnessMap;
+				delete uniforms.metalnessMap;
 
-        delete uniforms.roughness;
-        delete uniforms.metalness;
-        delete uniforms.roughnessMap;
-        delete uniforms.metalnessMap;
+				uniforms.specular = { value: new THREE.Color().setHex( 0x111111 ) };
+				uniforms.glossiness = { value: 0.5 };
+				uniforms.specularMap = { value: null };
+				uniforms.glossinessMap = { value: null };
 
-        uniforms.specular = { value: new THREE.Color().setHex( 0x111111 ) };
-        uniforms.glossiness = { value: 0.5 };
-        uniforms.specularMap = { value: null };
-        uniforms.glossinessMap = { value: null };
+				materialParams.vertexShader = shader.vertexShader;
+				materialParams.fragmentShader = fragmentShader;
+				materialParams.uniforms = uniforms;
+				materialParams.defines = { 'STANDARD': '' }
 
-        materialParams.vertexShader = shader.vertexShader;
-        materialParams.fragmentShader = fragmentShader;
-        materialParams.uniforms = uniforms;
-        materialParams.defines = { 'STANDARD': '' };
+				materialParams.color = new THREE.Color( 1.0, 1.0, 1.0 );
+				materialParams.opacity = 1.0;
 
-        materialParams.color = new THREE.Color( 1.0, 1.0, 1.0 );
-        materialParams.opacity = 1.0;
+				var pending = [];
 
-        var pending = [];
+				if ( Array.isArray( pbrSpecularGlossiness.diffuseFactor ) ) {
 
-        if ( Array.isArray( pbrSpecularGlossiness.diffuseFactor ) ) {
+					var array = pbrSpecularGlossiness.diffuseFactor;
 
-          var array = pbrSpecularGlossiness.diffuseFactor;
+					materialParams.color.fromArray( array );
+					materialParams.opacity = array[ 3 ];
 
-          materialParams.color.fromArray( array );
-          materialParams.opacity = array[ 3 ];
+				}
 
-        }
+				if ( pbrSpecularGlossiness.diffuseTexture !== undefined ) {
 
-        if ( pbrSpecularGlossiness.diffuseTexture !== undefined ) {
+					pending.push( parser.assignTexture( materialParams, 'map', pbrSpecularGlossiness.diffuseTexture ) );
 
-          pending.push( parser.assignTexture( materialParams, 'map', pbrSpecularGlossiness.diffuseTexture ) );
+				}
 
-        }
+				materialParams.emissive = new THREE.Color( 0.0, 0.0, 0.0 );
+				materialParams.glossiness = pbrSpecularGlossiness.glossinessFactor !== undefined ? pbrSpecularGlossiness.glossinessFactor : 1.0;
+				materialParams.specular = new THREE.Color( 1.0, 1.0, 1.0 );
 
-        materialParams.emissive = new THREE.Color( 0.0, 0.0, 0.0 );
-        materialParams.glossiness = pbrSpecularGlossiness.glossinessFactor !== undefined ? pbrSpecularGlossiness.glossinessFactor : 1.0;
-        materialParams.specular = new THREE.Color( 1.0, 1.0, 1.0 );
+				if ( Array.isArray( pbrSpecularGlossiness.specularFactor ) ) {
 
-        if ( Array.isArray( pbrSpecularGlossiness.specularFactor ) ) {
+					materialParams.specular.fromArray( pbrSpecularGlossiness.specularFactor );
 
-          materialParams.specular.fromArray( pbrSpecularGlossiness.specularFactor );
+				}
 
-        }
+				if ( pbrSpecularGlossiness.specularGlossinessTexture !== undefined ) {
 
-        if ( pbrSpecularGlossiness.specularGlossinessTexture !== undefined ) {
+					var specGlossMapDef = pbrSpecularGlossiness.specularGlossinessTexture;
+					pending.push( parser.assignTexture( materialParams, 'glossinessMap', specGlossMapDef ) );
+					pending.push( parser.assignTexture( materialParams, 'specularMap', specGlossMapDef ) );
 
-          var specGlossMapDef = pbrSpecularGlossiness.specularGlossinessTexture;
-          pending.push( parser.assignTexture( materialParams, 'glossinessMap', specGlossMapDef ) );
-          pending.push( parser.assignTexture( materialParams, 'specularMap', specGlossMapDef ) );
+				}
 
-        }
+				return Promise.all( pending );
 
-        return Promise.all( pending );
+			},
 
-      },
+			createMaterial: function ( params ) {
 
-      createMaterial: function ( params ) {
+				// setup material properties based on MeshStandardMaterial for Specular-Glossiness
 
-        // setup material properties based on MeshStandardMaterial for Specular-Glossiness
+				var material = new THREE.ShaderMaterial( {
+					defines: params.defines,
+					vertexShader: params.vertexShader,
+					fragmentShader: params.fragmentShader,
+					uniforms: params.uniforms,
+					fog: true,
+					lights: true,
+					opacity: params.opacity,
+					transparent: params.transparent
+				} );
 
-        var material = new THREE.ShaderMaterial( {
-          defines: params.defines,
-          vertexShader: params.vertexShader,
-          fragmentShader: params.fragmentShader,
-          uniforms: params.uniforms,
-          fog: true,
-          lights: true,
-          opacity: params.opacity,
-          transparent: params.transparent
-        } );
+				material.isGLTFSpecularGlossinessMaterial = true;
 
-        material.isGLTFSpecularGlossinessMaterial = true;
+				material.color = params.color;
 
-        material.color = params.color;
+				material.map = params.map === undefined ? null : params.map;
 
-        material.map = params.map === undefined ? null : params.map;
+				material.lightMap = null;
+				material.lightMapIntensity = 1.0;
 
-        material.lightMap = null;
-        material.lightMapIntensity = 1.0;
+				material.aoMap = params.aoMap === undefined ? null : params.aoMap;
+				material.aoMapIntensity = 1.0;
 
-        material.aoMap = params.aoMap === undefined ? null : params.aoMap;
-        material.aoMapIntensity = 1.0;
+				material.emissive = params.emissive;
+				material.emissiveIntensity = 1.0;
+				material.emissiveMap = params.emissiveMap === undefined ? null : params.emissiveMap;
 
-        material.emissive = params.emissive;
-        material.emissiveIntensity = 1.0;
-        material.emissiveMap = params.emissiveMap === undefined ? null : params.emissiveMap;
+				material.bumpMap = params.bumpMap === undefined ? null : params.bumpMap;
+				material.bumpScale = 1;
 
-        material.bumpMap = params.bumpMap === undefined ? null : params.bumpMap;
-        material.bumpScale = 1;
+				material.normalMap = params.normalMap === undefined ? null : params.normalMap;
 
-        material.normalMap = params.normalMap === undefined ? null : params.normalMap;
+				if ( params.normalScale ) material.normalScale = params.normalScale;
 
-        if ( params.normalScale ) material.normalScale = params.normalScale;
+				material.displacementMap = null;
+				material.displacementScale = 1;
+				material.displacementBias = 0;
 
-        material.displacementMap = null;
-        material.displacementScale = 1;
-        material.displacementBias = 0;
+				material.specularMap = params.specularMap === undefined ? null : params.specularMap;
+				material.specular = params.specular;
 
-        material.specularMap = params.specularMap === undefined ? null : params.specularMap;
-        material.specular = params.specular;
+				material.glossinessMap = params.glossinessMap === undefined ? null : params.glossinessMap;
+				material.glossiness = params.glossiness;
 
-        material.glossinessMap = params.glossinessMap === undefined ? null : params.glossinessMap;
-        material.glossiness = params.glossiness;
+				material.alphaMap = null;
 
-        material.alphaMap = null;
+				material.envMap = params.envMap === undefined ? null : params.envMap;
+				material.envMapIntensity = 1.0;
 
-        material.envMap = params.envMap === undefined ? null : params.envMap;
-        material.envMapIntensity = 1.0;
+				material.refractionRatio = 0.98;
 
-        material.refractionRatio = 0.98;
+				material.extensions.derivatives = true;
 
-        material.extensions.derivatives = true;
+				return material;
 
-        return material;
+			},
 
-      },
+			/**
+			 * Clones a GLTFSpecularGlossinessMaterial instance. The ShaderMaterial.copy() method can
+			 * copy only properties it knows about or inherits, and misses many properties that would
+			 * normally be defined by MeshStandardMaterial.
+			 *
+			 * This method allows GLTFSpecularGlossinessMaterials to be cloned in the process of
+			 * loading a glTF model, but cloning later (e.g. by the user) would require these changes
+			 * AND also updating `.onBeforeRender` on the parent mesh.
+			 *
+			 * @param  {THREE.ShaderMaterial} source
+			 * @return {THREE.ShaderMaterial}
+			 */
+			cloneMaterial: function ( source ) {
 
-      /**
-       * Clones a GLTFSpecularGlossinessMaterial instance. The ShaderMaterial.copy() method can
-       * copy only properties it knows about or inherits, and misses many properties that would
-       * normally be defined by MeshStandardMaterial.
-       *
-       * This method allows GLTFSpecularGlossinessMaterials to be cloned in the process of
-       * loading a glTF model, but cloning later (e.g. by the user) would require these changes
-       * AND also updating `.onBeforeRender` on the parent mesh.
-       *
-       * @param  {THREE.ShaderMaterial} source
-       * @return {THREE.ShaderMaterial}
-       */
-      cloneMaterial: function ( source ) {
+				var target = source.clone();
 
-        var target = source.clone();
+				target.isGLTFSpecularGlossinessMaterial = true;
 
-        target.isGLTFSpecularGlossinessMaterial = true;
+				var params = this.specularGlossinessParams;
 
-        var params = this.specularGlossinessParams;
+				for ( var i = 0, il = params.length; i < il; i ++ ) {
 
-        for ( var i = 0, il = params.length; i < il; i ++ ) {
+					var value = source[ params[ i ] ];
+					target[ params[ i ] ] = ( value && value.isColor ) ? value.clone() : value;
 
-          target[ params[ i ] ] = source[ params[ i ] ];
+				}
 
-        }
+				return target;
 
-        return target;
+			},
 
-      },
+			// Here's based on refreshUniformsCommon() and refreshUniformsStandard() in WebGLRenderer.
+			refreshUniforms: function ( renderer, scene, camera, geometry, material ) {
 
-      // Here's based on refreshUniformsCommon() and refreshUniformsStandard() in WebGLRenderer.
-      refreshUniforms: function ( renderer, scene, camera, geometry, material, group ) {
+				if ( material.isGLTFSpecularGlossinessMaterial !== true ) {
 
-        if ( material.isGLTFSpecularGlossinessMaterial !== true ) {
+					return;
 
-          return;
+				}
 
-        }
+				var uniforms = material.uniforms;
+				var defines = material.defines;
 
-        var uniforms = material.uniforms;
-        var defines = material.defines;
+				uniforms.opacity.value = material.opacity;
 
-        uniforms.opacity.value = material.opacity;
+				uniforms.diffuse.value.copy( material.color );
+				uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity );
 
-        uniforms.diffuse.value.copy( material.color );
-        uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity );
+				uniforms.map.value = material.map;
+				uniforms.specularMap.value = material.specularMap;
+				uniforms.alphaMap.value = material.alphaMap;
 
-        uniforms.map.value = material.map;
-        uniforms.specularMap.value = material.specularMap;
-        uniforms.alphaMap.value = material.alphaMap;
+				uniforms.lightMap.value = material.lightMap;
+				uniforms.lightMapIntensity.value = material.lightMapIntensity;
 
-        uniforms.lightMap.value = material.lightMap;
-        uniforms.lightMapIntensity.value = material.lightMapIntensity;
+				uniforms.aoMap.value = material.aoMap;
+				uniforms.aoMapIntensity.value = material.aoMapIntensity;
 
-        uniforms.aoMap.value = material.aoMap;
-        uniforms.aoMapIntensity.value = material.aoMapIntensity;
+				// uv repeat and offset setting priorities
+				// 1. color map
+				// 2. specular map
+				// 3. normal map
+				// 4. bump map
+				// 5. alpha map
+				// 6. emissive map
 
-        // uv repeat and offset setting priorities
-        // 1. color map
-        // 2. specular map
-        // 3. normal map
-        // 4. bump map
-        // 5. alpha map
-        // 6. emissive map
+				var uvScaleMap;
 
-        var uvScaleMap;
+				if ( material.map ) {
 
-        if ( material.map ) {
+					uvScaleMap = material.map;
 
-          uvScaleMap = material.map;
+				} else if ( material.specularMap ) {
 
-        } else if ( material.specularMap ) {
+					uvScaleMap = material.specularMap;
 
-          uvScaleMap = material.specularMap;
+				} else if ( material.displacementMap ) {
 
-        } else if ( material.displacementMap ) {
+					uvScaleMap = material.displacementMap;
 
-          uvScaleMap = material.displacementMap;
+				} else if ( material.normalMap ) {
 
-        } else if ( material.normalMap ) {
+					uvScaleMap = material.normalMap;
 
-          uvScaleMap = material.normalMap;
+				} else if ( material.bumpMap ) {
 
-        } else if ( material.bumpMap ) {
+					uvScaleMap = material.bumpMap;
 
-          uvScaleMap = material.bumpMap;
+				} else if ( material.glossinessMap ) {
 
-        } else if ( material.glossinessMap ) {
+					uvScaleMap = material.glossinessMap;
 
-          uvScaleMap = material.glossinessMap;
+				} else if ( material.alphaMap ) {
 
-        } else if ( material.alphaMap ) {
+					uvScaleMap = material.alphaMap;
 
-          uvScaleMap = material.alphaMap;
+				} else if ( material.emissiveMap ) {
 
-        } else if ( material.emissiveMap ) {
+					uvScaleMap = material.emissiveMap;
 
-          uvScaleMap = material.emissiveMap;
+				}
 
-        }
+				if ( uvScaleMap !== undefined ) {
 
-        if ( uvScaleMap !== undefined ) {
+					// backwards compatibility
+					if ( uvScaleMap.isWebGLRenderTarget ) {
 
-          // backwards compatibility
-          if ( uvScaleMap.isWebGLRenderTarget ) {
+						uvScaleMap = uvScaleMap.texture;
 
-            uvScaleMap = uvScaleMap.texture;
+					}
 
-          }
+					if ( uvScaleMap.matrixAutoUpdate === true ) {
 
-          if ( uvScaleMap.matrixAutoUpdate === true ) {
+						uvScaleMap.updateMatrix();
 
-            uvScaleMap.updateMatrix();
+					}
 
-          }
+					uniforms.uvTransform.value.copy( uvScaleMap.matrix );
 
-          uniforms.uvTransform.value.copy( uvScaleMap.matrix );
+				}
 
-        }
+				if ( material.envMap ) {
 
-        if ( material.envMap ) {
+					uniforms.envMap.value = material.envMap;
+					uniforms.envMapIntensity.value = material.envMapIntensity;
 
-          uniforms.envMap.value = material.envMap;
-          uniforms.envMapIntensity.value = material.envMapIntensity;
+					// don't flip CubeTexture envMaps, flip everything else:
+					//  WebGLRenderTargetCube will be flipped for backwards compatibility
+					//  WebGLRenderTargetCube.texture will be flipped because it's a Texture and NOT a CubeTexture
+					// this check must be handled differently, or removed entirely, if WebGLRenderTargetCube uses a CubeTexture in the future
+					uniforms.flipEnvMap.value = material.envMap.isCubeTexture ? - 1 : 1;
 
-          // don't flip CubeTexture envMaps, flip everything else:
-          //  WebGLRenderTargetCube will be flipped for backwards compatibility
-          //  WebGLRenderTargetCube.texture will be flipped because it's a Texture and NOT a CubeTexture
-          // this check must be handled differently, or removed entirely, if WebGLRenderTargetCube uses a CubeTexture in the future
-          uniforms.flipEnvMap.value = material.envMap.isCubeTexture ? - 1 : 1;
+					uniforms.reflectivity.value = material.reflectivity;
+					uniforms.refractionRatio.value = material.refractionRatio;
 
-          uniforms.reflectivity.value = material.reflectivity;
-          uniforms.refractionRatio.value = material.refractionRatio;
+					uniforms.maxMipLevel.value = renderer.properties.get( material.envMap ).__maxMipLevel;
 
-          uniforms.maxMipLevel.value = renderer.properties.get( material.envMap ).__maxMipLevel;
+				}
 
-        }
+				uniforms.specular.value.copy( material.specular );
+				uniforms.glossiness.value = material.glossiness;
 
-        uniforms.specular.value.copy( material.specular );
-        uniforms.glossiness.value = material.glossiness;
+				uniforms.glossinessMap.value = material.glossinessMap;
 
-        uniforms.glossinessMap.value = material.glossinessMap;
+				uniforms.emissiveMap.value = material.emissiveMap;
+				uniforms.bumpMap.value = material.bumpMap;
+				uniforms.normalMap.value = material.normalMap;
 
-        uniforms.emissiveMap.value = material.emissiveMap;
-        uniforms.bumpMap.value = material.bumpMap;
-        uniforms.normalMap.value = material.normalMap;
+				uniforms.displacementMap.value = material.displacementMap;
+				uniforms.displacementScale.value = material.displacementScale;
+				uniforms.displacementBias.value = material.displacementBias;
 
-        uniforms.displacementMap.value = material.displacementMap;
-        uniforms.displacementScale.value = material.displacementScale;
-        uniforms.displacementBias.value = material.displacementBias;
+				if ( uniforms.glossinessMap.value !== null && defines.USE_GLOSSINESSMAP === undefined ) {
 
-        if ( uniforms.glossinessMap.value !== null && defines.USE_GLOSSINESSMAP === undefined ) {
+					defines.USE_GLOSSINESSMAP = '';
+					// set USE_ROUGHNESSMAP to enable vUv
+					defines.USE_ROUGHNESSMAP = '';
 
-          defines.USE_GLOSSINESSMAP = '';
-          // set USE_ROUGHNESSMAP to enable vUv
-          defines.USE_ROUGHNESSMAP = '';
+				}
 
-        }
+				if ( uniforms.glossinessMap.value === null && defines.USE_GLOSSINESSMAP !== undefined ) {
 
-        if ( uniforms.glossinessMap.value === null && defines.USE_GLOSSINESSMAP !== undefined ) {
+					delete defines.USE_GLOSSINESSMAP;
+					delete defines.USE_ROUGHNESSMAP;
 
-          delete defines.USE_GLOSSINESSMAP;
-          delete defines.USE_ROUGHNESSMAP;
+				}
 
-        }
+			}
 
-      }
+		};
 
-    };
+	}
 
-  }
+	/*********************************/
+	/********** INTERPOLATION ********/
+	/*********************************/
 
-  /*********************************/
-  /********** INTERPOLATION ********/
-  /*********************************/
+	// Spline Interpolation
+	// Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#appendix-c-spline-interpolation
+	function GLTFCubicSplineInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
 
-  // Spline Interpolation
-  // Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#appendix-c-spline-interpolation
-  function GLTFCubicSplineInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
+		THREE.Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
 
-    THREE.Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
+	}
 
-  }
+	GLTFCubicSplineInterpolant.prototype = Object.create( THREE.Interpolant.prototype );
+	GLTFCubicSplineInterpolant.prototype.constructor = GLTFCubicSplineInterpolant;
 
-  GLTFCubicSplineInterpolant.prototype = Object.create( THREE.Interpolant.prototype );
-  GLTFCubicSplineInterpolant.prototype.constructor = GLTFCubicSplineInterpolant;
+	GLTFCubicSplineInterpolant.prototype.copySampleValue_ = function ( index ) {
 
-  GLTFCubicSplineInterpolant.prototype.copySampleValue_ = function ( index ) {
+		// Copies a sample value to the result buffer. See description of glTF
+		// CUBICSPLINE values layout in interpolate_() function below.
 
-    // Copies a sample value to the result buffer. See description of glTF
-    // CUBICSPLINE values layout in interpolate_() function below.
+		var result = this.resultBuffer,
+			values = this.sampleValues,
+			valueSize = this.valueSize,
+			offset = index * valueSize * 3 + valueSize;
 
-    var result = this.resultBuffer,
-      values = this.sampleValues,
-      valueSize = this.valueSize,
-      offset = index * valueSize * 3 + valueSize;
+		for ( var i = 0; i !== valueSize; i ++ ) {
 
-    for ( var i = 0; i !== valueSize; i ++ ) {
+			result[ i ] = values[ offset + i ];
 
-      result[ i ] = values[ offset + i ];
+		}
 
-    }
+		return result;
 
-    return result;
+	};
 
-  };
+	GLTFCubicSplineInterpolant.prototype.beforeStart_ = GLTFCubicSplineInterpolant.prototype.copySampleValue_;
 
-  GLTFCubicSplineInterpolant.prototype.beforeStart_ = GLTFCubicSplineInterpolant.prototype.copySampleValue_;
+	GLTFCubicSplineInterpolant.prototype.afterEnd_ = GLTFCubicSplineInterpolant.prototype.copySampleValue_;
 
-  GLTFCubicSplineInterpolant.prototype.afterEnd_ = GLTFCubicSplineInterpolant.prototype.copySampleValue_;
+	GLTFCubicSplineInterpolant.prototype.interpolate_ = function ( i1, t0, t, t1 ) {
 
-  GLTFCubicSplineInterpolant.prototype.interpolate_ = function ( i1, t0, t, t1 ) {
+		var result = this.resultBuffer;
+		var values = this.sampleValues;
+		var stride = this.valueSize;
 
-    var result = this.resultBuffer;
-    var values = this.sampleValues;
-    var stride = this.valueSize;
+		var stride2 = stride * 2;
+		var stride3 = stride * 3;
 
-    var stride2 = stride * 2;
-    var stride3 = stride * 3;
+		var td = t1 - t0;
 
-    var td = t1 - t0;
+		var p = ( t - t0 ) / td;
+		var pp = p * p;
+		var ppp = pp * p;
 
-    var p = ( t - t0 ) / td;
-    var pp = p * p;
-    var ppp = pp * p;
+		var offset1 = i1 * stride3;
+		var offset0 = offset1 - stride3;
 
-    var offset1 = i1 * stride3;
-    var offset0 = offset1 - stride3;
+		var s2 = - 2 * ppp + 3 * pp;
+		var s3 = ppp - pp;
+		var s0 = 1 - s2;
+		var s1 = s3 - pp + p;
 
-    var s2 = - 2 * ppp + 3 * pp;
-    var s3 = ppp - pp;
-    var s0 = 1 - s2;
-    var s1 = s3 - pp + p;
+		// Layout of keyframe output values for CUBICSPLINE animations:
+		//   [ inTangent_1, splineVertex_1, outTangent_1, inTangent_2, splineVertex_2, ... ]
+		for ( var i = 0; i !== stride; i ++ ) {
 
-    // Layout of keyframe output values for CUBICSPLINE animations:
-    //   [ inTangent_1, splineVertex_1, outTangent_1, inTangent_2, splineVertex_2, ... ]
-    for ( var i = 0; i !== stride; i ++ ) {
+			var p0 = values[ offset0 + i + stride ]; // splineVertex_k
+			var m0 = values[ offset0 + i + stride2 ] * td; // outTangent_k * (t_k+1 - t_k)
+			var p1 = values[ offset1 + i + stride ]; // splineVertex_k+1
+			var m1 = values[ offset1 + i ] * td; // inTangent_k+1 * (t_k+1 - t_k)
 
-      var p0 = values[ offset0 + i + stride ]; // splineVertex_k
-      var m0 = values[ offset0 + i + stride2 ] * td; // outTangent_k * (t_k+1 - t_k)
-      var p1 = values[ offset1 + i + stride ]; // splineVertex_k+1
-      var m1 = values[ offset1 + i ] * td; // inTangent_k+1 * (t_k+1 - t_k)
+			result[ i ] = s0 * p0 + s1 * m0 + s2 * p1 + s3 * m1;
 
-      result[ i ] = s0 * p0 + s1 * m0 + s2 * p1 + s3 * m1;
+		}
 
-    }
+		return result;
 
-    return result;
+	};
 
-  };
+	/*********************************/
+	/********** INTERNALS ************/
+	/*********************************/
 
-  /*********************************/
-  /********** INTERNALS ************/
-  /*********************************/
+	/* CONSTANTS */
 
-  /* CONSTANTS */
+	var WEBGL_CONSTANTS = {
+		FLOAT: 5126,
+		//FLOAT_MAT2: 35674,
+		FLOAT_MAT3: 35675,
+		FLOAT_MAT4: 35676,
+		FLOAT_VEC2: 35664,
+		FLOAT_VEC3: 35665,
+		FLOAT_VEC4: 35666,
+		LINEAR: 9729,
+		REPEAT: 10497,
+		SAMPLER_2D: 35678,
+		POINTS: 0,
+		LINES: 1,
+		LINE_LOOP: 2,
+		LINE_STRIP: 3,
+		TRIANGLES: 4,
+		TRIANGLE_STRIP: 5,
+		TRIANGLE_FAN: 6,
+		UNSIGNED_BYTE: 5121,
+		UNSIGNED_SHORT: 5123
+	};
 
-  var WEBGL_CONSTANTS = {
-    FLOAT: 5126,
-    //FLOAT_MAT2: 35674,
-    FLOAT_MAT3: 35675,
-    FLOAT_MAT4: 35676,
-    FLOAT_VEC2: 35664,
-    FLOAT_VEC3: 35665,
-    FLOAT_VEC4: 35666,
-    LINEAR: 9729,
-    REPEAT: 10497,
-    SAMPLER_2D: 35678,
-    POINTS: 0,
-    LINES: 1,
-    LINE_LOOP: 2,
-    LINE_STRIP: 3,
-    TRIANGLES: 4,
-    TRIANGLE_STRIP: 5,
-    TRIANGLE_FAN: 6,
-    UNSIGNED_BYTE: 5121,
-    UNSIGNED_SHORT: 5123
-  };
+	var WEBGL_COMPONENT_TYPES = {
+		5120: Int8Array,
+		5121: Uint8Array,
+		5122: Int16Array,
+		5123: Uint16Array,
+		5125: Uint32Array,
+		5126: Float32Array
+	};
 
-  var WEBGL_TYPE = {
-    5126: Number,
-    //35674: THREE.Matrix2,
-    35675: THREE.Matrix3,
-    35676: THREE.Matrix4,
-    35664: THREE.Vector2,
-    35665: THREE.Vector3,
-    35666: THREE.Vector4,
-    35678: THREE.Texture
-  };
+	var WEBGL_FILTERS = {
+		9728: THREE.NearestFilter,
+		9729: THREE.LinearFilter,
+		9984: THREE.NearestMipmapNearestFilter,
+		9985: THREE.LinearMipmapNearestFilter,
+		9986: THREE.NearestMipmapLinearFilter,
+		9987: THREE.LinearMipmapLinearFilter
+	};
 
-  var WEBGL_COMPONENT_TYPES = {
-    5120: Int8Array,
-    5121: Uint8Array,
-    5122: Int16Array,
-    5123: Uint16Array,
-    5125: Uint32Array,
-    5126: Float32Array
-  };
+	var WEBGL_WRAPPINGS = {
+		33071: THREE.ClampToEdgeWrapping,
+		33648: THREE.MirroredRepeatWrapping,
+		10497: THREE.RepeatWrapping
+	};
 
-  var WEBGL_FILTERS = {
-    9728: THREE.NearestFilter,
-    9729: THREE.LinearFilter,
-    9984: THREE.NearestMipMapNearestFilter,
-    9985: THREE.LinearMipMapNearestFilter,
-    9986: THREE.NearestMipMapLinearFilter,
-    9987: THREE.LinearMipMapLinearFilter
-  };
+	var WEBGL_TYPE_SIZES = {
+		'SCALAR': 1,
+		'VEC2': 2,
+		'VEC3': 3,
+		'VEC4': 4,
+		'MAT2': 4,
+		'MAT3': 9,
+		'MAT4': 16
+	};
 
-  var WEBGL_WRAPPINGS = {
-    33071: THREE.ClampToEdgeWrapping,
-    33648: THREE.MirroredRepeatWrapping,
-    10497: THREE.RepeatWrapping
-  };
-
-  var WEBGL_SIDES = {
-    1028: THREE.BackSide, // Culling front
-    1029: THREE.FrontSide // Culling back
-    //1032: THREE.NoSide   // Culling front and back, what to do?
-  };
-
-  var WEBGL_DEPTH_FUNCS = {
-    512: THREE.NeverDepth,
-    513: THREE.LessDepth,
-    514: THREE.EqualDepth,
-    515: THREE.LessEqualDepth,
-    516: THREE.GreaterEqualDepth,
-    517: THREE.NotEqualDepth,
-    518: THREE.GreaterEqualDepth,
-    519: THREE.AlwaysDepth
-  };
-
-  var WEBGL_BLEND_EQUATIONS = {
-    32774: THREE.AddEquation,
-    32778: THREE.SubtractEquation,
-    32779: THREE.ReverseSubtractEquation
-  };
-
-  var WEBGL_BLEND_FUNCS = {
-    0: THREE.ZeroFactor,
-    1: THREE.OneFactor,
-    768: THREE.SrcColorFactor,
-    769: THREE.OneMinusSrcColorFactor,
-    770: THREE.SrcAlphaFactor,
-    771: THREE.OneMinusSrcAlphaFactor,
-    772: THREE.DstAlphaFactor,
-    773: THREE.OneMinusDstAlphaFactor,
-    774: THREE.DstColorFactor,
-    775: THREE.OneMinusDstColorFactor,
-    776: THREE.SrcAlphaSaturateFactor
-    // The followings are not supported by Three.js yet
-    //32769: CONSTANT_COLOR,
-    //32770: ONE_MINUS_CONSTANT_COLOR,
-    //32771: CONSTANT_ALPHA,
-    //32772: ONE_MINUS_CONSTANT_COLOR
-  };
-
-  var WEBGL_TYPE_SIZES = {
-    'SCALAR': 1,
-    'VEC2': 2,
-    'VEC3': 3,
-    'VEC4': 4,
-    'MAT2': 4,
-    'MAT3': 9,
-    'MAT4': 16
-  };
-
-  var ATTRIBUTES = {
-    POSITION: 'position',
-    NORMAL: 'normal',
-    TANGENT: 'tangent',
-    TEXCOORD_0: 'uv',
-    TEXCOORD_1: 'uv2',
-    COLOR_0: 'color',
-    WEIGHTS_0: 'skinWeight',
-    JOINTS_0: 'skinIndex',
-  };
-
-  var PATH_PROPERTIES = {
-    scale: 'scale',
-    translation: 'position',
-    rotation: 'quaternion',
-    weights: 'morphTargetInfluences'
-  };
+	var ATTRIBUTES = {
+		POSITION: 'position',
+		NORMAL: 'normal',
+		TANGENT: 'tangent',
+		TEXCOORD_0: 'uv',
+		TEXCOORD_1: 'uv2',
+		COLOR_0: 'color',
+		WEIGHTS_0: 'skinWeight',
+		JOINTS_0: 'skinIndex',
+	};
 
-  var INTERPOLATION = {
-    CUBICSPLINE: undefined, // We use a custom interpolant (GLTFCubicSplineInterpolation) for CUBICSPLINE tracks. Each
-                            // keyframe track will be initialized with a default interpolation type, then modified.
-    LINEAR: THREE.InterpolateLinear,
-    STEP: THREE.InterpolateDiscrete
-  };
+	var PATH_PROPERTIES = {
+		scale: 'scale',
+		translation: 'position',
+		rotation: 'quaternion',
+		weights: 'morphTargetInfluences'
+	};
 
-  var STATES_ENABLES = {
-    2884: 'CULL_FACE',
-    2929: 'DEPTH_TEST',
-    3042: 'BLEND',
-    3089: 'SCISSOR_TEST',
-    32823: 'POLYGON_OFFSET_FILL',
-    32926: 'SAMPLE_ALPHA_TO_COVERAGE'
-  };
+	var INTERPOLATION = {
+		CUBICSPLINE: undefined, // We use a custom interpolant (GLTFCubicSplineInterpolation) for CUBICSPLINE tracks. Each
+		                        // keyframe track will be initialized with a default interpolation type, then modified.
+		LINEAR: THREE.InterpolateLinear,
+		STEP: THREE.InterpolateDiscrete
+	};
 
-  var ALPHA_MODES = {
-    OPAQUE: 'OPAQUE',
-    MASK: 'MASK',
-    BLEND: 'BLEND'
-  };
+	var ALPHA_MODES = {
+		OPAQUE: 'OPAQUE',
+		MASK: 'MASK',
+		BLEND: 'BLEND'
+	};
 
-  var MIME_TYPE_FORMATS = {
-    'image/png': THREE.RGBAFormat,
-    'image/jpeg': THREE.RGBFormat
-  };
+	var MIME_TYPE_FORMATS = {
+		'image/png': THREE.RGBAFormat,
+		'image/jpeg': THREE.RGBFormat
+	};
 
-  /* UTILITY FUNCTIONS */
+	/* UTILITY FUNCTIONS */
 
-  function resolveURL( url, path ) {
+	function resolveURL( url, path ) {
 
-    // Invalid URL
-    if ( typeof url !== 'string' || url === '' ) return '';
+		// Invalid URL
+		if ( typeof url !== 'string' || url === '' ) return '';
+		
+		// Host Relative URL
+		if ( /^https?:\/\//i.test( path ) && /^\//.test( url ) ) {
 
-    // Absolute URL http://,https://,//
-    if ( /^(https?:)?\/\//i.test( url ) ) return url;
+			path = path.replace( /(^https?:\/\/[^\/]+).*/i , '$1' );
 
-    // Data URI
-    if ( /^data:.*,.*$/i.test( url ) ) return url;
+		}
 
-    // Blob URL
-    if ( /^blob:.*$/i.test( url ) ) return url;
+		// Absolute URL http://,https://,//
+		if ( /^(https?:)?\/\//i.test( url ) ) return url;
 
-    // Relative URL
-    return path + url;
+		// Data URI
+		if ( /^data:.*,.*$/i.test( url ) ) return url;
 
-  }
+		// Blob URL
+		if ( /^blob:.*$/i.test( url ) ) return url;
 
-  var defaultMaterial;
+		// Relative URL
+		return path + url;
 
-  /**
-   * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#default-material
-   */
-  function createDefaultMaterial() {
+	}
 
-    defaultMaterial = defaultMaterial || new THREE.MeshStandardMaterial( {
-      color: 0xFFFFFF,
-      emissive: 0x000000,
-      metalness: 1,
-      roughness: 1,
-      transparent: false,
-      depthTest: true,
-      side: THREE.FrontSide
-    } );
+	var defaultMaterial;
 
-    return defaultMaterial;
+	/**
+	 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#default-material
+	 */
+	function createDefaultMaterial() {
 
-  }
+		defaultMaterial = defaultMaterial || new THREE.MeshStandardMaterial( {
+			color: 0xFFFFFF,
+			emissive: 0x000000,
+			metalness: 1,
+			roughness: 1,
+			transparent: false,
+			depthTest: true,
+			side: THREE.FrontSide
+		} );
 
-  function addUnknownExtensionsToUserData( knownExtensions, object, objectDef ) {
+		return defaultMaterial;
 
-    // Add unknown glTF extensions to an object's userData.
+	}
 
-    for ( var name in objectDef.extensions ) {
+	function addUnknownExtensionsToUserData( knownExtensions, object, objectDef ) {
 
-      if ( knownExtensions[ name ] === undefined ) {
+		// Add unknown glTF extensions to an object's userData.
 
-        object.userData.gltfExtensions = object.userData.gltfExtensions || {};
-        object.userData.gltfExtensions[ name ] = objectDef.extensions[ name ];
+		for ( var name in objectDef.extensions ) {
 
-      }
+			if ( knownExtensions[ name ] === undefined ) {
 
-    }
+				object.userData.gltfExtensions = object.userData.gltfExtensions || {};
+				object.userData.gltfExtensions[ name ] = objectDef.extensions[ name ];
 
-  }
+			}
 
-  /**
-   * @param {THREE.Object3D|THREE.Material|THREE.BufferGeometry} object
-   * @param {GLTF.definition} gltfDef
-   */
-  function assignExtrasToUserData( object, gltfDef ) {
+		}
 
-    if ( gltfDef.extras !== undefined ) {
+	}
 
-      if ( typeof gltfDef.extras === 'object' ) {
+	/**
+	 * @param {THREE.Object3D|THREE.Material|THREE.BufferGeometry} object
+	 * @param {GLTF.definition} gltfDef
+	 */
+	function assignExtrasToUserData( object, gltfDef ) {
 
-        object.userData = gltfDef.extras;
+		if ( gltfDef.extras !== undefined ) {
 
-      } else {
+			if ( typeof gltfDef.extras === 'object' ) {
 
-        console.warn( 'THREE.GLTFLoader: Ignoring primitive type .extras, ' + gltfDef.extras );
+				Object.assign( object.userData, gltfDef.extras );
 
-      }
+			} else {
 
-    }
+				console.warn( 'THREE.GLTFLoader: Ignoring primitive type .extras, ' + gltfDef.extras );
 
-  }
+			}
 
-  /**
-   * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#morph-targets
-   *
-   * @param {THREE.BufferGeometry} geometry
-   * @param {Array<GLTF.Target>} targets
-   * @param {GLTFParser} parser
-   * @return {Promise<THREE.BufferGeometry>}
-   */
-  function addMorphTargets( geometry, targets, parser ) {
+		}
 
-    var hasMorphPosition = false;
-    var hasMorphNormal = false;
+	}
 
-    for ( var i = 0, il = targets.length; i < il; i ++ ) {
+	/**
+	 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#morph-targets
+	 *
+	 * @param {THREE.BufferGeometry} geometry
+	 * @param {Array<GLTF.Target>} targets
+	 * @param {GLTFParser} parser
+	 * @return {Promise<THREE.BufferGeometry>}
+	 */
+	function addMorphTargets( geometry, targets, parser ) {
 
-      var target = targets[ i ];
+		var hasMorphPosition = false;
+		var hasMorphNormal = false;
 
-      if ( target.POSITION !== undefined ) hasMorphPosition = true;
-      if ( target.NORMAL !== undefined ) hasMorphNormal = true;
+		for ( var i = 0, il = targets.length; i < il; i ++ ) {
 
-      if ( hasMorphPosition && hasMorphNormal ) break;
+			var target = targets[ i ];
 
-    }
+			if ( target.POSITION !== undefined ) hasMorphPosition = true;
+			if ( target.NORMAL !== undefined ) hasMorphNormal = true;
 
-    if ( ! hasMorphPosition && ! hasMorphNormal ) return Promise.resolve( geometry );
+			if ( hasMorphPosition && hasMorphNormal ) break;
 
-    var pendingPositionAccessors = [];
-    var pendingNormalAccessors = [];
+		}
 
-    for ( var i = 0, il = targets.length; i < il; i ++ ) {
+		if ( ! hasMorphPosition && ! hasMorphNormal ) return Promise.resolve( geometry );
 
-      var target = targets[ i ];
+		var pendingPositionAccessors = [];
+		var pendingNormalAccessors = [];
 
-      if ( hasMorphPosition ) {
+		for ( var i = 0, il = targets.length; i < il; i ++ ) {
 
-        var pendingAccessor = target.POSITION !== undefined
-          ? parser.getDependency( 'accessor', target.POSITION )
-          : geometry.attributes.position;
+			var target = targets[ i ];
 
-        pendingPositionAccessors.push( pendingAccessor );
+			if ( hasMorphPosition ) {
 
-      }
+				var pendingAccessor = target.POSITION !== undefined
+					? parser.getDependency( 'accessor', target.POSITION )
+					: geometry.attributes.position;
 
-      if ( hasMorphNormal ) {
+				pendingPositionAccessors.push( pendingAccessor );
 
-        var pendingAccessor = target.NORMAL !== undefined
-          ? parser.getDependency( 'accessor', target.NORMAL )
-          : geometry.attributes.normal;
+			}
 
-        pendingNormalAccessors.push( pendingAccessor );
+			if ( hasMorphNormal ) {
 
-      }
+				var pendingAccessor = target.NORMAL !== undefined
+					? parser.getDependency( 'accessor', target.NORMAL )
+					: geometry.attributes.normal;
 
-    }
+				pendingNormalAccessors.push( pendingAccessor );
 
-    return Promise.all( [
-      Promise.all( pendingPositionAccessors ),
-      Promise.all( pendingNormalAccessors )
-    ] ).then( function ( accessors ) {
+			}
 
-      var morphPositions = accessors[ 0 ];
-      var morphNormals = accessors[ 1 ];
+		}
 
-      // Clone morph target accessors before modifying them.
+		return Promise.all( [
+			Promise.all( pendingPositionAccessors ),
+			Promise.all( pendingNormalAccessors )
+		] ).then( function ( accessors ) {
 
-      for ( var i = 0, il = morphPositions.length; i < il; i ++ ) {
+			var morphPositions = accessors[ 0 ];
+			var morphNormals = accessors[ 1 ];
 
-        if ( geometry.attributes.position === morphPositions[ i ] ) continue;
+			// Clone morph target accessors before modifying them.
 
-        morphPositions[ i ] = cloneBufferAttribute( morphPositions[ i ] );
+			for ( var i = 0, il = morphPositions.length; i < il; i ++ ) {
 
-      }
+				if ( geometry.attributes.position === morphPositions[ i ] ) continue;
 
-      for ( var i = 0, il = morphNormals.length; i < il; i ++ ) {
+				morphPositions[ i ] = cloneBufferAttribute( morphPositions[ i ] );
 
-        if ( geometry.attributes.normal === morphNormals[ i ] ) continue;
+			}
 
-        morphNormals[ i ] = cloneBufferAttribute( morphNormals[ i ] );
+			for ( var i = 0, il = morphNormals.length; i < il; i ++ ) {
 
-      }
+				if ( geometry.attributes.normal === morphNormals[ i ] ) continue;
 
-      for ( var i = 0, il = targets.length; i < il; i ++ ) {
+				morphNormals[ i ] = cloneBufferAttribute( morphNormals[ i ] );
 
-        var target = targets[ i ];
-        var attributeName = 'morphTarget' + i;
+			}
 
-        if ( hasMorphPosition ) {
+			for ( var i = 0, il = targets.length; i < il; i ++ ) {
 
-          // Three.js morph position is absolute value. The formula is
-          //   basePosition
-          //     + weight0 * ( morphPosition0 - basePosition )
-          //     + weight1 * ( morphPosition1 - basePosition )
-          //     ...
-          // while the glTF one is relative
-          //   basePosition
-          //     + weight0 * glTFmorphPosition0
-          //     + weight1 * glTFmorphPosition1
-          //     ...
-          // then we need to convert from relative to absolute here.
+				var target = targets[ i ];
+				var attributeName = 'morphTarget' + i;
 
-          if ( target.POSITION !== undefined ) {
+				if ( hasMorphPosition ) {
 
-            var positionAttribute = morphPositions[ i ];
-            positionAttribute.name = attributeName;
+					// Three.js morph position is absolute value. The formula is
+					//   basePosition
+					//     + weight0 * ( morphPosition0 - basePosition )
+					//     + weight1 * ( morphPosition1 - basePosition )
+					//     ...
+					// while the glTF one is relative
+					//   basePosition
+					//     + weight0 * glTFmorphPosition0
+					//     + weight1 * glTFmorphPosition1
+					//     ...
+					// then we need to convert from relative to absolute here.
 
-            var position = geometry.attributes.position;
+					if ( target.POSITION !== undefined ) {
 
-            for ( var j = 0, jl = positionAttribute.count; j < jl; j ++ ) {
+						var positionAttribute = morphPositions[ i ];
+						positionAttribute.name = attributeName;
 
-              positionAttribute.setXYZ(
-                j,
-                positionAttribute.getX( j ) + position.getX( j ),
-                positionAttribute.getY( j ) + position.getY( j ),
-                positionAttribute.getZ( j ) + position.getZ( j )
-              );
+						var position = geometry.attributes.position;
 
-            }
+						for ( var j = 0, jl = positionAttribute.count; j < jl; j ++ ) {
 
-          }
+							positionAttribute.setXYZ(
+								j,
+								positionAttribute.getX( j ) + position.getX( j ),
+								positionAttribute.getY( j ) + position.getY( j ),
+								positionAttribute.getZ( j ) + position.getZ( j )
+							);
 
-        }
+						}
 
-        if ( hasMorphNormal ) {
+					}
 
-          // see target.POSITION's comment
+				}
 
-          if ( target.NORMAL !== undefined ) {
+				if ( hasMorphNormal ) {
 
-            var normalAttribute = morphNormals[ i ];
-            normalAttribute.name = attributeName;
+					// see target.POSITION's comment
 
-            var normal = geometry.attributes.normal;
+					if ( target.NORMAL !== undefined ) {
 
-            for ( var j = 0, jl = normalAttribute.count; j < jl; j ++ ) {
+						var normalAttribute = morphNormals[ i ];
+						normalAttribute.name = attributeName;
 
-              normalAttribute.setXYZ(
-                j,
-                normalAttribute.getX( j ) + normal.getX( j ),
-                normalAttribute.getY( j ) + normal.getY( j ),
-                normalAttribute.getZ( j ) + normal.getZ( j )
-              );
+						var normal = geometry.attributes.normal;
 
-            }
+						for ( var j = 0, jl = normalAttribute.count; j < jl; j ++ ) {
 
-          }
+							normalAttribute.setXYZ(
+								j,
+								normalAttribute.getX( j ) + normal.getX( j ),
+								normalAttribute.getY( j ) + normal.getY( j ),
+								normalAttribute.getZ( j ) + normal.getZ( j )
+							);
 
-        }
+						}
 
-      }
+					}
 
-      if ( hasMorphPosition ) geometry.morphAttributes.position = morphPositions;
-      if ( hasMorphNormal ) geometry.morphAttributes.normal = morphNormals;
+				}
 
-      return geometry;
+			}
 
-    } );
+			if ( hasMorphPosition ) geometry.morphAttributes.position = morphPositions;
+			if ( hasMorphNormal ) geometry.morphAttributes.normal = morphNormals;
 
-  }
+			return geometry;
 
-  /**
-   * @param {THREE.Mesh} mesh
-   * @param {GLTF.Mesh} meshDef
-   */
-  function updateMorphTargets( mesh, meshDef ) {
+		} );
 
-    mesh.updateMorphTargets();
+	}
 
-    if ( meshDef.weights !== undefined ) {
+	/**
+	 * @param {THREE.Mesh} mesh
+	 * @param {GLTF.Mesh} meshDef
+	 */
+	function updateMorphTargets( mesh, meshDef ) {
 
-      for ( var i = 0, il = meshDef.weights.length; i < il; i ++ ) {
+		mesh.updateMorphTargets();
 
-        mesh.morphTargetInfluences[ i ] = meshDef.weights[ i ];
+		if ( meshDef.weights !== undefined ) {
 
-      }
+			for ( var i = 0, il = meshDef.weights.length; i < il; i ++ ) {
 
-    }
+				mesh.morphTargetInfluences[ i ] = meshDef.weights[ i ];
 
-    // .extras has user-defined data, so check that .extras.targetNames is an array.
-    if ( meshDef.extras && Array.isArray( meshDef.extras.targetNames ) ) {
+			}
 
-      var targetNames = meshDef.extras.targetNames;
+		}
 
-      if ( mesh.morphTargetInfluences.length === targetNames.length ) {
+		// .extras has user-defined data, so check that .extras.targetNames is an array.
+		if ( meshDef.extras && Array.isArray( meshDef.extras.targetNames ) ) {
 
-        mesh.morphTargetDictionary = {};
+			var targetNames = meshDef.extras.targetNames;
 
-        for ( var i = 0, il = targetNames.length; i < il; i ++ ) {
+			if ( mesh.morphTargetInfluences.length === targetNames.length ) {
 
-          mesh.morphTargetDictionary[ targetNames[ i ] ] = i;
+				mesh.morphTargetDictionary = {};
 
-        }
+				for ( var i = 0, il = targetNames.length; i < il; i ++ ) {
 
-      } else {
+					mesh.morphTargetDictionary[ targetNames[ i ] ] = i;
 
-        console.warn( 'THREE.GLTFLoader: Invalid extras.targetNames length. Ignoring names.' );
+				}
 
-      }
+			} else {
 
-    }
+				console.warn( 'THREE.GLTFLoader: Invalid extras.targetNames length. Ignoring names.' );
 
-  }
-  function isObjectEqual( a, b ) {
+			}
 
-    if ( Object.keys( a ).length !== Object.keys( b ).length ) return false;
+		}
 
-    for ( var key in a ) {
+	}
 
-      if ( a[ key ] !== b[ key ] ) return false;
+	function createPrimitiveKey( primitiveDef ) {
 
-    }
+		var dracoExtension = primitiveDef.extensions && primitiveDef.extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ];
+		var geometryKey;
 
-    return true;
+		if ( dracoExtension ) {
 
-  }
+			geometryKey = 'draco:' + dracoExtension.bufferView
+				+ ':' + dracoExtension.indices
+				+ ':' + createAttributesKey( dracoExtension.attributes );
 
-  function createPrimitiveKey( primitiveDef ) {
+		} else {
 
-    var dracoExtension = primitiveDef.extensions && primitiveDef.extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ];
-    var geometryKey;
+			geometryKey = primitiveDef.indices + ':' + createAttributesKey( primitiveDef.attributes ) + ':' + primitiveDef.mode;
 
-    if ( dracoExtension ) {
+		}
 
-      geometryKey = 'draco:' + dracoExtension.bufferView
-        + ':' + dracoExtension.indices
-        + ':' + createAttributesKey( dracoExtension.attributes );
+		return geometryKey;
 
-    } else {
+	}
 
-      geometryKey = primitiveDef.indices + ':' + createAttributesKey( primitiveDef.attributes ) + ':' + primitiveDef.mode;
+	function createAttributesKey( attributes ) {
 
-    }
+		var attributesKey = '';
 
-    return geometryKey;
+		var keys = Object.keys( attributes ).sort();
 
-  }
+		for ( var i = 0, il = keys.length; i < il; i ++ ) {
 
-  function createAttributesKey( attributes ) {
+			attributesKey += keys[ i ] + ':' + attributes[ keys[ i ] ] + ';';
 
-    var attributesKey = '';
+		}
 
-    var keys = Object.keys( attributes ).sort();
+		return attributesKey;
 
-    for ( var i = 0, il = keys.length; i < il; i ++ ) {
+	}
 
-      attributesKey += keys[ i ] + ':' + attributes[ keys[ i ] ] + ';';
+	function cloneBufferAttribute( attribute ) {
 
-    }
+		if ( attribute.isInterleavedBufferAttribute ) {
 
-    return attributesKey;
+			var count = attribute.count;
+			var itemSize = attribute.itemSize;
+			var array = attribute.array.slice( 0, count * itemSize );
 
-  }
+			for ( var i = 0, j = 0; i < count; ++ i ) {
 
-  function cloneBufferAttribute( attribute ) {
+				array[ j ++ ] = attribute.getX( i );
+				if ( itemSize >= 2 ) array[ j ++ ] = attribute.getY( i );
+				if ( itemSize >= 3 ) array[ j ++ ] = attribute.getZ( i );
+				if ( itemSize >= 4 ) array[ j ++ ] = attribute.getW( i );
 
-    if ( attribute.isInterleavedBufferAttribute ) {
+			}
 
-      var count = attribute.count;
-      var itemSize = attribute.itemSize;
-      var array = attribute.array.slice( 0, count * itemSize );
+			return new THREE.BufferAttribute( array, itemSize, attribute.normalized );
 
-      for ( var i = 0, j = 0; i < count; ++ i ) {
+		}
 
-        array[ j ++ ] = attribute.getX( i );
-        if ( itemSize >= 2 ) array[ j ++ ] = attribute.getY( i );
-        if ( itemSize >= 3 ) array[ j ++ ] = attribute.getZ( i );
-        if ( itemSize >= 4 ) array[ j ++ ] = attribute.getW( i );
+		return attribute.clone();
 
-      }
+	}
 
-      return new THREE.BufferAttribute( array, itemSize, attribute.normalized );
+	/* GLTF PARSER */
 
-    }
+	function GLTFParser( json, extensions, options ) {
 
-    return attribute.clone();
+		this.json = json || {};
+		this.extensions = extensions || {};
+		this.options = options || {};
 
-  }
+		// loader object cache
+		this.cache = new GLTFRegistry();
 
-  /* GLTF PARSER */
+		// BufferGeometry caching
+		this.primitiveCache = {};
 
-  function GLTFParser( json, extensions, options ) {
+		this.textureLoader = new THREE.TextureLoader( this.options.manager );
+		this.textureLoader.setCrossOrigin( this.options.crossOrigin );
 
-    this.json = json || {};
-    this.extensions = extensions || {};
-    this.options = options || {};
+		this.fileLoader = new THREE.FileLoader( this.options.manager );
+		this.fileLoader.setResponseType( 'arraybuffer' );
 
-    // loader object cache
-    this.cache = new GLTFRegistry();
+		if ( this.options.crossOrigin === 'use-credentials' ) {
 
-    // BufferGeometry caching
-    this.primitiveCache = {};
+			this.fileLoader.setWithCredentials( true );
 
-    this.textureLoader = new THREE.TextureLoader( this.options.manager );
-    this.textureLoader.setCrossOrigin( this.options.crossOrigin );
+		}
 
-    this.fileLoader = new THREE.FileLoader( this.options.manager );
-    this.fileLoader.setResponseType( 'arraybuffer' );
+	}
 
-  }
+	GLTFParser.prototype.parse = function ( onLoad, onError ) {
 
-  GLTFParser.prototype.parse = function ( onLoad, onError ) {
+		var parser = this;
+		var json = this.json;
+		var extensions = this.extensions;
 
-    var parser = this;
-    var json = this.json;
-    var extensions = this.extensions;
+		// Clear the loader cache
+		this.cache.removeAll();
 
-    // Clear the loader cache
-    this.cache.removeAll();
+		// Mark the special nodes/meshes in json for efficient parse
+		this.markDefs();
 
-    // Mark the special nodes/meshes in json for efficient parse
-    this.markDefs();
+		Promise.all( [
 
-    Promise.all( [
+			this.getDependencies( 'scene' ),
+			this.getDependencies( 'animation' ),
+			this.getDependencies( 'camera' ),
 
-      this.getDependencies( 'scene' ),
-      this.getDependencies( 'animation' ),
-      this.getDependencies( 'camera' ),
+		] ).then( function ( dependencies ) {
 
-    ] ).then( function ( dependencies ) {
+			var result = {
+				scene: dependencies[ 0 ][ json.scene || 0 ],
+				scenes: dependencies[ 0 ],
+				animations: dependencies[ 1 ],
+				cameras: dependencies[ 2 ],
+				asset: json.asset,
+				parser: parser,
+				userData: {}
+			};
 
-      var result = {
-        scene: dependencies[ 0 ][ json.scene || 0 ],
-        scenes: dependencies[ 0 ],
-        animations: dependencies[ 1 ],
-        cameras: dependencies[ 2 ],
-        asset: json.asset,
-        parser: parser,
-        userData: {}
-      };
+			addUnknownExtensionsToUserData( extensions, result, json );
 
-      addUnknownExtensionsToUserData( extensions, result, json );
+			assignExtrasToUserData( result, json );
 
-      onLoad( result );
+			onLoad( result );
 
-    } ).catch( onError );
+		} ).catch( onError );
 
-  };
+	};
 
-  /**
-   * Marks the special nodes/meshes in json for efficient parse.
-   */
-  GLTFParser.prototype.markDefs = function () {
+	/**
+	 * Marks the special nodes/meshes in json for efficient parse.
+	 */
+	GLTFParser.prototype.markDefs = function () {
 
-    var nodeDefs = this.json.nodes || [];
-    var skinDefs = this.json.skins || [];
-    var meshDefs = this.json.meshes || [];
+		var nodeDefs = this.json.nodes || [];
+		var skinDefs = this.json.skins || [];
+		var meshDefs = this.json.meshes || [];
 
-    var meshReferences = {};
-    var meshUses = {};
+		var meshReferences = {};
+		var meshUses = {};
 
-    // Nothing in the node definition indicates whether it is a Bone or an
-    // Object3D. Use the skins' joint references to mark bones.
-    for ( var skinIndex = 0, skinLength = skinDefs.length; skinIndex < skinLength; skinIndex ++ ) {
+		// Nothing in the node definition indicates whether it is a Bone or an
+		// Object3D. Use the skins' joint references to mark bones.
+		for ( var skinIndex = 0, skinLength = skinDefs.length; skinIndex < skinLength; skinIndex ++ ) {
 
-      var joints = skinDefs[ skinIndex ].joints;
+			var joints = skinDefs[ skinIndex ].joints;
 
-      for ( var i = 0, il = joints.length; i < il; i ++ ) {
+			for ( var i = 0, il = joints.length; i < il; i ++ ) {
 
-        nodeDefs[ joints[ i ] ].isBone = true;
+				nodeDefs[ joints[ i ] ].isBone = true;
 
-      }
+			}
 
-    }
+		}
 
-    // Meshes can (and should) be reused by multiple nodes in a glTF asset. To
-    // avoid having more than one THREE.Mesh with the same name, count
-    // references and rename instances below.
-    //
-    // Example: CesiumMilkTruck sample model reuses "Wheel" meshes.
-    for ( var nodeIndex = 0, nodeLength = nodeDefs.length; nodeIndex < nodeLength; nodeIndex ++ ) {
+		// Meshes can (and should) be reused by multiple nodes in a glTF asset. To
+		// avoid having more than one THREE.Mesh with the same name, count
+		// references and rename instances below.
+		//
+		// Example: CesiumMilkTruck sample model reuses "Wheel" meshes.
+		for ( var nodeIndex = 0, nodeLength = nodeDefs.length; nodeIndex < nodeLength; nodeIndex ++ ) {
 
-      var nodeDef = nodeDefs[ nodeIndex ];
+			var nodeDef = nodeDefs[ nodeIndex ];
 
-      if ( nodeDef.mesh !== undefined ) {
+			if ( nodeDef.mesh !== undefined ) {
 
-        if ( meshReferences[ nodeDef.mesh ] === undefined ) {
+				if ( meshReferences[ nodeDef.mesh ] === undefined ) {
 
-          meshReferences[ nodeDef.mesh ] = meshUses[ nodeDef.mesh ] = 0;
+					meshReferences[ nodeDef.mesh ] = meshUses[ nodeDef.mesh ] = 0;
 
-        }
+				}
 
-        meshReferences[ nodeDef.mesh ] ++;
+				meshReferences[ nodeDef.mesh ] ++;
 
-        // Nothing in the mesh definition indicates whether it is
-        // a SkinnedMesh or Mesh. Use the node's mesh reference
-        // to mark SkinnedMesh if node has skin.
-        if ( nodeDef.skin !== undefined ) {
+				// Nothing in the mesh definition indicates whether it is
+				// a SkinnedMesh or Mesh. Use the node's mesh reference
+				// to mark SkinnedMesh if node has skin.
+				if ( nodeDef.skin !== undefined ) {
 
-          meshDefs[ nodeDef.mesh ].isSkinnedMesh = true;
+					meshDefs[ nodeDef.mesh ].isSkinnedMesh = true;
 
-        }
+				}
 
-      }
+			}
 
-    }
+		}
 
-    this.json.meshReferences = meshReferences;
-    this.json.meshUses = meshUses;
+		this.json.meshReferences = meshReferences;
+		this.json.meshUses = meshUses;
 
-  };
+	};
 
-  /**
-   * Requests the specified dependency asynchronously, with caching.
-   * @param {string} type
-   * @param {number} index
-   * @return {Promise<THREE.Object3D|THREE.Material|THREE.Texture|THREE.AnimationClip|ArrayBuffer|Object>}
-   */
-  GLTFParser.prototype.getDependency = function ( type, index ) {
+	/**
+	 * Requests the specified dependency asynchronously, with caching.
+	 * @param {string} type
+	 * @param {number} index
+	 * @return {Promise<THREE.Object3D|THREE.Material|THREE.Texture|THREE.AnimationClip|ArrayBuffer|Object>}
+	 */
+	GLTFParser.prototype.getDependency = function ( type, index ) {
 
-    var cacheKey = type + ':' + index;
-    var dependency = this.cache.get( cacheKey );
+		var cacheKey = type + ':' + index;
+		var dependency = this.cache.get( cacheKey );
 
-    if ( ! dependency ) {
+		if ( ! dependency ) {
 
-      switch ( type ) {
+			switch ( type ) {
 
-        case 'scene':
-          dependency = this.loadScene( index );
-          break;
+				case 'scene':
+					dependency = this.loadScene( index );
+					break;
 
-        case 'node':
-          dependency = this.loadNode( index );
-          break;
+				case 'node':
+					dependency = this.loadNode( index );
+					break;
 
-        case 'mesh':
-          dependency = this.loadMesh( index );
-          break;
+				case 'mesh':
+					dependency = this.loadMesh( index );
+					break;
 
-        case 'accessor':
-          dependency = this.loadAccessor( index );
-          break;
+				case 'accessor':
+					dependency = this.loadAccessor( index );
+					break;
 
-        case 'bufferView':
-          dependency = this.loadBufferView( index );
-          break;
+				case 'bufferView':
+					dependency = this.loadBufferView( index );
+					break;
 
-        case 'buffer':
-          dependency = this.loadBuffer( index );
-          break;
+				case 'buffer':
+					dependency = this.loadBuffer( index );
+					break;
 
-        case 'material':
-          dependency = this.loadMaterial( index );
-          break;
+				case 'material':
+					dependency = this.loadMaterial( index );
+					break;
 
-        case 'texture':
-          dependency = this.loadTexture( index );
-          break;
+				case 'texture':
+					dependency = this.loadTexture( index );
+					break;
 
-        case 'skin':
-          dependency = this.loadSkin( index );
-          break;
+				case 'skin':
+					dependency = this.loadSkin( index );
+					break;
 
-        case 'animation':
-          dependency = this.loadAnimation( index );
-          break;
+				case 'animation':
+					dependency = this.loadAnimation( index );
+					break;
 
-        case 'camera':
-          dependency = this.loadCamera( index );
-          break;
+				case 'camera':
+					dependency = this.loadCamera( index );
+					break;
 
-        case 'light':
-          dependency = this.extensions[ EXTENSIONS.KHR_LIGHTS_PUNCTUAL ].loadLight( index );
-          break;
+				case 'light':
+					dependency = this.extensions[ EXTENSIONS.KHR_LIGHTS_PUNCTUAL ].loadLight( index );
+					break;
 
-        default:
-          throw new Error( 'Unknown type: ' + type );
+				default:
+					throw new Error( 'Unknown type: ' + type );
 
-      }
+			}
 
-      this.cache.add( cacheKey, dependency );
+			this.cache.add( cacheKey, dependency );
 
-    }
+		}
 
-    return dependency;
+		return dependency;
 
-  };
+	};
 
-  /**
-   * Requests all dependencies of the specified type asynchronously, with caching.
-   * @param {string} type
-   * @return {Promise<Array<Object>>}
-   */
-  GLTFParser.prototype.getDependencies = function ( type ) {
+	/**
+	 * Requests all dependencies of the specified type asynchronously, with caching.
+	 * @param {string} type
+	 * @return {Promise<Array<Object>>}
+	 */
+	GLTFParser.prototype.getDependencies = function ( type ) {
 
-    var dependencies = this.cache.get( type );
+		var dependencies = this.cache.get( type );
 
-    if ( ! dependencies ) {
+		if ( ! dependencies ) {
 
-      var parser = this;
-      var defs = this.json[ type + ( type === 'mesh' ? 'es' : 's' ) ] || [];
+			var parser = this;
+			var defs = this.json[ type + ( type === 'mesh' ? 'es' : 's' ) ] || [];
 
-      dependencies = Promise.all( defs.map( function ( def, index ) {
+			dependencies = Promise.all( defs.map( function ( def, index ) {
 
-        return parser.getDependency( type, index );
+				return parser.getDependency( type, index );
 
-      } ) );
+			} ) );
 
-      this.cache.add( type, dependencies );
+			this.cache.add( type, dependencies );
 
-    }
+		}
 
-    return dependencies;
+		return dependencies;
 
-  };
+	};
 
-  /**
-   * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views
-   * @param {number} bufferIndex
-   * @return {Promise<ArrayBuffer>}
-   */
-  GLTFParser.prototype.loadBuffer = function ( bufferIndex ) {
+	/**
+	 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views
+	 * @param {number} bufferIndex
+	 * @return {Promise<ArrayBuffer>}
+	 */
+	GLTFParser.prototype.loadBuffer = function ( bufferIndex ) {
 
-    var bufferDef = this.json.buffers[ bufferIndex ];
-    var loader = this.fileLoader;
+		var bufferDef = this.json.buffers[ bufferIndex ];
+		var loader = this.fileLoader;
 
-    if ( bufferDef.type && bufferDef.type !== 'arraybuffer' ) {
+		if ( bufferDef.type && bufferDef.type !== 'arraybuffer' ) {
 
-      throw new Error( 'THREE.GLTFLoader: ' + bufferDef.type + ' buffer type is not supported.' );
+			throw new Error( 'THREE.GLTFLoader: ' + bufferDef.type + ' buffer type is not supported.' );
 
-    }
+		}
 
-    // If present, GLB container is required to be the first buffer.
-    if ( bufferDef.uri === undefined && bufferIndex === 0 ) {
+		// If present, GLB container is required to be the first buffer.
+		if ( bufferDef.uri === undefined && bufferIndex === 0 ) {
 
-      return Promise.resolve( this.extensions[ EXTENSIONS.KHR_BINARY_GLTF ].body );
+			return Promise.resolve( this.extensions[ EXTENSIONS.KHR_BINARY_GLTF ].body );
 
-    }
+		}
 
-    var options = this.options;
+		var options = this.options;
 
-    return new Promise( function ( resolve, reject ) {
+		return new Promise( function ( resolve, reject ) {
 
-      loader.load( resolveURL( bufferDef.uri, options.path ), resolve, undefined, function () {
+			loader.load( resolveURL( bufferDef.uri, options.path ), resolve, undefined, function () {
 
-        reject( new Error( 'THREE.GLTFLoader: Failed to load buffer "' + bufferDef.uri + '".' ) );
+				reject( new Error( 'THREE.GLTFLoader: Failed to load buffer "' + bufferDef.uri + '".' ) );
 
-      } );
+			} );
 
-    } );
+		} );
 
-  };
+	};
 
-  /**
-   * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views
-   * @param {number} bufferViewIndex
-   * @return {Promise<ArrayBuffer>}
-   */
-  GLTFParser.prototype.loadBufferView = function ( bufferViewIndex ) {
+	/**
+	 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views
+	 * @param {number} bufferViewIndex
+	 * @return {Promise<ArrayBuffer>}
+	 */
+	GLTFParser.prototype.loadBufferView = function ( bufferViewIndex ) {
 
-    var bufferViewDef = this.json.bufferViews[ bufferViewIndex ];
+		var bufferViewDef = this.json.bufferViews[ bufferViewIndex ];
 
-    return this.getDependency( 'buffer', bufferViewDef.buffer ).then( function ( buffer ) {
+		return this.getDependency( 'buffer', bufferViewDef.buffer ).then( function ( buffer ) {
 
-      var byteLength = bufferViewDef.byteLength || 0;
-      var byteOffset = bufferViewDef.byteOffset || 0;
-      return buffer.slice( byteOffset, byteOffset + byteLength );
+			var byteLength = bufferViewDef.byteLength || 0;
+			var byteOffset = bufferViewDef.byteOffset || 0;
+			return buffer.slice( byteOffset, byteOffset + byteLength );
 
-    } );
+		} );
 
-  };
+	};
 
-  /**
-   * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#accessors
-   * @param {number} accessorIndex
-   * @return {Promise<THREE.BufferAttribute|THREE.InterleavedBufferAttribute>}
-   */
-  GLTFParser.prototype.loadAccessor = function ( accessorIndex ) {
+	/**
+	 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#accessors
+	 * @param {number} accessorIndex
+	 * @return {Promise<THREE.BufferAttribute|THREE.InterleavedBufferAttribute>}
+	 */
+	GLTFParser.prototype.loadAccessor = function ( accessorIndex ) {
 
-    var parser = this;
-    var json = this.json;
+		var parser = this;
+		var json = this.json;
 
-    var accessorDef = this.json.accessors[ accessorIndex ];
+		var accessorDef = this.json.accessors[ accessorIndex ];
 
-    if ( accessorDef.bufferView === undefined && accessorDef.sparse === undefined ) {
+		if ( accessorDef.bufferView === undefined && accessorDef.sparse === undefined ) {
 
-      // Ignore empty accessors, which may be used to declare runtime
-      // information about attributes coming from another source (e.g. Draco
-      // compression extension).
-      return Promise.resolve( null );
+			// Ignore empty accessors, which may be used to declare runtime
+			// information about attributes coming from another source (e.g. Draco
+			// compression extension).
+			return Promise.resolve( null );
 
-    }
+		}
 
-    var pendingBufferViews = [];
+		var pendingBufferViews = [];
 
-    if ( accessorDef.bufferView !== undefined ) {
+		if ( accessorDef.bufferView !== undefined ) {
 
-      pendingBufferViews.push( this.getDependency( 'bufferView', accessorDef.bufferView ) );
+			pendingBufferViews.push( this.getDependency( 'bufferView', accessorDef.bufferView ) );
 
-    } else {
+		} else {
 
-      pendingBufferViews.push( null );
+			pendingBufferViews.push( null );
 
-    }
+		}
 
-    if ( accessorDef.sparse !== undefined ) {
+		if ( accessorDef.sparse !== undefined ) {
 
-      pendingBufferViews.push( this.getDependency( 'bufferView', accessorDef.sparse.indices.bufferView ) );
-      pendingBufferViews.push( this.getDependency( 'bufferView', accessorDef.sparse.values.bufferView ) );
+			pendingBufferViews.push( this.getDependency( 'bufferView', accessorDef.sparse.indices.bufferView ) );
+			pendingBufferViews.push( this.getDependency( 'bufferView', accessorDef.sparse.values.bufferView ) );
 
-    }
+		}
 
-    return Promise.all( pendingBufferViews ).then( function ( bufferViews ) {
+		return Promise.all( pendingBufferViews ).then( function ( bufferViews ) {
 
-      var bufferView = bufferViews[ 0 ];
+			var bufferView = bufferViews[ 0 ];
 
-      var itemSize = WEBGL_TYPE_SIZES[ accessorDef.type ];
-      var TypedArray = WEBGL_COMPONENT_TYPES[ accessorDef.componentType ];
+			var itemSize = WEBGL_TYPE_SIZES[ accessorDef.type ];
+			var TypedArray = WEBGL_COMPONENT_TYPES[ accessorDef.componentType ];
 
-      // For VEC3: itemSize is 3, elementBytes is 4, itemBytes is 12.
-      var elementBytes = TypedArray.BYTES_PER_ELEMENT;
-      var itemBytes = elementBytes * itemSize;
-      var byteOffset = accessorDef.byteOffset || 0;
-      var byteStride = accessorDef.bufferView !== undefined ? json.bufferViews[ accessorDef.bufferView ].byteStride : undefined;
-      var normalized = accessorDef.normalized === true;
-      var array, bufferAttribute;
+			// For VEC3: itemSize is 3, elementBytes is 4, itemBytes is 12.
+			var elementBytes = TypedArray.BYTES_PER_ELEMENT;
+			var itemBytes = elementBytes * itemSize;
+			var byteOffset = accessorDef.byteOffset || 0;
+			var byteStride = accessorDef.bufferView !== undefined ? json.bufferViews[ accessorDef.bufferView ].byteStride : undefined;
+			var normalized = accessorDef.normalized === true;
+			var array, bufferAttribute;
 
-      // The buffer is not interleaved if the stride is the item size in bytes.
-      if ( byteStride && byteStride !== itemBytes ) {
+			// The buffer is not interleaved if the stride is the item size in bytes.
+			if ( byteStride && byteStride !== itemBytes ) {
 
-        var ibCacheKey = 'InterleavedBuffer:' + accessorDef.bufferView + ':' + accessorDef.componentType;
-        var ib = parser.cache.get( ibCacheKey );
+				// Each "slice" of the buffer, as defined by 'count' elements of 'byteStride' bytes, gets its own InterleavedBuffer
+				// This makes sure that IBA.count reflects accessor.count properly
+				var ibSlice = Math.floor( byteOffset / byteStride );
+				var ibCacheKey = 'InterleavedBuffer:' + accessorDef.bufferView + ':' + accessorDef.componentType + ':' + ibSlice + ':' + accessorDef.count;
+				var ib = parser.cache.get( ibCacheKey );
 
-        if ( ! ib ) {
+				if ( ! ib ) {
 
-          // Use the full buffer if it's interleaved.
-          array = new TypedArray( bufferView );
+					array = new TypedArray( bufferView, ibSlice * byteStride, accessorDef.count * byteStride / elementBytes );
 
-          // Integer parameters to IB/IBA are in array elements, not bytes.
-          ib = new THREE.InterleavedBuffer( array, byteStride / elementBytes );
+					// Integer parameters to IB/IBA are in array elements, not bytes.
+					ib = new THREE.InterleavedBuffer( array, byteStride / elementBytes );
 
-          parser.cache.add( ibCacheKey, ib );
+					parser.cache.add( ibCacheKey, ib );
 
-        }
+				}
 
-        bufferAttribute = new THREE.InterleavedBufferAttribute( ib, itemSize, byteOffset / elementBytes, normalized );
+				bufferAttribute = new THREE.InterleavedBufferAttribute( ib, itemSize, (byteOffset % byteStride) / elementBytes, normalized );
 
-      } else {
+			} else {
 
-        if ( bufferView === null ) {
+				if ( bufferView === null ) {
 
-          array = new TypedArray( accessorDef.count * itemSize );
+					array = new TypedArray( accessorDef.count * itemSize );
 
-        } else {
+				} else {
 
-          array = new TypedArray( bufferView, byteOffset, accessorDef.count * itemSize );
+					array = new TypedArray( bufferView, byteOffset, accessorDef.count * itemSize );
 
-        }
+				}
 
-        bufferAttribute = new THREE.BufferAttribute( array, itemSize, normalized );
+				bufferAttribute = new THREE.BufferAttribute( array, itemSize, normalized );
 
-      }
+			}
 
-      // https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#sparse-accessors
-      if ( accessorDef.sparse !== undefined ) {
+			// https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#sparse-accessors
+			if ( accessorDef.sparse !== undefined ) {
 
-        var itemSizeIndices = WEBGL_TYPE_SIZES.SCALAR;
-        var TypedArrayIndices = WEBGL_COMPONENT_TYPES[ accessorDef.sparse.indices.componentType ];
+				var itemSizeIndices = WEBGL_TYPE_SIZES.SCALAR;
+				var TypedArrayIndices = WEBGL_COMPONENT_TYPES[ accessorDef.sparse.indices.componentType ];
 
-        var byteOffsetIndices = accessorDef.sparse.indices.byteOffset || 0;
-        var byteOffsetValues = accessorDef.sparse.values.byteOffset || 0;
+				var byteOffsetIndices = accessorDef.sparse.indices.byteOffset || 0;
+				var byteOffsetValues = accessorDef.sparse.values.byteOffset || 0;
 
-        var sparseIndices = new TypedArrayIndices( bufferViews[ 1 ], byteOffsetIndices, accessorDef.sparse.count * itemSizeIndices );
-        var sparseValues = new TypedArray( bufferViews[ 2 ], byteOffsetValues, accessorDef.sparse.count * itemSize );
+				var sparseIndices = new TypedArrayIndices( bufferViews[ 1 ], byteOffsetIndices, accessorDef.sparse.count * itemSizeIndices );
+				var sparseValues = new TypedArray( bufferViews[ 2 ], byteOffsetValues, accessorDef.sparse.count * itemSize );
 
-        if ( bufferView !== null ) {
+				if ( bufferView !== null ) {
 
-          // Avoid modifying the original ArrayBuffer, if the bufferView wasn't initialized with zeroes.
-          bufferAttribute.setArray( bufferAttribute.array.slice() );
+					// Avoid modifying the original ArrayBuffer, if the bufferView wasn't initialized with zeroes.
+					bufferAttribute.setArray( bufferAttribute.array.slice() );
 
-        }
+				}
 
-        for ( var i = 0, il = sparseIndices.length; i < il; i ++ ) {
+				for ( var i = 0, il = sparseIndices.length; i < il; i ++ ) {
 
-          var index = sparseIndices[ i ];
+					var index = sparseIndices[ i ];
 
-          bufferAttribute.setX( index, sparseValues[ i * itemSize ] );
-          if ( itemSize >= 2 ) bufferAttribute.setY( index, sparseValues[ i * itemSize + 1 ] );
-          if ( itemSize >= 3 ) bufferAttribute.setZ( index, sparseValues[ i * itemSize + 2 ] );
-          if ( itemSize >= 4 ) bufferAttribute.setW( index, sparseValues[ i * itemSize + 3 ] );
-          if ( itemSize >= 5 ) throw new Error( 'THREE.GLTFLoader: Unsupported itemSize in sparse BufferAttribute.' );
+					bufferAttribute.setX( index, sparseValues[ i * itemSize ] );
+					if ( itemSize >= 2 ) bufferAttribute.setY( index, sparseValues[ i * itemSize + 1 ] );
+					if ( itemSize >= 3 ) bufferAttribute.setZ( index, sparseValues[ i * itemSize + 2 ] );
+					if ( itemSize >= 4 ) bufferAttribute.setW( index, sparseValues[ i * itemSize + 3 ] );
+					if ( itemSize >= 5 ) throw new Error( 'THREE.GLTFLoader: Unsupported itemSize in sparse BufferAttribute.' );
 
-        }
+				}
 
-      }
+			}
 
-      return bufferAttribute;
+			return bufferAttribute;
 
-    } );
+		} );
 
-  };
+	};
 
-  /**
-   * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#textures
-   * @param {number} textureIndex
-   * @return {Promise<THREE.Texture>}
-   */
-  GLTFParser.prototype.loadTexture = function ( textureIndex ) {
+	/**
+	 * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#textures
+	 * @param {number} textureIndex
+	 * @return {Promise<THREE.Texture>}
+	 */
+	GLTFParser.prototype.loadTexture = function ( textureIndex ) {
 
-    var parser = this;
-    var json = this.json;
-    var options = this.options;
-    var textureLoader = this.textureLoader;
+		var parser = this;
+		var json = this.json;
+		var options = this.options;
+		var textureLoader = this.textureLoader;
 
-    var URL = window.URL || window.webkitURL;
+		var URL = window.URL || window.webkitURL;
 
-    var textureDef = json.textures[ textureIndex ];
+		var textureDef = json.textures[ textureIndex ];
 
-    var textureExtensions = textureDef.extensions || {};
+		var textureExtensions = textureDef.extensions || {};
 
-    var source;
+		var source;
 
-    if ( textureExtensions[ EXTENSIONS.MSFT_TEXTURE_DDS ] ) {
+		if ( textureExtensions[ EXTENSIONS.MSFT_TEXTURE_DDS ] ) {
 
-      source = json.images[ textureExtensions[ EXTENSIONS.MSFT_TEXTURE_DDS ].source ];
+			source = json.images[ textureExtensions[ EXTENSIONS.MSFT_TEXTURE_DDS ].source ];
 
     } else if ( textureExtensions[ EXTENSIONS.GOOGLE_TEXTURE_BASIS ] ) {
 
       source = json.images[ textureExtensions[ EXTENSIONS.GOOGLE_TEXTURE_BASIS ].source ];
 
-    } else {
+		} else {
 
-      source = json.images[ textureDef.source ];
+			source = json.images[ textureDef.source ];
 
-    }
+		}
 
-    var sourceURI = source.uri;
-    var isObjectURL = false;
+		var sourceURI = source.uri;
+		var isObjectURL = false;
 
-    if ( source.bufferView !== undefined ) {
+		if ( source.bufferView !== undefined ) {
 
-      // Load binary image data from bufferView, if provided.
+			// Load binary image data from bufferView, if provided.
 
-      sourceURI = parser.getDependency( 'bufferView', source.bufferView ).then( function ( bufferView ) {
+			sourceURI = parser.getDependency( 'bufferView', source.bufferView ).then( function ( bufferView ) {
 
-        isObjectURL = true;
-        var blob = new Blob( [ bufferView ], { type: source.mimeType } );
-        sourceURI = URL.createObjectURL( blob );
-        return sourceURI;
+				isObjectURL = true;
+				var blob = new Blob( [ bufferView ], { type: source.mimeType } );
+				sourceURI = URL.createObjectURL( blob );
+				return sourceURI;
 
-      } );
+			} );
 
-    }
+		}
 
-    return Promise.resolve( sourceURI ).then( function ( sourceURI ) {
+		return Promise.resolve( sourceURI ).then( function ( sourceURI ) {
 
-      // Load Texture resource.
+			// Load Texture resource.
 
-      var loader = THREE.Loader.Handlers.get( sourceURI );
+			var loader = THREE.Loader.Handlers.get( sourceURI );
 
-      if ( ! loader ) {
+			if ( ! loader ) {
 
-        loader = textureExtensions[ EXTENSIONS.MSFT_TEXTURE_DDS ]
-          ? parser.extensions[ EXTENSIONS.MSFT_TEXTURE_DDS ].ddsLoader
-          : textureLoader;
+				loader = textureExtensions[ EXTENSIONS.MSFT_TEXTURE_DDS ]
+					? parser.extensions[ EXTENSIONS.MSFT_TEXTURE_DDS ].ddsLoader
+					: textureLoader;
 
-      }
+			}
 
-      return new Promise( function ( resolve, reject ) {
+			return new Promise( function ( resolve, reject ) {
 
-        loader.load( resolveURL( sourceURI, options.path ), resolve, undefined, reject );
+				loader.load( resolveURL( sourceURI, options.path ), resolve, undefined, reject );
 
-      } );
+			} );
 
-    } ).then( function ( texture ) {
+		} ).then( function ( texture ) {
 
-      // Clean up resources and configure Texture.
+			// Clean up resources and configure Texture.
 
-      if ( isObjectURL === true ) {
+			if ( isObjectURL === true ) {
 
-        URL.revokeObjectURL( sourceURI );
+				URL.revokeObjectURL( sourceURI );
 
-      }
+			}
 
-      texture.flipY = false;
+			texture.flipY = false;
 
-      if ( textureDef.name !== undefined ) texture.name = textureDef.name;
+			if ( textureDef.name !== undefined ) texture.name = textureDef.name;
 
-      // Ignore unknown mime types, like DDS files.
-      if ( source.mimeType in MIME_TYPE_FORMATS ) {
+			// Ignore unknown mime types, like DDS files.
+			if ( source.mimeType in MIME_TYPE_FORMATS ) {
 
-        texture.format = MIME_TYPE_FORMATS[ source.mimeType ];
+				texture.format = MIME_TYPE_FORMATS[ source.mimeType ];
 
-      }
+			}
 
-      var samplers = json.samplers || {};
-      var sampler = samplers[ textureDef.sampler ] || {};
+			var samplers = json.samplers || {};
+			var sampler = samplers[ textureDef.sampler ] || {};
 
-      texture.magFilter = WEBGL_FILTERS[ sampler.magFilter ] || THREE.LinearFilter;
-      texture.minFilter = WEBGL_FILTERS[ sampler.minFilter ] || THREE.LinearMipMapLinearFilter;
-      texture.wrapS = WEBGL_WRAPPINGS[ sampler.wrapS ] || THREE.RepeatWrapping;
-      texture.wrapT = WEBGL_WRAPPINGS[ sampler.wrapT ] || THREE.RepeatWrapping;
+			texture.magFilter = WEBGL_FILTERS[ sampler.magFilter ] || THREE.LinearFilter;
+			texture.minFilter = WEBGL_FILTERS[ sampler.minFilter ] || THREE.LinearMipmapLinearFilter;
+			texture.wrapS = WEBGL_WRAPPINGS[ sampler.wrapS ] || THREE.RepeatWrapping;
+			texture.wrapT = WEBGL_WRAPPINGS[ sampler.wrapT ] || THREE.RepeatWrapping;
 
-      return texture;
+			return texture;
 
-    } );
+		} );
 
-  };
+	};
 
-  /**
-   * Asynchronously assigns a texture to the given material parameters.
-   * @param {Object} materialParams
-   * @param {string} mapName
-   * @param {Object} mapDef
-   * @return {Promise}
-   */
-  GLTFParser.prototype.assignTexture = function ( materialParams, mapName, mapDef ) {
+	/**
+	 * Asynchronously assigns a texture to the given material parameters.
+	 * @param {Object} materialParams
+	 * @param {string} mapName
+	 * @param {Object} mapDef
+	 * @return {Promise}
+	 */
+	GLTFParser.prototype.assignTexture = function ( materialParams, mapName, mapDef ) {
 
-    var parser = this;
+		var parser = this;
 
-    return this.getDependency( 'texture', mapDef.index ).then( function ( texture ) {
+		return this.getDependency( 'texture', mapDef.index ).then( function ( texture ) {
 
-      if ( ! texture.isCompressedTexture ) {
+			if ( ! texture.isCompressedTexture ) {
 
-        switch ( mapName ) {
+				switch ( mapName ) {
 
-          case 'aoMap':
-          case 'emissiveMap':
-          case 'metalnessMap':
-          case 'normalMap':
-          case 'roughnessMap':
-            texture.format = THREE.RGBFormat;
-            break;
+					case 'aoMap':
+					case 'emissiveMap':
+					case 'metalnessMap':
+					case 'normalMap':
+					case 'roughnessMap':
+						texture.format = THREE.RGBFormat;
+						break;
 
-        }
+				}
 
-      }
+			}
 
-      if ( parser.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] ) {
+			if ( parser.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] ) {
 
-        var transform = mapDef.extensions !== undefined ? mapDef.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] : undefined;
+				var transform = mapDef.extensions !== undefined ? mapDef.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] : undefined;
 
-        if ( transform ) {
+				if ( transform ) {
 
-          texture = parser.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ].extendTexture( texture, transform );
+					texture = parser.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ].extendTexture( texture, transform );
 
-        }
+				}
 
-      }
+			}
 
-      materialParams[ mapName ] = texture;
+			materialParams[ mapName ] = texture;
 
-    } );
+		} );
 
-  };
+	};
 
-  /**
-   * Assigns final material to a Mesh, Line, or Points instance. The instance
-   * already has a material (generated from the glTF material options alone)
-   * but reuse of the same glTF material may require multiple threejs materials
-   * to accomodate different primitive types, defines, etc. New materials will
-   * be created if necessary, and reused from a cache.
-   * @param  {THREE.Object3D} mesh Mesh, Line, or Points instance.
-   */
-  GLTFParser.prototype.assignFinalMaterial = function ( mesh ) {
+	/**
+	 * Assigns final material to a Mesh, Line, or Points instance. The instance
+	 * already has a material (generated from the glTF material options alone)
+	 * but reuse of the same glTF material may require multiple threejs materials
+	 * to accomodate different primitive types, defines, etc. New materials will
+	 * be created if necessary, and reused from a cache.
+	 * @param  {THREE.Object3D} mesh Mesh, Line, or Points instance.
+	 */
+	GLTFParser.prototype.assignFinalMaterial = function ( mesh ) {
 
-    var geometry = mesh.geometry;
-    var material = mesh.material;
-    var extensions = this.extensions;
+		var geometry = mesh.geometry;
+		var material = mesh.material;
+		var extensions = this.extensions;
 
-    var useVertexTangents = geometry.attributes.tangent !== undefined;
-    var useVertexColors = geometry.attributes.color !== undefined;
-    var useFlatShading = geometry.attributes.normal === undefined;
-    var useSkinning = mesh.isSkinnedMesh === true;
-    var useMorphTargets = Object.keys( geometry.morphAttributes ).length > 0;
-    var useMorphNormals = useMorphTargets && geometry.morphAttributes.normal !== undefined;
+		var useVertexTangents = geometry.attributes.tangent !== undefined;
+		var useVertexColors = geometry.attributes.color !== undefined;
+		var useFlatShading = geometry.attributes.normal === undefined;
+		var useSkinning = mesh.isSkinnedMesh === true;
+		var useMorphTargets = Object.keys( geometry.morphAttributes ).length > 0;
+		var useMorphNormals = useMorphTargets && geometry.morphAttributes.normal !== undefined;
 
-    if ( mesh.isPoints ) {
+		if ( mesh.isPoints ) {
 
-      var cacheKey = 'PointsMaterial:' + material.uuid;
+			var cacheKey = 'PointsMaterial:' + material.uuid;
 
-      var pointsMaterial = this.cache.get( cacheKey );
+			var pointsMaterial = this.cache.get( cacheKey );
 
-      if ( ! pointsMaterial ) {
+			if ( ! pointsMaterial ) {
 
-        pointsMaterial = new THREE.PointsMaterial();
-        THREE.Material.prototype.copy.call( pointsMaterial, material );
-        pointsMaterial.color.copy( material.color );
-        pointsMaterial.map = material.map;
-        pointsMaterial.lights = false; // PointsMaterial doesn't support lights yet
+				pointsMaterial = new THREE.PointsMaterial();
+				THREE.Material.prototype.copy.call( pointsMaterial, material );
+				pointsMaterial.color.copy( material.color );
+				pointsMaterial.map = material.map;
+				pointsMaterial.lights = false; // PointsMaterial doesn't support lights yet
+				pointsMaterial.sizeAttenuation = false; // glTF spec says points should be 1px
 
-        this.cache.add( cacheKey, pointsMaterial );
+				this.cache.add( cacheKey, pointsMaterial );
 
-      }
+			}
 
-      material = pointsMaterial;
+			material = pointsMaterial;
 
-    } else if ( mesh.isLine ) {
+		} else if ( mesh.isLine ) {
 
-      var cacheKey = 'LineBasicMaterial:' + material.uuid;
+			var cacheKey = 'LineBasicMaterial:' + material.uuid;
 
-      var lineMaterial = this.cache.get( cacheKey );
+			var lineMaterial = this.cache.get( cacheKey );
 
-      if ( ! lineMaterial ) {
+			if ( ! lineMaterial ) {
 
-        lineMaterial = new THREE.LineBasicMaterial();
-        THREE.Material.prototype.copy.call( lineMaterial, material );
-        lineMaterial.color.copy( material.color );
-        lineMaterial.lights = false; // LineBasicMaterial doesn't support lights yet
+				lineMaterial = new THREE.LineBasicMaterial();
+				THREE.Material.prototype.copy.call( lineMaterial, material );
+				lineMaterial.color.copy( material.color );
+				lineMaterial.lights = false; // LineBasicMaterial doesn't support lights yet
 
-        this.cache.add( cacheKey, lineMaterial );
+				this.cache.add( cacheKey, lineMaterial );
 
-      }
+			}
 
-      material = lineMaterial;
+			material = lineMaterial;
 
-    }
+		}
 
-    // Clone the material if it will be modified
-    if ( useVertexTangents || useVertexColors || useFlatShading || useSkinning || useMorphTargets ) {
+		// Clone the material if it will be modified
+		if ( useVertexTangents || useVertexColors || useFlatShading || useSkinning || useMorphTargets ) {
 
-      var cacheKey = 'ClonedMaterial:' + material.uuid + ':';
+			var cacheKey = 'ClonedMaterial:' + material.uuid + ':';
 
-      if ( material.isGLTFSpecularGlossinessMaterial ) cacheKey += 'specular-glossiness:';
-      if ( useSkinning ) cacheKey += 'skinning:';
-      if ( useVertexTangents ) cacheKey += 'vertex-tangents:';
-      if ( useVertexColors ) cacheKey += 'vertex-colors:';
-      if ( useFlatShading ) cacheKey += 'flat-shading:';
-      if ( useMorphTargets ) cacheKey += 'morph-targets:';
-      if ( useMorphNormals ) cacheKey += 'morph-normals:';
+			if ( material.isGLTFSpecularGlossinessMaterial ) cacheKey += 'specular-glossiness:';
+			if ( useSkinning ) cacheKey += 'skinning:';
+			if ( useVertexTangents ) cacheKey += 'vertex-tangents:';
+			if ( useVertexColors ) cacheKey += 'vertex-colors:';
+			if ( useFlatShading ) cacheKey += 'flat-shading:';
+			if ( useMorphTargets ) cacheKey += 'morph-targets:';
+			if ( useMorphNormals ) cacheKey += 'morph-normals:';
 
-      var cachedMaterial = this.cache.get( cacheKey );
+			var cachedMaterial = this.cache.get( cacheKey );
 
-      if ( ! cachedMaterial ) {
+			if ( ! cachedMaterial ) {
 
-        cachedMaterial = material.isGLTFSpecularGlossinessMaterial
-          ? extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ].cloneMaterial( material )
-          : material.clone();
+				cachedMaterial = material.isGLTFSpecularGlossinessMaterial
+					? extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ].cloneMaterial( material )
+					: material.clone();
 
-        if ( useSkinning ) cachedMaterial.skinning = true;
-        if ( useVertexTangents ) cachedMaterial.vertexTangents = true;
-        if ( useVertexColors ) cachedMaterial.vertexColors = THREE.VertexColors;
-        if ( useFlatShading ) cachedMaterial.flatShading = true;
-        if ( useMorphTargets ) cachedMaterial.morphTargets = true;
-        if ( useMorphNormals ) cachedMaterial.morphNormals = true;
+				if ( useSkinning ) cachedMaterial.skinning = true;
+				if ( useVertexTangents ) cachedMaterial.vertexTangents = true;
+				if ( useVertexColors ) cachedMaterial.vertexColors = THREE.VertexColors;
+				if ( useFlatShading ) cachedMaterial.flatShading = true;
+				if ( useMorphTargets ) cachedMaterial.morphTargets = true;
+				if ( useMorphNormals ) cachedMaterial.morphNormals = true;
 
-        this.cache.add( cacheKey, cachedMaterial );
+				this.cache.add( cacheKey, cachedMaterial );
 
-      }
+			}
 
-      material = cachedMaterial;
+			material = cachedMaterial;
 
-    }
+		}
 
-    // workarounds for mesh and geometry
+		// workarounds for mesh and geometry
 
-    if ( material.aoMap && geometry.attributes.uv2 === undefined && geometry.attributes.uv !== undefined ) {
+		if ( material.aoMap && geometry.attributes.uv2 === undefined && geometry.attributes.uv !== undefined ) {
 
-      console.log( 'THREE.GLTFLoader: Duplicating UVs to support aoMap.' );
-      geometry.addAttribute( 'uv2', new THREE.BufferAttribute( geometry.attributes.uv.array, 2 ) );
+			console.log( 'THREE.GLTFLoader: Duplicating UVs to support aoMap.' );
+			geometry.addAttribute( 'uv2', new THREE.BufferAttribute( geometry.attributes.uv.array, 2 ) );
 
-    }
+		}
 
-    if ( material.isGLTFSpecularGlossinessMaterial ) {
+		if ( material.isGLTFSpecularGlossinessMaterial ) {
 
-      // for GLTFSpecularGlossinessMaterial(ShaderMaterial) uniforms runtime update
-      mesh.onBeforeRender = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ].refreshUniforms;
+			// for GLTFSpecularGlossinessMaterial(ShaderMaterial) uniforms runtime update
+			mesh.onBeforeRender = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ].refreshUniforms;
 
-    }
+		}
 
-    mesh.material = material;
+		mesh.material = material;
 
-  };
+	};
 
-  /**
-   * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#materials
-   * @param {number} materialIndex
-   * @return {Promise<THREE.Material>}
-   */
-  GLTFParser.prototype.loadMaterial = function ( materialIndex ) {
+	/**
+	 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#materials
+	 * @param {number} materialIndex
+	 * @return {Promise<THREE.Material>}
+	 */
+	GLTFParser.prototype.loadMaterial = function ( materialIndex ) {
 
-    var parser = this;
-    var json = this.json;
-    var extensions = this.extensions;
-    var materialDef = json.materials[ materialIndex ];
+		var parser = this;
+		var json = this.json;
+		var extensions = this.extensions;
+		var materialDef = json.materials[ materialIndex ];
 
-    var materialType;
-    var materialParams = {};
-    var materialExtensions = materialDef.extensions || {};
+		var materialType;
+		var materialParams = {};
+		var materialExtensions = materialDef.extensions || {};
 
-    var pending = [];
+		var pending = [];
 
-    if ( materialExtensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ] ) {
+		if ( materialExtensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ] ) {
 
-      var sgExtension = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ];
-      materialType = sgExtension.getMaterialType();
-      pending.push( sgExtension.extendParams( materialParams, materialDef, parser ) );
+			var sgExtension = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ];
+			materialType = sgExtension.getMaterialType();
+			pending.push( sgExtension.extendParams( materialParams, materialDef, parser ) );
 
-    } else if ( materialExtensions[ EXTENSIONS.KHR_MATERIALS_UNLIT ] ) {
+		} else if ( materialExtensions[ EXTENSIONS.KHR_MATERIALS_UNLIT ] ) {
 
-      var kmuExtension = extensions[ EXTENSIONS.KHR_MATERIALS_UNLIT ];
-      materialType = kmuExtension.getMaterialType();
-      pending.push( kmuExtension.extendParams( materialParams, materialDef, parser ) );
+			var kmuExtension = extensions[ EXTENSIONS.KHR_MATERIALS_UNLIT ];
+			materialType = kmuExtension.getMaterialType();
+			pending.push( kmuExtension.extendParams( materialParams, materialDef, parser ) );
 
-    } else {
+		} else {
 
-      // Specification:
-      // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#metallic-roughness-material
+			// Specification:
+			// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#metallic-roughness-material
 
-      materialType = THREE.MeshStandardMaterial;
+			materialType = THREE.MeshStandardMaterial;
 
-      var metallicRoughness = materialDef.pbrMetallicRoughness || {};
+			var metallicRoughness = materialDef.pbrMetallicRoughness || {};
 
-      materialParams.color = new THREE.Color( 1.0, 1.0, 1.0 );
-      materialParams.opacity = 1.0;
+			materialParams.color = new THREE.Color( 1.0, 1.0, 1.0 );
+			materialParams.opacity = 1.0;
 
-      if ( Array.isArray( metallicRoughness.baseColorFactor ) ) {
+			if ( Array.isArray( metallicRoughness.baseColorFactor ) ) {
 
-        var array = metallicRoughness.baseColorFactor;
+				var array = metallicRoughness.baseColorFactor;
 
-        materialParams.color.fromArray( array );
-        materialParams.opacity = array[ 3 ];
+				materialParams.color.fromArray( array );
+				materialParams.opacity = array[ 3 ];
 
-      }
+			}
 
-      if ( metallicRoughness.baseColorTexture !== undefined ) {
+			if ( metallicRoughness.baseColorTexture !== undefined ) {
 
-        pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture ) );
+				pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture ) );
 
-      }
+			}
 
-      materialParams.metalness = metallicRoughness.metallicFactor !== undefined ? metallicRoughness.metallicFactor : 1.0;
-      materialParams.roughness = metallicRoughness.roughnessFactor !== undefined ? metallicRoughness.roughnessFactor : 1.0;
+			materialParams.metalness = metallicRoughness.metallicFactor !== undefined ? metallicRoughness.metallicFactor : 1.0;
+			materialParams.roughness = metallicRoughness.roughnessFactor !== undefined ? metallicRoughness.roughnessFactor : 1.0;
 
-      if ( metallicRoughness.metallicRoughnessTexture !== undefined ) {
+			if ( metallicRoughness.metallicRoughnessTexture !== undefined ) {
 
-        pending.push( parser.assignTexture( materialParams, 'metalnessMap', metallicRoughness.metallicRoughnessTexture ) );
-        pending.push( parser.assignTexture( materialParams, 'roughnessMap', metallicRoughness.metallicRoughnessTexture ) );
+				pending.push( parser.assignTexture( materialParams, 'metalnessMap', metallicRoughness.metallicRoughnessTexture ) );
+				pending.push( parser.assignTexture( materialParams, 'roughnessMap', metallicRoughness.metallicRoughnessTexture ) );
 
-      }
+			}
 
-    }
+		}
 
-    if ( materialDef.doubleSided === true ) {
+		if ( materialDef.doubleSided === true ) {
 
-      materialParams.side = THREE.DoubleSide;
+			materialParams.side = THREE.DoubleSide;
 
-    }
+		}
 
-    var alphaMode = materialDef.alphaMode || ALPHA_MODES.OPAQUE;
+		var alphaMode = materialDef.alphaMode || ALPHA_MODES.OPAQUE;
 
-    if ( alphaMode === ALPHA_MODES.BLEND ) {
+		if ( alphaMode === ALPHA_MODES.BLEND ) {
 
-      materialParams.transparent = true;
+			materialParams.transparent = true;
 
-    } else {
+		} else {
 
-      materialParams.transparent = false;
+			materialParams.transparent = false;
 
-      if ( alphaMode === ALPHA_MODES.MASK ) {
+			if ( alphaMode === ALPHA_MODES.MASK ) {
 
-        materialParams.alphaTest = materialDef.alphaCutoff !== undefined ? materialDef.alphaCutoff : 0.5;
+				materialParams.alphaTest = materialDef.alphaCutoff !== undefined ? materialDef.alphaCutoff : 0.5;
 
-      }
+			}
 
-    }
+		}
 
-    if ( materialDef.normalTexture !== undefined && materialType !== THREE.MeshBasicMaterial ) {
+		if ( materialDef.normalTexture !== undefined && materialType !== THREE.MeshBasicMaterial ) {
 
-      pending.push( parser.assignTexture( materialParams, 'normalMap', materialDef.normalTexture ) );
+			pending.push( parser.assignTexture( materialParams, 'normalMap', materialDef.normalTexture ) );
 
-      materialParams.normalScale = new THREE.Vector2( 1, 1 );
+			materialParams.normalScale = new THREE.Vector2( 1, 1 );
 
-      if ( materialDef.normalTexture.scale !== undefined ) {
+			if ( materialDef.normalTexture.scale !== undefined ) {
 
-        materialParams.normalScale.set( materialDef.normalTexture.scale, materialDef.normalTexture.scale );
+				materialParams.normalScale.set( materialDef.normalTexture.scale, materialDef.normalTexture.scale );
 
-      }
+			}
 
-    }
+		}
 
-    if ( materialDef.occlusionTexture !== undefined && materialType !== THREE.MeshBasicMaterial ) {
+		if ( materialDef.occlusionTexture !== undefined && materialType !== THREE.MeshBasicMaterial ) {
 
-      pending.push( parser.assignTexture( materialParams, 'aoMap', materialDef.occlusionTexture ) );
+			pending.push( parser.assignTexture( materialParams, 'aoMap', materialDef.occlusionTexture ) );
 
-      if ( materialDef.occlusionTexture.strength !== undefined ) {
+			if ( materialDef.occlusionTexture.strength !== undefined ) {
 
-        materialParams.aoMapIntensity = materialDef.occlusionTexture.strength;
+				materialParams.aoMapIntensity = materialDef.occlusionTexture.strength;
 
-      }
+			}
 
-    }
+		}
 
-    if ( materialDef.emissiveFactor !== undefined && materialType !== THREE.MeshBasicMaterial ) {
+		if ( materialDef.emissiveFactor !== undefined && materialType !== THREE.MeshBasicMaterial ) {
 
-      materialParams.emissive = new THREE.Color().fromArray( materialDef.emissiveFactor );
+			materialParams.emissive = new THREE.Color().fromArray( materialDef.emissiveFactor );
 
-    }
+		}
 
-    if ( materialDef.emissiveTexture !== undefined && materialType !== THREE.MeshBasicMaterial ) {
+		if ( materialDef.emissiveTexture !== undefined && materialType !== THREE.MeshBasicMaterial ) {
 
-      pending.push( parser.assignTexture( materialParams, 'emissiveMap', materialDef.emissiveTexture ) );
+			pending.push( parser.assignTexture( materialParams, 'emissiveMap', materialDef.emissiveTexture ) );
 
-    }
+		}
 
-    return Promise.all( pending ).then( function () {
+		return Promise.all( pending ).then( function () {
 
-      var material;
+			var material;
 
-      if ( materialType === THREE.ShaderMaterial ) {
+			if ( materialType === THREE.ShaderMaterial ) {
 
-        material = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ].createMaterial( materialParams );
+				material = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ].createMaterial( materialParams );
 
-      } else {
+			} else {
 
-        material = new materialType( materialParams );
+				material = new materialType( materialParams );
 
-      }
+			}
 
-      if ( materialDef.name !== undefined ) material.name = materialDef.name;
+			if ( materialDef.name !== undefined ) material.name = materialDef.name;
 
-      // baseColorTexture, emissiveTexture, and specularGlossinessTexture use sRGB encoding.
-      if ( material.map ) material.map.encoding = THREE.sRGBEncoding;
-      if ( material.emissiveMap ) material.emissiveMap.encoding = THREE.sRGBEncoding;
-      if ( material.specularMap ) material.specularMap.encoding = THREE.sRGBEncoding;
+			// baseColorTexture, emissiveTexture, and specularGlossinessTexture use sRGB encoding.
+			if ( material.map ) material.map.encoding = THREE.sRGBEncoding;
+			if ( material.emissiveMap ) material.emissiveMap.encoding = THREE.sRGBEncoding;
+			if ( material.specularMap ) material.specularMap.encoding = THREE.sRGBEncoding;
 
-      assignExtrasToUserData( material, materialDef );
+			assignExtrasToUserData( material, materialDef );
 
-      if ( materialDef.extensions ) addUnknownExtensionsToUserData( extensions, material, materialDef );
+			if ( materialDef.extensions ) addUnknownExtensionsToUserData( extensions, material, materialDef );
 
-      return material;
+			return material;
 
-    } );
+		} );
 
-  };
+	};
 
-  /**
-   * @param {THREE.BufferGeometry} geometry
-   * @param {GLTF.Primitive} primitiveDef
-   * @param {GLTFParser} parser
-   * @return {Promise<THREE.BufferGeometry>}
-   */
-  function addPrimitiveAttributes( geometry, primitiveDef, parser ) {
+	/**
+	 * @param {THREE.BufferGeometry} geometry
+	 * @param {GLTF.Primitive} primitiveDef
+	 * @param {GLTFParser} parser
+	 * @return {Promise<THREE.BufferGeometry>}
+	 */
+	function addPrimitiveAttributes( geometry, primitiveDef, parser ) {
 
-    var attributes = primitiveDef.attributes;
+		var attributes = primitiveDef.attributes;
 
-    var pending = [];
+		var pending = [];
 
-    function assignAttributeAccessor( accessorIndex, attributeName ) {
+		function assignAttributeAccessor( accessorIndex, attributeName ) {
 
-      return parser.getDependency( 'accessor', accessorIndex )
-        .then( function ( accessor ) {
+			return parser.getDependency( 'accessor', accessorIndex )
+				.then( function ( accessor ) {
 
-          geometry.addAttribute( attributeName, accessor );
+					geometry.addAttribute( attributeName, accessor );
 
-        } );
+				} );
 
-    }
+		}
 
-    for ( var gltfAttributeName in attributes ) {
+		for ( var gltfAttributeName in attributes ) {
 
-      var threeAttributeName = ATTRIBUTES[ gltfAttributeName ] || gltfAttributeName.toLowerCase();
+			var threeAttributeName = ATTRIBUTES[ gltfAttributeName ] || gltfAttributeName.toLowerCase();
 
-      // Skip attributes already provided by e.g. Draco extension.
-      if ( threeAttributeName in geometry.attributes ) continue;
+			// Skip attributes already provided by e.g. Draco extension.
+			if ( threeAttributeName in geometry.attributes ) continue;
 
-      pending.push( assignAttributeAccessor( attributes[ gltfAttributeName ], threeAttributeName ) );
+			pending.push( assignAttributeAccessor( attributes[ gltfAttributeName ], threeAttributeName ) );
 
-    }
+		}
 
-    if ( primitiveDef.indices !== undefined && ! geometry.index ) {
+		if ( primitiveDef.indices !== undefined && ! geometry.index ) {
 
-      var accessor = parser.getDependency( 'accessor', primitiveDef.indices ).then( function ( accessor ) {
+			var accessor = parser.getDependency( 'accessor', primitiveDef.indices ).then( function ( accessor ) {
 
-        geometry.setIndex( accessor );
+				geometry.setIndex( accessor );
 
-      } );
+			} );
 
-      pending.push( accessor );
+			pending.push( accessor );
 
-    }
+		}
 
-    assignExtrasToUserData( geometry, primitiveDef );
+		assignExtrasToUserData( geometry, primitiveDef );
 
-    return Promise.all( pending ).then( function () {
+		return Promise.all( pending ).then( function () {
 
-      return primitiveDef.targets !== undefined
-        ? addMorphTargets( geometry, primitiveDef.targets, parser )
-        : geometry;
+			return primitiveDef.targets !== undefined
+				? addMorphTargets( geometry, primitiveDef.targets, parser )
+				: geometry;
 
-    } );
+		} );
 
-  }
+	}
 
-  /**
-   * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#geometry
-   *
-   * Creates BufferGeometries from primitives.
-   *
-   * @param {Array<GLTF.Primitive>} primitives
-   * @return {Promise<Array<THREE.BufferGeometry>>}
-   */
-  GLTFParser.prototype.loadGeometries = function ( primitives ) {
+	/**
+	 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#geometry
+	 *
+	 * Creates BufferGeometries from primitives.
+	 *
+	 * @param {Array<GLTF.Primitive>} primitives
+	 * @return {Promise<Array<THREE.BufferGeometry>>}
+	 */
+	GLTFParser.prototype.loadGeometries = function ( primitives ) {
 
-    var parser = this;
-    var extensions = this.extensions;
-    var cache = this.primitiveCache;
+		var parser = this;
+		var extensions = this.extensions;
+		var cache = this.primitiveCache;
 
-    function createDracoPrimitive( primitive ) {
+		function createDracoPrimitive( primitive ) {
 
-      return extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ]
-        .decodePrimitive( primitive, parser )
-        .then( function ( geometry ) {
+			return extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ]
+				.decodePrimitive( primitive, parser )
+				.then( function ( geometry ) {
 
-          return addPrimitiveAttributes( geometry, primitive, parser );
+					return addPrimitiveAttributes( geometry, primitive, parser );
 
-        } );
+				} );
 
-    }
+		}
 
-    var pending = [];
+		var pending = [];
 
-    for ( var i = 0, il = primitives.length; i < il; i ++ ) {
+		for ( var i = 0, il = primitives.length; i < il; i ++ ) {
 
-      var primitive = primitives[ i ];
-      var cacheKey = createPrimitiveKey( primitive );
+			var primitive = primitives[ i ];
+			var cacheKey = createPrimitiveKey( primitive );
 
-      // See if we've already created this geometry
-      var cached = cache[ cacheKey ];
+			// See if we've already created this geometry
+			var cached = cache[ cacheKey ];
 
-      if ( cached ) {
+			if ( cached ) {
 
-        // Use the cached geometry if it exists
-        pending.push( cached.promise );
+				// Use the cached geometry if it exists
+				pending.push( cached.promise );
 
-      } else {
+			} else {
 
-        var geometryPromise;
+				var geometryPromise;
 
-        if ( primitive.extensions && primitive.extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ] ) {
+				if ( primitive.extensions && primitive.extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ] ) {
 
-          // Use DRACO geometry if available
-          geometryPromise = createDracoPrimitive( primitive );
+					// Use DRACO geometry if available
+					geometryPromise = createDracoPrimitive( primitive );
 
-        } else {
+				} else {
 
-          // Otherwise create a new geometry
-          geometryPromise = addPrimitiveAttributes( new THREE.BufferGeometry(), primitive, parser );
+					// Otherwise create a new geometry
+					geometryPromise = addPrimitiveAttributes( new THREE.BufferGeometry(), primitive, parser );
 
-        }
+				}
 
-        // Cache this geometry
-        cache[ cacheKey ] = { primitive: primitive, promise: geometryPromise };
+				// Cache this geometry
+				cache[ cacheKey ] = { primitive: primitive, promise: geometryPromise };
+
+				pending.push( geometryPromise );
+
+			}
+
+		}
+
+		return Promise.all( pending );
+
+	};
+
+	/**
+	 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#meshes
+	 * @param {number} meshIndex
+	 * @return {Promise<THREE.Group|THREE.Mesh|THREE.SkinnedMesh>}
+	 */
+	GLTFParser.prototype.loadMesh = function ( meshIndex ) {
+
+		var parser = this;
+		var json = this.json;
+
+		var meshDef = json.meshes[ meshIndex ];
+		var primitives = meshDef.primitives;
+
+		var pending = [];
+
+		for ( var i = 0, il = primitives.length; i < il; i ++ ) {
+
+			var material = primitives[ i ].material === undefined
+				? createDefaultMaterial()
+				: this.getDependency( 'material', primitives[ i ].material );
+
+			pending.push( material );
+
+		}
+
+		return Promise.all( pending ).then( function ( originalMaterials ) {
+
+			return parser.loadGeometries( primitives ).then( function ( geometries ) {
+
+				var meshes = [];
+
+				for ( var i = 0, il = geometries.length; i < il; i ++ ) {
+
+					var geometry = geometries[ i ];
+					var primitive = primitives[ i ];
+
+					// 1. create Mesh
+
+					var mesh;
+
+					var material = originalMaterials[ i ];
+
+					if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLES ||
+						primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ||
+						primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ||
+						primitive.mode === undefined ) {
+
+						// .isSkinnedMesh isn't in glTF spec. See .markDefs()
+						mesh = meshDef.isSkinnedMesh === true
+							? new THREE.SkinnedMesh( geometry, material )
+							: new THREE.Mesh( geometry, material );
+
+						if ( mesh.isSkinnedMesh === true && ! mesh.geometry.attributes.skinWeight.normalized ) {
+
+							// we normalize floating point skin weight array to fix malformed assets (see #15319)
+							// it's important to skip this for non-float32 data since normalizeSkinWeights assumes non-normalized inputs
+							mesh.normalizeSkinWeights();
+
+						}
+
+						if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ) {
+
+							mesh.drawMode = THREE.TriangleStripDrawMode;
+
+						} else if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ) {
+
+							mesh.drawMode = THREE.TriangleFanDrawMode;
+
+						}
+
+					} else if ( primitive.mode === WEBGL_CONSTANTS.LINES ) {
+
+						mesh = new THREE.LineSegments( geometry, material );
+
+					} else if ( primitive.mode === WEBGL_CONSTANTS.LINE_STRIP ) {
+
+						mesh = new THREE.Line( geometry, material );
+
+					} else if ( primitive.mode === WEBGL_CONSTANTS.LINE_LOOP ) {
 
-        pending.push( geometryPromise );
+						mesh = new THREE.LineLoop( geometry, material );
 
-      }
+					} else if ( primitive.mode === WEBGL_CONSTANTS.POINTS ) {
 
-    }
+						mesh = new THREE.Points( geometry, material );
 
-    return Promise.all( pending );
+					} else {
 
-  };
+						throw new Error( 'THREE.GLTFLoader: Primitive mode unsupported: ' + primitive.mode );
 
-  /**
-   * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#meshes
-   * @param {number} meshIndex
-   * @return {Promise<THREE.Group|THREE.Mesh|THREE.SkinnedMesh>}
-   */
-  GLTFParser.prototype.loadMesh = function ( meshIndex ) {
+					}
 
-    var parser = this;
-    var json = this.json;
-    var extensions = this.extensions;
+					if ( Object.keys( mesh.geometry.morphAttributes ).length > 0 ) {
 
-    var meshDef = json.meshes[ meshIndex ];
-    var primitives = meshDef.primitives;
+						updateMorphTargets( mesh, meshDef );
 
-    var pending = [];
+					}
 
-    for ( var i = 0, il = primitives.length; i < il; i ++ ) {
+					mesh.name = meshDef.name || ( 'mesh_' + meshIndex );
 
-      var material = primitives[ i ].material === undefined
-        ? createDefaultMaterial()
-        : this.getDependency( 'material', primitives[ i ].material );
+					if ( geometries.length > 1 ) mesh.name += '_' + i;
 
-      pending.push( material );
+					assignExtrasToUserData( mesh, meshDef );
 
-    }
+					parser.assignFinalMaterial( mesh );
 
-    return Promise.all( pending ).then( function ( originalMaterials ) {
+					meshes.push( mesh );
 
-      return parser.loadGeometries( primitives ).then( function ( geometries ) {
+				}
 
-        var meshes = [];
+				if ( meshes.length === 1 ) {
 
-        for ( var i = 0, il = geometries.length; i < il; i ++ ) {
+					return meshes[ 0 ];
 
-          var geometry = geometries[ i ];
-          var primitive = primitives[ i ];
+				}
 
-          // 1. create Mesh
+				var group = new THREE.Group();
 
-          var mesh;
+				for ( var i = 0, il = meshes.length; i < il; i ++ ) {
 
-          var material = originalMaterials[ i ];
+					group.add( meshes[ i ] );
 
-          if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLES ||
-            primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ||
-            primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ||
-            primitive.mode === undefined ) {
+				}
 
-            // .isSkinnedMesh isn't in glTF spec. See .markDefs()
-            mesh = meshDef.isSkinnedMesh === true
-              ? new THREE.SkinnedMesh( geometry, material )
-              : new THREE.Mesh( geometry, material );
+				return group;
 
-            if ( mesh.isSkinnedMesh === true ) mesh.normalizeSkinWeights(); // #15319
+			} );
 
-            if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ) {
+		} );
 
-              mesh.drawMode = THREE.TriangleStripDrawMode;
+	};
 
-            } else if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ) {
+	/**
+	 * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#cameras
+	 * @param {number} cameraIndex
+	 * @return {Promise<THREE.Camera>}
+	 */
+	GLTFParser.prototype.loadCamera = function ( cameraIndex ) {
 
-              mesh.drawMode = THREE.TriangleFanDrawMode;
+		var camera;
+		var cameraDef = this.json.cameras[ cameraIndex ];
+		var params = cameraDef[ cameraDef.type ];
 
-            }
+		if ( ! params ) {
 
-          } else if ( primitive.mode === WEBGL_CONSTANTS.LINES ) {
+			console.warn( 'THREE.GLTFLoader: Missing camera parameters.' );
+			return;
 
-            mesh = new THREE.LineSegments( geometry, material );
+		}
 
-          } else if ( primitive.mode === WEBGL_CONSTANTS.LINE_STRIP ) {
+		if ( cameraDef.type === 'perspective' ) {
 
-            mesh = new THREE.Line( geometry, material );
+			camera = new THREE.PerspectiveCamera( THREE.Math.radToDeg( params.yfov ), params.aspectRatio || 1, params.znear || 1, params.zfar || 2e6 );
 
-          } else if ( primitive.mode === WEBGL_CONSTANTS.LINE_LOOP ) {
+		} else if ( cameraDef.type === 'orthographic' ) {
 
-            mesh = new THREE.LineLoop( geometry, material );
+			camera = new THREE.OrthographicCamera( params.xmag / - 2, params.xmag / 2, params.ymag / 2, params.ymag / - 2, params.znear, params.zfar );
 
-          } else if ( primitive.mode === WEBGL_CONSTANTS.POINTS ) {
+		}
 
-            mesh = new THREE.Points( geometry, material );
+		if ( cameraDef.name !== undefined ) camera.name = cameraDef.name;
 
-          } else {
+		assignExtrasToUserData( camera, cameraDef );
 
-            throw new Error( 'THREE.GLTFLoader: Primitive mode unsupported: ' + primitive.mode );
+		return Promise.resolve( camera );
 
-          }
+	};
 
-          if ( Object.keys( mesh.geometry.morphAttributes ).length > 0 ) {
+	/**
+	 * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins
+	 * @param {number} skinIndex
+	 * @return {Promise<Object>}
+	 */
+	GLTFParser.prototype.loadSkin = function ( skinIndex ) {
 
-            updateMorphTargets( mesh, meshDef );
+		var skinDef = this.json.skins[ skinIndex ];
 
-          }
+		var skinEntry = { joints: skinDef.joints };
 
-          mesh.name = meshDef.name || ( 'mesh_' + meshIndex );
+		if ( skinDef.inverseBindMatrices === undefined ) {
 
-          if ( geometries.length > 1 ) mesh.name += '_' + i;
+			return Promise.resolve( skinEntry );
 
-          assignExtrasToUserData( mesh, meshDef );
+		}
 
-          parser.assignFinalMaterial( mesh );
+		return this.getDependency( 'accessor', skinDef.inverseBindMatrices ).then( function ( accessor ) {
 
-          meshes.push( mesh );
+			skinEntry.inverseBindMatrices = accessor;
 
-        }
+			return skinEntry;
 
-        if ( meshes.length === 1 ) {
+		} );
 
-          return meshes[ 0 ];
+	};
 
-        }
+	/**
+	 * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#animations
+	 * @param {number} animationIndex
+	 * @return {Promise<THREE.AnimationClip>}
+	 */
+	GLTFParser.prototype.loadAnimation = function ( animationIndex ) {
 
-        var group = new THREE.Group();
+		var json = this.json;
 
-        for ( var i = 0, il = meshes.length; i < il; i ++ ) {
+		var animationDef = json.animations[ animationIndex ];
 
-          group.add( meshes[ i ] );
+		var pendingNodes = [];
+		var pendingInputAccessors = [];
+		var pendingOutputAccessors = [];
+		var pendingSamplers = [];
+		var pendingTargets = [];
 
-        }
+		for ( var i = 0, il = animationDef.channels.length; i < il; i ++ ) {
 
-        return group;
+			var channel = animationDef.channels[ i ];
+			var sampler = animationDef.samplers[ channel.sampler ];
+			var target = channel.target;
+			var name = target.node !== undefined ? target.node : target.id; // NOTE: target.id is deprecated.
+			var input = animationDef.parameters !== undefined ? animationDef.parameters[ sampler.input ] : sampler.input;
+			var output = animationDef.parameters !== undefined ? animationDef.parameters[ sampler.output ] : sampler.output;
 
-      } );
+			pendingNodes.push( this.getDependency( 'node', name ) );
+			pendingInputAccessors.push( this.getDependency( 'accessor', input ) );
+			pendingOutputAccessors.push( this.getDependency( 'accessor', output ) );
+			pendingSamplers.push( sampler );
+			pendingTargets.push( target );
 
-    } );
+		}
 
-  };
+		return Promise.all( [
 
-  /**
-   * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#cameras
-   * @param {number} cameraIndex
-   * @return {Promise<THREE.Camera>}
-   */
-  GLTFParser.prototype.loadCamera = function ( cameraIndex ) {
+			Promise.all( pendingNodes ),
+			Promise.all( pendingInputAccessors ),
+			Promise.all( pendingOutputAccessors ),
+			Promise.all( pendingSamplers ),
+			Promise.all( pendingTargets )
 
-    var camera;
-    var cameraDef = this.json.cameras[ cameraIndex ];
-    var params = cameraDef[ cameraDef.type ];
+		] ).then( function ( dependencies ) {
 
-    if ( ! params ) {
+			var nodes = dependencies[ 0 ];
+			var inputAccessors = dependencies[ 1 ];
+			var outputAccessors = dependencies[ 2 ];
+			var samplers = dependencies[ 3 ];
+			var targets = dependencies[ 4 ];
 
-      console.warn( 'THREE.GLTFLoader: Missing camera parameters.' );
-      return;
+			var tracks = [];
 
-    }
+			for ( var i = 0, il = nodes.length; i < il; i ++ ) {
 
-    if ( cameraDef.type === 'perspective' ) {
+				var node = nodes[ i ];
+				var inputAccessor = inputAccessors[ i ];
+				var outputAccessor = outputAccessors[ i ];
+				var sampler = samplers[ i ];
+				var target = targets[ i ];
 
-      camera = new THREE.PerspectiveCamera( THREE.Math.radToDeg( params.yfov ), params.aspectRatio || 1, params.znear || 1, params.zfar || 2e6 );
+				if ( node === undefined ) continue;
 
-    } else if ( cameraDef.type === 'orthographic' ) {
+				node.updateMatrix();
+				node.matrixAutoUpdate = true;
 
-      camera = new THREE.OrthographicCamera( params.xmag / - 2, params.xmag / 2, params.ymag / 2, params.ymag / - 2, params.znear, params.zfar );
+				var TypedKeyframeTrack;
 
-    }
+				switch ( PATH_PROPERTIES[ target.path ] ) {
 
-    if ( cameraDef.name !== undefined ) camera.name = cameraDef.name;
+					case PATH_PROPERTIES.weights:
 
-    assignExtrasToUserData( camera, cameraDef );
+						TypedKeyframeTrack = THREE.NumberKeyframeTrack;
+						break;
 
-    return Promise.resolve( camera );
+					case PATH_PROPERTIES.rotation:
 
-  };
+						TypedKeyframeTrack = THREE.QuaternionKeyframeTrack;
+						break;
 
-  /**
-   * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins
-   * @param {number} skinIndex
-   * @return {Promise<Object>}
-   */
-  GLTFParser.prototype.loadSkin = function ( skinIndex ) {
+					case PATH_PROPERTIES.position:
+					case PATH_PROPERTIES.scale:
+					default:
 
-    var skinDef = this.json.skins[ skinIndex ];
+						TypedKeyframeTrack = THREE.VectorKeyframeTrack;
+						break;
 
-    var skinEntry = { joints: skinDef.joints };
+				}
 
-    if ( skinDef.inverseBindMatrices === undefined ) {
+				var targetName = node.name ? node.name : node.uuid;
 
-      return Promise.resolve( skinEntry );
+				var interpolation = sampler.interpolation !== undefined ? INTERPOLATION[ sampler.interpolation ] : THREE.InterpolateLinear;
 
-    }
+				var targetNames = [];
 
-    return this.getDependency( 'accessor', skinDef.inverseBindMatrices ).then( function ( accessor ) {
+				if ( PATH_PROPERTIES[ target.path ] === PATH_PROPERTIES.weights ) {
 
-      skinEntry.inverseBindMatrices = accessor;
+					// Node may be a THREE.Group (glTF mesh with several primitives) or a THREE.Mesh.
+					node.traverse( function ( object ) {
 
-      return skinEntry;
+						if ( object.isMesh === true && object.morphTargetInfluences ) {
 
-    } );
+							targetNames.push( object.name ? object.name : object.uuid );
 
-  };
+						}
 
-  /**
-   * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#animations
-   * @param {number} animationIndex
-   * @return {Promise<THREE.AnimationClip>}
-   */
-  GLTFParser.prototype.loadAnimation = function ( animationIndex ) {
+					} );
 
-    var json = this.json;
+				} else {
 
-    var animationDef = json.animations[ animationIndex ];
+					targetNames.push( targetName );
 
-    var pendingNodes = [];
-    var pendingInputAccessors = [];
-    var pendingOutputAccessors = [];
-    var pendingSamplers = [];
-    var pendingTargets = [];
+				}
 
-    for ( var i = 0, il = animationDef.channels.length; i < il; i ++ ) {
+				var outputArray = outputAccessor.array;
 
-      var channel = animationDef.channels[ i ];
-      var sampler = animationDef.samplers[ channel.sampler ];
-      var target = channel.target;
-      var name = target.node !== undefined ? target.node : target.id; // NOTE: target.id is deprecated.
-      var input = animationDef.parameters !== undefined ? animationDef.parameters[ sampler.input ] : sampler.input;
-      var output = animationDef.parameters !== undefined ? animationDef.parameters[ sampler.output ] : sampler.output;
+				if ( outputAccessor.normalized ) {
 
-      pendingNodes.push( this.getDependency( 'node', name ) );
-      pendingInputAccessors.push( this.getDependency( 'accessor', input ) );
-      pendingOutputAccessors.push( this.getDependency( 'accessor', output ) );
-      pendingSamplers.push( sampler );
-      pendingTargets.push( target );
+					var scale;
 
-    }
+					if ( outputArray.constructor === Int8Array ) {
 
-    return Promise.all( [
+						scale = 1 / 127;
 
-      Promise.all( pendingNodes ),
-      Promise.all( pendingInputAccessors ),
-      Promise.all( pendingOutputAccessors ),
-      Promise.all( pendingSamplers ),
-      Promise.all( pendingTargets )
+					} else if ( outputArray.constructor === Uint8Array ) {
 
-    ] ).then( function ( dependencies ) {
+						scale = 1 / 255;
 
-      var nodes = dependencies[ 0 ];
-      var inputAccessors = dependencies[ 1 ];
-      var outputAccessors = dependencies[ 2 ];
-      var samplers = dependencies[ 3 ];
-      var targets = dependencies[ 4 ];
+					} else if ( outputArray.constructor == Int16Array ) {
 
-      var tracks = [];
+						scale = 1 / 32767;
 
-      for ( var i = 0, il = nodes.length; i < il; i ++ ) {
+					} else if ( outputArray.constructor === Uint16Array ) {
 
-        var node = nodes[ i ];
-        var inputAccessor = inputAccessors[ i ];
-        var outputAccessor = outputAccessors[ i ];
-        var sampler = samplers[ i ];
-        var target = targets[ i ];
+						scale = 1 / 65535;
 
-        if ( node === undefined ) continue;
+					} else {
 
-        node.updateMatrix();
-        node.matrixAutoUpdate = true;
+						throw new Error( 'THREE.GLTFLoader: Unsupported output accessor component type.' );
 
-        var TypedKeyframeTrack;
+					}
 
-        switch ( PATH_PROPERTIES[ target.path ] ) {
+					var scaled = new Float32Array( outputArray.length );
 
-          case PATH_PROPERTIES.weights:
+					for ( var j = 0, jl = outputArray.length; j < jl; j ++ ) {
 
-            TypedKeyframeTrack = THREE.NumberKeyframeTrack;
-            break;
+						scaled[ j ] = outputArray[ j ] * scale;
 
-          case PATH_PROPERTIES.rotation:
+					}
 
-            TypedKeyframeTrack = THREE.QuaternionKeyframeTrack;
-            break;
+					outputArray = scaled;
 
-          case PATH_PROPERTIES.position:
-          case PATH_PROPERTIES.scale:
-          default:
+				}
 
-            TypedKeyframeTrack = THREE.VectorKeyframeTrack;
-            break;
+				for ( var j = 0, jl = targetNames.length; j < jl; j ++ ) {
 
-        }
+					var track = new TypedKeyframeTrack(
+						targetNames[ j ] + '.' + PATH_PROPERTIES[ target.path ],
+						inputAccessor.array,
+						outputArray,
+						interpolation
+					);
 
-        var targetName = node.name ? node.name : node.uuid;
+					// Override interpolation with custom factory method.
+					if ( sampler.interpolation === 'CUBICSPLINE' ) {
 
-        var interpolation = sampler.interpolation !== undefined ? INTERPOLATION[ sampler.interpolation ] : THREE.InterpolateLinear;
+						track.createInterpolant = function InterpolantFactoryMethodGLTFCubicSpline( result ) {
 
-        var targetNames = [];
+							// A CUBICSPLINE keyframe in glTF has three output values for each input value,
+							// representing inTangent, splineVertex, and outTangent. As a result, track.getValueSize()
+							// must be divided by three to get the interpolant's sampleSize argument.
 
-        if ( PATH_PROPERTIES[ target.path ] === PATH_PROPERTIES.weights ) {
+							return new GLTFCubicSplineInterpolant( this.times, this.values, this.getValueSize() / 3, result );
 
-          // Node may be a THREE.Group (glTF mesh with several primitives) or a THREE.Mesh.
-          node.traverse( function ( object ) {
+						};
 
-            if ( object.isMesh === true && object.morphTargetInfluences ) {
+						// Mark as CUBICSPLINE. `track.getInterpolation()` doesn't support custom interpolants.
+						track.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline = true;
 
-              targetNames.push( object.name ? object.name : object.uuid );
+					}
 
-            }
+					tracks.push( track );
 
-          } );
+				}
 
-        } else {
+			}
 
-          targetNames.push( targetName );
+			var name = animationDef.name !== undefined ? animationDef.name : 'animation_' + animationIndex;
 
-        }
+			return new THREE.AnimationClip( name, undefined, tracks );
 
-        for ( var j = 0, jl = targetNames.length; j < jl; j ++ ) {
+		} );
 
-          var track = new TypedKeyframeTrack(
-            targetNames[ j ] + '.' + PATH_PROPERTIES[ target.path ],
-            inputAccessor.array,
-            outputAccessor.array,
-            interpolation
-          );
+	};
 
-          // Override interpolation with custom factory method.
-          if ( sampler.interpolation === 'CUBICSPLINE' ) {
+	/**
+	 * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#nodes-and-hierarchy
+	 * @param {number} nodeIndex
+	 * @return {Promise<THREE.Object3D>}
+	 */
+	GLTFParser.prototype.loadNode = function ( nodeIndex ) {
 
-            track.createInterpolant = function InterpolantFactoryMethodGLTFCubicSpline( result ) {
+		var json = this.json;
+		var extensions = this.extensions;
+		var parser = this;
 
-              // A CUBICSPLINE keyframe in glTF has three output values for each input value,
-              // representing inTangent, splineVertex, and outTangent. As a result, track.getValueSize()
-              // must be divided by three to get the interpolant's sampleSize argument.
+		var meshReferences = json.meshReferences;
+		var meshUses = json.meshUses;
 
-              return new GLTFCubicSplineInterpolant( this.times, this.values, this.getValueSize() / 3, result );
+		var nodeDef = json.nodes[ nodeIndex ];
 
-            };
+		return ( function () {
 
-            // Mark as CUBICSPLINE. `track.getInterpolation()` doesn't support custom interpolants.
-            track.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline = true;
+			var pending = [];
 
-          }
+			if ( nodeDef.mesh !== undefined ) {
 
-          tracks.push( track );
+				pending.push( parser.getDependency( 'mesh', nodeDef.mesh ).then( function ( mesh ) {
 
-        }
+					var node;
 
-      }
+					if ( meshReferences[ nodeDef.mesh ] > 1 ) {
 
-      var name = animationDef.name !== undefined ? animationDef.name : 'animation_' + animationIndex;
+						var instanceNum = meshUses[ nodeDef.mesh ] ++;
 
-      return new THREE.AnimationClip( name, undefined, tracks );
+						node = mesh.clone();
+						node.name += '_instance_' + instanceNum;
 
-    } );
+						// onBeforeRender copy for Specular-Glossiness
+						node.onBeforeRender = mesh.onBeforeRender;
 
-  };
+						for ( var i = 0, il = node.children.length; i < il; i ++ ) {
 
-  /**
-   * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#nodes-and-hierarchy
-   * @param {number} nodeIndex
-   * @return {Promise<THREE.Object3D>}
-   */
-  GLTFParser.prototype.loadNode = function ( nodeIndex ) {
+							node.children[ i ].name += '_instance_' + instanceNum;
+							node.children[ i ].onBeforeRender = mesh.children[ i ].onBeforeRender;
 
-    var json = this.json;
-    var extensions = this.extensions;
-    var parser = this;
+						}
 
-    var meshReferences = json.meshReferences;
-    var meshUses = json.meshUses;
+					} else {
 
-    var nodeDef = json.nodes[ nodeIndex ];
+						node = mesh;
 
-    return ( function () {
+					}
 
-      // .isBone isn't in glTF spec. See .markDefs
-      if ( nodeDef.isBone === true ) {
+					// if weights are provided on the node, override weights on the mesh.
+					if ( nodeDef.weights !== undefined ) {
 
-        return Promise.resolve( new THREE.Bone() );
+						node.traverse( function ( o ) {
 
-      } else if ( nodeDef.mesh !== undefined ) {
+							if ( ! o.isMesh ) return;
 
-        return parser.getDependency( 'mesh', nodeDef.mesh ).then( function ( mesh ) {
+							for ( var i = 0, il = nodeDef.weights.length; i < il; i ++ ) {
 
-          var node;
+								o.morphTargetInfluences[ i ] = nodeDef.weights[ i ];
 
-          if ( meshReferences[ nodeDef.mesh ] > 1 ) {
+							}
 
-            var instanceNum = meshUses[ nodeDef.mesh ] ++;
+						} );
 
-            node = mesh.clone();
-            node.name += '_instance_' + instanceNum;
+					}
 
-            // onBeforeRender copy for Specular-Glossiness
-            node.onBeforeRender = mesh.onBeforeRender;
+					return node;
 
-            for ( var i = 0, il = node.children.length; i < il; i ++ ) {
+				} ) );
 
-              node.children[ i ].name += '_instance_' + instanceNum;
-              node.children[ i ].onBeforeRender = mesh.children[ i ].onBeforeRender;
+			}
 
-            }
+			if ( nodeDef.camera !== undefined ) {
 
-          } else {
+				pending.push( parser.getDependency( 'camera', nodeDef.camera ) );
 
-            node = mesh;
+			}
 
-          }
+			if ( nodeDef.extensions
+				&& nodeDef.extensions[ EXTENSIONS.KHR_LIGHTS_PUNCTUAL ]
+				&& nodeDef.extensions[ EXTENSIONS.KHR_LIGHTS_PUNCTUAL ].light !== undefined ) {
 
-          // if weights are provided on the node, override weights on the mesh.
-          if ( nodeDef.weights !== undefined ) {
+				pending.push( parser.getDependency( 'light', nodeDef.extensions[ EXTENSIONS.KHR_LIGHTS_PUNCTUAL ].light ) );
 
-            node.traverse( function ( o ) {
+			}
 
-              if ( ! o.isMesh ) return;
+			return Promise.all( pending );
 
-              for ( var i = 0, il = nodeDef.weights.length; i < il; i ++ ) {
+		}() ).then( function ( objects ) {
 
-                o.morphTargetInfluences[ i ] = nodeDef.weights[ i ];
+			var node;
 
-              }
+			// .isBone isn't in glTF spec. See .markDefs
+			if ( nodeDef.isBone === true ) {
 
-            } );
+				node = new THREE.Bone();
 
-          }
+			} else if ( objects.length > 1 ) {
 
-          return node;
+				node = new THREE.Group();
 
-        } );
+			} else if ( objects.length === 1 ) {
 
-      } else if ( nodeDef.camera !== undefined ) {
+				node = objects[ 0 ];
 
-        return parser.getDependency( 'camera', nodeDef.camera );
+			} else {
 
-      } else if ( nodeDef.extensions
-        && nodeDef.extensions[ EXTENSIONS.KHR_LIGHTS_PUNCTUAL ]
-        && nodeDef.extensions[ EXTENSIONS.KHR_LIGHTS_PUNCTUAL ].light !== undefined ) {
+				node = new THREE.Object3D();
 
-        return parser.getDependency( 'light', nodeDef.extensions[ EXTENSIONS.KHR_LIGHTS_PUNCTUAL ].light );
+			}
 
-      } else {
+			if ( node !== objects[ 0 ] ) {
 
-        return Promise.resolve( new THREE.Object3D() );
+				for ( var i = 0, il = objects.length; i < il; i ++ ) {
 
-      }
+					node.add( objects[ i ] );
 
-    }() ).then( function ( node ) {
+				}
 
-      if ( nodeDef.name !== undefined ) {
+			}
 
-        node.name = THREE.PropertyBinding.sanitizeNodeName( nodeDef.name );
+			if ( nodeDef.name !== undefined ) {
 
-      }
+				node.userData.name = nodeDef.name;
+				node.name = THREE.PropertyBinding.sanitizeNodeName( nodeDef.name );
 
-      assignExtrasToUserData( node, nodeDef );
+			}
 
-      if ( nodeDef.extensions ) addUnknownExtensionsToUserData( extensions, node, nodeDef );
+			assignExtrasToUserData( node, nodeDef );
 
-      if ( nodeDef.matrix !== undefined ) {
+			if ( nodeDef.extensions ) addUnknownExtensionsToUserData( extensions, node, nodeDef );
 
-        var matrix = new THREE.Matrix4();
-        matrix.fromArray( nodeDef.matrix );
-        node.applyMatrix( matrix );
+			if ( nodeDef.matrix !== undefined ) {
 
-      } else {
+				var matrix = new THREE.Matrix4();
+				matrix.fromArray( nodeDef.matrix );
+				node.applyMatrix( matrix );
 
-        if ( nodeDef.translation !== undefined ) {
+			} else {
 
-          node.position.fromArray( nodeDef.translation );
+				if ( nodeDef.translation !== undefined ) {
 
-        }
+					node.position.fromArray( nodeDef.translation );
 
-        if ( nodeDef.rotation !== undefined ) {
+				}
 
-          node.quaternion.fromArray( nodeDef.rotation );
+				if ( nodeDef.rotation !== undefined ) {
 
-        }
+					node.quaternion.fromArray( nodeDef.rotation );
 
-        if ( nodeDef.scale !== undefined ) {
+				}
 
-          node.scale.fromArray( nodeDef.scale );
+				if ( nodeDef.scale !== undefined ) {
 
-        }
+					node.scale.fromArray( nodeDef.scale );
 
-      }
+				}
 
-      return node;
+			}
 
-    } );
+			return node;
 
-  };
+		} );
 
-  /**
-   * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#scenes
-   * @param {number} sceneIndex
-   * @return {Promise<THREE.Scene>}
-   */
-  GLTFParser.prototype.loadScene = function () {
+	};
 
-    // scene node hierachy builder
+	/**
+	 * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#scenes
+	 * @param {number} sceneIndex
+	 * @return {Promise<THREE.Scene>}
+	 */
+	GLTFParser.prototype.loadScene = function () {
 
-    function buildNodeHierachy( nodeId, parentObject, json, parser ) {
+		// scene node hierachy builder
 
-      var nodeDef = json.nodes[ nodeId ];
+		function buildNodeHierachy( nodeId, parentObject, json, parser ) {
 
-      return parser.getDependency( 'node', nodeId ).then( function ( node ) {
+			var nodeDef = json.nodes[ nodeId ];
 
-        if ( nodeDef.skin === undefined ) return node;
+			return parser.getDependency( 'node', nodeId ).then( function ( node ) {
 
-        // build skeleton here as well
+				if ( nodeDef.skin === undefined ) return node;
 
-        var skinEntry;
+				// build skeleton here as well
 
-        return parser.getDependency( 'skin', nodeDef.skin ).then( function ( skin ) {
+				var skinEntry;
 
-          skinEntry = skin;
+				return parser.getDependency( 'skin', nodeDef.skin ).then( function ( skin ) {
 
-          var pendingJoints = [];
+					skinEntry = skin;
 
-          for ( var i = 0, il = skinEntry.joints.length; i < il; i ++ ) {
+					var pendingJoints = [];
 
-            pendingJoints.push( parser.getDependency( 'node', skinEntry.joints[ i ] ) );
+					for ( var i = 0, il = skinEntry.joints.length; i < il; i ++ ) {
 
-          }
+						pendingJoints.push( parser.getDependency( 'node', skinEntry.joints[ i ] ) );
 
-          return Promise.all( pendingJoints );
+					}
 
-        } ).then( function ( jointNodes ) {
+					return Promise.all( pendingJoints );
 
-          var meshes = node.isGroup === true ? node.children : [ node ];
+				} ).then( function ( jointNodes ) {
 
-          for ( var i = 0, il = meshes.length; i < il; i ++ ) {
+					node.traverse( function ( mesh ) {
 
-            var mesh = meshes[ i ];
+						if ( ! mesh.isMesh ) return;
 
-            var bones = [];
-            var boneInverses = [];
+						var bones = [];
+						var boneInverses = [];
 
-            for ( var j = 0, jl = jointNodes.length; j < jl; j ++ ) {
+						for ( var j = 0, jl = jointNodes.length; j < jl; j ++ ) {
 
-              var jointNode = jointNodes[ j ];
+							var jointNode = jointNodes[ j ];
 
-              if ( jointNode ) {
+							if ( jointNode ) {
 
-                bones.push( jointNode );
+								bones.push( jointNode );
 
-                var mat = new THREE.Matrix4();
+								var mat = new THREE.Matrix4();
 
-                if ( skinEntry.inverseBindMatrices !== undefined ) {
+								if ( skinEntry.inverseBindMatrices !== undefined ) {
 
-                  mat.fromArray( skinEntry.inverseBindMatrices.array, j * 16 );
+									mat.fromArray( skinEntry.inverseBindMatrices.array, j * 16 );
 
-                }
+								}
 
-                boneInverses.push( mat );
+								boneInverses.push( mat );
 
-              } else {
+							} else {
 
-                console.warn( 'THREE.GLTFLoader: Joint "%s" could not be found.', skinEntry.joints[ j ] );
+								console.warn( 'THREE.GLTFLoader: Joint "%s" could not be found.', skinEntry.joints[ j ] );
 
-              }
+							}
 
-            }
+						}
 
-            mesh.bind( new THREE.Skeleton( bones, boneInverses ), mesh.matrixWorld );
+						mesh.bind( new THREE.Skeleton( bones, boneInverses ), mesh.matrixWorld );
 
-          }
+					} );
 
-          return node;
+					return node;
 
-        } );
+				} );
 
-      } ).then( function ( node ) {
+			} ).then( function ( node ) {
 
-        // build node hierachy
+				// build node hierachy
 
-        parentObject.add( node );
+				parentObject.add( node );
 
-        var pending = [];
+				var pending = [];
 
-        if ( nodeDef.children ) {
+				if ( nodeDef.children ) {
 
-          var children = nodeDef.children;
+					var children = nodeDef.children;
 
-          for ( var i = 0, il = children.length; i < il; i ++ ) {
+					for ( var i = 0, il = children.length; i < il; i ++ ) {
 
-            var child = children[ i ];
-            pending.push( buildNodeHierachy( child, node, json, parser ) );
+						var child = children[ i ];
+						pending.push( buildNodeHierachy( child, node, json, parser ) );
 
-          }
+					}
 
-        }
+				}
 
-        return Promise.all( pending );
+				return Promise.all( pending );
 
-      } );
+			} );
 
-    }
+		}
 
-    return function loadScene( sceneIndex ) {
+		return function loadScene( sceneIndex ) {
 
-      var json = this.json;
-      var extensions = this.extensions;
-      var sceneDef = this.json.scenes[ sceneIndex ];
-      var parser = this;
+			var json = this.json;
+			var extensions = this.extensions;
+			var sceneDef = this.json.scenes[ sceneIndex ];
+			var parser = this;
 
-      var scene = new THREE.Scene();
-      if ( sceneDef.name !== undefined ) scene.name = sceneDef.name;
+			var scene = new THREE.Scene();
+			if ( sceneDef.name !== undefined ) scene.name = sceneDef.name;
 
-      assignExtrasToUserData( scene, sceneDef );
+			assignExtrasToUserData( scene, sceneDef );
 
-      if ( sceneDef.extensions ) addUnknownExtensionsToUserData( extensions, scene, sceneDef );
+			if ( sceneDef.extensions ) addUnknownExtensionsToUserData( extensions, scene, sceneDef );
 
-      var nodeIds = sceneDef.nodes || [];
+			var nodeIds = sceneDef.nodes || [];
 
-      var pending = [];
+			var pending = [];
 
-      for ( var i = 0, il = nodeIds.length; i < il; i ++ ) {
+			for ( var i = 0, il = nodeIds.length; i < il; i ++ ) {
 
-        pending.push( buildNodeHierachy( nodeIds[ i ], scene, json, parser ) );
+				pending.push( buildNodeHierachy( nodeIds[ i ], scene, json, parser ) );
 
-      }
+			}
 
-      return Promise.all( pending ).then( function () {
+			return Promise.all( pending ).then( function () {
 
-        return scene;
+				return scene;
 
-      } );
+			} );
 
-    };
+		};
 
-  }();
+	}();
 
-  return GLTFLoader;
+	return GLTFLoader;
 
 } )();
\ No newline at end of file
diff --git a/webgl/gltf/index.html b/webgl/gltf/index.html
index 91e2bf6..55f8ae2 100644
--- a/webgl/gltf/index.html
+++ b/webgl/gltf/index.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 
 <head>
-  <script src="https://cdn.jsdelivr.net/npm/three@v0.104.0"></script>
+  <script src="https://cdn.jsdelivr.net/npm/three@v0.108.0"></script>
   <script src="GLTFLoader.js"></script>
   <script src="BasisTextureLoader.js"></script>
   <script src="https://cdn.jsdelivr.net/npm/three@v0.104.0/examples/js/controls/OrbitControls.js"></script>
-  <script src="../transcoder/build/basis_transcoder.js"></script>
+  <!-- <script src="../transcoder/build/basis_transcoder.js"></script> -->
   <style>
     html, body { width:100%; height:100%; margin:0; padding:0; }
     canvas { display:block; }
@@ -14,90 +14,104 @@
 </head>
 
 <body>
+    <div id="panel">
+      <strong>Basis Texture Transcoder glTF Demo</strong>
+      <div id="log"></div>
+  
+    </div>
   <script>
-    BASIS().then(Module => {
+    const renderer = new THREE.WebGLRenderer( { antialias: true } );
+    renderer.setSize( window.innerWidth, window.innerHeight );
+    renderer.gammaOutput = true;
+    renderer.gammaFactor = 2.2;
 
-      const { BasisFile, initializeBasis } = Module;
+    const scene = new THREE.Scene();
+    scene.background = new THREE.Color( 0xf0f0f0 );
 
-      window.BasisFile = BasisFile;
+    const light = new THREE.AmbientLight();
+    scene.add( light );
 
-      initializeBasis();
+    const light2 = new THREE.PointLight();
+    scene.add( light2 );
 
-      // Initialize three.js scene and renderer.
+    const camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.1, 100 );
+    camera.position.set( 8, 6, 5 );
+    camera.lookAt( new THREE.Vector3( 0, -2, 0 ) );
 
-      const renderer = new THREE.WebGLRenderer( { antialias: true } );
+    const controls = new THREE.OrbitControls( camera, renderer.domElement );
+    controls.autoRotate = true;
+
+    // Create BasisTextureLoader and detect supported target formats.
+
+    const basisLoader = new THREE.BasisTextureLoader();
+    basisLoader.setTranscoderPath( '../transcoder/build/' );
+    basisLoader.useAlpha = false;
+    basisLoader.detectSupport( renderer );
+
+    let formatName = 'Unknown format';
+    switch(basisLoader.workerConfig.format)
+    {
+      case THREE.BasisTextureLoader.BASIS_FORMAT.cTFASTC_4x4:
+        formatName = 'ASTC';
+        break;
+      case THREE.BasisTextureLoader.BASIS_FORMAT.cTFBC1:
+        formatName = 'BC1';
+        break;
+      case THREE.BasisTextureLoader.BASIS_FORMAT.cTFBC3:
+        formatName = 'BC3';
+        break;
+      case THREE.BasisTextureLoader.BASIS_FORMAT.cTFPVRTC1_4_RGB:
+      case THREE.BasisTextureLoader.BASIS_FORMAT.cTFPVRTC1_4_RGBA:
+        formatName = 'PVRTC';
+        break;
+      case THREE.BasisTextureLoader.BASIS_FORMAT.cTFETC1:
+        formatName = 'ETC1';
+        break;
+      default:
+        break;
+    }
+    log(`Transcode to: <strong>${formatName}</strong>`);
+
+    // Register BasisTextureLoader for .basis extension.
+
+    THREE.Loader.Handlers.add( /\.basis$/, basisLoader );
+
+    // Create GLTFLoader, load model, and render.
+
+    const loader = new THREE.GLTFLoader();
+
+    loader.load( 'assets/AgiHqSmall.gltf', ( gltf ) => {
+
+      const model = gltf.scene;
+      model.scale.set( 0.01, 0.01, 0.01 );
+
+      scene.add( model );
+
+      document.body.appendChild( renderer.domElement );
+
+      animate();
+
+    }, undefined, ( e ) => console.error( e ) );
+
+    // Main render loop.
+
+    function animate() {
+
+      requestAnimationFrame( animate );
+      controls.update();
+      renderer.render( scene, camera );
+
+    }
+
+    // Support viewport resizing.
+
+    window.addEventListener( 'resize', () => {
+
+      camera.aspect = window.innerWidth / window.innerHeight;
+      camera.updateProjectionMatrix();
       renderer.setSize( window.innerWidth, window.innerHeight );
-      renderer.gammaOutput = true;
-      renderer.gammaFactor = 2.2;
 
-      const scene = new THREE.Scene();
-      scene.background = new THREE.Color( 0xf0f0f0 );
-
-      const light = new THREE.AmbientLight();
-      scene.add( light );
-
-      const light2 = new THREE.PointLight();
-      scene.add( light2 );
-
-      const camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.1, 100 );
-      camera.position.set( 8, 6, 5 );
-      camera.lookAt( new THREE.Vector3( 0, -2, 0 ) );
-
-      const controls = new THREE.OrbitControls( camera, renderer.domElement );
-      controls.autoRotate = true;
-
-      // Create BasisTextureLoader and detect supported target formats.
-
-      const basisLoader = new THREE.BasisTextureLoader();
-      basisLoader.detectSupport( renderer );
-
-      const formatName = basisLoader.etcSupported
-        ? 'ETC1'
-        : ( basisLoader.dxtSupported ? 'BC1' : 'PVRTC' );
-      log(`Transcode to: <strong>${formatName}</strong>`);
-
-      // Register BasisTextureLoader for .basis extension.
-
-      THREE.Loader.Handlers.add( /\.basis$/, basisLoader );
-
-      // Create GLTFLoader, load model, and render.
-
-      const loader = new THREE.GLTFLoader();
-
-      loader.load( 'assets/AgiHqSmall.gltf', ( gltf ) => {
-
-        const model = gltf.scene;
-        model.scale.set( 0.01, 0.01, 0.01 );
-
-        scene.add( model );
-
-        document.body.appendChild( renderer.domElement );
-
-        animate();
-
-      }, undefined, ( e ) => console.error( e ) );
-
-      // Main render loop.
-
-      function animate() {
-
-        requestAnimationFrame( animate );
-        controls.update();
-        renderer.render( scene, camera );
-
-      }
-
-      // Support viewport resizing.
-
-      window.addEventListener( 'resize', () => {
-
-        camera.aspect = window.innerWidth / window.innerHeight;
-        camera.updateProjectionMatrix();
-        renderer.setSize( window.innerWidth, window.innerHeight );
-
-      }, false );
-
-    });
+    }, false );
 
     function log(s) {
 
@@ -107,11 +121,7 @@
 
     }
   </script>
-  <div id="panel">
-    <strong>Basis Texture Transcoder glTF Demo</strong>
-    <div id="log"></div>
-
-  </div>
+  
 </body>
 
 </html>
\ No newline at end of file
diff --git a/webgl/texture/index.html b/webgl/texture/index.html
index e3b39e6..931de31 100644
--- a/webgl/texture/index.html
+++ b/webgl/texture/index.html
@@ -79,6 +79,10 @@
   xhr.send(null);
 }
 
+// ASTC format, from:
+// https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_astc/
+COMPRESSED_RGBA_ASTC_4x4_KHR = 0x93B0;
+
 // DXT formats, from:
 // http://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/
 COMPRESSED_RGB_S3TC_DXT1_EXT  = 0x83F0;
@@ -86,15 +90,33 @@
 COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2;
 COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3;
 
+// ETC format, from:
+// https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_etc1/
+COMPRESSED_RGB_ETC1_WEBGL = 0x8D64;
+
+// PVRTC format, from:
+// https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_pvrtc/
+COMPRESSED_RGB_PVRTC_4BPPV1_IMG = 0x8C00;
+COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 0x8C02;
+
 BASIS_FORMAT = {
   cTFETC1: 0,
-	cTFBC1: 1,
-	cTFBC4: 2,
-	cTFPVRTC1_4_OPAQUE_ONLY: 3,
-	cTFBC7_M6_OPAQUE_ONLY: 4,
-	cTFETC2: 5,
-	cTFBC3: 6,
-	cTFBC5: 7,
+	cTFETC2: 1,
+	cTFBC1: 2,
+	cTFBC3: 3,
+	cTFBC4: 4,
+	cTFBC5: 5,
+	cTFBC7_M6_OPAQUE_ONLY: 6,
+  cTFBC7_M5: 7,
+  cTFPVRTC1_4_RGB: 8,
+  cTFPVRTC1_4_RGBA: 9,
+  cTFASTC_4x4: 10,
+  cTFATC_RGB: 11,
+  cTFATC_RGBA_INTERPOLATED_ALPHA: 12,
+  cTFRGBA32: 13,
+  cTFRGB565: 14,
+  cTFBGR565: 15,
+  cTFRGBA4444: 16,
 };
 
 BASIS_FORMAT_NAMES = {};
@@ -106,7 +128,10 @@
 DXT_FORMAT_MAP[BASIS_FORMAT.cTFBC1] = COMPRESSED_RGB_S3TC_DXT1_EXT;
 DXT_FORMAT_MAP[BASIS_FORMAT.cTFBC3] = COMPRESSED_RGBA_S3TC_DXT5_EXT;
 
-var dxtSupported = true;
+var astcSupported = false;
+var etcSupported = false;
+var dxtSupported = false;
+var pvrtcSupported = false;
 var drawMode = 0;
 
 var tex, width, height, images, levels, have_alpha, alignedWidth, alignedHeight, format;
@@ -116,18 +141,7 @@
   if (!width)
 	return;
 
-  if (dxtSupported)
-  {
-	  renderer.drawTexture(tex, alignedWidth, alignedHeight, drawMode);
-  }
-  else if (format == BASIS_FORMAT.cTFBC1)
-  {
-	  renderer.drawTexture(tex, alignedWidth, alignedHeight, drawMode);
-  }
-  else
-  {
-  	 log('TODO: Implement BC3->RGBA conversion for browsers that don\'t support BC3');
-  }
+  renderer.drawTexture(tex, alignedWidth, alignedHeight, drawMode);
 }
 
 function dataLoaded(data)
@@ -154,18 +168,52 @@
     return;
   }
 
-  format = BASIS_FORMAT.cTFBC1;
-  if (has_alpha)
+  var formatString = 'UNKNOWN';
+  if (astcSupported)
   {
-  	format = BASIS_FORMAT.cTFBC3;
-
-    log('Decoding .basis data to BC3');
+    formatString = 'ASTC';
+    format = BASIS_FORMAT.cTFASTC_4x4;
+  }
+  else if (dxtSupported)
+  {
+    if (has_alpha)
+    {
+      formatString = 'BC3';
+      format = BASIS_FORMAT.cTFBC3;
+    }
+    else
+    {
+      formatString = 'BC1';
+      format = BASIS_FORMAT.cTFBC1;
+    }
+  }
+  else if (pvrtcSupported)
+  {
+    if (has_alpha)
+    {
+      formatString = 'PVRTC1_RGBA';
+      format = BASIS_FORMAT.cTFPVRTC1_4_RGBA;
+    }
+    else
+    {
+      formatString = 'PVRTC1_RGB';
+      format = BASIS_FORMAT.cTFPVRTC1_4_RGB;
+    }
+  }
+  else if (etcSupported)
+  {
+    formatString = 'ETC1';
+    format = BASIS_FORMAT.cTFETC1;
   }
   else
   {
-  	log('Decoding .basis data to BC1');
+    formatString = 'RGB565';
+    format = BASIS_FORMAT.cTFBC1;
+    log('Decoding .basis data to BC1');
   }
 
+  elem('format').innerText = formatString;
+
   if (!basisFile.startTranscoding()) {
     console.warn('startTranscoding failed');
     basisFile.close();
@@ -202,12 +250,29 @@
   canvas.width = alignedWidth;
   canvas.height = alignedHeight;
 
-  if (dxtSupported)
+  if (format === BASIS_FORMAT.cTFASTC_4x4)
   {
-	  tex = renderer.createDxtTexture(dst, alignedWidth, alignedHeight, DXT_FORMAT_MAP[format]);
+    tex = renderer.createCompressedTexture(dst, alignedWidth, alignedHeight, COMPRESSED_RGBA_ASTC_4x4_KHR);
+  }
+  else if (formatString != 'RGB565' && (format === BASIS_FORMAT.cTFBC3 || format === BASIS_FORMAT.cTFBC1))
+  {
+	  tex = renderer.createCompressedTexture(dst, alignedWidth, alignedHeight, DXT_FORMAT_MAP[format]);
+  }
+  else if (format === BASIS_FORMAT.cTFETC1)
+  {
+    tex = renderer.createCompressedTexture(dst, alignedWidth, alignedHeight, COMPRESSED_RGB_ETC1_WEBGL);
+  }
+  else if (format === BASIS_FORMAT.cTFPVRTC1_4_RGB)
+  {
+    tex = renderer.createCompressedTexture(dst, alignedWidth, alignedHeight, COMPRESSED_RGB_PVRTC_4BPPV1_IMG);
+  }
+  else if (format === BASIS_FORMAT.cTFPVRTC1_4_RGBA)
+  {
+    tex = renderer.createCompressedTexture(dst, alignedWidth, alignedHeight, COMPRESSED_RGBA_PVRTC_4BPPV1_IMG);
   }
   else
   {
+    log('BC1 to RGB565');
   	var rgb565Data = dxtToRgb565(new Uint16Array(dst.buffer), 0, alignedWidth, alignedHeight);
 
 	  tex = renderer.createRgb565Texture(rgb565Data, alignedWidth, alignedHeight);
@@ -230,10 +295,10 @@
 <body>
   <br>
   <div style="font-size: 24pt; font-weight: bold">
-    .basis->BC1/BC3 transcoder test
+    .basis->Compressed texture transcoder test
   </div>
 
-  <br>This demo uses the Basis C++ transcoder (compiled to Javascript using Emscripten) to transcode a .basis file to BC1/BC3.
+  <br>This demo uses the Basis C++ transcoder (compiled to Javascript using Emscripten) to transcode a .basis file to <b id='format'>FORMAT</b>
   <br>Thanks to Evan Parker for providing <a href="https://github.com/toji/webgl-texture-utils">webgl-texture-utils</a> and this test bed.
   <br>
   <br>
@@ -247,10 +312,8 @@
 	  <input type="button" value="View Alpha" onclick="viewAlpha()"></input>
 
   <div style="position:absolute; left: 525px; top:130px; font-size: 20pt; font-weight: bold; color: red">
-    <div id="nodxt" style="display: none; width: 768px; font-size: 20pt; font-weight: bold; color: red">
-      NOTE: Your browser does not support DXT, so using RGB565
-      for the texture below.  To get DXT, try Chrome 19+
-      (beta channel as of 2012-04-20; graphics card DXT support also required).
+    <div id="no-compressed-tex" style="display: none; width: 768px; font-size: 20pt; font-weight: bold; color: red">
+      NOTE: Your browser does not support several compressed texture format, so using RGB565.
     </div>
     <canvas id='canvas'></canvas>
   </div>
@@ -260,9 +323,14 @@
 <script>
   BASIS({onRuntimeInitialized : () => {
     var gl = elem('canvas').getContext('webgl');
-    // Load the DXT extension, and verify it exists.
-    if (!gl.getExtension('WEBKIT_WEBGL_compressed_texture_s3tc') && !gl.getExtension('WEBGL_compressed_texture_s3tc')) {
-      dxtSupported = false;
+    
+    astcSupported = !!gl.getExtension('WEBGL_compressed_texture_astc');
+    etcSupported = !!gl.getExtension('WEBGL_compressed_texture_etc1');
+    dxtSupported = !!gl.getExtension('WEBGL_compressed_texture_s3tc');
+    pvrtcSupported = !!(gl.getExtension('WEBGL_compressed_texture_pvrtc')) || !!(gl.getExtension('WEBKIT_WEBGL_compressed_texture_pvrtc'));
+    
+    if (!(astcSupported || etcSupported || dxtSupported || pvrtcSupported))
+    {
       elem('nodxt').style.display = 'block';
     }
 
diff --git a/webgl/texture/renderer.js b/webgl/texture/renderer.js
index aba94a1..26f1a65 100644
--- a/webgl/texture/renderer.js
+++ b/webgl/texture/renderer.js
@@ -115,6 +115,27 @@
   return tex;
 };
 
+Renderer.prototype.createCompressedTexture = function(data, width, height, format) {
+  var gl = this.gl_;
+  var tex = gl.createTexture();
+  gl.bindTexture(gl.TEXTURE_2D, tex);
+  gl.compressedTexImage2D(
+      gl.TEXTURE_2D,
+      0,
+      format,
+      width,
+      height,
+      0,
+      data);
+  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+  //gl.generateMipmap(gl.TEXTURE_2D)
+  gl.bindTexture(gl.TEXTURE_2D, null);
+  return tex;
+};
+
 
 Renderer.prototype.createRgb565Texture = function(rgb565Data, width, height) {
   var gl = this.gl_;
diff --git a/webgl/transcoder/basis_wrappers.cpp b/webgl/transcoder/basis_wrappers.cpp
index d389d5a..8b6db05 100644
--- a/webgl/transcoder/basis_wrappers.cpp
+++ b/webgl/transcoder/basis_wrappers.cpp
@@ -119,7 +119,7 @@
     if (!m_transcoder.get_image_level_desc(m_file.data(), m_file.size(), image_index, level_index, orig_width, orig_height, total_blocks))
       return 0;
 
-    if (format == cTFPVRTC1_4_OPAQUE_ONLY)
+    if (format == cTFPVRTC1_4_RGB || format == cTFPVRTC1_4_RGBA)
     {
 	    // For PVRTC1, Basis only writes (or requires) total_blocks * bytes_per_block. But GL requires extra padding for very small textures: 
         // https://www.khronos.org/registry/OpenGL/extensions/IMG/IMG_texture_compression_pvrtc.txt
@@ -156,7 +156,7 @@
 
     uint32_t required_size = total_blocks * bytes_per_block;
 
-    if (format == cTFPVRTC1_4_OPAQUE_ONLY)
+    if (format == cTFPVRTC1_4_RGB || format == cTFPVRTC1_4_RGBA)
     {
 		// For PVRTC1, Basis only writes (or requires) total_blocks * bytes_per_block. But GL requires extra padding for very small textures: 
 		// https://www.khronos.org/registry/OpenGL/extensions/IMG/IMG_texture_compression_pvrtc.txt
diff --git a/webgl/transcoder/build/basis_transcoder.js b/webgl/transcoder/build/basis_transcoder.js
index 89d9529..3df0886 100644
--- a/webgl/transcoder/build/basis_transcoder.js
+++ b/webgl/transcoder/build/basis_transcoder.js
@@ -5,7 +5,7 @@
 function(BASIS) {
   BASIS = BASIS || {};
 
-var Module=typeof BASIS!=="undefined"?BASIS:{};var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}Module["arguments"]=[];Module["thisProgram"]="./this.program";Module["quit"]=function(status,toThrow){throw toThrow};Module["preRun"]=[];Module["postRun"]=[];var ENVIRONMENT_IS_WEB=false;var ENVIRONMENT_IS_WORKER=false;var ENVIRONMENT_IS_NODE=false;var ENVIRONMENT_HAS_NODE=false;var ENVIRONMENT_IS_SHELL=false;ENVIRONMENT_IS_WEB=typeof window==="object";ENVIRONMENT_IS_WORKER=typeof importScripts==="function";ENVIRONMENT_HAS_NODE=typeof process==="object"&&typeof require==="function";ENVIRONMENT_IS_NODE=ENVIRONMENT_HAS_NODE&&!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_WORKER;ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}else{return scriptDirectory+path}}if(ENVIRONMENT_IS_NODE){scriptDirectory=__dirname+"/";var nodeFS;var nodePath;Module["read"]=function shell_read(filename,binary){var ret;if(!nodeFS)nodeFS=require("fs");if(!nodePath)nodePath=require("path");filename=nodePath["normalize"](filename);ret=nodeFS["readFileSync"](filename);return binary?ret:ret.toString()};Module["readBinary"]=function readBinary(filename){var ret=Module["read"](filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}assert(ret.buffer);return ret};if(process["argv"].length>1){Module["thisProgram"]=process["argv"][1].replace(/\\/g,"/")}Module["arguments"]=process["argv"].slice(2);process["on"]("uncaughtException",function(ex){if(!(ex instanceof ExitStatus)){throw ex}});process["on"]("unhandledRejection",abort);Module["quit"]=function(status){process["exit"](status)};Module["inspect"]=function(){return"[Emscripten Module object]"}}else if(ENVIRONMENT_IS_SHELL){if(typeof read!="undefined"){Module["read"]=function shell_read(f){return read(f)}}Module["readBinary"]=function readBinary(f){var data;if(typeof readbuffer==="function"){return new Uint8Array(readbuffer(f))}data=read(f,"binary");assert(typeof data==="object");return data};if(typeof scriptArgs!="undefined"){Module["arguments"]=scriptArgs}else if(typeof arguments!="undefined"){Module["arguments"]=arguments}if(typeof quit==="function"){Module["quit"]=function(status){quit(status)}}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptDir){scriptDirectory=_scriptDir}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.lastIndexOf("/")+1)}else{scriptDirectory=""}Module["read"]=function shell_read(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){Module["readBinary"]=function readBinary(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}Module["readAsync"]=function readAsync(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function xhr_onload(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)};Module["setWindowTitle"]=function(title){document.title=title}}else{}var out=Module["print"]||(typeof console!=="undefined"?console.log.bind(console):typeof print!=="undefined"?print:null);var err=Module["printErr"]||(typeof printErr!=="undefined"?printErr:typeof console!=="undefined"&&console.warn.bind(console)||out);for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=undefined;var asm2wasmImports={"f64-rem":function(x,y){return x%y},"debugger":function(){debugger}};var functionPointers=new Array(0);var tempRet0=0;var setTempRet0=function(value){tempRet0=value};if(typeof WebAssembly!=="object"){err("no native wasm support detected")}var wasmMemory;var wasmTable;var ABORT=false;var EXITSTATUS=0;function assert(condition,text){if(!condition){abort("Assertion failed: "+text)}}var UTF8Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf8"):undefined;function UTF8ArrayToString(u8Array,idx,maxBytesToRead){var endIdx=idx+maxBytesToRead;var endPtr=idx;while(u8Array[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&u8Array.subarray&&UTF8Decoder){return UTF8Decoder.decode(u8Array.subarray(idx,endPtr))}else{var str="";while(idx<endPtr){var u0=u8Array[idx++];if(!(u0&128)){str+=String.fromCharCode(u0);continue}var u1=u8Array[idx++]&63;if((u0&224)==192){str+=String.fromCharCode((u0&31)<<6|u1);continue}var u2=u8Array[idx++]&63;if((u0&240)==224){u0=(u0&15)<<12|u1<<6|u2}else{u0=(u0&7)<<18|u1<<12|u2<<6|u8Array[idx++]&63}if(u0<65536){str+=String.fromCharCode(u0)}else{var ch=u0-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}}}return str}function UTF8ToString(ptr,maxBytesToRead){return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""}function stringToUTF8Array(str,outU8Array,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i<str.length;++i){var u=str.charCodeAt(i);if(u>=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;outU8Array[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;outU8Array[outIdx++]=192|u>>6;outU8Array[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;outU8Array[outIdx++]=224|u>>12;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;outU8Array[outIdx++]=240|u>>18;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}}outU8Array[outIdx]=0;return outIdx-startIdx}function stringToUTF8(str,outPtr,maxBytesToWrite){return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}function lengthBytesUTF8(str){var len=0;for(var i=0;i<str.length;++i){var u=str.charCodeAt(i);if(u>=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127)++len;else if(u<=2047)len+=2;else if(u<=65535)len+=3;else len+=4}return len}var UTF16Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf-16le"):undefined;var WASM_PAGE_SIZE=65536;function alignUp(x,multiple){if(x%multiple>0){x+=multiple-x%multiple}return x}var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBufferViews(){Module["HEAP8"]=HEAP8=new Int8Array(buffer);Module["HEAP16"]=HEAP16=new Int16Array(buffer);Module["HEAP32"]=HEAP32=new Int32Array(buffer);Module["HEAPU8"]=HEAPU8=new Uint8Array(buffer);Module["HEAPU16"]=HEAPU16=new Uint16Array(buffer);Module["HEAPU32"]=HEAPU32=new Uint32Array(buffer);Module["HEAPF32"]=HEAPF32=new Float32Array(buffer);Module["HEAPF64"]=HEAPF64=new Float64Array(buffer)}var DYNAMIC_BASE=5401280,DYNAMICTOP_PTR=158368;var TOTAL_STACK=5242880;var INITIAL_TOTAL_MEMORY=Module["TOTAL_MEMORY"]||16777216;if(INITIAL_TOTAL_MEMORY<TOTAL_STACK)err("TOTAL_MEMORY should be larger than TOTAL_STACK, was "+INITIAL_TOTAL_MEMORY+"! (TOTAL_STACK="+TOTAL_STACK+")");if(Module["buffer"]){buffer=Module["buffer"]}else{if(typeof WebAssembly==="object"&&typeof WebAssembly.Memory==="function"){wasmMemory=new WebAssembly.Memory({"initial":INITIAL_TOTAL_MEMORY/WASM_PAGE_SIZE});buffer=wasmMemory.buffer}else{buffer=new ArrayBuffer(INITIAL_TOTAL_MEMORY)}}updateGlobalBufferViews();HEAP32[DYNAMICTOP_PTR>>2]=DYNAMIC_BASE;function callRuntimeCallbacks(callbacks){while(callbacks.length>0){var callback=callbacks.shift();if(typeof callback=="function"){callback();continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){Module["dynCall_v"](func)}else{Module["dynCall_vi"](func,callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function ensureInitRuntime(){if(runtimeInitialized)return;runtimeInitialized=true;callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["preloadedImages"]={};Module["preloadedAudios"]={};var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return String.prototype.startsWith?filename.startsWith(dataURIPrefix):filename.indexOf(dataURIPrefix)===0}var wasmBinaryFile="basis_transcoder.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinary(){try{if(Module["wasmBinary"]){return new Uint8Array(Module["wasmBinary"])}if(Module["readBinary"]){return Module["readBinary"](wasmBinaryFile)}else{throw"both async and sync fetching of the wasm failed"}}catch(err){abort(err)}}function getBinaryPromise(){if(!Module["wasmBinary"]&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)&&typeof fetch==="function"){return fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){if(!response["ok"]){throw"failed to load wasm binary file at '"+wasmBinaryFile+"'"}return response["arrayBuffer"]()}).catch(function(){return getBinary()})}return new Promise(function(resolve,reject){resolve(getBinary())})}function createWasm(env){var info={"env":env,"global":{"NaN":NaN,Infinity:Infinity},"global.Math":Math,"asm2wasm":asm2wasmImports};function receiveInstance(instance,module){var exports=instance.exports;Module["asm"]=exports;removeRunDependency("wasm-instantiate")}addRunDependency("wasm-instantiate");function receiveInstantiatedSource(output){receiveInstance(output["instance"])}function instantiateArrayBuffer(receiver){return getBinaryPromise().then(function(binary){return WebAssembly.instantiate(binary,info)}).then(receiver,function(reason){err("failed to asynchronously prepare wasm: "+reason);abort(reason)})}function instantiateAsync(){if(!Module["wasmBinary"]&&typeof WebAssembly.instantiateStreaming==="function"&&!isDataURI(wasmBinaryFile)&&typeof fetch==="function"){return WebAssembly.instantiateStreaming(fetch(wasmBinaryFile,{credentials:"same-origin"}),info).then(receiveInstantiatedSource,function(reason){err("wasm streaming compile failed: "+reason);err("falling back to ArrayBuffer instantiation");instantiateArrayBuffer(receiveInstantiatedSource)})}else{return instantiateArrayBuffer(receiveInstantiatedSource)}}if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err("Module.instantiateWasm callback failed with error: "+e);return false}}instantiateAsync();return{}}Module["asm"]=function(global,env,providedBuffer){env["memory"]=wasmMemory;env["table"]=wasmTable=new WebAssembly.Table({"initial":70,"maximum":70,"element":"anyfunc"});env["__memory_base"]=1024;env["__table_base"]=0;var exports=createWasm(env);return exports};__ATINIT__.push({func:function(){globalCtors()}});function ___cxa_allocate_exception(size){return _malloc(size)}function __ZSt18uncaught_exceptionv(){return!!__ZSt18uncaught_exceptionv.uncaught_exception}function ___cxa_free_exception(ptr){try{return _free(ptr)}catch(e){}}var EXCEPTIONS={last:0,caught:[],infos:{},deAdjust:function(adjusted){if(!adjusted||EXCEPTIONS.infos[adjusted])return adjusted;for(var key in EXCEPTIONS.infos){var ptr=+key;var adj=EXCEPTIONS.infos[ptr].adjusted;var len=adj.length;for(var i=0;i<len;i++){if(adj[i]===adjusted){return ptr}}}return adjusted},addRef:function(ptr){if(!ptr)return;var info=EXCEPTIONS.infos[ptr];info.refcount++},decRef:function(ptr){if(!ptr)return;var info=EXCEPTIONS.infos[ptr];assert(info.refcount>0);info.refcount--;if(info.refcount===0&&!info.rethrown){if(info.destructor){Module["dynCall_vi"](info.destructor,ptr)}delete EXCEPTIONS.infos[ptr];___cxa_free_exception(ptr)}},clearRef:function(ptr){if(!ptr)return;var info=EXCEPTIONS.infos[ptr];info.refcount=0}};function ___cxa_throw(ptr,type,destructor){EXCEPTIONS.infos[ptr]={ptr:ptr,adjusted:[ptr],type:type,destructor:destructor,refcount:0,caught:false,rethrown:false};EXCEPTIONS.last=ptr;if(!("uncaught_exception"in __ZSt18uncaught_exceptionv)){__ZSt18uncaught_exceptionv.uncaught_exception=1}else{__ZSt18uncaught_exceptionv.uncaught_exception++}throw ptr}var PATH={splitPath:function(filename){var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:function(parts,allowAboveRoot){var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:function(path){var isAbsolute=path.charAt(0)==="/",trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(function(p){return!!p}),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:function(path){var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:function(path){if(path==="/")return"/";var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},extname:function(path){return PATH.splitPath(path)[3]},join:function(){var paths=Array.prototype.slice.call(arguments,0);return PATH.normalize(paths.join("/"))},join2:function(l,r){return PATH.normalize(l+"/"+r)}};var SYSCALLS={buffers:[null,[],[]],printChar:function(stream,curr){var buffer=SYSCALLS.buffers[stream];if(curr===0||curr===10){(stream===1?out:err)(UTF8ArrayToString(buffer,0));buffer.length=0}else{buffer.push(curr)}},varargs:0,get:function(varargs){SYSCALLS.varargs+=4;var ret=HEAP32[SYSCALLS.varargs-4>>2];return ret},getStr:function(){var ret=UTF8ToString(SYSCALLS.get());return ret},get64:function(){var low=SYSCALLS.get(),high=SYSCALLS.get();return low},getZero:function(){SYSCALLS.get()}};function ___syscall140(which,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(),offset_high=SYSCALLS.get(),offset_low=SYSCALLS.get(),result=SYSCALLS.get(),whence=SYSCALLS.get();return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall146(which,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.get(),iov=SYSCALLS.get(),iovcnt=SYSCALLS.get();var ret=0;for(var i=0;i<iovcnt;i++){var ptr=HEAP32[iov+i*8>>2];var len=HEAP32[iov+(i*8+4)>>2];for(var j=0;j<len;j++){SYSCALLS.printChar(stream,HEAPU8[ptr+j])}ret+=len}return ret}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall6(which,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD();return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function getShiftFromSize(size){switch(size){case 1:return 0;case 2:return 1;case 4:return 2;case 8:return 3;default:throw new TypeError("Unknown type size: "+size)}}function embind_init_charCodes(){var codes=new Array(256);for(var i=0;i<256;++i){codes[i]=String.fromCharCode(i)}embind_charCodes=codes}var embind_charCodes=undefined;function readLatin1String(ptr){var ret="";var c=ptr;while(HEAPU8[c]){ret+=embind_charCodes[HEAPU8[c++]]}return ret}var awaitingDependencies={};var registeredTypes={};var typeDependencies={};var char_0=48;var char_9=57;function makeLegalFunctionName(name){if(undefined===name){return"_unknown"}name=name.replace(/[^a-zA-Z0-9_]/g,"$");var f=name.charCodeAt(0);if(f>=char_0&&f<=char_9){return"_"+name}else{return name}}function createNamedFunction(name,body){name=makeLegalFunctionName(name);return new Function("body","return function "+name+"() {\n"+'    "use strict";'+"    return body.apply(this, arguments);\n"+"};\n")(body)}function extendError(baseErrorType,errorName){var errorClass=createNamedFunction(errorName,function(message){this.name=errorName;this.message=message;var stack=new Error(message).stack;if(stack!==undefined){this.stack=this.toString()+"\n"+stack.replace(/^Error(:[^\n]*)?\n/,"")}});errorClass.prototype=Object.create(baseErrorType.prototype);errorClass.prototype.constructor=errorClass;errorClass.prototype.toString=function(){if(this.message===undefined){return this.name}else{return this.name+": "+this.message}};return errorClass}var BindingError=undefined;function throwBindingError(message){throw new BindingError(message)}var InternalError=undefined;function throwInternalError(message){throw new InternalError(message)}function whenDependentTypesAreResolved(myTypes,dependentTypes,getTypeConverters){myTypes.forEach(function(type){typeDependencies[type]=dependentTypes});function onComplete(typeConverters){var myTypeConverters=getTypeConverters(typeConverters);if(myTypeConverters.length!==myTypes.length){throwInternalError("Mismatched type converter count")}for(var i=0;i<myTypes.length;++i){registerType(myTypes[i],myTypeConverters[i])}}var typeConverters=new Array(dependentTypes.length);var unregisteredTypes=[];var registered=0;dependentTypes.forEach(function(dt,i){if(registeredTypes.hasOwnProperty(dt)){typeConverters[i]=registeredTypes[dt]}else{unregisteredTypes.push(dt);if(!awaitingDependencies.hasOwnProperty(dt)){awaitingDependencies[dt]=[]}awaitingDependencies[dt].push(function(){typeConverters[i]=registeredTypes[dt];++registered;if(registered===unregisteredTypes.length){onComplete(typeConverters)}})}});if(0===unregisteredTypes.length){onComplete(typeConverters)}}function registerType(rawType,registeredInstance,options){options=options||{};if(!("argPackAdvance"in registeredInstance)){throw new TypeError("registerType registeredInstance requires argPackAdvance")}var name=registeredInstance.name;if(!rawType){throwBindingError('type "'+name+'" must have a positive integer typeid pointer')}if(registeredTypes.hasOwnProperty(rawType)){if(options.ignoreDuplicateRegistrations){return}else{throwBindingError("Cannot register type '"+name+"' twice")}}registeredTypes[rawType]=registeredInstance;delete typeDependencies[rawType];if(awaitingDependencies.hasOwnProperty(rawType)){var callbacks=awaitingDependencies[rawType];delete awaitingDependencies[rawType];callbacks.forEach(function(cb){cb()})}}function __embind_register_bool(rawType,name,size,trueValue,falseValue){var shift=getShiftFromSize(size);name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(wt){return!!wt},"toWireType":function(destructors,o){return o?trueValue:falseValue},"argPackAdvance":8,"readValueFromPointer":function(pointer){var heap;if(size===1){heap=HEAP8}else if(size===2){heap=HEAP16}else if(size===4){heap=HEAP32}else{throw new TypeError("Unknown boolean type size: "+name)}return this["fromWireType"](heap[pointer>>shift])},destructorFunction:null})}function ClassHandle_isAliasOf(other){if(!(this instanceof ClassHandle)){return false}if(!(other instanceof ClassHandle)){return false}var leftClass=this.$$.ptrType.registeredClass;var left=this.$$.ptr;var rightClass=other.$$.ptrType.registeredClass;var right=other.$$.ptr;while(leftClass.baseClass){left=leftClass.upcast(left);leftClass=leftClass.baseClass}while(rightClass.baseClass){right=rightClass.upcast(right);rightClass=rightClass.baseClass}return leftClass===rightClass&&left===right}function shallowCopyInternalPointer(o){return{count:o.count,deleteScheduled:o.deleteScheduled,preservePointerOnDelete:o.preservePointerOnDelete,ptr:o.ptr,ptrType:o.ptrType,smartPtr:o.smartPtr,smartPtrType:o.smartPtrType}}function throwInstanceAlreadyDeleted(obj){function getInstanceTypeName(handle){return handle.$$.ptrType.registeredClass.name}throwBindingError(getInstanceTypeName(obj)+" instance already deleted")}var finalizationGroup=false;function detachFinalizer(handle){}function runDestructor($$){if($$.smartPtr){$$.smartPtrType.rawDestructor($$.smartPtr)}else{$$.ptrType.registeredClass.rawDestructor($$.ptr)}}function releaseClassHandle($$){$$.count.value-=1;var toDelete=0===$$.count.value;if(toDelete){runDestructor($$)}}function attachFinalizer(handle){if("undefined"===typeof FinalizationGroup){attachFinalizer=function(handle){return handle};return handle}finalizationGroup=new FinalizationGroup(function(iter){for(var result=iter.next();!result.done;result=iter.next()){var $$=result.value;if(!$$.ptr){console.warn("object already deleted: "+$$.ptr)}else{releaseClassHandle($$)}}});attachFinalizer=function(handle){finalizationGroup.register(handle,handle.$$,handle.$$);return handle};detachFinalizer=function(handle){finalizationGroup.unregister(handle.$$)};return attachFinalizer(handle)}function ClassHandle_clone(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.preservePointerOnDelete){this.$$.count.value+=1;return this}else{var clone=attachFinalizer(Object.create(Object.getPrototypeOf(this),{$$:{value:shallowCopyInternalPointer(this.$$)}}));clone.$$.count.value+=1;clone.$$.deleteScheduled=false;return clone}}function ClassHandle_delete(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete){throwBindingError("Object already scheduled for deletion")}detachFinalizer(this);releaseClassHandle(this.$$);if(!this.$$.preservePointerOnDelete){this.$$.smartPtr=undefined;this.$$.ptr=undefined}}function ClassHandle_isDeleted(){return!this.$$.ptr}var delayFunction=undefined;var deletionQueue=[];function flushPendingDeletes(){while(deletionQueue.length){var obj=deletionQueue.pop();obj.$$.deleteScheduled=false;obj["delete"]()}}function ClassHandle_deleteLater(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete){throwBindingError("Object already scheduled for deletion")}deletionQueue.push(this);if(deletionQueue.length===1&&delayFunction){delayFunction(flushPendingDeletes)}this.$$.deleteScheduled=true;return this}function init_ClassHandle(){ClassHandle.prototype["isAliasOf"]=ClassHandle_isAliasOf;ClassHandle.prototype["clone"]=ClassHandle_clone;ClassHandle.prototype["delete"]=ClassHandle_delete;ClassHandle.prototype["isDeleted"]=ClassHandle_isDeleted;ClassHandle.prototype["deleteLater"]=ClassHandle_deleteLater}function ClassHandle(){}var registeredPointers={};function ensureOverloadTable(proto,methodName,humanName){if(undefined===proto[methodName].overloadTable){var prevFunc=proto[methodName];proto[methodName]=function(){if(!proto[methodName].overloadTable.hasOwnProperty(arguments.length)){throwBindingError("Function '"+humanName+"' called with an invalid number of arguments ("+arguments.length+") - expects one of ("+proto[methodName].overloadTable+")!")}return proto[methodName].overloadTable[arguments.length].apply(this,arguments)};proto[methodName].overloadTable=[];proto[methodName].overloadTable[prevFunc.argCount]=prevFunc}}function exposePublicSymbol(name,value,numArguments){if(Module.hasOwnProperty(name)){if(undefined===numArguments||undefined!==Module[name].overloadTable&&undefined!==Module[name].overloadTable[numArguments]){throwBindingError("Cannot register public name '"+name+"' twice")}ensureOverloadTable(Module,name,name);if(Module.hasOwnProperty(numArguments)){throwBindingError("Cannot register multiple overloads of a function with the same number of arguments ("+numArguments+")!")}Module[name].overloadTable[numArguments]=value}else{Module[name]=value;if(undefined!==numArguments){Module[name].numArguments=numArguments}}}function RegisteredClass(name,constructor,instancePrototype,rawDestructor,baseClass,getActualType,upcast,downcast){this.name=name;this.constructor=constructor;this.instancePrototype=instancePrototype;this.rawDestructor=rawDestructor;this.baseClass=baseClass;this.getActualType=getActualType;this.upcast=upcast;this.downcast=downcast;this.pureVirtualFunctions=[]}function upcastPointer(ptr,ptrClass,desiredClass){while(ptrClass!==desiredClass){if(!ptrClass.upcast){throwBindingError("Expected null or instance of "+desiredClass.name+", got an instance of "+ptrClass.name)}ptr=ptrClass.upcast(ptr);ptrClass=ptrClass.baseClass}return ptr}function constNoSmartPtrRawPointerToWireType(destructors,handle){if(handle===null){if(this.isReference){throwBindingError("null is not a valid "+this.name)}return 0}if(!handle.$$){throwBindingError('Cannot pass "'+_embind_repr(handle)+'" as a '+this.name)}if(!handle.$$.ptr){throwBindingError("Cannot pass deleted object as a pointer of type "+this.name)}var handleClass=handle.$$.ptrType.registeredClass;var ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);return ptr}function genericPointerToWireType(destructors,handle){var ptr;if(handle===null){if(this.isReference){throwBindingError("null is not a valid "+this.name)}if(this.isSmartPointer){ptr=this.rawConstructor();if(destructors!==null){destructors.push(this.rawDestructor,ptr)}return ptr}else{return 0}}if(!handle.$$){throwBindingError('Cannot pass "'+_embind_repr(handle)+'" as a '+this.name)}if(!handle.$$.ptr){throwBindingError("Cannot pass deleted object as a pointer of type "+this.name)}if(!this.isConst&&handle.$$.ptrType.isConst){throwBindingError("Cannot convert argument of type "+(handle.$$.smartPtrType?handle.$$.smartPtrType.name:handle.$$.ptrType.name)+" to parameter type "+this.name)}var handleClass=handle.$$.ptrType.registeredClass;ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);if(this.isSmartPointer){if(undefined===handle.$$.smartPtr){throwBindingError("Passing raw pointer to smart pointer is illegal")}switch(this.sharingPolicy){case 0:if(handle.$$.smartPtrType===this){ptr=handle.$$.smartPtr}else{throwBindingError("Cannot convert argument of type "+(handle.$$.smartPtrType?handle.$$.smartPtrType.name:handle.$$.ptrType.name)+" to parameter type "+this.name)}break;case 1:ptr=handle.$$.smartPtr;break;case 2:if(handle.$$.smartPtrType===this){ptr=handle.$$.smartPtr}else{var clonedHandle=handle["clone"]();ptr=this.rawShare(ptr,__emval_register(function(){clonedHandle["delete"]()}));if(destructors!==null){destructors.push(this.rawDestructor,ptr)}}break;default:throwBindingError("Unsupporting sharing policy")}}return ptr}function nonConstNoSmartPtrRawPointerToWireType(destructors,handle){if(handle===null){if(this.isReference){throwBindingError("null is not a valid "+this.name)}return 0}if(!handle.$$){throwBindingError('Cannot pass "'+_embind_repr(handle)+'" as a '+this.name)}if(!handle.$$.ptr){throwBindingError("Cannot pass deleted object as a pointer of type "+this.name)}if(handle.$$.ptrType.isConst){throwBindingError("Cannot convert argument of type "+handle.$$.ptrType.name+" to parameter type "+this.name)}var handleClass=handle.$$.ptrType.registeredClass;var ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);return ptr}function simpleReadValueFromPointer(pointer){return this["fromWireType"](HEAPU32[pointer>>2])}function RegisteredPointer_getPointee(ptr){if(this.rawGetPointee){ptr=this.rawGetPointee(ptr)}return ptr}function RegisteredPointer_destructor(ptr){if(this.rawDestructor){this.rawDestructor(ptr)}}function RegisteredPointer_deleteObject(handle){if(handle!==null){handle["delete"]()}}function downcastPointer(ptr,ptrClass,desiredClass){if(ptrClass===desiredClass){return ptr}if(undefined===desiredClass.baseClass){return null}var rv=downcastPointer(ptr,ptrClass,desiredClass.baseClass);if(rv===null){return null}return desiredClass.downcast(rv)}function getInheritedInstanceCount(){return Object.keys(registeredInstances).length}function getLiveInheritedInstances(){var rv=[];for(var k in registeredInstances){if(registeredInstances.hasOwnProperty(k)){rv.push(registeredInstances[k])}}return rv}function setDelayFunction(fn){delayFunction=fn;if(deletionQueue.length&&delayFunction){delayFunction(flushPendingDeletes)}}function init_embind(){Module["getInheritedInstanceCount"]=getInheritedInstanceCount;Module["getLiveInheritedInstances"]=getLiveInheritedInstances;Module["flushPendingDeletes"]=flushPendingDeletes;Module["setDelayFunction"]=setDelayFunction}var registeredInstances={};function getBasestPointer(class_,ptr){if(ptr===undefined){throwBindingError("ptr should not be undefined")}while(class_.baseClass){ptr=class_.upcast(ptr);class_=class_.baseClass}return ptr}function getInheritedInstance(class_,ptr){ptr=getBasestPointer(class_,ptr);return registeredInstances[ptr]}function makeClassHandle(prototype,record){if(!record.ptrType||!record.ptr){throwInternalError("makeClassHandle requires ptr and ptrType")}var hasSmartPtrType=!!record.smartPtrType;var hasSmartPtr=!!record.smartPtr;if(hasSmartPtrType!==hasSmartPtr){throwInternalError("Both smartPtrType and smartPtr must be specified")}record.count={value:1};return attachFinalizer(Object.create(prototype,{$$:{value:record}}))}function RegisteredPointer_fromWireType(ptr){var rawPointer=this.getPointee(ptr);if(!rawPointer){this.destructor(ptr);return null}var registeredInstance=getInheritedInstance(this.registeredClass,rawPointer);if(undefined!==registeredInstance){if(0===registeredInstance.$$.count.value){registeredInstance.$$.ptr=rawPointer;registeredInstance.$$.smartPtr=ptr;return registeredInstance["clone"]()}else{var rv=registeredInstance["clone"]();this.destructor(ptr);return rv}}function makeDefaultHandle(){if(this.isSmartPointer){return makeClassHandle(this.registeredClass.instancePrototype,{ptrType:this.pointeeType,ptr:rawPointer,smartPtrType:this,smartPtr:ptr})}else{return makeClassHandle(this.registeredClass.instancePrototype,{ptrType:this,ptr:ptr})}}var actualType=this.registeredClass.getActualType(rawPointer);var registeredPointerRecord=registeredPointers[actualType];if(!registeredPointerRecord){return makeDefaultHandle.call(this)}var toType;if(this.isConst){toType=registeredPointerRecord.constPointerType}else{toType=registeredPointerRecord.pointerType}var dp=downcastPointer(rawPointer,this.registeredClass,toType.registeredClass);if(dp===null){return makeDefaultHandle.call(this)}if(this.isSmartPointer){return makeClassHandle(toType.registeredClass.instancePrototype,{ptrType:toType,ptr:dp,smartPtrType:this,smartPtr:ptr})}else{return makeClassHandle(toType.registeredClass.instancePrototype,{ptrType:toType,ptr:dp})}}function init_RegisteredPointer(){RegisteredPointer.prototype.getPointee=RegisteredPointer_getPointee;RegisteredPointer.prototype.destructor=RegisteredPointer_destructor;RegisteredPointer.prototype["argPackAdvance"]=8;RegisteredPointer.prototype["readValueFromPointer"]=simpleReadValueFromPointer;RegisteredPointer.prototype["deleteObject"]=RegisteredPointer_deleteObject;RegisteredPointer.prototype["fromWireType"]=RegisteredPointer_fromWireType}function RegisteredPointer(name,registeredClass,isReference,isConst,isSmartPointer,pointeeType,sharingPolicy,rawGetPointee,rawConstructor,rawShare,rawDestructor){this.name=name;this.registeredClass=registeredClass;this.isReference=isReference;this.isConst=isConst;this.isSmartPointer=isSmartPointer;this.pointeeType=pointeeType;this.sharingPolicy=sharingPolicy;this.rawGetPointee=rawGetPointee;this.rawConstructor=rawConstructor;this.rawShare=rawShare;this.rawDestructor=rawDestructor;if(!isSmartPointer&&registeredClass.baseClass===undefined){if(isConst){this["toWireType"]=constNoSmartPtrRawPointerToWireType;this.destructorFunction=null}else{this["toWireType"]=nonConstNoSmartPtrRawPointerToWireType;this.destructorFunction=null}}else{this["toWireType"]=genericPointerToWireType}}function replacePublicSymbol(name,value,numArguments){if(!Module.hasOwnProperty(name)){throwInternalError("Replacing nonexistant public symbol")}if(undefined!==Module[name].overloadTable&&undefined!==numArguments){Module[name].overloadTable[numArguments]=value}else{Module[name]=value;Module[name].argCount=numArguments}}function embind__requireFunction(signature,rawFunction){signature=readLatin1String(signature);function makeDynCaller(dynCall){var args=[];for(var i=1;i<signature.length;++i){args.push("a"+i)}var name="dynCall_"+signature+"_"+rawFunction;var body="return function "+name+"("+args.join(", ")+") {\n";body+="    return dynCall(rawFunction"+(args.length?", ":"")+args.join(", ")+");\n";body+="};\n";return new Function("dynCall","rawFunction",body)(dynCall,rawFunction)}var fp;if(Module["FUNCTION_TABLE_"+signature]!==undefined){fp=Module["FUNCTION_TABLE_"+signature][rawFunction]}else if(typeof FUNCTION_TABLE!=="undefined"){fp=FUNCTION_TABLE[rawFunction]}else{var dc=Module["dynCall_"+signature];if(dc===undefined){dc=Module["dynCall_"+signature.replace(/f/g,"d")];if(dc===undefined){throwBindingError("No dynCall invoker for signature: "+signature)}}fp=makeDynCaller(dc)}if(typeof fp!=="function"){throwBindingError("unknown function pointer with signature "+signature+": "+rawFunction)}return fp}var UnboundTypeError=undefined;function getTypeName(type){var ptr=___getTypeName(type);var rv=readLatin1String(ptr);_free(ptr);return rv}function throwUnboundTypeError(message,types){var unboundTypes=[];var seen={};function visit(type){if(seen[type]){return}if(registeredTypes[type]){return}if(typeDependencies[type]){typeDependencies[type].forEach(visit);return}unboundTypes.push(type);seen[type]=true}types.forEach(visit);throw new UnboundTypeError(message+": "+unboundTypes.map(getTypeName).join([", "]))}function __embind_register_class(rawType,rawPointerType,rawConstPointerType,baseClassRawType,getActualTypeSignature,getActualType,upcastSignature,upcast,downcastSignature,downcast,name,destructorSignature,rawDestructor){name=readLatin1String(name);getActualType=embind__requireFunction(getActualTypeSignature,getActualType);if(upcast){upcast=embind__requireFunction(upcastSignature,upcast)}if(downcast){downcast=embind__requireFunction(downcastSignature,downcast)}rawDestructor=embind__requireFunction(destructorSignature,rawDestructor);var legalFunctionName=makeLegalFunctionName(name);exposePublicSymbol(legalFunctionName,function(){throwUnboundTypeError("Cannot construct "+name+" due to unbound types",[baseClassRawType])});whenDependentTypesAreResolved([rawType,rawPointerType,rawConstPointerType],baseClassRawType?[baseClassRawType]:[],function(base){base=base[0];var baseClass;var basePrototype;if(baseClassRawType){baseClass=base.registeredClass;basePrototype=baseClass.instancePrototype}else{basePrototype=ClassHandle.prototype}var constructor=createNamedFunction(legalFunctionName,function(){if(Object.getPrototypeOf(this)!==instancePrototype){throw new BindingError("Use 'new' to construct "+name)}if(undefined===registeredClass.constructor_body){throw new BindingError(name+" has no accessible constructor")}var body=registeredClass.constructor_body[arguments.length];if(undefined===body){throw new BindingError("Tried to invoke ctor of "+name+" with invalid number of parameters ("+arguments.length+") - expected ("+Object.keys(registeredClass.constructor_body).toString()+") parameters instead!")}return body.apply(this,arguments)});var instancePrototype=Object.create(basePrototype,{constructor:{value:constructor}});constructor.prototype=instancePrototype;var registeredClass=new RegisteredClass(name,constructor,instancePrototype,rawDestructor,baseClass,getActualType,upcast,downcast);var referenceConverter=new RegisteredPointer(name,registeredClass,true,false,false);var pointerConverter=new RegisteredPointer(name+"*",registeredClass,false,false,false);var constPointerConverter=new RegisteredPointer(name+" const*",registeredClass,false,true,false);registeredPointers[rawType]={pointerType:pointerConverter,constPointerType:constPointerConverter};replacePublicSymbol(legalFunctionName,constructor);return[referenceConverter,pointerConverter,constPointerConverter]})}function heap32VectorToArray(count,firstElement){var array=[];for(var i=0;i<count;i++){array.push(HEAP32[(firstElement>>2)+i])}return array}function runDestructors(destructors){while(destructors.length){var ptr=destructors.pop();var del=destructors.pop();del(ptr)}}function __embind_register_class_constructor(rawClassType,argCount,rawArgTypesAddr,invokerSignature,invoker,rawConstructor){var rawArgTypes=heap32VectorToArray(argCount,rawArgTypesAddr);invoker=embind__requireFunction(invokerSignature,invoker);whenDependentTypesAreResolved([],[rawClassType],function(classType){classType=classType[0];var humanName="constructor "+classType.name;if(undefined===classType.registeredClass.constructor_body){classType.registeredClass.constructor_body=[]}if(undefined!==classType.registeredClass.constructor_body[argCount-1]){throw new BindingError("Cannot register multiple constructors with identical number of parameters ("+(argCount-1)+") for class '"+classType.name+"'! Overload resolution is currently only performed using the parameter count, not actual type info!")}classType.registeredClass.constructor_body[argCount-1]=function unboundTypeHandler(){throwUnboundTypeError("Cannot construct "+classType.name+" due to unbound types",rawArgTypes)};whenDependentTypesAreResolved([],rawArgTypes,function(argTypes){classType.registeredClass.constructor_body[argCount-1]=function constructor_body(){if(arguments.length!==argCount-1){throwBindingError(humanName+" called with "+arguments.length+" arguments, expected "+(argCount-1))}var destructors=[];var args=new Array(argCount);args[0]=rawConstructor;for(var i=1;i<argCount;++i){args[i]=argTypes[i]["toWireType"](destructors,arguments[i-1])}var ptr=invoker.apply(null,args);runDestructors(destructors);return argTypes[0]["fromWireType"](ptr)};return[]});return[]})}function new_(constructor,argumentList){if(!(constructor instanceof Function)){throw new TypeError("new_ called with constructor type "+typeof constructor+" which is not a function")}var dummy=createNamedFunction(constructor.name||"unknownFunctionName",function(){});dummy.prototype=constructor.prototype;var obj=new dummy;var r=constructor.apply(obj,argumentList);return r instanceof Object?r:obj}function craftInvokerFunction(humanName,argTypes,classType,cppInvokerFunc,cppTargetFunc){var argCount=argTypes.length;if(argCount<2){throwBindingError("argTypes array size mismatch! Must at least get return value and 'this' types!")}var isClassMethodFunc=argTypes[1]!==null&&classType!==null;var needsDestructorStack=false;for(var i=1;i<argTypes.length;++i){if(argTypes[i]!==null&&argTypes[i].destructorFunction===undefined){needsDestructorStack=true;break}}var returns=argTypes[0].name!=="void";var argsList="";var argsListWired="";for(var i=0;i<argCount-2;++i){argsList+=(i!==0?", ":"")+"arg"+i;argsListWired+=(i!==0?", ":"")+"arg"+i+"Wired"}var invokerFnBody="return function "+makeLegalFunctionName(humanName)+"("+argsList+") {\n"+"if (arguments.length !== "+(argCount-2)+") {\n"+"throwBindingError('function "+humanName+" called with ' + arguments.length + ' arguments, expected "+(argCount-2)+" args!');\n"+"}\n";if(needsDestructorStack){invokerFnBody+="var destructors = [];\n"}var dtorStack=needsDestructorStack?"destructors":"null";var args1=["throwBindingError","invoker","fn","runDestructors","retType","classParam"];var args2=[throwBindingError,cppInvokerFunc,cppTargetFunc,runDestructors,argTypes[0],argTypes[1]];if(isClassMethodFunc){invokerFnBody+="var thisWired = classParam.toWireType("+dtorStack+", this);\n"}for(var i=0;i<argCount-2;++i){invokerFnBody+="var arg"+i+"Wired = argType"+i+".toWireType("+dtorStack+", arg"+i+"); // "+argTypes[i+2].name+"\n";args1.push("argType"+i);args2.push(argTypes[i+2])}if(isClassMethodFunc){argsListWired="thisWired"+(argsListWired.length>0?", ":"")+argsListWired}invokerFnBody+=(returns?"var rv = ":"")+"invoker(fn"+(argsListWired.length>0?", ":"")+argsListWired+");\n";if(needsDestructorStack){invokerFnBody+="runDestructors(destructors);\n"}else{for(var i=isClassMethodFunc?1:2;i<argTypes.length;++i){var paramName=i===1?"thisWired":"arg"+(i-2)+"Wired";if(argTypes[i].destructorFunction!==null){invokerFnBody+=paramName+"_dtor("+paramName+"); // "+argTypes[i].name+"\n";args1.push(paramName+"_dtor");args2.push(argTypes[i].destructorFunction)}}}if(returns){invokerFnBody+="var ret = retType.fromWireType(rv);\n"+"return ret;\n"}else{}invokerFnBody+="}\n";args1.push(invokerFnBody);var invokerFunction=new_(Function,args1).apply(null,args2);return invokerFunction}function __embind_register_class_function(rawClassType,methodName,argCount,rawArgTypesAddr,invokerSignature,rawInvoker,context,isPureVirtual){var rawArgTypes=heap32VectorToArray(argCount,rawArgTypesAddr);methodName=readLatin1String(methodName);rawInvoker=embind__requireFunction(invokerSignature,rawInvoker);whenDependentTypesAreResolved([],[rawClassType],function(classType){classType=classType[0];var humanName=classType.name+"."+methodName;if(isPureVirtual){classType.registeredClass.pureVirtualFunctions.push(methodName)}function unboundTypesHandler(){throwUnboundTypeError("Cannot call "+humanName+" due to unbound types",rawArgTypes)}var proto=classType.registeredClass.instancePrototype;var method=proto[methodName];if(undefined===method||undefined===method.overloadTable&&method.className!==classType.name&&method.argCount===argCount-2){unboundTypesHandler.argCount=argCount-2;unboundTypesHandler.className=classType.name;proto[methodName]=unboundTypesHandler}else{ensureOverloadTable(proto,methodName,humanName);proto[methodName].overloadTable[argCount-2]=unboundTypesHandler}whenDependentTypesAreResolved([],rawArgTypes,function(argTypes){var memberFunction=craftInvokerFunction(humanName,argTypes,classType,rawInvoker,context);if(undefined===proto[methodName].overloadTable){memberFunction.argCount=argCount-2;proto[methodName]=memberFunction}else{proto[methodName].overloadTable[argCount-2]=memberFunction}return[]});return[]})}var emval_free_list=[];var emval_handle_array=[{},{value:undefined},{value:null},{value:true},{value:false}];function __emval_decref(handle){if(handle>4&&0===--emval_handle_array[handle].refcount){emval_handle_array[handle]=undefined;emval_free_list.push(handle)}}function count_emval_handles(){var count=0;for(var i=5;i<emval_handle_array.length;++i){if(emval_handle_array[i]!==undefined){++count}}return count}function get_first_emval(){for(var i=5;i<emval_handle_array.length;++i){if(emval_handle_array[i]!==undefined){return emval_handle_array[i]}}return null}function init_emval(){Module["count_emval_handles"]=count_emval_handles;Module["get_first_emval"]=get_first_emval}function __emval_register(value){switch(value){case undefined:{return 1}case null:{return 2}case true:{return 3}case false:{return 4}default:{var handle=emval_free_list.length?emval_free_list.pop():emval_handle_array.length;emval_handle_array[handle]={refcount:1,value:value};return handle}}}function __embind_register_emval(rawType,name){name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(handle){var rv=emval_handle_array[handle].value;__emval_decref(handle);return rv},"toWireType":function(destructors,value){return __emval_register(value)},"argPackAdvance":8,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:null})}function _embind_repr(v){if(v===null){return"null"}var t=typeof v;if(t==="object"||t==="array"||t==="function"){return v.toString()}else{return""+v}}function floatReadValueFromPointer(name,shift){switch(shift){case 2:return function(pointer){return this["fromWireType"](HEAPF32[pointer>>2])};case 3:return function(pointer){return this["fromWireType"](HEAPF64[pointer>>3])};default:throw new TypeError("Unknown float type: "+name)}}function __embind_register_float(rawType,name,size){var shift=getShiftFromSize(size);name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(value){return value},"toWireType":function(destructors,value){if(typeof value!=="number"&&typeof value!=="boolean"){throw new TypeError('Cannot convert "'+_embind_repr(value)+'" to '+this.name)}return value},"argPackAdvance":8,"readValueFromPointer":floatReadValueFromPointer(name,shift),destructorFunction:null})}function __embind_register_function(name,argCount,rawArgTypesAddr,signature,rawInvoker,fn){var argTypes=heap32VectorToArray(argCount,rawArgTypesAddr);name=readLatin1String(name);rawInvoker=embind__requireFunction(signature,rawInvoker);exposePublicSymbol(name,function(){throwUnboundTypeError("Cannot call "+name+" due to unbound types",argTypes)},argCount-1);whenDependentTypesAreResolved([],argTypes,function(argTypes){var invokerArgsArray=[argTypes[0],null].concat(argTypes.slice(1));replacePublicSymbol(name,craftInvokerFunction(name,invokerArgsArray,null,rawInvoker,fn),argCount-1);return[]})}function integerReadValueFromPointer(name,shift,signed){switch(shift){case 0:return signed?function readS8FromPointer(pointer){return HEAP8[pointer]}:function readU8FromPointer(pointer){return HEAPU8[pointer]};case 1:return signed?function readS16FromPointer(pointer){return HEAP16[pointer>>1]}:function readU16FromPointer(pointer){return HEAPU16[pointer>>1]};case 2:return signed?function readS32FromPointer(pointer){return HEAP32[pointer>>2]}:function readU32FromPointer(pointer){return HEAPU32[pointer>>2]};default:throw new TypeError("Unknown integer type: "+name)}}function __embind_register_integer(primitiveType,name,size,minRange,maxRange){name=readLatin1String(name);if(maxRange===-1){maxRange=4294967295}var shift=getShiftFromSize(size);var fromWireType=function(value){return value};if(minRange===0){var bitshift=32-8*size;fromWireType=function(value){return value<<bitshift>>>bitshift}}var isUnsignedType=name.indexOf("unsigned")!=-1;registerType(primitiveType,{name:name,"fromWireType":fromWireType,"toWireType":function(destructors,value){if(typeof value!=="number"&&typeof value!=="boolean"){throw new TypeError('Cannot convert "'+_embind_repr(value)+'" to '+this.name)}if(value<minRange||value>maxRange){throw new TypeError('Passing a number "'+_embind_repr(value)+'" from JS side to C/C++ side to an argument of type "'+name+'", which is outside the valid range ['+minRange+", "+maxRange+"]!")}return isUnsignedType?value>>>0:value|0},"argPackAdvance":8,"readValueFromPointer":integerReadValueFromPointer(name,shift,minRange!==0),destructorFunction:null})}function __embind_register_memory_view(rawType,dataTypeIndex,name){var typeMapping=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];var TA=typeMapping[dataTypeIndex];function decodeMemoryView(handle){handle=handle>>2;var heap=HEAPU32;var size=heap[handle];var data=heap[handle+1];return new TA(heap["buffer"],data,size)}name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":decodeMemoryView,"argPackAdvance":8,"readValueFromPointer":decodeMemoryView},{ignoreDuplicateRegistrations:true})}function __embind_register_std_string(rawType,name){name=readLatin1String(name);var stdStringIsUTF8=name==="std::string";registerType(rawType,{name:name,"fromWireType":function(value){var length=HEAPU32[value>>2];var str;if(stdStringIsUTF8){var endChar=HEAPU8[value+4+length];var endCharSwap=0;if(endChar!=0){endCharSwap=endChar;HEAPU8[value+4+length]=0}var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i;if(HEAPU8[currentBytePtr]==0){var stringSegment=UTF8ToString(decodeStartPtr);if(str===undefined)str=stringSegment;else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+1}}if(endCharSwap!=0)HEAPU8[value+4+length]=endCharSwap}else{var a=new Array(length);for(var i=0;i<length;++i){a[i]=String.fromCharCode(HEAPU8[value+4+i])}str=a.join("")}_free(value);return str},"toWireType":function(destructors,value){if(value instanceof ArrayBuffer){value=new Uint8Array(value)}var getLength;var valueIsOfTypeString=typeof value==="string";if(!(valueIsOfTypeString||value instanceof Uint8Array||value instanceof Uint8ClampedArray||value instanceof Int8Array)){throwBindingError("Cannot pass non-string to std::string")}if(stdStringIsUTF8&&valueIsOfTypeString){getLength=function(){return lengthBytesUTF8(value)}}else{getLength=function(){return value.length}}var length=getLength();var ptr=_malloc(4+length+1);HEAPU32[ptr>>2]=length;if(stdStringIsUTF8&&valueIsOfTypeString){stringToUTF8(value,ptr+4,length+1)}else{if(valueIsOfTypeString){for(var i=0;i<length;++i){var charCode=value.charCodeAt(i);if(charCode>255){_free(ptr);throwBindingError("String has UTF-16 code units that do not fit in 8 bits")}HEAPU8[ptr+4+i]=charCode}}else{for(var i=0;i<length;++i){HEAPU8[ptr+4+i]=value[i]}}}if(destructors!==null){destructors.push(_free,ptr)}return ptr},"argPackAdvance":8,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:function(ptr){_free(ptr)}})}function __embind_register_std_wstring(rawType,charSize,name){name=readLatin1String(name);var getHeap,shift;if(charSize===2){getHeap=function(){return HEAPU16};shift=1}else if(charSize===4){getHeap=function(){return HEAPU32};shift=2}registerType(rawType,{name:name,"fromWireType":function(value){var HEAP=getHeap();var length=HEAPU32[value>>2];var a=new Array(length);var start=value+4>>shift;for(var i=0;i<length;++i){a[i]=String.fromCharCode(HEAP[start+i])}_free(value);return a.join("")},"toWireType":function(destructors,value){var HEAP=getHeap();var length=value.length;var ptr=_malloc(4+length*charSize);HEAPU32[ptr>>2]=length;var start=ptr+4>>shift;for(var i=0;i<length;++i){HEAP[start+i]=value.charCodeAt(i)}if(destructors!==null){destructors.push(_free,ptr)}return ptr},"argPackAdvance":8,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:function(ptr){_free(ptr)}})}function __embind_register_void(rawType,name){name=readLatin1String(name);registerType(rawType,{isVoid:true,name:name,"argPackAdvance":0,"fromWireType":function(){return undefined},"toWireType":function(destructors,o){return undefined}})}function requireHandle(handle){if(!handle){throwBindingError("Cannot use deleted val. handle = "+handle)}return emval_handle_array[handle].value}function requireRegisteredType(rawType,humanName){var impl=registeredTypes[rawType];if(undefined===impl){throwBindingError(humanName+" has unknown type "+getTypeName(rawType))}return impl}function __emval_as(handle,returnType,destructorsRef){handle=requireHandle(handle);returnType=requireRegisteredType(returnType,"emval::as");var destructors=[];var rd=__emval_register(destructors);HEAP32[destructorsRef>>2]=rd;return returnType["toWireType"](destructors,handle)}var emval_symbols={};function getStringOrSymbol(address){var symbol=emval_symbols[address];if(symbol===undefined){return readLatin1String(address)}else{return symbol}}var emval_methodCallers=[];function __emval_call_void_method(caller,handle,methodName,args){caller=emval_methodCallers[caller];handle=requireHandle(handle);methodName=getStringOrSymbol(methodName);caller(handle,methodName,null,args)}function emval_get_global(){return function(){return Function}()("return this")()}function __emval_get_global(name){if(name===0){return __emval_register(emval_get_global())}else{name=getStringOrSymbol(name);return __emval_register(emval_get_global()[name])}}function __emval_addMethodCaller(caller){var id=emval_methodCallers.length;emval_methodCallers.push(caller);return id}function __emval_lookupTypes(argCount,argTypes,argWireTypes){var a=new Array(argCount);for(var i=0;i<argCount;++i){a[i]=requireRegisteredType(HEAP32[(argTypes>>2)+i],"parameter "+i)}return a}function __emval_get_method_caller(argCount,argTypes){var types=__emval_lookupTypes(argCount,argTypes);var retType=types[0];var signatureName=retType.name+"_$"+types.slice(1).map(function(t){return t.name}).join("_")+"$";var params=["retType"];var args=[retType];var argsList="";for(var i=0;i<argCount-1;++i){argsList+=(i!==0?", ":"")+"arg"+i;params.push("argType"+i);args.push(types[1+i])}var functionName=makeLegalFunctionName("methodCaller_"+signatureName);var functionBody="return function "+functionName+"(handle, name, destructors, args) {\n";var offset=0;for(var i=0;i<argCount-1;++i){functionBody+="    var arg"+i+" = argType"+i+".readValueFromPointer(args"+(offset?"+"+offset:"")+");\n";offset+=types[i+1]["argPackAdvance"]}functionBody+="    var rv = handle[name]("+argsList+");\n";for(var i=0;i<argCount-1;++i){if(types[i+1]["deleteObject"]){functionBody+="    argType"+i+".deleteObject(arg"+i+");\n"}}if(!retType.isVoid){functionBody+="    return retType.toWireType(destructors, rv);\n"}functionBody+="};\n";params.push(functionBody);var invokerFunction=new_(Function,params).apply(null,args);return __emval_addMethodCaller(invokerFunction)}function __emval_get_module_property(name){name=getStringOrSymbol(name);return __emval_register(Module[name])}function __emval_get_property(handle,key){handle=requireHandle(handle);key=requireHandle(key);return __emval_register(handle[key])}function __emval_incref(handle){if(handle>4){emval_handle_array[handle].refcount+=1}}function craftEmvalAllocator(argCount){var argsList="";for(var i=0;i<argCount;++i){argsList+=(i!==0?", ":"")+"arg"+i}var functionBody="return function emval_allocator_"+argCount+"(constructor, argTypes, args) {\n";for(var i=0;i<argCount;++i){functionBody+="var argType"+i+" = requireRegisteredType(Module['HEAP32'][(argTypes >> 2) + "+i+'], "parameter '+i+'");\n'+"var arg"+i+" = argType"+i+".readValueFromPointer(args);\n"+"args += argType"+i+"['argPackAdvance'];\n"}functionBody+="var obj = new constructor("+argsList+");\n"+"return __emval_register(obj);\n"+"}\n";return new Function("requireRegisteredType","Module","__emval_register",functionBody)(requireRegisteredType,Module,__emval_register)}var emval_newers={};function __emval_new(handle,argCount,argTypes,args){handle=requireHandle(handle);var newer=emval_newers[argCount];if(!newer){newer=craftEmvalAllocator(argCount);emval_newers[argCount]=newer}return newer(handle,argTypes,args)}function __emval_new_cstring(v){return __emval_register(getStringOrSymbol(v))}function __emval_run_destructors(handle){var destructors=emval_handle_array[handle].value;runDestructors(destructors);__emval_decref(handle)}function _abort(){Module["abort"]()}function _emscripten_get_heap_size(){return HEAP8.length}function _emscripten_memcpy_big(dest,src,num){HEAPU8.set(HEAPU8.subarray(src,src+num),dest)}function ___setErrNo(value){if(Module["___errno_location"])HEAP32[Module["___errno_location"]()>>2]=value;return value}function abortOnCannotGrowMemory(requestedSize){abort("OOM")}function emscripten_realloc_buffer(size){var PAGE_MULTIPLE=65536;size=alignUp(size,PAGE_MULTIPLE);var oldSize=buffer.byteLength;try{var result=wasmMemory.grow((size-oldSize)/65536);if(result!==(-1|0)){buffer=wasmMemory.buffer;return true}else{return false}}catch(e){return false}}function _emscripten_resize_heap(requestedSize){var oldSize=_emscripten_get_heap_size();var PAGE_MULTIPLE=65536;var LIMIT=2147483648-PAGE_MULTIPLE;if(requestedSize>LIMIT){return false}var MIN_TOTAL_MEMORY=16777216;var newSize=Math.max(oldSize,MIN_TOTAL_MEMORY);while(newSize<requestedSize){if(newSize<=536870912){newSize=alignUp(2*newSize,PAGE_MULTIPLE)}else{newSize=Math.min(alignUp((3*newSize+2147483648)/4,PAGE_MULTIPLE),LIMIT)}}if(!emscripten_realloc_buffer(newSize)){return false}updateGlobalBufferViews();return true}embind_init_charCodes();BindingError=Module["BindingError"]=extendError(Error,"BindingError");InternalError=Module["InternalError"]=extendError(Error,"InternalError");init_ClassHandle();init_RegisteredPointer();init_embind();UnboundTypeError=Module["UnboundTypeError"]=extendError(Error,"UnboundTypeError");init_emval();var asmGlobalArg={};var asmLibraryArg={"d":abort,"B":setTempRet0,"i":___cxa_allocate_exception,"h":___cxa_throw,"n":___setErrNo,"A":___syscall140,"m":___syscall146,"z":___syscall6,"y":__embind_register_bool,"x":__embind_register_class,"w":__embind_register_class_constructor,"g":__embind_register_class_function,"K":__embind_register_emval,"v":__embind_register_float,"J":__embind_register_function,"f":__embind_register_integer,"c":__embind_register_memory_view,"u":__embind_register_std_string,"I":__embind_register_std_wstring,"H":__embind_register_void,"t":__emval_as,"s":__emval_call_void_method,"b":__emval_decref,"G":__emval_get_global,"r":__emval_get_method_caller,"q":__emval_get_module_property,"k":__emval_get_property,"l":__emval_incref,"p":__emval_new,"j":__emval_new_cstring,"o":__emval_run_destructors,"e":_abort,"F":_emscripten_get_heap_size,"E":_emscripten_memcpy_big,"D":_emscripten_resize_heap,"C":abortOnCannotGrowMemory,"a":DYNAMICTOP_PTR};var asm=Module["asm"](asmGlobalArg,asmLibraryArg,buffer);Module["asm"]=asm;var ___errno_location=Module["___errno_location"]=function(){return Module["asm"]["L"].apply(null,arguments)};var ___getTypeName=Module["___getTypeName"]=function(){return Module["asm"]["M"].apply(null,arguments)};var _free=Module["_free"]=function(){return Module["asm"]["N"].apply(null,arguments)};var _malloc=Module["_malloc"]=function(){return Module["asm"]["O"].apply(null,arguments)};var globalCtors=Module["globalCtors"]=function(){return Module["asm"]["ca"].apply(null,arguments)};var dynCall_ii=Module["dynCall_ii"]=function(){return Module["asm"]["P"].apply(null,arguments)};var dynCall_iidiiii=Module["dynCall_iidiiii"]=function(){return Module["asm"]["Q"].apply(null,arguments)};var dynCall_iii=Module["dynCall_iii"]=function(){return Module["asm"]["R"].apply(null,arguments)};var dynCall_iiii=Module["dynCall_iiii"]=function(){return Module["asm"]["S"].apply(null,arguments)};var dynCall_iiiii=Module["dynCall_iiiii"]=function(){return Module["asm"]["T"].apply(null,arguments)};var dynCall_iiiiii=Module["dynCall_iiiiii"]=function(){return Module["asm"]["U"].apply(null,arguments)};var dynCall_iiiiiiii=Module["dynCall_iiiiiiii"]=function(){return Module["asm"]["V"].apply(null,arguments)};var dynCall_iiiiiiiii=Module["dynCall_iiiiiiiii"]=function(){return Module["asm"]["W"].apply(null,arguments)};var dynCall_jiji=Module["dynCall_jiji"]=function(){return Module["asm"]["X"].apply(null,arguments)};var dynCall_v=Module["dynCall_v"]=function(){return Module["asm"]["Y"].apply(null,arguments)};var dynCall_vi=Module["dynCall_vi"]=function(){return Module["asm"]["Z"].apply(null,arguments)};var dynCall_vii=Module["dynCall_vii"]=function(){return Module["asm"]["_"].apply(null,arguments)};var dynCall_viiii=Module["dynCall_viiii"]=function(){return Module["asm"]["$"].apply(null,arguments)};var dynCall_viiiii=Module["dynCall_viiiii"]=function(){return Module["asm"]["aa"].apply(null,arguments)};var dynCall_viiiiii=Module["dynCall_viiiiii"]=function(){return Module["asm"]["ba"].apply(null,arguments)};Module["asm"]=asm;Module["then"]=function(func){if(Module["calledRun"]){func(Module)}else{var old=Module["onRuntimeInitialized"];Module["onRuntimeInitialized"]=function(){if(old)old();func(Module)}}return Module};function ExitStatus(status){this.name="ExitStatus";this.message="Program terminated with exit("+status+")";this.status=status}ExitStatus.prototype=new Error;ExitStatus.prototype.constructor=ExitStatus;dependenciesFulfilled=function runCaller(){if(!Module["calledRun"])run();if(!Module["calledRun"])dependenciesFulfilled=runCaller};function run(args){args=args||Module["arguments"];if(runDependencies>0){return}preRun();if(runDependencies>0)return;if(Module["calledRun"])return;function doRun(){if(Module["calledRun"])return;Module["calledRun"]=true;if(ABORT)return;ensureInitRuntime();preMain();if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}Module["run"]=run;function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}if(what!==undefined){out(what);err(what);what=JSON.stringify(what)}else{what=""}ABORT=true;EXITSTATUS=1;throw"abort("+what+"). Build with -s ASSERTIONS=1 for more info."}Module["abort"]=abort;if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}Module["noExitRuntime"]=true;run();
+var Module=typeof BASIS!=="undefined"?BASIS:{};var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}Module["arguments"]=[];Module["thisProgram"]="./this.program";Module["quit"]=function(status,toThrow){throw toThrow};Module["preRun"]=[];Module["postRun"]=[];var ENVIRONMENT_IS_WEB=false;var ENVIRONMENT_IS_WORKER=false;var ENVIRONMENT_IS_NODE=false;var ENVIRONMENT_IS_SHELL=false;ENVIRONMENT_IS_WEB=typeof window==="object";ENVIRONMENT_IS_WORKER=typeof importScripts==="function";ENVIRONMENT_IS_NODE=typeof process==="object"&&typeof require==="function"&&!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_WORKER;ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}else{return scriptDirectory+path}}if(ENVIRONMENT_IS_NODE){scriptDirectory=__dirname+"/";var nodeFS;var nodePath;Module["read"]=function shell_read(filename,binary){var ret;if(!nodeFS)nodeFS=require("fs");if(!nodePath)nodePath=require("path");filename=nodePath["normalize"](filename);ret=nodeFS["readFileSync"](filename);return binary?ret:ret.toString()};Module["readBinary"]=function readBinary(filename){var ret=Module["read"](filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}assert(ret.buffer);return ret};if(process["argv"].length>1){Module["thisProgram"]=process["argv"][1].replace(/\\/g,"/")}Module["arguments"]=process["argv"].slice(2);process["on"]("uncaughtException",function(ex){if(!(ex instanceof ExitStatus)){throw ex}});process["on"]("unhandledRejection",abort);Module["quit"]=function(status){process["exit"](status)};Module["inspect"]=function(){return"[Emscripten Module object]"}}else if(ENVIRONMENT_IS_SHELL){if(typeof read!="undefined"){Module["read"]=function shell_read(f){return read(f)}}Module["readBinary"]=function readBinary(f){var data;if(typeof readbuffer==="function"){return new Uint8Array(readbuffer(f))}data=read(f,"binary");assert(typeof data==="object");return data};if(typeof scriptArgs!="undefined"){Module["arguments"]=scriptArgs}else if(typeof arguments!="undefined"){Module["arguments"]=arguments}if(typeof quit==="function"){Module["quit"]=function(status){quit(status)}}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptDir){scriptDirectory=_scriptDir}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.lastIndexOf("/")+1)}else{scriptDirectory=""}Module["read"]=function shell_read(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){Module["readBinary"]=function readBinary(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}Module["readAsync"]=function readAsync(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function xhr_onload(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)};Module["setWindowTitle"]=function(title){document.title=title}}else{}var out=Module["print"]||(typeof console!=="undefined"?console.log.bind(console):typeof print!=="undefined"?print:null);var err=Module["printErr"]||(typeof printErr!=="undefined"?printErr:typeof console!=="undefined"&&console.warn.bind(console)||out);for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=undefined;var asm2wasmImports={"f64-rem":function(x,y){return x%y},"debugger":function(){debugger}};var functionPointers=new Array(0);var tempRet0=0;var setTempRet0=function(value){tempRet0=value};if(typeof WebAssembly!=="object"){err("no native wasm support detected")}var wasmMemory;var wasmTable;var ABORT=false;var EXITSTATUS=0;function assert(condition,text){if(!condition){abort("Assertion failed: "+text)}}var UTF8Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf8"):undefined;function UTF8ArrayToString(u8Array,idx,maxBytesToRead){var endIdx=idx+maxBytesToRead;var endPtr=idx;while(u8Array[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&u8Array.subarray&&UTF8Decoder){return UTF8Decoder.decode(u8Array.subarray(idx,endPtr))}else{var str="";while(idx<endPtr){var u0=u8Array[idx++];if(!(u0&128)){str+=String.fromCharCode(u0);continue}var u1=u8Array[idx++]&63;if((u0&224)==192){str+=String.fromCharCode((u0&31)<<6|u1);continue}var u2=u8Array[idx++]&63;if((u0&240)==224){u0=(u0&15)<<12|u1<<6|u2}else{u0=(u0&7)<<18|u1<<12|u2<<6|u8Array[idx++]&63}if(u0<65536){str+=String.fromCharCode(u0)}else{var ch=u0-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}}}return str}function UTF8ToString(ptr,maxBytesToRead){return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""}function stringToUTF8Array(str,outU8Array,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i<str.length;++i){var u=str.charCodeAt(i);if(u>=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;outU8Array[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;outU8Array[outIdx++]=192|u>>6;outU8Array[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;outU8Array[outIdx++]=224|u>>12;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;outU8Array[outIdx++]=240|u>>18;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}}outU8Array[outIdx]=0;return outIdx-startIdx}function stringToUTF8(str,outPtr,maxBytesToWrite){return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}function lengthBytesUTF8(str){var len=0;for(var i=0;i<str.length;++i){var u=str.charCodeAt(i);if(u>=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127)++len;else if(u<=2047)len+=2;else if(u<=65535)len+=3;else len+=4}return len}var UTF16Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf-16le"):undefined;var WASM_PAGE_SIZE=65536;function alignUp(x,multiple){if(x%multiple>0){x+=multiple-x%multiple}return x}var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBufferViews(){Module["HEAP8"]=HEAP8=new Int8Array(buffer);Module["HEAP16"]=HEAP16=new Int16Array(buffer);Module["HEAP32"]=HEAP32=new Int32Array(buffer);Module["HEAPU8"]=HEAPU8=new Uint8Array(buffer);Module["HEAPU16"]=HEAPU16=new Uint16Array(buffer);Module["HEAPU32"]=HEAPU32=new Uint32Array(buffer);Module["HEAPF32"]=HEAPF32=new Float32Array(buffer);Module["HEAPF64"]=HEAPF64=new Float64Array(buffer)}var DYNAMIC_BASE=6157184,DYNAMICTOP_PTR=914272;var TOTAL_STACK=5242880;var INITIAL_TOTAL_MEMORY=Module["TOTAL_MEMORY"]||16777216;if(INITIAL_TOTAL_MEMORY<TOTAL_STACK)err("TOTAL_MEMORY should be larger than TOTAL_STACK, was "+INITIAL_TOTAL_MEMORY+"! (TOTAL_STACK="+TOTAL_STACK+")");if(Module["buffer"]){buffer=Module["buffer"]}else{if(typeof WebAssembly==="object"&&typeof WebAssembly.Memory==="function"){wasmMemory=new WebAssembly.Memory({"initial":INITIAL_TOTAL_MEMORY/WASM_PAGE_SIZE});buffer=wasmMemory.buffer}else{buffer=new ArrayBuffer(INITIAL_TOTAL_MEMORY)}}updateGlobalBufferViews();HEAP32[DYNAMICTOP_PTR>>2]=DYNAMIC_BASE;function callRuntimeCallbacks(callbacks){while(callbacks.length>0){var callback=callbacks.shift();if(typeof callback=="function"){callback();continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){Module["dynCall_v"](func)}else{Module["dynCall_vi"](func,callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function ensureInitRuntime(){if(runtimeInitialized)return;runtimeInitialized=true;callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["preloadedImages"]={};Module["preloadedAudios"]={};var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return String.prototype.startsWith?filename.startsWith(dataURIPrefix):filename.indexOf(dataURIPrefix)===0}var wasmBinaryFile="basis_transcoder.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinary(){try{if(Module["wasmBinary"]){return new Uint8Array(Module["wasmBinary"])}if(Module["readBinary"]){return Module["readBinary"](wasmBinaryFile)}else{throw"both async and sync fetching of the wasm failed"}}catch(err){abort(err)}}function getBinaryPromise(){if(!Module["wasmBinary"]&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)&&typeof fetch==="function"){return fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){if(!response["ok"]){throw"failed to load wasm binary file at '"+wasmBinaryFile+"'"}return response["arrayBuffer"]()}).catch(function(){return getBinary()})}return new Promise(function(resolve,reject){resolve(getBinary())})}function createWasm(env){var info={"env":env,"global":{"NaN":NaN,Infinity:Infinity},"global.Math":Math,"asm2wasm":asm2wasmImports};function receiveInstance(instance,module){var exports=instance.exports;Module["asm"]=exports;removeRunDependency("wasm-instantiate")}addRunDependency("wasm-instantiate");if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err("Module.instantiateWasm callback failed with error: "+e);return false}}function receiveInstantiatedSource(output){receiveInstance(output["instance"])}function instantiateArrayBuffer(receiver){getBinaryPromise().then(function(binary){return WebAssembly.instantiate(binary,info)}).then(receiver,function(reason){err("failed to asynchronously prepare wasm: "+reason);abort(reason)})}if(!Module["wasmBinary"]&&typeof WebAssembly.instantiateStreaming==="function"&&!isDataURI(wasmBinaryFile)&&typeof fetch==="function"){WebAssembly.instantiateStreaming(fetch(wasmBinaryFile,{credentials:"same-origin"}),info).then(receiveInstantiatedSource,function(reason){err("wasm streaming compile failed: "+reason);err("falling back to ArrayBuffer instantiation");instantiateArrayBuffer(receiveInstantiatedSource)})}else{instantiateArrayBuffer(receiveInstantiatedSource)}return{}}Module["asm"]=function(global,env,providedBuffer){env["memory"]=wasmMemory;env["table"]=wasmTable=new WebAssembly.Table({"initial":70,"maximum":70,"element":"anyfunc"});env["__memory_base"]=1024;env["__table_base"]=0;var exports=createWasm(env);return exports};__ATINIT__.push({func:function(){globalCtors()}});function ___cxa_allocate_exception(size){return _malloc(size)}function __ZSt18uncaught_exceptionv(){return!!__ZSt18uncaught_exceptionv.uncaught_exception}function ___cxa_free_exception(ptr){try{return _free(ptr)}catch(e){}}var EXCEPTIONS={last:0,caught:[],infos:{},deAdjust:function(adjusted){if(!adjusted||EXCEPTIONS.infos[adjusted])return adjusted;for(var key in EXCEPTIONS.infos){var ptr=+key;var adj=EXCEPTIONS.infos[ptr].adjusted;var len=adj.length;for(var i=0;i<len;i++){if(adj[i]===adjusted){return ptr}}}return adjusted},addRef:function(ptr){if(!ptr)return;var info=EXCEPTIONS.infos[ptr];info.refcount++},decRef:function(ptr){if(!ptr)return;var info=EXCEPTIONS.infos[ptr];assert(info.refcount>0);info.refcount--;if(info.refcount===0&&!info.rethrown){if(info.destructor){Module["dynCall_vi"](info.destructor,ptr)}delete EXCEPTIONS.infos[ptr];___cxa_free_exception(ptr)}},clearRef:function(ptr){if(!ptr)return;var info=EXCEPTIONS.infos[ptr];info.refcount=0}};function ___cxa_throw(ptr,type,destructor){EXCEPTIONS.infos[ptr]={ptr:ptr,adjusted:[ptr],type:type,destructor:destructor,refcount:0,caught:false,rethrown:false};EXCEPTIONS.last=ptr;if(!("uncaught_exception"in __ZSt18uncaught_exceptionv)){__ZSt18uncaught_exceptionv.uncaught_exception=1}else{__ZSt18uncaught_exceptionv.uncaught_exception++}throw ptr}var SYSCALLS={buffers:[null,[],[]],printChar:function(stream,curr){var buffer=SYSCALLS.buffers[stream];if(curr===0||curr===10){(stream===1?out:err)(UTF8ArrayToString(buffer,0));buffer.length=0}else{buffer.push(curr)}},varargs:0,get:function(varargs){SYSCALLS.varargs+=4;var ret=HEAP32[SYSCALLS.varargs-4>>2];return ret},getStr:function(){var ret=UTF8ToString(SYSCALLS.get());return ret},get64:function(){var low=SYSCALLS.get(),high=SYSCALLS.get();return low},getZero:function(){SYSCALLS.get()}};function ___syscall140(which,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(),offset_high=SYSCALLS.get(),offset_low=SYSCALLS.get(),result=SYSCALLS.get(),whence=SYSCALLS.get();return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall146(which,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.get(),iov=SYSCALLS.get(),iovcnt=SYSCALLS.get();var ret=0;for(var i=0;i<iovcnt;i++){var ptr=HEAP32[iov+i*8>>2];var len=HEAP32[iov+(i*8+4)>>2];for(var j=0;j<len;j++){SYSCALLS.printChar(stream,HEAPU8[ptr+j])}ret+=len}return ret}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall6(which,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD();return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function getShiftFromSize(size){switch(size){case 1:return 0;case 2:return 1;case 4:return 2;case 8:return 3;default:throw new TypeError("Unknown type size: "+size)}}function embind_init_charCodes(){var codes=new Array(256);for(var i=0;i<256;++i){codes[i]=String.fromCharCode(i)}embind_charCodes=codes}var embind_charCodes=undefined;function readLatin1String(ptr){var ret="";var c=ptr;while(HEAPU8[c]){ret+=embind_charCodes[HEAPU8[c++]]}return ret}var awaitingDependencies={};var registeredTypes={};var typeDependencies={};var char_0=48;var char_9=57;function makeLegalFunctionName(name){if(undefined===name){return"_unknown"}name=name.replace(/[^a-zA-Z0-9_]/g,"$");var f=name.charCodeAt(0);if(f>=char_0&&f<=char_9){return"_"+name}else{return name}}function createNamedFunction(name,body){name=makeLegalFunctionName(name);return new Function("body","return function "+name+"() {\n"+'    "use strict";'+"    return body.apply(this, arguments);\n"+"};\n")(body)}function extendError(baseErrorType,errorName){var errorClass=createNamedFunction(errorName,function(message){this.name=errorName;this.message=message;var stack=new Error(message).stack;if(stack!==undefined){this.stack=this.toString()+"\n"+stack.replace(/^Error(:[^\n]*)?\n/,"")}});errorClass.prototype=Object.create(baseErrorType.prototype);errorClass.prototype.constructor=errorClass;errorClass.prototype.toString=function(){if(this.message===undefined){return this.name}else{return this.name+": "+this.message}};return errorClass}var BindingError=undefined;function throwBindingError(message){throw new BindingError(message)}var InternalError=undefined;function throwInternalError(message){throw new InternalError(message)}function whenDependentTypesAreResolved(myTypes,dependentTypes,getTypeConverters){myTypes.forEach(function(type){typeDependencies[type]=dependentTypes});function onComplete(typeConverters){var myTypeConverters=getTypeConverters(typeConverters);if(myTypeConverters.length!==myTypes.length){throwInternalError("Mismatched type converter count")}for(var i=0;i<myTypes.length;++i){registerType(myTypes[i],myTypeConverters[i])}}var typeConverters=new Array(dependentTypes.length);var unregisteredTypes=[];var registered=0;dependentTypes.forEach(function(dt,i){if(registeredTypes.hasOwnProperty(dt)){typeConverters[i]=registeredTypes[dt]}else{unregisteredTypes.push(dt);if(!awaitingDependencies.hasOwnProperty(dt)){awaitingDependencies[dt]=[]}awaitingDependencies[dt].push(function(){typeConverters[i]=registeredTypes[dt];++registered;if(registered===unregisteredTypes.length){onComplete(typeConverters)}})}});if(0===unregisteredTypes.length){onComplete(typeConverters)}}function registerType(rawType,registeredInstance,options){options=options||{};if(!("argPackAdvance"in registeredInstance)){throw new TypeError("registerType registeredInstance requires argPackAdvance")}var name=registeredInstance.name;if(!rawType){throwBindingError('type "'+name+'" must have a positive integer typeid pointer')}if(registeredTypes.hasOwnProperty(rawType)){if(options.ignoreDuplicateRegistrations){return}else{throwBindingError("Cannot register type '"+name+"' twice")}}registeredTypes[rawType]=registeredInstance;delete typeDependencies[rawType];if(awaitingDependencies.hasOwnProperty(rawType)){var callbacks=awaitingDependencies[rawType];delete awaitingDependencies[rawType];callbacks.forEach(function(cb){cb()})}}function __embind_register_bool(rawType,name,size,trueValue,falseValue){var shift=getShiftFromSize(size);name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(wt){return!!wt},"toWireType":function(destructors,o){return o?trueValue:falseValue},"argPackAdvance":8,"readValueFromPointer":function(pointer){var heap;if(size===1){heap=HEAP8}else if(size===2){heap=HEAP16}else if(size===4){heap=HEAP32}else{throw new TypeError("Unknown boolean type size: "+name)}return this["fromWireType"](heap[pointer>>shift])},destructorFunction:null})}function ClassHandle_isAliasOf(other){if(!(this instanceof ClassHandle)){return false}if(!(other instanceof ClassHandle)){return false}var leftClass=this.$$.ptrType.registeredClass;var left=this.$$.ptr;var rightClass=other.$$.ptrType.registeredClass;var right=other.$$.ptr;while(leftClass.baseClass){left=leftClass.upcast(left);leftClass=leftClass.baseClass}while(rightClass.baseClass){right=rightClass.upcast(right);rightClass=rightClass.baseClass}return leftClass===rightClass&&left===right}function shallowCopyInternalPointer(o){return{count:o.count,deleteScheduled:o.deleteScheduled,preservePointerOnDelete:o.preservePointerOnDelete,ptr:o.ptr,ptrType:o.ptrType,smartPtr:o.smartPtr,smartPtrType:o.smartPtrType}}function throwInstanceAlreadyDeleted(obj){function getInstanceTypeName(handle){return handle.$$.ptrType.registeredClass.name}throwBindingError(getInstanceTypeName(obj)+" instance already deleted")}function ClassHandle_clone(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.preservePointerOnDelete){this.$$.count.value+=1;return this}else{var clone=Object.create(Object.getPrototypeOf(this),{$$:{value:shallowCopyInternalPointer(this.$$)}});clone.$$.count.value+=1;clone.$$.deleteScheduled=false;return clone}}function runDestructor(handle){var $$=handle.$$;if($$.smartPtr){$$.smartPtrType.rawDestructor($$.smartPtr)}else{$$.ptrType.registeredClass.rawDestructor($$.ptr)}}function ClassHandle_delete(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete){throwBindingError("Object already scheduled for deletion")}this.$$.count.value-=1;var toDelete=0===this.$$.count.value;if(toDelete){runDestructor(this)}if(!this.$$.preservePointerOnDelete){this.$$.smartPtr=undefined;this.$$.ptr=undefined}}function ClassHandle_isDeleted(){return!this.$$.ptr}var delayFunction=undefined;var deletionQueue=[];function flushPendingDeletes(){while(deletionQueue.length){var obj=deletionQueue.pop();obj.$$.deleteScheduled=false;obj["delete"]()}}function ClassHandle_deleteLater(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete){throwBindingError("Object already scheduled for deletion")}deletionQueue.push(this);if(deletionQueue.length===1&&delayFunction){delayFunction(flushPendingDeletes)}this.$$.deleteScheduled=true;return this}function init_ClassHandle(){ClassHandle.prototype["isAliasOf"]=ClassHandle_isAliasOf;ClassHandle.prototype["clone"]=ClassHandle_clone;ClassHandle.prototype["delete"]=ClassHandle_delete;ClassHandle.prototype["isDeleted"]=ClassHandle_isDeleted;ClassHandle.prototype["deleteLater"]=ClassHandle_deleteLater}function ClassHandle(){}var registeredPointers={};function ensureOverloadTable(proto,methodName,humanName){if(undefined===proto[methodName].overloadTable){var prevFunc=proto[methodName];proto[methodName]=function(){if(!proto[methodName].overloadTable.hasOwnProperty(arguments.length)){throwBindingError("Function '"+humanName+"' called with an invalid number of arguments ("+arguments.length+") - expects one of ("+proto[methodName].overloadTable+")!")}return proto[methodName].overloadTable[arguments.length].apply(this,arguments)};proto[methodName].overloadTable=[];proto[methodName].overloadTable[prevFunc.argCount]=prevFunc}}function exposePublicSymbol(name,value,numArguments){if(Module.hasOwnProperty(name)){if(undefined===numArguments||undefined!==Module[name].overloadTable&&undefined!==Module[name].overloadTable[numArguments]){throwBindingError("Cannot register public name '"+name+"' twice")}ensureOverloadTable(Module,name,name);if(Module.hasOwnProperty(numArguments)){throwBindingError("Cannot register multiple overloads of a function with the same number of arguments ("+numArguments+")!")}Module[name].overloadTable[numArguments]=value}else{Module[name]=value;if(undefined!==numArguments){Module[name].numArguments=numArguments}}}function RegisteredClass(name,constructor,instancePrototype,rawDestructor,baseClass,getActualType,upcast,downcast){this.name=name;this.constructor=constructor;this.instancePrototype=instancePrototype;this.rawDestructor=rawDestructor;this.baseClass=baseClass;this.getActualType=getActualType;this.upcast=upcast;this.downcast=downcast;this.pureVirtualFunctions=[]}function upcastPointer(ptr,ptrClass,desiredClass){while(ptrClass!==desiredClass){if(!ptrClass.upcast){throwBindingError("Expected null or instance of "+desiredClass.name+", got an instance of "+ptrClass.name)}ptr=ptrClass.upcast(ptr);ptrClass=ptrClass.baseClass}return ptr}function constNoSmartPtrRawPointerToWireType(destructors,handle){if(handle===null){if(this.isReference){throwBindingError("null is not a valid "+this.name)}return 0}if(!handle.$$){throwBindingError('Cannot pass "'+_embind_repr(handle)+'" as a '+this.name)}if(!handle.$$.ptr){throwBindingError("Cannot pass deleted object as a pointer of type "+this.name)}var handleClass=handle.$$.ptrType.registeredClass;var ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);return ptr}function genericPointerToWireType(destructors,handle){var ptr;if(handle===null){if(this.isReference){throwBindingError("null is not a valid "+this.name)}if(this.isSmartPointer){ptr=this.rawConstructor();if(destructors!==null){destructors.push(this.rawDestructor,ptr)}return ptr}else{return 0}}if(!handle.$$){throwBindingError('Cannot pass "'+_embind_repr(handle)+'" as a '+this.name)}if(!handle.$$.ptr){throwBindingError("Cannot pass deleted object as a pointer of type "+this.name)}if(!this.isConst&&handle.$$.ptrType.isConst){throwBindingError("Cannot convert argument of type "+(handle.$$.smartPtrType?handle.$$.smartPtrType.name:handle.$$.ptrType.name)+" to parameter type "+this.name)}var handleClass=handle.$$.ptrType.registeredClass;ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);if(this.isSmartPointer){if(undefined===handle.$$.smartPtr){throwBindingError("Passing raw pointer to smart pointer is illegal")}switch(this.sharingPolicy){case 0:if(handle.$$.smartPtrType===this){ptr=handle.$$.smartPtr}else{throwBindingError("Cannot convert argument of type "+(handle.$$.smartPtrType?handle.$$.smartPtrType.name:handle.$$.ptrType.name)+" to parameter type "+this.name)}break;case 1:ptr=handle.$$.smartPtr;break;case 2:if(handle.$$.smartPtrType===this){ptr=handle.$$.smartPtr}else{var clonedHandle=handle["clone"]();ptr=this.rawShare(ptr,__emval_register(function(){clonedHandle["delete"]()}));if(destructors!==null){destructors.push(this.rawDestructor,ptr)}}break;default:throwBindingError("Unsupporting sharing policy")}}return ptr}function nonConstNoSmartPtrRawPointerToWireType(destructors,handle){if(handle===null){if(this.isReference){throwBindingError("null is not a valid "+this.name)}return 0}if(!handle.$$){throwBindingError('Cannot pass "'+_embind_repr(handle)+'" as a '+this.name)}if(!handle.$$.ptr){throwBindingError("Cannot pass deleted object as a pointer of type "+this.name)}if(handle.$$.ptrType.isConst){throwBindingError("Cannot convert argument of type "+handle.$$.ptrType.name+" to parameter type "+this.name)}var handleClass=handle.$$.ptrType.registeredClass;var ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);return ptr}function simpleReadValueFromPointer(pointer){return this["fromWireType"](HEAPU32[pointer>>2])}function RegisteredPointer_getPointee(ptr){if(this.rawGetPointee){ptr=this.rawGetPointee(ptr)}return ptr}function RegisteredPointer_destructor(ptr){if(this.rawDestructor){this.rawDestructor(ptr)}}function RegisteredPointer_deleteObject(handle){if(handle!==null){handle["delete"]()}}function downcastPointer(ptr,ptrClass,desiredClass){if(ptrClass===desiredClass){return ptr}if(undefined===desiredClass.baseClass){return null}var rv=downcastPointer(ptr,ptrClass,desiredClass.baseClass);if(rv===null){return null}return desiredClass.downcast(rv)}function getInheritedInstanceCount(){return Object.keys(registeredInstances).length}function getLiveInheritedInstances(){var rv=[];for(var k in registeredInstances){if(registeredInstances.hasOwnProperty(k)){rv.push(registeredInstances[k])}}return rv}function setDelayFunction(fn){delayFunction=fn;if(deletionQueue.length&&delayFunction){delayFunction(flushPendingDeletes)}}function init_embind(){Module["getInheritedInstanceCount"]=getInheritedInstanceCount;Module["getLiveInheritedInstances"]=getLiveInheritedInstances;Module["flushPendingDeletes"]=flushPendingDeletes;Module["setDelayFunction"]=setDelayFunction}var registeredInstances={};function getBasestPointer(class_,ptr){if(ptr===undefined){throwBindingError("ptr should not be undefined")}while(class_.baseClass){ptr=class_.upcast(ptr);class_=class_.baseClass}return ptr}function getInheritedInstance(class_,ptr){ptr=getBasestPointer(class_,ptr);return registeredInstances[ptr]}function makeClassHandle(prototype,record){if(!record.ptrType||!record.ptr){throwInternalError("makeClassHandle requires ptr and ptrType")}var hasSmartPtrType=!!record.smartPtrType;var hasSmartPtr=!!record.smartPtr;if(hasSmartPtrType!==hasSmartPtr){throwInternalError("Both smartPtrType and smartPtr must be specified")}record.count={value:1};return Object.create(prototype,{$$:{value:record}})}function RegisteredPointer_fromWireType(ptr){var rawPointer=this.getPointee(ptr);if(!rawPointer){this.destructor(ptr);return null}var registeredInstance=getInheritedInstance(this.registeredClass,rawPointer);if(undefined!==registeredInstance){if(0===registeredInstance.$$.count.value){registeredInstance.$$.ptr=rawPointer;registeredInstance.$$.smartPtr=ptr;return registeredInstance["clone"]()}else{var rv=registeredInstance["clone"]();this.destructor(ptr);return rv}}function makeDefaultHandle(){if(this.isSmartPointer){return makeClassHandle(this.registeredClass.instancePrototype,{ptrType:this.pointeeType,ptr:rawPointer,smartPtrType:this,smartPtr:ptr})}else{return makeClassHandle(this.registeredClass.instancePrototype,{ptrType:this,ptr:ptr})}}var actualType=this.registeredClass.getActualType(rawPointer);var registeredPointerRecord=registeredPointers[actualType];if(!registeredPointerRecord){return makeDefaultHandle.call(this)}var toType;if(this.isConst){toType=registeredPointerRecord.constPointerType}else{toType=registeredPointerRecord.pointerType}var dp=downcastPointer(rawPointer,this.registeredClass,toType.registeredClass);if(dp===null){return makeDefaultHandle.call(this)}if(this.isSmartPointer){return makeClassHandle(toType.registeredClass.instancePrototype,{ptrType:toType,ptr:dp,smartPtrType:this,smartPtr:ptr})}else{return makeClassHandle(toType.registeredClass.instancePrototype,{ptrType:toType,ptr:dp})}}function init_RegisteredPointer(){RegisteredPointer.prototype.getPointee=RegisteredPointer_getPointee;RegisteredPointer.prototype.destructor=RegisteredPointer_destructor;RegisteredPointer.prototype["argPackAdvance"]=8;RegisteredPointer.prototype["readValueFromPointer"]=simpleReadValueFromPointer;RegisteredPointer.prototype["deleteObject"]=RegisteredPointer_deleteObject;RegisteredPointer.prototype["fromWireType"]=RegisteredPointer_fromWireType}function RegisteredPointer(name,registeredClass,isReference,isConst,isSmartPointer,pointeeType,sharingPolicy,rawGetPointee,rawConstructor,rawShare,rawDestructor){this.name=name;this.registeredClass=registeredClass;this.isReference=isReference;this.isConst=isConst;this.isSmartPointer=isSmartPointer;this.pointeeType=pointeeType;this.sharingPolicy=sharingPolicy;this.rawGetPointee=rawGetPointee;this.rawConstructor=rawConstructor;this.rawShare=rawShare;this.rawDestructor=rawDestructor;if(!isSmartPointer&&registeredClass.baseClass===undefined){if(isConst){this["toWireType"]=constNoSmartPtrRawPointerToWireType;this.destructorFunction=null}else{this["toWireType"]=nonConstNoSmartPtrRawPointerToWireType;this.destructorFunction=null}}else{this["toWireType"]=genericPointerToWireType}}function replacePublicSymbol(name,value,numArguments){if(!Module.hasOwnProperty(name)){throwInternalError("Replacing nonexistant public symbol")}if(undefined!==Module[name].overloadTable&&undefined!==numArguments){Module[name].overloadTable[numArguments]=value}else{Module[name]=value;Module[name].argCount=numArguments}}function embind__requireFunction(signature,rawFunction){signature=readLatin1String(signature);function makeDynCaller(dynCall){var args=[];for(var i=1;i<signature.length;++i){args.push("a"+i)}var name="dynCall_"+signature+"_"+rawFunction;var body="return function "+name+"("+args.join(", ")+") {\n";body+="    return dynCall(rawFunction"+(args.length?", ":"")+args.join(", ")+");\n";body+="};\n";return new Function("dynCall","rawFunction",body)(dynCall,rawFunction)}var fp;if(Module["FUNCTION_TABLE_"+signature]!==undefined){fp=Module["FUNCTION_TABLE_"+signature][rawFunction]}else if(typeof FUNCTION_TABLE!=="undefined"){fp=FUNCTION_TABLE[rawFunction]}else{var dc=Module["dynCall_"+signature];if(dc===undefined){dc=Module["dynCall_"+signature.replace(/f/g,"d")];if(dc===undefined){throwBindingError("No dynCall invoker for signature: "+signature)}}fp=makeDynCaller(dc)}if(typeof fp!=="function"){throwBindingError("unknown function pointer with signature "+signature+": "+rawFunction)}return fp}var UnboundTypeError=undefined;function getTypeName(type){var ptr=___getTypeName(type);var rv=readLatin1String(ptr);_free(ptr);return rv}function throwUnboundTypeError(message,types){var unboundTypes=[];var seen={};function visit(type){if(seen[type]){return}if(registeredTypes[type]){return}if(typeDependencies[type]){typeDependencies[type].forEach(visit);return}unboundTypes.push(type);seen[type]=true}types.forEach(visit);throw new UnboundTypeError(message+": "+unboundTypes.map(getTypeName).join([", "]))}function __embind_register_class(rawType,rawPointerType,rawConstPointerType,baseClassRawType,getActualTypeSignature,getActualType,upcastSignature,upcast,downcastSignature,downcast,name,destructorSignature,rawDestructor){name=readLatin1String(name);getActualType=embind__requireFunction(getActualTypeSignature,getActualType);if(upcast){upcast=embind__requireFunction(upcastSignature,upcast)}if(downcast){downcast=embind__requireFunction(downcastSignature,downcast)}rawDestructor=embind__requireFunction(destructorSignature,rawDestructor);var legalFunctionName=makeLegalFunctionName(name);exposePublicSymbol(legalFunctionName,function(){throwUnboundTypeError("Cannot construct "+name+" due to unbound types",[baseClassRawType])});whenDependentTypesAreResolved([rawType,rawPointerType,rawConstPointerType],baseClassRawType?[baseClassRawType]:[],function(base){base=base[0];var baseClass;var basePrototype;if(baseClassRawType){baseClass=base.registeredClass;basePrototype=baseClass.instancePrototype}else{basePrototype=ClassHandle.prototype}var constructor=createNamedFunction(legalFunctionName,function(){if(Object.getPrototypeOf(this)!==instancePrototype){throw new BindingError("Use 'new' to construct "+name)}if(undefined===registeredClass.constructor_body){throw new BindingError(name+" has no accessible constructor")}var body=registeredClass.constructor_body[arguments.length];if(undefined===body){throw new BindingError("Tried to invoke ctor of "+name+" with invalid number of parameters ("+arguments.length+") - expected ("+Object.keys(registeredClass.constructor_body).toString()+") parameters instead!")}return body.apply(this,arguments)});var instancePrototype=Object.create(basePrototype,{constructor:{value:constructor}});constructor.prototype=instancePrototype;var registeredClass=new RegisteredClass(name,constructor,instancePrototype,rawDestructor,baseClass,getActualType,upcast,downcast);var referenceConverter=new RegisteredPointer(name,registeredClass,true,false,false);var pointerConverter=new RegisteredPointer(name+"*",registeredClass,false,false,false);var constPointerConverter=new RegisteredPointer(name+" const*",registeredClass,false,true,false);registeredPointers[rawType]={pointerType:pointerConverter,constPointerType:constPointerConverter};replacePublicSymbol(legalFunctionName,constructor);return[referenceConverter,pointerConverter,constPointerConverter]})}function heap32VectorToArray(count,firstElement){var array=[];for(var i=0;i<count;i++){array.push(HEAP32[(firstElement>>2)+i])}return array}function runDestructors(destructors){while(destructors.length){var ptr=destructors.pop();var del=destructors.pop();del(ptr)}}function __embind_register_class_constructor(rawClassType,argCount,rawArgTypesAddr,invokerSignature,invoker,rawConstructor){var rawArgTypes=heap32VectorToArray(argCount,rawArgTypesAddr);invoker=embind__requireFunction(invokerSignature,invoker);whenDependentTypesAreResolved([],[rawClassType],function(classType){classType=classType[0];var humanName="constructor "+classType.name;if(undefined===classType.registeredClass.constructor_body){classType.registeredClass.constructor_body=[]}if(undefined!==classType.registeredClass.constructor_body[argCount-1]){throw new BindingError("Cannot register multiple constructors with identical number of parameters ("+(argCount-1)+") for class '"+classType.name+"'! Overload resolution is currently only performed using the parameter count, not actual type info!")}classType.registeredClass.constructor_body[argCount-1]=function unboundTypeHandler(){throwUnboundTypeError("Cannot construct "+classType.name+" due to unbound types",rawArgTypes)};whenDependentTypesAreResolved([],rawArgTypes,function(argTypes){classType.registeredClass.constructor_body[argCount-1]=function constructor_body(){if(arguments.length!==argCount-1){throwBindingError(humanName+" called with "+arguments.length+" arguments, expected "+(argCount-1))}var destructors=[];var args=new Array(argCount);args[0]=rawConstructor;for(var i=1;i<argCount;++i){args[i]=argTypes[i]["toWireType"](destructors,arguments[i-1])}var ptr=invoker.apply(null,args);runDestructors(destructors);return argTypes[0]["fromWireType"](ptr)};return[]});return[]})}function new_(constructor,argumentList){if(!(constructor instanceof Function)){throw new TypeError("new_ called with constructor type "+typeof constructor+" which is not a function")}var dummy=createNamedFunction(constructor.name||"unknownFunctionName",function(){});dummy.prototype=constructor.prototype;var obj=new dummy;var r=constructor.apply(obj,argumentList);return r instanceof Object?r:obj}function craftInvokerFunction(humanName,argTypes,classType,cppInvokerFunc,cppTargetFunc){var argCount=argTypes.length;if(argCount<2){throwBindingError("argTypes array size mismatch! Must at least get return value and 'this' types!")}var isClassMethodFunc=argTypes[1]!==null&&classType!==null;var needsDestructorStack=false;for(var i=1;i<argTypes.length;++i){if(argTypes[i]!==null&&argTypes[i].destructorFunction===undefined){needsDestructorStack=true;break}}var returns=argTypes[0].name!=="void";var argsList="";var argsListWired="";for(var i=0;i<argCount-2;++i){argsList+=(i!==0?", ":"")+"arg"+i;argsListWired+=(i!==0?", ":"")+"arg"+i+"Wired"}var invokerFnBody="return function "+makeLegalFunctionName(humanName)+"("+argsList+") {\n"+"if (arguments.length !== "+(argCount-2)+") {\n"+"throwBindingError('function "+humanName+" called with ' + arguments.length + ' arguments, expected "+(argCount-2)+" args!');\n"+"}\n";if(needsDestructorStack){invokerFnBody+="var destructors = [];\n"}var dtorStack=needsDestructorStack?"destructors":"null";var args1=["throwBindingError","invoker","fn","runDestructors","retType","classParam"];var args2=[throwBindingError,cppInvokerFunc,cppTargetFunc,runDestructors,argTypes[0],argTypes[1]];if(isClassMethodFunc){invokerFnBody+="var thisWired = classParam.toWireType("+dtorStack+", this);\n"}for(var i=0;i<argCount-2;++i){invokerFnBody+="var arg"+i+"Wired = argType"+i+".toWireType("+dtorStack+", arg"+i+"); // "+argTypes[i+2].name+"\n";args1.push("argType"+i);args2.push(argTypes[i+2])}if(isClassMethodFunc){argsListWired="thisWired"+(argsListWired.length>0?", ":"")+argsListWired}invokerFnBody+=(returns?"var rv = ":"")+"invoker(fn"+(argsListWired.length>0?", ":"")+argsListWired+");\n";if(needsDestructorStack){invokerFnBody+="runDestructors(destructors);\n"}else{for(var i=isClassMethodFunc?1:2;i<argTypes.length;++i){var paramName=i===1?"thisWired":"arg"+(i-2)+"Wired";if(argTypes[i].destructorFunction!==null){invokerFnBody+=paramName+"_dtor("+paramName+"); // "+argTypes[i].name+"\n";args1.push(paramName+"_dtor");args2.push(argTypes[i].destructorFunction)}}}if(returns){invokerFnBody+="var ret = retType.fromWireType(rv);\n"+"return ret;\n"}else{}invokerFnBody+="}\n";args1.push(invokerFnBody);var invokerFunction=new_(Function,args1).apply(null,args2);return invokerFunction}function __embind_register_class_function(rawClassType,methodName,argCount,rawArgTypesAddr,invokerSignature,rawInvoker,context,isPureVirtual){var rawArgTypes=heap32VectorToArray(argCount,rawArgTypesAddr);methodName=readLatin1String(methodName);rawInvoker=embind__requireFunction(invokerSignature,rawInvoker);whenDependentTypesAreResolved([],[rawClassType],function(classType){classType=classType[0];var humanName=classType.name+"."+methodName;if(isPureVirtual){classType.registeredClass.pureVirtualFunctions.push(methodName)}function unboundTypesHandler(){throwUnboundTypeError("Cannot call "+humanName+" due to unbound types",rawArgTypes)}var proto=classType.registeredClass.instancePrototype;var method=proto[methodName];if(undefined===method||undefined===method.overloadTable&&method.className!==classType.name&&method.argCount===argCount-2){unboundTypesHandler.argCount=argCount-2;unboundTypesHandler.className=classType.name;proto[methodName]=unboundTypesHandler}else{ensureOverloadTable(proto,methodName,humanName);proto[methodName].overloadTable[argCount-2]=unboundTypesHandler}whenDependentTypesAreResolved([],rawArgTypes,function(argTypes){var memberFunction=craftInvokerFunction(humanName,argTypes,classType,rawInvoker,context);if(undefined===proto[methodName].overloadTable){memberFunction.argCount=argCount-2;proto[methodName]=memberFunction}else{proto[methodName].overloadTable[argCount-2]=memberFunction}return[]});return[]})}var emval_free_list=[];var emval_handle_array=[{},{value:undefined},{value:null},{value:true},{value:false}];function __emval_decref(handle){if(handle>4&&0===--emval_handle_array[handle].refcount){emval_handle_array[handle]=undefined;emval_free_list.push(handle)}}function count_emval_handles(){var count=0;for(var i=5;i<emval_handle_array.length;++i){if(emval_handle_array[i]!==undefined){++count}}return count}function get_first_emval(){for(var i=5;i<emval_handle_array.length;++i){if(emval_handle_array[i]!==undefined){return emval_handle_array[i]}}return null}function init_emval(){Module["count_emval_handles"]=count_emval_handles;Module["get_first_emval"]=get_first_emval}function __emval_register(value){switch(value){case undefined:{return 1}case null:{return 2}case true:{return 3}case false:{return 4}default:{var handle=emval_free_list.length?emval_free_list.pop():emval_handle_array.length;emval_handle_array[handle]={refcount:1,value:value};return handle}}}function __embind_register_emval(rawType,name){name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(handle){var rv=emval_handle_array[handle].value;__emval_decref(handle);return rv},"toWireType":function(destructors,value){return __emval_register(value)},"argPackAdvance":8,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:null})}function _embind_repr(v){if(v===null){return"null"}var t=typeof v;if(t==="object"||t==="array"||t==="function"){return v.toString()}else{return""+v}}function floatReadValueFromPointer(name,shift){switch(shift){case 2:return function(pointer){return this["fromWireType"](HEAPF32[pointer>>2])};case 3:return function(pointer){return this["fromWireType"](HEAPF64[pointer>>3])};default:throw new TypeError("Unknown float type: "+name)}}function __embind_register_float(rawType,name,size){var shift=getShiftFromSize(size);name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(value){return value},"toWireType":function(destructors,value){if(typeof value!=="number"&&typeof value!=="boolean"){throw new TypeError('Cannot convert "'+_embind_repr(value)+'" to '+this.name)}return value},"argPackAdvance":8,"readValueFromPointer":floatReadValueFromPointer(name,shift),destructorFunction:null})}function __embind_register_function(name,argCount,rawArgTypesAddr,signature,rawInvoker,fn){var argTypes=heap32VectorToArray(argCount,rawArgTypesAddr);name=readLatin1String(name);rawInvoker=embind__requireFunction(signature,rawInvoker);exposePublicSymbol(name,function(){throwUnboundTypeError("Cannot call "+name+" due to unbound types",argTypes)},argCount-1);whenDependentTypesAreResolved([],argTypes,function(argTypes){var invokerArgsArray=[argTypes[0],null].concat(argTypes.slice(1));replacePublicSymbol(name,craftInvokerFunction(name,invokerArgsArray,null,rawInvoker,fn),argCount-1);return[]})}function integerReadValueFromPointer(name,shift,signed){switch(shift){case 0:return signed?function readS8FromPointer(pointer){return HEAP8[pointer]}:function readU8FromPointer(pointer){return HEAPU8[pointer]};case 1:return signed?function readS16FromPointer(pointer){return HEAP16[pointer>>1]}:function readU16FromPointer(pointer){return HEAPU16[pointer>>1]};case 2:return signed?function readS32FromPointer(pointer){return HEAP32[pointer>>2]}:function readU32FromPointer(pointer){return HEAPU32[pointer>>2]};default:throw new TypeError("Unknown integer type: "+name)}}function __embind_register_integer(primitiveType,name,size,minRange,maxRange){name=readLatin1String(name);if(maxRange===-1){maxRange=4294967295}var shift=getShiftFromSize(size);var fromWireType=function(value){return value};if(minRange===0){var bitshift=32-8*size;fromWireType=function(value){return value<<bitshift>>>bitshift}}var isUnsignedType=name.indexOf("unsigned")!=-1;registerType(primitiveType,{name:name,"fromWireType":fromWireType,"toWireType":function(destructors,value){if(typeof value!=="number"&&typeof value!=="boolean"){throw new TypeError('Cannot convert "'+_embind_repr(value)+'" to '+this.name)}if(value<minRange||value>maxRange){throw new TypeError('Passing a number "'+_embind_repr(value)+'" from JS side to C/C++ side to an argument of type "'+name+'", which is outside the valid range ['+minRange+", "+maxRange+"]!")}return isUnsignedType?value>>>0:value|0},"argPackAdvance":8,"readValueFromPointer":integerReadValueFromPointer(name,shift,minRange!==0),destructorFunction:null})}function __embind_register_memory_view(rawType,dataTypeIndex,name){var typeMapping=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];var TA=typeMapping[dataTypeIndex];function decodeMemoryView(handle){handle=handle>>2;var heap=HEAPU32;var size=heap[handle];var data=heap[handle+1];return new TA(heap["buffer"],data,size)}name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":decodeMemoryView,"argPackAdvance":8,"readValueFromPointer":decodeMemoryView},{ignoreDuplicateRegistrations:true})}function __embind_register_std_string(rawType,name){name=readLatin1String(name);var stdStringIsUTF8=name==="std::string";registerType(rawType,{name:name,"fromWireType":function(value){var length=HEAPU32[value>>2];var str;if(stdStringIsUTF8){var endChar=HEAPU8[value+4+length];var endCharSwap=0;if(endChar!=0){endCharSwap=endChar;HEAPU8[value+4+length]=0}var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i;if(HEAPU8[currentBytePtr]==0){var stringSegment=UTF8ToString(decodeStartPtr);if(str===undefined)str=stringSegment;else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+1}}if(endCharSwap!=0)HEAPU8[value+4+length]=endCharSwap}else{var a=new Array(length);for(var i=0;i<length;++i){a[i]=String.fromCharCode(HEAPU8[value+4+i])}str=a.join("")}_free(value);return str},"toWireType":function(destructors,value){if(value instanceof ArrayBuffer){value=new Uint8Array(value)}var getLength;var valueIsOfTypeString=typeof value==="string";if(!(valueIsOfTypeString||value instanceof Uint8Array||value instanceof Uint8ClampedArray||value instanceof Int8Array)){throwBindingError("Cannot pass non-string to std::string")}if(stdStringIsUTF8&&valueIsOfTypeString){getLength=function(){return lengthBytesUTF8(value)}}else{getLength=function(){return value.length}}var length=getLength();var ptr=_malloc(4+length+1);HEAPU32[ptr>>2]=length;if(stdStringIsUTF8&&valueIsOfTypeString){stringToUTF8(value,ptr+4,length+1)}else{if(valueIsOfTypeString){for(var i=0;i<length;++i){var charCode=value.charCodeAt(i);if(charCode>255){_free(ptr);throwBindingError("String has UTF-16 code units that do not fit in 8 bits")}HEAPU8[ptr+4+i]=charCode}}else{for(var i=0;i<length;++i){HEAPU8[ptr+4+i]=value[i]}}}if(destructors!==null){destructors.push(_free,ptr)}return ptr},"argPackAdvance":8,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:function(ptr){_free(ptr)}})}function __embind_register_std_wstring(rawType,charSize,name){name=readLatin1String(name);var getHeap,shift;if(charSize===2){getHeap=function(){return HEAPU16};shift=1}else if(charSize===4){getHeap=function(){return HEAPU32};shift=2}registerType(rawType,{name:name,"fromWireType":function(value){var HEAP=getHeap();var length=HEAPU32[value>>2];var a=new Array(length);var start=value+4>>shift;for(var i=0;i<length;++i){a[i]=String.fromCharCode(HEAP[start+i])}_free(value);return a.join("")},"toWireType":function(destructors,value){var HEAP=getHeap();var length=value.length;var ptr=_malloc(4+length*charSize);HEAPU32[ptr>>2]=length;var start=ptr+4>>shift;for(var i=0;i<length;++i){HEAP[start+i]=value.charCodeAt(i)}if(destructors!==null){destructors.push(_free,ptr)}return ptr},"argPackAdvance":8,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:function(ptr){_free(ptr)}})}function __embind_register_void(rawType,name){name=readLatin1String(name);registerType(rawType,{isVoid:true,name:name,"argPackAdvance":0,"fromWireType":function(){return undefined},"toWireType":function(destructors,o){return undefined}})}function requireHandle(handle){if(!handle){throwBindingError("Cannot use deleted val. handle = "+handle)}return emval_handle_array[handle].value}function requireRegisteredType(rawType,humanName){var impl=registeredTypes[rawType];if(undefined===impl){throwBindingError(humanName+" has unknown type "+getTypeName(rawType))}return impl}function __emval_as(handle,returnType,destructorsRef){handle=requireHandle(handle);returnType=requireRegisteredType(returnType,"emval::as");var destructors=[];var rd=__emval_register(destructors);HEAP32[destructorsRef>>2]=rd;return returnType["toWireType"](destructors,handle)}var emval_symbols={};function getStringOrSymbol(address){var symbol=emval_symbols[address];if(symbol===undefined){return readLatin1String(address)}else{return symbol}}var emval_methodCallers=[];function __emval_call_void_method(caller,handle,methodName,args){caller=emval_methodCallers[caller];handle=requireHandle(handle);methodName=getStringOrSymbol(methodName);caller(handle,methodName,null,args)}function emval_get_global(){return function(){return Function}()("return this")()}function __emval_get_global(name){if(name===0){return __emval_register(emval_get_global())}else{name=getStringOrSymbol(name);return __emval_register(emval_get_global()[name])}}function __emval_addMethodCaller(caller){var id=emval_methodCallers.length;emval_methodCallers.push(caller);return id}function __emval_lookupTypes(argCount,argTypes,argWireTypes){var a=new Array(argCount);for(var i=0;i<argCount;++i){a[i]=requireRegisteredType(HEAP32[(argTypes>>2)+i],"parameter "+i)}return a}function __emval_get_method_caller(argCount,argTypes){var types=__emval_lookupTypes(argCount,argTypes);var retType=types[0];var signatureName=retType.name+"_$"+types.slice(1).map(function(t){return t.name}).join("_")+"$";var params=["retType"];var args=[retType];var argsList="";for(var i=0;i<argCount-1;++i){argsList+=(i!==0?", ":"")+"arg"+i;params.push("argType"+i);args.push(types[1+i])}var functionName=makeLegalFunctionName("methodCaller_"+signatureName);var functionBody="return function "+functionName+"(handle, name, destructors, args) {\n";var offset=0;for(var i=0;i<argCount-1;++i){functionBody+="    var arg"+i+" = argType"+i+".readValueFromPointer(args"+(offset?"+"+offset:"")+");\n";offset+=types[i+1]["argPackAdvance"]}functionBody+="    var rv = handle[name]("+argsList+");\n";for(var i=0;i<argCount-1;++i){if(types[i+1]["deleteObject"]){functionBody+="    argType"+i+".deleteObject(arg"+i+");\n"}}if(!retType.isVoid){functionBody+="    return retType.toWireType(destructors, rv);\n"}functionBody+="};\n";params.push(functionBody);var invokerFunction=new_(Function,params).apply(null,args);return __emval_addMethodCaller(invokerFunction)}function __emval_get_module_property(name){name=getStringOrSymbol(name);return __emval_register(Module[name])}function __emval_get_property(handle,key){handle=requireHandle(handle);key=requireHandle(key);return __emval_register(handle[key])}function __emval_incref(handle){if(handle>4){emval_handle_array[handle].refcount+=1}}function craftEmvalAllocator(argCount){var argsList="";for(var i=0;i<argCount;++i){argsList+=(i!==0?", ":"")+"arg"+i}var functionBody="return function emval_allocator_"+argCount+"(constructor, argTypes, args) {\n";for(var i=0;i<argCount;++i){functionBody+="var argType"+i+" = requireRegisteredType(Module['HEAP32'][(argTypes >> 2) + "+i+'], "parameter '+i+'");\n'+"var arg"+i+" = argType"+i+".readValueFromPointer(args);\n"+"args += argType"+i+"['argPackAdvance'];\n"}functionBody+="var obj = new constructor("+argsList+");\n"+"return __emval_register(obj);\n"+"}\n";return new Function("requireRegisteredType","Module","__emval_register",functionBody)(requireRegisteredType,Module,__emval_register)}var emval_newers={};function __emval_new(handle,argCount,argTypes,args){handle=requireHandle(handle);var newer=emval_newers[argCount];if(!newer){newer=craftEmvalAllocator(argCount);emval_newers[argCount]=newer}return newer(handle,argTypes,args)}function __emval_new_cstring(v){return __emval_register(getStringOrSymbol(v))}function __emval_run_destructors(handle){var destructors=emval_handle_array[handle].value;runDestructors(destructors);__emval_decref(handle)}function _abort(){Module["abort"]()}function _emscripten_get_heap_size(){return HEAP8.length}function abortOnCannotGrowMemory(requestedSize){abort("OOM")}function emscripten_realloc_buffer(size){var PAGE_MULTIPLE=65536;size=alignUp(size,PAGE_MULTIPLE);var oldSize=buffer.byteLength;try{var result=wasmMemory.grow((size-oldSize)/65536);if(result!==(-1|0)){buffer=wasmMemory.buffer;return true}else{return false}}catch(e){return false}}function _emscripten_resize_heap(requestedSize){var oldSize=_emscripten_get_heap_size();var PAGE_MULTIPLE=65536;var LIMIT=2147483648-PAGE_MULTIPLE;if(requestedSize>LIMIT){return false}var MIN_TOTAL_MEMORY=16777216;var newSize=Math.max(oldSize,MIN_TOTAL_MEMORY);while(newSize<requestedSize){if(newSize<=536870912){newSize=alignUp(2*newSize,PAGE_MULTIPLE)}else{newSize=Math.min(alignUp((3*newSize+2147483648)/4,PAGE_MULTIPLE),LIMIT)}}if(!emscripten_realloc_buffer(newSize)){return false}updateGlobalBufferViews();return true}function _emscripten_memcpy_big(dest,src,num){HEAPU8.set(HEAPU8.subarray(src,src+num),dest)}function ___setErrNo(value){if(Module["___errno_location"])HEAP32[Module["___errno_location"]()>>2]=value;return value}embind_init_charCodes();BindingError=Module["BindingError"]=extendError(Error,"BindingError");InternalError=Module["InternalError"]=extendError(Error,"InternalError");init_ClassHandle();init_RegisteredPointer();init_embind();UnboundTypeError=Module["UnboundTypeError"]=extendError(Error,"UnboundTypeError");init_emval();var asmGlobalArg={};var asmLibraryArg={"d":abort,"B":setTempRet0,"i":___cxa_allocate_exception,"h":___cxa_throw,"n":___setErrNo,"A":___syscall140,"m":___syscall146,"z":___syscall6,"y":__embind_register_bool,"x":__embind_register_class,"w":__embind_register_class_constructor,"g":__embind_register_class_function,"K":__embind_register_emval,"v":__embind_register_float,"J":__embind_register_function,"f":__embind_register_integer,"c":__embind_register_memory_view,"u":__embind_register_std_string,"I":__embind_register_std_wstring,"H":__embind_register_void,"t":__emval_as,"s":__emval_call_void_method,"b":__emval_decref,"G":__emval_get_global,"r":__emval_get_method_caller,"q":__emval_get_module_property,"k":__emval_get_property,"l":__emval_incref,"p":__emval_new,"j":__emval_new_cstring,"o":__emval_run_destructors,"e":_abort,"F":_emscripten_get_heap_size,"E":_emscripten_memcpy_big,"D":_emscripten_resize_heap,"C":abortOnCannotGrowMemory,"a":DYNAMICTOP_PTR};var asm=Module["asm"](asmGlobalArg,asmLibraryArg,buffer);Module["asm"]=asm;var ___errno_location=Module["___errno_location"]=function(){return Module["asm"]["L"].apply(null,arguments)};var ___getTypeName=Module["___getTypeName"]=function(){return Module["asm"]["M"].apply(null,arguments)};var _free=Module["_free"]=function(){return Module["asm"]["N"].apply(null,arguments)};var _malloc=Module["_malloc"]=function(){return Module["asm"]["O"].apply(null,arguments)};var globalCtors=Module["globalCtors"]=function(){return Module["asm"]["ca"].apply(null,arguments)};var dynCall_ii=Module["dynCall_ii"]=function(){return Module["asm"]["P"].apply(null,arguments)};var dynCall_iidiiii=Module["dynCall_iidiiii"]=function(){return Module["asm"]["Q"].apply(null,arguments)};var dynCall_iii=Module["dynCall_iii"]=function(){return Module["asm"]["R"].apply(null,arguments)};var dynCall_iiii=Module["dynCall_iiii"]=function(){return Module["asm"]["S"].apply(null,arguments)};var dynCall_iiiii=Module["dynCall_iiiii"]=function(){return Module["asm"]["T"].apply(null,arguments)};var dynCall_iiiiii=Module["dynCall_iiiiii"]=function(){return Module["asm"]["U"].apply(null,arguments)};var dynCall_iiiiiiii=Module["dynCall_iiiiiiii"]=function(){return Module["asm"]["V"].apply(null,arguments)};var dynCall_iiiiiiiii=Module["dynCall_iiiiiiiii"]=function(){return Module["asm"]["W"].apply(null,arguments)};var dynCall_jiji=Module["dynCall_jiji"]=function(){return Module["asm"]["X"].apply(null,arguments)};var dynCall_v=Module["dynCall_v"]=function(){return Module["asm"]["Y"].apply(null,arguments)};var dynCall_vi=Module["dynCall_vi"]=function(){return Module["asm"]["Z"].apply(null,arguments)};var dynCall_vii=Module["dynCall_vii"]=function(){return Module["asm"]["_"].apply(null,arguments)};var dynCall_viiii=Module["dynCall_viiii"]=function(){return Module["asm"]["$"].apply(null,arguments)};var dynCall_viiiii=Module["dynCall_viiiii"]=function(){return Module["asm"]["aa"].apply(null,arguments)};var dynCall_viiiiii=Module["dynCall_viiiiii"]=function(){return Module["asm"]["ba"].apply(null,arguments)};Module["asm"]=asm;Module["then"]=function(func){if(Module["calledRun"]){func(Module)}else{var old=Module["onRuntimeInitialized"];Module["onRuntimeInitialized"]=function(){if(old)old();func(Module)}}return Module};function ExitStatus(status){this.name="ExitStatus";this.message="Program terminated with exit("+status+")";this.status=status}ExitStatus.prototype=new Error;ExitStatus.prototype.constructor=ExitStatus;dependenciesFulfilled=function runCaller(){if(!Module["calledRun"])run();if(!Module["calledRun"])dependenciesFulfilled=runCaller};function run(args){args=args||Module["arguments"];if(runDependencies>0){return}preRun();if(runDependencies>0)return;if(Module["calledRun"])return;function doRun(){if(Module["calledRun"])return;Module["calledRun"]=true;if(ABORT)return;ensureInitRuntime();preMain();if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}Module["run"]=run;function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}if(what!==undefined){out(what);err(what);what=JSON.stringify(what)}else{what=""}ABORT=true;EXITSTATUS=1;throw"abort("+what+"). Build with -s ASSERTIONS=1 for more info."}Module["abort"]=abort;if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}Module["noExitRuntime"]=true;run();
 
 
   return BASIS
diff --git a/webgl/transcoder/build/basis_transcoder.wasm b/webgl/transcoder/build/basis_transcoder.wasm
index 18d4861..92ee548 100644
--- a/webgl/transcoder/build/basis_transcoder.wasm
+++ b/webgl/transcoder/build/basis_transcoder.wasm
Binary files differ