Browse Source

Merge pull request #2 from mrdoob/dev

Update dev from origin
Sukhwant Prafullit 10 years ago
parent
commit
3ee357eb62
51 changed files with 9023 additions and 624 deletions
  1. 0 1
      bower.json
  2. 150 130
      build/three.js
  3. 250 250
      build/three.min.js
  4. 2 2
      docs/api/CONTRIBUTING.md
  5. 15 0
      docs/api/cameras/Camera.html
  6. 1 1
      docs/api/cameras/CubeCamera.html
  7. 30 1
      docs/api/cameras/OrthographicCamera.html
  8. 23 2
      docs/api/cameras/PerspectiveCamera.html
  9. 1 1
      docs/api/core/Object3D.html
  10. 14 2
      docs/api/examples/cameras/CombinedCamera.html
  11. 10 3
      docs/api/extras/geometries/BoxGeometry.html
  12. 9 9
      docs/api/renderers/webgl/WebGLProgram.html
  13. 1 1
      docs/page.js
  14. 18 0
      editor/index.html
  15. 41 2
      editor/js/Script.js
  16. 1 1
      editor/js/Sidebar.Material.js
  17. 877 0
      editor/js/libs/acorn/acorn.js
  18. 1299 0
      editor/js/libs/acorn/acorn_loose.js
  19. 344 0
      editor/js/libs/acorn/walk.js
  20. 32 0
      editor/js/libs/codemirror/addon/dialog.css
  21. 157 0
      editor/js/libs/codemirror/addon/dialog.js
  22. 38 0
      editor/js/libs/codemirror/addon/show-hint.css
  23. 383 0
      editor/js/libs/codemirror/addon/show-hint.js
  24. 86 0
      editor/js/libs/codemirror/addon/tern.css
  25. 698 0
      editor/js/libs/codemirror/addon/tern.js
  26. 276 0
      editor/js/libs/tern-threejs/threejs.js
  27. 87 0
      editor/js/libs/ternjs/comment.js
  28. 589 0
      editor/js/libs/ternjs/def.js
  29. 402 0
      editor/js/libs/ternjs/doc_comment.js
  30. 1635 0
      editor/js/libs/ternjs/infer.js
  31. 80 0
      editor/js/libs/ternjs/polyfill.js
  32. 26 0
      editor/js/libs/ternjs/signal.js
  33. 994 0
      editor/js/libs/ternjs/tern.js
  34. 2 0
      examples/index.html
  35. 2 0
      examples/js/exporters/OBJExporter.js
  36. 4 5
      examples/js/libs/stats.min.js
  37. 2 1
      examples/js/loaders/STLLoader.js
  38. 7 6
      examples/js/renderers/Projector.js
  39. 251 0
      examples/webgl_buffergeometry_constructed_from_geometry.html
  40. 1 7
      examples/webgl_morphtargets_horse.html
  41. 20 60
      examples/webgl_multiple_elements.html
  42. 7 6
      examples/webgl_particles_sprites.html
  43. 2 2
      src/core/BufferGeometry.js
  44. 3 6
      src/core/DirectGeometry.js
  45. 0 2
      src/extras/geometries/PlaneGeometry.js
  46. 2 0
      src/loaders/XHRLoader.js
  47. 34 19
      src/renderers/WebGLRenderer.js
  48. 4 2
      src/renderers/webgl/WebGLObjects.js
  49. 70 80
      src/renderers/webgl/WebGLProgram.js
  50. 35 21
      src/textures/Texture.js
  51. 8 1
      utils/servers/python_server.sh

+ 0 - 1
bower.json

@@ -1,6 +1,5 @@
 {
 {
 	"name": "three.js",
 	"name": "three.js",
-	"version": "0.0.71",
 	"homepage": "http://threejs.org/",
 	"homepage": "http://threejs.org/",
 	"description": "JavaScript 3D library",
 	"description": "JavaScript 3D library",
 	"main": "build/three.js",
 	"main": "build/three.js",

+ 150 - 130
build/three.js

@@ -10012,14 +10012,11 @@ THREE.DirectGeometry.prototype = {
 
 
 	},
 	},
 
 
-	fromGeometry: function ( geometry, material ) {
-
-		material = material || { 'vertexColors': THREE.NoColors };
+	fromGeometry: function ( geometry ) {
 
 
 		var faces = geometry.faces;
 		var faces = geometry.faces;
 		var vertices = geometry.vertices;
 		var vertices = geometry.vertices;
 		var faceVertexUvs = geometry.faceVertexUvs;
 		var faceVertexUvs = geometry.faceVertexUvs;
-		var materialVertexColors = material.vertexColors;
 
 
 		var hasFaceVertexUv = faceVertexUvs[ 0 ] && faceVertexUvs[ 0 ].length > 0;
 		var hasFaceVertexUv = faceVertexUvs[ 0 ] && faceVertexUvs[ 0 ].length > 0;
 		var hasFaceVertexUv2 = faceVertexUvs[ 1 ] && faceVertexUvs[ 1 ].length > 0;
 		var hasFaceVertexUv2 = faceVertexUvs[ 1 ] && faceVertexUvs[ 1 ].length > 0;
@@ -10085,11 +10082,11 @@ THREE.DirectGeometry.prototype = {
 
 
 			var vertexColors = face.vertexColors;
 			var vertexColors = face.vertexColors;
 
 
-			if ( materialVertexColors === THREE.VertexColors ) {
+			if ( vertexColors.length === 3 ) {
 
 
 				this.colors.push( vertexColors[ 0 ], vertexColors[ 1 ], vertexColors[ 2 ] );
 				this.colors.push( vertexColors[ 0 ], vertexColors[ 1 ], vertexColors[ 2 ] );
 
 
-			} else if ( materialVertexColors === THREE.FaceColors ) {
+			} else {
 
 
 				var color = face.color;
 				var color = face.color;
 
 
@@ -10452,9 +10449,9 @@ THREE.BufferGeometry.prototype = {
 
 
 	},
 	},
 
 
-	fromGeometry: function ( geometry, material ) {
+	fromGeometry: function ( geometry ) {
 
 
-		geometry.__directGeometry = new THREE.DirectGeometry().fromGeometry( geometry, material );
+		geometry.__directGeometry = new THREE.DirectGeometry().fromGeometry( geometry );
 
 
 		return this.fromDirectGeometry( geometry.__directGeometry );
 		return this.fromDirectGeometry( geometry.__directGeometry );
 
 
@@ -12696,6 +12693,8 @@ THREE.XHRLoader.prototype = {
 
 
 		scope.manager.itemStart( url );
 		scope.manager.itemStart( url );
 
 
+		return request;
+
 	},
 	},
 
 
 	setResponseType: function ( value ) {
 	setResponseType: function ( value ) {
@@ -15667,6 +15666,36 @@ THREE.Texture.prototype = {
 
 
 		}
 		}
 
 
+		function getDataURL( image ) {
+
+			var canvas;
+
+			if ( image.toDataURL !== undefined ) {
+
+				canvas = image;
+
+			} else {
+
+				canvas = document.createElement( 'canvas' );
+				canvas.width = image.width;
+				canvas.height = image.height;
+
+				canvas.getContext( '2d' ).drawImage( image, 0, 0, image.width, image.height );
+
+			}
+
+			if ( canvas.width > 2048 || canvas.height > 2048 ) {
+
+				return canvas.toDataURL( 'image/jpeg', 0.6 );
+
+			} else {
+
+				return canvas.toDataURL( 'image/png' );
+
+			}
+
+		}
+
 		var output = {
 		var output = {
 			metadata: {
 			metadata: {
 				version: 4.4,
 				version: 4.4,
@@ -15700,28 +15729,12 @@ THREE.Texture.prototype = {
 
 
 			}
 			}
 
 
-			if ( meta.images[ this.image.uuid ] === undefined ) {
-
-				var canvas = document.createElement( 'canvas' );
-				canvas.width = image.width;
-				canvas.height = image.height;
-
-				var context = canvas.getContext( '2d' );
-				context.drawImage( image, 0, 0, image.width, image.height );
-
-				var src;
-
-				if ( image.width > 2048 || image.height > 2048 ) {
-
-					src = canvas.toDataURL( 'image/jpeg', 0.6 );
-
-				} else {
-
-					src = canvas.toDataURL( 'image/png' );
+			if ( meta.images[ image.uuid ] === undefined ) {
 
 
-				}
-
-				meta.images[ this.image.uuid ] = { uuid: this.image.uuid, url: src };
+				meta.images[ image.uuid ] = {
+					uuid: image.uuid,
+					url: getDataURL( image )
+				};
 
 
 			}
 			}
 
 
@@ -19690,14 +19703,15 @@ THREE.WebGLRenderer = function ( parameters ) {
 		if ( object.hasUvs && ! object.__webglUvBuffer ) object.__webglUvBuffer = _gl.createBuffer();
 		if ( object.hasUvs && ! object.__webglUvBuffer ) object.__webglUvBuffer = _gl.createBuffer();
 		if ( object.hasColors && ! object.__webglColorBuffer ) object.__webglColorBuffer = _gl.createBuffer();
 		if ( object.hasColors && ! object.__webglColorBuffer ) object.__webglColorBuffer = _gl.createBuffer();
 
 
+		var attributes = program.getAttributes();
+
 		if ( object.hasPositions ) {
 		if ( object.hasPositions ) {
 
 
 			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglVertexBuffer );
 			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglVertexBuffer );
 			_gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW );
 			_gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW );
 
 
-			state.enableAttribute( program.attributes.position );
-
-			_gl.vertexAttribPointer( program.attributes.position, 3, _gl.FLOAT, false, 0, 0 );
+			state.enableAttribute( attributes.position );
+			_gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );
 
 
 		}
 		}
 
 
@@ -19750,9 +19764,9 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 			_gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW );
 			_gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW );
 
 
-			state.enableAttribute( program.attributes.normal );
+			state.enableAttribute( attributes.normal );
 
 
-			_gl.vertexAttribPointer( program.attributes.normal, 3, _gl.FLOAT, false, 0, 0 );
+			_gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 );
 
 
 		}
 		}
 
 
@@ -19761,9 +19775,9 @@ THREE.WebGLRenderer = function ( parameters ) {
 			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglUvBuffer );
 			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglUvBuffer );
 			_gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW );
 			_gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW );
 
 
-			state.enableAttribute( program.attributes.uv );
+			state.enableAttribute( attributes.uv );
 
 
-			_gl.vertexAttribPointer( program.attributes.uv, 2, _gl.FLOAT, false, 0, 0 );
+			_gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 );
 
 
 		}
 		}
 
 
@@ -19772,9 +19786,9 @@ THREE.WebGLRenderer = function ( parameters ) {
 			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglColorBuffer );
 			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglColorBuffer );
 			_gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW );
 			_gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW );
 
 
-			state.enableAttribute( program.attributes.color );
+			state.enableAttribute( attributes.color );
 
 
-			_gl.vertexAttribPointer( program.attributes.color, 3, _gl.FLOAT, false, 0, 0 );
+			_gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 );
 
 
 		}
 		}
 
 
@@ -19804,7 +19818,10 @@ THREE.WebGLRenderer = function ( parameters ) {
 		}
 		}
 
 
 		var geometryAttributes = geometry.attributes;
 		var geometryAttributes = geometry.attributes;
-		var programAttributes = program.attributes;
+
+		var programAttributes = program.getAttributes();
+
+		var materialDefaultAttributeValues = material.defaultAttributeValues;
 
 
 		for ( var name in programAttributes ) {
 		for ( var name in programAttributes ) {
 
 
@@ -19873,17 +19890,27 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 					}
 					}
 
 
-				} else if ( material.defaultAttributeValues !== undefined ) {
+				} else if ( materialDefaultAttributeValues !== undefined ) {
 
 
-					if ( material.defaultAttributeValues[ name ] !== undefined ) {
+					var value = materialDefaultAttributeValues[ name ];
+					if ( value !== undefined ) {
 
 
-						if ( material.defaultAttributeValues[ name ].length === 2 ) {
+						switch ( value.length ) {
 
 
-							_gl.vertexAttrib2fv( programAttribute, material.defaultAttributeValues[ name ] );
+							case 2:
+								_gl.vertexAttrib2fv( programAttribute, value );
+								break;
 
 
-						} else if ( material.defaultAttributeValues[ name ].length === 3 ) {
+							case 3:
+								_gl.vertexAttrib3fv( programAttribute, value );
+								break;
+
+							case 4:
+								_gl.vertexAttrib4fv( programAttribute, value );
+								break;
 
 
-							_gl.vertexAttrib3fv( programAttribute, material.defaultAttributeValues[ name ] );
+							default:
+								_gl.vertexAttrib1fv( programAttribute, value );
 
 
 						}
 						}
 
 
@@ -20894,7 +20921,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 		material.program = program;
 		material.program = program;
 
 
-		var attributes = program.attributes;
+		var attributes = program.getAttributes();
 
 
 		if ( material.morphTargets ) {
 		if ( material.morphTargets ) {
 
 
@@ -20930,9 +20957,10 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 		material.uniformsList = [];
 		material.uniformsList = [];
 
 
+		var uniformLocations = material.program.getUniforms();
 		for ( var u in material.__webglShader.uniforms ) {
 		for ( var u in material.__webglShader.uniforms ) {
 
 
-			var location = material.program.uniforms[ u ];
+			var location = uniformLocations[ u ];
 
 
 			if ( location ) {
 			if ( location ) {
 				material.uniformsList.push( [ material.__webglShader.uniforms[ u ], location ] );
 				material.uniformsList.push( [ material.__webglShader.uniforms[ u ], location ] );
@@ -20978,7 +21006,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 		var refreshLights = false;
 		var refreshLights = false;
 
 
 		var program = material.program,
 		var program = material.program,
-			p_uniforms = program.uniforms,
+			p_uniforms = program.getUniforms(),
 			m_uniforms = material.__webglShader.uniforms;
 			m_uniforms = material.__webglShader.uniforms;
 
 
 		if ( program.id !== _currentProgram ) {
 		if ( program.id !== _currentProgram ) {
@@ -23309,9 +23337,11 @@ THREE.WebGLObjects = function ( gl, info ) {
 
 
 			if ( material.program !== undefined ) {
 			if ( material.program !== undefined ) {
 
 
-				if ( material.program.uniforms.morphTargetInfluences !== null ) {
+				var uniforms = material.program.getUniforms();
 
 
-					gl.uniform1fv( material.program.uniforms.morphTargetInfluences, morphInfluences );
+				if ( uniforms.morphTargetInfluences !== null ) {
+
+					gl.uniform1fv( uniforms.morphTargetInfluences, morphInfluences );
 
 
 				}
 				}
 
 
@@ -23425,14 +23455,29 @@ THREE.WebGLProgram = ( function () {
 
 
 	}
 	}
 
 
-	function cacheUniformLocations( gl, program, identifiers ) {
+	function fetchUniformLocations( gl, program, identifiers ) {
+
 
 
 		var uniforms = {};
 		var uniforms = {};
 
 
-		for ( var i = 0, l = identifiers.length; i < l; i ++ ) {
+		var n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS );
+
+		for ( var i = 0; i < n; i ++ ) {
+
+			var info = gl.getActiveUniform( program , i );
+			var name = info.name;
+			var location = gl.getUniformLocation( program, name );
+
+			//console.log("THREE.WebGLProgram: ACTIVE UNIFORM:", name);
+
+			var suffixPos = name.lastIndexOf( '[0]' );
+			if ( suffixPos !== -1 && suffixPos === name.length - 3 ) {
 
 
-			var id = identifiers[ i ];
-			uniforms[ id ] = gl.getUniformLocation( program, id );
+				uniforms[ name.substr( 0, suffixPos ) ] = location;
+
+			}
+
+			uniforms[ name ] = location;
 
 
 		}
 		}
 
 
@@ -23440,14 +23485,20 @@ THREE.WebGLProgram = ( function () {
 
 
 	}
 	}
 
 
-	function cacheAttributeLocations( gl, program, identifiers ) {
+	function fetchAttributeLocations( gl, program, identifiers ) {
 
 
 		var attributes = {};
 		var attributes = {};
 
 
-		for ( var i = 0, l = identifiers.length; i < l; i ++ ) {
+		var n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES );
+
+		for ( var i = 0; i < n; i ++ ) {
+
+			var info = gl.getActiveAttrib( program , i );
+			var name = info.name;
 
 
-			var id = identifiers[ i ];
-			attributes[ id ] = gl.getAttribLocation( program, id );
+			//console.log("THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:", name);
+
+			attributes[ name ] = gl.getAttribLocation( program, name );
 
 
 		}
 		}
 
 
@@ -23559,16 +23610,16 @@ THREE.WebGLProgram = ( function () {
 
 
 		var program = gl.createProgram();
 		var program = gl.createProgram();
 
 
-		var prefix_vertex, prefix_fragment;
+		var prefixVertex, prefixFragment;
 
 
 		if ( material instanceof THREE.RawShaderMaterial ) {
 		if ( material instanceof THREE.RawShaderMaterial ) {
 
 
-			prefix_vertex = '';
-			prefix_fragment = '';
+			prefixVertex = '';
+			prefixFragment = '';
 
 
 		} else {
 		} else {
 
 
-			prefix_vertex = [
+			prefixVertex = [
 
 
 				'precision ' + parameters.precision + ' float;',
 				'precision ' + parameters.precision + ' float;',
 				'precision ' + parameters.precision + ' int;',
 				'precision ' + parameters.precision + ' int;',
@@ -23675,7 +23726,7 @@ THREE.WebGLProgram = ( function () {
 
 
 			].filter( filterEmptyLine ).join( '\n' );
 			].filter( filterEmptyLine ).join( '\n' );
 
 
-			prefix_fragment = [
+			prefixFragment = [
 
 
 				( parameters.bumpMap || parameters.normalMap || parameters.flatShading || material.derivatives ) ? '#extension GL_OES_standard_derivatives : enable' : '',
 				( parameters.bumpMap || parameters.normalMap || parameters.flatShading || material.derivatives ) ? '#extension GL_OES_standard_derivatives : enable' : '',
 
 
@@ -23736,8 +23787,11 @@ THREE.WebGLProgram = ( function () {
 
 
 		}
 		}
 
 
-		var glVertexShader = new THREE.WebGLShader( gl, gl.VERTEX_SHADER, prefix_vertex + vertexShader );
-		var glFragmentShader = new THREE.WebGLShader( gl, gl.FRAGMENT_SHADER, prefix_fragment + fragmentShader );
+		var vertexGlsl = prefixVertex + vertexShader;
+		var fragmentGlsl = prefixFragment + fragmentShader;
+
+		var glVertexShader = new THREE.WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl );
+		var glFragmentShader = new THREE.WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl );
 
 
 		gl.attachShader( program, glVertexShader );
 		gl.attachShader( program, glVertexShader );
 		gl.attachShader( program, glFragmentShader );
 		gl.attachShader( program, glFragmentShader );
@@ -23775,91 +23829,57 @@ THREE.WebGLProgram = ( function () {
 		gl.deleteShader( glVertexShader );
 		gl.deleteShader( glVertexShader );
 		gl.deleteShader( glFragmentShader );
 		gl.deleteShader( glFragmentShader );
 
 
-		// cache uniform locations
-
-		var identifiers = [
-
-			'viewMatrix',
-			'modelViewMatrix',
-			'projectionMatrix',
-			'normalMatrix',
-			'modelMatrix',
-			'cameraPosition',
-			'morphTargetInfluences',
-			'bindMatrix',
-			'bindMatrixInverse'
-
-		];
-
-		if ( parameters.useVertexTexture ) {
-
-			identifiers.push( 'boneTexture', 'boneTextureWidth', 'boneTextureHeight' );
-
-		} else {
-
-			identifiers.push( 'boneGlobalMatrices' );
+		// set up caching for uniform locations
 
 
-		}
-
-		if ( parameters.logarithmicDepthBuffer ) {
-
-			identifiers.push( 'logDepthBufFC' );
-
-		}
-
-		for ( var u in uniforms ) {
-
-			identifiers.push( u );
-
-		}
-
-		this.uniforms = cacheUniformLocations( gl, program, identifiers );
-
-		// cache attributes locations
+		var getUniforms = function() { return this._cachedUniforms; };
 
 
-		if ( material instanceof THREE.RawShaderMaterial ) {
+		this.getUniforms = function() {
 
 
-			identifiers = attributes;
+			// fetch, cache, and next time just use a dumb accessor
+			var uniforms = fetchUniformLocations( gl, program );
+			this._cachedUniforms = uniforms;
+			this.getUniforms = getUniforms;
+			return uniforms;
 
 
-		} else {
+		};
 
 
-			identifiers = [
+		// set up caching for attribute locations
 
 
-				'position',
-				'normal',
-				'uv',
-				'uv2',
-				'tangent',
-				'color',
-				'skinIndex',
-				'skinWeight',
-				'lineDistance'
+		var getAttributes = function() { return this._cachedAttributes; };
 
 
-			];
+		this.getAttributes = function() {
 
 
-			for ( var i = 0; i < parameters.maxMorphTargets; i ++ ) {
+			var attributes = fetchAttributeLocations( gl, program );
+			this._cachedAttributes = attributes;
+			this.getAttributes = getAttributes;
+			return attributes;
 
 
-				identifiers.push( 'morphTarget' + i );
+		};
 
 
-			}
+		// DEPRECATED
 
 
-			for ( var i = 0; i < parameters.maxMorphNormals; i ++ ) {
+		Object.defineProperties( this, {
 
 
-				identifiers.push( 'morphNormal' + i );
+			uniforms: {
+				get: function() {
 
 
-			}
+					console.warn( 'THREE.WebGLProgram: .uniforms is now .getUniforms().' );
+					return this.getUniforms();
 
 
-			// ShaderMaterial attributes
+				}
+			},
 
 
-			if ( Array.isArray( attributes ) ) {
+			attributes: {
+				get: function() {
 
 
-				identifiers = identifiers.concat( attributes );
+					console.warn( 'THREE.WebGLProgram: .attributes is now .getAttributes().' );
+					return this.getAttributes();
 
 
+				}
 			}
 			}
 
 
-		}
+		});
 
 
-		this.attributes = cacheAttributeLocations( gl, program, identifiers );
 
 
 		//
 		//
 
 

+ 250 - 250
build/three.min.js

@@ -94,22 +94,22 @@ void 0===c&&(c=0);void 0===d&&(d=b.length/b.itemSize);for(var e=0;e<d;e++,c++)a.
 this.elements;d[0]=c[10]*c[5]-c[6]*c[9];d[1]=-c[10]*c[1]+c[2]*c[9];d[2]=c[6]*c[1]-c[2]*c[5];d[3]=-c[10]*c[4]+c[6]*c[8];d[4]=c[10]*c[0]-c[2]*c[8];d[5]=-c[6]*c[0]+c[2]*c[4];d[6]=c[9]*c[4]-c[5]*c[8];d[7]=-c[9]*c[0]+c[1]*c[8];d[8]=c[5]*c[0]-c[1]*c[4];c=c[0]*d[0]+c[1]*d[3]+c[2]*d[6];if(0===c){if(b)throw Error("Matrix3.getInverse(): can't invert matrix, determinant is 0");console.warn("Matrix3.getInverse(): can't invert matrix, determinant is 0");this.identity();return this}this.multiplyScalar(1/c);return this},
 this.elements;d[0]=c[10]*c[5]-c[6]*c[9];d[1]=-c[10]*c[1]+c[2]*c[9];d[2]=c[6]*c[1]-c[2]*c[5];d[3]=-c[10]*c[4]+c[6]*c[8];d[4]=c[10]*c[0]-c[2]*c[8];d[5]=-c[6]*c[0]+c[2]*c[4];d[6]=c[9]*c[4]-c[5]*c[8];d[7]=-c[9]*c[0]+c[1]*c[8];d[8]=c[5]*c[0]-c[1]*c[4];c=c[0]*d[0]+c[1]*d[3]+c[2]*d[6];if(0===c){if(b)throw Error("Matrix3.getInverse(): can't invert matrix, determinant is 0");console.warn("Matrix3.getInverse(): can't invert matrix, determinant is 0");this.identity();return this}this.multiplyScalar(1/c);return this},
 transpose:function(){var a,b=this.elements;a=b[1];b[1]=b[3];b[3]=a;a=b[2];b[2]=b[6];b[6]=a;a=b[5];b[5]=b[7];b[7]=a;return this},flattenToArrayOffset:function(a,b){var c=this.elements;a[b]=c[0];a[b+1]=c[1];a[b+2]=c[2];a[b+3]=c[3];a[b+4]=c[4];a[b+5]=c[5];a[b+6]=c[6];a[b+7]=c[7];a[b+8]=c[8];return a},getNormalMatrix:function(a){this.getInverse(a).transpose();return this},transposeIntoArray:function(a){var b=this.elements;a[0]=b[0];a[1]=b[3];a[2]=b[6];a[3]=b[1];a[4]=b[4];a[5]=b[7];a[6]=b[2];a[7]=b[5];
 transpose:function(){var a,b=this.elements;a=b[1];b[1]=b[3];b[3]=a;a=b[2];b[2]=b[6];b[6]=a;a=b[5];b[5]=b[7];b[7]=a;return this},flattenToArrayOffset:function(a,b){var c=this.elements;a[b]=c[0];a[b+1]=c[1];a[b+2]=c[2];a[b+3]=c[3];a[b+4]=c[4];a[b+5]=c[5];a[b+6]=c[6];a[b+7]=c[7];a[b+8]=c[8];return a},getNormalMatrix:function(a){this.getInverse(a).transpose();return this},transposeIntoArray:function(a){var b=this.elements;a[0]=b[0];a[1]=b[3];a[2]=b[6];a[3]=b[1];a[4]=b[4];a[5]=b[7];a[6]=b[2];a[7]=b[5];
 a[8]=b[8];return this},fromArray:function(a){this.elements.set(a);return this},toArray:function(){var a=this.elements;return[a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]]},clone:function(){return(new THREE.Matrix3).fromArray(this.elements)}};THREE.Matrix4=function(){this.elements=new Float32Array([1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]);0<arguments.length&&console.error("THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.")};
 a[8]=b[8];return this},fromArray:function(a){this.elements.set(a);return this},toArray:function(){var a=this.elements;return[a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]]},clone:function(){return(new THREE.Matrix3).fromArray(this.elements)}};THREE.Matrix4=function(){this.elements=new Float32Array([1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]);0<arguments.length&&console.error("THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.")};
-THREE.Matrix4.prototype={constructor:THREE.Matrix4,set:function(a,b,c,d,e,f,g,h,k,l,n,p,m,q,t,s){var u=this.elements;u[0]=a;u[4]=b;u[8]=c;u[12]=d;u[1]=e;u[5]=f;u[9]=g;u[13]=h;u[2]=k;u[6]=l;u[10]=n;u[14]=p;u[3]=m;u[7]=q;u[11]=t;u[15]=s;return this},identity:function(){this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);return this},copy:function(a){this.elements.set(a.elements);return this},extractPosition:function(a){console.warn("THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().");return this.copyPosition(a)},
+THREE.Matrix4.prototype={constructor:THREE.Matrix4,set:function(a,b,c,d,e,f,g,h,k,l,n,p,m,q,s,t){var u=this.elements;u[0]=a;u[4]=b;u[8]=c;u[12]=d;u[1]=e;u[5]=f;u[9]=g;u[13]=h;u[2]=k;u[6]=l;u[10]=n;u[14]=p;u[3]=m;u[7]=q;u[11]=s;u[15]=t;return this},identity:function(){this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);return this},copy:function(a){this.elements.set(a.elements);return this},extractPosition:function(a){console.warn("THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().");return this.copyPosition(a)},
 copyPosition:function(a){var b=this.elements;a=a.elements;b[12]=a[12];b[13]=a[13];b[14]=a[14];return this},extractBasis:function(a,b,c){var d=this.elements;a.set(d[0],d[1],d[2]);b.set(d[4],d[5],d[6]);c.set(d[8],d[9],d[10]);return this},makeBasis:function(a,b,c){this.set(a.x,b.x,c.x,0,a.y,b.y,c.y,0,a.z,b.z,c.z,0,0,0,0,1);return this},extractRotation:function(){var a;return function(b){void 0===a&&(a=new THREE.Vector3);var c=this.elements;b=b.elements;var d=1/a.set(b[0],b[1],b[2]).length(),e=1/a.set(b[4],
 copyPosition:function(a){var b=this.elements;a=a.elements;b[12]=a[12];b[13]=a[13];b[14]=a[14];return this},extractBasis:function(a,b,c){var d=this.elements;a.set(d[0],d[1],d[2]);b.set(d[4],d[5],d[6]);c.set(d[8],d[9],d[10]);return this},makeBasis:function(a,b,c){this.set(a.x,b.x,c.x,0,a.y,b.y,c.y,0,a.z,b.z,c.z,0,0,0,0,1);return this},extractRotation:function(){var a;return function(b){void 0===a&&(a=new THREE.Vector3);var c=this.elements;b=b.elements;var d=1/a.set(b[0],b[1],b[2]).length(),e=1/a.set(b[4],
 b[5],b[6]).length(),f=1/a.set(b[8],b[9],b[10]).length();c[0]=b[0]*d;c[1]=b[1]*d;c[2]=b[2]*d;c[4]=b[4]*e;c[5]=b[5]*e;c[6]=b[6]*e;c[8]=b[8]*f;c[9]=b[9]*f;c[10]=b[10]*f;return this}}(),makeRotationFromEuler:function(a){!1===a instanceof THREE.Euler&&console.error("THREE.Matrix: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.");var b=this.elements,c=a.x,d=a.y,e=a.z,f=Math.cos(c),c=Math.sin(c),g=Math.cos(d),d=Math.sin(d),h=Math.cos(e),e=Math.sin(e);if("XYZ"===a.order){a=
 b[5],b[6]).length(),f=1/a.set(b[8],b[9],b[10]).length();c[0]=b[0]*d;c[1]=b[1]*d;c[2]=b[2]*d;c[4]=b[4]*e;c[5]=b[5]*e;c[6]=b[6]*e;c[8]=b[8]*f;c[9]=b[9]*f;c[10]=b[10]*f;return this}}(),makeRotationFromEuler:function(a){!1===a instanceof THREE.Euler&&console.error("THREE.Matrix: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.");var b=this.elements,c=a.x,d=a.y,e=a.z,f=Math.cos(c),c=Math.sin(c),g=Math.cos(d),d=Math.sin(d),h=Math.cos(e),e=Math.sin(e);if("XYZ"===a.order){a=
 f*h;var k=f*e,l=c*h,n=c*e;b[0]=g*h;b[4]=-g*e;b[8]=d;b[1]=k+l*d;b[5]=a-n*d;b[9]=-c*g;b[2]=n-a*d;b[6]=l+k*d;b[10]=f*g}else"YXZ"===a.order?(a=g*h,k=g*e,l=d*h,n=d*e,b[0]=a+n*c,b[4]=l*c-k,b[8]=f*d,b[1]=f*e,b[5]=f*h,b[9]=-c,b[2]=k*c-l,b[6]=n+a*c,b[10]=f*g):"ZXY"===a.order?(a=g*h,k=g*e,l=d*h,n=d*e,b[0]=a-n*c,b[4]=-f*e,b[8]=l+k*c,b[1]=k+l*c,b[5]=f*h,b[9]=n-a*c,b[2]=-f*d,b[6]=c,b[10]=f*g):"ZYX"===a.order?(a=f*h,k=f*e,l=c*h,n=c*e,b[0]=g*h,b[4]=l*d-k,b[8]=a*d+n,b[1]=g*e,b[5]=n*d+a,b[9]=k*d-l,b[2]=-d,b[6]=c*
 f*h;var k=f*e,l=c*h,n=c*e;b[0]=g*h;b[4]=-g*e;b[8]=d;b[1]=k+l*d;b[5]=a-n*d;b[9]=-c*g;b[2]=n-a*d;b[6]=l+k*d;b[10]=f*g}else"YXZ"===a.order?(a=g*h,k=g*e,l=d*h,n=d*e,b[0]=a+n*c,b[4]=l*c-k,b[8]=f*d,b[1]=f*e,b[5]=f*h,b[9]=-c,b[2]=k*c-l,b[6]=n+a*c,b[10]=f*g):"ZXY"===a.order?(a=g*h,k=g*e,l=d*h,n=d*e,b[0]=a-n*c,b[4]=-f*e,b[8]=l+k*c,b[1]=k+l*c,b[5]=f*h,b[9]=n-a*c,b[2]=-f*d,b[6]=c,b[10]=f*g):"ZYX"===a.order?(a=f*h,k=f*e,l=c*h,n=c*e,b[0]=g*h,b[4]=l*d-k,b[8]=a*d+n,b[1]=g*e,b[5]=n*d+a,b[9]=k*d-l,b[2]=-d,b[6]=c*
 g,b[10]=f*g):"YZX"===a.order?(a=f*g,k=f*d,l=c*g,n=c*d,b[0]=g*h,b[4]=n-a*e,b[8]=l*e+k,b[1]=e,b[5]=f*h,b[9]=-c*h,b[2]=-d*h,b[6]=k*e+l,b[10]=a-n*e):"XZY"===a.order&&(a=f*g,k=f*d,l=c*g,n=c*d,b[0]=g*h,b[4]=-e,b[8]=d*h,b[1]=a*e+n,b[5]=f*h,b[9]=k*e-l,b[2]=l*e-k,b[6]=c*h,b[10]=n*e+a);b[3]=0;b[7]=0;b[11]=0;b[12]=0;b[13]=0;b[14]=0;b[15]=1;return this},setRotationFromQuaternion:function(a){console.warn("THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().");return this.makeRotationFromQuaternion(a)},
 g,b[10]=f*g):"YZX"===a.order?(a=f*g,k=f*d,l=c*g,n=c*d,b[0]=g*h,b[4]=n-a*e,b[8]=l*e+k,b[1]=e,b[5]=f*h,b[9]=-c*h,b[2]=-d*h,b[6]=k*e+l,b[10]=a-n*e):"XZY"===a.order&&(a=f*g,k=f*d,l=c*g,n=c*d,b[0]=g*h,b[4]=-e,b[8]=d*h,b[1]=a*e+n,b[5]=f*h,b[9]=k*e-l,b[2]=l*e-k,b[6]=c*h,b[10]=n*e+a);b[3]=0;b[7]=0;b[11]=0;b[12]=0;b[13]=0;b[14]=0;b[15]=1;return this},setRotationFromQuaternion:function(a){console.warn("THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().");return this.makeRotationFromQuaternion(a)},
 makeRotationFromQuaternion:function(a){var b=this.elements,c=a.x,d=a.y,e=a.z,f=a.w,g=c+c,h=d+d,k=e+e;a=c*g;var l=c*h,c=c*k,n=d*h,d=d*k,e=e*k,g=f*g,h=f*h,f=f*k;b[0]=1-(n+e);b[4]=l-f;b[8]=c+h;b[1]=l+f;b[5]=1-(a+e);b[9]=d-g;b[2]=c-h;b[6]=d+g;b[10]=1-(a+n);b[3]=0;b[7]=0;b[11]=0;b[12]=0;b[13]=0;b[14]=0;b[15]=1;return this},lookAt:function(){var a,b,c;return function(d,e,f){void 0===a&&(a=new THREE.Vector3);void 0===b&&(b=new THREE.Vector3);void 0===c&&(c=new THREE.Vector3);var g=this.elements;c.subVectors(d,
 makeRotationFromQuaternion:function(a){var b=this.elements,c=a.x,d=a.y,e=a.z,f=a.w,g=c+c,h=d+d,k=e+e;a=c*g;var l=c*h,c=c*k,n=d*h,d=d*k,e=e*k,g=f*g,h=f*h,f=f*k;b[0]=1-(n+e);b[4]=l-f;b[8]=c+h;b[1]=l+f;b[5]=1-(a+e);b[9]=d-g;b[2]=c-h;b[6]=d+g;b[10]=1-(a+n);b[3]=0;b[7]=0;b[11]=0;b[12]=0;b[13]=0;b[14]=0;b[15]=1;return this},lookAt:function(){var a,b,c;return function(d,e,f){void 0===a&&(a=new THREE.Vector3);void 0===b&&(b=new THREE.Vector3);void 0===c&&(c=new THREE.Vector3);var g=this.elements;c.subVectors(d,
 e).normalize();0===c.length()&&(c.z=1);a.crossVectors(f,c).normalize();0===a.length()&&(c.x+=1E-4,a.crossVectors(f,c).normalize());b.crossVectors(c,a);g[0]=a.x;g[4]=b.x;g[8]=c.x;g[1]=a.y;g[5]=b.y;g[9]=c.y;g[2]=a.z;g[6]=b.z;g[10]=c.z;return this}}(),multiply:function(a,b){return void 0!==b?(console.warn("THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead."),this.multiplyMatrices(a,b)):this.multiplyMatrices(this,a)},multiplyMatrices:function(a,b){var c=a.elements,
 e).normalize();0===c.length()&&(c.z=1);a.crossVectors(f,c).normalize();0===a.length()&&(c.x+=1E-4,a.crossVectors(f,c).normalize());b.crossVectors(c,a);g[0]=a.x;g[4]=b.x;g[8]=c.x;g[1]=a.y;g[5]=b.y;g[9]=c.y;g[2]=a.z;g[6]=b.z;g[10]=c.z;return this}}(),multiply:function(a,b){return void 0!==b?(console.warn("THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead."),this.multiplyMatrices(a,b)):this.multiplyMatrices(this,a)},multiplyMatrices:function(a,b){var c=a.elements,
-d=b.elements,e=this.elements,f=c[0],g=c[4],h=c[8],k=c[12],l=c[1],n=c[5],p=c[9],m=c[13],q=c[2],t=c[6],s=c[10],u=c[14],w=c[3],x=c[7],A=c[11],c=c[15],y=d[0],D=d[4],I=d[8],v=d[12],E=d[1],L=d[5],C=d[9],F=d[13],R=d[2],J=d[6],z=d[10],G=d[14],B=d[3],T=d[7],O=d[11],d=d[15];e[0]=f*y+g*E+h*R+k*B;e[4]=f*D+g*L+h*J+k*T;e[8]=f*I+g*C+h*z+k*O;e[12]=f*v+g*F+h*G+k*d;e[1]=l*y+n*E+p*R+m*B;e[5]=l*D+n*L+p*J+m*T;e[9]=l*I+n*C+p*z+m*O;e[13]=l*v+n*F+p*G+m*d;e[2]=q*y+t*E+s*R+u*B;e[6]=q*D+t*L+s*J+u*T;e[10]=q*I+t*C+s*z+u*O;e[14]=
-q*v+t*F+s*G+u*d;e[3]=w*y+x*E+A*R+c*B;e[7]=w*D+x*L+A*J+c*T;e[11]=w*I+x*C+A*z+c*O;e[15]=w*v+x*F+A*G+c*d;return this},multiplyToArray:function(a,b,c){var d=this.elements;this.multiplyMatrices(a,b);c[0]=d[0];c[1]=d[1];c[2]=d[2];c[3]=d[3];c[4]=d[4];c[5]=d[5];c[6]=d[6];c[7]=d[7];c[8]=d[8];c[9]=d[9];c[10]=d[10];c[11]=d[11];c[12]=d[12];c[13]=d[13];c[14]=d[14];c[15]=d[15];return this},multiplyScalar:function(a){var b=this.elements;b[0]*=a;b[4]*=a;b[8]*=a;b[12]*=a;b[1]*=a;b[5]*=a;b[9]*=a;b[13]*=a;b[2]*=a;b[6]*=
+d=b.elements,e=this.elements,f=c[0],g=c[4],h=c[8],k=c[12],l=c[1],n=c[5],p=c[9],m=c[13],q=c[2],s=c[6],t=c[10],u=c[14],x=c[3],w=c[7],A=c[11],c=c[15],y=d[0],G=d[4],I=d[8],v=d[12],D=d[1],L=d[5],C=d[9],E=d[13],R=d[2],J=d[6],z=d[10],F=d[14],B=d[3],T=d[7],O=d[11],d=d[15];e[0]=f*y+g*D+h*R+k*B;e[4]=f*G+g*L+h*J+k*T;e[8]=f*I+g*C+h*z+k*O;e[12]=f*v+g*E+h*F+k*d;e[1]=l*y+n*D+p*R+m*B;e[5]=l*G+n*L+p*J+m*T;e[9]=l*I+n*C+p*z+m*O;e[13]=l*v+n*E+p*F+m*d;e[2]=q*y+s*D+t*R+u*B;e[6]=q*G+s*L+t*J+u*T;e[10]=q*I+s*C+t*z+u*O;e[14]=
+q*v+s*E+t*F+u*d;e[3]=x*y+w*D+A*R+c*B;e[7]=x*G+w*L+A*J+c*T;e[11]=x*I+w*C+A*z+c*O;e[15]=x*v+w*E+A*F+c*d;return this},multiplyToArray:function(a,b,c){var d=this.elements;this.multiplyMatrices(a,b);c[0]=d[0];c[1]=d[1];c[2]=d[2];c[3]=d[3];c[4]=d[4];c[5]=d[5];c[6]=d[6];c[7]=d[7];c[8]=d[8];c[9]=d[9];c[10]=d[10];c[11]=d[11];c[12]=d[12];c[13]=d[13];c[14]=d[14];c[15]=d[15];return this},multiplyScalar:function(a){var b=this.elements;b[0]*=a;b[4]*=a;b[8]*=a;b[12]*=a;b[1]*=a;b[5]*=a;b[9]*=a;b[13]*=a;b[2]*=a;b[6]*=
 a;b[10]*=a;b[14]*=a;b[3]*=a;b[7]*=a;b[11]*=a;b[15]*=a;return this},multiplyVector3:function(a){console.warn("THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead.");return a.applyProjection(this)},multiplyVector4:function(a){console.warn("THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.");return a.applyMatrix4(this)},multiplyVector3Array:function(a){console.warn("THREE.Matrix4: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.");
 a;b[10]*=a;b[14]*=a;b[3]*=a;b[7]*=a;b[11]*=a;b[15]*=a;return this},multiplyVector3:function(a){console.warn("THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead.");return a.applyProjection(this)},multiplyVector4:function(a){console.warn("THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.");return a.applyMatrix4(this)},multiplyVector3Array:function(a){console.warn("THREE.Matrix4: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.");
 return this.applyToVector3Array(a)},applyToVector3Array:function(){var a;return function(b,c,d){void 0===a&&(a=new THREE.Vector3);void 0===c&&(c=0);void 0===d&&(d=b.length);for(var e=0;e<d;e+=3,c+=3)a.fromArray(b,c),a.applyMatrix4(this),a.toArray(b,c);return b}}(),applyToBuffer:function(){var a;return function(b,c,d){void 0===a&&(a=new THREE.Vector3);void 0===c&&(c=0);void 0===d&&(d=b.length/b.itemSize);for(var e=0;e<d;e++,c++)a.x=b.getX(c),a.y=b.getY(c),a.z=b.getZ(c),a.applyMatrix4(this),b.setXYZ(a.x,
 return this.applyToVector3Array(a)},applyToVector3Array:function(){var a;return function(b,c,d){void 0===a&&(a=new THREE.Vector3);void 0===c&&(c=0);void 0===d&&(d=b.length);for(var e=0;e<d;e+=3,c+=3)a.fromArray(b,c),a.applyMatrix4(this),a.toArray(b,c);return b}}(),applyToBuffer:function(){var a;return function(b,c,d){void 0===a&&(a=new THREE.Vector3);void 0===c&&(c=0);void 0===d&&(d=b.length/b.itemSize);for(var e=0;e<d;e++,c++)a.x=b.getX(c),a.y=b.getY(c),a.z=b.getZ(c),a.applyMatrix4(this),b.setXYZ(a.x,
 a.y,a.z);return b}}(),rotateAxis:function(a){console.warn("THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.");a.transformDirection(this)},crossVector:function(a){console.warn("THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.");return a.applyMatrix4(this)},determinant:function(){var a=this.elements,b=a[0],c=a[4],d=a[8],e=a[12],f=a[1],g=a[5],h=a[9],k=a[13],l=a[2],n=a[6],p=a[10],m=a[14];return a[3]*(+e*h*n-d*k*
 a.y,a.z);return b}}(),rotateAxis:function(a){console.warn("THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.");a.transformDirection(this)},crossVector:function(a){console.warn("THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.");return a.applyMatrix4(this)},determinant:function(){var a=this.elements,b=a[0],c=a[4],d=a[8],e=a[12],f=a[1],g=a[5],h=a[9],k=a[13],l=a[2],n=a[6],p=a[10],m=a[14];return a[3]*(+e*h*n-d*k*
 n-e*g*p+c*k*p+d*g*m-c*h*m)+a[7]*(+b*h*m-b*k*p+e*f*p-d*f*m+d*k*l-e*h*l)+a[11]*(+b*k*n-b*g*m-e*f*n+c*f*m+e*g*l-c*k*l)+a[15]*(-d*g*l-b*h*n+b*g*p+d*f*n-c*f*p+c*h*l)},transpose:function(){var a=this.elements,b;b=a[1];a[1]=a[4];a[4]=b;b=a[2];a[2]=a[8];a[8]=b;b=a[6];a[6]=a[9];a[9]=b;b=a[3];a[3]=a[12];a[12]=b;b=a[7];a[7]=a[13];a[13]=b;b=a[11];a[11]=a[14];a[14]=b;return this},flattenToArrayOffset:function(a,b){var c=this.elements;a[b]=c[0];a[b+1]=c[1];a[b+2]=c[2];a[b+3]=c[3];a[b+4]=c[4];a[b+5]=c[5];a[b+6]=
 n-e*g*p+c*k*p+d*g*m-c*h*m)+a[7]*(+b*h*m-b*k*p+e*f*p-d*f*m+d*k*l-e*h*l)+a[11]*(+b*k*n-b*g*m-e*f*n+c*f*m+e*g*l-c*k*l)+a[15]*(-d*g*l-b*h*n+b*g*p+d*f*n-c*f*p+c*h*l)},transpose:function(){var a=this.elements,b;b=a[1];a[1]=a[4];a[4]=b;b=a[2];a[2]=a[8];a[8]=b;b=a[6];a[6]=a[9];a[9]=b;b=a[3];a[3]=a[12];a[12]=b;b=a[7];a[7]=a[13];a[13]=b;b=a[11];a[11]=a[14];a[14]=b;return this},flattenToArrayOffset:function(a,b){var c=this.elements;a[b]=c[0];a[b+1]=c[1];a[b+2]=c[2];a[b+3]=c[3];a[b+4]=c[4];a[b+5]=c[5];a[b+6]=
 c[6];a[b+7]=c[7];a[b+8]=c[8];a[b+9]=c[9];a[b+10]=c[10];a[b+11]=c[11];a[b+12]=c[12];a[b+13]=c[13];a[b+14]=c[14];a[b+15]=c[15];return a},getPosition:function(){var a;return function(){void 0===a&&(a=new THREE.Vector3);console.warn("THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.");var b=this.elements;return a.set(b[12],b[13],b[14])}}(),setPosition:function(a){var b=this.elements;b[12]=a.x;b[13]=a.y;b[14]=a.z;return this},getInverse:function(a,b){var c=
 c[6];a[b+7]=c[7];a[b+8]=c[8];a[b+9]=c[9];a[b+10]=c[10];a[b+11]=c[11];a[b+12]=c[12];a[b+13]=c[13];a[b+14]=c[14];a[b+15]=c[15];return a},getPosition:function(){var a;return function(){void 0===a&&(a=new THREE.Vector3);console.warn("THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.");var b=this.elements;return a.set(b[12],b[13],b[14])}}(),setPosition:function(a){var b=this.elements;b[12]=a.x;b[13]=a.y;b[14]=a.z;return this},getInverse:function(a,b){var c=
-this.elements,d=a.elements,e=d[0],f=d[4],g=d[8],h=d[12],k=d[1],l=d[5],n=d[9],p=d[13],m=d[2],q=d[6],t=d[10],s=d[14],u=d[3],w=d[7],x=d[11],d=d[15];c[0]=n*s*w-p*t*w+p*q*x-l*s*x-n*q*d+l*t*d;c[4]=h*t*w-g*s*w-h*q*x+f*s*x+g*q*d-f*t*d;c[8]=g*p*w-h*n*w+h*l*x-f*p*x-g*l*d+f*n*d;c[12]=h*n*q-g*p*q-h*l*t+f*p*t+g*l*s-f*n*s;c[1]=p*t*u-n*s*u-p*m*x+k*s*x+n*m*d-k*t*d;c[5]=g*s*u-h*t*u+h*m*x-e*s*x-g*m*d+e*t*d;c[9]=h*n*u-g*p*u-h*k*x+e*p*x+g*k*d-e*n*d;c[13]=g*p*m-h*n*m+h*k*t-e*p*t-g*k*s+e*n*s;c[2]=l*s*u-p*q*u+p*m*w-k*s*
-w-l*m*d+k*q*d;c[6]=h*q*u-f*s*u-h*m*w+e*s*w+f*m*d-e*q*d;c[10]=f*p*u-h*l*u+h*k*w-e*p*w-f*k*d+e*l*d;c[14]=h*l*m-f*p*m-h*k*q+e*p*q+f*k*s-e*l*s;c[3]=n*q*u-l*t*u-n*m*w+k*t*w+l*m*x-k*q*x;c[7]=f*t*u-g*q*u+g*m*w-e*t*w-f*m*x+e*q*x;c[11]=g*l*u-f*n*u-g*k*w+e*n*w+f*k*x-e*l*x;c[15]=f*n*m-g*l*m+g*k*q-e*n*q-f*k*t+e*l*t;c=e*c[0]+k*c[4]+m*c[8]+u*c[12];if(0===c){if(b)throw Error("THREE.Matrix4.getInverse(): can't invert matrix, determinant is 0");console.warn("THREE.Matrix4.getInverse(): can't invert matrix, determinant is 0");
+this.elements,d=a.elements,e=d[0],f=d[4],g=d[8],h=d[12],k=d[1],l=d[5],n=d[9],p=d[13],m=d[2],q=d[6],s=d[10],t=d[14],u=d[3],x=d[7],w=d[11],d=d[15];c[0]=n*t*x-p*s*x+p*q*w-l*t*w-n*q*d+l*s*d;c[4]=h*s*x-g*t*x-h*q*w+f*t*w+g*q*d-f*s*d;c[8]=g*p*x-h*n*x+h*l*w-f*p*w-g*l*d+f*n*d;c[12]=h*n*q-g*p*q-h*l*s+f*p*s+g*l*t-f*n*t;c[1]=p*s*u-n*t*u-p*m*w+k*t*w+n*m*d-k*s*d;c[5]=g*t*u-h*s*u+h*m*w-e*t*w-g*m*d+e*s*d;c[9]=h*n*u-g*p*u-h*k*w+e*p*w+g*k*d-e*n*d;c[13]=g*p*m-h*n*m+h*k*s-e*p*s-g*k*t+e*n*t;c[2]=l*t*u-p*q*u+p*m*x-k*t*
+x-l*m*d+k*q*d;c[6]=h*q*u-f*t*u-h*m*x+e*t*x+f*m*d-e*q*d;c[10]=f*p*u-h*l*u+h*k*x-e*p*x-f*k*d+e*l*d;c[14]=h*l*m-f*p*m-h*k*q+e*p*q+f*k*t-e*l*t;c[3]=n*q*u-l*s*u-n*m*x+k*s*x+l*m*w-k*q*w;c[7]=f*s*u-g*q*u+g*m*x-e*s*x-f*m*w+e*q*w;c[11]=g*l*u-f*n*u-g*k*x+e*n*x+f*k*w-e*l*w;c[15]=f*n*m-g*l*m+g*k*q-e*n*q-f*k*s+e*l*s;c=e*c[0]+k*c[4]+m*c[8]+u*c[12];if(0===c){if(b)throw Error("THREE.Matrix4.getInverse(): can't invert matrix, determinant is 0");console.warn("THREE.Matrix4.getInverse(): can't invert matrix, determinant is 0");
 this.identity();return this}this.multiplyScalar(1/c);return this},translate:function(a){console.error("THREE.Matrix4: .translate() has been removed.")},rotateX:function(a){console.error("THREE.Matrix4: .rotateX() has been removed.")},rotateY:function(a){console.error("THREE.Matrix4: .rotateY() has been removed.")},rotateZ:function(a){console.error("THREE.Matrix4: .rotateZ() has been removed.")},rotateByAxis:function(a,b){console.error("THREE.Matrix4: .rotateByAxis() has been removed.")},scale:function(a){var b=
 this.identity();return this}this.multiplyScalar(1/c);return this},translate:function(a){console.error("THREE.Matrix4: .translate() has been removed.")},rotateX:function(a){console.error("THREE.Matrix4: .rotateX() has been removed.")},rotateY:function(a){console.error("THREE.Matrix4: .rotateY() has been removed.")},rotateZ:function(a){console.error("THREE.Matrix4: .rotateZ() has been removed.")},rotateByAxis:function(a,b){console.error("THREE.Matrix4: .rotateByAxis() has been removed.")},scale:function(a){var b=
 this.elements,c=a.x,d=a.y;a=a.z;b[0]*=c;b[4]*=d;b[8]*=a;b[1]*=c;b[5]*=d;b[9]*=a;b[2]*=c;b[6]*=d;b[10]*=a;b[3]*=c;b[7]*=d;b[11]*=a;return this},getMaxScaleOnAxis:function(){var a=this.elements;return Math.sqrt(Math.max(a[0]*a[0]+a[1]*a[1]+a[2]*a[2],Math.max(a[4]*a[4]+a[5]*a[5]+a[6]*a[6],a[8]*a[8]+a[9]*a[9]+a[10]*a[10])))},makeTranslation:function(a,b,c){this.set(1,0,0,a,0,1,0,b,0,0,1,c,0,0,0,1);return this},makeRotationX:function(a){var b=Math.cos(a);a=Math.sin(a);this.set(1,0,0,0,0,b,-a,0,0,a,b,0,
 this.elements,c=a.x,d=a.y;a=a.z;b[0]*=c;b[4]*=d;b[8]*=a;b[1]*=c;b[5]*=d;b[9]*=a;b[2]*=c;b[6]*=d;b[10]*=a;b[3]*=c;b[7]*=d;b[11]*=a;return this},getMaxScaleOnAxis:function(){var a=this.elements;return Math.sqrt(Math.max(a[0]*a[0]+a[1]*a[1]+a[2]*a[2],Math.max(a[4]*a[4]+a[5]*a[5]+a[6]*a[6],a[8]*a[8]+a[9]*a[9]+a[10]*a[10])))},makeTranslation:function(a,b,c){this.set(1,0,0,a,0,1,0,b,0,0,1,c,0,0,0,1);return this},makeRotationX:function(a){var b=Math.cos(a);a=Math.sin(a);this.set(1,0,0,0,0,b,-a,0,0,a,b,0,
 0,0,0,1);return this},makeRotationY:function(a){var b=Math.cos(a);a=Math.sin(a);this.set(b,0,a,0,0,1,0,0,-a,0,b,0,0,0,0,1);return this},makeRotationZ:function(a){var b=Math.cos(a);a=Math.sin(a);this.set(b,-a,0,0,a,b,0,0,0,0,1,0,0,0,0,1);return this},makeRotationAxis:function(a,b){var c=Math.cos(b),d=Math.sin(b),e=1-c,f=a.x,g=a.y,h=a.z,k=e*f,l=e*g;this.set(k*f+c,k*g-d*h,k*h+d*g,0,k*g+d*h,l*g+c,l*h-d*f,0,k*h-d*g,l*h+d*f,e*h*h+c,0,0,0,0,1);return this},makeScale:function(a,b,c){this.set(a,0,0,0,0,b,
 0,0,0,1);return this},makeRotationY:function(a){var b=Math.cos(a);a=Math.sin(a);this.set(b,0,a,0,0,1,0,0,-a,0,b,0,0,0,0,1);return this},makeRotationZ:function(a){var b=Math.cos(a);a=Math.sin(a);this.set(b,-a,0,0,a,b,0,0,0,0,1,0,0,0,0,1);return this},makeRotationAxis:function(a,b){var c=Math.cos(b),d=Math.sin(b),e=1-c,f=a.x,g=a.y,h=a.z,k=e*f,l=e*g;this.set(k*f+c,k*g-d*h,k*h+d*g,0,k*g+d*h,l*g+c,l*h-d*f,0,k*h-d*g,l*h+d*f,e*h*h+c,0,0,0,0,1);return this},makeScale:function(a,b,c){this.set(a,0,0,0,0,b,
@@ -129,8 +129,8 @@ THREE.Sphere.prototype={constructor:THREE.Sphere,set:function(a,b){this.center.c
 this.radius*this.radius},distanceToPoint:function(a){return a.distanceTo(this.center)-this.radius},intersectsSphere:function(a){var b=this.radius+a.radius;return a.center.distanceToSquared(this.center)<=b*b},clampPoint:function(a,b){var c=this.center.distanceToSquared(a),d=b||new THREE.Vector3;d.copy(a);c>this.radius*this.radius&&(d.sub(this.center).normalize(),d.multiplyScalar(this.radius).add(this.center));return d},getBoundingBox:function(a){a=a||new THREE.Box3;a.set(this.center,this.center);a.expandByScalar(this.radius);
 this.radius*this.radius},distanceToPoint:function(a){return a.distanceTo(this.center)-this.radius},intersectsSphere:function(a){var b=this.radius+a.radius;return a.center.distanceToSquared(this.center)<=b*b},clampPoint:function(a,b){var c=this.center.distanceToSquared(a),d=b||new THREE.Vector3;d.copy(a);c>this.radius*this.radius&&(d.sub(this.center).normalize(),d.multiplyScalar(this.radius).add(this.center));return d},getBoundingBox:function(a){a=a||new THREE.Box3;a.set(this.center,this.center);a.expandByScalar(this.radius);
 return a},applyMatrix4:function(a){this.center.applyMatrix4(a);this.radius*=a.getMaxScaleOnAxis();return this},translate:function(a){this.center.add(a);return this},equals:function(a){return a.center.equals(this.center)&&a.radius===this.radius},clone:function(){return(new THREE.Sphere).copy(this)}};
 return a},applyMatrix4:function(a){this.center.applyMatrix4(a);this.radius*=a.getMaxScaleOnAxis();return this},translate:function(a){this.center.add(a);return this},equals:function(a){return a.center.equals(this.center)&&a.radius===this.radius},clone:function(){return(new THREE.Sphere).copy(this)}};
 THREE.Frustum=function(a,b,c,d,e,f){this.planes=[void 0!==a?a:new THREE.Plane,void 0!==b?b:new THREE.Plane,void 0!==c?c:new THREE.Plane,void 0!==d?d:new THREE.Plane,void 0!==e?e:new THREE.Plane,void 0!==f?f:new THREE.Plane]};
 THREE.Frustum=function(a,b,c,d,e,f){this.planes=[void 0!==a?a:new THREE.Plane,void 0!==b?b:new THREE.Plane,void 0!==c?c:new THREE.Plane,void 0!==d?d:new THREE.Plane,void 0!==e?e:new THREE.Plane,void 0!==f?f:new THREE.Plane]};
-THREE.Frustum.prototype={constructor:THREE.Frustum,set:function(a,b,c,d,e,f){var g=this.planes;g[0].copy(a);g[1].copy(b);g[2].copy(c);g[3].copy(d);g[4].copy(e);g[5].copy(f);return this},copy:function(a){for(var b=this.planes,c=0;6>c;c++)b[c].copy(a.planes[c]);return this},setFromMatrix:function(a){var b=this.planes,c=a.elements;a=c[0];var d=c[1],e=c[2],f=c[3],g=c[4],h=c[5],k=c[6],l=c[7],n=c[8],p=c[9],m=c[10],q=c[11],t=c[12],s=c[13],u=c[14],c=c[15];b[0].setComponents(f-a,l-g,q-n,c-t).normalize();b[1].setComponents(f+
-a,l+g,q+n,c+t).normalize();b[2].setComponents(f+d,l+h,q+p,c+s).normalize();b[3].setComponents(f-d,l-h,q-p,c-s).normalize();b[4].setComponents(f-e,l-k,q-m,c-u).normalize();b[5].setComponents(f+e,l+k,q+m,c+u).normalize();return this},intersectsObject:function(){var a=new THREE.Sphere;return function(b){var c=b.geometry;null===c.boundingSphere&&c.computeBoundingSphere();a.copy(c.boundingSphere);a.applyMatrix4(b.matrixWorld);return this.intersectsSphere(a)}}(),intersectsSphere:function(a){var b=this.planes,
+THREE.Frustum.prototype={constructor:THREE.Frustum,set:function(a,b,c,d,e,f){var g=this.planes;g[0].copy(a);g[1].copy(b);g[2].copy(c);g[3].copy(d);g[4].copy(e);g[5].copy(f);return this},copy:function(a){for(var b=this.planes,c=0;6>c;c++)b[c].copy(a.planes[c]);return this},setFromMatrix:function(a){var b=this.planes,c=a.elements;a=c[0];var d=c[1],e=c[2],f=c[3],g=c[4],h=c[5],k=c[6],l=c[7],n=c[8],p=c[9],m=c[10],q=c[11],s=c[12],t=c[13],u=c[14],c=c[15];b[0].setComponents(f-a,l-g,q-n,c-s).normalize();b[1].setComponents(f+
+a,l+g,q+n,c+s).normalize();b[2].setComponents(f+d,l+h,q+p,c+t).normalize();b[3].setComponents(f-d,l-h,q-p,c-t).normalize();b[4].setComponents(f-e,l-k,q-m,c-u).normalize();b[5].setComponents(f+e,l+k,q+m,c+u).normalize();return this},intersectsObject:function(){var a=new THREE.Sphere;return function(b){var c=b.geometry;null===c.boundingSphere&&c.computeBoundingSphere();a.copy(c.boundingSphere);a.applyMatrix4(b.matrixWorld);return this.intersectsSphere(a)}}(),intersectsSphere:function(a){var b=this.planes,
 c=a.center;a=-a.radius;for(var d=0;6>d;d++)if(b[d].distanceToPoint(c)<a)return!1;return!0},intersectsBox:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(c){for(var d=this.planes,e=0;6>e;e++){var f=d[e];a.x=0<f.normal.x?c.min.x:c.max.x;b.x=0<f.normal.x?c.max.x:c.min.x;a.y=0<f.normal.y?c.min.y:c.max.y;b.y=0<f.normal.y?c.max.y:c.min.y;a.z=0<f.normal.z?c.min.z:c.max.z;b.z=0<f.normal.z?c.max.z:c.min.z;var g=f.distanceToPoint(a),f=f.distanceToPoint(b);if(0>g&&0>f)return!1}return!0}}(),
 c=a.center;a=-a.radius;for(var d=0;6>d;d++)if(b[d].distanceToPoint(c)<a)return!1;return!0},intersectsBox:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(c){for(var d=this.planes,e=0;6>e;e++){var f=d[e];a.x=0<f.normal.x?c.min.x:c.max.x;b.x=0<f.normal.x?c.max.x:c.min.x;a.y=0<f.normal.y?c.min.y:c.max.y;b.y=0<f.normal.y?c.max.y:c.min.y;a.z=0<f.normal.z?c.min.z:c.max.z;b.z=0<f.normal.z?c.max.z:c.min.z;var g=f.distanceToPoint(a),f=f.distanceToPoint(b);if(0>g&&0>f)return!1}return!0}}(),
 containsPoint:function(a){for(var b=this.planes,c=0;6>c;c++)if(0>b[c].distanceToPoint(a))return!1;return!0},clone:function(){return(new THREE.Frustum).copy(this)}};THREE.Plane=function(a,b){this.normal=void 0!==a?a:new THREE.Vector3(1,0,0);this.constant=void 0!==b?b:0};
 containsPoint:function(a){for(var b=this.planes,c=0;6>c;c++)if(0>b[c].distanceToPoint(a))return!1;return!0},clone:function(){return(new THREE.Frustum).copy(this)}};THREE.Plane=function(a,b){this.normal=void 0!==a?a:new THREE.Vector3(1,0,0);this.constant=void 0!==b?b:0};
 THREE.Plane.prototype={constructor:THREE.Plane,set:function(a,b){this.normal.copy(a);this.constant=b;return this},setComponents:function(a,b,c,d){this.normal.set(a,b,c);this.constant=d;return this},setFromNormalAndCoplanarPoint:function(a,b){this.normal.copy(a);this.constant=-b.dot(this.normal);return this},setFromCoplanarPoints:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(c,d,e){d=a.subVectors(e,d).cross(b.subVectors(c,d)).normalize();this.setFromNormalAndCoplanarPoint(d,
 THREE.Plane.prototype={constructor:THREE.Plane,set:function(a,b){this.normal.copy(a);this.constant=b;return this},setComponents:function(a,b,c,d){this.normal.set(a,b,c);this.constant=d;return this},setFromNormalAndCoplanarPoint:function(a,b){this.normal.copy(a);this.constant=-b.dot(this.normal);return this},setFromCoplanarPoints:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(c,d,e){d=a.subVectors(e,d).cross(b.subVectors(c,d)).normalize();this.setFromNormalAndCoplanarPoint(d,
@@ -143,7 +143,7 @@ c){if(a<=b)return 0;if(a>=c)return 1;a=(a-b)/(c-b);return a*a*(3-2*a)},smoothers
 180/Math.PI;return function(b){return b*a}}(),isPowerOfTwo:function(a){return 0===(a&a-1)&&0!==a},nextPowerOfTwo:function(a){a--;a|=a>>1;a|=a>>2;a|=a>>4;a|=a>>8;a|=a>>16;a++;return a}};
 180/Math.PI;return function(b){return b*a}}(),isPowerOfTwo:function(a){return 0===(a&a-1)&&0!==a},nextPowerOfTwo:function(a){a--;a|=a>>1;a|=a>>2;a|=a>>4;a|=a>>8;a|=a>>16;a++;return a}};
 THREE.Spline=function(a){function b(a,b,c,d,e,f,g){a=.5*(c-a);d=.5*(d-b);return(2*(b-c)+a+d)*g+(-3*(b-c)-2*a-d)*f+a*e+b}this.points=a;var c=[],d={x:0,y:0,z:0},e,f,g,h,k,l,n,p,m;this.initFromArray=function(a){this.points=[];for(var b=0;b<a.length;b++)this.points[b]={x:a[b][0],y:a[b][1],z:a[b][2]}};this.getPoint=function(a){e=(this.points.length-1)*a;f=Math.floor(e);g=e-f;c[0]=0===f?f:f-1;c[1]=f;c[2]=f>this.points.length-2?this.points.length-1:f+1;c[3]=f>this.points.length-3?this.points.length-1:f+
 THREE.Spline=function(a){function b(a,b,c,d,e,f,g){a=.5*(c-a);d=.5*(d-b);return(2*(b-c)+a+d)*g+(-3*(b-c)-2*a-d)*f+a*e+b}this.points=a;var c=[],d={x:0,y:0,z:0},e,f,g,h,k,l,n,p,m;this.initFromArray=function(a){this.points=[];for(var b=0;b<a.length;b++)this.points[b]={x:a[b][0],y:a[b][1],z:a[b][2]}};this.getPoint=function(a){e=(this.points.length-1)*a;f=Math.floor(e);g=e-f;c[0]=0===f?f:f-1;c[1]=f;c[2]=f>this.points.length-2?this.points.length-1:f+1;c[3]=f>this.points.length-3?this.points.length-1:f+
 2;l=this.points[c[0]];n=this.points[c[1]];p=this.points[c[2]];m=this.points[c[3]];h=g*g;k=g*h;d.x=b(l.x,n.x,p.x,m.x,g,h,k);d.y=b(l.y,n.y,p.y,m.y,g,h,k);d.z=b(l.z,n.z,p.z,m.z,g,h,k);return d};this.getControlPointsArray=function(){var a,b,c=this.points.length,d=[];for(a=0;a<c;a++)b=this.points[a],d[a]=[b.x,b.y,b.z];return d};this.getLength=function(a){var b,c,d,e=b=b=0,f=new THREE.Vector3,g=new THREE.Vector3,h=[],k=0;h[0]=0;a||(a=100);c=this.points.length*a;f.copy(this.points[0]);for(a=1;a<c;a++)b=
 2;l=this.points[c[0]];n=this.points[c[1]];p=this.points[c[2]];m=this.points[c[3]];h=g*g;k=g*h;d.x=b(l.x,n.x,p.x,m.x,g,h,k);d.y=b(l.y,n.y,p.y,m.y,g,h,k);d.z=b(l.z,n.z,p.z,m.z,g,h,k);return d};this.getControlPointsArray=function(){var a,b,c=this.points.length,d=[];for(a=0;a<c;a++)b=this.points[a],d[a]=[b.x,b.y,b.z];return d};this.getLength=function(a){var b,c,d,e=b=b=0,f=new THREE.Vector3,g=new THREE.Vector3,h=[],k=0;h[0]=0;a||(a=100);c=this.points.length*a;f.copy(this.points[0]);for(a=1;a<c;a++)b=
-a/c,d=this.getPoint(b),g.copy(d),k+=g.distanceTo(f),f.copy(d),b*=this.points.length-1,b=Math.floor(b),b!==e&&(h[b]=k,e=b);h[h.length]=k;return{chunks:h,total:k}};this.reparametrizeByArcLength=function(a){var b,c,d,e,f,g,h=[],k=new THREE.Vector3,m=this.getLength();h.push(k.copy(this.points[0]).clone());for(b=1;b<this.points.length;b++){c=m.chunks[b]-m.chunks[b-1];g=Math.ceil(a*c/m.total);e=(b-1)/(this.points.length-1);f=b/(this.points.length-1);for(c=1;c<g-1;c++)d=e+1/g*c*(f-e),d=this.getPoint(d),
+a/c,d=this.getPoint(b),g.copy(d),k+=g.distanceTo(f),f.copy(d),b*=this.points.length-1,b=Math.floor(b),b!==e&&(h[b]=k,e=b);h[h.length]=k;return{chunks:h,total:k}};this.reparametrizeByArcLength=function(a){var b,c,d,e,f,g,h=[],k=new THREE.Vector3,l=this.getLength();h.push(k.copy(this.points[0]).clone());for(b=1;b<this.points.length;b++){c=l.chunks[b]-l.chunks[b-1];g=Math.ceil(a*c/l.total);e=(b-1)/(this.points.length-1);f=b/(this.points.length-1);for(c=1;c<g-1;c++)d=e+1/g*c*(f-e),d=this.getPoint(d),
 h.push(k.copy(d).clone());h.push(k.copy(this.points[b]).clone())}this.points=h}};THREE.Triangle=function(a,b,c){this.a=void 0!==a?a:new THREE.Vector3;this.b=void 0!==b?b:new THREE.Vector3;this.c=void 0!==c?c:new THREE.Vector3};THREE.Triangle.normal=function(){var a=new THREE.Vector3;return function(b,c,d,e){e=e||new THREE.Vector3;e.subVectors(d,c);a.subVectors(b,c);e.cross(a);b=e.lengthSq();return 0<b?e.multiplyScalar(1/Math.sqrt(b)):e.set(0,0,0)}}();
 h.push(k.copy(d).clone());h.push(k.copy(this.points[b]).clone())}this.points=h}};THREE.Triangle=function(a,b,c){this.a=void 0!==a?a:new THREE.Vector3;this.b=void 0!==b?b:new THREE.Vector3;this.c=void 0!==c?c:new THREE.Vector3};THREE.Triangle.normal=function(){var a=new THREE.Vector3;return function(b,c,d,e){e=e||new THREE.Vector3;e.subVectors(d,c);a.subVectors(b,c);e.cross(a);b=e.lengthSq();return 0<b?e.multiplyScalar(1/Math.sqrt(b)):e.set(0,0,0)}}();
 THREE.Triangle.barycoordFromPoint=function(){var a=new THREE.Vector3,b=new THREE.Vector3,c=new THREE.Vector3;return function(d,e,f,g,h){a.subVectors(g,e);b.subVectors(f,e);c.subVectors(d,e);d=a.dot(a);e=a.dot(b);f=a.dot(c);var k=b.dot(b);g=b.dot(c);var l=d*k-e*e;h=h||new THREE.Vector3;if(0===l)return h.set(-2,-1,-1);l=1/l;k=(k*f-e*g)*l;d=(d*g-e*f)*l;return h.set(1-k-d,d,k)}}();
 THREE.Triangle.barycoordFromPoint=function(){var a=new THREE.Vector3,b=new THREE.Vector3,c=new THREE.Vector3;return function(d,e,f,g,h){a.subVectors(g,e);b.subVectors(f,e);c.subVectors(d,e);d=a.dot(a);e=a.dot(b);f=a.dot(c);var k=b.dot(b);g=b.dot(c);var l=d*k-e*e;h=h||new THREE.Vector3;if(0===l)return h.set(-2,-1,-1);l=1/l;k=(k*f-e*g)*l;d=(d*g-e*f)*l;return h.set(1-k-d,d,k)}}();
 THREE.Triangle.containsPoint=function(){var a=new THREE.Vector3;return function(b,c,d,e){b=THREE.Triangle.barycoordFromPoint(b,c,d,e,a);return 0<=b.x&&0<=b.y&&1>=b.x+b.y}}();
 THREE.Triangle.containsPoint=function(){var a=new THREE.Vector3;return function(b,c,d,e){b=THREE.Triangle.barycoordFromPoint(b,c,d,e,a);return 0<=b.x&&0<=b.y&&1>=b.x+b.y}}();
@@ -194,55 +194,55 @@ THREE.Geometry=function(){Object.defineProperty(this,"id",{value:THREE.GeometryI
 this.uvsNeedUpdate=this.elementsNeedUpdate=this.verticesNeedUpdate=this.hasTangents=!1};
 this.uvsNeedUpdate=this.elementsNeedUpdate=this.verticesNeedUpdate=this.hasTangents=!1};
 THREE.Geometry.prototype={constructor:THREE.Geometry,applyMatrix:function(a){for(var b=(new THREE.Matrix3).getNormalMatrix(a),c=0,d=this.vertices.length;c<d;c++)this.vertices[c].applyMatrix4(a);c=0;for(d=this.faces.length;c<d;c++){a=this.faces[c];a.normal.applyMatrix3(b).normalize();for(var e=0,f=a.vertexNormals.length;e<f;e++)a.vertexNormals[e].applyMatrix3(b).normalize()}null!==this.boundingBox&&this.computeBoundingBox();null!==this.boundingSphere&&this.computeBoundingSphere();this.normalsNeedUpdate=
 THREE.Geometry.prototype={constructor:THREE.Geometry,applyMatrix:function(a){for(var b=(new THREE.Matrix3).getNormalMatrix(a),c=0,d=this.vertices.length;c<d;c++)this.vertices[c].applyMatrix4(a);c=0;for(d=this.faces.length;c<d;c++){a=this.faces[c];a.normal.applyMatrix3(b).normalize();for(var e=0,f=a.vertexNormals.length;e<f;e++)a.vertexNormals[e].applyMatrix3(b).normalize()}null!==this.boundingBox&&this.computeBoundingBox();null!==this.boundingSphere&&this.computeBoundingSphere();this.normalsNeedUpdate=
 this.verticesNeedUpdate=!0},fromBufferGeometry:function(a){for(var b=this,c=a.attributes,d=c.position.array,e=void 0!==c.index?c.index.array:void 0,f=void 0!==c.normal?c.normal.array:void 0,g=void 0!==c.color?c.color.array:void 0,h=void 0!==c.uv?c.uv.array:void 0,k=[],l=[],n=c=0;c<d.length;c+=3,n+=2)b.vertices.push(new THREE.Vector3(d[c],d[c+1],d[c+2])),void 0!==f&&k.push(new THREE.Vector3(f[c],f[c+1],f[c+2])),void 0!==g&&b.colors.push(new THREE.Color(g[c],g[c+1],g[c+2])),void 0!==h&&l.push(new THREE.Vector2(h[n],
 this.verticesNeedUpdate=!0},fromBufferGeometry:function(a){for(var b=this,c=a.attributes,d=c.position.array,e=void 0!==c.index?c.index.array:void 0,f=void 0!==c.normal?c.normal.array:void 0,g=void 0!==c.color?c.color.array:void 0,h=void 0!==c.uv?c.uv.array:void 0,k=[],l=[],n=c=0;c<d.length;c+=3,n+=2)b.vertices.push(new THREE.Vector3(d[c],d[c+1],d[c+2])),void 0!==f&&k.push(new THREE.Vector3(f[c],f[c+1],f[c+2])),void 0!==g&&b.colors.push(new THREE.Color(g[c],g[c+1],g[c+2])),void 0!==h&&l.push(new THREE.Vector2(h[n],
-h[n+1]));var p=function(a,c,d){var e=void 0!==f?[k[a].clone(),k[c].clone(),k[d].clone()]:[],m=void 0!==g?[b.colors[a].clone(),b.colors[c].clone(),b.colors[d].clone()]:[];b.faces.push(new THREE.Face3(a,c,d,e,m));void 0!==h&&b.faceVertexUvs[0].push([l[a].clone(),l[c].clone(),l[d].clone()])};if(void 0!==e)if(d=a.drawcalls,0<d.length)for(c=0;c<d.length;c++)for(var n=d[c],m=n.start,q=n.count,t=n.index,n=m,m=m+q;n<m;n+=3)p(t+e[n],t+e[n+1],t+e[n+2]);else for(c=0;c<e.length;c+=3)p(e[c],e[c+1],e[c+2]);else for(c=
+h[n+1]));var p=function(a,c,d){var e=void 0!==f?[k[a].clone(),k[c].clone(),k[d].clone()]:[],m=void 0!==g?[b.colors[a].clone(),b.colors[c].clone(),b.colors[d].clone()]:[];b.faces.push(new THREE.Face3(a,c,d,e,m));void 0!==h&&b.faceVertexUvs[0].push([l[a].clone(),l[c].clone(),l[d].clone()])};if(void 0!==e)if(d=a.drawcalls,0<d.length)for(c=0;c<d.length;c++)for(var n=d[c],m=n.start,q=n.count,s=n.index,n=m,m=m+q;n<m;n+=3)p(s+e[n],s+e[n+1],s+e[n+2]);else for(c=0;c<e.length;c+=3)p(e[c],e[c+1],e[c+2]);else for(c=
 0;c<d.length/3;c+=3)p(c,c+1,c+2);this.computeFaceNormals();null!==a.boundingBox&&(this.boundingBox=a.boundingBox.clone());null!==a.boundingSphere&&(this.boundingSphere=a.boundingSphere.clone());return this},center:function(){this.computeBoundingBox();var a=this.boundingBox.center().negate();this.applyMatrix((new THREE.Matrix4).setPosition(a));return a},normalize:function(){this.computeBoundingSphere();var a=this.boundingSphere.center,b=this.boundingSphere.radius,b=0===b?1:1/b,c=new THREE.Matrix4;
 0;c<d.length/3;c+=3)p(c,c+1,c+2);this.computeFaceNormals();null!==a.boundingBox&&(this.boundingBox=a.boundingBox.clone());null!==a.boundingSphere&&(this.boundingSphere=a.boundingSphere.clone());return this},center:function(){this.computeBoundingBox();var a=this.boundingBox.center().negate();this.applyMatrix((new THREE.Matrix4).setPosition(a));return a},normalize:function(){this.computeBoundingSphere();var a=this.boundingSphere.center,b=this.boundingSphere.radius,b=0===b?1:1/b,c=new THREE.Matrix4;
 c.set(b,0,0,-b*a.x,0,b,0,-b*a.y,0,0,b,-b*a.z,0,0,0,1);this.applyMatrix(c);return this},computeFaceNormals:function(){for(var a=new THREE.Vector3,b=new THREE.Vector3,c=0,d=this.faces.length;c<d;c++){var e=this.faces[c],f=this.vertices[e.a],g=this.vertices[e.b];a.subVectors(this.vertices[e.c],g);b.subVectors(f,g);a.cross(b);a.normalize();e.normal.copy(a)}},computeVertexNormals:function(a){var b,c,d;d=Array(this.vertices.length);b=0;for(c=this.vertices.length;b<c;b++)d[b]=new THREE.Vector3;if(a){var e,
 c.set(b,0,0,-b*a.x,0,b,0,-b*a.y,0,0,b,-b*a.z,0,0,0,1);this.applyMatrix(c);return this},computeFaceNormals:function(){for(var a=new THREE.Vector3,b=new THREE.Vector3,c=0,d=this.faces.length;c<d;c++){var e=this.faces[c],f=this.vertices[e.a],g=this.vertices[e.b];a.subVectors(this.vertices[e.c],g);b.subVectors(f,g);a.cross(b);a.normalize();e.normal.copy(a)}},computeVertexNormals:function(a){var b,c,d;d=Array(this.vertices.length);b=0;for(c=this.vertices.length;b<c;b++)d[b]=new THREE.Vector3;if(a){var e,
 f,g,h=new THREE.Vector3,k=new THREE.Vector3;a=0;for(b=this.faces.length;a<b;a++)c=this.faces[a],e=this.vertices[c.a],f=this.vertices[c.b],g=this.vertices[c.c],h.subVectors(g,f),k.subVectors(e,f),h.cross(k),d[c.a].add(h),d[c.b].add(h),d[c.c].add(h)}else for(a=0,b=this.faces.length;a<b;a++)c=this.faces[a],d[c.a].add(c.normal),d[c.b].add(c.normal),d[c.c].add(c.normal);b=0;for(c=this.vertices.length;b<c;b++)d[b].normalize();a=0;for(b=this.faces.length;a<b;a++)c=this.faces[a],e=c.vertexNormals,3===e.length?
 f,g,h=new THREE.Vector3,k=new THREE.Vector3;a=0;for(b=this.faces.length;a<b;a++)c=this.faces[a],e=this.vertices[c.a],f=this.vertices[c.b],g=this.vertices[c.c],h.subVectors(g,f),k.subVectors(e,f),h.cross(k),d[c.a].add(h),d[c.b].add(h),d[c.c].add(h)}else for(a=0,b=this.faces.length;a<b;a++)c=this.faces[a],d[c.a].add(c.normal),d[c.b].add(c.normal),d[c.c].add(c.normal);b=0;for(c=this.vertices.length;b<c;b++)d[b].normalize();a=0;for(b=this.faces.length;a<b;a++)c=this.faces[a],e=c.vertexNormals,3===e.length?
 (e[0].copy(d[c.a]),e[1].copy(d[c.b]),e[2].copy(d[c.c])):(e[0]=d[c.a].clone(),e[1]=d[c.b].clone(),e[2]=d[c.c].clone())},computeMorphNormals:function(){var a,b,c,d,e;c=0;for(d=this.faces.length;c<d;c++)for(e=this.faces[c],e.__originalFaceNormal?e.__originalFaceNormal.copy(e.normal):e.__originalFaceNormal=e.normal.clone(),e.__originalVertexNormals||(e.__originalVertexNormals=[]),a=0,b=e.vertexNormals.length;a<b;a++)e.__originalVertexNormals[a]?e.__originalVertexNormals[a].copy(e.vertexNormals[a]):e.__originalVertexNormals[a]=
 (e[0].copy(d[c.a]),e[1].copy(d[c.b]),e[2].copy(d[c.c])):(e[0]=d[c.a].clone(),e[1]=d[c.b].clone(),e[2]=d[c.c].clone())},computeMorphNormals:function(){var a,b,c,d,e;c=0;for(d=this.faces.length;c<d;c++)for(e=this.faces[c],e.__originalFaceNormal?e.__originalFaceNormal.copy(e.normal):e.__originalFaceNormal=e.normal.clone(),e.__originalVertexNormals||(e.__originalVertexNormals=[]),a=0,b=e.vertexNormals.length;a<b;a++)e.__originalVertexNormals[a]?e.__originalVertexNormals[a].copy(e.vertexNormals[a]):e.__originalVertexNormals[a]=
 e.vertexNormals[a].clone();var f=new THREE.Geometry;f.faces=this.faces;a=0;for(b=this.morphTargets.length;a<b;a++){if(!this.morphNormals[a]){this.morphNormals[a]={};this.morphNormals[a].faceNormals=[];this.morphNormals[a].vertexNormals=[];e=this.morphNormals[a].faceNormals;var g=this.morphNormals[a].vertexNormals,h,k;c=0;for(d=this.faces.length;c<d;c++)h=new THREE.Vector3,k={a:new THREE.Vector3,b:new THREE.Vector3,c:new THREE.Vector3},e.push(h),g.push(k)}g=this.morphNormals[a];f.vertices=this.morphTargets[a].vertices;
 e.vertexNormals[a].clone();var f=new THREE.Geometry;f.faces=this.faces;a=0;for(b=this.morphTargets.length;a<b;a++){if(!this.morphNormals[a]){this.morphNormals[a]={};this.morphNormals[a].faceNormals=[];this.morphNormals[a].vertexNormals=[];e=this.morphNormals[a].faceNormals;var g=this.morphNormals[a].vertexNormals,h,k;c=0;for(d=this.faces.length;c<d;c++)h=new THREE.Vector3,k={a:new THREE.Vector3,b:new THREE.Vector3,c:new THREE.Vector3},e.push(h),g.push(k)}g=this.morphNormals[a];f.vertices=this.morphTargets[a].vertices;
-f.computeFaceNormals();f.computeVertexNormals();c=0;for(d=this.faces.length;c<d;c++)e=this.faces[c],h=g.faceNormals[c],k=g.vertexNormals[c],h.copy(e.normal),k.a.copy(e.vertexNormals[0]),k.b.copy(e.vertexNormals[1]),k.c.copy(e.vertexNormals[2])}c=0;for(d=this.faces.length;c<d;c++)e=this.faces[c],e.normal=e.__originalFaceNormal,e.vertexNormals=e.__originalVertexNormals},computeTangents:function(){var a,b,c,d,e,f,g,h,k,l,n,p,m,q,t,s,u,w=[],x=[];c=new THREE.Vector3;var A=new THREE.Vector3,y=new THREE.Vector3,
-D=new THREE.Vector3,I=new THREE.Vector3;a=0;for(b=this.vertices.length;a<b;a++)w[a]=new THREE.Vector3,x[a]=new THREE.Vector3;a=0;for(b=this.faces.length;a<b;a++)e=this.faces[a],f=this.faceVertexUvs[0][a],d=e.a,u=e.b,e=e.c,g=this.vertices[d],h=this.vertices[u],k=this.vertices[e],l=f[0],n=f[1],p=f[2],f=h.x-g.x,m=k.x-g.x,q=h.y-g.y,t=k.y-g.y,h=h.z-g.z,g=k.z-g.z,k=n.x-l.x,s=p.x-l.x,n=n.y-l.y,l=p.y-l.y,p=1/(k*l-s*n),c.set((l*f-n*m)*p,(l*q-n*t)*p,(l*h-n*g)*p),A.set((k*m-s*f)*p,(k*t-s*q)*p,(k*g-s*h)*p),w[d].add(c),
-w[u].add(c),w[e].add(c),x[d].add(A),x[u].add(A),x[e].add(A);A=["a","b","c","d"];a=0;for(b=this.faces.length;a<b;a++)for(e=this.faces[a],c=0;c<Math.min(e.vertexNormals.length,3);c++)I.copy(e.vertexNormals[c]),d=e[A[c]],u=w[d],y.copy(u),y.sub(I.multiplyScalar(I.dot(u))).normalize(),D.crossVectors(e.vertexNormals[c],u),d=D.dot(x[d]),d=0>d?-1:1,e.vertexTangents[c]=new THREE.Vector4(y.x,y.y,y.z,d);this.hasTangents=!0},computeLineDistances:function(){for(var a=0,b=this.vertices,c=0,d=b.length;c<d;c++)0<
+f.computeFaceNormals();f.computeVertexNormals();c=0;for(d=this.faces.length;c<d;c++)e=this.faces[c],h=g.faceNormals[c],k=g.vertexNormals[c],h.copy(e.normal),k.a.copy(e.vertexNormals[0]),k.b.copy(e.vertexNormals[1]),k.c.copy(e.vertexNormals[2])}c=0;for(d=this.faces.length;c<d;c++)e=this.faces[c],e.normal=e.__originalFaceNormal,e.vertexNormals=e.__originalVertexNormals},computeTangents:function(){var a,b,c,d,e,f,g,h,k,l,n,p,m,q,s,t,u,x=[],w=[];c=new THREE.Vector3;var A=new THREE.Vector3,y=new THREE.Vector3,
+G=new THREE.Vector3,I=new THREE.Vector3;a=0;for(b=this.vertices.length;a<b;a++)x[a]=new THREE.Vector3,w[a]=new THREE.Vector3;a=0;for(b=this.faces.length;a<b;a++)e=this.faces[a],f=this.faceVertexUvs[0][a],d=e.a,u=e.b,e=e.c,g=this.vertices[d],h=this.vertices[u],k=this.vertices[e],l=f[0],n=f[1],p=f[2],f=h.x-g.x,m=k.x-g.x,q=h.y-g.y,s=k.y-g.y,h=h.z-g.z,g=k.z-g.z,k=n.x-l.x,t=p.x-l.x,n=n.y-l.y,l=p.y-l.y,p=1/(k*l-t*n),c.set((l*f-n*m)*p,(l*q-n*s)*p,(l*h-n*g)*p),A.set((k*m-t*f)*p,(k*s-t*q)*p,(k*g-t*h)*p),x[d].add(c),
+x[u].add(c),x[e].add(c),w[d].add(A),w[u].add(A),w[e].add(A);A=["a","b","c","d"];a=0;for(b=this.faces.length;a<b;a++)for(e=this.faces[a],c=0;c<Math.min(e.vertexNormals.length,3);c++)I.copy(e.vertexNormals[c]),d=e[A[c]],u=x[d],y.copy(u),y.sub(I.multiplyScalar(I.dot(u))).normalize(),G.crossVectors(e.vertexNormals[c],u),d=G.dot(w[d]),d=0>d?-1:1,e.vertexTangents[c]=new THREE.Vector4(y.x,y.y,y.z,d);this.hasTangents=!0},computeLineDistances:function(){for(var a=0,b=this.vertices,c=0,d=b.length;c<d;c++)0<
 c&&(a+=b[c].distanceTo(b[c-1])),this.lineDistances[c]=a},computeBoundingBox:function(){null===this.boundingBox&&(this.boundingBox=new THREE.Box3);this.boundingBox.setFromPoints(this.vertices)},computeBoundingSphere:function(){null===this.boundingSphere&&(this.boundingSphere=new THREE.Sphere);this.boundingSphere.setFromPoints(this.vertices)},merge:function(a,b){if(!1===a instanceof THREE.Geometry)console.error("THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.",a);else{var c,d=this.vertices.length,
 c&&(a+=b[c].distanceTo(b[c-1])),this.lineDistances[c]=a},computeBoundingBox:function(){null===this.boundingBox&&(this.boundingBox=new THREE.Box3);this.boundingBox.setFromPoints(this.vertices)},computeBoundingSphere:function(){null===this.boundingSphere&&(this.boundingSphere=new THREE.Sphere);this.boundingSphere.setFromPoints(this.vertices)},merge:function(a,b){if(!1===a instanceof THREE.Geometry)console.error("THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.",a);else{var c,d=this.vertices.length,
-e=this.vertices,f=a.vertices,g=this.faces,h=a.faces,k=this.faceVertexUvs[0],l=a.faceVertexUvs[0];void 0!==b&&(c=(new THREE.Matrix3).getNormalMatrix(b));for(var n=0,p=f.length;n<p;n++){var m=f[n].clone();void 0!==b&&m.applyMatrix4(b);e.push(m)}n=0;for(p=h.length;n<p;n++){var q=h[n],t,s=q.vertexNormals,u=q.vertexColors,m=new THREE.Face3(q.a+d,q.b+d,q.c+d);m.normal.copy(q.normal);void 0!==c&&m.normal.applyMatrix3(c).normalize();e=0;for(f=s.length;e<f;e++)t=s[e].clone(),void 0!==c&&t.applyMatrix3(c).normalize(),
-m.vertexNormals.push(t);m.color.copy(q.color);e=0;for(f=u.length;e<f;e++)q=u[e],m.vertexColors.push(q.clone());g.push(m)}n=0;for(p=l.length;n<p;n++)if(c=l[n],d=[],void 0!==c){e=0;for(f=c.length;e<f;e++)d.push(c[e].clone());k.push(d)}}},mergeMesh:function(a){!1===a instanceof THREE.Mesh?console.error("THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.",a):(a.matrixAutoUpdate&&a.updateMatrix(),this.merge(a.geometry,a.matrix))},mergeVertices:function(){var a={},b=[],c=[],d,e=Math.pow(10,
+e=this.vertices,f=a.vertices,g=this.faces,h=a.faces,k=this.faceVertexUvs[0],l=a.faceVertexUvs[0];void 0!==b&&(c=(new THREE.Matrix3).getNormalMatrix(b));for(var n=0,p=f.length;n<p;n++){var m=f[n].clone();void 0!==b&&m.applyMatrix4(b);e.push(m)}n=0;for(p=h.length;n<p;n++){var q=h[n],s,t=q.vertexNormals,u=q.vertexColors,m=new THREE.Face3(q.a+d,q.b+d,q.c+d);m.normal.copy(q.normal);void 0!==c&&m.normal.applyMatrix3(c).normalize();e=0;for(f=t.length;e<f;e++)s=t[e].clone(),void 0!==c&&s.applyMatrix3(c).normalize(),
+m.vertexNormals.push(s);m.color.copy(q.color);e=0;for(f=u.length;e<f;e++)q=u[e],m.vertexColors.push(q.clone());g.push(m)}n=0;for(p=l.length;n<p;n++)if(c=l[n],d=[],void 0!==c){e=0;for(f=c.length;e<f;e++)d.push(c[e].clone());k.push(d)}}},mergeMesh:function(a){!1===a instanceof THREE.Mesh?console.error("THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.",a):(a.matrixAutoUpdate&&a.updateMatrix(),this.merge(a.geometry,a.matrix))},mergeVertices:function(){var a={},b=[],c=[],d,e=Math.pow(10,
 4),f,g;f=0;for(g=this.vertices.length;f<g;f++)d=this.vertices[f],d=Math.round(d.x*e)+"_"+Math.round(d.y*e)+"_"+Math.round(d.z*e),void 0===a[d]?(a[d]=f,b.push(this.vertices[f]),c[f]=b.length-1):c[f]=c[a[d]];a=[];f=0;for(g=this.faces.length;f<g;f++)for(e=this.faces[f],e.a=c[e.a],e.b=c[e.b],e.c=c[e.c],e=[e.a,e.b,e.c],d=0;3>d;d++)if(e[d]===e[(d+1)%3]){a.push(f);break}for(f=a.length-1;0<=f;f--)for(e=a[f],this.faces.splice(e,1),c=0,g=this.faceVertexUvs.length;c<g;c++)this.faceVertexUvs[c].splice(e,1);f=
 4),f,g;f=0;for(g=this.vertices.length;f<g;f++)d=this.vertices[f],d=Math.round(d.x*e)+"_"+Math.round(d.y*e)+"_"+Math.round(d.z*e),void 0===a[d]?(a[d]=f,b.push(this.vertices[f]),c[f]=b.length-1):c[f]=c[a[d]];a=[];f=0;for(g=this.faces.length;f<g;f++)for(e=this.faces[f],e.a=c[e.a],e.b=c[e.b],e.c=c[e.c],e=[e.a,e.b,e.c],d=0;3>d;d++)if(e[d]===e[(d+1)%3]){a.push(f);break}for(f=a.length-1;0<=f;f--)for(e=a[f],this.faces.splice(e,1),c=0,g=this.faceVertexUvs.length;c<g;c++)this.faceVertexUvs[c].splice(e,1);f=
 this.vertices.length-b.length;this.vertices=b;return f},toJSON:function(){function a(a,b,c){return c?a|1<<b:a&~(1<<b)}function b(a){var b=a.x.toString()+a.y.toString()+a.z.toString();if(void 0!==l[b])return l[b];l[b]=k.length/3;k.push(a.x,a.y,a.z);return l[b]}function c(a){var b=a.r.toString()+a.g.toString()+a.b.toString();if(void 0!==p[b])return p[b];p[b]=n.length;n.push(a.getHex());return p[b]}function d(a){var b=a.x.toString()+a.y.toString();if(void 0!==q[b])return q[b];q[b]=m.length/2;m.push(a.x,
 this.vertices.length-b.length;this.vertices=b;return f},toJSON:function(){function a(a,b,c){return c?a|1<<b:a&~(1<<b)}function b(a){var b=a.x.toString()+a.y.toString()+a.z.toString();if(void 0!==l[b])return l[b];l[b]=k.length/3;k.push(a.x,a.y,a.z);return l[b]}function c(a){var b=a.r.toString()+a.g.toString()+a.b.toString();if(void 0!==p[b])return p[b];p[b]=n.length;n.push(a.getHex());return p[b]}function d(a){var b=a.x.toString()+a.y.toString();if(void 0!==q[b])return q[b];q[b]=m.length/2;m.push(a.x,
-a.y);return q[b]}var e={metadata:{version:4.4,type:"Geometry",generator:"Geometry.toJSON"}};e.uuid=this.uuid;e.type=this.type;""!==this.name&&(e.name=this.name);if(void 0!==this.parameters){var f=this.parameters,g;for(g in f)void 0!==f[g]&&(e[g]=f[g]);return e}f=[];for(g=0;g<this.vertices.length;g++){var h=this.vertices[g];f.push(h.x,h.y,h.z)}var h=[],k=[],l={},n=[],p={},m=[],q={};for(g=0;g<this.faces.length;g++){var t=this.faces[g],s=void 0!==this.faceVertexUvs[0][g],u=0<t.normal.length(),w=0<t.vertexNormals.length,
-x=1!==t.color.r||1!==t.color.g||1!==t.color.b,A=0<t.vertexColors.length,y=0,y=a(y,0,0),y=a(y,1,!1),y=a(y,2,!1),y=a(y,3,s),y=a(y,4,u),y=a(y,5,w),y=a(y,6,x),y=a(y,7,A);h.push(y);h.push(t.a,t.b,t.c);s&&(s=this.faceVertexUvs[0][g],h.push(d(s[0]),d(s[1]),d(s[2])));u&&h.push(b(t.normal));w&&(u=t.vertexNormals,h.push(b(u[0]),b(u[1]),b(u[2])));x&&h.push(c(t.color));A&&(t=t.vertexColors,h.push(c(t[0]),c(t[1]),c(t[2])))}e.data={};e.data.vertices=f;e.data.normals=k;0<n.length&&(e.data.colors=n);0<m.length&&
+a.y);return q[b]}var e={metadata:{version:4.4,type:"Geometry",generator:"Geometry.toJSON"}};e.uuid=this.uuid;e.type=this.type;""!==this.name&&(e.name=this.name);if(void 0!==this.parameters){var f=this.parameters,g;for(g in f)void 0!==f[g]&&(e[g]=f[g]);return e}f=[];for(g=0;g<this.vertices.length;g++){var h=this.vertices[g];f.push(h.x,h.y,h.z)}var h=[],k=[],l={},n=[],p={},m=[],q={};for(g=0;g<this.faces.length;g++){var s=this.faces[g],t=void 0!==this.faceVertexUvs[0][g],u=0<s.normal.length(),x=0<s.vertexNormals.length,
+w=1!==s.color.r||1!==s.color.g||1!==s.color.b,A=0<s.vertexColors.length,y=0,y=a(y,0,0),y=a(y,1,!1),y=a(y,2,!1),y=a(y,3,t),y=a(y,4,u),y=a(y,5,x),y=a(y,6,w),y=a(y,7,A);h.push(y);h.push(s.a,s.b,s.c);t&&(t=this.faceVertexUvs[0][g],h.push(d(t[0]),d(t[1]),d(t[2])));u&&h.push(b(s.normal));x&&(u=s.vertexNormals,h.push(b(u[0]),b(u[1]),b(u[2])));w&&h.push(c(s.color));A&&(s=s.vertexColors,h.push(c(s[0]),c(s[1]),c(s[2])))}e.data={};e.data.vertices=f;e.data.normals=k;0<n.length&&(e.data.colors=n);0<m.length&&
 (e.data.uvs=[m]);e.data.faces=h;return e},clone:function(){for(var a=new THREE.Geometry,b=this.vertices,c=0,d=b.length;c<d;c++)a.vertices.push(b[c].clone());b=this.faces;c=0;for(d=b.length;c<d;c++)a.faces.push(b[c].clone());c=0;for(d=this.faceVertexUvs.length;c<d;c++){b=this.faceVertexUvs[c];void 0===a.faceVertexUvs[c]&&(a.faceVertexUvs[c]=[]);for(var e=0,f=b.length;e<f;e++){for(var g=b[e],h=[],k=0,l=g.length;k<l;k++)h.push(g[k].clone());a.faceVertexUvs[c].push(h)}}return a},dispose:function(){this.dispatchEvent({type:"dispose"})}};
 (e.data.uvs=[m]);e.data.faces=h;return e},clone:function(){for(var a=new THREE.Geometry,b=this.vertices,c=0,d=b.length;c<d;c++)a.vertices.push(b[c].clone());b=this.faces;c=0;for(d=b.length;c<d;c++)a.faces.push(b[c].clone());c=0;for(d=this.faceVertexUvs.length;c<d;c++){b=this.faceVertexUvs[c];void 0===a.faceVertexUvs[c]&&(a.faceVertexUvs[c]=[]);for(var e=0,f=b.length;e<f;e++){for(var g=b[e],h=[],k=0,l=g.length;k<l;k++)h.push(g[k].clone());a.faceVertexUvs[c].push(h)}}return a},dispose:function(){this.dispatchEvent({type:"dispose"})}};
 THREE.EventDispatcher.prototype.apply(THREE.Geometry.prototype);THREE.GeometryIdCount=0;
 THREE.EventDispatcher.prototype.apply(THREE.Geometry.prototype);THREE.GeometryIdCount=0;
 THREE.DirectGeometry=function(){Object.defineProperty(this,"id",{value:THREE.GeometryIdCount++});this.uuid=THREE.Math.generateUUID();this.name="";this.type="DirectGeometry";this.indices=[];this.vertices=[];this.colors=[];this.normals=[];this.colors=[];this.uvs=[];this.uvs2=[];this.morphTargets=[];this.morphColors=[];this.morphNormals=[];this.skinWeights=[];this.skinIndices=[];this.boundingSphere=this.boundingBox=null;this.uvsNeedUpdate=this.colorsNeedUpdate=this.normalsNeedUpdate=this.verticesNeedUpdate=
 THREE.DirectGeometry=function(){Object.defineProperty(this,"id",{value:THREE.GeometryIdCount++});this.uuid=THREE.Math.generateUUID();this.name="";this.type="DirectGeometry";this.indices=[];this.vertices=[];this.colors=[];this.normals=[];this.colors=[];this.uvs=[];this.uvs2=[];this.morphTargets=[];this.morphColors=[];this.morphNormals=[];this.skinWeights=[];this.skinIndices=[];this.boundingSphere=this.boundingBox=null;this.uvsNeedUpdate=this.colorsNeedUpdate=this.normalsNeedUpdate=this.verticesNeedUpdate=
 !1};
 !1};
-THREE.DirectGeometry.prototype={constructor:THREE.DirectGeometry,computeBoundingBox:THREE.Geometry.prototype.computeBoundingBox,computeBoundingSphere:THREE.Geometry.prototype.computeBoundingSphere,computeFaceNormals:function(){console.warn("THREE.DirectGeometry: computeFaceNormals() is not a method of this type of geometry.");return this},computeVertexNormals:function(){console.warn("THREE.DirectGeometry: computeVertexNormals() is not a method of this type of geometry.");return this},fromGeometry:function(a,b){b=
-b||{vertexColors:THREE.NoColors};for(var c=a.faces,d=a.vertices,e=a.faceVertexUvs,f=b.vertexColors,g=e[0]&&0<e[0].length,h=e[1]&&0<e[1].length,k=a.morphTargets,l=k.length,n=0;n<l;n++)this.morphTargets[n]=[];for(var p=a.morphNormals.length,n=0;n<p;n++)this.morphNormals[n]=[];p=a.morphColors.length;for(n=0;n<p;n++)this.morphColors[n]=[];for(var p=a.skinIndices,m=a.skinWeights,q=p.length===d.length,t=m.length===d.length,n=0;n<c.length;n++){var s=c[n];this.vertices.push(d[s.a],d[s.b],d[s.c]);var u=s.vertexNormals;
-3===u.length?this.normals.push(u[0],u[1],u[2]):(u=s.normal,this.normals.push(u,u,u));u=s.vertexColors;f===THREE.VertexColors?this.colors.push(u[0],u[1],u[2]):f===THREE.FaceColors&&(u=s.color,this.colors.push(u,u,u));!0===g&&(u=e[0][n],void 0!==u?this.uvs.push(u[0],u[1],u[2]):(console.warn("THREE.BufferGeometry.fromGeometry(): Undefined vertexUv",n),this.uvs.push(new THREE.Vector2,new THREE.Vector2,new THREE.Vector2)));!0===h&&(u=e[1][n],void 0!==u?this.uvs2.push(u[0],u[1],u[2]):(console.warn("THREE.BufferGeometry.fromGeometry(): Undefined vertexUv2",
-n),this.uvs2.push(new THREE.Vector2,new THREE.Vector2,new THREE.Vector2)));for(u=0;u<l;u++){var w=k[u].vertices;this.morphTargets[u].push(w[s.a],w[s.b],w[s.c])}q&&this.skinIndices.push(p[s.a],p[s.b],p[s.c]);t&&this.skinWeights.push(m[s.a],m[s.b],m[s.c])}this.verticesNeedUpdate=a.verticesNeedUpdate;this.normalsNeedUpdate=a.normalsNeedUpdate;this.colorsNeedUpdate=a.colorsNeedUpdate;this.uvsNeedUpdate=a.uvsNeedUpdate;return this},dispose:function(){this.dispatchEvent({type:"dispose"})}};THREE.EventDispatcher.prototype.apply(THREE.DirectGeometry.prototype);
+THREE.DirectGeometry.prototype={constructor:THREE.DirectGeometry,computeBoundingBox:THREE.Geometry.prototype.computeBoundingBox,computeBoundingSphere:THREE.Geometry.prototype.computeBoundingSphere,computeFaceNormals:function(){console.warn("THREE.DirectGeometry: computeFaceNormals() is not a method of this type of geometry.");return this},computeVertexNormals:function(){console.warn("THREE.DirectGeometry: computeVertexNormals() is not a method of this type of geometry.");return this},fromGeometry:function(a){for(var b=a.faces,
+c=a.vertices,d=a.faceVertexUvs,e=d[0]&&0<d[0].length,f=d[1]&&0<d[1].length,g=a.morphTargets,h=g.length,k=0;k<h;k++)this.morphTargets[k]=[];for(var l=a.morphNormals.length,k=0;k<l;k++)this.morphNormals[k]=[];l=a.morphColors.length;for(k=0;k<l;k++)this.morphColors[k]=[];for(var l=a.skinIndices,n=a.skinWeights,p=l.length===c.length,m=n.length===c.length,k=0;k<b.length;k++){var q=b[k];this.vertices.push(c[q.a],c[q.b],c[q.c]);var s=q.vertexNormals;3===s.length?this.normals.push(s[0],s[1],s[2]):(s=q.normal,
+this.normals.push(s,s,s));s=q.vertexColors;3===s.length?this.colors.push(s[0],s[1],s[2]):(s=q.color,this.colors.push(s,s,s));!0===e&&(s=d[0][k],void 0!==s?this.uvs.push(s[0],s[1],s[2]):(console.warn("THREE.BufferGeometry.fromGeometry(): Undefined vertexUv",k),this.uvs.push(new THREE.Vector2,new THREE.Vector2,new THREE.Vector2)));!0===f&&(s=d[1][k],void 0!==s?this.uvs2.push(s[0],s[1],s[2]):(console.warn("THREE.BufferGeometry.fromGeometry(): Undefined vertexUv2",k),this.uvs2.push(new THREE.Vector2,
+new THREE.Vector2,new THREE.Vector2)));for(s=0;s<h;s++){var t=g[s].vertices;this.morphTargets[s].push(t[q.a],t[q.b],t[q.c])}p&&this.skinIndices.push(l[q.a],l[q.b],l[q.c]);m&&this.skinWeights.push(n[q.a],n[q.b],n[q.c])}this.verticesNeedUpdate=a.verticesNeedUpdate;this.normalsNeedUpdate=a.normalsNeedUpdate;this.colorsNeedUpdate=a.colorsNeedUpdate;this.uvsNeedUpdate=a.uvsNeedUpdate;return this},dispose:function(){this.dispatchEvent({type:"dispose"})}};THREE.EventDispatcher.prototype.apply(THREE.DirectGeometry.prototype);
 THREE.BufferGeometry=function(){Object.defineProperty(this,"id",{value:THREE.GeometryIdCount++});this.uuid=THREE.Math.generateUUID();this.name="";this.type="BufferGeometry";this.attributes={};this.morphAttributes=[];this.offsets=this.drawcalls=[];this.boundingSphere=this.boundingBox=null};
 THREE.BufferGeometry=function(){Object.defineProperty(this,"id",{value:THREE.GeometryIdCount++});this.uuid=THREE.Math.generateUUID();this.name="";this.type="BufferGeometry";this.attributes={};this.morphAttributes=[];this.offsets=this.drawcalls=[];this.boundingSphere=this.boundingBox=null};
 THREE.BufferGeometry.prototype={constructor:THREE.BufferGeometry,addAttribute:function(a,b,c){!1===b instanceof THREE.BufferAttribute&&!1===b instanceof THREE.InterleavedBufferAttribute?(console.warn("THREE.BufferGeometry: .addAttribute() now expects ( name, attribute )."),this.attributes[a]={array:b,itemSize:c}):this.attributes[a]=b},getAttribute:function(a){return this.attributes[a]},addDrawCall:function(a,b,c){this.drawcalls.push({start:a,count:b,index:void 0!==c?c:0})},applyMatrix:function(a){var b=
 THREE.BufferGeometry.prototype={constructor:THREE.BufferGeometry,addAttribute:function(a,b,c){!1===b instanceof THREE.BufferAttribute&&!1===b instanceof THREE.InterleavedBufferAttribute?(console.warn("THREE.BufferGeometry: .addAttribute() now expects ( name, attribute )."),this.attributes[a]={array:b,itemSize:c}):this.attributes[a]=b},getAttribute:function(a){return this.attributes[a]},addDrawCall:function(a,b,c){this.drawcalls.push({start:a,count:b,index:void 0!==c?c:0})},applyMatrix:function(a){var b=
 this.attributes.position;void 0!==b&&(a.applyToVector3Array(b.array),b.needsUpdate=!0);b=this.attributes.normal;void 0!==b&&((new THREE.Matrix3).getNormalMatrix(a).applyToVector3Array(b.array),b.needsUpdate=!0);null!==this.boundingBox&&this.computeBoundingBox();null!==this.boundingSphere&&this.computeBoundingSphere()},copy:function(a){var b=a.attributes;a=a.offsets;for(var c in b)this.addAttribute(c,b[c].clone());b=0;for(c=a.length;b<c;b++){var d=a[b];this.offsets.push({start:d.start,index:d.index,
 this.attributes.position;void 0!==b&&(a.applyToVector3Array(b.array),b.needsUpdate=!0);b=this.attributes.normal;void 0!==b&&((new THREE.Matrix3).getNormalMatrix(a).applyToVector3Array(b.array),b.needsUpdate=!0);null!==this.boundingBox&&this.computeBoundingBox();null!==this.boundingSphere&&this.computeBoundingSphere()},copy:function(a){var b=a.attributes;a=a.offsets;for(var c in b)this.addAttribute(c,b[c].clone());b=0;for(c=a.length;b<c;b++){var d=a[b];this.offsets.push({start:d.start,index:d.index,
 count:d.count})}return this},center:function(){this.computeBoundingBox();var a=this.boundingBox.center().negate();this.applyMatrix((new THREE.Matrix4).setPosition(a));return a},setFromObject:function(a){console.log("THREE.BufferGeometry.setFromObject(). Converting",a,this);var b=a.geometry;if(a instanceof THREE.PointCloud||a instanceof THREE.Line){a=new THREE.Float32Attribute(3*b.vertices.length,3);var c=new THREE.Float32Attribute(3*b.colors.length,3);this.addAttribute("position",a.copyVector3sArray(b.vertices));
 count:d.count})}return this},center:function(){this.computeBoundingBox();var a=this.boundingBox.center().negate();this.applyMatrix((new THREE.Matrix4).setPosition(a));return a},setFromObject:function(a){console.log("THREE.BufferGeometry.setFromObject(). Converting",a,this);var b=a.geometry;if(a instanceof THREE.PointCloud||a instanceof THREE.Line){a=new THREE.Float32Attribute(3*b.vertices.length,3);var c=new THREE.Float32Attribute(3*b.colors.length,3);this.addAttribute("position",a.copyVector3sArray(b.vertices));
 this.addAttribute("color",c.copyColorsArray(b.colors));null!==b.boundingSphere&&(this.boundingSphere=b.boundingSphere.clone());null!==b.boundingBox&&(this.boundingBox=b.boundingBox.clone())}else a instanceof THREE.Mesh&&b instanceof THREE.Geometry&&this.fromGeometry(b);return this},updateFromObject:function(a){var b=a.geometry;a instanceof THREE.Mesh&&(a=b.__directGeometry,a.verticesNeedUpdate=b.verticesNeedUpdate,a.normalsNeedUpdate=b.normalsNeedUpdate,a.colorsNeedUpdate=b.colorsNeedUpdate,a.uvsNeedUpdate=
 this.addAttribute("color",c.copyColorsArray(b.colors));null!==b.boundingSphere&&(this.boundingSphere=b.boundingSphere.clone());null!==b.boundingBox&&(this.boundingBox=b.boundingBox.clone())}else a instanceof THREE.Mesh&&b instanceof THREE.Geometry&&this.fromGeometry(b);return this},updateFromObject:function(a){var b=a.geometry;a instanceof THREE.Mesh&&(a=b.__directGeometry,a.verticesNeedUpdate=b.verticesNeedUpdate,a.normalsNeedUpdate=b.normalsNeedUpdate,a.colorsNeedUpdate=b.colorsNeedUpdate,a.uvsNeedUpdate=
 b.uvsNeedUpdate,b.verticesNeedUpdate=!1,b.normalsNeedUpdate=!1,b.colorsNeedUpdate=!1,b.uvsNeedUpdate=!1,b=a);!0===b.verticesNeedUpdate&&(a=this.attributes.position,void 0!==a&&(a.copyVector3sArray(b.vertices),a.needsUpdate=!0),b.verticesNeedUpdate=!1);!0===b.normalsNeedUpdate&&(a=this.attributes.normal,void 0!==a&&(a.copyVector3sArray(b.normals),a.needsUpdate=!0),b.normalsNeedUpdate=!1);!0===b.colorsNeedUpdate&&(a=this.attributes.color,void 0!==a&&(a.copyColorsArray(b.colors),a.needsUpdate=!0),b.colorsNeedUpdate=
 b.uvsNeedUpdate,b.verticesNeedUpdate=!1,b.normalsNeedUpdate=!1,b.colorsNeedUpdate=!1,b.uvsNeedUpdate=!1,b=a);!0===b.verticesNeedUpdate&&(a=this.attributes.position,void 0!==a&&(a.copyVector3sArray(b.vertices),a.needsUpdate=!0),b.verticesNeedUpdate=!1);!0===b.normalsNeedUpdate&&(a=this.attributes.normal,void 0!==a&&(a.copyVector3sArray(b.normals),a.needsUpdate=!0),b.normalsNeedUpdate=!1);!0===b.colorsNeedUpdate&&(a=this.attributes.color,void 0!==a&&(a.copyColorsArray(b.colors),a.needsUpdate=!0),b.colorsNeedUpdate=
-!1);return this},fromGeometry:function(a,b){a.__directGeometry=(new THREE.DirectGeometry).fromGeometry(a,b);return this.fromDirectGeometry(a.__directGeometry)},fromDirectGeometry:function(a){if(0<a.indices.length){var b=new Uint16Array(3*a.indices.length);this.addAttribute("index",(new THREE.BufferAttribute(b,1)).copyIndicesArray(a.indices))}0<a.vertices.length&&(b=new Float32Array(3*a.vertices.length),this.addAttribute("position",(new THREE.BufferAttribute(b,3)).copyVector3sArray(a.vertices)));0<
-a.normals.length&&(b=new Float32Array(3*a.normals.length),this.addAttribute("normal",(new THREE.BufferAttribute(b,3)).copyVector3sArray(a.normals)));0<a.colors.length&&(b=new Float32Array(3*a.colors.length),this.addAttribute("color",(new THREE.BufferAttribute(b,3)).copyColorsArray(a.colors)));0<a.uvs.length&&(b=new Float32Array(2*a.uvs.length),this.addAttribute("uv",(new THREE.BufferAttribute(b,2)).copyVector2sArray(a.uvs)));if(0<a.morphTargets.length)for(var b=a.morphTargets,c=0,d=b.length;c<d;c++){var e=
-b[c],f=new THREE.Float32Attribute(3*e.length,3);this.morphAttributes.push(f.copyVector3sArray(e))}0<a.skinIndices.length&&(b=new THREE.Float32Attribute(4*a.skinIndices.length,4),this.addAttribute("skinIndex",b.copyVector4sArray(a.skinIndices)));0<a.skinWeights.length&&(b=new THREE.Float32Attribute(4*a.skinWeights.length,4),this.addAttribute("skinWeight",b.copyVector4sArray(a.skinWeights)));null!==a.boundingSphere&&(this.boundingSphere=a.boundingSphere.clone());null!==a.boundingBox&&(this.boundingBox=
-a.boundingBox.clone());return this},computeBoundingBox:function(){var a=new THREE.Vector3;return function(){null===this.boundingBox&&(this.boundingBox=new THREE.Box3);var b=this.attributes.position.array;if(b){var c=this.boundingBox;c.makeEmpty();for(var d=0,e=b.length;d<e;d+=3)a.fromArray(b,d),c.expandByPoint(a)}if(void 0===b||0===b.length)this.boundingBox.min.set(0,0,0),this.boundingBox.max.set(0,0,0);(isNaN(this.boundingBox.min.x)||isNaN(this.boundingBox.min.y)||isNaN(this.boundingBox.min.z))&&
-console.error('THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.',this)}}(),computeBoundingSphere:function(){var a=new THREE.Box3,b=new THREE.Vector3;return function(){null===this.boundingSphere&&(this.boundingSphere=new THREE.Sphere);var c=this.attributes.position.array;if(c){a.makeEmpty();for(var d=this.boundingSphere.center,e=0,f=c.length;e<f;e+=3)b.fromArray(c,e),a.expandByPoint(b);a.center(d);for(var g=0,e=0,f=c.length;e<
-f;e+=3)b.fromArray(c,e),g=Math.max(g,d.distanceToSquared(b));this.boundingSphere.radius=Math.sqrt(g);isNaN(this.boundingSphere.radius)&&console.error('THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.',this)}}}(),computeFaceNormals:function(){},computeVertexNormals:function(){var a=this.attributes;if(a.position){var b=a.position.array;if(void 0===a.normal)this.addAttribute("normal",new THREE.BufferAttribute(new Float32Array(b.length),
-3));else for(var c=a.normal.array,d=0,e=c.length;d<e;d++)c[d]=0;var c=a.normal.array,f,g,h,k=new THREE.Vector3,l=new THREE.Vector3,n=new THREE.Vector3,p=new THREE.Vector3,m=new THREE.Vector3;if(a.index)for(var q=a.index.array,t=0<this.offsets.length?this.offsets:[{start:0,count:q.length,index:0}],s=0,u=t.length;s<u;++s){e=t[s].start;f=t[s].count;for(var w=t[s].index,d=e,e=e+f;d<e;d+=3)f=3*(w+q[d]),g=3*(w+q[d+1]),h=3*(w+q[d+2]),k.fromArray(b,f),l.fromArray(b,g),n.fromArray(b,h),p.subVectors(n,l),m.subVectors(k,
-l),p.cross(m),c[f]+=p.x,c[f+1]+=p.y,c[f+2]+=p.z,c[g]+=p.x,c[g+1]+=p.y,c[g+2]+=p.z,c[h]+=p.x,c[h+1]+=p.y,c[h+2]+=p.z}else for(d=0,e=b.length;d<e;d+=9)k.fromArray(b,d),l.fromArray(b,d+3),n.fromArray(b,d+6),p.subVectors(n,l),m.subVectors(k,l),p.cross(m),c[d]=p.x,c[d+1]=p.y,c[d+2]=p.z,c[d+3]=p.x,c[d+4]=p.y,c[d+5]=p.z,c[d+6]=p.x,c[d+7]=p.y,c[d+8]=p.z;this.normalizeNormals();a.normal.needsUpdate=!0}},computeTangents:function(){function a(a,b,c){p.fromArray(d,3*a);m.fromArray(d,3*b);q.fromArray(d,3*c);t.fromArray(f,
-2*a);s.fromArray(f,2*b);u.fromArray(f,2*c);w=m.x-p.x;x=q.x-p.x;A=m.y-p.y;y=q.y-p.y;D=m.z-p.z;I=q.z-p.z;v=s.x-t.x;E=u.x-t.x;L=s.y-t.y;C=u.y-t.y;F=1/(v*C-E*L);R.set((C*w-L*x)*F,(C*A-L*y)*F,(C*D-L*I)*F);J.set((v*x-E*w)*F,(v*y-E*A)*F,(v*I-E*D)*F);k[a].add(R);k[b].add(R);k[c].add(R);l[a].add(J);l[b].add(J);l[c].add(J)}function b(a){na.fromArray(e,3*a);da.copy(na);ja=k[a];H.copy(ja);H.sub(na.multiplyScalar(na.dot(ja))).normalize();K.crossVectors(da,ja);ua=K.dot(l[a]);ka=0>ua?-1:1;h[4*a]=H.x;h[4*a+1]=H.y;
-h[4*a+2]=H.z;h[4*a+3]=ka}if(void 0===this.attributes.index||void 0===this.attributes.position||void 0===this.attributes.normal||void 0===this.attributes.uv)console.warn("THREE.BufferGeometry: Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()");else{var c=this.attributes.index.array,d=this.attributes.position.array,e=this.attributes.normal.array,f=this.attributes.uv.array,g=d.length/3;void 0===this.attributes.tangent&&this.addAttribute("tangent",new THREE.BufferAttribute(new Float32Array(4*
-g),4));for(var h=this.attributes.tangent.array,k=[],l=[],n=0;n<g;n++)k[n]=new THREE.Vector3,l[n]=new THREE.Vector3;var p=new THREE.Vector3,m=new THREE.Vector3,q=new THREE.Vector3,t=new THREE.Vector2,s=new THREE.Vector2,u=new THREE.Vector2,w,x,A,y,D,I,v,E,L,C,F,R=new THREE.Vector3,J=new THREE.Vector3,z,G,B,T,O;0===this.drawcalls.length&&this.addDrawCall(0,c.length,0);var S=this.drawcalls,n=0;for(G=S.length;n<G;++n){z=S[n].start;B=S[n].count;var P=S[n].index,g=z;for(z+=B;g<z;g+=3)B=P+c[g],T=P+c[g+1],
-O=P+c[g+2],a(B,T,O)}var H=new THREE.Vector3,K=new THREE.Vector3,na=new THREE.Vector3,da=new THREE.Vector3,ka,ja,ua,n=0;for(G=S.length;n<G;++n)for(z=S[n].start,B=S[n].count,P=S[n].index,g=z,z+=B;g<z;g+=3)B=P+c[g],T=P+c[g+1],O=P+c[g+2],b(B),b(T),b(O)}},computeOffsets:function(a){void 0===a&&(a=THREE.BufferGeometry.MaxIndex);for(var b=this.attributes.index.array,c=this.attributes.position.array,d=b.length/3,e=new (65535<c.length/3&&65535<THREE.BufferGeometry.MaxIndex?Uint32Array:Uint16Array)(b.length),
-f=0,g=0,h=[{start:0,count:0,index:0}],k=h[0],l=0,n=0,p=new Int32Array(6),m=new Int32Array(c.length),q=new Int32Array(c.length),t=0;t<c.length;t++)m[t]=-1,q[t]=-1;for(c=0;c<d;c++){for(var s=n=0;3>s;s++)t=b[3*c+s],-1===m[t]?(p[2*s]=t,p[2*s+1]=-1,n++):m[t]<k.index?(p[2*s]=t,p[2*s+1]=-1,l++):(p[2*s]=t,p[2*s+1]=m[t]);if(g+n>k.index+a)for(k={start:f,count:0,index:g},h.push(k),n=0;6>n;n+=2)s=p[n+1],-1<s&&s<k.index&&(p[n+1]=-1);for(n=0;6>n;n+=2)t=p[n],s=p[n+1],-1===s&&(s=g++),m[t]=s,q[s]=t,e[f++]=s-k.index,
-k.count++}this.reorderBuffers(e,q,g);return this.drawcalls=this.offsets=h},merge:function(a,b){if(!1===a instanceof THREE.BufferGeometry)console.error("THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.",a);else{void 0===b&&(b=0);var c=this.attributes,d;for(d in c)if(void 0!==a.attributes[d])for(var e=c[d].array,f=a.attributes[d],g=f.array,h=0,f=f.itemSize*b;h<g.length;h++,f++)e[f]=g[h];return this}},normalizeNormals:function(){for(var a=this.attributes.normal.array,b,
-c,d,e=0,f=a.length;e<f;e+=3)b=a[e],c=a[e+1],d=a[e+2],b=1/Math.sqrt(b*b+c*c+d*d),a[e]*=b,a[e+1]*=b,a[e+2]*=b},reorderBuffers:function(a,b,c){var d={},e;for(e in this.attributes)"index"!==e&&(d[e]=new this.attributes[e].array.constructor(this.attributes[e].itemSize*c));for(var f=0;f<c;f++){var g=b[f];for(e in this.attributes)if("index"!==e)for(var h=this.attributes[e].array,k=this.attributes[e].itemSize,l=d[e],n=0;n<k;n++)l[f*k+n]=h[g*k+n]}this.attributes.index.array=a;for(e in this.attributes)"index"!==
-e&&(this.attributes[e].array=d[e],this.attributes[e].numItems=this.attributes[e].itemSize*c)},toJSON:function(){var a={metadata:{version:4.4,type:"BufferGeometry",generator:"BufferGeometry.toJSON"}};a.uuid=this.uuid;a.type=this.type;""!==this.name&&(a.name=this.name);if(void 0!==this.parameters){var b=this.parameters,c;for(c in b)void 0!==b[c]&&(a[c]=b[c]);return a}a.data={attributes:{}};var b=this.attributes,d=this.offsets,e=this.boundingSphere;for(c in b){var f=b[c],g=Array.prototype.slice.call(f.array);
-a.data.attributes[c]={itemSize:f.itemSize,type:f.array.constructor.name,array:g}}0<d.length&&(a.data.offsets=JSON.parse(JSON.stringify(d)));null!==e&&(a.data.boundingSphere={center:e.center.toArray(),radius:e.radius});return a},clone:function(){var a=new THREE.BufferGeometry,b;for(b in this.attributes)a.addAttribute(b,this.attributes[b].clone());b=0;for(var c=this.offsets.length;b<c;b++){var d=this.offsets[b];a.offsets.push({start:d.start,index:d.index,count:d.count})}return a},dispose:function(){this.dispatchEvent({type:"dispose"})}};
-THREE.EventDispatcher.prototype.apply(THREE.BufferGeometry.prototype);THREE.BufferGeometry.MaxIndex=65535;THREE.InstancedBufferGeometry=function(){THREE.BufferGeometry.call(this);this.type="InstancedBufferGeometry";this.maxInstancedCount=void 0};THREE.InstancedBufferGeometry.prototype=Object.create(THREE.BufferGeometry.prototype);THREE.InstancedBufferGeometry.prototype.constructor=THREE.InstancedBufferGeometry;
-THREE.InstancedBufferGeometry.prototype.addDrawCall=function(a,b,c,d){this.drawcalls.push({start:a,count:b,index:void 0!==c?c:0,instances:d})};THREE.InstancedBufferGeometry.prototype.clone=function(){var a=new THREE.InstancedBufferGeometry,b;for(b in this.attributes)a.addAttribute(b,this.attributes[b].clone());b=0;for(var c=this.offsets.length;b<c;b++){var d=this.offsets[b];a.offsets.push({start:d.start,index:d.index,count:d.count,instances:d.instances})}return a};THREE.EventDispatcher.prototype.apply(THREE.InstancedBufferGeometry.prototype);
+!1);return this},fromGeometry:function(a){a.__directGeometry=(new THREE.DirectGeometry).fromGeometry(a);return this.fromDirectGeometry(a.__directGeometry)},fromDirectGeometry:function(a){if(0<a.indices.length){var b=new Uint16Array(3*a.indices.length);this.addAttribute("index",(new THREE.BufferAttribute(b,1)).copyIndicesArray(a.indices))}0<a.vertices.length&&(b=new Float32Array(3*a.vertices.length),this.addAttribute("position",(new THREE.BufferAttribute(b,3)).copyVector3sArray(a.vertices)));0<a.normals.length&&
+(b=new Float32Array(3*a.normals.length),this.addAttribute("normal",(new THREE.BufferAttribute(b,3)).copyVector3sArray(a.normals)));0<a.colors.length&&(b=new Float32Array(3*a.colors.length),this.addAttribute("color",(new THREE.BufferAttribute(b,3)).copyColorsArray(a.colors)));0<a.uvs.length&&(b=new Float32Array(2*a.uvs.length),this.addAttribute("uv",(new THREE.BufferAttribute(b,2)).copyVector2sArray(a.uvs)));if(0<a.morphTargets.length)for(var b=a.morphTargets,c=0,d=b.length;c<d;c++){var e=b[c],f=new THREE.Float32Attribute(3*
+e.length,3);this.morphAttributes.push(f.copyVector3sArray(e))}0<a.skinIndices.length&&(b=new THREE.Float32Attribute(4*a.skinIndices.length,4),this.addAttribute("skinIndex",b.copyVector4sArray(a.skinIndices)));0<a.skinWeights.length&&(b=new THREE.Float32Attribute(4*a.skinWeights.length,4),this.addAttribute("skinWeight",b.copyVector4sArray(a.skinWeights)));null!==a.boundingSphere&&(this.boundingSphere=a.boundingSphere.clone());null!==a.boundingBox&&(this.boundingBox=a.boundingBox.clone());return this},
+computeBoundingBox:function(){var a=new THREE.Vector3;return function(){null===this.boundingBox&&(this.boundingBox=new THREE.Box3);var b=this.attributes.position.array;if(b){var c=this.boundingBox;c.makeEmpty();for(var d=0,e=b.length;d<e;d+=3)a.fromArray(b,d),c.expandByPoint(a)}if(void 0===b||0===b.length)this.boundingBox.min.set(0,0,0),this.boundingBox.max.set(0,0,0);(isNaN(this.boundingBox.min.x)||isNaN(this.boundingBox.min.y)||isNaN(this.boundingBox.min.z))&&console.error('THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.',
+this)}}(),computeBoundingSphere:function(){var a=new THREE.Box3,b=new THREE.Vector3;return function(){null===this.boundingSphere&&(this.boundingSphere=new THREE.Sphere);var c=this.attributes.position.array;if(c){a.makeEmpty();for(var d=this.boundingSphere.center,e=0,f=c.length;e<f;e+=3)b.fromArray(c,e),a.expandByPoint(b);a.center(d);for(var g=0,e=0,f=c.length;e<f;e+=3)b.fromArray(c,e),g=Math.max(g,d.distanceToSquared(b));this.boundingSphere.radius=Math.sqrt(g);isNaN(this.boundingSphere.radius)&&console.error('THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.',
+this)}}}(),computeFaceNormals:function(){},computeVertexNormals:function(){var a=this.attributes;if(a.position){var b=a.position.array;if(void 0===a.normal)this.addAttribute("normal",new THREE.BufferAttribute(new Float32Array(b.length),3));else for(var c=a.normal.array,d=0,e=c.length;d<e;d++)c[d]=0;var c=a.normal.array,f,g,h,k=new THREE.Vector3,l=new THREE.Vector3,n=new THREE.Vector3,p=new THREE.Vector3,m=new THREE.Vector3;if(a.index)for(var q=a.index.array,s=0<this.offsets.length?this.offsets:[{start:0,
+count:q.length,index:0}],t=0,u=s.length;t<u;++t){e=s[t].start;f=s[t].count;for(var x=s[t].index,d=e,e=e+f;d<e;d+=3)f=3*(x+q[d]),g=3*(x+q[d+1]),h=3*(x+q[d+2]),k.fromArray(b,f),l.fromArray(b,g),n.fromArray(b,h),p.subVectors(n,l),m.subVectors(k,l),p.cross(m),c[f]+=p.x,c[f+1]+=p.y,c[f+2]+=p.z,c[g]+=p.x,c[g+1]+=p.y,c[g+2]+=p.z,c[h]+=p.x,c[h+1]+=p.y,c[h+2]+=p.z}else for(d=0,e=b.length;d<e;d+=9)k.fromArray(b,d),l.fromArray(b,d+3),n.fromArray(b,d+6),p.subVectors(n,l),m.subVectors(k,l),p.cross(m),c[d]=p.x,
+c[d+1]=p.y,c[d+2]=p.z,c[d+3]=p.x,c[d+4]=p.y,c[d+5]=p.z,c[d+6]=p.x,c[d+7]=p.y,c[d+8]=p.z;this.normalizeNormals();a.normal.needsUpdate=!0}},computeTangents:function(){function a(a,b,c){p.fromArray(d,3*a);m.fromArray(d,3*b);q.fromArray(d,3*c);s.fromArray(f,2*a);t.fromArray(f,2*b);u.fromArray(f,2*c);x=m.x-p.x;w=q.x-p.x;A=m.y-p.y;y=q.y-p.y;G=m.z-p.z;I=q.z-p.z;v=t.x-s.x;D=u.x-s.x;L=t.y-s.y;C=u.y-s.y;E=1/(v*C-D*L);R.set((C*x-L*w)*E,(C*A-L*y)*E,(C*G-L*I)*E);J.set((v*w-D*x)*E,(v*y-D*A)*E,(v*I-D*G)*E);k[a].add(R);
+k[b].add(R);k[c].add(R);l[a].add(J);l[b].add(J);l[c].add(J)}function b(a){na.fromArray(e,3*a);da.copy(na);ja=k[a];H.copy(ja);H.sub(na.multiplyScalar(na.dot(ja))).normalize();K.crossVectors(da,ja);ua=K.dot(l[a]);ka=0>ua?-1:1;h[4*a]=H.x;h[4*a+1]=H.y;h[4*a+2]=H.z;h[4*a+3]=ka}if(void 0===this.attributes.index||void 0===this.attributes.position||void 0===this.attributes.normal||void 0===this.attributes.uv)console.warn("THREE.BufferGeometry: Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()");
+else{var c=this.attributes.index.array,d=this.attributes.position.array,e=this.attributes.normal.array,f=this.attributes.uv.array,g=d.length/3;void 0===this.attributes.tangent&&this.addAttribute("tangent",new THREE.BufferAttribute(new Float32Array(4*g),4));for(var h=this.attributes.tangent.array,k=[],l=[],n=0;n<g;n++)k[n]=new THREE.Vector3,l[n]=new THREE.Vector3;var p=new THREE.Vector3,m=new THREE.Vector3,q=new THREE.Vector3,s=new THREE.Vector2,t=new THREE.Vector2,u=new THREE.Vector2,x,w,A,y,G,I,
+v,D,L,C,E,R=new THREE.Vector3,J=new THREE.Vector3,z,F,B,T,O;0===this.drawcalls.length&&this.addDrawCall(0,c.length,0);var S=this.drawcalls,n=0;for(F=S.length;n<F;++n){z=S[n].start;B=S[n].count;var P=S[n].index,g=z;for(z+=B;g<z;g+=3)B=P+c[g],T=P+c[g+1],O=P+c[g+2],a(B,T,O)}var H=new THREE.Vector3,K=new THREE.Vector3,na=new THREE.Vector3,da=new THREE.Vector3,ka,ja,ua,n=0;for(F=S.length;n<F;++n)for(z=S[n].start,B=S[n].count,P=S[n].index,g=z,z+=B;g<z;g+=3)B=P+c[g],T=P+c[g+1],O=P+c[g+2],b(B),b(T),b(O)}},
+computeOffsets:function(a){void 0===a&&(a=THREE.BufferGeometry.MaxIndex);for(var b=this.attributes.index.array,c=this.attributes.position.array,d=b.length/3,e=new (65535<c.length/3&&65535<THREE.BufferGeometry.MaxIndex?Uint32Array:Uint16Array)(b.length),f=0,g=0,h=[{start:0,count:0,index:0}],k=h[0],l=0,n=0,p=new Int32Array(6),m=new Int32Array(c.length),q=new Int32Array(c.length),s=0;s<c.length;s++)m[s]=-1,q[s]=-1;for(c=0;c<d;c++){for(var t=n=0;3>t;t++)s=b[3*c+t],-1===m[s]?(p[2*t]=s,p[2*t+1]=-1,n++):
+m[s]<k.index?(p[2*t]=s,p[2*t+1]=-1,l++):(p[2*t]=s,p[2*t+1]=m[s]);if(g+n>k.index+a)for(k={start:f,count:0,index:g},h.push(k),n=0;6>n;n+=2)t=p[n+1],-1<t&&t<k.index&&(p[n+1]=-1);for(n=0;6>n;n+=2)s=p[n],t=p[n+1],-1===t&&(t=g++),m[s]=t,q[t]=s,e[f++]=t-k.index,k.count++}this.reorderBuffers(e,q,g);return this.drawcalls=this.offsets=h},merge:function(a,b){if(!1===a instanceof THREE.BufferGeometry)console.error("THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.",a);else{void 0===
+b&&(b=0);var c=this.attributes,d;for(d in c)if(void 0!==a.attributes[d])for(var e=c[d].array,f=a.attributes[d],g=f.array,h=0,f=f.itemSize*b;h<g.length;h++,f++)e[f]=g[h];return this}},normalizeNormals:function(){for(var a=this.attributes.normal.array,b,c,d,e=0,f=a.length;e<f;e+=3)b=a[e],c=a[e+1],d=a[e+2],b=1/Math.sqrt(b*b+c*c+d*d),a[e]*=b,a[e+1]*=b,a[e+2]*=b},reorderBuffers:function(a,b,c){var d={},e;for(e in this.attributes)"index"!==e&&(d[e]=new this.attributes[e].array.constructor(this.attributes[e].itemSize*
+c));for(var f=0;f<c;f++){var g=b[f];for(e in this.attributes)if("index"!==e)for(var h=this.attributes[e].array,k=this.attributes[e].itemSize,l=d[e],n=0;n<k;n++)l[f*k+n]=h[g*k+n]}this.attributes.index.array=a;for(e in this.attributes)"index"!==e&&(this.attributes[e].array=d[e],this.attributes[e].numItems=this.attributes[e].itemSize*c)},toJSON:function(){var a={metadata:{version:4.4,type:"BufferGeometry",generator:"BufferGeometry.toJSON"}};a.uuid=this.uuid;a.type=this.type;""!==this.name&&(a.name=this.name);
+if(void 0!==this.parameters){var b=this.parameters,c;for(c in b)void 0!==b[c]&&(a[c]=b[c]);return a}a.data={attributes:{}};var b=this.attributes,d=this.offsets,e=this.boundingSphere;for(c in b){var f=b[c],g=Array.prototype.slice.call(f.array);a.data.attributes[c]={itemSize:f.itemSize,type:f.array.constructor.name,array:g}}0<d.length&&(a.data.offsets=JSON.parse(JSON.stringify(d)));null!==e&&(a.data.boundingSphere={center:e.center.toArray(),radius:e.radius});return a},clone:function(){var a=new THREE.BufferGeometry,
+b;for(b in this.attributes)a.addAttribute(b,this.attributes[b].clone());b=0;for(var c=this.offsets.length;b<c;b++){var d=this.offsets[b];a.offsets.push({start:d.start,index:d.index,count:d.count})}return a},dispose:function(){this.dispatchEvent({type:"dispose"})}};THREE.EventDispatcher.prototype.apply(THREE.BufferGeometry.prototype);THREE.BufferGeometry.MaxIndex=65535;
+THREE.InstancedBufferGeometry=function(){THREE.BufferGeometry.call(this);this.type="InstancedBufferGeometry";this.maxInstancedCount=void 0};THREE.InstancedBufferGeometry.prototype=Object.create(THREE.BufferGeometry.prototype);THREE.InstancedBufferGeometry.prototype.constructor=THREE.InstancedBufferGeometry;THREE.InstancedBufferGeometry.prototype.addDrawCall=function(a,b,c,d){this.drawcalls.push({start:a,count:b,index:void 0!==c?c:0,instances:d})};
+THREE.InstancedBufferGeometry.prototype.clone=function(){var a=new THREE.InstancedBufferGeometry,b;for(b in this.attributes)a.addAttribute(b,this.attributes[b].clone());b=0;for(var c=this.offsets.length;b<c;b++){var d=this.offsets[b];a.offsets.push({start:d.start,index:d.index,count:d.count,instances:d.instances})}return a};THREE.EventDispatcher.prototype.apply(THREE.InstancedBufferGeometry.prototype);
 THREE.Camera=function(){THREE.Object3D.call(this);this.type="Camera";this.matrixWorldInverse=new THREE.Matrix4;this.projectionMatrix=new THREE.Matrix4};THREE.Camera.prototype=Object.create(THREE.Object3D.prototype);THREE.Camera.prototype.constructor=THREE.Camera;THREE.Camera.prototype.getWorldDirection=function(){var a=new THREE.Quaternion;return function(b){b=b||new THREE.Vector3;this.getWorldQuaternion(a);return b.set(0,0,-1).applyQuaternion(a)}}();
 THREE.Camera=function(){THREE.Object3D.call(this);this.type="Camera";this.matrixWorldInverse=new THREE.Matrix4;this.projectionMatrix=new THREE.Matrix4};THREE.Camera.prototype=Object.create(THREE.Object3D.prototype);THREE.Camera.prototype.constructor=THREE.Camera;THREE.Camera.prototype.getWorldDirection=function(){var a=new THREE.Quaternion;return function(b){b=b||new THREE.Vector3;this.getWorldQuaternion(a);return b.set(0,0,-1).applyQuaternion(a)}}();
 THREE.Camera.prototype.lookAt=function(){var a=new THREE.Matrix4;return function(b){a.lookAt(this.position,b,this.up);this.quaternion.setFromRotationMatrix(a)}}();THREE.Camera.prototype.clone=function(a){void 0===a&&(a=new THREE.Camera);THREE.Object3D.prototype.clone.call(this,a);a.matrixWorldInverse.copy(this.matrixWorldInverse);a.projectionMatrix.copy(this.projectionMatrix);return a};
 THREE.Camera.prototype.lookAt=function(){var a=new THREE.Matrix4;return function(b){a.lookAt(this.position,b,this.up);this.quaternion.setFromRotationMatrix(a)}}();THREE.Camera.prototype.clone=function(a){void 0===a&&(a=new THREE.Camera);THREE.Object3D.prototype.clone.call(this,a);a.matrixWorldInverse.copy(this.matrixWorldInverse);a.projectionMatrix.copy(this.projectionMatrix);return a};
 THREE.CubeCamera=function(a,b,c){THREE.Object3D.call(this);this.type="CubeCamera";var d=new THREE.PerspectiveCamera(90,1,a,b);d.up.set(0,-1,0);d.lookAt(new THREE.Vector3(1,0,0));this.add(d);var e=new THREE.PerspectiveCamera(90,1,a,b);e.up.set(0,-1,0);e.lookAt(new THREE.Vector3(-1,0,0));this.add(e);var f=new THREE.PerspectiveCamera(90,1,a,b);f.up.set(0,0,1);f.lookAt(new THREE.Vector3(0,1,0));this.add(f);var g=new THREE.PerspectiveCamera(90,1,a,b);g.up.set(0,0,-1);g.lookAt(new THREE.Vector3(0,-1,0));
 THREE.CubeCamera=function(a,b,c){THREE.Object3D.call(this);this.type="CubeCamera";var d=new THREE.PerspectiveCamera(90,1,a,b);d.up.set(0,-1,0);d.lookAt(new THREE.Vector3(1,0,0));this.add(d);var e=new THREE.PerspectiveCamera(90,1,a,b);e.up.set(0,-1,0);e.lookAt(new THREE.Vector3(-1,0,0));this.add(e);var f=new THREE.PerspectiveCamera(90,1,a,b);f.up.set(0,0,1);f.lookAt(new THREE.Vector3(0,1,0));this.add(f);var g=new THREE.PerspectiveCamera(90,1,a,b);g.up.set(0,0,-1);g.lookAt(new THREE.Vector3(0,-1,0));
@@ -273,23 +273,23 @@ a.shadowDarkness=this.shadowDarkness;a.shadowMapWidth=this.shadowMapWidth;a.shad
 THREE.Cache={files:{},add:function(a,b){this.files[a]=b},get:function(a){return this.files[a]},remove:function(a){delete this.files[a]},clear:function(){this.files={}}};THREE.Loader=function(a){this.statusDomElement=(this.showStatus=a)?THREE.Loader.prototype.addStatusElement():null;this.imageLoader=new THREE.ImageLoader;this.onLoadStart=function(){};this.onLoadProgress=function(){};this.onLoadComplete=function(){}};
 THREE.Cache={files:{},add:function(a,b){this.files[a]=b},get:function(a){return this.files[a]},remove:function(a){delete this.files[a]},clear:function(){this.files={}}};THREE.Loader=function(a){this.statusDomElement=(this.showStatus=a)?THREE.Loader.prototype.addStatusElement():null;this.imageLoader=new THREE.ImageLoader;this.onLoadStart=function(){};this.onLoadProgress=function(){};this.onLoadComplete=function(){}};
 THREE.Loader.prototype={constructor:THREE.Loader,crossOrigin:void 0,addStatusElement:function(){var a=document.createElement("div");a.style.position="absolute";a.style.right="0px";a.style.top="0px";a.style.fontSize="0.8em";a.style.textAlign="left";a.style.background="rgba(0,0,0,0.25)";a.style.color="#fff";a.style.width="120px";a.style.padding="0.5em 0.5em 0.5em 0.5em";a.style.zIndex=1E3;a.innerHTML="Loading ...";return a},updateProgress:function(a){var b="Loaded ",b=a.total?b+((100*a.loaded/a.total).toFixed(0)+
 THREE.Loader.prototype={constructor:THREE.Loader,crossOrigin:void 0,addStatusElement:function(){var a=document.createElement("div");a.style.position="absolute";a.style.right="0px";a.style.top="0px";a.style.fontSize="0.8em";a.style.textAlign="left";a.style.background="rgba(0,0,0,0.25)";a.style.color="#fff";a.style.width="120px";a.style.padding="0.5em 0.5em 0.5em 0.5em";a.style.zIndex=1E3;a.innerHTML="Loading ...";return a},updateProgress:function(a){var b="Loaded ",b=a.total?b+((100*a.loaded/a.total).toFixed(0)+
 "%"):b+((a.loaded/1024).toFixed(2)+" KB");this.statusDomElement.innerHTML=b},extractUrlBase:function(a){a=a.split("/");if(1===a.length)return"./";a.pop();return a.join("/")+"/"},initMaterials:function(a,b){for(var c=[],d=0;d<a.length;++d)c[d]=this.createMaterial(a[d],b);return c},needsTangents:function(a){for(var b=0,c=a.length;b<c;b++)if(a[b]instanceof THREE.ShaderMaterial)return!0;return!1},createMaterial:function(a,b){function c(a){a=Math.log(a)/Math.LN2;return Math.pow(2,Math.round(a))}function d(a,
 "%"):b+((a.loaded/1024).toFixed(2)+" KB");this.statusDomElement.innerHTML=b},extractUrlBase:function(a){a=a.split("/");if(1===a.length)return"./";a.pop();return a.join("/")+"/"},initMaterials:function(a,b){for(var c=[],d=0;d<a.length;++d)c[d]=this.createMaterial(a[d],b);return c},needsTangents:function(a){for(var b=0,c=a.length;b<c;b++)if(a[b]instanceof THREE.ShaderMaterial)return!0;return!1},createMaterial:function(a,b){function c(a){a=Math.log(a)/Math.LN2;return Math.pow(2,Math.round(a))}function d(a,
-d,e,g,h,k,s){var u=b+e,w,x=THREE.Loader.Handlers.get(u);null!==x?w=x.load(u):(w=new THREE.Texture,x=f.imageLoader,x.crossOrigin=f.crossOrigin,x.load(u,function(a){if(!1===THREE.Math.isPowerOfTwo(a.width)||!1===THREE.Math.isPowerOfTwo(a.height)){var b=c(a.width),d=c(a.height),e=document.createElement("canvas");e.width=b;e.height=d;e.getContext("2d").drawImage(a,0,0,b,d);w.image=e}else w.image=a;w.needsUpdate=!0}));w.sourceFile=e;g&&(w.repeat.set(g[0],g[1]),1!==g[0]&&(w.wrapS=THREE.RepeatWrapping),
-1!==g[1]&&(w.wrapT=THREE.RepeatWrapping));h&&w.offset.set(h[0],h[1]);k&&(e={repeat:THREE.RepeatWrapping,mirror:THREE.MirroredRepeatWrapping},void 0!==e[k[0]]&&(w.wrapS=e[k[0]]),void 0!==e[k[1]]&&(w.wrapT=e[k[1]]));s&&(w.anisotropy=s);a[d]=w}function e(a){return(255*a[0]<<16)+(255*a[1]<<8)+255*a[2]}var f=this,g="MeshLambertMaterial",h={color:15658734,opacity:1,map:null,lightMap:null,normalMap:null,bumpMap:null,wireframe:!1};if(a.shading){var k=a.shading.toLowerCase();"phong"===k?g="MeshPhongMaterial":
+d,e,g,h,k,t){var u=b+e,x,w=THREE.Loader.Handlers.get(u);null!==w?x=w.load(u):(x=new THREE.Texture,w=f.imageLoader,w.crossOrigin=f.crossOrigin,w.load(u,function(a){if(!1===THREE.Math.isPowerOfTwo(a.width)||!1===THREE.Math.isPowerOfTwo(a.height)){var b=c(a.width),d=c(a.height),e=document.createElement("canvas");e.width=b;e.height=d;e.getContext("2d").drawImage(a,0,0,b,d);x.image=e}else x.image=a;x.needsUpdate=!0}));x.sourceFile=e;g&&(x.repeat.set(g[0],g[1]),1!==g[0]&&(x.wrapS=THREE.RepeatWrapping),
+1!==g[1]&&(x.wrapT=THREE.RepeatWrapping));h&&x.offset.set(h[0],h[1]);k&&(e={repeat:THREE.RepeatWrapping,mirror:THREE.MirroredRepeatWrapping},void 0!==e[k[0]]&&(x.wrapS=e[k[0]]),void 0!==e[k[1]]&&(x.wrapT=e[k[1]]));t&&(x.anisotropy=t);a[d]=x}function e(a){return(255*a[0]<<16)+(255*a[1]<<8)+255*a[2]}var f=this,g="MeshLambertMaterial",h={color:15658734,opacity:1,map:null,lightMap:null,normalMap:null,bumpMap:null,wireframe:!1};if(a.shading){var k=a.shading.toLowerCase();"phong"===k?g="MeshPhongMaterial":
 "basic"===k&&(g="MeshBasicMaterial")}void 0!==a.blending&&void 0!==THREE[a.blending]&&(h.blending=THREE[a.blending]);void 0!==a.transparent&&(h.transparent=a.transparent);void 0!==a.opacity&&1>a.opacity&&(h.transparent=!0);void 0!==a.depthTest&&(h.depthTest=a.depthTest);void 0!==a.depthWrite&&(h.depthWrite=a.depthWrite);void 0!==a.visible&&(h.visible=a.visible);void 0!==a.flipSided&&(h.side=THREE.BackSide);void 0!==a.doubleSided&&(h.side=THREE.DoubleSide);void 0!==a.wireframe&&(h.wireframe=a.wireframe);
 "basic"===k&&(g="MeshBasicMaterial")}void 0!==a.blending&&void 0!==THREE[a.blending]&&(h.blending=THREE[a.blending]);void 0!==a.transparent&&(h.transparent=a.transparent);void 0!==a.opacity&&1>a.opacity&&(h.transparent=!0);void 0!==a.depthTest&&(h.depthTest=a.depthTest);void 0!==a.depthWrite&&(h.depthWrite=a.depthWrite);void 0!==a.visible&&(h.visible=a.visible);void 0!==a.flipSided&&(h.side=THREE.BackSide);void 0!==a.doubleSided&&(h.side=THREE.DoubleSide);void 0!==a.wireframe&&(h.wireframe=a.wireframe);
 void 0!==a.vertexColors&&("face"===a.vertexColors?h.vertexColors=THREE.FaceColors:a.vertexColors&&(h.vertexColors=THREE.VertexColors));a.colorDiffuse?h.color=e(a.colorDiffuse):a.DbgColor&&(h.color=a.DbgColor);a.colorSpecular&&(h.specular=e(a.colorSpecular));a.colorEmissive&&(h.emissive=e(a.colorEmissive));void 0!==a.transparency&&(console.warn("THREE.Loader: transparency has been renamed to opacity"),a.opacity=a.transparency);void 0!==a.opacity&&(h.opacity=a.opacity);a.specularCoef&&(h.shininess=
 void 0!==a.vertexColors&&("face"===a.vertexColors?h.vertexColors=THREE.FaceColors:a.vertexColors&&(h.vertexColors=THREE.VertexColors));a.colorDiffuse?h.color=e(a.colorDiffuse):a.DbgColor&&(h.color=a.DbgColor);a.colorSpecular&&(h.specular=e(a.colorSpecular));a.colorEmissive&&(h.emissive=e(a.colorEmissive));void 0!==a.transparency&&(console.warn("THREE.Loader: transparency has been renamed to opacity"),a.opacity=a.transparency);void 0!==a.opacity&&(h.opacity=a.opacity);a.specularCoef&&(h.shininess=
 a.specularCoef);a.mapDiffuse&&b&&d(h,"map",a.mapDiffuse,a.mapDiffuseRepeat,a.mapDiffuseOffset,a.mapDiffuseWrap,a.mapDiffuseAnisotropy);a.mapLight&&b&&d(h,"lightMap",a.mapLight,a.mapLightRepeat,a.mapLightOffset,a.mapLightWrap,a.mapLightAnisotropy);a.mapAO&&b&&d(h,"aoMap",a.mapAO,a.mapAORepeat,a.mapAOOffset,a.mapAOWrap,a.mapAOAnisotropy);a.mapBump&&b&&d(h,"bumpMap",a.mapBump,a.mapBumpRepeat,a.mapBumpOffset,a.mapBumpWrap,a.mapBumpAnisotropy);a.mapNormal&&b&&d(h,"normalMap",a.mapNormal,a.mapNormalRepeat,
 a.specularCoef);a.mapDiffuse&&b&&d(h,"map",a.mapDiffuse,a.mapDiffuseRepeat,a.mapDiffuseOffset,a.mapDiffuseWrap,a.mapDiffuseAnisotropy);a.mapLight&&b&&d(h,"lightMap",a.mapLight,a.mapLightRepeat,a.mapLightOffset,a.mapLightWrap,a.mapLightAnisotropy);a.mapAO&&b&&d(h,"aoMap",a.mapAO,a.mapAORepeat,a.mapAOOffset,a.mapAOWrap,a.mapAOAnisotropy);a.mapBump&&b&&d(h,"bumpMap",a.mapBump,a.mapBumpRepeat,a.mapBumpOffset,a.mapBumpWrap,a.mapBumpAnisotropy);a.mapNormal&&b&&d(h,"normalMap",a.mapNormal,a.mapNormalRepeat,
 a.mapNormalOffset,a.mapNormalWrap,a.mapNormalAnisotropy);a.mapSpecular&&b&&d(h,"specularMap",a.mapSpecular,a.mapSpecularRepeat,a.mapSpecularOffset,a.mapSpecularWrap,a.mapSpecularAnisotropy);a.mapAlpha&&b&&d(h,"alphaMap",a.mapAlpha,a.mapAlphaRepeat,a.mapAlphaOffset,a.mapAlphaWrap,a.mapAlphaAnisotropy);a.mapBumpScale&&(h.bumpScale=a.mapBumpScale);a.mapNormalFactor&&(h.normalScale=new THREE.Vector2(a.mapNormalFactor,a.mapNormalFactor));g=new THREE[g](h);void 0!==a.DbgName&&(g.name=a.DbgName);return g}};
 a.mapNormalOffset,a.mapNormalWrap,a.mapNormalAnisotropy);a.mapSpecular&&b&&d(h,"specularMap",a.mapSpecular,a.mapSpecularRepeat,a.mapSpecularOffset,a.mapSpecularWrap,a.mapSpecularAnisotropy);a.mapAlpha&&b&&d(h,"alphaMap",a.mapAlpha,a.mapAlphaRepeat,a.mapAlphaOffset,a.mapAlphaWrap,a.mapAlphaAnisotropy);a.mapBumpScale&&(h.bumpScale=a.mapBumpScale);a.mapNormalFactor&&(h.normalScale=new THREE.Vector2(a.mapNormalFactor,a.mapNormalFactor));g=new THREE[g](h);void 0!==a.DbgName&&(g.name=a.DbgName);return g}};
 THREE.Loader.Handlers={handlers:[],add:function(a,b){this.handlers.push(a,b)},get:function(a){for(var b=0,c=this.handlers.length;b<c;b+=2){var d=this.handlers[b+1];if(this.handlers[b].test(a))return d}return null}};THREE.XHRLoader=function(a){this.manager=void 0!==a?a:THREE.DefaultLoadingManager};
 THREE.Loader.Handlers={handlers:[],add:function(a,b){this.handlers.push(a,b)},get:function(a){for(var b=0,c=this.handlers.length;b<c;b+=2){var d=this.handlers[b+1];if(this.handlers[b].test(a))return d}return null}};THREE.XHRLoader=function(a){this.manager=void 0!==a?a:THREE.DefaultLoadingManager};
 THREE.XHRLoader.prototype={constructor:THREE.XHRLoader,load:function(a,b,c,d){var e=this,f=THREE.Cache.get(a);if(void 0!==f)return b&&b(f),f;f=new XMLHttpRequest;f.open("GET",a,!0);f.addEventListener("load",function(c){THREE.Cache.add(a,this.response);b&&b(this.response);e.manager.itemEnd(a)},!1);void 0!==c&&f.addEventListener("progress",function(a){c(a)},!1);void 0!==d&&f.addEventListener("error",function(a){d(a)},!1);void 0!==this.crossOrigin&&(f.crossOrigin=this.crossOrigin);void 0!==this.responseType&&
 THREE.XHRLoader.prototype={constructor:THREE.XHRLoader,load:function(a,b,c,d){var e=this,f=THREE.Cache.get(a);if(void 0!==f)return b&&b(f),f;f=new XMLHttpRequest;f.open("GET",a,!0);f.addEventListener("load",function(c){THREE.Cache.add(a,this.response);b&&b(this.response);e.manager.itemEnd(a)},!1);void 0!==c&&f.addEventListener("progress",function(a){c(a)},!1);void 0!==d&&f.addEventListener("error",function(a){d(a)},!1);void 0!==this.crossOrigin&&(f.crossOrigin=this.crossOrigin);void 0!==this.responseType&&
-(f.responseType=this.responseType);f.send(null);e.manager.itemStart(a)},setResponseType:function(a){this.responseType=a},setCrossOrigin:function(a){this.crossOrigin=a}};THREE.ImageLoader=function(a){this.manager=void 0!==a?a:THREE.DefaultLoadingManager};
+(f.responseType=this.responseType);f.send(null);e.manager.itemStart(a);return f},setResponseType:function(a){this.responseType=a},setCrossOrigin:function(a){this.crossOrigin=a}};THREE.ImageLoader=function(a){this.manager=void 0!==a?a:THREE.DefaultLoadingManager};
 THREE.ImageLoader.prototype={constructor:THREE.ImageLoader,load:function(a,b,c,d){var e=this,f=THREE.Cache.get(a);if(void 0!==f)return b&&b(f),f;f=document.createElement("img");f.addEventListener("load",function(c){THREE.Cache.add(a,this);b&&b(this);e.manager.itemEnd(a)},!1);void 0!==c&&f.addEventListener("progress",function(a){c(a)},!1);void 0!==d&&f.addEventListener("error",function(a){d(a)},!1);void 0!==this.crossOrigin&&(f.crossOrigin=this.crossOrigin);e.manager.itemStart(a);f.src=a;return f},
 THREE.ImageLoader.prototype={constructor:THREE.ImageLoader,load:function(a,b,c,d){var e=this,f=THREE.Cache.get(a);if(void 0!==f)return b&&b(f),f;f=document.createElement("img");f.addEventListener("load",function(c){THREE.Cache.add(a,this);b&&b(this);e.manager.itemEnd(a)},!1);void 0!==c&&f.addEventListener("progress",function(a){c(a)},!1);void 0!==d&&f.addEventListener("error",function(a){d(a)},!1);void 0!==this.crossOrigin&&(f.crossOrigin=this.crossOrigin);e.manager.itemStart(a);f.src=a;return f},
 setCrossOrigin:function(a){this.crossOrigin=a}};THREE.JSONLoader=function(a){THREE.Loader.call(this,a);this.withCredentials=!1};THREE.JSONLoader.prototype=Object.create(THREE.Loader.prototype);THREE.JSONLoader.prototype.constructor=THREE.JSONLoader;THREE.JSONLoader.prototype.load=function(a,b,c){c=c&&"string"===typeof c?c:this.extractUrlBase(a);this.onLoadStart();this.loadAjaxJSON(this,a,b,c)};
 setCrossOrigin:function(a){this.crossOrigin=a}};THREE.JSONLoader=function(a){THREE.Loader.call(this,a);this.withCredentials=!1};THREE.JSONLoader.prototype=Object.create(THREE.Loader.prototype);THREE.JSONLoader.prototype.constructor=THREE.JSONLoader;THREE.JSONLoader.prototype.load=function(a,b,c){c=c&&"string"===typeof c?c:this.extractUrlBase(a);this.onLoadStart();this.loadAjaxJSON(this,a,b,c)};
 THREE.JSONLoader.prototype.loadAjaxJSON=function(a,b,c,d,e){var f=new XMLHttpRequest,g=0;f.onreadystatechange=function(){if(f.readyState===f.DONE)if(200===f.status||0===f.status){if(f.responseText){var h=JSON.parse(f.responseText),k=h.metadata;if(void 0!==k){if("object"===k.type){console.error("THREE.JSONLoader: "+b+" should be loaded with THREE.ObjectLoader instead.");return}if("scene"===k.type){console.error("THREE.JSONLoader: "+b+" seems to be a Scene. Use THREE.SceneLoader instead.");return}}h=
 THREE.JSONLoader.prototype.loadAjaxJSON=function(a,b,c,d,e){var f=new XMLHttpRequest,g=0;f.onreadystatechange=function(){if(f.readyState===f.DONE)if(200===f.status||0===f.status){if(f.responseText){var h=JSON.parse(f.responseText),k=h.metadata;if(void 0!==k){if("object"===k.type){console.error("THREE.JSONLoader: "+b+" should be loaded with THREE.ObjectLoader instead.");return}if("scene"===k.type){console.error("THREE.JSONLoader: "+b+" seems to be a Scene. Use THREE.SceneLoader instead.");return}}h=
 a.parse(h,d);c(h.geometry,h.materials)}else console.error("THREE.JSONLoader: "+b+" seems to be unreachable or the file is empty.");a.onLoadComplete()}else console.error("THREE.JSONLoader: Couldn't load "+b+" ("+f.status+")");else f.readyState===f.LOADING?e&&(0===g&&(g=f.getResponseHeader("Content-Length")),e({total:g,loaded:f.responseText.length})):f.readyState===f.HEADERS_RECEIVED&&void 0!==e&&(g=f.getResponseHeader("Content-Length"))};f.open("GET",b,!0);f.withCredentials=this.withCredentials;f.send(null)};
 a.parse(h,d);c(h.geometry,h.materials)}else console.error("THREE.JSONLoader: "+b+" seems to be unreachable or the file is empty.");a.onLoadComplete()}else console.error("THREE.JSONLoader: Couldn't load "+b+" ("+f.status+")");else f.readyState===f.LOADING?e&&(0===g&&(g=f.getResponseHeader("Content-Length")),e({total:g,loaded:f.responseText.length})):f.readyState===f.HEADERS_RECEIVED&&void 0!==e&&(g=f.getResponseHeader("Content-Length"))};f.open("GET",b,!0);f.withCredentials=this.withCredentials;f.send(null)};
-THREE.JSONLoader.prototype.parse=function(a,b){var c=new THREE.Geometry,d=void 0!==a.scale?1/a.scale:1;(function(b){var d,g,h,k,l,n,p,m,q,t,s,u,w,x=a.faces;n=a.vertices;var A=a.normals,y=a.colors,D=0;if(void 0!==a.uvs){for(d=0;d<a.uvs.length;d++)a.uvs[d].length&&D++;for(d=0;d<D;d++)c.faceVertexUvs[d]=[]}k=0;for(l=n.length;k<l;)d=new THREE.Vector3,d.x=n[k++]*b,d.y=n[k++]*b,d.z=n[k++]*b,c.vertices.push(d);k=0;for(l=x.length;k<l;)if(b=x[k++],q=b&1,h=b&2,d=b&8,p=b&16,t=b&32,n=b&64,b&=128,q){q=new THREE.Face3;
-q.a=x[k];q.b=x[k+1];q.c=x[k+3];s=new THREE.Face3;s.a=x[k+1];s.b=x[k+2];s.c=x[k+3];k+=4;h&&k++;h=c.faces.length;if(d)for(d=0;d<D;d++)for(u=a.uvs[d],c.faceVertexUvs[d][h]=[],c.faceVertexUvs[d][h+1]=[],g=0;4>g;g++)m=x[k++],w=u[2*m],m=u[2*m+1],w=new THREE.Vector2(w,m),2!==g&&c.faceVertexUvs[d][h].push(w),0!==g&&c.faceVertexUvs[d][h+1].push(w);p&&(p=3*x[k++],q.normal.set(A[p++],A[p++],A[p]),s.normal.copy(q.normal));if(t)for(d=0;4>d;d++)p=3*x[k++],t=new THREE.Vector3(A[p++],A[p++],A[p]),2!==d&&q.vertexNormals.push(t),
-0!==d&&s.vertexNormals.push(t);n&&(n=x[k++],n=y[n],q.color.setHex(n),s.color.setHex(n));if(b)for(d=0;4>d;d++)n=x[k++],n=y[n],2!==d&&q.vertexColors.push(new THREE.Color(n)),0!==d&&s.vertexColors.push(new THREE.Color(n));c.faces.push(q);c.faces.push(s)}else{q=new THREE.Face3;q.a=x[k++];q.b=x[k++];q.c=x[k++];h&&k++;h=c.faces.length;if(d)for(d=0;d<D;d++)for(u=a.uvs[d],c.faceVertexUvs[d][h]=[],g=0;3>g;g++)m=x[k++],w=u[2*m],m=u[2*m+1],w=new THREE.Vector2(w,m),c.faceVertexUvs[d][h].push(w);p&&(p=3*x[k++],
-q.normal.set(A[p++],A[p++],A[p]));if(t)for(d=0;3>d;d++)p=3*x[k++],t=new THREE.Vector3(A[p++],A[p++],A[p]),q.vertexNormals.push(t);n&&(n=x[k++],q.color.setHex(y[n]));if(b)for(d=0;3>d;d++)n=x[k++],q.vertexColors.push(new THREE.Color(y[n]));c.faces.push(q)}})(d);(function(){var b=void 0!==a.influencesPerVertex?a.influencesPerVertex:2;if(a.skinWeights)for(var d=0,g=a.skinWeights.length;d<g;d+=b)c.skinWeights.push(new THREE.Vector4(a.skinWeights[d],1<b?a.skinWeights[d+1]:0,2<b?a.skinWeights[d+2]:0,3<b?
+THREE.JSONLoader.prototype.parse=function(a,b){var c=new THREE.Geometry,d=void 0!==a.scale?1/a.scale:1;(function(b){var d,g,h,k,l,n,p,m,q,s,t,u,x,w=a.faces;n=a.vertices;var A=a.normals,y=a.colors,G=0;if(void 0!==a.uvs){for(d=0;d<a.uvs.length;d++)a.uvs[d].length&&G++;for(d=0;d<G;d++)c.faceVertexUvs[d]=[]}k=0;for(l=n.length;k<l;)d=new THREE.Vector3,d.x=n[k++]*b,d.y=n[k++]*b,d.z=n[k++]*b,c.vertices.push(d);k=0;for(l=w.length;k<l;)if(b=w[k++],q=b&1,h=b&2,d=b&8,p=b&16,s=b&32,n=b&64,b&=128,q){q=new THREE.Face3;
+q.a=w[k];q.b=w[k+1];q.c=w[k+3];t=new THREE.Face3;t.a=w[k+1];t.b=w[k+2];t.c=w[k+3];k+=4;h&&k++;h=c.faces.length;if(d)for(d=0;d<G;d++)for(u=a.uvs[d],c.faceVertexUvs[d][h]=[],c.faceVertexUvs[d][h+1]=[],g=0;4>g;g++)m=w[k++],x=u[2*m],m=u[2*m+1],x=new THREE.Vector2(x,m),2!==g&&c.faceVertexUvs[d][h].push(x),0!==g&&c.faceVertexUvs[d][h+1].push(x);p&&(p=3*w[k++],q.normal.set(A[p++],A[p++],A[p]),t.normal.copy(q.normal));if(s)for(d=0;4>d;d++)p=3*w[k++],s=new THREE.Vector3(A[p++],A[p++],A[p]),2!==d&&q.vertexNormals.push(s),
+0!==d&&t.vertexNormals.push(s);n&&(n=w[k++],n=y[n],q.color.setHex(n),t.color.setHex(n));if(b)for(d=0;4>d;d++)n=w[k++],n=y[n],2!==d&&q.vertexColors.push(new THREE.Color(n)),0!==d&&t.vertexColors.push(new THREE.Color(n));c.faces.push(q);c.faces.push(t)}else{q=new THREE.Face3;q.a=w[k++];q.b=w[k++];q.c=w[k++];h&&k++;h=c.faces.length;if(d)for(d=0;d<G;d++)for(u=a.uvs[d],c.faceVertexUvs[d][h]=[],g=0;3>g;g++)m=w[k++],x=u[2*m],m=u[2*m+1],x=new THREE.Vector2(x,m),c.faceVertexUvs[d][h].push(x);p&&(p=3*w[k++],
+q.normal.set(A[p++],A[p++],A[p]));if(s)for(d=0;3>d;d++)p=3*w[k++],s=new THREE.Vector3(A[p++],A[p++],A[p]),q.vertexNormals.push(s);n&&(n=w[k++],q.color.setHex(y[n]));if(b)for(d=0;3>d;d++)n=w[k++],q.vertexColors.push(new THREE.Color(y[n]));c.faces.push(q)}})(d);(function(){var b=void 0!==a.influencesPerVertex?a.influencesPerVertex:2;if(a.skinWeights)for(var d=0,g=a.skinWeights.length;d<g;d+=b)c.skinWeights.push(new THREE.Vector4(a.skinWeights[d],1<b?a.skinWeights[d+1]:0,2<b?a.skinWeights[d+2]:0,3<b?
 a.skinWeights[d+3]:0));if(a.skinIndices)for(d=0,g=a.skinIndices.length;d<g;d+=b)c.skinIndices.push(new THREE.Vector4(a.skinIndices[d],1<b?a.skinIndices[d+1]:0,2<b?a.skinIndices[d+2]:0,3<b?a.skinIndices[d+3]:0));c.bones=a.bones;c.bones&&0<c.bones.length&&(c.skinWeights.length!==c.skinIndices.length||c.skinIndices.length!==c.vertices.length)&&console.warn("THREE.JSONLoader: When skinning, number of vertices ("+c.vertices.length+"), skinIndices ("+c.skinIndices.length+"), and skinWeights ("+c.skinWeights.length+
 a.skinWeights[d+3]:0));if(a.skinIndices)for(d=0,g=a.skinIndices.length;d<g;d+=b)c.skinIndices.push(new THREE.Vector4(a.skinIndices[d],1<b?a.skinIndices[d+1]:0,2<b?a.skinIndices[d+2]:0,3<b?a.skinIndices[d+3]:0));c.bones=a.bones;c.bones&&0<c.bones.length&&(c.skinWeights.length!==c.skinIndices.length||c.skinIndices.length!==c.vertices.length)&&console.warn("THREE.JSONLoader: When skinning, number of vertices ("+c.vertices.length+"), skinIndices ("+c.skinIndices.length+"), and skinWeights ("+c.skinWeights.length+
 ") should match.");c.animation=a.animation;c.animations=a.animations})();(function(b){if(void 0!==a.morphTargets){var d,g,h,k,l,n;d=0;for(g=a.morphTargets.length;d<g;d++)for(c.morphTargets[d]={},c.morphTargets[d].name=a.morphTargets[d].name,c.morphTargets[d].vertices=[],l=c.morphTargets[d].vertices,n=a.morphTargets[d].vertices,h=0,k=n.length;h<k;h+=3){var p=new THREE.Vector3;p.x=n[h]*b;p.y=n[h+1]*b;p.z=n[h+2]*b;l.push(p)}}if(void 0!==a.morphColors)for(d=0,g=a.morphColors.length;d<g;d++)for(c.morphColors[d]=
 ") should match.");c.animation=a.animation;c.animations=a.animations})();(function(b){if(void 0!==a.morphTargets){var d,g,h,k,l,n;d=0;for(g=a.morphTargets.length;d<g;d++)for(c.morphTargets[d]={},c.morphTargets[d].name=a.morphTargets[d].name,c.morphTargets[d].vertices=[],l=c.morphTargets[d].vertices,n=a.morphTargets[d].vertices,h=0,k=n.length;h<k;h+=3){var p=new THREE.Vector3;p.x=n[h]*b;p.y=n[h+1]*b;p.z=n[h+2]*b;l.push(p)}}if(void 0!==a.morphColors)for(d=0,g=a.morphColors.length;d<g;d++)for(c.morphColors[d]=
 {},c.morphColors[d].name=a.morphColors[d].name,c.morphColors[d].colors=[],k=c.morphColors[d].colors,l=a.morphColors[d].colors,b=0,h=l.length;b<h;b+=3)n=new THREE.Color(16755200),n.setRGB(l[b],l[b+1],l[b+2]),k.push(n)})(d);c.computeFaceNormals();c.computeBoundingSphere();if(void 0===a.materials||0===a.materials.length)return{geometry:c};d=this.initMaterials(a.materials,b);this.needsTangents(d)&&c.computeTangents();return{geometry:c,materials:d}};
 {},c.morphColors[d].name=a.morphColors[d].name,c.morphColors[d].colors=[],k=c.morphColors[d].colors,l=a.morphColors[d].colors,b=0,h=l.length;b<h;b+=3)n=new THREE.Color(16755200),n.setRGB(l[b],l[b+1],l[b+2]),k.push(n)})(d);c.computeFaceNormals();c.computeBoundingSphere();if(void 0===a.materials||0===a.materials.length)return{geometry:c};d=this.initMaterials(a.materials,b);this.needsTangents(d)&&c.computeTangents();return{geometry:c,materials:d}};
@@ -356,20 +356,20 @@ THREE.Texture=function(a,b,c,d,e,f,g,h,k){Object.defineProperty(this,"id",{value
 this.anisotropy=void 0!==k?k:1;this.format=void 0!==g?g:THREE.RGBAFormat;this.type=void 0!==h?h:THREE.UnsignedByteType;this.offset=new THREE.Vector2(0,0);this.repeat=new THREE.Vector2(1,1);this.generateMipmaps=!0;this.premultiplyAlpha=!1;this.flipY=!0;this.unpackAlignment=4;this._needsUpdate=!1;this.onUpdate=null};THREE.Texture.DEFAULT_IMAGE=void 0;THREE.Texture.DEFAULT_MAPPING=THREE.UVMapping;
 this.anisotropy=void 0!==k?k:1;this.format=void 0!==g?g:THREE.RGBAFormat;this.type=void 0!==h?h:THREE.UnsignedByteType;this.offset=new THREE.Vector2(0,0);this.repeat=new THREE.Vector2(1,1);this.generateMipmaps=!0;this.premultiplyAlpha=!1;this.flipY=!0;this.unpackAlignment=4;this._needsUpdate=!1;this.onUpdate=null};THREE.Texture.DEFAULT_IMAGE=void 0;THREE.Texture.DEFAULT_MAPPING=THREE.UVMapping;
 THREE.Texture.prototype={constructor:THREE.Texture,get needsUpdate(){return this._needsUpdate},set needsUpdate(a){!0===a&&this.update();this._needsUpdate=a},clone:function(a){void 0===a&&(a=new THREE.Texture);a.image=this.image;a.mipmaps=this.mipmaps.slice(0);a.mapping=this.mapping;a.wrapS=this.wrapS;a.wrapT=this.wrapT;a.magFilter=this.magFilter;a.minFilter=this.minFilter;a.anisotropy=this.anisotropy;a.format=this.format;a.type=this.type;a.offset.copy(this.offset);a.repeat.copy(this.repeat);a.generateMipmaps=
 THREE.Texture.prototype={constructor:THREE.Texture,get needsUpdate(){return this._needsUpdate},set needsUpdate(a){!0===a&&this.update();this._needsUpdate=a},clone:function(a){void 0===a&&(a=new THREE.Texture);a.image=this.image;a.mipmaps=this.mipmaps.slice(0);a.mapping=this.mapping;a.wrapS=this.wrapS;a.wrapT=this.wrapT;a.magFilter=this.magFilter;a.minFilter=this.minFilter;a.anisotropy=this.anisotropy;a.format=this.format;a.type=this.type;a.offset.copy(this.offset);a.repeat.copy(this.repeat);a.generateMipmaps=
 this.generateMipmaps;a.premultiplyAlpha=this.premultiplyAlpha;a.flipY=this.flipY;a.unpackAlignment=this.unpackAlignment;return a},toJSON:function(a){if(void 0!==a.textures[this.uuid])return a.textures[this.uuid];var b={metadata:{version:4.4,type:"Texture",generator:"Texture.toJSON"},uuid:this.uuid,name:this.name,mapping:this.mapping,repeat:[this.repeat.x,this.repeat.y],offset:[this.offset.x,this.offset.y],wrap:[this.wrapS,this.wrapT],minFilter:this.minFilter,magFilter:this.magFilter,anisotropy:this.anisotropy};
 this.generateMipmaps;a.premultiplyAlpha=this.premultiplyAlpha;a.flipY=this.flipY;a.unpackAlignment=this.unpackAlignment;return a},toJSON:function(a){if(void 0!==a.textures[this.uuid])return a.textures[this.uuid];var b={metadata:{version:4.4,type:"Texture",generator:"Texture.toJSON"},uuid:this.uuid,name:this.name,mapping:this.mapping,repeat:[this.repeat.x,this.repeat.y],offset:[this.offset.x,this.offset.y],wrap:[this.wrapS,this.wrapT],minFilter:this.minFilter,magFilter:this.magFilter,anisotropy:this.anisotropy};
-if(void 0!==this.image){var c=this.image;void 0===c.uuid&&(c.uuid=THREE.Math.generateUUID());if(void 0===a.images[this.image.uuid]){var d=document.createElement("canvas");d.width=c.width;d.height=c.height;d.getContext("2d").drawImage(c,0,0,c.width,c.height);d=2048<c.width||2048<c.height?d.toDataURL("image/jpeg",.6):d.toDataURL("image/png");a.images[this.image.uuid]={uuid:this.image.uuid,url:d}}b.image=c.uuid}return a.textures[this.uuid]=b},update:function(){this.dispatchEvent({type:"update"})},dispose:function(){this.dispatchEvent({type:"dispose"})}};
-THREE.EventDispatcher.prototype.apply(THREE.Texture.prototype);THREE.TextureIdCount=0;THREE.CubeTexture=function(a,b,c,d,e,f,g,h,k){b=void 0!==b?b:THREE.CubeReflectionMapping;THREE.Texture.call(this,a,b,c,d,e,f,g,h,k);this.images=a};THREE.CubeTexture.prototype=Object.create(THREE.Texture.prototype);THREE.CubeTexture.prototype.constructor=THREE.CubeTexture;THREE.CubeTexture.clone=function(a){void 0===a&&(a=new THREE.CubeTexture);THREE.Texture.prototype.clone.call(this,a);a.images=this.images;return a};
-THREE.CompressedTexture=function(a,b,c,d,e,f,g,h,k,l,n){THREE.Texture.call(this,null,f,g,h,k,l,d,e,n);this.image={width:b,height:c};this.mipmaps=a;this.generateMipmaps=this.flipY=!1};THREE.CompressedTexture.prototype=Object.create(THREE.Texture.prototype);THREE.CompressedTexture.prototype.constructor=THREE.CompressedTexture;THREE.CompressedTexture.prototype.clone=function(){var a=new THREE.CompressedTexture;THREE.Texture.prototype.clone.call(this,a);return a};
-THREE.DataTexture=function(a,b,c,d,e,f,g,h,k,l,n){THREE.Texture.call(this,null,f,g,h,k,l,d,e,n);this.image={data:a,width:b,height:c}};THREE.DataTexture.prototype=Object.create(THREE.Texture.prototype);THREE.DataTexture.prototype.constructor=THREE.DataTexture;THREE.DataTexture.prototype.clone=function(){var a=new THREE.DataTexture;THREE.Texture.prototype.clone.call(this,a);return a};
-THREE.VideoTexture=function(a,b,c,d,e,f,g,h,k){THREE.Texture.call(this,a,b,c,d,e,f,g,h,k);this.generateMipmaps=!1;var l=this,n=function(){requestAnimationFrame(n);a.readyState===a.HAVE_ENOUGH_DATA&&(l.needsUpdate=!0)};n()};THREE.VideoTexture.prototype=Object.create(THREE.Texture.prototype);THREE.VideoTexture.prototype.constructor=THREE.VideoTexture;THREE.Group=function(){THREE.Object3D.call(this);this.type="Group"};THREE.Group.prototype=Object.create(THREE.Object3D.prototype);
-THREE.Group.prototype.constructor=THREE.Group;THREE.PointCloud=function(a,b){THREE.Object3D.call(this);this.type="PointCloud";this.geometry=void 0!==a?a:new THREE.Geometry;this.material=void 0!==b?b:new THREE.PointCloudMaterial({color:16777215*Math.random()})};THREE.PointCloud.prototype=Object.create(THREE.Object3D.prototype);THREE.PointCloud.prototype.constructor=THREE.PointCloud;
-THREE.PointCloud.prototype.raycast=function(){var a=new THREE.Matrix4,b=new THREE.Ray;return function(c,d){var e=this,f=e.geometry,g=c.params.PointCloud.threshold;a.getInverse(this.matrixWorld);b.copy(c.ray).applyMatrix4(a);if(null===f.boundingBox||!1!==b.isIntersectionBox(f.boundingBox)){var h=g/((this.scale.x+this.scale.y+this.scale.z)/3),k=new THREE.Vector3,g=function(a,f){var g=b.distanceToPoint(a);if(g<h){var k=b.closestPointToPoint(a);k.applyMatrix4(e.matrixWorld);var m=c.ray.origin.distanceTo(k);
-m<c.near||m>c.far||d.push({distance:m,distanceToRay:g,point:k.clone(),index:f,face:null,object:e})}};if(f instanceof THREE.BufferGeometry){var l=f.attributes,n=l.position.array;if(void 0!==l.index){var l=l.index.array,p=f.offsets;0===p.length&&(p=[{start:0,count:l.length,index:0}]);for(var m=0,q=p.length;m<q;++m)for(var t=p[m].start,s=p[m].index,f=t,t=t+p[m].count;f<t;f++){var u=s+l[f];k.fromArray(n,3*u);g(k,u)}}else for(l=n.length/3,f=0;f<l;f++)k.set(n[3*f],n[3*f+1],n[3*f+2]),g(k,f)}else for(k=this.geometry.vertices,
+if(void 0!==this.image){var c=this.image;void 0===c.uuid&&(c.uuid=THREE.Math.generateUUID());if(void 0===a.images[c.uuid]){var d=a.images,e=c.uuid,f=c.uuid,g;void 0!==c.toDataURL?g=c:(g=document.createElement("canvas"),g.width=c.width,g.height=c.height,g.getContext("2d").drawImage(c,0,0,c.width,c.height));g=2048<g.width||2048<g.height?g.toDataURL("image/jpeg",.6):g.toDataURL("image/png");d[e]={uuid:f,url:g}}b.image=c.uuid}return a.textures[this.uuid]=b},update:function(){this.dispatchEvent({type:"update"})},
+dispose:function(){this.dispatchEvent({type:"dispose"})}};THREE.EventDispatcher.prototype.apply(THREE.Texture.prototype);THREE.TextureIdCount=0;THREE.CubeTexture=function(a,b,c,d,e,f,g,h,k){b=void 0!==b?b:THREE.CubeReflectionMapping;THREE.Texture.call(this,a,b,c,d,e,f,g,h,k);this.images=a};THREE.CubeTexture.prototype=Object.create(THREE.Texture.prototype);THREE.CubeTexture.prototype.constructor=THREE.CubeTexture;
+THREE.CubeTexture.clone=function(a){void 0===a&&(a=new THREE.CubeTexture);THREE.Texture.prototype.clone.call(this,a);a.images=this.images;return a};THREE.CompressedTexture=function(a,b,c,d,e,f,g,h,k,l,n){THREE.Texture.call(this,null,f,g,h,k,l,d,e,n);this.image={width:b,height:c};this.mipmaps=a;this.generateMipmaps=this.flipY=!1};THREE.CompressedTexture.prototype=Object.create(THREE.Texture.prototype);THREE.CompressedTexture.prototype.constructor=THREE.CompressedTexture;
+THREE.CompressedTexture.prototype.clone=function(){var a=new THREE.CompressedTexture;THREE.Texture.prototype.clone.call(this,a);return a};THREE.DataTexture=function(a,b,c,d,e,f,g,h,k,l,n){THREE.Texture.call(this,null,f,g,h,k,l,d,e,n);this.image={data:a,width:b,height:c}};THREE.DataTexture.prototype=Object.create(THREE.Texture.prototype);THREE.DataTexture.prototype.constructor=THREE.DataTexture;
+THREE.DataTexture.prototype.clone=function(){var a=new THREE.DataTexture;THREE.Texture.prototype.clone.call(this,a);return a};THREE.VideoTexture=function(a,b,c,d,e,f,g,h,k){THREE.Texture.call(this,a,b,c,d,e,f,g,h,k);this.generateMipmaps=!1;var l=this,n=function(){requestAnimationFrame(n);a.readyState===a.HAVE_ENOUGH_DATA&&(l.needsUpdate=!0)};n()};THREE.VideoTexture.prototype=Object.create(THREE.Texture.prototype);THREE.VideoTexture.prototype.constructor=THREE.VideoTexture;
+THREE.Group=function(){THREE.Object3D.call(this);this.type="Group"};THREE.Group.prototype=Object.create(THREE.Object3D.prototype);THREE.Group.prototype.constructor=THREE.Group;THREE.PointCloud=function(a,b){THREE.Object3D.call(this);this.type="PointCloud";this.geometry=void 0!==a?a:new THREE.Geometry;this.material=void 0!==b?b:new THREE.PointCloudMaterial({color:16777215*Math.random()})};THREE.PointCloud.prototype=Object.create(THREE.Object3D.prototype);THREE.PointCloud.prototype.constructor=THREE.PointCloud;
+THREE.PointCloud.prototype.raycast=function(){var a=new THREE.Matrix4,b=new THREE.Ray;return function(c,d){var e=this,f=e.geometry,g=c.params.PointCloud.threshold;a.getInverse(this.matrixWorld);b.copy(c.ray).applyMatrix4(a);if(null===f.boundingBox||!1!==b.isIntersectionBox(f.boundingBox)){var h=g/((this.scale.x+this.scale.y+this.scale.z)/3),k=new THREE.Vector3,g=function(a,g){var f=b.distanceToPoint(a);if(f<h){var k=b.closestPointToPoint(a);k.applyMatrix4(e.matrixWorld);var l=c.ray.origin.distanceTo(k);
+l<c.near||l>c.far||d.push({distance:l,distanceToRay:f,point:k.clone(),index:g,face:null,object:e})}};if(f instanceof THREE.BufferGeometry){var l=f.attributes,n=l.position.array;if(void 0!==l.index){var l=l.index.array,p=f.offsets;0===p.length&&(p=[{start:0,count:l.length,index:0}]);for(var m=0,q=p.length;m<q;++m)for(var s=p[m].start,t=p[m].index,f=s,s=s+p[m].count;f<s;f++){var u=t+l[f];k.fromArray(n,3*u);g(k,u)}}else for(l=n.length/3,f=0;f<l;f++)k.set(n[3*f],n[3*f+1],n[3*f+2]),g(k,f)}else for(k=this.geometry.vertices,
 f=0;f<k.length;f++)g(k[f],f)}}}();THREE.PointCloud.prototype.clone=function(a){void 0===a&&(a=new THREE.PointCloud(this.geometry,this.material));THREE.Object3D.prototype.clone.call(this,a);return a};
 f=0;f<k.length;f++)g(k[f],f)}}}();THREE.PointCloud.prototype.clone=function(a){void 0===a&&(a=new THREE.PointCloud(this.geometry,this.material));THREE.Object3D.prototype.clone.call(this,a);return a};
 THREE.PointCloud.prototype.toJSON=function(a){var b=THREE.Object3D.prototype.toJSON.call(this,a);void 0===a.geometries[this.geometry.uuid]&&(a.geometries[this.geometry.uuid]=this.geometry.toJSON());void 0===a.materials[this.material.uuid]&&(a.materials[this.material.uuid]=this.material.toJSON());b.object.geometry=this.geometry.uuid;b.object.material=this.material.uuid;return b};
 THREE.PointCloud.prototype.toJSON=function(a){var b=THREE.Object3D.prototype.toJSON.call(this,a);void 0===a.geometries[this.geometry.uuid]&&(a.geometries[this.geometry.uuid]=this.geometry.toJSON());void 0===a.materials[this.material.uuid]&&(a.materials[this.material.uuid]=this.material.toJSON());b.object.geometry=this.geometry.uuid;b.object.material=this.material.uuid;return b};
 THREE.ParticleSystem=function(a,b){console.warn("THREE.ParticleSystem has been renamed to THREE.PointCloud.");return new THREE.PointCloud(a,b)};THREE.Line=function(a,b,c){1===c&&console.error("THREE.Line: THREE.LinePieces mode has been removed. Use THREE.LineSegments instead.");THREE.Object3D.call(this);this.type="Line";this.geometry=void 0!==a?a:new THREE.Geometry;this.material=void 0!==b?b:new THREE.LineBasicMaterial({color:16777215*Math.random()})};THREE.Line.prototype=Object.create(THREE.Object3D.prototype);
 THREE.ParticleSystem=function(a,b){console.warn("THREE.ParticleSystem has been renamed to THREE.PointCloud.");return new THREE.PointCloud(a,b)};THREE.Line=function(a,b,c){1===c&&console.error("THREE.Line: THREE.LinePieces mode has been removed. Use THREE.LineSegments instead.");THREE.Object3D.call(this);this.type="Line";this.geometry=void 0!==a?a:new THREE.Geometry;this.material=void 0!==b?b:new THREE.LineBasicMaterial({color:16777215*Math.random()})};THREE.Line.prototype=Object.create(THREE.Object3D.prototype);
 THREE.Line.prototype.constructor=THREE.Line;
 THREE.Line.prototype.constructor=THREE.Line;
 THREE.Line.prototype.raycast=function(){var a=new THREE.Matrix4,b=new THREE.Ray,c=new THREE.Sphere;return function(d,e){var f=d.linePrecision,f=f*f,g=this.geometry;null===g.boundingSphere&&g.computeBoundingSphere();c.copy(g.boundingSphere);c.applyMatrix4(this.matrixWorld);if(!1!==d.ray.isIntersectionSphere(c)){a.getInverse(this.matrixWorld);b.copy(d.ray).applyMatrix4(a);var h=new THREE.Vector3,k=new THREE.Vector3,l=new THREE.Vector3,n=new THREE.Vector3,p=this instanceof THREE.LineSegments?2:1;if(g instanceof
 THREE.Line.prototype.raycast=function(){var a=new THREE.Matrix4,b=new THREE.Ray,c=new THREE.Sphere;return function(d,e){var f=d.linePrecision,f=f*f,g=this.geometry;null===g.boundingSphere&&g.computeBoundingSphere();c.copy(g.boundingSphere);c.applyMatrix4(this.matrixWorld);if(!1!==d.ray.isIntersectionSphere(c)){a.getInverse(this.matrixWorld);b.copy(d.ray).applyMatrix4(a);var h=new THREE.Vector3,k=new THREE.Vector3,l=new THREE.Vector3,n=new THREE.Vector3,p=this instanceof THREE.LineSegments?2:1;if(g instanceof
-THREE.BufferGeometry){var m=g.attributes;if(void 0!==m.index){var q=m.index.array,m=m.position.array,t=g.offsets;0===t.length&&(t=[{start:0,count:q.length,index:0}]);for(var s=0;s<t.length;s++)for(var u=t[s].start,w=t[s].count,x=t[s].index,g=u;g<u+w-1;g+=p){var A=x+q[g+1];h.fromArray(m,3*(x+q[g]));k.fromArray(m,3*A);A=b.distanceSqToSegment(h,k,n,l);A>f||(A=b.origin.distanceTo(n),A<d.near||A>d.far||e.push({distance:A,point:l.clone().applyMatrix4(this.matrixWorld),index:g,offsetIndex:s,face:null,faceIndex:null,
+THREE.BufferGeometry){var m=g.attributes;if(void 0!==m.index){var q=m.index.array,m=m.position.array,s=g.offsets;0===s.length&&(s=[{start:0,count:q.length,index:0}]);for(var t=0;t<s.length;t++)for(var u=s[t].start,x=s[t].count,w=s[t].index,g=u;g<u+x-1;g+=p){var A=w+q[g+1];h.fromArray(m,3*(w+q[g]));k.fromArray(m,3*A);A=b.distanceSqToSegment(h,k,n,l);A>f||(A=b.origin.distanceTo(n),A<d.near||A>d.far||e.push({distance:A,point:l.clone().applyMatrix4(this.matrixWorld),index:g,offsetIndex:t,face:null,faceIndex:null,
 object:this}))}}else for(m=m.position.array,g=0;g<m.length/3-1;g+=p)h.fromArray(m,3*g),k.fromArray(m,3*g+3),A=b.distanceSqToSegment(h,k,n,l),A>f||(A=b.origin.distanceTo(n),A<d.near||A>d.far||e.push({distance:A,point:l.clone().applyMatrix4(this.matrixWorld),index:g,face:null,faceIndex:null,object:this}))}else if(g instanceof THREE.Geometry)for(h=g.vertices,k=h.length,g=0;g<k-1;g+=p)A=b.distanceSqToSegment(h[g],h[g+1],n,l),A>f||(A=b.origin.distanceTo(n),A<d.near||A>d.far||e.push({distance:A,point:l.clone().applyMatrix4(this.matrixWorld),
 object:this}))}}else for(m=m.position.array,g=0;g<m.length/3-1;g+=p)h.fromArray(m,3*g),k.fromArray(m,3*g+3),A=b.distanceSqToSegment(h,k,n,l),A>f||(A=b.origin.distanceTo(n),A<d.near||A>d.far||e.push({distance:A,point:l.clone().applyMatrix4(this.matrixWorld),index:g,face:null,faceIndex:null,object:this}))}else if(g instanceof THREE.Geometry)for(h=g.vertices,k=h.length,g=0;g<k-1;g+=p)A=b.distanceSqToSegment(h[g],h[g+1],n,l),A>f||(A=b.origin.distanceTo(n),A<d.near||A>d.far||e.push({distance:A,point:l.clone().applyMatrix4(this.matrixWorld),
 index:g,face:null,faceIndex:null,object:this}))}}}();THREE.Line.prototype.clone=function(a){void 0===a&&(a=new THREE[this.type](this.geometry,this.material));THREE.Object3D.prototype.clone.call(this,a);return a};
 index:g,face:null,faceIndex:null,object:this}))}}}();THREE.Line.prototype.clone=function(a){void 0===a&&(a=new THREE[this.type](this.geometry,this.material));THREE.Object3D.prototype.clone.call(this,a);return a};
 THREE.Line.prototype.toJSON=function(a){var b=THREE.Object3D.prototype.toJSON.call(this,a);void 0===a.geometries[this.geometry.uuid]&&(a.geometries[this.geometry.uuid]=this.geometry.toJSON());void 0===a.materials[this.material.uuid]&&(a.materials[this.material.uuid]=this.material.toJSON());b.object.geometry=this.geometry.uuid;b.object.material=this.material.uuid;return b};THREE.LineStrip=0;THREE.LinePieces=1;THREE.LineSegments=function(a,b){THREE.Line.call(this,a,b);this.type="LineSegments"};
 THREE.Line.prototype.toJSON=function(a){var b=THREE.Object3D.prototype.toJSON.call(this,a);void 0===a.geometries[this.geometry.uuid]&&(a.geometries[this.geometry.uuid]=this.geometry.toJSON());void 0===a.materials[this.material.uuid]&&(a.materials[this.material.uuid]=this.material.toJSON());b.object.geometry=this.geometry.uuid;b.object.material=this.material.uuid;return b};THREE.LineStrip=0;THREE.LinePieces=1;THREE.LineSegments=function(a,b){THREE.Line.call(this,a,b);this.type="LineSegments"};
@@ -377,11 +377,11 @@ THREE.LineSegments.prototype=Object.create(THREE.Line.prototype);THREE.LineSegme
 THREE.Mesh.prototype.updateMorphTargets=function(){if(void 0!==this.geometry.morphTargets&&0<this.geometry.morphTargets.length){this.morphTargetBase=-1;this.morphTargetForcedOrder=[];this.morphTargetInfluences=[];this.morphTargetDictionary={};for(var a=0,b=this.geometry.morphTargets.length;a<b;a++)this.morphTargetInfluences.push(0),this.morphTargetDictionary[this.geometry.morphTargets[a].name]=a}};
 THREE.Mesh.prototype.updateMorphTargets=function(){if(void 0!==this.geometry.morphTargets&&0<this.geometry.morphTargets.length){this.morphTargetBase=-1;this.morphTargetForcedOrder=[];this.morphTargetInfluences=[];this.morphTargetDictionary={};for(var a=0,b=this.geometry.morphTargets.length;a<b;a++)this.morphTargetInfluences.push(0),this.morphTargetDictionary[this.geometry.morphTargets[a].name]=a}};
 THREE.Mesh.prototype.getMorphTargetIndexByName=function(a){if(void 0!==this.morphTargetDictionary[a])return this.morphTargetDictionary[a];console.warn("THREE.Mesh.getMorphTargetIndexByName: morph target "+a+" does not exist. Returning 0.");return 0};
 THREE.Mesh.prototype.getMorphTargetIndexByName=function(a){if(void 0!==this.morphTargetDictionary[a])return this.morphTargetDictionary[a];console.warn("THREE.Mesh.getMorphTargetIndexByName: morph target "+a+" does not exist. Returning 0.");return 0};
 THREE.Mesh.prototype.raycast=function(){var a=new THREE.Matrix4,b=new THREE.Ray,c=new THREE.Sphere,d=new THREE.Vector3,e=new THREE.Vector3,f=new THREE.Vector3;return function(g,h){var k=this.geometry;null===k.boundingSphere&&k.computeBoundingSphere();c.copy(k.boundingSphere);c.applyMatrix4(this.matrixWorld);if(!1!==g.ray.isIntersectionSphere(c)&&(a.getInverse(this.matrixWorld),b.copy(g.ray).applyMatrix4(a),null===k.boundingBox||!1!==b.isIntersectionBox(k.boundingBox)))if(k instanceof THREE.BufferGeometry){var l=
 THREE.Mesh.prototype.raycast=function(){var a=new THREE.Matrix4,b=new THREE.Ray,c=new THREE.Sphere,d=new THREE.Vector3,e=new THREE.Vector3,f=new THREE.Vector3;return function(g,h){var k=this.geometry;null===k.boundingSphere&&k.computeBoundingSphere();c.copy(k.boundingSphere);c.applyMatrix4(this.matrixWorld);if(!1!==g.ray.isIntersectionSphere(c)&&(a.getInverse(this.matrixWorld),b.copy(g.ray).applyMatrix4(a),null===k.boundingBox||!1!==b.isIntersectionBox(k.boundingBox)))if(k instanceof THREE.BufferGeometry){var l=
-this.material;if(void 0!==l){var n=k.attributes,p,m;if(void 0!==n.index){var q=n.index.array,t=n.position.array,s=k.offsets;0===s.length&&(s=[{start:0,count:q.length,index:0}]);for(var u=0,w=s.length;u<w;++u)for(var n=s[u].start,x=s[u].index,k=n,A=n+s[u].count;k<A;k+=3){n=x+q[k];p=x+q[k+1];m=x+q[k+2];d.fromArray(t,3*n);e.fromArray(t,3*p);f.fromArray(t,3*m);var y=l.side===THREE.BackSide?b.intersectTriangle(f,e,d,!0):b.intersectTriangle(d,e,f,l.side!==THREE.DoubleSide);if(null!==y){y.applyMatrix4(this.matrixWorld);
-var D=g.ray.origin.distanceTo(y);D<g.near||D>g.far||h.push({distance:D,point:y,face:new THREE.Face3(n,p,m,THREE.Triangle.normal(d,e,f)),faceIndex:null,object:this})}}}else for(t=n.position.array,q=k=0,A=t.length;k<A;k+=3,q+=9)n=k,p=k+1,m=k+2,d.fromArray(t,q),e.fromArray(t,q+3),f.fromArray(t,q+6),y=l.side===THREE.BackSide?b.intersectTriangle(f,e,d,!0):b.intersectTriangle(d,e,f,l.side!==THREE.DoubleSide),null!==y&&(y.applyMatrix4(this.matrixWorld),D=g.ray.origin.distanceTo(y),D<g.near||D>g.far||h.push({distance:D,
-point:y,face:new THREE.Face3(n,p,m,THREE.Triangle.normal(d,e,f)),faceIndex:null,object:this}))}}else if(k instanceof THREE.Geometry)for(q=this.material instanceof THREE.MeshFaceMaterial,t=!0===q?this.material.materials:null,s=k.vertices,u=0,w=k.faces.length;u<w;u++)if(x=k.faces[u],l=!0===q?t[x.materialIndex]:this.material,void 0!==l){n=s[x.a];p=s[x.b];m=s[x.c];if(!0===l.morphTargets){y=k.morphTargets;D=this.morphTargetInfluences;d.set(0,0,0);e.set(0,0,0);f.set(0,0,0);for(var A=0,I=y.length;A<I;A++){var v=
-D[A];if(0!==v){var E=y[A].vertices;d.x+=(E[x.a].x-n.x)*v;d.y+=(E[x.a].y-n.y)*v;d.z+=(E[x.a].z-n.z)*v;e.x+=(E[x.b].x-p.x)*v;e.y+=(E[x.b].y-p.y)*v;e.z+=(E[x.b].z-p.z)*v;f.x+=(E[x.c].x-m.x)*v;f.y+=(E[x.c].y-m.y)*v;f.z+=(E[x.c].z-m.z)*v}}d.add(n);e.add(p);f.add(m);n=d;p=e;m=f}y=l.side===THREE.BackSide?b.intersectTriangle(m,p,n,!0):b.intersectTriangle(n,p,m,l.side!==THREE.DoubleSide);null!==y&&(y.applyMatrix4(this.matrixWorld),D=g.ray.origin.distanceTo(y),D<g.near||D>g.far||h.push({distance:D,point:y,
-face:x,faceIndex:u,object:this}))}}}();THREE.Mesh.prototype.clone=function(a,b){void 0===a&&(a=new THREE.Mesh(this.geometry,this.material));THREE.Object3D.prototype.clone.call(this,a,b);return a};
+this.material;if(void 0!==l){var n=k.attributes,p,m;if(void 0!==n.index){var q=n.index.array,s=n.position.array,t=k.offsets;0===t.length&&(t=[{start:0,count:q.length,index:0}]);for(var u=0,x=t.length;u<x;++u)for(var n=t[u].start,w=t[u].index,k=n,A=n+t[u].count;k<A;k+=3){n=w+q[k];p=w+q[k+1];m=w+q[k+2];d.fromArray(s,3*n);e.fromArray(s,3*p);f.fromArray(s,3*m);var y=l.side===THREE.BackSide?b.intersectTriangle(f,e,d,!0):b.intersectTriangle(d,e,f,l.side!==THREE.DoubleSide);if(null!==y){y.applyMatrix4(this.matrixWorld);
+var G=g.ray.origin.distanceTo(y);G<g.near||G>g.far||h.push({distance:G,point:y,face:new THREE.Face3(n,p,m,THREE.Triangle.normal(d,e,f)),faceIndex:null,object:this})}}}else for(s=n.position.array,q=k=0,A=s.length;k<A;k+=3,q+=9)n=k,p=k+1,m=k+2,d.fromArray(s,q),e.fromArray(s,q+3),f.fromArray(s,q+6),y=l.side===THREE.BackSide?b.intersectTriangle(f,e,d,!0):b.intersectTriangle(d,e,f,l.side!==THREE.DoubleSide),null!==y&&(y.applyMatrix4(this.matrixWorld),G=g.ray.origin.distanceTo(y),G<g.near||G>g.far||h.push({distance:G,
+point:y,face:new THREE.Face3(n,p,m,THREE.Triangle.normal(d,e,f)),faceIndex:null,object:this}))}}else if(k instanceof THREE.Geometry)for(q=this.material instanceof THREE.MeshFaceMaterial,s=!0===q?this.material.materials:null,t=k.vertices,u=0,x=k.faces.length;u<x;u++)if(w=k.faces[u],l=!0===q?s[w.materialIndex]:this.material,void 0!==l){n=t[w.a];p=t[w.b];m=t[w.c];if(!0===l.morphTargets){y=k.morphTargets;G=this.morphTargetInfluences;d.set(0,0,0);e.set(0,0,0);f.set(0,0,0);for(var A=0,I=y.length;A<I;A++){var v=
+G[A];if(0!==v){var D=y[A].vertices;d.x+=(D[w.a].x-n.x)*v;d.y+=(D[w.a].y-n.y)*v;d.z+=(D[w.a].z-n.z)*v;e.x+=(D[w.b].x-p.x)*v;e.y+=(D[w.b].y-p.y)*v;e.z+=(D[w.b].z-p.z)*v;f.x+=(D[w.c].x-m.x)*v;f.y+=(D[w.c].y-m.y)*v;f.z+=(D[w.c].z-m.z)*v}}d.add(n);e.add(p);f.add(m);n=d;p=e;m=f}y=l.side===THREE.BackSide?b.intersectTriangle(m,p,n,!0):b.intersectTriangle(n,p,m,l.side!==THREE.DoubleSide);null!==y&&(y.applyMatrix4(this.matrixWorld),G=g.ray.origin.distanceTo(y),G<g.near||G>g.far||h.push({distance:G,point:y,
+face:w,faceIndex:u,object:this}))}}}();THREE.Mesh.prototype.clone=function(a,b){void 0===a&&(a=new THREE.Mesh(this.geometry,this.material));THREE.Object3D.prototype.clone.call(this,a,b);return a};
 THREE.Mesh.prototype.toJSON=function(a){var b=THREE.Object3D.prototype.toJSON.call(this,a);void 0===a.geometries[this.geometry.uuid]&&(a.geometries[this.geometry.uuid]=this.geometry.toJSON(a));void 0===a.materials[this.material.uuid]&&(a.materials[this.material.uuid]=this.material.toJSON(a));b.object.geometry=this.geometry.uuid;b.object.material=this.material.uuid;return b};THREE.Bone=function(a){THREE.Object3D.call(this);this.type="Bone";this.skin=a};THREE.Bone.prototype=Object.create(THREE.Object3D.prototype);
 THREE.Mesh.prototype.toJSON=function(a){var b=THREE.Object3D.prototype.toJSON.call(this,a);void 0===a.geometries[this.geometry.uuid]&&(a.geometries[this.geometry.uuid]=this.geometry.toJSON(a));void 0===a.materials[this.material.uuid]&&(a.materials[this.material.uuid]=this.material.toJSON(a));b.object.geometry=this.geometry.uuid;b.object.material=this.material.uuid;return b};THREE.Bone=function(a){THREE.Object3D.call(this);this.type="Bone";this.skin=a};THREE.Bone.prototype=Object.create(THREE.Object3D.prototype);
 THREE.Bone.prototype.constructor=THREE.Bone;
 THREE.Bone.prototype.constructor=THREE.Bone;
 THREE.Skeleton=function(a,b,c){this.useVertexTexture=void 0!==c?c:!0;this.identityMatrix=new THREE.Matrix4;a=a||[];this.bones=a.slice(0);this.useVertexTexture?(this.boneTextureHeight=this.boneTextureWidth=a=256<this.bones.length?64:64<this.bones.length?32:16<this.bones.length?16:8,this.boneMatrices=new Float32Array(this.boneTextureWidth*this.boneTextureHeight*4),this.boneTexture=new THREE.DataTexture(this.boneMatrices,this.boneTextureWidth,this.boneTextureHeight,THREE.RGBAFormat,THREE.FloatType),
 THREE.Skeleton=function(a,b,c){this.useVertexTexture=void 0!==c?c:!0;this.identityMatrix=new THREE.Matrix4;a=a||[];this.bones=a.slice(0);this.useVertexTexture?(this.boneTextureHeight=this.boneTextureWidth=a=256<this.bones.length?64:64<this.bones.length?32:16<this.bones.length?16:8,this.boneMatrices=new Float32Array(this.boneTextureWidth*this.boneTextureHeight*4),this.boneTexture=new THREE.DataTexture(this.boneMatrices,this.boneTextureWidth,this.boneTextureHeight,THREE.RGBAFormat,THREE.FloatType),
@@ -473,97 +473,96 @@ tFlip:{type:"f",value:-1}},vertexShader:["varying vec3 vWorldPosition;",THREE.Sh
 THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:["uniform sampler2D tEquirect;\nuniform float tFlip;\nvarying vec3 vWorldPosition;",THREE.ShaderChunk.common,THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {\nvec3 direction = normalize( vWorldPosition );\nvec2 sampleUV;\nsampleUV.y = saturate( tFlip * direction.y * -0.5 + 0.5 );\nsampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;\ngl_FragColor = texture2D( tEquirect, sampleUV );",THREE.ShaderChunk.logdepthbuf_fragment,
 THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:["uniform sampler2D tEquirect;\nuniform float tFlip;\nvarying vec3 vWorldPosition;",THREE.ShaderChunk.common,THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {\nvec3 direction = normalize( vWorldPosition );\nvec2 sampleUV;\nsampleUV.y = saturate( tFlip * direction.y * -0.5 + 0.5 );\nsampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;\ngl_FragColor = texture2D( tEquirect, sampleUV );",THREE.ShaderChunk.logdepthbuf_fragment,
 "}"].join("\n")},depthRGBA:{uniforms:{},vertexShader:[THREE.ShaderChunk.common,THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.skinning_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {",THREE.ShaderChunk.skinbase_vertex,THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.skinning_vertex,THREE.ShaderChunk.default_vertex,THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:[THREE.ShaderChunk.common,THREE.ShaderChunk.logdepthbuf_pars_fragment,"vec4 pack_depth( const in float depth ) {\n\tconst vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );\n\tconst vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );\n\tvec4 res = mod( depth * bit_shift * vec4( 255 ), vec4( 256 ) ) / vec4( 255 );\n\tres -= res.xxyz * bit_mask;\n\treturn res;\n}\nvoid main() {",
 "}"].join("\n")},depthRGBA:{uniforms:{},vertexShader:[THREE.ShaderChunk.common,THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.skinning_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {",THREE.ShaderChunk.skinbase_vertex,THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.skinning_vertex,THREE.ShaderChunk.default_vertex,THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:[THREE.ShaderChunk.common,THREE.ShaderChunk.logdepthbuf_pars_fragment,"vec4 pack_depth( const in float depth ) {\n\tconst vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );\n\tconst vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );\n\tvec4 res = mod( depth * bit_shift * vec4( 255 ), vec4( 256 ) ) / vec4( 255 );\n\tres -= res.xxyz * bit_mask;\n\treturn res;\n}\nvoid main() {",
 THREE.ShaderChunk.logdepthbuf_fragment,"\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tgl_FragData[ 0 ] = pack_depth( gl_FragDepthEXT );\n\t#else\n\t\tgl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );\n\t#endif\n}"].join("\n")}};
 THREE.ShaderChunk.logdepthbuf_fragment,"\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tgl_FragData[ 0 ] = pack_depth( gl_FragDepthEXT );\n\t#else\n\t\tgl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );\n\t#endif\n}"].join("\n")}};
-THREE.WebGLRenderer=function(a){function b(a,b,c,d){var e;if(c instanceof THREE.InstancedBufferGeometry&&(e=V.get("ANGLE_instanced_arrays"),null===e)){console.error("THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.");return}var f=c.attributes;b=b.attributes;for(var g in b){var h=b[g];if(0<=h){var k=f[g];if(void 0!==k){var m=k.itemSize;Q.enableAttribute(h);if(k instanceof THREE.InterleavedBufferAttribute){var l=
-k.data,n=l.stride,p=k.offset;r.bindBuffer(r.ARRAY_BUFFER,k.data.buffer);r.vertexAttribPointer(h,m,r.FLOAT,!1,n*l.array.BYTES_PER_ELEMENT,(d*n+p)*l.array.BYTES_PER_ELEMENT);if(l instanceof THREE.InstancedInterleavedBuffer){if(null===e){console.error("THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferAttribute but hardware does not support extension ANGLE_instanced_arrays.");return}e.vertexAttribDivisorANGLE(h,l.meshPerAttribute);void 0===c.maxInstancedCount&&(c.maxInstancedCount=
-l.array.length/l.stride*l.meshPerAttribute)}}else if(r.bindBuffer(r.ARRAY_BUFFER,k.buffer),r.vertexAttribPointer(h,m,r.FLOAT,!1,0,d*m*4),k instanceof THREE.InstancedBufferAttribute){if(null===e){console.error("THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferAttribute but hardware does not support extension ANGLE_instanced_arrays.");return}e.vertexAttribDivisorANGLE(h,k.meshPerAttribute);void 0===c.maxInstancedCount&&(c.maxInstancedCount=k.array.length/k.itemSize*k.meshPerAttribute)}}else void 0!==
-a.defaultAttributeValues&&void 0!==a.defaultAttributeValues[g]&&(2===a.defaultAttributeValues[g].length?r.vertexAttrib2fv(h,a.defaultAttributeValues[g]):3===a.defaultAttributeValues[g].length&&r.vertexAttrib3fv(h,a.defaultAttributeValues[g]))}}Q.disableUnusedAttributes()}function c(a,b){return a.object.renderOrder!==b.object.renderOrder?a.object.renderOrder-b.object.renderOrder:a.object.material.id!==b.object.material.id?a.object.material.id-b.object.material.id:a.z!==b.z?a.z-b.z:a.id-b.id}function d(a,
-b){return a.object.renderOrder!==b.object.renderOrder?a.object.renderOrder-b.object.renderOrder:a.z!==b.z?b.z-a.z:a.id-b.id}function e(a){if(!0===a.visible){if(!(a instanceof THREE.Scene||a instanceof THREE.Group))if(a instanceof THREE.SkinnedMesh&&a.skeleton.update(),ha.init(a),a instanceof THREE.Light)B.push(a);else if(a instanceof THREE.Sprite)S.push(a);else if(a instanceof THREE.LensFlare)P.push(a);else{var b=ha.objects[a.id];!b||!1!==a.frustumCulled&&!0!==Ha.intersectsObject(a)||(a.material.transparent?
-O.push(b):T.push(b),!0===H.sortObjects&&(ia.setFromMatrixPosition(a.matrixWorld),ia.applyProjection(za),b.z=ia.z))}for(var b=0,c=a.children.length;b<c;b++)e(a.children[b])}}function f(a,b,c,d,e){for(var f,g=0,k=a.length;g<k;g++){var m=a[g].object;f=m;f._modelViewMatrix.multiplyMatrices(b.matrixWorldInverse,f.matrixWorld);f._normalMatrix.getNormalMatrix(f._modelViewMatrix);if(e)f=e;else{f=m.material;if(!f)continue;h(f)}H.setMaterialFaces(f);H.renderBufferDirect(b,c,d,f,m)}}function g(a,b,c,d,e,f){for(var g,
-k=0,m=a.length;k<m;k++){g=a[k];var l=g.object;if(!0===l.visible){if(f)g=f;else{g=g[b];if(!g)continue;h(g)}H.renderImmediateObject(c,d,e,g,l)}}}function h(a){!0===a.transparent?Q.setBlending(a.blending,a.blendEquation,a.blendSrc,a.blendDst,a.blendEquationAlpha,a.blendSrcAlpha,a.blendDstAlpha):Q.setBlending(THREE.NoBlending);Q.setDepthFunc(a.depthFunc);Q.setDepthTest(a.depthTest);Q.setDepthWrite(a.depthWrite);Q.setColorWrite(a.colorWrite);Q.setPolygonOffset(a.polygonOffset,a.polygonOffsetFactor,a.polygonOffsetUnits)}
-function k(a,b,c,d,e){var f,g,h,k;Va=0;if(d.needsUpdate){a:{for(var s=Sb[d.type],t=0,x=0,y=0,v=0,A=0,L=b.length;A<L;A++){var D=b[A];D.onlyShadow||!1===D.visible||(D instanceof THREE.DirectionalLight&&t++,D instanceof THREE.PointLight&&x++,D instanceof THREE.SpotLight&&y++,D instanceof THREE.HemisphereLight&&v++)}f=t;g=x;h=y;k=v;for(var z,C=0,E=0,F=b.length;E<F;E++){var B=b[E];B.castShadow&&(B instanceof THREE.SpotLight&&C++,B instanceof THREE.DirectionalLight&&!B.shadowCascade&&C++)}z=C;var G;if(bb&&
-e&&e.skeleton&&e.skeleton.useVertexTexture)G=1024;else{var O=r.getParameter(r.MAX_VERTEX_UNIFORM_VECTORS),R=Math.floor((O-20)/4);void 0!==e&&e instanceof THREE.SkinnedMesh&&(R=Math.min(e.skeleton.bones.length,R),R<e.skeleton.bones.length&&console.warn("WebGLRenderer: too many bones - "+e.skeleton.bones.length+", this GPU supports just "+R+" (try OpenGL instead of ANGLE)"));G=R}var ja={precision:I,supportsVertexTextures:cb,map:!!d.map,envMap:!!d.envMap,envMapMode:d.envMap&&d.envMap.mapping,lightMap:!!d.lightMap,
-aoMap:!!d.aoMap,bumpMap:!!d.bumpMap,normalMap:!!d.normalMap,specularMap:!!d.specularMap,alphaMap:!!d.alphaMap,combine:d.combine,vertexColors:d.vertexColors,fog:c,useFog:d.fog,fogExp:c instanceof THREE.FogExp2,flatShading:d.shading===THREE.FlatShading,sizeAttenuation:d.sizeAttenuation,logarithmicDepthBuffer:J,skinning:d.skinning,maxBones:G,useVertexTexture:bb&&e&&e.skeleton&&e.skeleton.useVertexTexture,morphTargets:d.morphTargets,morphNormals:d.morphNormals,maxMorphTargets:H.maxMorphTargets,maxMorphNormals:H.maxMorphNormals,
-maxDirLights:f,maxPointLights:g,maxSpotLights:h,maxHemiLights:k,maxShadows:z,shadowMapEnabled:ga.enabled&&e.receiveShadow&&0<z,shadowMapType:ga.type,shadowMapDebug:ga.debug,shadowMapCascade:ga.cascade,alphaTest:d.alphaTest,metal:d.metal,doubleSided:d.side===THREE.DoubleSide,flipSided:d.side===THREE.BackSide},S=[];s?S.push(s):(S.push(d.fragmentShader),S.push(d.vertexShader));if(void 0!==d.defines)for(var P in d.defines)S.push(P),S.push(d.defines[P]);for(P in ja)S.push(P),S.push(ja[P]);var T=S.join();
-if(!d.program)d.addEventListener("dispose",Eb);else if(d.program.code!==T)Fb(d);else if(void 0!==s)break a;else if(d.__webglShader.uniforms===d.uniforms)break a;if(s){var V=THREE.ShaderLib[s];d.__webglShader={uniforms:THREE.UniformsUtils.clone(V.uniforms),vertexShader:V.vertexShader,fragmentShader:V.fragmentShader}}else d.__webglShader={uniforms:d.uniforms,vertexShader:d.vertexShader,fragmentShader:d.fragmentShader};for(var ma,ya=0,Ga=K.length;ya<Ga;ya++){var Fa=K[ya];if(Fa.code===T){ma=Fa;ma.usedTimes++;
-break}}void 0===ma&&(ma=new THREE.WebGLProgram(H,T,d,ja),K.push(ma),H.info.memory.programs=K.length);d.program=ma;var Ta=ma.attributes;if(d.morphTargets)for(var ra=d.numSupportedMorphTargets=0;ra<H.maxMorphTargets;ra++)0<=Ta["morphTarget"+ra]&&d.numSupportedMorphTargets++;if(d.morphNormals)for(ra=d.numSupportedMorphNormals=0;ra<H.maxMorphNormals;ra++)0<=Ta["morphNormal"+ra]&&d.numSupportedMorphNormals++;d.uniformsList=[];for(var da in d.__webglShader.uniforms){var ha=d.program.uniforms[da];ha&&d.uniformsList.push([d.__webglShader.uniforms[da],
-ha])}}d.needsUpdate=!1}var Ha=!1,za=!1,Wa=!1,Na=d.program,$=Na.uniforms,M=d.__webglShader.uniforms;Na.id!==na&&(r.useProgram(Na.program),na=Na.id,Wa=za=Ha=!0);d.id!==ka&&(-1===ka&&(Wa=!0),ka=d.id,za=!0);if(Ha||a!==ua)r.uniformMatrix4fv($.projectionMatrix,!1,a.projectionMatrix.elements),J&&r.uniform1f($.logDepthBufFC,2/(Math.log(a.far+1)/Math.LN2)),a!==ua&&(ua=a),(d instanceof THREE.ShaderMaterial||d instanceof THREE.MeshPhongMaterial||d.envMap)&&null!==$.cameraPosition&&(ia.setFromMatrixPosition(a.matrixWorld),
-r.uniform3f($.cameraPosition,ia.x,ia.y,ia.z)),(d instanceof THREE.MeshPhongMaterial||d instanceof THREE.MeshLambertMaterial||d instanceof THREE.MeshBasicMaterial||d instanceof THREE.ShaderMaterial||d.skinning)&&null!==$.viewMatrix&&r.uniformMatrix4fv($.viewMatrix,!1,a.matrixWorldInverse.elements);if(d.skinning)if(e.bindMatrix&&null!==$.bindMatrix&&r.uniformMatrix4fv($.bindMatrix,!1,e.bindMatrix.elements),e.bindMatrixInverse&&null!==$.bindMatrixInverse&&r.uniformMatrix4fv($.bindMatrixInverse,!1,e.bindMatrixInverse.elements),
-bb&&e.skeleton&&e.skeleton.useVertexTexture){if(null!==$.boneTexture){var Ma=n();r.uniform1i($.boneTexture,Ma);H.setTexture(e.skeleton.boneTexture,Ma)}null!==$.boneTextureWidth&&r.uniform1i($.boneTextureWidth,e.skeleton.boneTextureWidth);null!==$.boneTextureHeight&&r.uniform1i($.boneTextureHeight,e.skeleton.boneTextureHeight)}else e.skeleton&&e.skeleton.boneMatrices&&null!==$.boneGlobalMatrices&&r.uniformMatrix4fv($.boneGlobalMatrices,!1,e.skeleton.boneMatrices);if(za){c&&d.fog&&(M.fogColor.value=
-c.color,c instanceof THREE.Fog?(M.fogNear.value=c.near,M.fogFar.value=c.far):c instanceof THREE.FogExp2&&(M.fogDensity.value=c.density));if(d instanceof THREE.MeshPhongMaterial||d instanceof THREE.MeshLambertMaterial||d.lights){if(Xa){var Wa=!0,Z,oa,Y,db=0,eb=0,fb=0,Aa,Sa,Ua,Ia,gb,aa=Gb,hb=aa.directional.colors,ib=aa.directional.positions,jb=aa.point.colors,kb=aa.point.positions,$a=aa.point.distances,ab=aa.point.decays,lb=aa.spot.colors,mb=aa.spot.positions,zb=aa.spot.distances,nb=aa.spot.directions,
-Ab=aa.spot.anglesCos,Bb=aa.spot.exponents,Cb=aa.spot.decays,ob=aa.hemi.skyColors,pb=aa.hemi.groundColors,qb=aa.hemi.positions,Oa=0,Ba=0,sa=0,Ja=0,rb=0,sb=0,tb=0,Ya=0,Pa=0,Qa=0,va=0,Ka=0;Z=0;for(oa=b.length;Z<oa;Z++)Y=b[Z],Y.onlyShadow||(Aa=Y.color,Ia=Y.intensity,gb=Y.distance,Y instanceof THREE.AmbientLight?Y.visible&&(db+=Aa.r,eb+=Aa.g,fb+=Aa.b):Y instanceof THREE.DirectionalLight?(rb+=1,Y.visible&&(ca.setFromMatrixPosition(Y.matrixWorld),ia.setFromMatrixPosition(Y.target.matrixWorld),ca.sub(ia),
-ca.normalize(),Pa=3*Oa,ib[Pa+0]=ca.x,ib[Pa+1]=ca.y,ib[Pa+2]=ca.z,p(hb,Pa,Aa,Ia),Oa+=1)):Y instanceof THREE.PointLight?(sb+=1,Y.visible&&(Qa=3*Ba,p(jb,Qa,Aa,Ia),ia.setFromMatrixPosition(Y.matrixWorld),kb[Qa+0]=ia.x,kb[Qa+1]=ia.y,kb[Qa+2]=ia.z,$a[Ba]=gb,ab[Ba]=0===Y.distance?0:Y.decay,Ba+=1)):Y instanceof THREE.SpotLight?(tb+=1,Y.visible&&(va=3*sa,p(lb,va,Aa,Ia),ca.setFromMatrixPosition(Y.matrixWorld),mb[va+0]=ca.x,mb[va+1]=ca.y,mb[va+2]=ca.z,zb[sa]=gb,ia.setFromMatrixPosition(Y.target.matrixWorld),
-ca.sub(ia),ca.normalize(),nb[va+0]=ca.x,nb[va+1]=ca.y,nb[va+2]=ca.z,Ab[sa]=Math.cos(Y.angle),Bb[sa]=Y.exponent,Cb[sa]=0===Y.distance?0:Y.decay,sa+=1)):Y instanceof THREE.HemisphereLight&&(Ya+=1,Y.visible&&(ca.setFromMatrixPosition(Y.matrixWorld),ca.normalize(),Ka=3*Ja,qb[Ka+0]=ca.x,qb[Ka+1]=ca.y,qb[Ka+2]=ca.z,Sa=Y.color,Ua=Y.groundColor,p(ob,Ka,Sa,Ia),p(pb,Ka,Ua,Ia),Ja+=1)));Z=3*Oa;for(oa=Math.max(hb.length,3*rb);Z<oa;Z++)hb[Z]=0;Z=3*Ba;for(oa=Math.max(jb.length,3*sb);Z<oa;Z++)jb[Z]=0;Z=3*sa;for(oa=
-Math.max(lb.length,3*tb);Z<oa;Z++)lb[Z]=0;Z=3*Ja;for(oa=Math.max(ob.length,3*Ya);Z<oa;Z++)ob[Z]=0;Z=3*Ja;for(oa=Math.max(pb.length,3*Ya);Z<oa;Z++)pb[Z]=0;aa.directional.length=Oa;aa.point.length=Ba;aa.spot.length=sa;aa.hemi.length=Ja;aa.ambient[0]=db;aa.ambient[1]=eb;aa.ambient[2]=fb;Xa=!1}if(Wa){var fa=Gb;M.ambientLightColor.value=fa.ambient;M.directionalLightColor.value=fa.directional.colors;M.directionalLightDirection.value=fa.directional.positions;M.pointLightColor.value=fa.point.colors;M.pointLightPosition.value=
-fa.point.positions;M.pointLightDistance.value=fa.point.distances;M.pointLightDecay.value=fa.point.decays;M.spotLightColor.value=fa.spot.colors;M.spotLightPosition.value=fa.spot.positions;M.spotLightDistance.value=fa.spot.distances;M.spotLightDirection.value=fa.spot.directions;M.spotLightAngleCos.value=fa.spot.anglesCos;M.spotLightExponent.value=fa.spot.exponents;M.spotLightDecay.value=fa.spot.decays;M.hemisphereLightSkyColor.value=fa.hemi.skyColors;M.hemisphereLightGroundColor.value=fa.hemi.groundColors;
-M.hemisphereLightDirection.value=fa.hemi.positions;l(M,!0)}else l(M,!1)}if(d instanceof THREE.MeshBasicMaterial||d instanceof THREE.MeshLambertMaterial||d instanceof THREE.MeshPhongMaterial){M.opacity.value=d.opacity;M.diffuse.value=d.color;M.map.value=d.map;M.specularMap.value=d.specularMap;M.alphaMap.value=d.alphaMap;d.bumpMap&&(M.bumpMap.value=d.bumpMap,M.bumpScale.value=d.bumpScale);d.normalMap&&(M.normalMap.value=d.normalMap,M.normalScale.value.copy(d.normalScale));var wa;d.map?wa=d.map:d.specularMap?
-wa=d.specularMap:d.normalMap?wa=d.normalMap:d.bumpMap?wa=d.bumpMap:d.alphaMap&&(wa=d.alphaMap);if(void 0!==wa){var Hb=wa.offset,Ib=wa.repeat;M.offsetRepeat.value.set(Hb.x,Hb.y,Ib.x,Ib.y)}M.envMap.value=d.envMap;M.flipEnvMap.value=d.envMap instanceof THREE.WebGLRenderTargetCube?1:-1;M.reflectivity.value=d.reflectivity;M.refractionRatio.value=d.refractionRatio}if(d instanceof THREE.LineBasicMaterial)M.diffuse.value=d.color,M.opacity.value=d.opacity;else if(d instanceof THREE.LineDashedMaterial)M.diffuse.value=
-d.color,M.opacity.value=d.opacity,M.dashSize.value=d.dashSize,M.totalSize.value=d.dashSize+d.gapSize,M.scale.value=d.scale;else if(d instanceof THREE.PointCloudMaterial){if(M.psColor.value=d.color,M.opacity.value=d.opacity,M.size.value=d.size,M.scale.value=w.height/2,M.map.value=d.map,null!==d.map){var Jb=d.map.offset,Kb=d.map.repeat;M.offsetRepeat.value.set(Jb.x,Jb.y,Kb.x,Kb.y)}}else d instanceof THREE.MeshPhongMaterial?(M.shininess.value=d.shininess,M.emissive.value=d.emissive,M.specular.value=
-d.specular,M.lightMap.value=d.lightMap,M.lightMapIntensity.value=d.lightMapIntensity,M.aoMap.value=d.aoMap,M.aoMapIntensity.value=d.aoMapIntensity):d instanceof THREE.MeshLambertMaterial?M.emissive.value=d.emissive:d instanceof THREE.MeshBasicMaterial?(M.aoMap.value=d.aoMap,M.aoMapIntensity.value=d.aoMapIntensity):d instanceof THREE.MeshDepthMaterial?(M.mNear.value=a.near,M.mFar.value=a.far,M.opacity.value=d.opacity):d instanceof THREE.MeshNormalMaterial&&(M.opacity.value=d.opacity);if(e.receiveShadow&&
-!d._shadowPass&&M.shadowMatrix)for(var La=0,ub=0,Db=b.length;ub<Db;ub++){var ta=b[ub];ta.castShadow&&(ta instanceof THREE.SpotLight||ta instanceof THREE.DirectionalLight&&!ta.shadowCascade)&&(M.shadowMap.value[La]=ta.shadowMap,M.shadowMapSize.value[La]=ta.shadowMapSize,M.shadowMatrix.value[La]=ta.shadowMatrix,M.shadowDarkness.value[La]=ta.shadowDarkness,M.shadowBias.value[La]=ta.shadowBias,La++)}for(var vb=d.uniformsList,pa,Ca,qa,Za=0,Tb=vb.length;Za<Tb;Za++){var W=vb[Za][0];if(!1!==W.needsUpdate){var Lb=
-W.type,N=W.value,X=vb[Za][1];switch(Lb){case "1i":r.uniform1i(X,N);break;case "1f":r.uniform1f(X,N);break;case "2f":r.uniform2f(X,N[0],N[1]);break;case "3f":r.uniform3f(X,N[0],N[1],N[2]);break;case "4f":r.uniform4f(X,N[0],N[1],N[2],N[3]);break;case "1iv":r.uniform1iv(X,N);break;case "3iv":r.uniform3iv(X,N);break;case "1fv":r.uniform1fv(X,N);break;case "2fv":r.uniform2fv(X,N);break;case "3fv":r.uniform3fv(X,N);break;case "4fv":r.uniform4fv(X,N);break;case "Matrix3fv":r.uniformMatrix3fv(X,!1,N);break;
-case "Matrix4fv":r.uniformMatrix4fv(X,!1,N);break;case "i":r.uniform1i(X,N);break;case "f":r.uniform1f(X,N);break;case "v2":r.uniform2f(X,N.x,N.y);break;case "v3":r.uniform3f(X,N.x,N.y,N.z);break;case "v4":r.uniform4f(X,N.x,N.y,N.z,N.w);break;case "c":r.uniform3f(X,N.r,N.g,N.b);break;case "iv1":r.uniform1iv(X,N);break;case "iv":r.uniform3iv(X,N);break;case "fv1":r.uniform1fv(X,N);break;case "fv":r.uniform3fv(X,N);break;case "v2v":void 0===W._array&&(W._array=new Float32Array(2*N.length));for(var U=
-0,la=N.length;U<la;U++)qa=2*U,W._array[qa+0]=N[U].x,W._array[qa+1]=N[U].y;r.uniform2fv(X,W._array);break;case "v3v":void 0===W._array&&(W._array=new Float32Array(3*N.length));U=0;for(la=N.length;U<la;U++)qa=3*U,W._array[qa+0]=N[U].x,W._array[qa+1]=N[U].y,W._array[qa+2]=N[U].z;r.uniform3fv(X,W._array);break;case "v4v":void 0===W._array&&(W._array=new Float32Array(4*N.length));U=0;for(la=N.length;U<la;U++)qa=4*U,W._array[qa+0]=N[U].x,W._array[qa+1]=N[U].y,W._array[qa+2]=N[U].z,W._array[qa+3]=N[U].w;
-r.uniform4fv(X,W._array);break;case "m3":r.uniformMatrix3fv(X,!1,N.elements);break;case "m3v":void 0===W._array&&(W._array=new Float32Array(9*N.length));U=0;for(la=N.length;U<la;U++)N[U].flattenToArrayOffset(W._array,9*U);r.uniformMatrix3fv(X,!1,W._array);break;case "m4":r.uniformMatrix4fv(X,!1,N.elements);break;case "m4v":void 0===W._array&&(W._array=new Float32Array(16*N.length));U=0;for(la=N.length;U<la;U++)N[U].flattenToArrayOffset(W._array,16*U);r.uniformMatrix4fv(X,!1,W._array);break;case "t":pa=
-N;Ca=n();r.uniform1i(X,Ca);if(!pa)continue;if(pa instanceof THREE.CubeTexture||Array.isArray(pa.image)&&6===pa.image.length){var ba=pa,Mb=Ca;if(6===ba.image.length)if(ba.needsUpdate){ba.image.__webglTextureCube||(ba.addEventListener("dispose",wb),ba.image.__webglTextureCube=r.createTexture(),H.info.memory.textures++);Q.activeTexture(r.TEXTURE0+Mb);Q.bindTexture(r.TEXTURE_CUBE_MAP,ba.image.__webglTextureCube);r.pixelStorei(r.UNPACK_FLIP_Y_WEBGL,ba.flipY);for(var Nb=ba instanceof THREE.CompressedTexture,
-xb=ba.image[0]instanceof THREE.DataTexture,Da=[],ea=0;6>ea;ea++)Da[ea]=!H.autoScaleCubemaps||Nb||xb?xb?ba.image[ea].image:ba.image[ea]:q(ba.image[ea],Ub);var Ob=Da[0],Pb=THREE.Math.isPowerOfTwo(Ob.width)&&THREE.Math.isPowerOfTwo(Ob.height),xa=u(ba.format),yb=u(ba.type);m(r.TEXTURE_CUBE_MAP,ba,Pb);for(ea=0;6>ea;ea++)if(Nb)for(var Ea,Qb=Da[ea].mipmaps,Ra=0,Vb=Qb.length;Ra<Vb;Ra++)Ea=Qb[Ra],ba.format!==THREE.RGBAFormat&&ba.format!==THREE.RGBFormat?-1<Rb().indexOf(xa)?Q.compressedTexImage2D(r.TEXTURE_CUBE_MAP_POSITIVE_X+
-ea,Ra,xa,Ea.width,Ea.height,0,Ea.data):console.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setCubeTexture()"):Q.texImage2D(r.TEXTURE_CUBE_MAP_POSITIVE_X+ea,Ra,xa,Ea.width,Ea.height,0,xa,yb,Ea.data);else xb?Q.texImage2D(r.TEXTURE_CUBE_MAP_POSITIVE_X+ea,0,xa,Da[ea].width,Da[ea].height,0,xa,yb,Da[ea].data):Q.texImage2D(r.TEXTURE_CUBE_MAP_POSITIVE_X+ea,0,xa,xa,yb,Da[ea]);ba.generateMipmaps&&Pb&&r.generateMipmap(r.TEXTURE_CUBE_MAP);ba.needsUpdate=!1;if(ba.onUpdate)ba.onUpdate(ba)}else Q.activeTexture(r.TEXTURE0+
-Mb),Q.bindTexture(r.TEXTURE_CUBE_MAP,ba.image.__webglTextureCube)}else if(pa instanceof THREE.WebGLRenderTargetCube){var Wb=pa;Q.activeTexture(r.TEXTURE0+Ca);Q.bindTexture(r.TEXTURE_CUBE_MAP,Wb.__webglTexture)}else H.setTexture(pa,Ca);break;case "tv":void 0===W._array&&(W._array=[]);U=0;for(la=W.value.length;U<la;U++)W._array[U]=n();r.uniform1iv(X,W._array);U=0;for(la=W.value.length;U<la;U++)pa=W.value[U],Ca=W._array[U],pa&&H.setTexture(pa,Ca);break;default:console.warn("THREE.WebGLRenderer: Unknown uniform type: "+
-Lb)}}}}r.uniformMatrix4fv($.modelViewMatrix,!1,e._modelViewMatrix.elements);$.normalMatrix&&r.uniformMatrix3fv($.normalMatrix,!1,e._normalMatrix.elements);null!==$.modelMatrix&&r.uniformMatrix4fv($.modelMatrix,!1,e.matrixWorld.elements);return Na}function l(a,b){a.ambientLightColor.needsUpdate=b;a.directionalLightColor.needsUpdate=b;a.directionalLightDirection.needsUpdate=b;a.pointLightColor.needsUpdate=b;a.pointLightPosition.needsUpdate=b;a.pointLightDistance.needsUpdate=b;a.pointLightDecay.needsUpdate=
-b;a.spotLightColor.needsUpdate=b;a.spotLightPosition.needsUpdate=b;a.spotLightDistance.needsUpdate=b;a.spotLightDirection.needsUpdate=b;a.spotLightAngleCos.needsUpdate=b;a.spotLightExponent.needsUpdate=b;a.spotLightDecay.needsUpdate=b;a.hemisphereLightSkyColor.needsUpdate=b;a.hemisphereLightGroundColor.needsUpdate=b;a.hemisphereLightDirection.needsUpdate=b}function n(){var a=Va;a>=Sa&&console.warn("WebGLRenderer: trying to use "+a+" texture units while this GPU supports only "+Sa);Va+=1;return a}
-function p(a,b,c,d){a[b+0]=c.r*d;a[b+1]=c.g*d;a[b+2]=c.b*d}function m(a,b,c){c?(r.texParameteri(a,r.TEXTURE_WRAP_S,u(b.wrapS)),r.texParameteri(a,r.TEXTURE_WRAP_T,u(b.wrapT)),r.texParameteri(a,r.TEXTURE_MAG_FILTER,u(b.magFilter)),r.texParameteri(a,r.TEXTURE_MIN_FILTER,u(b.minFilter))):(r.texParameteri(a,r.TEXTURE_WRAP_S,r.CLAMP_TO_EDGE),r.texParameteri(a,r.TEXTURE_WRAP_T,r.CLAMP_TO_EDGE),b.wrapS===THREE.ClampToEdgeWrapping&&b.wrapT===THREE.ClampToEdgeWrapping||console.warn("THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping. ( "+
-b.sourceFile+" )"),r.texParameteri(a,r.TEXTURE_MAG_FILTER,s(b.magFilter)),r.texParameteri(a,r.TEXTURE_MIN_FILTER,s(b.minFilter)),b.minFilter!==THREE.NearestFilter&&b.minFilter!==THREE.LinearFilter&&console.warn("THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter. ( "+b.sourceFile+" )"));(c=V.get("EXT_texture_filter_anisotropic"))&&b.type!==THREE.FloatType&&b.type!==THREE.HalfFloatType&&(1<b.anisotropy||b.__currentAnisotropy)&&
-(r.texParameterf(a,c.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(b.anisotropy,H.getMaxAnisotropy())),b.__currentAnisotropy=b.anisotropy)}function q(a,b){if(a.width>b||a.height>b){var c=b/Math.max(a.width,a.height),d=document.createElement("canvas");d.width=Math.floor(a.width*c);d.height=Math.floor(a.height*c);d.getContext("2d").drawImage(a,0,0,a.width,a.height,0,0,d.width,d.height);console.warn("THREE.WebGLRenderer: image is too big ("+a.width+"x"+a.height+"). Resized to "+d.width+"x"+d.height,a);return d}return a}
-function t(a,b){r.bindRenderbuffer(r.RENDERBUFFER,a);b.depthBuffer&&!b.stencilBuffer?(r.renderbufferStorage(r.RENDERBUFFER,r.DEPTH_COMPONENT16,b.width,b.height),r.framebufferRenderbuffer(r.FRAMEBUFFER,r.DEPTH_ATTACHMENT,r.RENDERBUFFER,a)):b.depthBuffer&&b.stencilBuffer?(r.renderbufferStorage(r.RENDERBUFFER,r.DEPTH_STENCIL,b.width,b.height),r.framebufferRenderbuffer(r.FRAMEBUFFER,r.DEPTH_STENCIL_ATTACHMENT,r.RENDERBUFFER,a)):r.renderbufferStorage(r.RENDERBUFFER,r.RGBA4,b.width,b.height)}function s(a){return a===
-THREE.NearestFilter||a===THREE.NearestMipMapNearestFilter||a===THREE.NearestMipMapLinearFilter?r.NEAREST:r.LINEAR}function u(a){var b;if(a===THREE.RepeatWrapping)return r.REPEAT;if(a===THREE.ClampToEdgeWrapping)return r.CLAMP_TO_EDGE;if(a===THREE.MirroredRepeatWrapping)return r.MIRRORED_REPEAT;if(a===THREE.NearestFilter)return r.NEAREST;if(a===THREE.NearestMipMapNearestFilter)return r.NEAREST_MIPMAP_NEAREST;if(a===THREE.NearestMipMapLinearFilter)return r.NEAREST_MIPMAP_LINEAR;if(a===THREE.LinearFilter)return r.LINEAR;
-if(a===THREE.LinearMipMapNearestFilter)return r.LINEAR_MIPMAP_NEAREST;if(a===THREE.LinearMipMapLinearFilter)return r.LINEAR_MIPMAP_LINEAR;if(a===THREE.UnsignedByteType)return r.UNSIGNED_BYTE;if(a===THREE.UnsignedShort4444Type)return r.UNSIGNED_SHORT_4_4_4_4;if(a===THREE.UnsignedShort5551Type)return r.UNSIGNED_SHORT_5_5_5_1;if(a===THREE.UnsignedShort565Type)return r.UNSIGNED_SHORT_5_6_5;if(a===THREE.ByteType)return r.BYTE;if(a===THREE.ShortType)return r.SHORT;if(a===THREE.UnsignedShortType)return r.UNSIGNED_SHORT;
-if(a===THREE.IntType)return r.INT;if(a===THREE.UnsignedIntType)return r.UNSIGNED_INT;if(a===THREE.FloatType)return r.FLOAT;b=V.get("OES_texture_half_float");if(null!==b&&a===THREE.HalfFloatType)return b.HALF_FLOAT_OES;if(a===THREE.AlphaFormat)return r.ALPHA;if(a===THREE.RGBFormat)return r.RGB;if(a===THREE.RGBAFormat)return r.RGBA;if(a===THREE.LuminanceFormat)return r.LUMINANCE;if(a===THREE.LuminanceAlphaFormat)return r.LUMINANCE_ALPHA;if(a===THREE.AddEquation)return r.FUNC_ADD;if(a===THREE.SubtractEquation)return r.FUNC_SUBTRACT;
-if(a===THREE.ReverseSubtractEquation)return r.FUNC_REVERSE_SUBTRACT;if(a===THREE.ZeroFactor)return r.ZERO;if(a===THREE.OneFactor)return r.ONE;if(a===THREE.SrcColorFactor)return r.SRC_COLOR;if(a===THREE.OneMinusSrcColorFactor)return r.ONE_MINUS_SRC_COLOR;if(a===THREE.SrcAlphaFactor)return r.SRC_ALPHA;if(a===THREE.OneMinusSrcAlphaFactor)return r.ONE_MINUS_SRC_ALPHA;if(a===THREE.DstAlphaFactor)return r.DST_ALPHA;if(a===THREE.OneMinusDstAlphaFactor)return r.ONE_MINUS_DST_ALPHA;if(a===THREE.DstColorFactor)return r.DST_COLOR;
-if(a===THREE.OneMinusDstColorFactor)return r.ONE_MINUS_DST_COLOR;if(a===THREE.SrcAlphaSaturateFactor)return r.SRC_ALPHA_SATURATE;b=V.get("WEBGL_compressed_texture_s3tc");if(null!==b){if(a===THREE.RGB_S3TC_DXT1_Format)return b.COMPRESSED_RGB_S3TC_DXT1_EXT;if(a===THREE.RGBA_S3TC_DXT1_Format)return b.COMPRESSED_RGBA_S3TC_DXT1_EXT;if(a===THREE.RGBA_S3TC_DXT3_Format)return b.COMPRESSED_RGBA_S3TC_DXT3_EXT;if(a===THREE.RGBA_S3TC_DXT5_Format)return b.COMPRESSED_RGBA_S3TC_DXT5_EXT}b=V.get("WEBGL_compressed_texture_pvrtc");
-if(null!==b){if(a===THREE.RGB_PVRTC_4BPPV1_Format)return b.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;if(a===THREE.RGB_PVRTC_2BPPV1_Format)return b.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;if(a===THREE.RGBA_PVRTC_4BPPV1_Format)return b.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;if(a===THREE.RGBA_PVRTC_2BPPV1_Format)return b.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG}b=V.get("EXT_blend_minmax");if(null!==b){if(a===THREE.MinEquation)return b.MIN_EXT;if(a===THREE.MaxEquation)return b.MAX_EXT}return 0}console.log("THREE.WebGLRenderer",THREE.REVISION);
-a=a||{};var w=void 0!==a.canvas?a.canvas:document.createElement("canvas"),x=void 0!==a.context?a.context:null,A=w.width,y=w.height,D=1,I=void 0!==a.precision?a.precision:"highp",v=void 0!==a.alpha?a.alpha:!1,E=void 0!==a.depth?a.depth:!0,L=void 0!==a.stencil?a.stencil:!0,C=void 0!==a.antialias?a.antialias:!1,F=void 0!==a.premultipliedAlpha?a.premultipliedAlpha:!0,R=void 0!==a.preserveDrawingBuffer?a.preserveDrawingBuffer:!1,J=void 0!==a.logarithmicDepthBuffer?a.logarithmicDepthBuffer:!1,z=new THREE.Color(0),
-G=0,B=[],T=[],O=[],S=[],P=[];this.domElement=w;this.context=null;this.sortObjects=this.autoClearStencil=this.autoClearDepth=this.autoClearColor=this.autoClear=!0;this.gammaFactor=2;this.gammaOutput=this.gammaInput=!1;this.maxMorphTargets=8;this.maxMorphNormals=4;this.autoScaleCubemaps=!0;this.info={memory:{programs:0,geometries:0,textures:0},render:{calls:0,vertices:0,faces:0,points:0}};var H=this,K=[],na=null,da=null,ka=-1,ja="",ua=null,Va=0,ma=0,Ga=0,Fa=w.width,ya=w.height,Ta=0,ra=0,Ha=new THREE.Frustum,
-za=new THREE.Matrix4,ia=new THREE.Vector3,ca=new THREE.Vector3,Xa=!0,Gb={ambient:[0,0,0],directional:{length:0,colors:[],positions:[]},point:{length:0,colors:[],positions:[],distances:[],decays:[]},spot:{length:0,colors:[],positions:[],distances:[],directions:[],anglesCos:[],exponents:[],decays:[]},hemi:{length:0,skyColors:[],groundColors:[],positions:[]}},r;try{a={alpha:v,depth:E,stencil:L,antialias:C,premultipliedAlpha:F,preserveDrawingBuffer:R};r=x||w.getContext("webgl",a)||w.getContext("experimental-webgl",
-a);if(null===r){if(null!==w.getContext("webgl"))throw"Error creating WebGL context with your selected attributes.";throw"Error creating WebGL context.";}w.addEventListener("webglcontextlost",function(a){a.preventDefault();Ua();$a();ha.objects={}},!1)}catch(zb){console.error("THREE.WebGLRenderer: "+zb)}var Q=new THREE.WebGLState(r,u);void 0===r.getShaderPrecisionFormat&&(r.getShaderPrecisionFormat=function(){return{rangeMin:1,rangeMax:1,precision:1}});var V=new THREE.WebGLExtensions(r),ha=new THREE.WebGLObjects(r,
-this.info);V.get("OES_texture_float");V.get("OES_texture_float_linear");V.get("OES_texture_half_float");V.get("OES_texture_half_float_linear");V.get("OES_standard_derivatives");V.get("ANGLE_instanced_arrays");V.get("OES_element_index_uint")&&(THREE.BufferGeometry.MaxIndex=4294967296);J&&V.get("EXT_frag_depth");var Ma=function(a,b,c,d){!0===F&&(a*=d,b*=d,c*=d);r.clearColor(a,b,c,d)},$a=function(){r.clearColor(0,0,0,1);r.clearDepth(1);r.clearStencil(0);r.enable(r.DEPTH_TEST);r.depthFunc(r.LEQUAL);r.frontFace(r.CCW);
-r.cullFace(r.BACK);r.enable(r.CULL_FACE);r.enable(r.BLEND);r.blendEquation(r.FUNC_ADD);r.blendFunc(r.SRC_ALPHA,r.ONE_MINUS_SRC_ALPHA);r.viewport(ma,Ga,Fa,ya);Ma(z.r,z.g,z.b,G)},Ua=function(){ua=na=null;ja="";ka=-1;Xa=!0;Q.reset()};$a();this.context=r;this.extensions=V;this.state=Q;var ga=new THREE.WebGLShadowMap(this,B,ha);this.shadowMap=ga;var Sa=r.getParameter(r.MAX_TEXTURE_IMAGE_UNITS),x=r.getParameter(r.MAX_VERTEX_TEXTURE_IMAGE_UNITS),Ab=r.getParameter(r.MAX_TEXTURE_SIZE),Ub=r.getParameter(r.MAX_CUBE_MAP_TEXTURE_SIZE),
-cb=0<x,bb=cb&&V.get("OES_texture_float"),Bb=V.get("ANGLE_instanced_arrays"),v=r.getShaderPrecisionFormat(r.VERTEX_SHADER,r.HIGH_FLOAT),x=r.getShaderPrecisionFormat(r.VERTEX_SHADER,r.MEDIUM_FLOAT),E=r.getShaderPrecisionFormat(r.FRAGMENT_SHADER,r.HIGH_FLOAT);a=r.getShaderPrecisionFormat(r.FRAGMENT_SHADER,r.MEDIUM_FLOAT);var Rb=function(){var a;return function(){if(void 0!==a)return a;a=[];if(V.get("WEBGL_compressed_texture_pvrtc")||V.get("WEBGL_compressed_texture_s3tc"))for(var b=r.getParameter(r.COMPRESSED_TEXTURE_FORMATS),
-c=0;c<b.length;c++)a.push(b[c]);return a}}(),v=0<v.precision&&0<E.precision,x=0<x.precision&&0<a.precision;"highp"!==I||v||(x?(I="mediump",console.warn("THREE.WebGLRenderer: highp not supported, using mediump.")):(I="lowp",console.warn("THREE.WebGLRenderer: highp and mediump not supported, using lowp.")));"mediump"!==I||x||(I="lowp",console.warn("THREE.WebGLRenderer: mediump not supported, using lowp."));var Cb=new THREE.SpritePlugin(this,S),Db=new THREE.LensFlarePlugin(this,P);this.getContext=function(){return r};
-this.forceContextLoss=function(){V.get("WEBGL_lose_context").loseContext()};this.supportsVertexTextures=function(){return cb};this.supportsInstancedArrays=function(){return Bb};this.supportsFloatTextures=function(){return V.get("OES_texture_float")};this.supportsHalfFloatTextures=function(){return V.get("OES_texture_half_float")};this.supportsStandardDerivatives=function(){return V.get("OES_standard_derivatives")};this.supportsCompressedTextureS3TC=function(){return V.get("WEBGL_compressed_texture_s3tc")};
-this.supportsCompressedTexturePVRTC=function(){return V.get("WEBGL_compressed_texture_pvrtc")};this.supportsBlendMinMax=function(){return V.get("EXT_blend_minmax")};this.getMaxAnisotropy=function(){var a;return function(){if(void 0!==a)return a;var b=V.get("EXT_texture_filter_anisotropic");return a=null!==b?r.getParameter(b.MAX_TEXTURE_MAX_ANISOTROPY_EXT):0}}();this.getPrecision=function(){return I};this.getPixelRatio=function(){return D};this.setPixelRatio=function(a){void 0!==a&&(D=a)};this.getSize=
-function(){return{width:A,height:y}};this.setSize=function(a,b,c){A=a;y=b;w.width=a*D;w.height=b*D;!1!==c&&(w.style.width=a+"px",w.style.height=b+"px");this.setViewport(0,0,a,b)};this.setViewport=function(a,b,c,d){ma=a*D;Ga=b*D;Fa=c*D;ya=d*D;r.viewport(ma,Ga,Fa,ya)};this.setScissor=function(a,b,c,d){r.scissor(a*D,b*D,c*D,d*D)};this.enableScissorTest=function(a){a?r.enable(r.SCISSOR_TEST):r.disable(r.SCISSOR_TEST)};this.getClearColor=function(){return z};this.setClearColor=function(a,b){z.set(a);G=
-void 0!==b?b:1;Ma(z.r,z.g,z.b,G)};this.getClearAlpha=function(){return G};this.setClearAlpha=function(a){G=a;Ma(z.r,z.g,z.b,G)};this.clear=function(a,b,c){var d=0;if(void 0===a||a)d|=r.COLOR_BUFFER_BIT;if(void 0===b||b)d|=r.DEPTH_BUFFER_BIT;if(void 0===c||c)d|=r.STENCIL_BUFFER_BIT;r.clear(d)};this.clearColor=function(){r.clear(r.COLOR_BUFFER_BIT)};this.clearDepth=function(){r.clear(r.DEPTH_BUFFER_BIT)};this.clearStencil=function(){r.clear(r.STENCIL_BUFFER_BIT)};this.clearTarget=function(a,b,c,d){this.setRenderTarget(a);
-this.clear(b,c,d)};this.resetGLState=Ua;var wb=function(a){a=a.target;a.removeEventListener("dispose",wb);a.image&&a.image.__webglTextureCube?(r.deleteTexture(a.image.__webglTextureCube),delete a.image.__webglTextureCube):void 0!==a.__webglInit&&(r.deleteTexture(a.__webglTexture),delete a.__webglTexture,delete a.__webglInit);H.info.memory.textures--},ab=function(a){a=a.target;a.removeEventListener("dispose",ab);if(a&&void 0!==a.__webglTexture){r.deleteTexture(a.__webglTexture);delete a.__webglTexture;
-if(a instanceof THREE.WebGLRenderTargetCube)for(var b=0;6>b;b++)r.deleteFramebuffer(a.__webglFramebuffer[b]),r.deleteRenderbuffer(a.__webglRenderbuffer[b]);else r.deleteFramebuffer(a.__webglFramebuffer),r.deleteRenderbuffer(a.__webglRenderbuffer);delete a.__webglFramebuffer;delete a.__webglRenderbuffer}H.info.memory.textures--},Eb=function(a){a=a.target;a.removeEventListener("dispose",Eb);Fb(a)},Fb=function(a){var b=a.program.program;if(void 0!==b){a.program=void 0;var c,d,e=!1;a=0;for(c=K.length;a<
-c;a++)if(d=K[a],d.program===b){d.usedTimes--;0===d.usedTimes&&(e=!0);break}if(!0===e){e=[];a=0;for(c=K.length;a<c;a++)d=K[a],d.program!==b&&e.push(d);K=e;r.deleteProgram(b);H.info.memory.programs--}}};this.renderBufferImmediate=function(a,b,c){Q.initAttributes();a.hasPositions&&!a.__webglVertexBuffer&&(a.__webglVertexBuffer=r.createBuffer());a.hasNormals&&!a.__webglNormalBuffer&&(a.__webglNormalBuffer=r.createBuffer());a.hasUvs&&!a.__webglUvBuffer&&(a.__webglUvBuffer=r.createBuffer());a.hasColors&&
-!a.__webglColorBuffer&&(a.__webglColorBuffer=r.createBuffer());a.hasPositions&&(r.bindBuffer(r.ARRAY_BUFFER,a.__webglVertexBuffer),r.bufferData(r.ARRAY_BUFFER,a.positionArray,r.DYNAMIC_DRAW),Q.enableAttribute(b.attributes.position),r.vertexAttribPointer(b.attributes.position,3,r.FLOAT,!1,0,0));if(a.hasNormals){r.bindBuffer(r.ARRAY_BUFFER,a.__webglNormalBuffer);if(!1===c instanceof THREE.MeshPhongMaterial&&c.shading===THREE.FlatShading){var d,e,f,g,h,k,m,l,n,p,q,s=3*a.count;for(q=0;q<s;q+=9)p=a.normalArray,
-d=p[q],e=p[q+1],f=p[q+2],g=p[q+3],k=p[q+4],l=p[q+5],h=p[q+6],m=p[q+7],n=p[q+8],d=(d+g+h)/3,e=(e+k+m)/3,f=(f+l+n)/3,p[q]=d,p[q+1]=e,p[q+2]=f,p[q+3]=d,p[q+4]=e,p[q+5]=f,p[q+6]=d,p[q+7]=e,p[q+8]=f}r.bufferData(r.ARRAY_BUFFER,a.normalArray,r.DYNAMIC_DRAW);Q.enableAttribute(b.attributes.normal);r.vertexAttribPointer(b.attributes.normal,3,r.FLOAT,!1,0,0)}a.hasUvs&&c.map&&(r.bindBuffer(r.ARRAY_BUFFER,a.__webglUvBuffer),r.bufferData(r.ARRAY_BUFFER,a.uvArray,r.DYNAMIC_DRAW),Q.enableAttribute(b.attributes.uv),
-r.vertexAttribPointer(b.attributes.uv,2,r.FLOAT,!1,0,0));a.hasColors&&c.vertexColors!==THREE.NoColors&&(r.bindBuffer(r.ARRAY_BUFFER,a.__webglColorBuffer),r.bufferData(r.ARRAY_BUFFER,a.colorArray,r.DYNAMIC_DRAW),Q.enableAttribute(b.attributes.color),r.vertexAttribPointer(b.attributes.color,3,r.FLOAT,!1,0,0));Q.disableUnusedAttributes();r.drawArrays(r.TRIANGLES,0,a.count);a.count=0};this.renderBufferDirect=function(a,c,d,e,f){if(!1!==e.visible){var g=ha.geometries.get(f);a=k(a,c,d,e,f);c=!1;d=g.id+
-"_"+a.id+"_"+(e.wireframe?1:0);d!==ja&&(ja=d,c=!0);c&&Q.initAttributes();if(f instanceof THREE.Mesh)a:if(f=c,c=!0===e.wireframe?r.LINES:r.TRIANGLES,d=g.attributes.index){var h,m;d.array instanceof Uint32Array&&V.get("OES_element_index_uint")?(h=r.UNSIGNED_INT,m=4):(h=r.UNSIGNED_SHORT,m=2);var l=g.offsets;if(0===l.length){f&&(b(e,a,g,0),r.bindBuffer(r.ELEMENT_ARRAY_BUFFER,d.buffer));if(g instanceof THREE.InstancedBufferGeometry&&0<g.maxInstancedCount){var n=V.get("ANGLE_instanced_arrays");if(null===
-n){console.error("THREE.WebGLRenderer.renderMesh: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.");break a}n.drawElementsInstancedANGLE(c,d.array.length,h,0,g.maxInstancedCount)}else r.drawElements(c,d.array.length,h,0);H.info.render.calls++;H.info.render.vertices+=d.array.length;H.info.render.faces+=d.array.length/3}else{f=!0;for(var p=0,q=l.length;p<q;p++){n=l[p].index;f&&(b(e,a,g,n),r.bindBuffer(r.ELEMENT_ARRAY_BUFFER,d.buffer));if(g instanceof
-THREE.InstancedBufferGeometry&&0<l[p].instances){n=V.get("ANGLE_instanced_arrays");if(null===n){console.error("THREE.WebGLRenderer.renderMesh: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.");break a}n.drawElementsInstancedANGLE(c,l[p].count,h,l[p].start*m,l[p].count,h,l[p].instances)}else r.drawElements(c,l[p].count,h,l[p].start*m);H.info.render.calls++;H.info.render.vertices+=l[p].count;H.info.render.faces+=l[p].count/3}}}else if(l=g.offsets,
-0===l.length){f&&b(e,a,g,0);e=g.attributes.position;if(g instanceof THREE.InstancedBufferGeometry&&0<g.maxInstancedCount){n=V.get("ANGLE_instanced_arrays");if(null===n){console.error("THREE.WebGLRenderer.renderMesh: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.");break a}e instanceof THREE.InterleavedBufferAttribute?n.drawArraysInstancedANGLE(c,0,e.data.array.length/e.data.stride,g.maxInstancedCount):n.drawArraysInstancedANGLE(c,0,e.array.length/
-e.itemSize,g.maxInstancedCount)}else e instanceof THREE.InterleavedBufferAttribute?r.drawArrays(c,0,e.data.array.length/e.data.stride):r.drawArrays(c,0,e.array.length/e.itemSize);H.info.render.calls++;H.info.render.vertices+=e.array.length/e.itemSize;H.info.render.faces+=e.array.length/(3*e.itemSize)}else for(f&&b(e,a,g,0),p=0,q=l.length;p<q;p++){if(g instanceof THREE.InstancedBufferGeometry){console.error("THREE.WebGLRenderer.renderMesh: cannot use drawCalls with THREE.InstancedBufferGeometry.");
-break a}else r.drawArrays(c,l[p].start,l[p].count);H.info.render.calls++;H.info.render.vertices+=l[p].count;H.info.render.faces+=l[p].count/3}else if(f instanceof THREE.Line)if(f=f instanceof THREE.LineSegments?r.LINES:r.LINE_STRIP,Q.setLineWidth((void 0!==e.linewidth?e.linewidth:1)*D),h=g.attributes.index)if(h.array instanceof Uint32Array&&V.get("OES_element_index_uint")?(m=r.UNSIGNED_INT,l=4):(m=r.UNSIGNED_SHORT,l=2),d=g.offsets,0===d.length)c&&(b(e,a,g,0),r.bindBuffer(r.ELEMENT_ARRAY_BUFFER,h.buffer)),
-r.drawElements(f,h.array.length,m,0),H.info.render.calls++,H.info.render.vertices+=h.array.length;else for(1<d.length&&(c=!0),n=0,p=d.length;n<p;n++)q=d[n].index,c&&(b(e,a,g,q),r.bindBuffer(r.ELEMENT_ARRAY_BUFFER,h.buffer)),r.drawElements(f,d[n].count,m,d[n].start*l),H.info.render.calls++,H.info.render.vertices+=d[n].count;else if(c&&b(e,a,g,0),e=g.attributes.position,d=g.offsets,0===d.length)r.drawArrays(f,0,e.array.length/3),H.info.render.calls++,H.info.render.vertices+=e.array.length/3;else for(n=
-0,p=d.length;n<p;n++)r.drawArrays(f,d[n].index,d[n].count),H.info.render.calls++,H.info.render.vertices+=d[n].count;else if(f instanceof THREE.PointCloud)if(d=c,c=r.POINTS,h=g.attributes.index)if(h.array instanceof Uint32Array&&V.get("OES_element_index_uint")?(m=r.UNSIGNED_INT,l=4):(m=r.UNSIGNED_SHORT,l=2),f=g.offsets,0===f.length)d&&(b(e,a,g,0),r.bindBuffer(r.ELEMENT_ARRAY_BUFFER,h.buffer)),r.drawElements(c,h.array.length,m,0),H.info.render.calls++,H.info.render.points+=h.array.length;else for(1<
-f.length&&(d=!0),n=0,p=f.length;n<p;n++)q=f[n].index,d&&(b(e,a,g,q),r.bindBuffer(r.ELEMENT_ARRAY_BUFFER,h.buffer)),r.drawElements(c,f[n].count,m,f[n].start*l),H.info.render.calls++,H.info.render.points+=f[n].count;else if(d&&b(e,a,g,0),e=g.attributes.position,f=g.offsets,0===f.length)r.drawArrays(c,0,e.array.length/3),H.info.render.calls++,H.info.render.points+=e.array.length/3;else for(n=0,p=f.length;n<p;n++)r.drawArrays(c,f[n].index,f[n].count),H.info.render.calls++,H.info.render.points+=f[n].count}};
-this.render=function(a,b,k,m){if(!1===b instanceof THREE.Camera)console.error("THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.");else{var l=a.fog;ja="";ka=-1;ua=null;Xa=!0;!0===a.autoUpdate&&a.updateMatrixWorld();void 0===b.parent&&b.updateMatrixWorld();b.matrixWorldInverse.getInverse(b.matrixWorld);za.multiplyMatrices(b.projectionMatrix,b.matrixWorldInverse);Ha.setFromMatrix(za);B.length=0;T.length=0;O.length=0;S.length=0;P.length=0;e(a);!0===H.sortObjects&&(T.sort(c),O.sort(d));
-ha.update(T);ha.update(O);ga.render(a,b);H.info.render.calls=0;H.info.render.vertices=0;H.info.render.faces=0;H.info.render.points=0;this.setRenderTarget(k);(this.autoClear||m)&&this.clear(this.autoClearColor,this.autoClearDepth,this.autoClearStencil);m=0;for(var n=ha.objectsImmediate.length;m<n;m++){var p=ha.objectsImmediate[m],q=p.object;if(!0===q.visible){var s=q;s._modelViewMatrix.multiplyMatrices(b.matrixWorldInverse,s.matrixWorld);s._normalMatrix.getNormalMatrix(s._modelViewMatrix);q=q.material;
-q.transparent?(p.transparent=q,p.opaque=null):(p.opaque=q,p.transparent=null)}}a.overrideMaterial?(m=a.overrideMaterial,h(m),f(T,b,B,l,m),f(O,b,B,l,m),g(ha.objectsImmediate,"",b,B,l,m)):(Q.setBlending(THREE.NoBlending),f(T,b,B,l,null),g(ha.objectsImmediate,"opaque",b,B,l,null),f(O,b,B,l,null),g(ha.objectsImmediate,"transparent",b,B,l,null));Cb.render(a,b);Db.render(a,b,Ta,ra);k&&k.generateMipmaps&&k.minFilter!==THREE.NearestFilter&&k.minFilter!==THREE.LinearFilter&&(k instanceof THREE.WebGLRenderTargetCube?
-(Q.bindTexture(r.TEXTURE_CUBE_MAP,k.__webglTexture),r.generateMipmap(r.TEXTURE_CUBE_MAP),Q.bindTexture(r.TEXTURE_CUBE_MAP,null)):(Q.bindTexture(r.TEXTURE_2D,k.__webglTexture),r.generateMipmap(r.TEXTURE_2D),Q.bindTexture(r.TEXTURE_2D,null)));Q.setDepthTest(!0);Q.setDepthWrite(!0);Q.setColorWrite(!0)}};this.renderImmediateObject=function(a,b,c,d,e){var f=k(a,b,c,d,e);ja="";H.setMaterialFaces(d);e.immediateRenderCallback?e.immediateRenderCallback(f,r,Ha):e.render(function(a){H.renderBufferImmediate(a,
-f,d)})};var Sb={MeshDepthMaterial:"depth",MeshNormalMaterial:"normal",MeshBasicMaterial:"basic",MeshLambertMaterial:"lambert",MeshPhongMaterial:"phong",LineBasicMaterial:"basic",LineDashedMaterial:"dashed",PointCloudMaterial:"particle_basic"};this.setFaceCulling=function(a,b){a===THREE.CullFaceNone?r.disable(r.CULL_FACE):(b===THREE.FrontFaceDirectionCW?r.frontFace(r.CW):r.frontFace(r.CCW),a===THREE.CullFaceBack?r.cullFace(r.BACK):a===THREE.CullFaceFront?r.cullFace(r.FRONT):r.cullFace(r.FRONT_AND_BACK),
-r.enable(r.CULL_FACE))};this.setMaterialFaces=function(a){Q.setDoubleSided(a.side===THREE.DoubleSide);Q.setFlipSided(a.side===THREE.BackSide)};this.uploadTexture=function(a,b){void 0===a.__webglInit&&(a.__webglInit=!0,a.addEventListener("dispose",wb),a.__webglTexture=r.createTexture(),H.info.memory.textures++);Q.activeTexture(r.TEXTURE0+b);Q.bindTexture(r.TEXTURE_2D,a.__webglTexture);r.pixelStorei(r.UNPACK_FLIP_Y_WEBGL,a.flipY);r.pixelStorei(r.UNPACK_PREMULTIPLY_ALPHA_WEBGL,a.premultiplyAlpha);r.pixelStorei(r.UNPACK_ALIGNMENT,
-a.unpackAlignment);a.image=q(a.image,Ab);var c=a.image,d=THREE.Math.isPowerOfTwo(c.width)&&THREE.Math.isPowerOfTwo(c.height),e=u(a.format),f=u(a.type);m(r.TEXTURE_2D,a,d);var g=a.mipmaps;if(a instanceof THREE.DataTexture)if(0<g.length&&d){for(var h=0,k=g.length;h<k;h++)c=g[h],Q.texImage2D(r.TEXTURE_2D,h,e,c.width,c.height,0,e,f,c.data);a.generateMipmaps=!1}else Q.texImage2D(r.TEXTURE_2D,0,e,c.width,c.height,0,e,f,c.data);else if(a instanceof THREE.CompressedTexture)for(h=0,k=g.length;h<k;h++)c=g[h],
-a.format!==THREE.RGBAFormat&&a.format!==THREE.RGBFormat?-1<Rb().indexOf(e)?Q.compressedTexImage2D(r.TEXTURE_2D,h,e,c.width,c.height,0,c.data):console.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()"):Q.texImage2D(r.TEXTURE_2D,h,e,c.width,c.height,0,e,f,c.data);else if(0<g.length&&d){h=0;for(k=g.length;h<k;h++)c=g[h],Q.texImage2D(r.TEXTURE_2D,h,e,e,f,c);a.generateMipmaps=!1}else Q.texImage2D(r.TEXTURE_2D,0,e,e,f,a.image);a.generateMipmaps&&d&&r.generateMipmap(r.TEXTURE_2D);
-a.needsUpdate=!1;if(a.onUpdate)a.onUpdate(a)};this.setTexture=function(a,b){if(!0===a.needsUpdate){var c=a.image;void 0===c?console.warn("THREE.WebGLRenderer: Texture marked for update but image is undefined",a):!1===c.complete?console.warn("THREE.WebGLRenderer: Texture marked for update but image is incomplete",a):H.uploadTexture(a,b)}else Q.activeTexture(r.TEXTURE0+b),Q.bindTexture(r.TEXTURE_2D,a.__webglTexture)};this.setRenderTarget=function(a){var b=a instanceof THREE.WebGLRenderTargetCube;if(a&&
-void 0===a.__webglFramebuffer){void 0===a.depthBuffer&&(a.depthBuffer=!0);void 0===a.stencilBuffer&&(a.stencilBuffer=!0);a.addEventListener("dispose",ab);a.__webglTexture=r.createTexture();H.info.memory.textures++;var c=THREE.Math.isPowerOfTwo(a.width)&&THREE.Math.isPowerOfTwo(a.height),d=u(a.format),e=u(a.type);if(b){a.__webglFramebuffer=[];a.__webglRenderbuffer=[];Q.bindTexture(r.TEXTURE_CUBE_MAP,a.__webglTexture);m(r.TEXTURE_CUBE_MAP,a,c);for(var f=0;6>f;f++){a.__webglFramebuffer[f]=r.createFramebuffer();
-a.__webglRenderbuffer[f]=r.createRenderbuffer();Q.texImage2D(r.TEXTURE_CUBE_MAP_POSITIVE_X+f,0,d,a.width,a.height,0,d,e,null);var g=a,h=r.TEXTURE_CUBE_MAP_POSITIVE_X+f;r.bindFramebuffer(r.FRAMEBUFFER,a.__webglFramebuffer[f]);r.framebufferTexture2D(r.FRAMEBUFFER,r.COLOR_ATTACHMENT0,h,g.__webglTexture,0);t(a.__webglRenderbuffer[f],a)}a.generateMipmaps&&c&&r.generateMipmap(r.TEXTURE_CUBE_MAP)}else a.__webglFramebuffer=r.createFramebuffer(),a.__webglRenderbuffer=a.shareDepthFrom?a.shareDepthFrom.__webglRenderbuffer:
-r.createRenderbuffer(),Q.bindTexture(r.TEXTURE_2D,a.__webglTexture),m(r.TEXTURE_2D,a,c),Q.texImage2D(r.TEXTURE_2D,0,d,a.width,a.height,0,d,e,null),d=r.TEXTURE_2D,r.bindFramebuffer(r.FRAMEBUFFER,a.__webglFramebuffer),r.framebufferTexture2D(r.FRAMEBUFFER,r.COLOR_ATTACHMENT0,d,a.__webglTexture,0),a.shareDepthFrom?a.depthBuffer&&!a.stencilBuffer?r.framebufferRenderbuffer(r.FRAMEBUFFER,r.DEPTH_ATTACHMENT,r.RENDERBUFFER,a.__webglRenderbuffer):a.depthBuffer&&a.stencilBuffer&&r.framebufferRenderbuffer(r.FRAMEBUFFER,
-r.DEPTH_STENCIL_ATTACHMENT,r.RENDERBUFFER,a.__webglRenderbuffer):t(a.__webglRenderbuffer,a),a.generateMipmaps&&c&&r.generateMipmap(r.TEXTURE_2D);b?Q.bindTexture(r.TEXTURE_CUBE_MAP,null):Q.bindTexture(r.TEXTURE_2D,null);r.bindRenderbuffer(r.RENDERBUFFER,null);r.bindFramebuffer(r.FRAMEBUFFER,null)}a?(b=b?a.__webglFramebuffer[a.activeCubeFace]:a.__webglFramebuffer,c=a.width,a=a.height,e=d=0):(b=null,c=Fa,a=ya,d=ma,e=Ga);b!==da&&(r.bindFramebuffer(r.FRAMEBUFFER,b),r.viewport(d,e,c,a),da=b);Ta=c;ra=a};
-this.readRenderTargetPixels=function(a,b,c,d,e,f){if(!(a instanceof THREE.WebGLRenderTarget))console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");else if(a.__webglFramebuffer)if(a.format!==THREE.RGBAFormat)console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA format. readPixels can read only RGBA format.");else{var g=!1;a.__webglFramebuffer!==da&&(r.bindFramebuffer(r.FRAMEBUFFER,a.__webglFramebuffer),g=!0);r.checkFramebufferStatus(r.FRAMEBUFFER)===
-r.FRAMEBUFFER_COMPLETE?r.readPixels(b,c,d,e,r.RGBA,r.UNSIGNED_BYTE,f):console.error("THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.");g&&r.bindFramebuffer(r.FRAMEBUFFER,da)}};this.initMaterial=function(){console.warn("THREE.WebGLRenderer: .initMaterial() has been removed.")};this.addPrePlugin=function(){console.warn("THREE.WebGLRenderer: .addPrePlugin() has been removed.")};this.addPostPlugin=function(){console.warn("THREE.WebGLRenderer: .addPostPlugin() has been removed.")};
-this.updateShadowMap=function(){console.warn("THREE.WebGLRenderer: .updateShadowMap() has been removed.")};Object.defineProperties(this,{shadowMapEnabled:{get:function(){return ga.enabled},set:function(a){console.warn("THREE.WebGLRenderer: .shadowMapEnabled is now .shadowMap.enabled.");ga.enabled=a}},shadowMapType:{get:function(){return ga.type},set:function(a){console.warn("THREE.WebGLRenderer: .shadowMapType is now .shadowMap.type.");ga.type=a}},shadowMapCullFace:{get:function(){return ga.cullFace},
-set:function(a){console.warn("THREE.WebGLRenderer: .shadowMapCullFace is now .shadowMap.cullFace.");ga.cullFace=a}},shadowMapDebug:{get:function(){return ga.debug},set:function(a){console.warn("THREE.WebGLRenderer: .shadowMapDebug is now .shadowMap.debug.");ga.debug=a}},shadowMapCascade:{get:function(){return ga.cascade},set:function(a){console.warn("THREE.WebGLRenderer: .shadowMapCascade is now .shadowMap.cascade.");ga.cascade=a}}})};
+THREE.WebGLRenderer=function(a){function b(a,b,c,d){var e;if(c instanceof THREE.InstancedBufferGeometry&&(e=V.get("ANGLE_instanced_arrays"),null===e)){console.error("THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.");return}var g=c.attributes;b=b.getAttributes();a=a.defaultAttributeValues;for(var f in b){var h=b[f];if(0<=h){var k=g[f];if(void 0!==k){var l=k.itemSize;Q.enableAttribute(h);if(k instanceof THREE.InterleavedBufferAttribute){var m=
+k.data,n=m.stride,p=k.offset;r.bindBuffer(r.ARRAY_BUFFER,k.data.buffer);r.vertexAttribPointer(h,l,r.FLOAT,!1,n*m.array.BYTES_PER_ELEMENT,(d*n+p)*m.array.BYTES_PER_ELEMENT);if(m instanceof THREE.InstancedInterleavedBuffer){if(null===e){console.error("THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferAttribute but hardware does not support extension ANGLE_instanced_arrays.");return}e.vertexAttribDivisorANGLE(h,m.meshPerAttribute);void 0===c.maxInstancedCount&&(c.maxInstancedCount=
+m.array.length/m.stride*m.meshPerAttribute)}}else if(r.bindBuffer(r.ARRAY_BUFFER,k.buffer),r.vertexAttribPointer(h,l,r.FLOAT,!1,0,d*l*4),k instanceof THREE.InstancedBufferAttribute){if(null===e){console.error("THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferAttribute but hardware does not support extension ANGLE_instanced_arrays.");return}e.vertexAttribDivisorANGLE(h,k.meshPerAttribute);void 0===c.maxInstancedCount&&(c.maxInstancedCount=k.array.length/k.itemSize*k.meshPerAttribute)}}else if(void 0!==
+a&&(k=a[f],void 0!==k))switch(k.length){case 2:r.vertexAttrib2fv(h,k);break;case 3:r.vertexAttrib3fv(h,k);break;case 4:r.vertexAttrib4fv(h,k);break;default:r.vertexAttrib1fv(h,k)}}}Q.disableUnusedAttributes()}function c(a,b){return a.object.renderOrder!==b.object.renderOrder?a.object.renderOrder-b.object.renderOrder:a.object.material.id!==b.object.material.id?a.object.material.id-b.object.material.id:a.z!==b.z?a.z-b.z:a.id-b.id}function d(a,b){return a.object.renderOrder!==b.object.renderOrder?a.object.renderOrder-
+b.object.renderOrder:a.z!==b.z?b.z-a.z:a.id-b.id}function e(a){if(!0===a.visible){if(!(a instanceof THREE.Scene||a instanceof THREE.Group))if(a instanceof THREE.SkinnedMesh&&a.skeleton.update(),ga.init(a),a instanceof THREE.Light)B.push(a);else if(a instanceof THREE.Sprite)S.push(a);else if(a instanceof THREE.LensFlare)P.push(a);else{var b=ga.objects[a.id];!b||!1!==a.frustumCulled&&!0!==Ha.intersectsObject(a)||(a.material.transparent?O.push(b):T.push(b),!0===H.sortObjects&&(ia.setFromMatrixPosition(a.matrixWorld),
+ia.applyProjection(Ia),b.z=ia.z))}for(var b=0,c=a.children.length;b<c;b++)e(a.children[b])}}function f(a,b,c,d,e){for(var f,g=0,k=a.length;g<k;g++){var l=a[g].object;f=l;f._modelViewMatrix.multiplyMatrices(b.matrixWorldInverse,f.matrixWorld);f._normalMatrix.getNormalMatrix(f._modelViewMatrix);if(e)f=e;else{f=l.material;if(!f)continue;h(f)}H.setMaterialFaces(f);H.renderBufferDirect(b,c,d,f,l)}}function g(a,b,c,d,e,f){for(var g,k=0,l=a.length;k<l;k++){g=a[k];var m=g.object;if(!0===m.visible){if(f)g=
+f;else{g=g[b];if(!g)continue;h(g)}H.renderImmediateObject(c,d,e,g,m)}}}function h(a){!0===a.transparent?Q.setBlending(a.blending,a.blendEquation,a.blendSrc,a.blendDst,a.blendEquationAlpha,a.blendSrcAlpha,a.blendDstAlpha):Q.setBlending(THREE.NoBlending);Q.setDepthFunc(a.depthFunc);Q.setDepthTest(a.depthTest);Q.setDepthWrite(a.depthWrite);Q.setColorWrite(a.colorWrite);Q.setPolygonOffset(a.polygonOffset,a.polygonOffsetFactor,a.polygonOffsetUnits)}function k(a,b,c,d,e){var f,g,h,k;Wa=0;if(d.needsUpdate){a:{for(var s=
+Sb[d.type],t=0,w=0,y=0,v=0,A=0,L=b.length;A<L;A++){var G=b[A];G.onlyShadow||!1===G.visible||(G instanceof THREE.DirectionalLight&&t++,G instanceof THREE.PointLight&&w++,G instanceof THREE.SpotLight&&y++,G instanceof THREE.HemisphereLight&&v++)}f=t;g=w;h=y;k=v;for(var z,D=0,C=0,E=b.length;C<E;C++){var B=b[C];B.castShadow&&(B instanceof THREE.SpotLight&&D++,B instanceof THREE.DirectionalLight&&!B.shadowCascade&&D++)}z=D;var F;if(bb&&e&&e.skeleton&&e.skeleton.useVertexTexture)F=1024;else{var O=r.getParameter(r.MAX_VERTEX_UNIFORM_VECTORS),
+R=Math.floor((O-20)/4);void 0!==e&&e instanceof THREE.SkinnedMesh&&(R=Math.min(e.skeleton.bones.length,R),R<e.skeleton.bones.length&&console.warn("WebGLRenderer: too many bones - "+e.skeleton.bones.length+", this GPU supports just "+R+" (try OpenGL instead of ANGLE)"));F=R}var ja={precision:I,supportsVertexTextures:cb,map:!!d.map,envMap:!!d.envMap,envMapMode:d.envMap&&d.envMap.mapping,lightMap:!!d.lightMap,aoMap:!!d.aoMap,bumpMap:!!d.bumpMap,normalMap:!!d.normalMap,specularMap:!!d.specularMap,alphaMap:!!d.alphaMap,
+combine:d.combine,vertexColors:d.vertexColors,fog:c,useFog:d.fog,fogExp:c instanceof THREE.FogExp2,flatShading:d.shading===THREE.FlatShading,sizeAttenuation:d.sizeAttenuation,logarithmicDepthBuffer:J,skinning:d.skinning,maxBones:F,useVertexTexture:bb&&e&&e.skeleton&&e.skeleton.useVertexTexture,morphTargets:d.morphTargets,morphNormals:d.morphNormals,maxMorphTargets:H.maxMorphTargets,maxMorphNormals:H.maxMorphNormals,maxDirLights:f,maxPointLights:g,maxSpotLights:h,maxHemiLights:k,maxShadows:z,shadowMapEnabled:ha.enabled&&
+e.receiveShadow&&0<z,shadowMapType:ha.type,shadowMapDebug:ha.debug,shadowMapCascade:ha.cascade,alphaTest:d.alphaTest,metal:d.metal,doubleSided:d.side===THREE.DoubleSide,flipSided:d.side===THREE.BackSide},S=[];s?S.push(s):(S.push(d.fragmentShader),S.push(d.vertexShader));if(void 0!==d.defines)for(var P in d.defines)S.push(P),S.push(d.defines[P]);for(P in ja)S.push(P),S.push(ja[P]);var T=S.join();if(!d.program)d.addEventListener("dispose",Eb);else if(d.program.code!==T)Fb(d);else if(void 0!==s)break a;
+else if(d.__webglShader.uniforms===d.uniforms)break a;if(s){var V=THREE.ShaderLib[s];d.__webglShader={uniforms:THREE.UniformsUtils.clone(V.uniforms),vertexShader:V.vertexShader,fragmentShader:V.fragmentShader}}else d.__webglShader={uniforms:d.uniforms,vertexShader:d.vertexShader,fragmentShader:d.fragmentShader};for(var ma,ya=0,Ga=K.length;ya<Ga;ya++){var Ea=K[ya];if(Ea.code===T){ma=Ea;ma.usedTimes++;break}}void 0===ma&&(ma=new THREE.WebGLProgram(H,T,d,ja),K.push(ma),H.info.memory.programs=K.length);
+d.program=ma;var Ta=ma.getAttributes();if(d.morphTargets)for(var ra=d.numSupportedMorphTargets=0;ra<H.maxMorphTargets;ra++)0<=Ta["morphTarget"+ra]&&d.numSupportedMorphTargets++;if(d.morphNormals)for(ra=d.numSupportedMorphNormals=0;ra<H.maxMorphNormals;ra++)0<=Ta["morphNormal"+ra]&&d.numSupportedMorphNormals++;d.uniformsList=[];var da=d.program.getUniforms(),ga;for(ga in d.__webglShader.uniforms){var Ha=da[ga];Ha&&d.uniformsList.push([d.__webglShader.uniforms[ga],Ha])}}d.needsUpdate=!1}var Ia=!1,Fa=
+!1,Xa=!1,Na=d.program,$=Na.getUniforms(),M=d.__webglShader.uniforms;Na.id!==na&&(r.useProgram(Na.program),na=Na.id,Xa=Fa=Ia=!0);d.id!==ka&&(-1===ka&&(Xa=!0),ka=d.id,Fa=!0);if(Ia||a!==ua)r.uniformMatrix4fv($.projectionMatrix,!1,a.projectionMatrix.elements),J&&r.uniform1f($.logDepthBufFC,2/(Math.log(a.far+1)/Math.LN2)),a!==ua&&(ua=a),(d instanceof THREE.ShaderMaterial||d instanceof THREE.MeshPhongMaterial||d.envMap)&&null!==$.cameraPosition&&(ia.setFromMatrixPosition(a.matrixWorld),r.uniform3f($.cameraPosition,
+ia.x,ia.y,ia.z)),(d instanceof THREE.MeshPhongMaterial||d instanceof THREE.MeshLambertMaterial||d instanceof THREE.MeshBasicMaterial||d instanceof THREE.ShaderMaterial||d.skinning)&&null!==$.viewMatrix&&r.uniformMatrix4fv($.viewMatrix,!1,a.matrixWorldInverse.elements);if(d.skinning)if(e.bindMatrix&&null!==$.bindMatrix&&r.uniformMatrix4fv($.bindMatrix,!1,e.bindMatrix.elements),e.bindMatrixInverse&&null!==$.bindMatrixInverse&&r.uniformMatrix4fv($.bindMatrixInverse,!1,e.bindMatrixInverse.elements),bb&&
+e.skeleton&&e.skeleton.useVertexTexture){if(null!==$.boneTexture){var Sa=n();r.uniform1i($.boneTexture,Sa);H.setTexture(e.skeleton.boneTexture,Sa)}null!==$.boneTextureWidth&&r.uniform1i($.boneTextureWidth,e.skeleton.boneTextureWidth);null!==$.boneTextureHeight&&r.uniform1i($.boneTextureHeight,e.skeleton.boneTextureHeight)}else e.skeleton&&e.skeleton.boneMatrices&&null!==$.boneGlobalMatrices&&r.uniformMatrix4fv($.boneGlobalMatrices,!1,e.skeleton.boneMatrices);if(Fa){c&&d.fog&&(M.fogColor.value=c.color,
+c instanceof THREE.Fog?(M.fogNear.value=c.near,M.fogFar.value=c.far):c instanceof THREE.FogExp2&&(M.fogDensity.value=c.density));if(d instanceof THREE.MeshPhongMaterial||d instanceof THREE.MeshLambertMaterial||d.lights){if(Ya){var Xa=!0,Z,oa,Y,db=0,eb=0,fb=0,za,Ua,Va,Ja,gb,aa=Gb,hb=aa.directional.colors,ib=aa.directional.positions,jb=aa.point.colors,kb=aa.point.positions,ab=aa.point.distances,zb=aa.point.decays,lb=aa.spot.colors,mb=aa.spot.positions,Ab=aa.spot.distances,nb=aa.spot.directions,Bb=aa.spot.anglesCos,
+Cb=aa.spot.exponents,Db=aa.spot.decays,ob=aa.hemi.skyColors,pb=aa.hemi.groundColors,qb=aa.hemi.positions,Oa=0,Aa=0,sa=0,Ka=0,rb=0,sb=0,tb=0,Za=0,Pa=0,Qa=0,va=0,La=0;Z=0;for(oa=b.length;Z<oa;Z++)Y=b[Z],Y.onlyShadow||(za=Y.color,Ja=Y.intensity,gb=Y.distance,Y instanceof THREE.AmbientLight?Y.visible&&(db+=za.r,eb+=za.g,fb+=za.b):Y instanceof THREE.DirectionalLight?(rb+=1,Y.visible&&(ca.setFromMatrixPosition(Y.matrixWorld),ia.setFromMatrixPosition(Y.target.matrixWorld),ca.sub(ia),ca.normalize(),Pa=3*
+Oa,ib[Pa+0]=ca.x,ib[Pa+1]=ca.y,ib[Pa+2]=ca.z,p(hb,Pa,za,Ja),Oa+=1)):Y instanceof THREE.PointLight?(sb+=1,Y.visible&&(Qa=3*Aa,p(jb,Qa,za,Ja),ia.setFromMatrixPosition(Y.matrixWorld),kb[Qa+0]=ia.x,kb[Qa+1]=ia.y,kb[Qa+2]=ia.z,ab[Aa]=gb,zb[Aa]=0===Y.distance?0:Y.decay,Aa+=1)):Y instanceof THREE.SpotLight?(tb+=1,Y.visible&&(va=3*sa,p(lb,va,za,Ja),ca.setFromMatrixPosition(Y.matrixWorld),mb[va+0]=ca.x,mb[va+1]=ca.y,mb[va+2]=ca.z,Ab[sa]=gb,ia.setFromMatrixPosition(Y.target.matrixWorld),ca.sub(ia),ca.normalize(),
+nb[va+0]=ca.x,nb[va+1]=ca.y,nb[va+2]=ca.z,Bb[sa]=Math.cos(Y.angle),Cb[sa]=Y.exponent,Db[sa]=0===Y.distance?0:Y.decay,sa+=1)):Y instanceof THREE.HemisphereLight&&(Za+=1,Y.visible&&(ca.setFromMatrixPosition(Y.matrixWorld),ca.normalize(),La=3*Ka,qb[La+0]=ca.x,qb[La+1]=ca.y,qb[La+2]=ca.z,Ua=Y.color,Va=Y.groundColor,p(ob,La,Ua,Ja),p(pb,La,Va,Ja),Ka+=1)));Z=3*Oa;for(oa=Math.max(hb.length,3*rb);Z<oa;Z++)hb[Z]=0;Z=3*Aa;for(oa=Math.max(jb.length,3*sb);Z<oa;Z++)jb[Z]=0;Z=3*sa;for(oa=Math.max(lb.length,3*tb);Z<
+oa;Z++)lb[Z]=0;Z=3*Ka;for(oa=Math.max(ob.length,3*Za);Z<oa;Z++)ob[Z]=0;Z=3*Ka;for(oa=Math.max(pb.length,3*Za);Z<oa;Z++)pb[Z]=0;aa.directional.length=Oa;aa.point.length=Aa;aa.spot.length=sa;aa.hemi.length=Ka;aa.ambient[0]=db;aa.ambient[1]=eb;aa.ambient[2]=fb;Ya=!1}if(Xa){var fa=Gb;M.ambientLightColor.value=fa.ambient;M.directionalLightColor.value=fa.directional.colors;M.directionalLightDirection.value=fa.directional.positions;M.pointLightColor.value=fa.point.colors;M.pointLightPosition.value=fa.point.positions;
+M.pointLightDistance.value=fa.point.distances;M.pointLightDecay.value=fa.point.decays;M.spotLightColor.value=fa.spot.colors;M.spotLightPosition.value=fa.spot.positions;M.spotLightDistance.value=fa.spot.distances;M.spotLightDirection.value=fa.spot.directions;M.spotLightAngleCos.value=fa.spot.anglesCos;M.spotLightExponent.value=fa.spot.exponents;M.spotLightDecay.value=fa.spot.decays;M.hemisphereLightSkyColor.value=fa.hemi.skyColors;M.hemisphereLightGroundColor.value=fa.hemi.groundColors;M.hemisphereLightDirection.value=
+fa.hemi.positions;l(M,!0)}else l(M,!1)}if(d instanceof THREE.MeshBasicMaterial||d instanceof THREE.MeshLambertMaterial||d instanceof THREE.MeshPhongMaterial){M.opacity.value=d.opacity;M.diffuse.value=d.color;M.map.value=d.map;M.specularMap.value=d.specularMap;M.alphaMap.value=d.alphaMap;d.bumpMap&&(M.bumpMap.value=d.bumpMap,M.bumpScale.value=d.bumpScale);d.normalMap&&(M.normalMap.value=d.normalMap,M.normalScale.value.copy(d.normalScale));var wa;d.map?wa=d.map:d.specularMap?wa=d.specularMap:d.normalMap?
+wa=d.normalMap:d.bumpMap?wa=d.bumpMap:d.alphaMap&&(wa=d.alphaMap);if(void 0!==wa){var Hb=wa.offset,Ib=wa.repeat;M.offsetRepeat.value.set(Hb.x,Hb.y,Ib.x,Ib.y)}M.envMap.value=d.envMap;M.flipEnvMap.value=d.envMap instanceof THREE.WebGLRenderTargetCube?1:-1;M.reflectivity.value=d.reflectivity;M.refractionRatio.value=d.refractionRatio}if(d instanceof THREE.LineBasicMaterial)M.diffuse.value=d.color,M.opacity.value=d.opacity;else if(d instanceof THREE.LineDashedMaterial)M.diffuse.value=d.color,M.opacity.value=
+d.opacity,M.dashSize.value=d.dashSize,M.totalSize.value=d.dashSize+d.gapSize,M.scale.value=d.scale;else if(d instanceof THREE.PointCloudMaterial){if(M.psColor.value=d.color,M.opacity.value=d.opacity,M.size.value=d.size,M.scale.value=x.height/2,M.map.value=d.map,null!==d.map){var Jb=d.map.offset,Kb=d.map.repeat;M.offsetRepeat.value.set(Jb.x,Jb.y,Kb.x,Kb.y)}}else d instanceof THREE.MeshPhongMaterial?(M.shininess.value=d.shininess,M.emissive.value=d.emissive,M.specular.value=d.specular,M.lightMap.value=
+d.lightMap,M.lightMapIntensity.value=d.lightMapIntensity,M.aoMap.value=d.aoMap,M.aoMapIntensity.value=d.aoMapIntensity):d instanceof THREE.MeshLambertMaterial?M.emissive.value=d.emissive:d instanceof THREE.MeshBasicMaterial?(M.aoMap.value=d.aoMap,M.aoMapIntensity.value=d.aoMapIntensity):d instanceof THREE.MeshDepthMaterial?(M.mNear.value=a.near,M.mFar.value=a.far,M.opacity.value=d.opacity):d instanceof THREE.MeshNormalMaterial&&(M.opacity.value=d.opacity);if(e.receiveShadow&&!d._shadowPass&&M.shadowMatrix)for(var Ma=
+0,ub=0,Tb=b.length;ub<Tb;ub++){var ta=b[ub];ta.castShadow&&(ta instanceof THREE.SpotLight||ta instanceof THREE.DirectionalLight&&!ta.shadowCascade)&&(M.shadowMap.value[Ma]=ta.shadowMap,M.shadowMapSize.value[Ma]=ta.shadowMapSize,M.shadowMatrix.value[Ma]=ta.shadowMatrix,M.shadowDarkness.value[Ma]=ta.shadowDarkness,M.shadowBias.value[Ma]=ta.shadowBias,Ma++)}for(var vb=d.uniformsList,pa,Ba,qa,$a=0,Ub=vb.length;$a<Ub;$a++){var W=vb[$a][0];if(!1!==W.needsUpdate){var Lb=W.type,N=W.value,X=vb[$a][1];switch(Lb){case "1i":r.uniform1i(X,
+N);break;case "1f":r.uniform1f(X,N);break;case "2f":r.uniform2f(X,N[0],N[1]);break;case "3f":r.uniform3f(X,N[0],N[1],N[2]);break;case "4f":r.uniform4f(X,N[0],N[1],N[2],N[3]);break;case "1iv":r.uniform1iv(X,N);break;case "3iv":r.uniform3iv(X,N);break;case "1fv":r.uniform1fv(X,N);break;case "2fv":r.uniform2fv(X,N);break;case "3fv":r.uniform3fv(X,N);break;case "4fv":r.uniform4fv(X,N);break;case "Matrix3fv":r.uniformMatrix3fv(X,!1,N);break;case "Matrix4fv":r.uniformMatrix4fv(X,!1,N);break;case "i":r.uniform1i(X,
+N);break;case "f":r.uniform1f(X,N);break;case "v2":r.uniform2f(X,N.x,N.y);break;case "v3":r.uniform3f(X,N.x,N.y,N.z);break;case "v4":r.uniform4f(X,N.x,N.y,N.z,N.w);break;case "c":r.uniform3f(X,N.r,N.g,N.b);break;case "iv1":r.uniform1iv(X,N);break;case "iv":r.uniform3iv(X,N);break;case "fv1":r.uniform1fv(X,N);break;case "fv":r.uniform3fv(X,N);break;case "v2v":void 0===W._array&&(W._array=new Float32Array(2*N.length));for(var U=0,la=N.length;U<la;U++)qa=2*U,W._array[qa+0]=N[U].x,W._array[qa+1]=N[U].y;
+r.uniform2fv(X,W._array);break;case "v3v":void 0===W._array&&(W._array=new Float32Array(3*N.length));U=0;for(la=N.length;U<la;U++)qa=3*U,W._array[qa+0]=N[U].x,W._array[qa+1]=N[U].y,W._array[qa+2]=N[U].z;r.uniform3fv(X,W._array);break;case "v4v":void 0===W._array&&(W._array=new Float32Array(4*N.length));U=0;for(la=N.length;U<la;U++)qa=4*U,W._array[qa+0]=N[U].x,W._array[qa+1]=N[U].y,W._array[qa+2]=N[U].z,W._array[qa+3]=N[U].w;r.uniform4fv(X,W._array);break;case "m3":r.uniformMatrix3fv(X,!1,N.elements);
+break;case "m3v":void 0===W._array&&(W._array=new Float32Array(9*N.length));U=0;for(la=N.length;U<la;U++)N[U].flattenToArrayOffset(W._array,9*U);r.uniformMatrix3fv(X,!1,W._array);break;case "m4":r.uniformMatrix4fv(X,!1,N.elements);break;case "m4v":void 0===W._array&&(W._array=new Float32Array(16*N.length));U=0;for(la=N.length;U<la;U++)N[U].flattenToArrayOffset(W._array,16*U);r.uniformMatrix4fv(X,!1,W._array);break;case "t":pa=N;Ba=n();r.uniform1i(X,Ba);if(!pa)continue;if(pa instanceof THREE.CubeTexture||
+Array.isArray(pa.image)&&6===pa.image.length){var ba=pa,Mb=Ba;if(6===ba.image.length)if(ba.needsUpdate){ba.image.__webglTextureCube||(ba.addEventListener("dispose",wb),ba.image.__webglTextureCube=r.createTexture(),H.info.memory.textures++);Q.activeTexture(r.TEXTURE0+Mb);Q.bindTexture(r.TEXTURE_CUBE_MAP,ba.image.__webglTextureCube);r.pixelStorei(r.UNPACK_FLIP_Y_WEBGL,ba.flipY);for(var Nb=ba instanceof THREE.CompressedTexture,xb=ba.image[0]instanceof THREE.DataTexture,Ca=[],ea=0;6>ea;ea++)Ca[ea]=!H.autoScaleCubemaps||
+Nb||xb?xb?ba.image[ea].image:ba.image[ea]:q(ba.image[ea],Vb);var Ob=Ca[0],Pb=THREE.Math.isPowerOfTwo(Ob.width)&&THREE.Math.isPowerOfTwo(Ob.height),xa=u(ba.format),yb=u(ba.type);m(r.TEXTURE_CUBE_MAP,ba,Pb);for(ea=0;6>ea;ea++)if(Nb)for(var Da,Qb=Ca[ea].mipmaps,Ra=0,Wb=Qb.length;Ra<Wb;Ra++)Da=Qb[Ra],ba.format!==THREE.RGBAFormat&&ba.format!==THREE.RGBFormat?-1<Rb().indexOf(xa)?Q.compressedTexImage2D(r.TEXTURE_CUBE_MAP_POSITIVE_X+ea,Ra,xa,Da.width,Da.height,0,Da.data):console.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setCubeTexture()"):
+Q.texImage2D(r.TEXTURE_CUBE_MAP_POSITIVE_X+ea,Ra,xa,Da.width,Da.height,0,xa,yb,Da.data);else xb?Q.texImage2D(r.TEXTURE_CUBE_MAP_POSITIVE_X+ea,0,xa,Ca[ea].width,Ca[ea].height,0,xa,yb,Ca[ea].data):Q.texImage2D(r.TEXTURE_CUBE_MAP_POSITIVE_X+ea,0,xa,xa,yb,Ca[ea]);ba.generateMipmaps&&Pb&&r.generateMipmap(r.TEXTURE_CUBE_MAP);ba.needsUpdate=!1;if(ba.onUpdate)ba.onUpdate(ba)}else Q.activeTexture(r.TEXTURE0+Mb),Q.bindTexture(r.TEXTURE_CUBE_MAP,ba.image.__webglTextureCube)}else if(pa instanceof THREE.WebGLRenderTargetCube){var Xb=
+pa;Q.activeTexture(r.TEXTURE0+Ba);Q.bindTexture(r.TEXTURE_CUBE_MAP,Xb.__webglTexture)}else H.setTexture(pa,Ba);break;case "tv":void 0===W._array&&(W._array=[]);U=0;for(la=W.value.length;U<la;U++)W._array[U]=n();r.uniform1iv(X,W._array);U=0;for(la=W.value.length;U<la;U++)pa=W.value[U],Ba=W._array[U],pa&&H.setTexture(pa,Ba);break;default:console.warn("THREE.WebGLRenderer: Unknown uniform type: "+Lb)}}}}r.uniformMatrix4fv($.modelViewMatrix,!1,e._modelViewMatrix.elements);$.normalMatrix&&r.uniformMatrix3fv($.normalMatrix,
+!1,e._normalMatrix.elements);null!==$.modelMatrix&&r.uniformMatrix4fv($.modelMatrix,!1,e.matrixWorld.elements);return Na}function l(a,b){a.ambientLightColor.needsUpdate=b;a.directionalLightColor.needsUpdate=b;a.directionalLightDirection.needsUpdate=b;a.pointLightColor.needsUpdate=b;a.pointLightPosition.needsUpdate=b;a.pointLightDistance.needsUpdate=b;a.pointLightDecay.needsUpdate=b;a.spotLightColor.needsUpdate=b;a.spotLightPosition.needsUpdate=b;a.spotLightDistance.needsUpdate=b;a.spotLightDirection.needsUpdate=
+b;a.spotLightAngleCos.needsUpdate=b;a.spotLightExponent.needsUpdate=b;a.spotLightDecay.needsUpdate=b;a.hemisphereLightSkyColor.needsUpdate=b;a.hemisphereLightGroundColor.needsUpdate=b;a.hemisphereLightDirection.needsUpdate=b}function n(){var a=Wa;a>=Sa&&console.warn("WebGLRenderer: trying to use "+a+" texture units while this GPU supports only "+Sa);Wa+=1;return a}function p(a,b,c,d){a[b+0]=c.r*d;a[b+1]=c.g*d;a[b+2]=c.b*d}function m(a,b,c){c?(r.texParameteri(a,r.TEXTURE_WRAP_S,u(b.wrapS)),r.texParameteri(a,
+r.TEXTURE_WRAP_T,u(b.wrapT)),r.texParameteri(a,r.TEXTURE_MAG_FILTER,u(b.magFilter)),r.texParameteri(a,r.TEXTURE_MIN_FILTER,u(b.minFilter))):(r.texParameteri(a,r.TEXTURE_WRAP_S,r.CLAMP_TO_EDGE),r.texParameteri(a,r.TEXTURE_WRAP_T,r.CLAMP_TO_EDGE),b.wrapS===THREE.ClampToEdgeWrapping&&b.wrapT===THREE.ClampToEdgeWrapping||console.warn("THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping. ( "+b.sourceFile+" )"),r.texParameteri(a,r.TEXTURE_MAG_FILTER,
+t(b.magFilter)),r.texParameteri(a,r.TEXTURE_MIN_FILTER,t(b.minFilter)),b.minFilter!==THREE.NearestFilter&&b.minFilter!==THREE.LinearFilter&&console.warn("THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter. ( "+b.sourceFile+" )"));(c=V.get("EXT_texture_filter_anisotropic"))&&b.type!==THREE.FloatType&&b.type!==THREE.HalfFloatType&&(1<b.anisotropy||b.__currentAnisotropy)&&(r.texParameterf(a,c.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(b.anisotropy,
+H.getMaxAnisotropy())),b.__currentAnisotropy=b.anisotropy)}function q(a,b){if(a.width>b||a.height>b){var c=b/Math.max(a.width,a.height),d=document.createElement("canvas");d.width=Math.floor(a.width*c);d.height=Math.floor(a.height*c);d.getContext("2d").drawImage(a,0,0,a.width,a.height,0,0,d.width,d.height);console.warn("THREE.WebGLRenderer: image is too big ("+a.width+"x"+a.height+"). Resized to "+d.width+"x"+d.height,a);return d}return a}function s(a,b){r.bindRenderbuffer(r.RENDERBUFFER,a);b.depthBuffer&&
+!b.stencilBuffer?(r.renderbufferStorage(r.RENDERBUFFER,r.DEPTH_COMPONENT16,b.width,b.height),r.framebufferRenderbuffer(r.FRAMEBUFFER,r.DEPTH_ATTACHMENT,r.RENDERBUFFER,a)):b.depthBuffer&&b.stencilBuffer?(r.renderbufferStorage(r.RENDERBUFFER,r.DEPTH_STENCIL,b.width,b.height),r.framebufferRenderbuffer(r.FRAMEBUFFER,r.DEPTH_STENCIL_ATTACHMENT,r.RENDERBUFFER,a)):r.renderbufferStorage(r.RENDERBUFFER,r.RGBA4,b.width,b.height)}function t(a){return a===THREE.NearestFilter||a===THREE.NearestMipMapNearestFilter||
+a===THREE.NearestMipMapLinearFilter?r.NEAREST:r.LINEAR}function u(a){var b;if(a===THREE.RepeatWrapping)return r.REPEAT;if(a===THREE.ClampToEdgeWrapping)return r.CLAMP_TO_EDGE;if(a===THREE.MirroredRepeatWrapping)return r.MIRRORED_REPEAT;if(a===THREE.NearestFilter)return r.NEAREST;if(a===THREE.NearestMipMapNearestFilter)return r.NEAREST_MIPMAP_NEAREST;if(a===THREE.NearestMipMapLinearFilter)return r.NEAREST_MIPMAP_LINEAR;if(a===THREE.LinearFilter)return r.LINEAR;if(a===THREE.LinearMipMapNearestFilter)return r.LINEAR_MIPMAP_NEAREST;
+if(a===THREE.LinearMipMapLinearFilter)return r.LINEAR_MIPMAP_LINEAR;if(a===THREE.UnsignedByteType)return r.UNSIGNED_BYTE;if(a===THREE.UnsignedShort4444Type)return r.UNSIGNED_SHORT_4_4_4_4;if(a===THREE.UnsignedShort5551Type)return r.UNSIGNED_SHORT_5_5_5_1;if(a===THREE.UnsignedShort565Type)return r.UNSIGNED_SHORT_5_6_5;if(a===THREE.ByteType)return r.BYTE;if(a===THREE.ShortType)return r.SHORT;if(a===THREE.UnsignedShortType)return r.UNSIGNED_SHORT;if(a===THREE.IntType)return r.INT;if(a===THREE.UnsignedIntType)return r.UNSIGNED_INT;
+if(a===THREE.FloatType)return r.FLOAT;b=V.get("OES_texture_half_float");if(null!==b&&a===THREE.HalfFloatType)return b.HALF_FLOAT_OES;if(a===THREE.AlphaFormat)return r.ALPHA;if(a===THREE.RGBFormat)return r.RGB;if(a===THREE.RGBAFormat)return r.RGBA;if(a===THREE.LuminanceFormat)return r.LUMINANCE;if(a===THREE.LuminanceAlphaFormat)return r.LUMINANCE_ALPHA;if(a===THREE.AddEquation)return r.FUNC_ADD;if(a===THREE.SubtractEquation)return r.FUNC_SUBTRACT;if(a===THREE.ReverseSubtractEquation)return r.FUNC_REVERSE_SUBTRACT;
+if(a===THREE.ZeroFactor)return r.ZERO;if(a===THREE.OneFactor)return r.ONE;if(a===THREE.SrcColorFactor)return r.SRC_COLOR;if(a===THREE.OneMinusSrcColorFactor)return r.ONE_MINUS_SRC_COLOR;if(a===THREE.SrcAlphaFactor)return r.SRC_ALPHA;if(a===THREE.OneMinusSrcAlphaFactor)return r.ONE_MINUS_SRC_ALPHA;if(a===THREE.DstAlphaFactor)return r.DST_ALPHA;if(a===THREE.OneMinusDstAlphaFactor)return r.ONE_MINUS_DST_ALPHA;if(a===THREE.DstColorFactor)return r.DST_COLOR;if(a===THREE.OneMinusDstColorFactor)return r.ONE_MINUS_DST_COLOR;
+if(a===THREE.SrcAlphaSaturateFactor)return r.SRC_ALPHA_SATURATE;b=V.get("WEBGL_compressed_texture_s3tc");if(null!==b){if(a===THREE.RGB_S3TC_DXT1_Format)return b.COMPRESSED_RGB_S3TC_DXT1_EXT;if(a===THREE.RGBA_S3TC_DXT1_Format)return b.COMPRESSED_RGBA_S3TC_DXT1_EXT;if(a===THREE.RGBA_S3TC_DXT3_Format)return b.COMPRESSED_RGBA_S3TC_DXT3_EXT;if(a===THREE.RGBA_S3TC_DXT5_Format)return b.COMPRESSED_RGBA_S3TC_DXT5_EXT}b=V.get("WEBGL_compressed_texture_pvrtc");if(null!==b){if(a===THREE.RGB_PVRTC_4BPPV1_Format)return b.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
+if(a===THREE.RGB_PVRTC_2BPPV1_Format)return b.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;if(a===THREE.RGBA_PVRTC_4BPPV1_Format)return b.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;if(a===THREE.RGBA_PVRTC_2BPPV1_Format)return b.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG}b=V.get("EXT_blend_minmax");if(null!==b){if(a===THREE.MinEquation)return b.MIN_EXT;if(a===THREE.MaxEquation)return b.MAX_EXT}return 0}console.log("THREE.WebGLRenderer",THREE.REVISION);a=a||{};var x=void 0!==a.canvas?a.canvas:document.createElement("canvas"),w=void 0!==
+a.context?a.context:null,A=x.width,y=x.height,G=1,I=void 0!==a.precision?a.precision:"highp",v=void 0!==a.alpha?a.alpha:!1,D=void 0!==a.depth?a.depth:!0,L=void 0!==a.stencil?a.stencil:!0,C=void 0!==a.antialias?a.antialias:!1,E=void 0!==a.premultipliedAlpha?a.premultipliedAlpha:!0,R=void 0!==a.preserveDrawingBuffer?a.preserveDrawingBuffer:!1,J=void 0!==a.logarithmicDepthBuffer?a.logarithmicDepthBuffer:!1,z=new THREE.Color(0),F=0,B=[],T=[],O=[],S=[],P=[];this.domElement=x;this.context=null;this.sortObjects=
+this.autoClearStencil=this.autoClearDepth=this.autoClearColor=this.autoClear=!0;this.gammaFactor=2;this.gammaOutput=this.gammaInput=!1;this.maxMorphTargets=8;this.maxMorphNormals=4;this.autoScaleCubemaps=!0;this.info={memory:{programs:0,geometries:0,textures:0},render:{calls:0,vertices:0,faces:0,points:0}};var H=this,K=[],na=null,da=null,ka=-1,ja="",ua=null,Wa=0,ma=0,Ga=0,Ea=x.width,ya=x.height,Ta=0,ra=0,Ha=new THREE.Frustum,Ia=new THREE.Matrix4,ia=new THREE.Vector3,ca=new THREE.Vector3,Ya=!0,Gb=
+{ambient:[0,0,0],directional:{length:0,colors:[],positions:[]},point:{length:0,colors:[],positions:[],distances:[],decays:[]},spot:{length:0,colors:[],positions:[],distances:[],directions:[],anglesCos:[],exponents:[],decays:[]},hemi:{length:0,skyColors:[],groundColors:[],positions:[]}},r;try{a={alpha:v,depth:D,stencil:L,antialias:C,premultipliedAlpha:E,preserveDrawingBuffer:R};r=w||x.getContext("webgl",a)||x.getContext("experimental-webgl",a);if(null===r){if(null!==x.getContext("webgl"))throw"Error creating WebGL context with your selected attributes.";
+throw"Error creating WebGL context.";}x.addEventListener("webglcontextlost",function(a){a.preventDefault();Ua();Va();ga.objects={}},!1)}catch(zb){console.error("THREE.WebGLRenderer: "+zb)}var Q=new THREE.WebGLState(r,u);void 0===r.getShaderPrecisionFormat&&(r.getShaderPrecisionFormat=function(){return{rangeMin:1,rangeMax:1,precision:1}});var V=new THREE.WebGLExtensions(r),ga=new THREE.WebGLObjects(r,this.info);V.get("OES_texture_float");V.get("OES_texture_float_linear");V.get("OES_texture_half_float");
+V.get("OES_texture_half_float_linear");V.get("OES_standard_derivatives");V.get("ANGLE_instanced_arrays");V.get("OES_element_index_uint")&&(THREE.BufferGeometry.MaxIndex=4294967296);J&&V.get("EXT_frag_depth");var Fa=function(a,b,c,d){!0===E&&(a*=d,b*=d,c*=d);r.clearColor(a,b,c,d)},Va=function(){r.clearColor(0,0,0,1);r.clearDepth(1);r.clearStencil(0);r.enable(r.DEPTH_TEST);r.depthFunc(r.LEQUAL);r.frontFace(r.CCW);r.cullFace(r.BACK);r.enable(r.CULL_FACE);r.enable(r.BLEND);r.blendEquation(r.FUNC_ADD);
+r.blendFunc(r.SRC_ALPHA,r.ONE_MINUS_SRC_ALPHA);r.viewport(ma,Ga,Ea,ya);Fa(z.r,z.g,z.b,F)},Ua=function(){ua=na=null;ja="";ka=-1;Ya=!0;Q.reset()};Va();this.context=r;this.extensions=V;this.state=Q;var ha=new THREE.WebGLShadowMap(this,B,ga);this.shadowMap=ha;var Sa=r.getParameter(r.MAX_TEXTURE_IMAGE_UNITS),w=r.getParameter(r.MAX_VERTEX_TEXTURE_IMAGE_UNITS),Ab=r.getParameter(r.MAX_TEXTURE_SIZE),Vb=r.getParameter(r.MAX_CUBE_MAP_TEXTURE_SIZE),cb=0<w,bb=cb&&V.get("OES_texture_float"),Bb=V.get("ANGLE_instanced_arrays"),
+v=r.getShaderPrecisionFormat(r.VERTEX_SHADER,r.HIGH_FLOAT),w=r.getShaderPrecisionFormat(r.VERTEX_SHADER,r.MEDIUM_FLOAT),D=r.getShaderPrecisionFormat(r.FRAGMENT_SHADER,r.HIGH_FLOAT);a=r.getShaderPrecisionFormat(r.FRAGMENT_SHADER,r.MEDIUM_FLOAT);var Rb=function(){var a;return function(){if(void 0!==a)return a;a=[];if(V.get("WEBGL_compressed_texture_pvrtc")||V.get("WEBGL_compressed_texture_s3tc"))for(var b=r.getParameter(r.COMPRESSED_TEXTURE_FORMATS),c=0;c<b.length;c++)a.push(b[c]);return a}}(),v=0<
+v.precision&&0<D.precision,w=0<w.precision&&0<a.precision;"highp"!==I||v||(w?(I="mediump",console.warn("THREE.WebGLRenderer: highp not supported, using mediump.")):(I="lowp",console.warn("THREE.WebGLRenderer: highp and mediump not supported, using lowp.")));"mediump"!==I||w||(I="lowp",console.warn("THREE.WebGLRenderer: mediump not supported, using lowp."));var Cb=new THREE.SpritePlugin(this,S),Db=new THREE.LensFlarePlugin(this,P);this.getContext=function(){return r};this.forceContextLoss=function(){V.get("WEBGL_lose_context").loseContext()};
+this.supportsVertexTextures=function(){return cb};this.supportsInstancedArrays=function(){return Bb};this.supportsFloatTextures=function(){return V.get("OES_texture_float")};this.supportsHalfFloatTextures=function(){return V.get("OES_texture_half_float")};this.supportsStandardDerivatives=function(){return V.get("OES_standard_derivatives")};this.supportsCompressedTextureS3TC=function(){return V.get("WEBGL_compressed_texture_s3tc")};this.supportsCompressedTexturePVRTC=function(){return V.get("WEBGL_compressed_texture_pvrtc")};
+this.supportsBlendMinMax=function(){return V.get("EXT_blend_minmax")};this.getMaxAnisotropy=function(){var a;return function(){if(void 0!==a)return a;var b=V.get("EXT_texture_filter_anisotropic");return a=null!==b?r.getParameter(b.MAX_TEXTURE_MAX_ANISOTROPY_EXT):0}}();this.getPrecision=function(){return I};this.getPixelRatio=function(){return G};this.setPixelRatio=function(a){void 0!==a&&(G=a)};this.getSize=function(){return{width:A,height:y}};this.setSize=function(a,b,c){A=a;y=b;x.width=a*G;x.height=
+b*G;!1!==c&&(x.style.width=a+"px",x.style.height=b+"px");this.setViewport(0,0,a,b)};this.setViewport=function(a,b,c,d){ma=a*G;Ga=b*G;Ea=c*G;ya=d*G;r.viewport(ma,Ga,Ea,ya)};this.setScissor=function(a,b,c,d){r.scissor(a*G,b*G,c*G,d*G)};this.enableScissorTest=function(a){a?r.enable(r.SCISSOR_TEST):r.disable(r.SCISSOR_TEST)};this.getClearColor=function(){return z};this.setClearColor=function(a,b){z.set(a);F=void 0!==b?b:1;Fa(z.r,z.g,z.b,F)};this.getClearAlpha=function(){return F};this.setClearAlpha=function(a){F=
+a;Fa(z.r,z.g,z.b,F)};this.clear=function(a,b,c){var d=0;if(void 0===a||a)d|=r.COLOR_BUFFER_BIT;if(void 0===b||b)d|=r.DEPTH_BUFFER_BIT;if(void 0===c||c)d|=r.STENCIL_BUFFER_BIT;r.clear(d)};this.clearColor=function(){r.clear(r.COLOR_BUFFER_BIT)};this.clearDepth=function(){r.clear(r.DEPTH_BUFFER_BIT)};this.clearStencil=function(){r.clear(r.STENCIL_BUFFER_BIT)};this.clearTarget=function(a,b,c,d){this.setRenderTarget(a);this.clear(b,c,d)};this.resetGLState=Ua;var wb=function(a){a=a.target;a.removeEventListener("dispose",
+wb);a.image&&a.image.__webglTextureCube?(r.deleteTexture(a.image.__webglTextureCube),delete a.image.__webglTextureCube):void 0!==a.__webglInit&&(r.deleteTexture(a.__webglTexture),delete a.__webglTexture,delete a.__webglInit);H.info.memory.textures--},ab=function(a){a=a.target;a.removeEventListener("dispose",ab);if(a&&void 0!==a.__webglTexture){r.deleteTexture(a.__webglTexture);delete a.__webglTexture;if(a instanceof THREE.WebGLRenderTargetCube)for(var b=0;6>b;b++)r.deleteFramebuffer(a.__webglFramebuffer[b]),
+r.deleteRenderbuffer(a.__webglRenderbuffer[b]);else r.deleteFramebuffer(a.__webglFramebuffer),r.deleteRenderbuffer(a.__webglRenderbuffer);delete a.__webglFramebuffer;delete a.__webglRenderbuffer}H.info.memory.textures--},Eb=function(a){a=a.target;a.removeEventListener("dispose",Eb);Fb(a)},Fb=function(a){var b=a.program.program;if(void 0!==b){a.program=void 0;var c,d,e=!1;a=0;for(c=K.length;a<c;a++)if(d=K[a],d.program===b){d.usedTimes--;0===d.usedTimes&&(e=!0);break}if(!0===e){e=[];a=0;for(c=K.length;a<
+c;a++)d=K[a],d.program!==b&&e.push(d);K=e;r.deleteProgram(b);H.info.memory.programs--}}};this.renderBufferImmediate=function(a,b,c){Q.initAttributes();a.hasPositions&&!a.__webglVertexBuffer&&(a.__webglVertexBuffer=r.createBuffer());a.hasNormals&&!a.__webglNormalBuffer&&(a.__webglNormalBuffer=r.createBuffer());a.hasUvs&&!a.__webglUvBuffer&&(a.__webglUvBuffer=r.createBuffer());a.hasColors&&!a.__webglColorBuffer&&(a.__webglColorBuffer=r.createBuffer());b=b.getAttributes();a.hasPositions&&(r.bindBuffer(r.ARRAY_BUFFER,
+a.__webglVertexBuffer),r.bufferData(r.ARRAY_BUFFER,a.positionArray,r.DYNAMIC_DRAW),Q.enableAttribute(b.position),r.vertexAttribPointer(b.position,3,r.FLOAT,!1,0,0));if(a.hasNormals){r.bindBuffer(r.ARRAY_BUFFER,a.__webglNormalBuffer);if(!1===c instanceof THREE.MeshPhongMaterial&&c.shading===THREE.FlatShading){var d,e,f,g,h,k,l,m,n,p,q,s=3*a.count;for(q=0;q<s;q+=9)p=a.normalArray,d=p[q],e=p[q+1],f=p[q+2],g=p[q+3],k=p[q+4],m=p[q+5],h=p[q+6],l=p[q+7],n=p[q+8],d=(d+g+h)/3,e=(e+k+l)/3,f=(f+m+n)/3,p[q]=
+d,p[q+1]=e,p[q+2]=f,p[q+3]=d,p[q+4]=e,p[q+5]=f,p[q+6]=d,p[q+7]=e,p[q+8]=f}r.bufferData(r.ARRAY_BUFFER,a.normalArray,r.DYNAMIC_DRAW);Q.enableAttribute(b.normal);r.vertexAttribPointer(b.normal,3,r.FLOAT,!1,0,0)}a.hasUvs&&c.map&&(r.bindBuffer(r.ARRAY_BUFFER,a.__webglUvBuffer),r.bufferData(r.ARRAY_BUFFER,a.uvArray,r.DYNAMIC_DRAW),Q.enableAttribute(b.uv),r.vertexAttribPointer(b.uv,2,r.FLOAT,!1,0,0));a.hasColors&&c.vertexColors!==THREE.NoColors&&(r.bindBuffer(r.ARRAY_BUFFER,a.__webglColorBuffer),r.bufferData(r.ARRAY_BUFFER,
+a.colorArray,r.DYNAMIC_DRAW),Q.enableAttribute(b.color),r.vertexAttribPointer(b.color,3,r.FLOAT,!1,0,0));Q.disableUnusedAttributes();r.drawArrays(r.TRIANGLES,0,a.count);a.count=0};this.renderBufferDirect=function(a,c,d,e,f){if(!1!==e.visible){var g=ga.geometries.get(f);a=k(a,c,d,e,f);c=!1;d=g.id+"_"+a.id+"_"+(e.wireframe?1:0);d!==ja&&(ja=d,c=!0);c&&Q.initAttributes();if(f instanceof THREE.Mesh)a:if(f=c,c=!0===e.wireframe?r.LINES:r.TRIANGLES,d=g.attributes.index){var h,l;d.array instanceof Uint32Array&&
+V.get("OES_element_index_uint")?(h=r.UNSIGNED_INT,l=4):(h=r.UNSIGNED_SHORT,l=2);var m=g.offsets;if(0===m.length){f&&(b(e,a,g,0),r.bindBuffer(r.ELEMENT_ARRAY_BUFFER,d.buffer));if(g instanceof THREE.InstancedBufferGeometry&&0<g.maxInstancedCount){var n=V.get("ANGLE_instanced_arrays");if(null===n){console.error("THREE.WebGLRenderer.renderMesh: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.");break a}n.drawElementsInstancedANGLE(c,d.array.length,h,
+0,g.maxInstancedCount)}else r.drawElements(c,d.array.length,h,0);H.info.render.calls++;H.info.render.vertices+=d.array.length;H.info.render.faces+=d.array.length/3}else{f=!0;for(var p=0,q=m.length;p<q;p++){n=m[p].index;f&&(b(e,a,g,n),r.bindBuffer(r.ELEMENT_ARRAY_BUFFER,d.buffer));if(g instanceof THREE.InstancedBufferGeometry&&0<m[p].instances){n=V.get("ANGLE_instanced_arrays");if(null===n){console.error("THREE.WebGLRenderer.renderMesh: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.");
+break a}n.drawElementsInstancedANGLE(c,m[p].count,h,m[p].start*l,m[p].count,h,m[p].instances)}else r.drawElements(c,m[p].count,h,m[p].start*l);H.info.render.calls++;H.info.render.vertices+=m[p].count;H.info.render.faces+=m[p].count/3}}}else if(m=g.offsets,0===m.length){f&&b(e,a,g,0);e=g.attributes.position;if(g instanceof THREE.InstancedBufferGeometry&&0<g.maxInstancedCount){n=V.get("ANGLE_instanced_arrays");if(null===n){console.error("THREE.WebGLRenderer.renderMesh: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.");
+break a}e instanceof THREE.InterleavedBufferAttribute?n.drawArraysInstancedANGLE(c,0,e.data.array.length/e.data.stride,g.maxInstancedCount):n.drawArraysInstancedANGLE(c,0,e.array.length/e.itemSize,g.maxInstancedCount)}else e instanceof THREE.InterleavedBufferAttribute?r.drawArrays(c,0,e.data.array.length/e.data.stride):r.drawArrays(c,0,e.array.length/e.itemSize);H.info.render.calls++;H.info.render.vertices+=e.array.length/e.itemSize;H.info.render.faces+=e.array.length/(3*e.itemSize)}else for(f&&b(e,
+a,g,0),p=0,q=m.length;p<q;p++){if(g instanceof THREE.InstancedBufferGeometry){console.error("THREE.WebGLRenderer.renderMesh: cannot use drawCalls with THREE.InstancedBufferGeometry.");break a}else r.drawArrays(c,m[p].start,m[p].count);H.info.render.calls++;H.info.render.vertices+=m[p].count;H.info.render.faces+=m[p].count/3}else if(f instanceof THREE.Line)if(f=f instanceof THREE.LineSegments?r.LINES:r.LINE_STRIP,Q.setLineWidth((void 0!==e.linewidth?e.linewidth:1)*G),h=g.attributes.index)if(h.array instanceof
+Uint32Array&&V.get("OES_element_index_uint")?(l=r.UNSIGNED_INT,m=4):(l=r.UNSIGNED_SHORT,m=2),d=g.offsets,0===d.length)c&&(b(e,a,g,0),r.bindBuffer(r.ELEMENT_ARRAY_BUFFER,h.buffer)),r.drawElements(f,h.array.length,l,0),H.info.render.calls++,H.info.render.vertices+=h.array.length;else for(1<d.length&&(c=!0),n=0,p=d.length;n<p;n++)q=d[n].index,c&&(b(e,a,g,q),r.bindBuffer(r.ELEMENT_ARRAY_BUFFER,h.buffer)),r.drawElements(f,d[n].count,l,d[n].start*m),H.info.render.calls++,H.info.render.vertices+=d[n].count;
+else if(c&&b(e,a,g,0),e=g.attributes.position,d=g.offsets,0===d.length)r.drawArrays(f,0,e.array.length/3),H.info.render.calls++,H.info.render.vertices+=e.array.length/3;else for(n=0,p=d.length;n<p;n++)r.drawArrays(f,d[n].index,d[n].count),H.info.render.calls++,H.info.render.vertices+=d[n].count;else if(f instanceof THREE.PointCloud)if(d=c,c=r.POINTS,h=g.attributes.index)if(h.array instanceof Uint32Array&&V.get("OES_element_index_uint")?(l=r.UNSIGNED_INT,m=4):(l=r.UNSIGNED_SHORT,m=2),f=g.offsets,0===
+f.length)d&&(b(e,a,g,0),r.bindBuffer(r.ELEMENT_ARRAY_BUFFER,h.buffer)),r.drawElements(c,h.array.length,l,0),H.info.render.calls++,H.info.render.points+=h.array.length;else for(1<f.length&&(d=!0),n=0,p=f.length;n<p;n++)q=f[n].index,d&&(b(e,a,g,q),r.bindBuffer(r.ELEMENT_ARRAY_BUFFER,h.buffer)),r.drawElements(c,f[n].count,l,f[n].start*m),H.info.render.calls++,H.info.render.points+=f[n].count;else if(d&&b(e,a,g,0),e=g.attributes.position,f=g.offsets,0===f.length)r.drawArrays(c,0,e.array.length/3),H.info.render.calls++,
+H.info.render.points+=e.array.length/3;else for(n=0,p=f.length;n<p;n++)r.drawArrays(c,f[n].index,f[n].count),H.info.render.calls++,H.info.render.points+=f[n].count}};this.render=function(a,b,k,m){if(!1===b instanceof THREE.Camera)console.error("THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.");else{var l=a.fog;ja="";ka=-1;ua=null;Ya=!0;!0===a.autoUpdate&&a.updateMatrixWorld();void 0===b.parent&&b.updateMatrixWorld();b.matrixWorldInverse.getInverse(b.matrixWorld);Ia.multiplyMatrices(b.projectionMatrix,
+b.matrixWorldInverse);Ha.setFromMatrix(Ia);B.length=0;T.length=0;O.length=0;S.length=0;P.length=0;e(a);!0===H.sortObjects&&(T.sort(c),O.sort(d));ga.update(T);ga.update(O);ha.render(a,b);H.info.render.calls=0;H.info.render.vertices=0;H.info.render.faces=0;H.info.render.points=0;this.setRenderTarget(k);(this.autoClear||m)&&this.clear(this.autoClearColor,this.autoClearDepth,this.autoClearStencil);m=0;for(var n=ga.objectsImmediate.length;m<n;m++){var p=ga.objectsImmediate[m],q=p.object;if(!0===q.visible){var s=
+q;s._modelViewMatrix.multiplyMatrices(b.matrixWorldInverse,s.matrixWorld);s._normalMatrix.getNormalMatrix(s._modelViewMatrix);q=q.material;q.transparent?(p.transparent=q,p.opaque=null):(p.opaque=q,p.transparent=null)}}a.overrideMaterial?(m=a.overrideMaterial,h(m),f(T,b,B,l,m),f(O,b,B,l,m),g(ga.objectsImmediate,"",b,B,l,m)):(Q.setBlending(THREE.NoBlending),f(T,b,B,l,null),g(ga.objectsImmediate,"opaque",b,B,l,null),f(O,b,B,l,null),g(ga.objectsImmediate,"transparent",b,B,l,null));Cb.render(a,b);Db.render(a,
+b,Ta,ra);k&&k.generateMipmaps&&k.minFilter!==THREE.NearestFilter&&k.minFilter!==THREE.LinearFilter&&(k instanceof THREE.WebGLRenderTargetCube?(Q.bindTexture(r.TEXTURE_CUBE_MAP,k.__webglTexture),r.generateMipmap(r.TEXTURE_CUBE_MAP),Q.bindTexture(r.TEXTURE_CUBE_MAP,null)):(Q.bindTexture(r.TEXTURE_2D,k.__webglTexture),r.generateMipmap(r.TEXTURE_2D),Q.bindTexture(r.TEXTURE_2D,null)));Q.setDepthTest(!0);Q.setDepthWrite(!0);Q.setColorWrite(!0)}};this.renderImmediateObject=function(a,b,c,d,e){var f=k(a,
+b,c,d,e);ja="";H.setMaterialFaces(d);e.immediateRenderCallback?e.immediateRenderCallback(f,r,Ha):e.render(function(a){H.renderBufferImmediate(a,f,d)})};var Sb={MeshDepthMaterial:"depth",MeshNormalMaterial:"normal",MeshBasicMaterial:"basic",MeshLambertMaterial:"lambert",MeshPhongMaterial:"phong",LineBasicMaterial:"basic",LineDashedMaterial:"dashed",PointCloudMaterial:"particle_basic"};this.setFaceCulling=function(a,b){a===THREE.CullFaceNone?r.disable(r.CULL_FACE):(b===THREE.FrontFaceDirectionCW?r.frontFace(r.CW):
+r.frontFace(r.CCW),a===THREE.CullFaceBack?r.cullFace(r.BACK):a===THREE.CullFaceFront?r.cullFace(r.FRONT):r.cullFace(r.FRONT_AND_BACK),r.enable(r.CULL_FACE))};this.setMaterialFaces=function(a){Q.setDoubleSided(a.side===THREE.DoubleSide);Q.setFlipSided(a.side===THREE.BackSide)};this.uploadTexture=function(a,b){void 0===a.__webglInit&&(a.__webglInit=!0,a.addEventListener("dispose",wb),a.__webglTexture=r.createTexture(),H.info.memory.textures++);Q.activeTexture(r.TEXTURE0+b);Q.bindTexture(r.TEXTURE_2D,
+a.__webglTexture);r.pixelStorei(r.UNPACK_FLIP_Y_WEBGL,a.flipY);r.pixelStorei(r.UNPACK_PREMULTIPLY_ALPHA_WEBGL,a.premultiplyAlpha);r.pixelStorei(r.UNPACK_ALIGNMENT,a.unpackAlignment);a.image=q(a.image,Ab);var c=a.image,d=THREE.Math.isPowerOfTwo(c.width)&&THREE.Math.isPowerOfTwo(c.height),e=u(a.format),f=u(a.type);m(r.TEXTURE_2D,a,d);var g=a.mipmaps;if(a instanceof THREE.DataTexture)if(0<g.length&&d){for(var h=0,k=g.length;h<k;h++)c=g[h],Q.texImage2D(r.TEXTURE_2D,h,e,c.width,c.height,0,e,f,c.data);
+a.generateMipmaps=!1}else Q.texImage2D(r.TEXTURE_2D,0,e,c.width,c.height,0,e,f,c.data);else if(a instanceof THREE.CompressedTexture)for(h=0,k=g.length;h<k;h++)c=g[h],a.format!==THREE.RGBAFormat&&a.format!==THREE.RGBFormat?-1<Rb().indexOf(e)?Q.compressedTexImage2D(r.TEXTURE_2D,h,e,c.width,c.height,0,c.data):console.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()"):Q.texImage2D(r.TEXTURE_2D,h,e,c.width,c.height,0,e,f,c.data);else if(0<g.length&&d){h=
+0;for(k=g.length;h<k;h++)c=g[h],Q.texImage2D(r.TEXTURE_2D,h,e,e,f,c);a.generateMipmaps=!1}else Q.texImage2D(r.TEXTURE_2D,0,e,e,f,a.image);a.generateMipmaps&&d&&r.generateMipmap(r.TEXTURE_2D);a.needsUpdate=!1;if(a.onUpdate)a.onUpdate(a)};this.setTexture=function(a,b){if(!0===a.needsUpdate){var c=a.image;void 0===c?console.warn("THREE.WebGLRenderer: Texture marked for update but image is undefined",a):!1===c.complete?console.warn("THREE.WebGLRenderer: Texture marked for update but image is incomplete",
+a):H.uploadTexture(a,b)}else Q.activeTexture(r.TEXTURE0+b),Q.bindTexture(r.TEXTURE_2D,a.__webglTexture)};this.setRenderTarget=function(a){var b=a instanceof THREE.WebGLRenderTargetCube;if(a&&void 0===a.__webglFramebuffer){void 0===a.depthBuffer&&(a.depthBuffer=!0);void 0===a.stencilBuffer&&(a.stencilBuffer=!0);a.addEventListener("dispose",ab);a.__webglTexture=r.createTexture();H.info.memory.textures++;var c=THREE.Math.isPowerOfTwo(a.width)&&THREE.Math.isPowerOfTwo(a.height),d=u(a.format),e=u(a.type);
+if(b){a.__webglFramebuffer=[];a.__webglRenderbuffer=[];Q.bindTexture(r.TEXTURE_CUBE_MAP,a.__webglTexture);m(r.TEXTURE_CUBE_MAP,a,c);for(var f=0;6>f;f++){a.__webglFramebuffer[f]=r.createFramebuffer();a.__webglRenderbuffer[f]=r.createRenderbuffer();Q.texImage2D(r.TEXTURE_CUBE_MAP_POSITIVE_X+f,0,d,a.width,a.height,0,d,e,null);var g=a,h=r.TEXTURE_CUBE_MAP_POSITIVE_X+f;r.bindFramebuffer(r.FRAMEBUFFER,a.__webglFramebuffer[f]);r.framebufferTexture2D(r.FRAMEBUFFER,r.COLOR_ATTACHMENT0,h,g.__webglTexture,0);
+s(a.__webglRenderbuffer[f],a)}a.generateMipmaps&&c&&r.generateMipmap(r.TEXTURE_CUBE_MAP)}else a.__webglFramebuffer=r.createFramebuffer(),a.__webglRenderbuffer=a.shareDepthFrom?a.shareDepthFrom.__webglRenderbuffer:r.createRenderbuffer(),Q.bindTexture(r.TEXTURE_2D,a.__webglTexture),m(r.TEXTURE_2D,a,c),Q.texImage2D(r.TEXTURE_2D,0,d,a.width,a.height,0,d,e,null),d=r.TEXTURE_2D,r.bindFramebuffer(r.FRAMEBUFFER,a.__webglFramebuffer),r.framebufferTexture2D(r.FRAMEBUFFER,r.COLOR_ATTACHMENT0,d,a.__webglTexture,
+0),a.shareDepthFrom?a.depthBuffer&&!a.stencilBuffer?r.framebufferRenderbuffer(r.FRAMEBUFFER,r.DEPTH_ATTACHMENT,r.RENDERBUFFER,a.__webglRenderbuffer):a.depthBuffer&&a.stencilBuffer&&r.framebufferRenderbuffer(r.FRAMEBUFFER,r.DEPTH_STENCIL_ATTACHMENT,r.RENDERBUFFER,a.__webglRenderbuffer):s(a.__webglRenderbuffer,a),a.generateMipmaps&&c&&r.generateMipmap(r.TEXTURE_2D);b?Q.bindTexture(r.TEXTURE_CUBE_MAP,null):Q.bindTexture(r.TEXTURE_2D,null);r.bindRenderbuffer(r.RENDERBUFFER,null);r.bindFramebuffer(r.FRAMEBUFFER,
+null)}a?(b=b?a.__webglFramebuffer[a.activeCubeFace]:a.__webglFramebuffer,c=a.width,a=a.height,e=d=0):(b=null,c=Ea,a=ya,d=ma,e=Ga);b!==da&&(r.bindFramebuffer(r.FRAMEBUFFER,b),r.viewport(d,e,c,a),da=b);Ta=c;ra=a};this.readRenderTargetPixels=function(a,b,c,d,e,f){if(!(a instanceof THREE.WebGLRenderTarget))console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");else if(a.__webglFramebuffer)if(a.format!==THREE.RGBAFormat)console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA format. readPixels can read only RGBA format.");
+else{var g=!1;a.__webglFramebuffer!==da&&(r.bindFramebuffer(r.FRAMEBUFFER,a.__webglFramebuffer),g=!0);r.checkFramebufferStatus(r.FRAMEBUFFER)===r.FRAMEBUFFER_COMPLETE?r.readPixels(b,c,d,e,r.RGBA,r.UNSIGNED_BYTE,f):console.error("THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.");g&&r.bindFramebuffer(r.FRAMEBUFFER,da)}};this.initMaterial=function(){console.warn("THREE.WebGLRenderer: .initMaterial() has been removed.")};this.addPrePlugin=function(){console.warn("THREE.WebGLRenderer: .addPrePlugin() has been removed.")};
+this.addPostPlugin=function(){console.warn("THREE.WebGLRenderer: .addPostPlugin() has been removed.")};this.updateShadowMap=function(){console.warn("THREE.WebGLRenderer: .updateShadowMap() has been removed.")};Object.defineProperties(this,{shadowMapEnabled:{get:function(){return ha.enabled},set:function(a){console.warn("THREE.WebGLRenderer: .shadowMapEnabled is now .shadowMap.enabled.");ha.enabled=a}},shadowMapType:{get:function(){return ha.type},set:function(a){console.warn("THREE.WebGLRenderer: .shadowMapType is now .shadowMap.type.");
+ha.type=a}},shadowMapCullFace:{get:function(){return ha.cullFace},set:function(a){console.warn("THREE.WebGLRenderer: .shadowMapCullFace is now .shadowMap.cullFace.");ha.cullFace=a}},shadowMapDebug:{get:function(){return ha.debug},set:function(a){console.warn("THREE.WebGLRenderer: .shadowMapDebug is now .shadowMap.debug.");ha.debug=a}},shadowMapCascade:{get:function(){return ha.cascade},set:function(a){console.warn("THREE.WebGLRenderer: .shadowMapCascade is now .shadowMap.cascade.");ha.cascade=a}}})};
 THREE.WebGLRenderTarget=function(a,b,c){this.width=a;this.height=b;c=c||{};this.wrapS=void 0!==c.wrapS?c.wrapS:THREE.ClampToEdgeWrapping;this.wrapT=void 0!==c.wrapT?c.wrapT:THREE.ClampToEdgeWrapping;this.magFilter=void 0!==c.magFilter?c.magFilter:THREE.LinearFilter;this.minFilter=void 0!==c.minFilter?c.minFilter:THREE.LinearMipMapLinearFilter;this.anisotropy=void 0!==c.anisotropy?c.anisotropy:1;this.offset=new THREE.Vector2(0,0);this.repeat=new THREE.Vector2(1,1);this.format=void 0!==c.format?c.format:
 THREE.WebGLRenderTarget=function(a,b,c){this.width=a;this.height=b;c=c||{};this.wrapS=void 0!==c.wrapS?c.wrapS:THREE.ClampToEdgeWrapping;this.wrapT=void 0!==c.wrapT?c.wrapT:THREE.ClampToEdgeWrapping;this.magFilter=void 0!==c.magFilter?c.magFilter:THREE.LinearFilter;this.minFilter=void 0!==c.minFilter?c.minFilter:THREE.LinearMipMapLinearFilter;this.anisotropy=void 0!==c.anisotropy?c.anisotropy:1;this.offset=new THREE.Vector2(0,0);this.repeat=new THREE.Vector2(1,1);this.format=void 0!==c.format?c.format:
 THREE.RGBAFormat;this.type=void 0!==c.type?c.type:THREE.UnsignedByteType;this.depthBuffer=void 0!==c.depthBuffer?c.depthBuffer:!0;this.stencilBuffer=void 0!==c.stencilBuffer?c.stencilBuffer:!0;this.generateMipmaps=!0;this.shareDepthFrom=void 0!==c.shareDepthFrom?c.shareDepthFrom:null};
 THREE.RGBAFormat;this.type=void 0!==c.type?c.type:THREE.UnsignedByteType;this.depthBuffer=void 0!==c.depthBuffer?c.depthBuffer:!0;this.stencilBuffer=void 0!==c.stencilBuffer?c.stencilBuffer:!0;this.generateMipmaps=!0;this.shareDepthFrom=void 0!==c.shareDepthFrom?c.shareDepthFrom:null};
 THREE.WebGLRenderTarget.prototype={constructor:THREE.WebGLRenderTarget,setSize:function(a,b){if(this.width!==a||this.height!==b)this.width=a,this.height=b,this.dispose()},clone:function(){var a=new THREE.WebGLRenderTarget(this.width,this.height);a.wrapS=this.wrapS;a.wrapT=this.wrapT;a.magFilter=this.magFilter;a.minFilter=this.minFilter;a.anisotropy=this.anisotropy;a.offset.copy(this.offset);a.repeat.copy(this.repeat);a.format=this.format;a.type=this.type;a.depthBuffer=this.depthBuffer;a.stencilBuffer=
 THREE.WebGLRenderTarget.prototype={constructor:THREE.WebGLRenderTarget,setSize:function(a,b){if(this.width!==a||this.height!==b)this.width=a,this.height=b,this.dispose()},clone:function(){var a=new THREE.WebGLRenderTarget(this.width,this.height);a.wrapS=this.wrapS;a.wrapT=this.wrapT;a.magFilter=this.magFilter;a.minFilter=this.minFilter;a.anisotropy=this.anisotropy;a.offset.copy(this.offset);a.repeat.copy(this.repeat);a.format=this.format;a.type=this.type;a.depthBuffer=this.depthBuffer;a.stencilBuffer=
@@ -573,75 +572,76 @@ break;case "WEBGL_compressed_texture_pvrtc":d=a.getExtension("WEBGL_compressed_t
 THREE.WebGLGeometries=function(a,b){function c(e){e=e.target;e.removeEventListener("dispose",c);e=d[e.id];for(var f in e.attributes){var g=e.attributes[f];void 0!==g.buffer&&(a.deleteBuffer(g.buffer),delete g.buffer)}b.memory.geometries--}var d={};this.get=function(a){var f=a.geometry;if(void 0!==d[f.id])return d[f.id];f.addEventListener("dispose",c);d[f.id]=f instanceof THREE.BufferGeometry?f:(new THREE.BufferGeometry).setFromObject(a);b.memory.geometries++;return d[f.id]}};
 THREE.WebGLGeometries=function(a,b){function c(e){e=e.target;e.removeEventListener("dispose",c);e=d[e.id];for(var f in e.attributes){var g=e.attributes[f];void 0!==g.buffer&&(a.deleteBuffer(g.buffer),delete g.buffer)}b.memory.geometries--}var d={};this.get=function(a){var f=a.geometry;if(void 0!==d[f.id])return d[f.id];f.addEventListener("dispose",c);d[f.id]=f instanceof THREE.BufferGeometry?f:(new THREE.BufferGeometry).setFromObject(a);b.memory.geometries++;return d[f.id]}};
 THREE.WebGLObjects=function(a,b){function c(a){a.target.traverse(function(a){a.removeEventListener("remove",c);if(a instanceof THREE.Mesh||a instanceof THREE.PointCloud||a instanceof THREE.Line)delete e[a.id];else if(a instanceof THREE.ImmediateRenderObject||a.immediateRenderCallback)for(var b=f,d=b.length-1;0<=d;d--)b[d].object===a&&b.splice(d,1);delete a.__webglInit;delete a._modelViewMatrix;delete a._normalMatrix;delete a.__webglActive})}function d(a,b){return b[0]-a[0]}var e={},f=[],g=new Float32Array(8),
 THREE.WebGLObjects=function(a,b){function c(a){a.target.traverse(function(a){a.removeEventListener("remove",c);if(a instanceof THREE.Mesh||a instanceof THREE.PointCloud||a instanceof THREE.Line)delete e[a.id];else if(a instanceof THREE.ImmediateRenderObject||a.immediateRenderCallback)for(var b=f,d=b.length-1;0<=d;d--)b[d].object===a&&b.splice(d,1);delete a.__webglInit;delete a._modelViewMatrix;delete a._normalMatrix;delete a.__webglActive})}function d(a,b){return b[0]-a[0]}var e={},f=[],g=new Float32Array(8),
 h=new THREE.WebGLGeometries(a,b);this.objects=e;this.objectsImmediate=f;this.geometries=h;this.init=function(a){void 0===a.__webglInit&&(a.__webglInit=!0,a._modelViewMatrix=new THREE.Matrix4,a._normalMatrix=new THREE.Matrix3,a.addEventListener("removed",c));void 0===a.__webglActive&&(a.__webglActive=!0,a instanceof THREE.Mesh||a instanceof THREE.Line||a instanceof THREE.PointCloud?e[a.id]={id:a.id,object:a,z:0}:(a instanceof THREE.ImmediateRenderObject||a.immediateRenderCallback)&&f.push({id:null,
 h=new THREE.WebGLGeometries(a,b);this.objects=e;this.objectsImmediate=f;this.geometries=h;this.init=function(a){void 0===a.__webglInit&&(a.__webglInit=!0,a._modelViewMatrix=new THREE.Matrix4,a._normalMatrix=new THREE.Matrix3,a.addEventListener("removed",c));void 0===a.__webglActive&&(a.__webglActive=!0,a instanceof THREE.Mesh||a instanceof THREE.Line||a instanceof THREE.PointCloud?e[a.id]={id:a.id,object:a,z:0}:(a instanceof THREE.ImmediateRenderObject||a.immediateRenderCallback)&&f.push({id:null,
-object:a,opaque:null,transparent:null,z:0}))};this.update=function(b){for(var c=0,e=b.length;c<e;c++){var f=b[c].object;if(!1!==f.material.visible){var m=f,q=h.get(m);!0===m.geometry.dynamic&&q.updateFromObject(m);if(void 0!==m.morphTargetInfluences){for(var t=[],f=m.morphTargetInfluences,s=0,u=f.length;s<u;s++)t.push([f[s],s]);t.sort(d);8<t.length&&(t.length=8);s=0;for(u=t.length;s<u;s++)g[s]=t[s][0],f=q.morphAttributes[t[s][1]],q.addAttribute("morphTarget"+s,f);f=m.material;void 0!==f.program?null!==
-f.program.uniforms.morphTargetInfluences&&a.uniform1fv(f.program.uniforms.morphTargetInfluences,g):console.warn("TOFIX: material.program is undefined")}q=q.attributes;m=void 0;for(m in q)if(f=q[m],t="index"===m?a.ELEMENT_ARRAY_BUFFER:a.ARRAY_BUFFER,f=f instanceof THREE.InterleavedBufferAttribute?f.data:f,void 0===f.buffer){f.buffer=a.createBuffer();a.bindBuffer(t,f.buffer);s=a.STATIC_DRAW;if(f instanceof THREE.DynamicBufferAttribute||f instanceof THREE.InstancedBufferAttribute&&!0===f.dynamic||f instanceof
-THREE.InterleavedBuffer&&!0===f.dynamic)s=a.DYNAMIC_DRAW;a.bufferData(t,f.array,s);f.needsUpdate=!1}else!0===f.needsUpdate&&(a.bindBuffer(t,f.buffer),void 0===f.updateRange||-1===f.updateRange.count?a.bufferSubData(t,0,f.array):0===f.updateRange.count?console.error("THREE.WebGLRenderer.updateObject: using updateRange for THREE.DynamicBufferAttribute and marked as needsUpdate but count is 0, ensure you are using set methods or updating manually."):(a.bufferSubData(t,f.updateRange.offset*f.array.BYTES_PER_ELEMENT,
-f.array.subarray(f.updateRange.offset,f.updateRange.offset+f.updateRange.count)),f.updateRange.count=0),f.needsUpdate=!1)}}}};
-THREE.WebGLProgram=function(){function a(a){return""!==a}var b=0;return function(c,d,e,f){var g=c.context,h=e.defines,k=e.__webglShader.uniforms,l=e.attributes,n=e.__webglShader.vertexShader,p=e.__webglShader.fragmentShader,m=e.index0AttributeName,q="SHADOWMAP_TYPE_BASIC";f.shadowMapType===THREE.PCFShadowMap?q="SHADOWMAP_TYPE_PCF":f.shadowMapType===THREE.PCFSoftShadowMap&&(q="SHADOWMAP_TYPE_PCF_SOFT");var t="ENVMAP_TYPE_CUBE",s="ENVMAP_MODE_REFLECTION",u="ENVMAP_BLENDING_MULTIPLY";if(f.envMap){switch(e.envMap.mapping){case THREE.CubeReflectionMapping:case THREE.CubeRefractionMapping:t=
-"ENVMAP_TYPE_CUBE";break;case THREE.EquirectangularReflectionMapping:case THREE.EquirectangularRefractionMapping:t="ENVMAP_TYPE_EQUIREC";break;case THREE.SphericalReflectionMapping:t="ENVMAP_TYPE_SPHERE"}switch(e.envMap.mapping){case THREE.CubeRefractionMapping:case THREE.EquirectangularRefractionMapping:s="ENVMAP_MODE_REFRACTION"}switch(e.combine){case THREE.MultiplyOperation:u="ENVMAP_BLENDING_MULTIPLY";break;case THREE.MixOperation:u="ENVMAP_BLENDING_MIX";break;case THREE.AddOperation:u="ENVMAP_BLENDING_ADD"}}var w=
-0<c.gammaFactor?c.gammaFactor:1,x,A=[];for(x in h){var y=h[x];!1!==y&&A.push("#define "+x+" "+y)}x=A.join("\n");h=g.createProgram();e instanceof THREE.RawShaderMaterial?c=A="":(A=["precision "+f.precision+" float;","precision "+f.precision+" int;",x,f.supportsVertexTextures?"#define VERTEX_TEXTURES":"",c.gammaInput?"#define GAMMA_INPUT":"",c.gammaOutput?"#define GAMMA_OUTPUT":"","#define GAMMA_FACTOR "+w,"#define MAX_DIR_LIGHTS "+f.maxDirLights,"#define MAX_POINT_LIGHTS "+f.maxPointLights,"#define MAX_SPOT_LIGHTS "+
-f.maxSpotLights,"#define MAX_HEMI_LIGHTS "+f.maxHemiLights,"#define MAX_SHADOWS "+f.maxShadows,"#define MAX_BONES "+f.maxBones,f.map?"#define USE_MAP":"",f.envMap?"#define USE_ENVMAP":"",f.envMap?"#define "+s:"",f.lightMap?"#define USE_LIGHTMAP":"",f.aoMap?"#define USE_AOMAP":"",f.bumpMap?"#define USE_BUMPMAP":"",f.normalMap?"#define USE_NORMALMAP":"",f.specularMap?"#define USE_SPECULARMAP":"",f.alphaMap?"#define USE_ALPHAMAP":"",f.vertexColors?"#define USE_COLOR":"",f.flatShading?"#define FLAT_SHADED":
-"",f.skinning?"#define USE_SKINNING":"",f.useVertexTexture?"#define BONE_TEXTURE":"",f.morphTargets?"#define USE_MORPHTARGETS":"",f.morphNormals?"#define USE_MORPHNORMALS":"",f.doubleSided?"#define DOUBLE_SIDED":"",f.flipSided?"#define FLIP_SIDED":"",f.shadowMapEnabled?"#define USE_SHADOWMAP":"",f.shadowMapEnabled?"#define "+q:"",f.shadowMapDebug?"#define SHADOWMAP_DEBUG":"",f.shadowMapCascade?"#define SHADOWMAP_CASCADE":"",f.sizeAttenuation?"#define USE_SIZEATTENUATION":"",f.logarithmicDepthBuffer?
-"#define USE_LOGDEPTHBUF":"",f.logarithmicDepthBuffer&&c.extensions.get("EXT_frag_depth")?"#define USE_LOGDEPTHBUF_EXT":"","uniform mat4 modelMatrix;","uniform mat4 modelViewMatrix;","uniform mat4 projectionMatrix;","uniform mat4 viewMatrix;","uniform mat3 normalMatrix;","uniform vec3 cameraPosition;","attribute vec3 position;","attribute vec3 normal;","attribute vec2 uv;","#ifdef USE_COLOR","\tattribute vec3 color;","#endif","#ifdef USE_MORPHTARGETS","\tattribute vec3 morphTarget0;","\tattribute vec3 morphTarget1;",
-"\tattribute vec3 morphTarget2;","\tattribute vec3 morphTarget3;","\t#ifdef USE_MORPHNORMALS","\t\tattribute vec3 morphNormal0;","\t\tattribute vec3 morphNormal1;","\t\tattribute vec3 morphNormal2;","\t\tattribute vec3 morphNormal3;","\t#else","\t\tattribute vec3 morphTarget4;","\t\tattribute vec3 morphTarget5;","\t\tattribute vec3 morphTarget6;","\t\tattribute vec3 morphTarget7;","\t#endif","#endif","#ifdef USE_SKINNING","\tattribute vec4 skinIndex;","\tattribute vec4 skinWeight;","#endif","\n"].filter(a).join("\n"),
-c=[f.bumpMap||f.normalMap||f.flatShading||e.derivatives?"#extension GL_OES_standard_derivatives : enable":"","precision "+f.precision+" float;","precision "+f.precision+" int;",x,"#define MAX_DIR_LIGHTS "+f.maxDirLights,"#define MAX_POINT_LIGHTS "+f.maxPointLights,"#define MAX_SPOT_LIGHTS "+f.maxSpotLights,"#define MAX_HEMI_LIGHTS "+f.maxHemiLights,"#define MAX_SHADOWS "+f.maxShadows,f.alphaTest?"#define ALPHATEST "+f.alphaTest:"",c.gammaInput?"#define GAMMA_INPUT":"",c.gammaOutput?"#define GAMMA_OUTPUT":
-"","#define GAMMA_FACTOR "+w,f.useFog&&f.fog?"#define USE_FOG":"",f.useFog&&f.fogExp?"#define FOG_EXP2":"",f.map?"#define USE_MAP":"",f.envMap?"#define USE_ENVMAP":"",f.envMap?"#define "+t:"",f.envMap?"#define "+s:"",f.envMap?"#define "+u:"",f.lightMap?"#define USE_LIGHTMAP":"",f.aoMap?"#define USE_AOMAP":"",f.bumpMap?"#define USE_BUMPMAP":"",f.normalMap?"#define USE_NORMALMAP":"",f.specularMap?"#define USE_SPECULARMAP":"",f.alphaMap?"#define USE_ALPHAMAP":"",f.vertexColors?"#define USE_COLOR":"",
-f.flatShading?"#define FLAT_SHADED":"",f.metal?"#define METAL":"",f.doubleSided?"#define DOUBLE_SIDED":"",f.flipSided?"#define FLIP_SIDED":"",f.shadowMapEnabled?"#define USE_SHADOWMAP":"",f.shadowMapEnabled?"#define "+q:"",f.shadowMapDebug?"#define SHADOWMAP_DEBUG":"",f.shadowMapCascade?"#define SHADOWMAP_CASCADE":"",f.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"",f.logarithmicDepthBuffer&&c.extensions.get("EXT_frag_depth")?"#define USE_LOGDEPTHBUF_EXT":"","uniform mat4 viewMatrix;","uniform vec3 cameraPosition;",
-"\n"].filter(a).join("\n"));n=new THREE.WebGLShader(g,g.VERTEX_SHADER,A+n);p=new THREE.WebGLShader(g,g.FRAGMENT_SHADER,c+p);g.attachShader(h,n);g.attachShader(h,p);void 0!==m&&g.bindAttribLocation(h,0,m);g.linkProgram(h);m=g.getProgramInfoLog(h);c=g.getShaderInfoLog(n);q=g.getShaderInfoLog(p);!1===g.getProgramParameter(h,g.LINK_STATUS)&&console.error("THREE.WebGLProgram: shader error: ",g.getError(),"gl.VALIDATE_STATUS",g.getProgramParameter(h,g.VALIDATE_STATUS),"gl.getProgramInfoLog",m,c,q);""!==
-m&&console.warn("THREE.WebGLProgram: gl.getProgramInfoLog()",m);g.deleteShader(n);g.deleteShader(p);m="viewMatrix modelViewMatrix projectionMatrix normalMatrix modelMatrix cameraPosition morphTargetInfluences bindMatrix bindMatrixInverse".split(" ");f.useVertexTexture?m.push("boneTexture","boneTextureWidth","boneTextureHeight"):m.push("boneGlobalMatrices");f.logarithmicDepthBuffer&&m.push("logDepthBufFC");for(var D in k)m.push(D);k=m;D={};m=0;for(c=k.length;m<c;m++)q=k[m],D[q]=g.getUniformLocation(h,
-q);this.uniforms=D;if(e instanceof THREE.RawShaderMaterial)m=l;else{m="position normal uv uv2 tangent color skinIndex skinWeight lineDistance".split(" ");for(e=0;e<f.maxMorphTargets;e++)m.push("morphTarget"+e);for(e=0;e<f.maxMorphNormals;e++)m.push("morphNormal"+e);Array.isArray(l)&&(m=m.concat(l))}f=m;l={};e=0;for(k=f.length;e<k;e++)D=f[e],l[D]=g.getAttribLocation(h,D);this.attributes=l;this.id=b++;this.code=d;this.usedTimes=1;this.program=h;this.vertexShader=n;this.fragmentShader=p;return this}}();
+object:a,opaque:null,transparent:null,z:0}))};this.update=function(b){for(var c=0,e=b.length;c<e;c++){var f=b[c].object;if(!1!==f.material.visible){var m=f,f=h.get(m);!0===m.geometry.dynamic&&f.updateFromObject(m);if(void 0!==m.morphTargetInfluences){for(var q=[],s=m.morphTargetInfluences,t=0,u=s.length;t<u;t++)q.push([s[t],t]);q.sort(d);8<q.length&&(q.length=8);t=0;for(u=q.length;t<u;t++)g[t]=q[t][0],s=f.morphAttributes[q[t][1]],f.addAttribute("morphTarget"+t,s);s=m.material;void 0!==s.program?(s=
+s.program.getUniforms(),null!==s.morphTargetInfluences&&a.uniform1fv(s.morphTargetInfluences,g)):console.warn("TOFIX: material.program is undefined")}f=f.attributes;m=void 0;for(m in f)if(s=f[m],q="index"===m?a.ELEMENT_ARRAY_BUFFER:a.ARRAY_BUFFER,s=s instanceof THREE.InterleavedBufferAttribute?s.data:s,void 0===s.buffer){s.buffer=a.createBuffer();a.bindBuffer(q,s.buffer);t=a.STATIC_DRAW;if(s instanceof THREE.DynamicBufferAttribute||s instanceof THREE.InstancedBufferAttribute&&!0===s.dynamic||s instanceof
+THREE.InterleavedBuffer&&!0===s.dynamic)t=a.DYNAMIC_DRAW;a.bufferData(q,s.array,t);s.needsUpdate=!1}else!0===s.needsUpdate&&(a.bindBuffer(q,s.buffer),void 0===s.updateRange||-1===s.updateRange.count?a.bufferSubData(q,0,s.array):0===s.updateRange.count?console.error("THREE.WebGLRenderer.updateObject: using updateRange for THREE.DynamicBufferAttribute and marked as needsUpdate but count is 0, ensure you are using set methods or updating manually."):(a.bufferSubData(q,s.updateRange.offset*s.array.BYTES_PER_ELEMENT,
+s.array.subarray(s.updateRange.offset,s.updateRange.offset+s.updateRange.count)),s.updateRange.count=0),s.needsUpdate=!1)}}}};
+THREE.WebGLProgram=function(){function a(a){var b=[],c;for(c in a){var g=a[c];!1!==g&&b.push("#define "+c+" "+g)}return b.join("\n")}function b(a){return""!==a}var c=0;return function(d,e,f,g){var h=d.context,k=f.defines,l=f.__webglShader.vertexShader,n=f.__webglShader.fragmentShader,p=f.index0AttributeName,m="SHADOWMAP_TYPE_BASIC";g.shadowMapType===THREE.PCFShadowMap?m="SHADOWMAP_TYPE_PCF":g.shadowMapType===THREE.PCFSoftShadowMap&&(m="SHADOWMAP_TYPE_PCF_SOFT");var q="ENVMAP_TYPE_CUBE",s="ENVMAP_MODE_REFLECTION",
+t="ENVMAP_BLENDING_MULTIPLY";if(g.envMap){switch(f.envMap.mapping){case THREE.CubeReflectionMapping:case THREE.CubeRefractionMapping:q="ENVMAP_TYPE_CUBE";break;case THREE.EquirectangularReflectionMapping:case THREE.EquirectangularRefractionMapping:q="ENVMAP_TYPE_EQUIREC";break;case THREE.SphericalReflectionMapping:q="ENVMAP_TYPE_SPHERE"}switch(f.envMap.mapping){case THREE.CubeRefractionMapping:case THREE.EquirectangularRefractionMapping:s="ENVMAP_MODE_REFRACTION"}switch(f.combine){case THREE.MultiplyOperation:t=
+"ENVMAP_BLENDING_MULTIPLY";break;case THREE.MixOperation:t="ENVMAP_BLENDING_MIX";break;case THREE.AddOperation:t="ENVMAP_BLENDING_ADD"}}var u=0<d.gammaFactor?d.gammaFactor:1,x=a(k),w=h.createProgram();f instanceof THREE.RawShaderMaterial?d=k="":(k=["precision "+g.precision+" float;","precision "+g.precision+" int;",x,g.supportsVertexTextures?"#define VERTEX_TEXTURES":"",d.gammaInput?"#define GAMMA_INPUT":"",d.gammaOutput?"#define GAMMA_OUTPUT":"","#define GAMMA_FACTOR "+u,"#define MAX_DIR_LIGHTS "+
+g.maxDirLights,"#define MAX_POINT_LIGHTS "+g.maxPointLights,"#define MAX_SPOT_LIGHTS "+g.maxSpotLights,"#define MAX_HEMI_LIGHTS "+g.maxHemiLights,"#define MAX_SHADOWS "+g.maxShadows,"#define MAX_BONES "+g.maxBones,g.map?"#define USE_MAP":"",g.envMap?"#define USE_ENVMAP":"",g.envMap?"#define "+s:"",g.lightMap?"#define USE_LIGHTMAP":"",g.aoMap?"#define USE_AOMAP":"",g.bumpMap?"#define USE_BUMPMAP":"",g.normalMap?"#define USE_NORMALMAP":"",g.specularMap?"#define USE_SPECULARMAP":"",g.alphaMap?"#define USE_ALPHAMAP":
+"",g.vertexColors?"#define USE_COLOR":"",g.flatShading?"#define FLAT_SHADED":"",g.skinning?"#define USE_SKINNING":"",g.useVertexTexture?"#define BONE_TEXTURE":"",g.morphTargets?"#define USE_MORPHTARGETS":"",g.morphNormals?"#define USE_MORPHNORMALS":"",g.doubleSided?"#define DOUBLE_SIDED":"",g.flipSided?"#define FLIP_SIDED":"",g.shadowMapEnabled?"#define USE_SHADOWMAP":"",g.shadowMapEnabled?"#define "+m:"",g.shadowMapDebug?"#define SHADOWMAP_DEBUG":"",g.shadowMapCascade?"#define SHADOWMAP_CASCADE":
+"",g.sizeAttenuation?"#define USE_SIZEATTENUATION":"",g.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"",g.logarithmicDepthBuffer&&d.extensions.get("EXT_frag_depth")?"#define USE_LOGDEPTHBUF_EXT":"","uniform mat4 modelMatrix;","uniform mat4 modelViewMatrix;","uniform mat4 projectionMatrix;","uniform mat4 viewMatrix;","uniform mat3 normalMatrix;","uniform vec3 cameraPosition;","attribute vec3 position;","attribute vec3 normal;","attribute vec2 uv;","#ifdef USE_COLOR","\tattribute vec3 color;","#endif",
+"#ifdef USE_MORPHTARGETS","\tattribute vec3 morphTarget0;","\tattribute vec3 morphTarget1;","\tattribute vec3 morphTarget2;","\tattribute vec3 morphTarget3;","\t#ifdef USE_MORPHNORMALS","\t\tattribute vec3 morphNormal0;","\t\tattribute vec3 morphNormal1;","\t\tattribute vec3 morphNormal2;","\t\tattribute vec3 morphNormal3;","\t#else","\t\tattribute vec3 morphTarget4;","\t\tattribute vec3 morphTarget5;","\t\tattribute vec3 morphTarget6;","\t\tattribute vec3 morphTarget7;","\t#endif","#endif","#ifdef USE_SKINNING",
+"\tattribute vec4 skinIndex;","\tattribute vec4 skinWeight;","#endif","\n"].filter(b).join("\n"),d=[g.bumpMap||g.normalMap||g.flatShading||f.derivatives?"#extension GL_OES_standard_derivatives : enable":"","precision "+g.precision+" float;","precision "+g.precision+" int;",x,"#define MAX_DIR_LIGHTS "+g.maxDirLights,"#define MAX_POINT_LIGHTS "+g.maxPointLights,"#define MAX_SPOT_LIGHTS "+g.maxSpotLights,"#define MAX_HEMI_LIGHTS "+g.maxHemiLights,"#define MAX_SHADOWS "+g.maxShadows,g.alphaTest?"#define ALPHATEST "+
+g.alphaTest:"",d.gammaInput?"#define GAMMA_INPUT":"",d.gammaOutput?"#define GAMMA_OUTPUT":"","#define GAMMA_FACTOR "+u,g.useFog&&g.fog?"#define USE_FOG":"",g.useFog&&g.fogExp?"#define FOG_EXP2":"",g.map?"#define USE_MAP":"",g.envMap?"#define USE_ENVMAP":"",g.envMap?"#define "+q:"",g.envMap?"#define "+s:"",g.envMap?"#define "+t:"",g.lightMap?"#define USE_LIGHTMAP":"",g.aoMap?"#define USE_AOMAP":"",g.bumpMap?"#define USE_BUMPMAP":"",g.normalMap?"#define USE_NORMALMAP":"",g.specularMap?"#define USE_SPECULARMAP":
+"",g.alphaMap?"#define USE_ALPHAMAP":"",g.vertexColors?"#define USE_COLOR":"",g.flatShading?"#define FLAT_SHADED":"",g.metal?"#define METAL":"",g.doubleSided?"#define DOUBLE_SIDED":"",g.flipSided?"#define FLIP_SIDED":"",g.shadowMapEnabled?"#define USE_SHADOWMAP":"",g.shadowMapEnabled?"#define "+m:"",g.shadowMapDebug?"#define SHADOWMAP_DEBUG":"",g.shadowMapCascade?"#define SHADOWMAP_CASCADE":"",g.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"",g.logarithmicDepthBuffer&&d.extensions.get("EXT_frag_depth")?
+"#define USE_LOGDEPTHBUF_EXT":"","uniform mat4 viewMatrix;","uniform vec3 cameraPosition;","\n"].filter(b).join("\n"));n=d+n;l=new THREE.WebGLShader(h,h.VERTEX_SHADER,k+l);n=new THREE.WebGLShader(h,h.FRAGMENT_SHADER,n);h.attachShader(w,l);h.attachShader(w,n);void 0!==p&&h.bindAttribLocation(w,0,p);h.linkProgram(w);p=h.getProgramInfoLog(w);k=h.getShaderInfoLog(l);d=h.getShaderInfoLog(n);!1===h.getProgramParameter(w,h.LINK_STATUS)&&console.error("THREE.WebGLProgram: shader error: ",h.getError(),"gl.VALIDATE_STATUS",
+h.getProgramParameter(w,h.VALIDATE_STATUS),"gl.getProgramInfoLog",p,k,d);""!==p&&console.warn("THREE.WebGLProgram: gl.getProgramInfoLog()",p);h.deleteShader(l);h.deleteShader(n);var A=function(){return this._cachedUniforms};this.getUniforms=function(){for(var a={},b=h.getProgramParameter(w,h.ACTIVE_UNIFORMS),c=0;c<b;c++){var d=h.getActiveUniform(w,c).name,e=h.getUniformLocation(w,d),f=d.lastIndexOf("[0]");-1!==f&&f===d.length-3&&(a[d.substr(0,f)]=e);a[d]=e}this._cachedUniforms=a;this.getUniforms=
+A;return a};var y=function(){return this._cachedAttributes};this.getAttributes=function(){for(var a={},b=h.getProgramParameter(w,h.ACTIVE_ATTRIBUTES),c=0;c<b;c++){var d=h.getActiveAttrib(w,c).name;a[d]=h.getAttribLocation(w,d)}this._cachedAttributes=a;this.getAttributes=y;return a};Object.defineProperties(this,{uniforms:{get:function(){console.warn("THREE.WebGLProgram: .uniforms is now .getUniforms().");return this.getUniforms()}},attributes:{get:function(){console.warn("THREE.WebGLProgram: .attributes is now .getAttributes().");
+return this.getAttributes()}}});this.id=c++;this.code=e;this.usedTimes=1;this.program=w;this.vertexShader=l;this.fragmentShader=n;return this}}();
 THREE.WebGLShader=function(){var a=function(a){a=a.split("\n");for(var c=0;c<a.length;c++)a[c]=c+1+": "+a[c];return a.join("\n")};return function(b,c,d){var e=b.createShader(c);b.shaderSource(e,d);b.compileShader(e);!1===b.getShaderParameter(e,b.COMPILE_STATUS)&&console.error("THREE.WebGLShader: Shader couldn't compile.");""!==b.getShaderInfoLog(e)&&console.warn("THREE.WebGLShader: gl.getShaderInfoLog()",c===b.VERTEX_SHADER?"vertex":"fragment",b.getShaderInfoLog(e),a(d));return e}}();
 THREE.WebGLShader=function(){var a=function(a){a=a.split("\n");for(var c=0;c<a.length;c++)a[c]=c+1+": "+a[c];return a.join("\n")};return function(b,c,d){var e=b.createShader(c);b.shaderSource(e,d);b.compileShader(e);!1===b.getShaderParameter(e,b.COMPILE_STATUS)&&console.error("THREE.WebGLShader: Shader couldn't compile.");""!==b.getShaderInfoLog(e)&&console.warn("THREE.WebGLShader: gl.getShaderInfoLog()",c===b.VERTEX_SHADER?"vertex":"fragment",b.getShaderInfoLog(e),a(d));return e}}();
 THREE.WebGLShadowMap=function(a,b,c){function d(a,b){if(!0===a.visible){var e=c.objects[a.id];e&&a.castShadow&&(!1===a.frustumCulled||!0===f.intersectsObject(a))&&(a._modelViewMatrix.multiplyMatrices(b.matrixWorldInverse,a.matrixWorld),p.push(e));for(var e=0,g=a.children.length;e<g;e++)d(a.children[e],b)}}var e=a.context,f=new THREE.Frustum,g=new THREE.Matrix4,h=new THREE.Vector3,k=new THREE.Vector3,l=c.objectsImmediate,n=new THREE.Vector3,p=[],m=THREE.ShaderLib.depthRGBA,q=THREE.UniformsUtils.clone(m.uniforms),
 THREE.WebGLShadowMap=function(a,b,c){function d(a,b){if(!0===a.visible){var e=c.objects[a.id];e&&a.castShadow&&(!1===a.frustumCulled||!0===f.intersectsObject(a))&&(a._modelViewMatrix.multiplyMatrices(b.matrixWorldInverse,a.matrixWorld),p.push(e));for(var e=0,g=a.children.length;e<g;e++)d(a.children[e],b)}}var e=a.context,f=new THREE.Frustum,g=new THREE.Matrix4,h=new THREE.Vector3,k=new THREE.Vector3,l=c.objectsImmediate,n=new THREE.Vector3,p=[],m=THREE.ShaderLib.depthRGBA,q=THREE.UniformsUtils.clone(m.uniforms),
-t=new THREE.ShaderMaterial({uniforms:q,vertexShader:m.vertexShader,fragmentShader:m.fragmentShader}),s=new THREE.ShaderMaterial({uniforms:q,vertexShader:m.vertexShader,fragmentShader:m.fragmentShader,morphTargets:!0}),u=new THREE.ShaderMaterial({uniforms:q,vertexShader:m.vertexShader,fragmentShader:m.fragmentShader,skinning:!0}),w=new THREE.ShaderMaterial({uniforms:q,vertexShader:m.vertexShader,fragmentShader:m.fragmentShader,morphTargets:!0,skinning:!0});t._shadowPass=!0;s._shadowPass=!0;u._shadowPass=
-!0;w._shadowPass=!0;var x=this;this.enabled=!1;this.type=THREE.PCFShadowMap;this.cullFace=THREE.CullFaceFront;this.cascade=this.debug=!1;this.render=function(c,m){if(!1!==x.enabled){var q,I,v,E,L,C,F,R=[];E=0;e.clearColor(1,1,1,1);e.disable(e.BLEND);e.enable(e.CULL_FACE);e.frontFace(e.CCW);x.cullFace===THREE.CullFaceFront?e.cullFace(e.FRONT):e.cullFace(e.BACK);a.state.setDepthTest(!0);q=0;for(I=b.length;q<I;q++)if(v=b[q],v.castShadow)if(v instanceof THREE.DirectionalLight&&v.shadowCascade)for(L=0;L<
-v.shadowCascadeCount;L++){var J;if(v.shadowCascadeArray[L])J=v.shadowCascadeArray[L];else{var z=v;F=L;J=new THREE.DirectionalLight;J.isVirtual=!0;J.onlyShadow=!0;J.castShadow=!0;J.shadowCameraNear=z.shadowCameraNear;J.shadowCameraFar=z.shadowCameraFar;J.shadowCameraLeft=z.shadowCameraLeft;J.shadowCameraRight=z.shadowCameraRight;J.shadowCameraBottom=z.shadowCameraBottom;J.shadowCameraTop=z.shadowCameraTop;J.shadowCameraVisible=z.shadowCameraVisible;J.shadowDarkness=z.shadowDarkness;J.shadowBias=z.shadowCascadeBias[F];
-J.shadowMapWidth=z.shadowCascadeWidth[F];J.shadowMapHeight=z.shadowCascadeHeight[F];J.pointsWorld=[];J.pointsFrustum=[];var G=J.pointsWorld;C=J.pointsFrustum;for(var B=0;8>B;B++)G[B]=new THREE.Vector3,C[B]=new THREE.Vector3;G=z.shadowCascadeNearZ[F];z=z.shadowCascadeFarZ[F];C[0].set(-1,-1,G);C[1].set(1,-1,G);C[2].set(-1,1,G);C[3].set(1,1,G);C[4].set(-1,-1,z);C[5].set(1,-1,z);C[6].set(-1,1,z);C[7].set(1,1,z);J.originalCamera=m;C=new THREE.Gyroscope;C.position.copy(v.shadowCascadeOffset);C.add(J);C.add(J.target);
-m.add(C);v.shadowCascadeArray[L]=J}F=v;G=L;z=F.shadowCascadeArray[G];z.position.copy(F.position);z.target.position.copy(F.target.position);z.lookAt(z.target);z.shadowCameraVisible=F.shadowCameraVisible;z.shadowDarkness=F.shadowDarkness;z.shadowBias=F.shadowCascadeBias[G];C=F.shadowCascadeNearZ[G];F=F.shadowCascadeFarZ[G];z=z.pointsFrustum;z[0].z=C;z[1].z=C;z[2].z=C;z[3].z=C;z[4].z=F;z[5].z=F;z[6].z=F;z[7].z=F;R[E]=J;E++}else R[E]=v,E++;q=0;for(I=R.length;q<I;q++){v=R[q];v.shadowMap||(L=THREE.LinearFilter,
-x.type===THREE.PCFSoftShadowMap&&(L=THREE.NearestFilter),v.shadowMap=new THREE.WebGLRenderTarget(v.shadowMapWidth,v.shadowMapHeight,{minFilter:L,magFilter:L,format:THREE.RGBAFormat}),v.shadowMapSize=new THREE.Vector2(v.shadowMapWidth,v.shadowMapHeight),v.shadowMatrix=new THREE.Matrix4);if(!v.shadowCamera){if(v instanceof THREE.SpotLight)v.shadowCamera=new THREE.PerspectiveCamera(v.shadowCameraFov,v.shadowMapWidth/v.shadowMapHeight,v.shadowCameraNear,v.shadowCameraFar);else if(v instanceof THREE.DirectionalLight)v.shadowCamera=
-new THREE.OrthographicCamera(v.shadowCameraLeft,v.shadowCameraRight,v.shadowCameraTop,v.shadowCameraBottom,v.shadowCameraNear,v.shadowCameraFar);else{console.error("THREE.ShadowMapPlugin: Unsupported light type for shadow",v);continue}c.add(v.shadowCamera);!0===c.autoUpdate&&c.updateMatrixWorld()}v.shadowCameraVisible&&!v.cameraHelper&&(v.cameraHelper=new THREE.CameraHelper(v.shadowCamera),c.add(v.cameraHelper));if(v.isVirtual&&J.originalCamera==m){L=m;E=v.shadowCamera;C=v.pointsFrustum;z=v.pointsWorld;
-h.set(Infinity,Infinity,Infinity);k.set(-Infinity,-Infinity,-Infinity);for(F=0;8>F;F++)G=z[F],G.copy(C[F]),G.unproject(L),G.applyMatrix4(E.matrixWorldInverse),G.x<h.x&&(h.x=G.x),G.x>k.x&&(k.x=G.x),G.y<h.y&&(h.y=G.y),G.y>k.y&&(k.y=G.y),G.z<h.z&&(h.z=G.z),G.z>k.z&&(k.z=G.z);E.left=h.x;E.right=k.x;E.top=k.y;E.bottom=h.y;E.updateProjectionMatrix()}E=v.shadowMap;C=v.shadowMatrix;L=v.shadowCamera;L.position.setFromMatrixPosition(v.matrixWorld);n.setFromMatrixPosition(v.target.matrixWorld);L.lookAt(n);L.updateMatrixWorld();
-L.matrixWorldInverse.getInverse(L.matrixWorld);v.cameraHelper&&(v.cameraHelper.visible=v.shadowCameraVisible);v.shadowCameraVisible&&v.cameraHelper.update();C.set(.5,0,0,.5,0,.5,0,.5,0,0,.5,.5,0,0,0,1);C.multiply(L.projectionMatrix);C.multiply(L.matrixWorldInverse);g.multiplyMatrices(L.projectionMatrix,L.matrixWorldInverse);f.setFromMatrix(g);a.setRenderTarget(E);a.clear();p.length=0;d(c,L);v=0;for(E=p.length;v<E;v++)C=p[v],C=C.object,z=C.material instanceof THREE.MeshFaceMaterial?C.material.materials[0]:
-C.material,F=void 0!==C.geometry.morphTargets&&0<C.geometry.morphTargets.length&&z.morphTargets,G=C instanceof THREE.SkinnedMesh&&z.skinning,F=C.customDepthMaterial?C.customDepthMaterial:G?F?w:u:F?s:t,a.setMaterialFaces(z),a.renderBufferDirect(L,b,null,F,C);v=0;for(E=l.length;v<E;v++)C=l[v],C=C.object,C.visible&&C.castShadow&&(C._modelViewMatrix.multiplyMatrices(L.matrixWorldInverse,C.matrixWorld),a.renderImmediateObject(L,b,null,t,C))}q=a.getClearColor();I=a.getClearAlpha();e.clearColor(q.r,q.g,
-q.b,I);e.enable(e.BLEND);x.cullFace===THREE.CullFaceFront&&e.cullFace(e.BACK);a.resetGLState()}}};
-THREE.WebGLState=function(a,b){var c=this,d=new Uint8Array(16),e=new Uint8Array(16),f=null,g=null,h=null,k=null,l=null,n=null,p=null,m=null,q=null,t=null,s=null,u=null,w=null,x=null,A=null,y=null,D=null,I=a.getParameter(a.MAX_TEXTURE_IMAGE_UNITS),v=void 0,E={};this.initAttributes=function(){for(var a=0,b=d.length;a<b;a++)d[a]=0};this.enableAttribute=function(b){d[b]=1;0===e[b]&&(a.enableVertexAttribArray(b),e[b]=1)};this.disableUnusedAttributes=function(){for(var b=0,c=e.length;b<c;b++)e[b]!==d[b]&&
+s=new THREE.ShaderMaterial({uniforms:q,vertexShader:m.vertexShader,fragmentShader:m.fragmentShader}),t=new THREE.ShaderMaterial({uniforms:q,vertexShader:m.vertexShader,fragmentShader:m.fragmentShader,morphTargets:!0}),u=new THREE.ShaderMaterial({uniforms:q,vertexShader:m.vertexShader,fragmentShader:m.fragmentShader,skinning:!0}),x=new THREE.ShaderMaterial({uniforms:q,vertexShader:m.vertexShader,fragmentShader:m.fragmentShader,morphTargets:!0,skinning:!0});s._shadowPass=!0;t._shadowPass=!0;u._shadowPass=
+!0;x._shadowPass=!0;var w=this;this.enabled=!1;this.type=THREE.PCFShadowMap;this.cullFace=THREE.CullFaceFront;this.cascade=this.debug=!1;this.render=function(c,m){if(!1!==w.enabled){var q,I,v,D,L,C,E,R=[];D=0;e.clearColor(1,1,1,1);e.disable(e.BLEND);e.enable(e.CULL_FACE);e.frontFace(e.CCW);w.cullFace===THREE.CullFaceFront?e.cullFace(e.FRONT):e.cullFace(e.BACK);a.state.setDepthTest(!0);q=0;for(I=b.length;q<I;q++)if(v=b[q],v.castShadow)if(v instanceof THREE.DirectionalLight&&v.shadowCascade)for(L=0;L<
+v.shadowCascadeCount;L++){var J;if(v.shadowCascadeArray[L])J=v.shadowCascadeArray[L];else{var z=v;E=L;J=new THREE.DirectionalLight;J.isVirtual=!0;J.onlyShadow=!0;J.castShadow=!0;J.shadowCameraNear=z.shadowCameraNear;J.shadowCameraFar=z.shadowCameraFar;J.shadowCameraLeft=z.shadowCameraLeft;J.shadowCameraRight=z.shadowCameraRight;J.shadowCameraBottom=z.shadowCameraBottom;J.shadowCameraTop=z.shadowCameraTop;J.shadowCameraVisible=z.shadowCameraVisible;J.shadowDarkness=z.shadowDarkness;J.shadowBias=z.shadowCascadeBias[E];
+J.shadowMapWidth=z.shadowCascadeWidth[E];J.shadowMapHeight=z.shadowCascadeHeight[E];J.pointsWorld=[];J.pointsFrustum=[];var F=J.pointsWorld;C=J.pointsFrustum;for(var B=0;8>B;B++)F[B]=new THREE.Vector3,C[B]=new THREE.Vector3;F=z.shadowCascadeNearZ[E];z=z.shadowCascadeFarZ[E];C[0].set(-1,-1,F);C[1].set(1,-1,F);C[2].set(-1,1,F);C[3].set(1,1,F);C[4].set(-1,-1,z);C[5].set(1,-1,z);C[6].set(-1,1,z);C[7].set(1,1,z);J.originalCamera=m;C=new THREE.Gyroscope;C.position.copy(v.shadowCascadeOffset);C.add(J);C.add(J.target);
+m.add(C);v.shadowCascadeArray[L]=J}E=v;F=L;z=E.shadowCascadeArray[F];z.position.copy(E.position);z.target.position.copy(E.target.position);z.lookAt(z.target);z.shadowCameraVisible=E.shadowCameraVisible;z.shadowDarkness=E.shadowDarkness;z.shadowBias=E.shadowCascadeBias[F];C=E.shadowCascadeNearZ[F];E=E.shadowCascadeFarZ[F];z=z.pointsFrustum;z[0].z=C;z[1].z=C;z[2].z=C;z[3].z=C;z[4].z=E;z[5].z=E;z[6].z=E;z[7].z=E;R[D]=J;D++}else R[D]=v,D++;q=0;for(I=R.length;q<I;q++){v=R[q];v.shadowMap||(L=THREE.LinearFilter,
+w.type===THREE.PCFSoftShadowMap&&(L=THREE.NearestFilter),v.shadowMap=new THREE.WebGLRenderTarget(v.shadowMapWidth,v.shadowMapHeight,{minFilter:L,magFilter:L,format:THREE.RGBAFormat}),v.shadowMapSize=new THREE.Vector2(v.shadowMapWidth,v.shadowMapHeight),v.shadowMatrix=new THREE.Matrix4);if(!v.shadowCamera){if(v instanceof THREE.SpotLight)v.shadowCamera=new THREE.PerspectiveCamera(v.shadowCameraFov,v.shadowMapWidth/v.shadowMapHeight,v.shadowCameraNear,v.shadowCameraFar);else if(v instanceof THREE.DirectionalLight)v.shadowCamera=
+new THREE.OrthographicCamera(v.shadowCameraLeft,v.shadowCameraRight,v.shadowCameraTop,v.shadowCameraBottom,v.shadowCameraNear,v.shadowCameraFar);else{console.error("THREE.ShadowMapPlugin: Unsupported light type for shadow",v);continue}c.add(v.shadowCamera);!0===c.autoUpdate&&c.updateMatrixWorld()}v.shadowCameraVisible&&!v.cameraHelper&&(v.cameraHelper=new THREE.CameraHelper(v.shadowCamera),c.add(v.cameraHelper));if(v.isVirtual&&J.originalCamera==m){L=m;D=v.shadowCamera;C=v.pointsFrustum;z=v.pointsWorld;
+h.set(Infinity,Infinity,Infinity);k.set(-Infinity,-Infinity,-Infinity);for(E=0;8>E;E++)F=z[E],F.copy(C[E]),F.unproject(L),F.applyMatrix4(D.matrixWorldInverse),F.x<h.x&&(h.x=F.x),F.x>k.x&&(k.x=F.x),F.y<h.y&&(h.y=F.y),F.y>k.y&&(k.y=F.y),F.z<h.z&&(h.z=F.z),F.z>k.z&&(k.z=F.z);D.left=h.x;D.right=k.x;D.top=k.y;D.bottom=h.y;D.updateProjectionMatrix()}D=v.shadowMap;C=v.shadowMatrix;L=v.shadowCamera;L.position.setFromMatrixPosition(v.matrixWorld);n.setFromMatrixPosition(v.target.matrixWorld);L.lookAt(n);L.updateMatrixWorld();
+L.matrixWorldInverse.getInverse(L.matrixWorld);v.cameraHelper&&(v.cameraHelper.visible=v.shadowCameraVisible);v.shadowCameraVisible&&v.cameraHelper.update();C.set(.5,0,0,.5,0,.5,0,.5,0,0,.5,.5,0,0,0,1);C.multiply(L.projectionMatrix);C.multiply(L.matrixWorldInverse);g.multiplyMatrices(L.projectionMatrix,L.matrixWorldInverse);f.setFromMatrix(g);a.setRenderTarget(D);a.clear();p.length=0;d(c,L);v=0;for(D=p.length;v<D;v++)C=p[v],C=C.object,z=C.material instanceof THREE.MeshFaceMaterial?C.material.materials[0]:
+C.material,E=void 0!==C.geometry.morphTargets&&0<C.geometry.morphTargets.length&&z.morphTargets,F=C instanceof THREE.SkinnedMesh&&z.skinning,E=C.customDepthMaterial?C.customDepthMaterial:F?E?x:u:E?t:s,a.setMaterialFaces(z),a.renderBufferDirect(L,b,null,E,C);v=0;for(D=l.length;v<D;v++)C=l[v],C=C.object,C.visible&&C.castShadow&&(C._modelViewMatrix.multiplyMatrices(L.matrixWorldInverse,C.matrixWorld),a.renderImmediateObject(L,b,null,s,C))}q=a.getClearColor();I=a.getClearAlpha();e.clearColor(q.r,q.g,
+q.b,I);e.enable(e.BLEND);w.cullFace===THREE.CullFaceFront&&e.cullFace(e.BACK);a.resetGLState()}}};
+THREE.WebGLState=function(a,b){var c=this,d=new Uint8Array(16),e=new Uint8Array(16),f=null,g=null,h=null,k=null,l=null,n=null,p=null,m=null,q=null,s=null,t=null,u=null,x=null,w=null,A=null,y=null,G=null,I=a.getParameter(a.MAX_TEXTURE_IMAGE_UNITS),v=void 0,D={};this.initAttributes=function(){for(var a=0,b=d.length;a<b;a++)d[a]=0};this.enableAttribute=function(b){d[b]=1;0===e[b]&&(a.enableVertexAttribArray(b),e[b]=1)};this.disableUnusedAttributes=function(){for(var b=0,c=e.length;b<c;b++)e[b]!==d[b]&&
 (a.disableVertexAttribArray(b),e[b]=0)};this.setBlending=function(c,d,e,m,q,s,t){c!==f&&(c===THREE.NoBlending?a.disable(a.BLEND):c===THREE.AdditiveBlending?(a.enable(a.BLEND),a.blendEquation(a.FUNC_ADD),a.blendFunc(a.SRC_ALPHA,a.ONE)):c===THREE.SubtractiveBlending?(a.enable(a.BLEND),a.blendEquation(a.FUNC_ADD),a.blendFunc(a.ZERO,a.ONE_MINUS_SRC_COLOR)):c===THREE.MultiplyBlending?(a.enable(a.BLEND),a.blendEquation(a.FUNC_ADD),a.blendFunc(a.ZERO,a.SRC_COLOR)):c===THREE.CustomBlending?a.enable(a.BLEND):
 (a.disableVertexAttribArray(b),e[b]=0)};this.setBlending=function(c,d,e,m,q,s,t){c!==f&&(c===THREE.NoBlending?a.disable(a.BLEND):c===THREE.AdditiveBlending?(a.enable(a.BLEND),a.blendEquation(a.FUNC_ADD),a.blendFunc(a.SRC_ALPHA,a.ONE)):c===THREE.SubtractiveBlending?(a.enable(a.BLEND),a.blendEquation(a.FUNC_ADD),a.blendFunc(a.ZERO,a.ONE_MINUS_SRC_COLOR)):c===THREE.MultiplyBlending?(a.enable(a.BLEND),a.blendEquation(a.FUNC_ADD),a.blendFunc(a.ZERO,a.SRC_COLOR)):c===THREE.CustomBlending?a.enable(a.BLEND):
 (a.enable(a.BLEND),a.blendEquationSeparate(a.FUNC_ADD,a.FUNC_ADD),a.blendFuncSeparate(a.SRC_ALPHA,a.ONE_MINUS_SRC_ALPHA,a.ONE,a.ONE_MINUS_SRC_ALPHA)),f=c);if(c===THREE.CustomBlending){q=q||d;s=s||e;t=t||m;if(d!==g||q!==l)a.blendEquationSeparate(b(d),b(q)),g=d,l=q;if(e!==h||m!==k||s!==n||t!==p)a.blendFuncSeparate(b(e),b(m),b(s),b(t)),h=e,k=m,n=s,p=t}else p=n=l=k=h=g=null};this.setDepthFunc=function(b){if(m!==b){if(b)switch(b){case THREE.NeverDepth:a.depthFunc(a.NEVER);break;case THREE.AlwaysDepth:a.depthFunc(a.ALWAYS);
 (a.enable(a.BLEND),a.blendEquationSeparate(a.FUNC_ADD,a.FUNC_ADD),a.blendFuncSeparate(a.SRC_ALPHA,a.ONE_MINUS_SRC_ALPHA,a.ONE,a.ONE_MINUS_SRC_ALPHA)),f=c);if(c===THREE.CustomBlending){q=q||d;s=s||e;t=t||m;if(d!==g||q!==l)a.blendEquationSeparate(b(d),b(q)),g=d,l=q;if(e!==h||m!==k||s!==n||t!==p)a.blendFuncSeparate(b(e),b(m),b(s),b(t)),h=e,k=m,n=s,p=t}else p=n=l=k=h=g=null};this.setDepthFunc=function(b){if(m!==b){if(b)switch(b){case THREE.NeverDepth:a.depthFunc(a.NEVER);break;case THREE.AlwaysDepth:a.depthFunc(a.ALWAYS);
-break;case THREE.LessDepth:a.depthFunc(a.LESS);break;case THREE.LessEqualDepth:a.depthFunc(a.LEQUAL);break;case THREE.EqualDepth:a.depthFunc(a.EQUAL);break;case THREE.GreaterEqualDepth:a.depthFunc(a.GEQUAL);break;case THREE.GreaterDepth:a.depthFunc(a.GREATER);break;case THREE.NotEqualDepth:a.depthFunc(a.NOTEQUAL);break;default:a.depthFunc(a.LEQUAL)}else a.depthFunc(a.LEQUAL);m=b}};this.setDepthTest=function(b){q!==b&&(b?a.enable(a.DEPTH_TEST):a.disable(a.DEPTH_TEST),q=b)};this.setDepthWrite=function(b){t!==
-b&&(a.depthMask(b),t=b)};this.setColorWrite=function(b){s!==b&&(a.colorMask(b,b,b,b),s=b)};this.setDoubleSided=function(b){u!==b&&(b?a.disable(a.CULL_FACE):a.enable(a.CULL_FACE),u=b)};this.setFlipSided=function(b){w!==b&&(b?a.frontFace(a.CW):a.frontFace(a.CCW),w=b)};this.setLineWidth=function(b){b!==x&&(a.lineWidth(b),x=b)};this.setPolygonOffset=function(b,c,d){A!==b&&(b?a.enable(a.POLYGON_OFFSET_FILL):a.disable(a.POLYGON_OFFSET_FILL),A=b);!b||y===c&&D===d||(a.polygonOffset(c,d),y=c,D=d)};this.activeTexture=
-function(b){void 0===b&&(b=a.TEXTURE0+I-1);v!==b&&(a.activeTexture(b),v=b)};this.bindTexture=function(b,d){void 0===v&&c.activeTexture();var e=E[v];void 0===e&&(e={type:void 0,texture:void 0},E[v]=e);if(e.type!==b||e.texture!==d)a.bindTexture(b,d),e.type=b,e.texture=d};this.compressedTexImage2D=function(){try{a.compressedTexImage2D.apply(a,arguments)}catch(b){console.error(b)}};this.texImage2D=function(){try{a.texImage2D.apply(a,arguments)}catch(b){console.error(b)}};this.reset=function(){for(var b=
-0;b<e.length;b++)1===e[b]&&(a.disableVertexAttribArray(b),e[b]=0);w=u=s=t=q=f=null}};
-THREE.LensFlarePlugin=function(a,b){var c,d,e,f,g,h,k,l,n,p,m=a.context,q,t,s,u,w,x;this.render=function(A,y,D,I){if(0!==b.length){A=new THREE.Vector3;var v=I/D,E=.5*D,L=.5*I,C=16/I,F=new THREE.Vector2(C*v,C),R=new THREE.Vector3(1,1,0),J=new THREE.Vector2(1,1);if(void 0===s){var C=new Float32Array([-1,-1,0,0,1,-1,1,0,1,1,1,1,-1,1,0,1]),z=new Uint16Array([0,1,2,0,2,3]);q=m.createBuffer();t=m.createBuffer();m.bindBuffer(m.ARRAY_BUFFER,q);m.bufferData(m.ARRAY_BUFFER,C,m.STATIC_DRAW);m.bindBuffer(m.ELEMENT_ARRAY_BUFFER,
-t);m.bufferData(m.ELEMENT_ARRAY_BUFFER,z,m.STATIC_DRAW);w=m.createTexture();x=m.createTexture();a.state.bindTexture(m.TEXTURE_2D,w);m.texImage2D(m.TEXTURE_2D,0,m.RGB,16,16,0,m.RGB,m.UNSIGNED_BYTE,null);m.texParameteri(m.TEXTURE_2D,m.TEXTURE_WRAP_S,m.CLAMP_TO_EDGE);m.texParameteri(m.TEXTURE_2D,m.TEXTURE_WRAP_T,m.CLAMP_TO_EDGE);m.texParameteri(m.TEXTURE_2D,m.TEXTURE_MAG_FILTER,m.NEAREST);m.texParameteri(m.TEXTURE_2D,m.TEXTURE_MIN_FILTER,m.NEAREST);a.state.bindTexture(m.TEXTURE_2D,x);m.texImage2D(m.TEXTURE_2D,
+break;case THREE.LessDepth:a.depthFunc(a.LESS);break;case THREE.LessEqualDepth:a.depthFunc(a.LEQUAL);break;case THREE.EqualDepth:a.depthFunc(a.EQUAL);break;case THREE.GreaterEqualDepth:a.depthFunc(a.GEQUAL);break;case THREE.GreaterDepth:a.depthFunc(a.GREATER);break;case THREE.NotEqualDepth:a.depthFunc(a.NOTEQUAL);break;default:a.depthFunc(a.LEQUAL)}else a.depthFunc(a.LEQUAL);m=b}};this.setDepthTest=function(b){q!==b&&(b?a.enable(a.DEPTH_TEST):a.disable(a.DEPTH_TEST),q=b)};this.setDepthWrite=function(b){s!==
+b&&(a.depthMask(b),s=b)};this.setColorWrite=function(b){t!==b&&(a.colorMask(b,b,b,b),t=b)};this.setDoubleSided=function(b){u!==b&&(b?a.disable(a.CULL_FACE):a.enable(a.CULL_FACE),u=b)};this.setFlipSided=function(b){x!==b&&(b?a.frontFace(a.CW):a.frontFace(a.CCW),x=b)};this.setLineWidth=function(b){b!==w&&(a.lineWidth(b),w=b)};this.setPolygonOffset=function(b,c,d){A!==b&&(b?a.enable(a.POLYGON_OFFSET_FILL):a.disable(a.POLYGON_OFFSET_FILL),A=b);!b||y===c&&G===d||(a.polygonOffset(c,d),y=c,G=d)};this.activeTexture=
+function(b){void 0===b&&(b=a.TEXTURE0+I-1);v!==b&&(a.activeTexture(b),v=b)};this.bindTexture=function(b,d){void 0===v&&c.activeTexture();var e=D[v];void 0===e&&(e={type:void 0,texture:void 0},D[v]=e);if(e.type!==b||e.texture!==d)a.bindTexture(b,d),e.type=b,e.texture=d};this.compressedTexImage2D=function(){try{a.compressedTexImage2D.apply(a,arguments)}catch(b){console.error(b)}};this.texImage2D=function(){try{a.texImage2D.apply(a,arguments)}catch(b){console.error(b)}};this.reset=function(){for(var b=
+0;b<e.length;b++)1===e[b]&&(a.disableVertexAttribArray(b),e[b]=0);x=u=t=s=q=f=null}};
+THREE.LensFlarePlugin=function(a,b){var c,d,e,f,g,h,k,l,n,p,m=a.context,q,s,t,u,x,w;this.render=function(A,y,G,I){if(0!==b.length){A=new THREE.Vector3;var v=I/G,D=.5*G,L=.5*I,C=16/I,E=new THREE.Vector2(C*v,C),R=new THREE.Vector3(1,1,0),J=new THREE.Vector2(1,1);if(void 0===t){var C=new Float32Array([-1,-1,0,0,1,-1,1,0,1,1,1,1,-1,1,0,1]),z=new Uint16Array([0,1,2,0,2,3]);q=m.createBuffer();s=m.createBuffer();m.bindBuffer(m.ARRAY_BUFFER,q);m.bufferData(m.ARRAY_BUFFER,C,m.STATIC_DRAW);m.bindBuffer(m.ELEMENT_ARRAY_BUFFER,
+s);m.bufferData(m.ELEMENT_ARRAY_BUFFER,z,m.STATIC_DRAW);x=m.createTexture();w=m.createTexture();a.state.bindTexture(m.TEXTURE_2D,x);m.texImage2D(m.TEXTURE_2D,0,m.RGB,16,16,0,m.RGB,m.UNSIGNED_BYTE,null);m.texParameteri(m.TEXTURE_2D,m.TEXTURE_WRAP_S,m.CLAMP_TO_EDGE);m.texParameteri(m.TEXTURE_2D,m.TEXTURE_WRAP_T,m.CLAMP_TO_EDGE);m.texParameteri(m.TEXTURE_2D,m.TEXTURE_MAG_FILTER,m.NEAREST);m.texParameteri(m.TEXTURE_2D,m.TEXTURE_MIN_FILTER,m.NEAREST);a.state.bindTexture(m.TEXTURE_2D,w);m.texImage2D(m.TEXTURE_2D,
 0,m.RGBA,16,16,0,m.RGBA,m.UNSIGNED_BYTE,null);m.texParameteri(m.TEXTURE_2D,m.TEXTURE_WRAP_S,m.CLAMP_TO_EDGE);m.texParameteri(m.TEXTURE_2D,m.TEXTURE_WRAP_T,m.CLAMP_TO_EDGE);m.texParameteri(m.TEXTURE_2D,m.TEXTURE_MAG_FILTER,m.NEAREST);m.texParameteri(m.TEXTURE_2D,m.TEXTURE_MIN_FILTER,m.NEAREST);var C=(u=0<m.getParameter(m.MAX_VERTEX_TEXTURE_IMAGE_UNITS))?{vertexShader:"uniform lowp int renderType;\nuniform vec3 screenPosition;\nuniform vec2 scale;\nuniform float rotation;\nuniform sampler2D occlusionMap;\nattribute vec2 position;\nattribute vec2 uv;\nvarying vec2 vUV;\nvarying float vVisibility;\nvoid main() {\nvUV = uv;\nvec2 pos = position;\nif( renderType == 2 ) {\nvec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.5, 0.1 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.9, 0.1 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.9, 0.9 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.1, 0.9 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.5, 0.5 ) );\nvVisibility =        visibility.r / 9.0;\nvVisibility *= 1.0 - visibility.g / 9.0;\nvVisibility *=       visibility.b / 9.0;\nvVisibility *= 1.0 - visibility.a / 9.0;\npos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;\npos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;\n}\ngl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );\n}",
 0,m.RGBA,16,16,0,m.RGBA,m.UNSIGNED_BYTE,null);m.texParameteri(m.TEXTURE_2D,m.TEXTURE_WRAP_S,m.CLAMP_TO_EDGE);m.texParameteri(m.TEXTURE_2D,m.TEXTURE_WRAP_T,m.CLAMP_TO_EDGE);m.texParameteri(m.TEXTURE_2D,m.TEXTURE_MAG_FILTER,m.NEAREST);m.texParameteri(m.TEXTURE_2D,m.TEXTURE_MIN_FILTER,m.NEAREST);var C=(u=0<m.getParameter(m.MAX_VERTEX_TEXTURE_IMAGE_UNITS))?{vertexShader:"uniform lowp int renderType;\nuniform vec3 screenPosition;\nuniform vec2 scale;\nuniform float rotation;\nuniform sampler2D occlusionMap;\nattribute vec2 position;\nattribute vec2 uv;\nvarying vec2 vUV;\nvarying float vVisibility;\nvoid main() {\nvUV = uv;\nvec2 pos = position;\nif( renderType == 2 ) {\nvec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.5, 0.1 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.9, 0.1 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.9, 0.9 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.1, 0.9 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) );\nvisibility += texture2D( occlusionMap, vec2( 0.5, 0.5 ) );\nvVisibility =        visibility.r / 9.0;\nvVisibility *= 1.0 - visibility.g / 9.0;\nvVisibility *=       visibility.b / 9.0;\nvVisibility *= 1.0 - visibility.a / 9.0;\npos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;\npos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;\n}\ngl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );\n}",
 fragmentShader:"uniform lowp int renderType;\nuniform sampler2D map;\nuniform float opacity;\nuniform vec3 color;\nvarying vec2 vUV;\nvarying float vVisibility;\nvoid main() {\nif( renderType == 0 ) {\ngl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );\n} else if( renderType == 1 ) {\ngl_FragColor = texture2D( map, vUV );\n} else {\nvec4 texture = texture2D( map, vUV );\ntexture.a *= opacity * vVisibility;\ngl_FragColor = texture;\ngl_FragColor.rgb *= color;\n}\n}"}:{vertexShader:"uniform lowp int renderType;\nuniform vec3 screenPosition;\nuniform vec2 scale;\nuniform float rotation;\nattribute vec2 position;\nattribute vec2 uv;\nvarying vec2 vUV;\nvoid main() {\nvUV = uv;\nvec2 pos = position;\nif( renderType == 2 ) {\npos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;\npos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;\n}\ngl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );\n}",
 fragmentShader:"uniform lowp int renderType;\nuniform sampler2D map;\nuniform float opacity;\nuniform vec3 color;\nvarying vec2 vUV;\nvarying float vVisibility;\nvoid main() {\nif( renderType == 0 ) {\ngl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );\n} else if( renderType == 1 ) {\ngl_FragColor = texture2D( map, vUV );\n} else {\nvec4 texture = texture2D( map, vUV );\ntexture.a *= opacity * vVisibility;\ngl_FragColor = texture;\ngl_FragColor.rgb *= color;\n}\n}"}:{vertexShader:"uniform lowp int renderType;\nuniform vec3 screenPosition;\nuniform vec2 scale;\nuniform float rotation;\nattribute vec2 position;\nattribute vec2 uv;\nvarying vec2 vUV;\nvoid main() {\nvUV = uv;\nvec2 pos = position;\nif( renderType == 2 ) {\npos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;\npos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;\n}\ngl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );\n}",
 fragmentShader:"precision mediump float;\nuniform lowp int renderType;\nuniform sampler2D map;\nuniform sampler2D occlusionMap;\nuniform float opacity;\nuniform vec3 color;\nvarying vec2 vUV;\nvoid main() {\nif( renderType == 0 ) {\ngl_FragColor = vec4( texture2D( map, vUV ).rgb, 0.0 );\n} else if( renderType == 1 ) {\ngl_FragColor = texture2D( map, vUV );\n} else {\nfloat visibility = texture2D( occlusionMap, vec2( 0.5, 0.1 ) ).a;\nvisibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) ).a;\nvisibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) ).a;\nvisibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) ).a;\nvisibility = ( 1.0 - visibility / 4.0 );\nvec4 texture = texture2D( map, vUV );\ntexture.a *= opacity * visibility;\ngl_FragColor = texture;\ngl_FragColor.rgb *= color;\n}\n}"},
 fragmentShader:"precision mediump float;\nuniform lowp int renderType;\nuniform sampler2D map;\nuniform sampler2D occlusionMap;\nuniform float opacity;\nuniform vec3 color;\nvarying vec2 vUV;\nvoid main() {\nif( renderType == 0 ) {\ngl_FragColor = vec4( texture2D( map, vUV ).rgb, 0.0 );\n} else if( renderType == 1 ) {\ngl_FragColor = texture2D( map, vUV );\n} else {\nfloat visibility = texture2D( occlusionMap, vec2( 0.5, 0.1 ) ).a;\nvisibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) ).a;\nvisibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) ).a;\nvisibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) ).a;\nvisibility = ( 1.0 - visibility / 4.0 );\nvec4 texture = texture2D( map, vUV );\ntexture.a *= opacity * visibility;\ngl_FragColor = texture;\ngl_FragColor.rgb *= color;\n}\n}"},
-z=m.createProgram(),G=m.createShader(m.FRAGMENT_SHADER),B=m.createShader(m.VERTEX_SHADER),T="precision "+a.getPrecision()+" float;\n";m.shaderSource(G,T+C.fragmentShader);m.shaderSource(B,T+C.vertexShader);m.compileShader(G);m.compileShader(B);m.attachShader(z,G);m.attachShader(z,B);m.linkProgram(z);s=z;n=m.getAttribLocation(s,"position");p=m.getAttribLocation(s,"uv");c=m.getUniformLocation(s,"renderType");d=m.getUniformLocation(s,"map");e=m.getUniformLocation(s,"occlusionMap");f=m.getUniformLocation(s,
-"opacity");g=m.getUniformLocation(s,"color");h=m.getUniformLocation(s,"scale");k=m.getUniformLocation(s,"rotation");l=m.getUniformLocation(s,"screenPosition")}m.useProgram(s);a.state.initAttributes();a.state.enableAttribute(n);a.state.enableAttribute(p);a.state.disableUnusedAttributes();m.uniform1i(e,0);m.uniform1i(d,1);m.bindBuffer(m.ARRAY_BUFFER,q);m.vertexAttribPointer(n,2,m.FLOAT,!1,16,0);m.vertexAttribPointer(p,2,m.FLOAT,!1,16,8);m.bindBuffer(m.ELEMENT_ARRAY_BUFFER,t);m.disable(m.CULL_FACE);
-m.depthMask(!1);z=0;for(G=b.length;z<G;z++)if(C=16/I,F.set(C*v,C),B=b[z],A.set(B.matrixWorld.elements[12],B.matrixWorld.elements[13],B.matrixWorld.elements[14]),A.applyMatrix4(y.matrixWorldInverse),A.applyProjection(y.projectionMatrix),R.copy(A),J.x=R.x*E+E,J.y=R.y*L+L,u||0<J.x&&J.x<D&&0<J.y&&J.y<I){a.state.activeTexture(m.TEXTURE1);a.state.bindTexture(m.TEXTURE_2D,w);m.copyTexImage2D(m.TEXTURE_2D,0,m.RGB,J.x-8,J.y-8,16,16,0);m.uniform1i(c,0);m.uniform2f(h,F.x,F.y);m.uniform3f(l,R.x,R.y,R.z);m.disable(m.BLEND);
-m.enable(m.DEPTH_TEST);m.drawElements(m.TRIANGLES,6,m.UNSIGNED_SHORT,0);a.state.activeTexture(m.TEXTURE0);a.state.bindTexture(m.TEXTURE_2D,x);m.copyTexImage2D(m.TEXTURE_2D,0,m.RGBA,J.x-8,J.y-8,16,16,0);m.uniform1i(c,1);m.disable(m.DEPTH_TEST);a.state.activeTexture(m.TEXTURE1);a.state.bindTexture(m.TEXTURE_2D,w);m.drawElements(m.TRIANGLES,6,m.UNSIGNED_SHORT,0);B.positionScreen.copy(R);B.customUpdateCallback?B.customUpdateCallback(B):B.updateLensFlares();m.uniform1i(c,2);m.enable(m.BLEND);for(var T=
-0,O=B.lensFlares.length;T<O;T++){var S=B.lensFlares[T];.001<S.opacity&&.001<S.scale&&(R.x=S.x,R.y=S.y,R.z=S.z,C=S.size*S.scale/I,F.x=C*v,F.y=C,m.uniform3f(l,R.x,R.y,R.z),m.uniform2f(h,F.x,F.y),m.uniform1f(k,S.rotation),m.uniform1f(f,S.opacity),m.uniform3f(g,S.color.r,S.color.g,S.color.b),a.state.setBlending(S.blending,S.blendEquation,S.blendSrc,S.blendDst),a.setTexture(S.texture,1),m.drawElements(m.TRIANGLES,6,m.UNSIGNED_SHORT,0))}}m.enable(m.CULL_FACE);m.enable(m.DEPTH_TEST);m.depthMask(!0);a.resetGLState()}}};
-THREE.SpritePlugin=function(a,b){var c,d,e,f,g,h,k,l,n,p,m,q,t,s,u,w,x;function A(a,b){return a.z!==b.z?b.z-a.z:b.id-a.id}var y=a.context,D,I,v,E,L=new THREE.Vector3,C=new THREE.Quaternion,F=new THREE.Vector3;this.render=function(R,J){if(0!==b.length){if(void 0===v){var z=new Float32Array([-.5,-.5,0,0,.5,-.5,1,0,.5,.5,1,1,-.5,.5,0,1]),G=new Uint16Array([0,1,2,0,2,3]);D=y.createBuffer();I=y.createBuffer();y.bindBuffer(y.ARRAY_BUFFER,D);y.bufferData(y.ARRAY_BUFFER,z,y.STATIC_DRAW);y.bindBuffer(y.ELEMENT_ARRAY_BUFFER,
-I);y.bufferData(y.ELEMENT_ARRAY_BUFFER,G,y.STATIC_DRAW);var z=y.createProgram(),G=y.createShader(y.VERTEX_SHADER),B=y.createShader(y.FRAGMENT_SHADER);y.shaderSource(G,["precision "+a.getPrecision()+" float;","uniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform float rotation;\nuniform vec2 scale;\nuniform vec2 uvOffset;\nuniform vec2 uvScale;\nattribute vec2 position;\nattribute vec2 uv;\nvarying vec2 vUV;\nvoid main() {\nvUV = uvOffset + uv * uvScale;\nvec2 alignedPosition = position * scale;\nvec2 rotatedPosition;\nrotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\nrotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\nvec4 finalPosition;\nfinalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\nfinalPosition.xy += rotatedPosition;\nfinalPosition = projectionMatrix * finalPosition;\ngl_Position = finalPosition;\n}"].join("\n"));
+z=m.createProgram(),F=m.createShader(m.FRAGMENT_SHADER),B=m.createShader(m.VERTEX_SHADER),T="precision "+a.getPrecision()+" float;\n";m.shaderSource(F,T+C.fragmentShader);m.shaderSource(B,T+C.vertexShader);m.compileShader(F);m.compileShader(B);m.attachShader(z,F);m.attachShader(z,B);m.linkProgram(z);t=z;n=m.getAttribLocation(t,"position");p=m.getAttribLocation(t,"uv");c=m.getUniformLocation(t,"renderType");d=m.getUniformLocation(t,"map");e=m.getUniformLocation(t,"occlusionMap");f=m.getUniformLocation(t,
+"opacity");g=m.getUniformLocation(t,"color");h=m.getUniformLocation(t,"scale");k=m.getUniformLocation(t,"rotation");l=m.getUniformLocation(t,"screenPosition")}m.useProgram(t);a.state.initAttributes();a.state.enableAttribute(n);a.state.enableAttribute(p);a.state.disableUnusedAttributes();m.uniform1i(e,0);m.uniform1i(d,1);m.bindBuffer(m.ARRAY_BUFFER,q);m.vertexAttribPointer(n,2,m.FLOAT,!1,16,0);m.vertexAttribPointer(p,2,m.FLOAT,!1,16,8);m.bindBuffer(m.ELEMENT_ARRAY_BUFFER,s);m.disable(m.CULL_FACE);
+m.depthMask(!1);z=0;for(F=b.length;z<F;z++)if(C=16/I,E.set(C*v,C),B=b[z],A.set(B.matrixWorld.elements[12],B.matrixWorld.elements[13],B.matrixWorld.elements[14]),A.applyMatrix4(y.matrixWorldInverse),A.applyProjection(y.projectionMatrix),R.copy(A),J.x=R.x*D+D,J.y=R.y*L+L,u||0<J.x&&J.x<G&&0<J.y&&J.y<I){a.state.activeTexture(m.TEXTURE1);a.state.bindTexture(m.TEXTURE_2D,x);m.copyTexImage2D(m.TEXTURE_2D,0,m.RGB,J.x-8,J.y-8,16,16,0);m.uniform1i(c,0);m.uniform2f(h,E.x,E.y);m.uniform3f(l,R.x,R.y,R.z);m.disable(m.BLEND);
+m.enable(m.DEPTH_TEST);m.drawElements(m.TRIANGLES,6,m.UNSIGNED_SHORT,0);a.state.activeTexture(m.TEXTURE0);a.state.bindTexture(m.TEXTURE_2D,w);m.copyTexImage2D(m.TEXTURE_2D,0,m.RGBA,J.x-8,J.y-8,16,16,0);m.uniform1i(c,1);m.disable(m.DEPTH_TEST);a.state.activeTexture(m.TEXTURE1);a.state.bindTexture(m.TEXTURE_2D,x);m.drawElements(m.TRIANGLES,6,m.UNSIGNED_SHORT,0);B.positionScreen.copy(R);B.customUpdateCallback?B.customUpdateCallback(B):B.updateLensFlares();m.uniform1i(c,2);m.enable(m.BLEND);for(var T=
+0,O=B.lensFlares.length;T<O;T++){var S=B.lensFlares[T];.001<S.opacity&&.001<S.scale&&(R.x=S.x,R.y=S.y,R.z=S.z,C=S.size*S.scale/I,E.x=C*v,E.y=C,m.uniform3f(l,R.x,R.y,R.z),m.uniform2f(h,E.x,E.y),m.uniform1f(k,S.rotation),m.uniform1f(f,S.opacity),m.uniform3f(g,S.color.r,S.color.g,S.color.b),a.state.setBlending(S.blending,S.blendEquation,S.blendSrc,S.blendDst),a.setTexture(S.texture,1),m.drawElements(m.TRIANGLES,6,m.UNSIGNED_SHORT,0))}}m.enable(m.CULL_FACE);m.enable(m.DEPTH_TEST);m.depthMask(!0);a.resetGLState()}}};
+THREE.SpritePlugin=function(a,b){var c,d,e,f,g,h,k,l,n,p,m,q,s,t,u,x,w;function A(a,b){return a.z!==b.z?b.z-a.z:b.id-a.id}var y=a.context,G,I,v,D,L=new THREE.Vector3,C=new THREE.Quaternion,E=new THREE.Vector3;this.render=function(R,J){if(0!==b.length){if(void 0===v){var z=new Float32Array([-.5,-.5,0,0,.5,-.5,1,0,.5,.5,1,1,-.5,.5,0,1]),F=new Uint16Array([0,1,2,0,2,3]);G=y.createBuffer();I=y.createBuffer();y.bindBuffer(y.ARRAY_BUFFER,G);y.bufferData(y.ARRAY_BUFFER,z,y.STATIC_DRAW);y.bindBuffer(y.ELEMENT_ARRAY_BUFFER,
+I);y.bufferData(y.ELEMENT_ARRAY_BUFFER,F,y.STATIC_DRAW);var z=y.createProgram(),F=y.createShader(y.VERTEX_SHADER),B=y.createShader(y.FRAGMENT_SHADER);y.shaderSource(F,["precision "+a.getPrecision()+" float;","uniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform float rotation;\nuniform vec2 scale;\nuniform vec2 uvOffset;\nuniform vec2 uvScale;\nattribute vec2 position;\nattribute vec2 uv;\nvarying vec2 vUV;\nvoid main() {\nvUV = uvOffset + uv * uvScale;\nvec2 alignedPosition = position * scale;\nvec2 rotatedPosition;\nrotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\nrotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\nvec4 finalPosition;\nfinalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\nfinalPosition.xy += rotatedPosition;\nfinalPosition = projectionMatrix * finalPosition;\ngl_Position = finalPosition;\n}"].join("\n"));
 y.shaderSource(B,["precision "+a.getPrecision()+" float;","uniform vec3 color;\nuniform sampler2D map;\nuniform float opacity;\nuniform int fogType;\nuniform vec3 fogColor;\nuniform float fogDensity;\nuniform float fogNear;\nuniform float fogFar;\nuniform float alphaTest;\nvarying vec2 vUV;\nvoid main() {\nvec4 texture = texture2D( map, vUV );\nif ( texture.a < alphaTest ) discard;\ngl_FragColor = vec4( color * texture.xyz, texture.a * opacity );\nif ( fogType > 0 ) {\nfloat depth = gl_FragCoord.z / gl_FragCoord.w;\nfloat fogFactor = 0.0;\nif ( fogType == 1 ) {\nfogFactor = smoothstep( fogNear, fogFar, depth );\n} else {\nconst float LOG2 = 1.442695;\nfogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );\nfogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );\n}\ngl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );\n}\n}"].join("\n"));
 y.shaderSource(B,["precision "+a.getPrecision()+" float;","uniform vec3 color;\nuniform sampler2D map;\nuniform float opacity;\nuniform int fogType;\nuniform vec3 fogColor;\nuniform float fogDensity;\nuniform float fogNear;\nuniform float fogFar;\nuniform float alphaTest;\nvarying vec2 vUV;\nvoid main() {\nvec4 texture = texture2D( map, vUV );\nif ( texture.a < alphaTest ) discard;\ngl_FragColor = vec4( color * texture.xyz, texture.a * opacity );\nif ( fogType > 0 ) {\nfloat depth = gl_FragCoord.z / gl_FragCoord.w;\nfloat fogFactor = 0.0;\nif ( fogType == 1 ) {\nfogFactor = smoothstep( fogNear, fogFar, depth );\n} else {\nconst float LOG2 = 1.442695;\nfogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );\nfogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );\n}\ngl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );\n}\n}"].join("\n"));
-y.compileShader(G);y.compileShader(B);y.attachShader(z,G);y.attachShader(z,B);y.linkProgram(z);v=z;w=y.getAttribLocation(v,"position");x=y.getAttribLocation(v,"uv");c=y.getUniformLocation(v,"uvOffset");d=y.getUniformLocation(v,"uvScale");e=y.getUniformLocation(v,"rotation");f=y.getUniformLocation(v,"scale");g=y.getUniformLocation(v,"color");h=y.getUniformLocation(v,"map");k=y.getUniformLocation(v,"opacity");l=y.getUniformLocation(v,"modelViewMatrix");n=y.getUniformLocation(v,"projectionMatrix");p=
-y.getUniformLocation(v,"fogType");m=y.getUniformLocation(v,"fogDensity");q=y.getUniformLocation(v,"fogNear");t=y.getUniformLocation(v,"fogFar");s=y.getUniformLocation(v,"fogColor");u=y.getUniformLocation(v,"alphaTest");z=document.createElement("canvas");z.width=8;z.height=8;G=z.getContext("2d");G.fillStyle="white";G.fillRect(0,0,8,8);E=new THREE.Texture(z);E.needsUpdate=!0}y.useProgram(v);a.state.initAttributes();a.state.enableAttribute(w);a.state.enableAttribute(x);a.state.disableUnusedAttributes();
-y.disable(y.CULL_FACE);y.enable(y.BLEND);y.bindBuffer(y.ARRAY_BUFFER,D);y.vertexAttribPointer(w,2,y.FLOAT,!1,16,0);y.vertexAttribPointer(x,2,y.FLOAT,!1,16,8);y.bindBuffer(y.ELEMENT_ARRAY_BUFFER,I);y.uniformMatrix4fv(n,!1,J.projectionMatrix.elements);a.state.activeTexture(y.TEXTURE0);y.uniform1i(h,0);G=z=0;(B=R.fog)?(y.uniform3f(s,B.color.r,B.color.g,B.color.b),B instanceof THREE.Fog?(y.uniform1f(q,B.near),y.uniform1f(t,B.far),y.uniform1i(p,1),G=z=1):B instanceof THREE.FogExp2&&(y.uniform1f(m,B.density),
-y.uniform1i(p,2),G=z=2)):(y.uniform1i(p,0),G=z=0);for(var B=0,T=b.length;B<T;B++){var O=b[B];O._modelViewMatrix.multiplyMatrices(J.matrixWorldInverse,O.matrixWorld);O.z=-O._modelViewMatrix.elements[14]}b.sort(A);for(var S=[],B=0,T=b.length;B<T;B++){var O=b[B],P=O.material;y.uniform1f(u,P.alphaTest);y.uniformMatrix4fv(l,!1,O._modelViewMatrix.elements);O.matrixWorld.decompose(L,C,F);S[0]=F.x;S[1]=F.y;O=0;R.fog&&P.fog&&(O=G);z!==O&&(y.uniform1i(p,O),z=O);null!==P.map?(y.uniform2f(c,P.map.offset.x,P.map.offset.y),
-y.uniform2f(d,P.map.repeat.x,P.map.repeat.y)):(y.uniform2f(c,0,0),y.uniform2f(d,1,1));y.uniform1f(k,P.opacity);y.uniform3f(g,P.color.r,P.color.g,P.color.b);y.uniform1f(e,P.rotation);y.uniform2fv(f,S);a.state.setBlending(P.blending,P.blendEquation,P.blendSrc,P.blendDst);a.state.setDepthTest(P.depthTest);a.state.setDepthWrite(P.depthWrite);P.map&&P.map.image&&P.map.image.width?a.setTexture(P.map,0):a.setTexture(E,0);y.drawElements(y.TRIANGLES,6,y.UNSIGNED_SHORT,0)}y.enable(y.CULL_FACE);a.resetGLState()}}};
+y.compileShader(F);y.compileShader(B);y.attachShader(z,F);y.attachShader(z,B);y.linkProgram(z);v=z;x=y.getAttribLocation(v,"position");w=y.getAttribLocation(v,"uv");c=y.getUniformLocation(v,"uvOffset");d=y.getUniformLocation(v,"uvScale");e=y.getUniformLocation(v,"rotation");f=y.getUniformLocation(v,"scale");g=y.getUniformLocation(v,"color");h=y.getUniformLocation(v,"map");k=y.getUniformLocation(v,"opacity");l=y.getUniformLocation(v,"modelViewMatrix");n=y.getUniformLocation(v,"projectionMatrix");p=
+y.getUniformLocation(v,"fogType");m=y.getUniformLocation(v,"fogDensity");q=y.getUniformLocation(v,"fogNear");s=y.getUniformLocation(v,"fogFar");t=y.getUniformLocation(v,"fogColor");u=y.getUniformLocation(v,"alphaTest");z=document.createElement("canvas");z.width=8;z.height=8;F=z.getContext("2d");F.fillStyle="white";F.fillRect(0,0,8,8);D=new THREE.Texture(z);D.needsUpdate=!0}y.useProgram(v);a.state.initAttributes();a.state.enableAttribute(x);a.state.enableAttribute(w);a.state.disableUnusedAttributes();
+y.disable(y.CULL_FACE);y.enable(y.BLEND);y.bindBuffer(y.ARRAY_BUFFER,G);y.vertexAttribPointer(x,2,y.FLOAT,!1,16,0);y.vertexAttribPointer(w,2,y.FLOAT,!1,16,8);y.bindBuffer(y.ELEMENT_ARRAY_BUFFER,I);y.uniformMatrix4fv(n,!1,J.projectionMatrix.elements);a.state.activeTexture(y.TEXTURE0);y.uniform1i(h,0);F=z=0;(B=R.fog)?(y.uniform3f(t,B.color.r,B.color.g,B.color.b),B instanceof THREE.Fog?(y.uniform1f(q,B.near),y.uniform1f(s,B.far),y.uniform1i(p,1),F=z=1):B instanceof THREE.FogExp2&&(y.uniform1f(m,B.density),
+y.uniform1i(p,2),F=z=2)):(y.uniform1i(p,0),F=z=0);for(var B=0,T=b.length;B<T;B++){var O=b[B];O._modelViewMatrix.multiplyMatrices(J.matrixWorldInverse,O.matrixWorld);O.z=-O._modelViewMatrix.elements[14]}b.sort(A);for(var S=[],B=0,T=b.length;B<T;B++){var O=b[B],P=O.material;y.uniform1f(u,P.alphaTest);y.uniformMatrix4fv(l,!1,O._modelViewMatrix.elements);O.matrixWorld.decompose(L,C,E);S[0]=E.x;S[1]=E.y;O=0;R.fog&&P.fog&&(O=F);z!==O&&(y.uniform1i(p,O),z=O);null!==P.map?(y.uniform2f(c,P.map.offset.x,P.map.offset.y),
+y.uniform2f(d,P.map.repeat.x,P.map.repeat.y)):(y.uniform2f(c,0,0),y.uniform2f(d,1,1));y.uniform1f(k,P.opacity);y.uniform3f(g,P.color.r,P.color.g,P.color.b);y.uniform1f(e,P.rotation);y.uniform2fv(f,S);a.state.setBlending(P.blending,P.blendEquation,P.blendSrc,P.blendDst);a.state.setDepthTest(P.depthTest);a.state.setDepthWrite(P.depthWrite);P.map&&P.map.image&&P.map.image.width?a.setTexture(P.map,0):a.setTexture(D,0);y.drawElements(y.TRIANGLES,6,y.UNSIGNED_SHORT,0)}y.enable(y.CULL_FACE);a.resetGLState()}}};
 THREE.GeometryUtils={merge:function(a,b,c){console.warn("THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.");var d;b instanceof THREE.Mesh&&(b.matrixAutoUpdate&&b.updateMatrix(),d=b.matrix,b=b.geometry);a.merge(b,d,c)},center:function(a){console.warn("THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.");return a.center()}};
 THREE.GeometryUtils={merge:function(a,b,c){console.warn("THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.");var d;b instanceof THREE.Mesh&&(b.matrixAutoUpdate&&b.updateMatrix(),d=b.matrix,b=b.geometry);a.merge(b,d,c)},center:function(a){console.warn("THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.");return a.center()}};
 THREE.ImageUtils={crossOrigin:void 0,loadTexture:function(a,b,c,d){var e=new THREE.ImageLoader;e.crossOrigin=this.crossOrigin;var f=new THREE.Texture(void 0,b);e.load(a,function(a){f.image=a;f.needsUpdate=!0;c&&c(f)},void 0,function(a){d&&d(a)});f.sourceFile=a;return f},loadTextureCube:function(a,b,c,d){var e=new THREE.ImageLoader;e.crossOrigin=this.crossOrigin;var f=new THREE.CubeTexture([],b);f.flipY=!1;var g=0;b=function(b){e.load(a[b],function(a){f.images[b]=a;g+=1;6===g&&(f.needsUpdate=!0,c&&
 THREE.ImageUtils={crossOrigin:void 0,loadTexture:function(a,b,c,d){var e=new THREE.ImageLoader;e.crossOrigin=this.crossOrigin;var f=new THREE.Texture(void 0,b);e.load(a,function(a){f.image=a;f.needsUpdate=!0;c&&c(f)},void 0,function(a){d&&d(a)});f.sourceFile=a;return f},loadTextureCube:function(a,b,c,d){var e=new THREE.ImageLoader;e.crossOrigin=this.crossOrigin;var f=new THREE.CubeTexture([],b);f.flipY=!1;var g=0;b=function(b){e.load(a[b],function(a){f.images[b]=a;g+=1;6===g&&(f.needsUpdate=!0,c&&
 c(f))},void 0,d)};for(var h=0,k=a.length;h<k;++h)b(h);return f},loadCompressedTexture:function(){console.error("THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.")},loadCompressedTextureCube:function(){console.error("THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.")},getNormalMap:function(a,b){var c=function(a){var b=Math.sqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]);return[a[0]/b,a[1]/b,a[2]/b]};b|=1;var d=a.width,e=a.height,f=document.createElement("canvas");
 c(f))},void 0,d)};for(var h=0,k=a.length;h<k;++h)b(h);return f},loadCompressedTexture:function(){console.error("THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.")},loadCompressedTextureCube:function(){console.error("THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.")},getNormalMap:function(a,b){var c=function(a){var b=Math.sqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]);return[a[0]/b,a[1]/b,a[2]/b]};b|=1;var d=a.width,e=a.height,f=document.createElement("canvas");
-f.width=d;f.height=e;var g=f.getContext("2d");g.drawImage(a,0,0);for(var h=g.getImageData(0,0,d,e).data,k=g.createImageData(d,e),l=k.data,n=0;n<d;n++)for(var p=0;p<e;p++){var m=0>p-1?0:p-1,q=p+1>e-1?e-1:p+1,t=0>n-1?0:n-1,s=n+1>d-1?d-1:n+1,u=[],w=[0,0,h[4*(p*d+n)]/255*b];u.push([-1,0,h[4*(p*d+t)]/255*b]);u.push([-1,-1,h[4*(m*d+t)]/255*b]);u.push([0,-1,h[4*(m*d+n)]/255*b]);u.push([1,-1,h[4*(m*d+s)]/255*b]);u.push([1,0,h[4*(p*d+s)]/255*b]);u.push([1,1,h[4*(q*d+s)]/255*b]);u.push([0,1,h[4*(q*d+n)]/255*
-b]);u.push([-1,1,h[4*(q*d+t)]/255*b]);m=[];t=u.length;for(q=0;q<t;q++){var s=u[q],x=u[(q+1)%t],s=[s[0]-w[0],s[1]-w[1],s[2]-w[2]],x=[x[0]-w[0],x[1]-w[1],x[2]-w[2]];m.push(c([s[1]*x[2]-s[2]*x[1],s[2]*x[0]-s[0]*x[2],s[0]*x[1]-s[1]*x[0]]))}u=[0,0,0];for(q=0;q<m.length;q++)u[0]+=m[q][0],u[1]+=m[q][1],u[2]+=m[q][2];u[0]/=m.length;u[1]/=m.length;u[2]/=m.length;w=4*(p*d+n);l[w]=(u[0]+1)/2*255|0;l[w+1]=(u[1]+1)/2*255|0;l[w+2]=255*u[2]|0;l[w+3]=255}g.putImageData(k,0,0);return f},generateDataTexture:function(a,
+f.width=d;f.height=e;var g=f.getContext("2d");g.drawImage(a,0,0);for(var h=g.getImageData(0,0,d,e).data,k=g.createImageData(d,e),l=k.data,n=0;n<d;n++)for(var p=0;p<e;p++){var m=0>p-1?0:p-1,q=p+1>e-1?e-1:p+1,s=0>n-1?0:n-1,t=n+1>d-1?d-1:n+1,u=[],x=[0,0,h[4*(p*d+n)]/255*b];u.push([-1,0,h[4*(p*d+s)]/255*b]);u.push([-1,-1,h[4*(m*d+s)]/255*b]);u.push([0,-1,h[4*(m*d+n)]/255*b]);u.push([1,-1,h[4*(m*d+t)]/255*b]);u.push([1,0,h[4*(p*d+t)]/255*b]);u.push([1,1,h[4*(q*d+t)]/255*b]);u.push([0,1,h[4*(q*d+n)]/255*
+b]);u.push([-1,1,h[4*(q*d+s)]/255*b]);m=[];s=u.length;for(q=0;q<s;q++){var t=u[q],w=u[(q+1)%s],t=[t[0]-x[0],t[1]-x[1],t[2]-x[2]],w=[w[0]-x[0],w[1]-x[1],w[2]-x[2]];m.push(c([t[1]*w[2]-t[2]*w[1],t[2]*w[0]-t[0]*w[2],t[0]*w[1]-t[1]*w[0]]))}u=[0,0,0];for(q=0;q<m.length;q++)u[0]+=m[q][0],u[1]+=m[q][1],u[2]+=m[q][2];u[0]/=m.length;u[1]/=m.length;u[2]/=m.length;x=4*(p*d+n);l[x]=(u[0]+1)/2*255|0;l[x+1]=(u[1]+1)/2*255|0;l[x+2]=255*u[2]|0;l[x+3]=255}g.putImageData(k,0,0);return f},generateDataTexture:function(a,
 b,c){var d=a*b,e=new Uint8Array(3*d),f=Math.floor(255*c.r),g=Math.floor(255*c.g);c=Math.floor(255*c.b);for(var h=0;h<d;h++)e[3*h]=f,e[3*h+1]=g,e[3*h+2]=c;a=new THREE.DataTexture(e,a,b,THREE.RGBFormat);a.needsUpdate=!0;return a}};
 b,c){var d=a*b,e=new Uint8Array(3*d),f=Math.floor(255*c.r),g=Math.floor(255*c.g);c=Math.floor(255*c.b);for(var h=0;h<d;h++)e[3*h]=f,e[3*h+1]=g,e[3*h+2]=c;a=new THREE.DataTexture(e,a,b,THREE.RGBFormat);a.needsUpdate=!0;return a}};
 THREE.SceneUtils={createMultiMaterialObject:function(a,b){for(var c=new THREE.Object3D,d=0,e=b.length;d<e;d++)c.add(new THREE.Mesh(a,b[d]));return c},detach:function(a,b,c){a.applyMatrix(b.matrixWorld);b.remove(a);c.add(a)},attach:function(a,b,c){var d=new THREE.Matrix4;d.getInverse(c.matrixWorld);a.applyMatrix(d);b.remove(a);c.add(a)}};
 THREE.SceneUtils={createMultiMaterialObject:function(a,b){for(var c=new THREE.Object3D,d=0,e=b.length;d<e;d++)c.add(new THREE.Mesh(a,b[d]));return c},detach:function(a,b,c){a.applyMatrix(b.matrixWorld);b.remove(a);c.add(a)},attach:function(a,b,c){var d=new THREE.Matrix4;d.getInverse(c.matrixWorld);a.applyMatrix(d);b.remove(a);c.add(a)}};
 THREE.FontUtils={faces:{},face:"helvetiker",weight:"normal",style:"normal",size:150,divisions:10,getFace:function(){try{return this.faces[this.face][this.weight][this.style]}catch(a){throw"The font "+this.face+" with "+this.weight+" weight and "+this.style+" style is missing.";}},loadFace:function(a){var b=a.familyName.toLowerCase();this.faces[b]=this.faces[b]||{};this.faces[b][a.cssFontWeight]=this.faces[b][a.cssFontWeight]||{};this.faces[b][a.cssFontWeight][a.cssFontStyle]=a;return this.faces[b][a.cssFontWeight][a.cssFontStyle]=
 THREE.FontUtils={faces:{},face:"helvetiker",weight:"normal",style:"normal",size:150,divisions:10,getFace:function(){try{return this.faces[this.face][this.weight][this.style]}catch(a){throw"The font "+this.face+" with "+this.weight+" weight and "+this.style+" style is missing.";}},loadFace:function(a){var b=a.familyName.toLowerCase();this.faces[b]=this.faces[b]||{};this.faces[b][a.cssFontWeight]=this.faces[b][a.cssFontWeight]||{};this.faces[b][a.cssFontWeight][a.cssFontStyle]=a;return this.faces[b][a.cssFontWeight][a.cssFontStyle]=
-a},drawText:function(a){var b=this.getFace(),c=this.size/b.resolution,d=0,e=String(a).split(""),f=e.length,g=[];for(a=0;a<f;a++){var h=new THREE.Path,h=this.extractGlyphPoints(e[a],b,c,d,h),d=d+h.offset;g.push(h.path)}return{paths:g,offset:d/2}},extractGlyphPoints:function(a,b,c,d,e){var f=[],g,h,k,l,n,p,m,q,t,s,u,w=b.glyphs[a]||b.glyphs["?"];if(w){if(w.o)for(b=w._cachedOutline||(w._cachedOutline=w.o.split(" ")),l=b.length,a=0;a<l;)switch(k=b[a++],k){case "m":k=b[a++]*c+d;n=b[a++]*c;e.moveTo(k,n);
-break;case "l":k=b[a++]*c+d;n=b[a++]*c;e.lineTo(k,n);break;case "q":k=b[a++]*c+d;n=b[a++]*c;q=b[a++]*c+d;t=b[a++]*c;e.quadraticCurveTo(q,t,k,n);if(g=f[f.length-1])for(p=g.x,m=g.y,g=1,h=this.divisions;g<=h;g++){var x=g/h;THREE.Shape.Utils.b2(x,p,q,k);THREE.Shape.Utils.b2(x,m,t,n)}break;case "b":if(k=b[a++]*c+d,n=b[a++]*c,q=b[a++]*c+d,t=b[a++]*c,s=b[a++]*c+d,u=b[a++]*c,e.bezierCurveTo(q,t,s,u,k,n),g=f[f.length-1])for(p=g.x,m=g.y,g=1,h=this.divisions;g<=h;g++)x=g/h,THREE.Shape.Utils.b3(x,p,q,s,k),THREE.Shape.Utils.b3(x,
-m,t,u,n)}return{offset:w.ha*c,path:e}}}};
+a},drawText:function(a){var b=this.getFace(),c=this.size/b.resolution,d=0,e=String(a).split(""),f=e.length,g=[];for(a=0;a<f;a++){var h=new THREE.Path,h=this.extractGlyphPoints(e[a],b,c,d,h),d=d+h.offset;g.push(h.path)}return{paths:g,offset:d/2}},extractGlyphPoints:function(a,b,c,d,e){var f=[],g,h,k,l,n,p,m,q,s,t,u,x=b.glyphs[a]||b.glyphs["?"];if(x){if(x.o)for(b=x._cachedOutline||(x._cachedOutline=x.o.split(" ")),l=b.length,a=0;a<l;)switch(k=b[a++],k){case "m":k=b[a++]*c+d;n=b[a++]*c;e.moveTo(k,n);
+break;case "l":k=b[a++]*c+d;n=b[a++]*c;e.lineTo(k,n);break;case "q":k=b[a++]*c+d;n=b[a++]*c;q=b[a++]*c+d;s=b[a++]*c;e.quadraticCurveTo(q,s,k,n);if(g=f[f.length-1])for(p=g.x,m=g.y,g=1,h=this.divisions;g<=h;g++){var w=g/h;THREE.Shape.Utils.b2(w,p,q,k);THREE.Shape.Utils.b2(w,m,s,n)}break;case "b":if(k=b[a++]*c+d,n=b[a++]*c,q=b[a++]*c+d,s=b[a++]*c,t=b[a++]*c+d,u=b[a++]*c,e.bezierCurveTo(q,s,t,u,k,n),g=f[f.length-1])for(p=g.x,m=g.y,g=1,h=this.divisions;g<=h;g++)w=g/h,THREE.Shape.Utils.b3(w,p,q,t,k),THREE.Shape.Utils.b3(w,
+m,s,u,n)}return{offset:x.ha*c,path:e}}}};
 THREE.FontUtils.generateShapes=function(a,b){b=b||{};var c=void 0!==b.curveSegments?b.curveSegments:4,d=void 0!==b.font?b.font:"helvetiker",e=void 0!==b.weight?b.weight:"normal",f=void 0!==b.style?b.style:"normal";THREE.FontUtils.size=void 0!==b.size?b.size:100;THREE.FontUtils.divisions=c;THREE.FontUtils.face=d;THREE.FontUtils.weight=e;THREE.FontUtils.style=f;c=THREE.FontUtils.drawText(a).paths;d=[];e=0;for(f=c.length;e<f;e++)Array.prototype.push.apply(d,c[e].toShapes());return d};
 THREE.FontUtils.generateShapes=function(a,b){b=b||{};var c=void 0!==b.curveSegments?b.curveSegments:4,d=void 0!==b.font?b.font:"helvetiker",e=void 0!==b.weight?b.weight:"normal",f=void 0!==b.style?b.style:"normal";THREE.FontUtils.size=void 0!==b.size?b.size:100;THREE.FontUtils.divisions=c;THREE.FontUtils.face=d;THREE.FontUtils.weight=e;THREE.FontUtils.style=f;c=THREE.FontUtils.drawText(a).paths;d=[];e=0;for(f=c.length;e<f;e++)Array.prototype.push.apply(d,c[e].toShapes());return d};
-(function(a){var b=function(a){for(var b=a.length,e=0,f=b-1,g=0;g<b;f=g++)e+=a[f].x*a[g].y-a[g].x*a[f].y;return.5*e};a.Triangulate=function(a,d){var e=a.length;if(3>e)return null;var f=[],g=[],h=[],k,l,n;if(0<b(a))for(l=0;l<e;l++)g[l]=l;else for(l=0;l<e;l++)g[l]=e-1-l;var p=2*e;for(l=e-1;2<e;){if(0>=p--){console.warn("THREE.FontUtils: Warning, unable to triangulate polygon! in Triangulate.process()");break}k=l;e<=k&&(k=0);l=k+1;e<=l&&(l=0);n=l+1;e<=n&&(n=0);var m;a:{var q=m=void 0,t=void 0,s=void 0,
-u=void 0,w=void 0,x=void 0,A=void 0,y=void 0,q=a[g[k]].x,t=a[g[k]].y,s=a[g[l]].x,u=a[g[l]].y,w=a[g[n]].x,x=a[g[n]].y;if(1E-10>(s-q)*(x-t)-(u-t)*(w-q))m=!1;else{var D=void 0,I=void 0,v=void 0,E=void 0,L=void 0,C=void 0,F=void 0,R=void 0,J=void 0,z=void 0,J=R=F=y=A=void 0,D=w-s,I=x-u,v=q-w,E=t-x,L=s-q,C=u-t;for(m=0;m<e;m++)if(A=a[g[m]].x,y=a[g[m]].y,!(A===q&&y===t||A===s&&y===u||A===w&&y===x)&&(F=A-q,R=y-t,J=A-s,z=y-u,A-=w,y-=x,J=D*z-I*J,F=L*R-C*F,R=v*y-E*A,-1E-10<=J&&-1E-10<=R&&-1E-10<=F)){m=!1;break a}m=
+(function(a){var b=function(a){for(var b=a.length,e=0,f=b-1,g=0;g<b;f=g++)e+=a[f].x*a[g].y-a[g].x*a[f].y;return.5*e};a.Triangulate=function(a,d){var e=a.length;if(3>e)return null;var f=[],g=[],h=[],k,l,n;if(0<b(a))for(l=0;l<e;l++)g[l]=l;else for(l=0;l<e;l++)g[l]=e-1-l;var p=2*e;for(l=e-1;2<e;){if(0>=p--){console.warn("THREE.FontUtils: Warning, unable to triangulate polygon! in Triangulate.process()");break}k=l;e<=k&&(k=0);l=k+1;e<=l&&(l=0);n=l+1;e<=n&&(n=0);var m;a:{var q=m=void 0,s=void 0,t=void 0,
+u=void 0,x=void 0,w=void 0,A=void 0,y=void 0,q=a[g[k]].x,s=a[g[k]].y,t=a[g[l]].x,u=a[g[l]].y,x=a[g[n]].x,w=a[g[n]].y;if(1E-10>(t-q)*(w-s)-(u-s)*(x-q))m=!1;else{var G=void 0,I=void 0,v=void 0,D=void 0,L=void 0,C=void 0,E=void 0,R=void 0,J=void 0,z=void 0,J=R=E=y=A=void 0,G=x-t,I=w-u,v=q-x,D=s-w,L=t-q,C=u-s;for(m=0;m<e;m++)if(A=a[g[m]].x,y=a[g[m]].y,!(A===q&&y===s||A===t&&y===u||A===x&&y===w)&&(E=A-q,R=y-s,J=A-t,z=y-u,A-=x,y-=w,J=G*z-I*J,E=L*R-C*E,R=v*y-D*A,-1E-10<=J&&-1E-10<=R&&-1E-10<=E)){m=!1;break a}m=
 !0}}if(m){f.push([a[g[k]],a[g[l]],a[g[n]]]);h.push([g[k],g[l],g[n]]);k=l;for(n=l+1;n<e;k++,n++)g[k]=g[n];e--;p=2*e}}return d?h:f};a.Triangulate.area=b;return a})(THREE.FontUtils);THREE.typeface_js={faces:THREE.FontUtils.faces,loadFace:THREE.FontUtils.loadFace};"undefined"!==typeof self&&(self._typeface_js=THREE.typeface_js);
 !0}}if(m){f.push([a[g[k]],a[g[l]],a[g[n]]]);h.push([g[k],g[l],g[n]]);k=l;for(n=l+1;n<e;k++,n++)g[k]=g[n];e--;p=2*e}}return d?h:f};a.Triangulate.area=b;return a})(THREE.FontUtils);THREE.typeface_js={faces:THREE.FontUtils.faces,loadFace:THREE.FontUtils.loadFace};"undefined"!==typeof self&&(self._typeface_js=THREE.typeface_js);
 THREE.Audio=function(a){THREE.Object3D.call(this);this.type="Audio";this.context=a.context;this.source=this.context.createBufferSource();this.source.onended=this.onEnded.bind(this);this.gain=this.context.createGain();this.gain.connect(this.context.destination);this.panner=this.context.createPanner();this.panner.connect(this.gain);this.autoplay=!1;this.startTime=0;this.isPlaying=!1};THREE.Audio.prototype=Object.create(THREE.Object3D.prototype);THREE.Audio.prototype.constructor=THREE.Audio;
 THREE.Audio=function(a){THREE.Object3D.call(this);this.type="Audio";this.context=a.context;this.source=this.context.createBufferSource();this.source.onended=this.onEnded.bind(this);this.gain=this.context.createGain();this.gain.connect(this.context.destination);this.panner=this.context.createPanner();this.panner.connect(this.gain);this.autoplay=!1;this.startTime=0;this.isPlaying=!1};THREE.Audio.prototype=Object.create(THREE.Object3D.prototype);THREE.Audio.prototype.constructor=THREE.Audio;
 THREE.Audio.prototype.load=function(a){var b=this,c=new XMLHttpRequest;c.open("GET",a,!0);c.responseType="arraybuffer";c.onload=function(a){b.context.decodeAudioData(this.response,function(a){b.source.buffer=a;b.autoplay&&b.play()})};c.send();return this};
 THREE.Audio.prototype.load=function(a){var b=this,c=new XMLHttpRequest;c.open("GET",a,!0);c.responseType="arraybuffer";c.onload=function(a){b.context.decodeAudioData(this.response,function(a){b.source.buffer=a;b.autoplay&&b.play()})};c.send();return this};
@@ -670,21 +670,21 @@ THREE.Path.prototype.bezierCurveTo=function(a,b,c,d,e,f){var g=Array.prototype.s
 THREE.Path.prototype.splineThru=function(a){var b=Array.prototype.slice.call(arguments),c=this.actions[this.actions.length-1].args,c=[new THREE.Vector2(c[c.length-2],c[c.length-1])];Array.prototype.push.apply(c,a);c=new THREE.SplineCurve(c);this.curves.push(c);this.actions.push({action:THREE.PathActions.CSPLINE_THRU,args:b})};THREE.Path.prototype.arc=function(a,b,c,d,e,f){var g=this.actions[this.actions.length-1].args;this.absarc(a+g[g.length-2],b+g[g.length-1],c,d,e,f)};
 THREE.Path.prototype.splineThru=function(a){var b=Array.prototype.slice.call(arguments),c=this.actions[this.actions.length-1].args,c=[new THREE.Vector2(c[c.length-2],c[c.length-1])];Array.prototype.push.apply(c,a);c=new THREE.SplineCurve(c);this.curves.push(c);this.actions.push({action:THREE.PathActions.CSPLINE_THRU,args:b})};THREE.Path.prototype.arc=function(a,b,c,d,e,f){var g=this.actions[this.actions.length-1].args;this.absarc(a+g[g.length-2],b+g[g.length-1],c,d,e,f)};
 THREE.Path.prototype.absarc=function(a,b,c,d,e,f){this.absellipse(a,b,c,c,d,e,f)};THREE.Path.prototype.ellipse=function(a,b,c,d,e,f,g){var h=this.actions[this.actions.length-1].args;this.absellipse(a+h[h.length-2],b+h[h.length-1],c,d,e,f,g)};THREE.Path.prototype.absellipse=function(a,b,c,d,e,f,g){var h=Array.prototype.slice.call(arguments),k=new THREE.EllipseCurve(a,b,c,d,e,f,g);this.curves.push(k);k=k.getPoint(1);h.push(k.x);h.push(k.y);this.actions.push({action:THREE.PathActions.ELLIPSE,args:h})};
 THREE.Path.prototype.absarc=function(a,b,c,d,e,f){this.absellipse(a,b,c,c,d,e,f)};THREE.Path.prototype.ellipse=function(a,b,c,d,e,f,g){var h=this.actions[this.actions.length-1].args;this.absellipse(a+h[h.length-2],b+h[h.length-1],c,d,e,f,g)};THREE.Path.prototype.absellipse=function(a,b,c,d,e,f,g){var h=Array.prototype.slice.call(arguments),k=new THREE.EllipseCurve(a,b,c,d,e,f,g);this.curves.push(k);k=k.getPoint(1);h.push(k.x);h.push(k.y);this.actions.push({action:THREE.PathActions.ELLIPSE,args:h})};
 THREE.Path.prototype.getSpacedPoints=function(a,b){a||(a=40);for(var c=[],d=0;d<a;d++)c.push(this.getPoint(d/a));return c};
 THREE.Path.prototype.getSpacedPoints=function(a,b){a||(a=40);for(var c=[],d=0;d<a;d++)c.push(this.getPoint(d/a));return c};
-THREE.Path.prototype.getPoints=function(a,b){if(this.useSpacedPoints)return console.log("tata"),this.getSpacedPoints(a,b);a=a||12;var c=[],d,e,f,g,h,k,l,n,p,m,q,t,s;d=0;for(e=this.actions.length;d<e;d++)switch(f=this.actions[d],g=f.action,f=f.args,g){case THREE.PathActions.MOVE_TO:c.push(new THREE.Vector2(f[0],f[1]));break;case THREE.PathActions.LINE_TO:c.push(new THREE.Vector2(f[0],f[1]));break;case THREE.PathActions.QUADRATIC_CURVE_TO:h=f[2];k=f[3];p=f[0];m=f[1];0<c.length?(g=c[c.length-1],q=g.x,
-t=g.y):(g=this.actions[d-1].args,q=g[g.length-2],t=g[g.length-1]);for(f=1;f<=a;f++)s=f/a,g=THREE.Shape.Utils.b2(s,q,p,h),s=THREE.Shape.Utils.b2(s,t,m,k),c.push(new THREE.Vector2(g,s));break;case THREE.PathActions.BEZIER_CURVE_TO:h=f[4];k=f[5];p=f[0];m=f[1];l=f[2];n=f[3];0<c.length?(g=c[c.length-1],q=g.x,t=g.y):(g=this.actions[d-1].args,q=g[g.length-2],t=g[g.length-1]);for(f=1;f<=a;f++)s=f/a,g=THREE.Shape.Utils.b3(s,q,p,l,h),s=THREE.Shape.Utils.b3(s,t,m,n,k),c.push(new THREE.Vector2(g,s));break;case THREE.PathActions.CSPLINE_THRU:g=
-this.actions[d-1].args;s=[new THREE.Vector2(g[g.length-2],g[g.length-1])];g=a*f[0].length;s=s.concat(f[0]);s=new THREE.SplineCurve(s);for(f=1;f<=g;f++)c.push(s.getPointAt(f/g));break;case THREE.PathActions.ARC:h=f[0];k=f[1];m=f[2];l=f[3];g=f[4];p=!!f[5];q=g-l;t=2*a;for(f=1;f<=t;f++)s=f/t,p||(s=1-s),s=l+s*q,g=h+m*Math.cos(s),s=k+m*Math.sin(s),c.push(new THREE.Vector2(g,s));break;case THREE.PathActions.ELLIPSE:for(h=f[0],k=f[1],m=f[2],n=f[3],l=f[4],g=f[5],p=!!f[6],q=g-l,t=2*a,f=1;f<=t;f++)s=f/t,p||
-(s=1-s),s=l+s*q,g=h+m*Math.cos(s),s=k+n*Math.sin(s),c.push(new THREE.Vector2(g,s))}d=c[c.length-1];1E-10>Math.abs(d.x-c[0].x)&&1E-10>Math.abs(d.y-c[0].y)&&c.splice(c.length-1,1);b&&c.push(c[0]);return c};
+THREE.Path.prototype.getPoints=function(a,b){if(this.useSpacedPoints)return console.log("tata"),this.getSpacedPoints(a,b);a=a||12;var c=[],d,e,f,g,h,k,l,n,p,m,q,s,t;d=0;for(e=this.actions.length;d<e;d++)switch(f=this.actions[d],g=f.action,f=f.args,g){case THREE.PathActions.MOVE_TO:c.push(new THREE.Vector2(f[0],f[1]));break;case THREE.PathActions.LINE_TO:c.push(new THREE.Vector2(f[0],f[1]));break;case THREE.PathActions.QUADRATIC_CURVE_TO:h=f[2];k=f[3];p=f[0];m=f[1];0<c.length?(g=c[c.length-1],q=g.x,
+s=g.y):(g=this.actions[d-1].args,q=g[g.length-2],s=g[g.length-1]);for(f=1;f<=a;f++)t=f/a,g=THREE.Shape.Utils.b2(t,q,p,h),t=THREE.Shape.Utils.b2(t,s,m,k),c.push(new THREE.Vector2(g,t));break;case THREE.PathActions.BEZIER_CURVE_TO:h=f[4];k=f[5];p=f[0];m=f[1];l=f[2];n=f[3];0<c.length?(g=c[c.length-1],q=g.x,s=g.y):(g=this.actions[d-1].args,q=g[g.length-2],s=g[g.length-1]);for(f=1;f<=a;f++)t=f/a,g=THREE.Shape.Utils.b3(t,q,p,l,h),t=THREE.Shape.Utils.b3(t,s,m,n,k),c.push(new THREE.Vector2(g,t));break;case THREE.PathActions.CSPLINE_THRU:g=
+this.actions[d-1].args;t=[new THREE.Vector2(g[g.length-2],g[g.length-1])];g=a*f[0].length;t=t.concat(f[0]);t=new THREE.SplineCurve(t);for(f=1;f<=g;f++)c.push(t.getPointAt(f/g));break;case THREE.PathActions.ARC:h=f[0];k=f[1];m=f[2];l=f[3];g=f[4];p=!!f[5];q=g-l;s=2*a;for(f=1;f<=s;f++)t=f/s,p||(t=1-t),t=l+t*q,g=h+m*Math.cos(t),t=k+m*Math.sin(t),c.push(new THREE.Vector2(g,t));break;case THREE.PathActions.ELLIPSE:for(h=f[0],k=f[1],m=f[2],n=f[3],l=f[4],g=f[5],p=!!f[6],q=g-l,s=2*a,f=1;f<=s;f++)t=f/s,p||
+(t=1-t),t=l+t*q,g=h+m*Math.cos(t),t=k+n*Math.sin(t),c.push(new THREE.Vector2(g,t))}d=c[c.length-1];1E-10>Math.abs(d.x-c[0].x)&&1E-10>Math.abs(d.y-c[0].y)&&c.splice(c.length-1,1);b&&c.push(c[0]);return c};
 THREE.Path.prototype.toShapes=function(a,b){function c(a){for(var b=[],c=0,d=a.length;c<d;c++){var e=a[c],f=new THREE.Shape;f.actions=e.actions;f.curves=e.curves;b.push(f)}return b}function d(a,b){for(var c=b.length,d=!1,e=c-1,f=0;f<c;e=f++){var g=b[e],h=b[f],k=h.x-g.x,m=h.y-g.y;if(1E-10<Math.abs(m)){if(0>m&&(g=b[f],k=-k,h=b[e],m=-m),!(a.y<g.y||a.y>h.y))if(a.y===g.y){if(a.x===g.x)return!0}else{e=m*(a.x-g.x)-k*(a.y-g.y);if(0===e)return!0;0>e||(d=!d)}}else if(a.y===g.y&&(h.x<=a.x&&a.x<=g.x||g.x<=a.x&&
 THREE.Path.prototype.toShapes=function(a,b){function c(a){for(var b=[],c=0,d=a.length;c<d;c++){var e=a[c],f=new THREE.Shape;f.actions=e.actions;f.curves=e.curves;b.push(f)}return b}function d(a,b){for(var c=b.length,d=!1,e=c-1,f=0;f<c;e=f++){var g=b[e],h=b[f],k=h.x-g.x,m=h.y-g.y;if(1E-10<Math.abs(m)){if(0>m&&(g=b[f],k=-k,h=b[e],m=-m),!(a.y<g.y||a.y>h.y))if(a.y===g.y){if(a.x===g.x)return!0}else{e=m*(a.x-g.x)-k*(a.y-g.y);if(0===e)return!0;0>e||(d=!d)}}else if(a.y===g.y&&(h.x<=a.x&&a.x<=g.x||g.x<=a.x&&
 a.x<=h.x))return!0}return d}var e=function(a){var b,c,d,e,f=[],g=new THREE.Path;b=0;for(c=a.length;b<c;b++)d=a[b],e=d.args,d=d.action,d===THREE.PathActions.MOVE_TO&&0!==g.actions.length&&(f.push(g),g=new THREE.Path),g[d].apply(g,e);0!==g.actions.length&&f.push(g);return f}(this.actions);if(0===e.length)return[];if(!0===b)return c(e);var f,g,h,k=[];if(1===e.length)return g=e[0],h=new THREE.Shape,h.actions=g.actions,h.curves=g.curves,k.push(h),k;var l=!THREE.Shape.Utils.isClockWise(e[0].getPoints()),
 a.x<=h.x))return!0}return d}var e=function(a){var b,c,d,e,f=[],g=new THREE.Path;b=0;for(c=a.length;b<c;b++)d=a[b],e=d.args,d=d.action,d===THREE.PathActions.MOVE_TO&&0!==g.actions.length&&(f.push(g),g=new THREE.Path),g[d].apply(g,e);0!==g.actions.length&&f.push(g);return f}(this.actions);if(0===e.length)return[];if(!0===b)return c(e);var f,g,h,k=[];if(1===e.length)return g=e[0],h=new THREE.Shape,h.actions=g.actions,h.curves=g.curves,k.push(h),k;var l=!THREE.Shape.Utils.isClockWise(e[0].getPoints()),
-l=a?!l:l;h=[];var n=[],p=[],m=0,q;n[m]=void 0;p[m]=[];var t,s;t=0;for(s=e.length;t<s;t++)g=e[t],q=g.getPoints(),f=THREE.Shape.Utils.isClockWise(q),(f=a?!f:f)?(!l&&n[m]&&m++,n[m]={s:new THREE.Shape,p:q},n[m].s.actions=g.actions,n[m].s.curves=g.curves,l&&m++,p[m]=[]):p[m].push({h:g,p:q[0]});if(!n[0])return c(e);if(1<n.length){t=!1;s=[];g=0;for(e=n.length;g<e;g++)h[g]=[];g=0;for(e=n.length;g<e;g++)for(f=p[g],l=0;l<f.length;l++){m=f[l];q=!0;for(var u=0;u<n.length;u++)d(m.p,n[u].p)&&(g!==u&&s.push({froms:g,
-tos:u,hole:l}),q?(q=!1,h[u].push(m)):t=!0);q&&h[g].push(m)}0<s.length&&(t||(p=h))}t=0;for(s=n.length;t<s;t++)for(h=n[t].s,k.push(h),g=p[t],e=0,f=g.length;e<f;e++)h.holes.push(g[e].h);return k};THREE.Shape=function(){THREE.Path.apply(this,arguments);this.holes=[]};THREE.Shape.prototype=Object.create(THREE.Path.prototype);THREE.Shape.prototype.constructor=THREE.Shape;THREE.Shape.prototype.extrude=function(a){return new THREE.ExtrudeGeometry(this,a)};
+l=a?!l:l;h=[];var n=[],p=[],m=0,q;n[m]=void 0;p[m]=[];var s,t;s=0;for(t=e.length;s<t;s++)g=e[s],q=g.getPoints(),f=THREE.Shape.Utils.isClockWise(q),(f=a?!f:f)?(!l&&n[m]&&m++,n[m]={s:new THREE.Shape,p:q},n[m].s.actions=g.actions,n[m].s.curves=g.curves,l&&m++,p[m]=[]):p[m].push({h:g,p:q[0]});if(!n[0])return c(e);if(1<n.length){s=!1;t=[];g=0;for(e=n.length;g<e;g++)h[g]=[];g=0;for(e=n.length;g<e;g++)for(f=p[g],l=0;l<f.length;l++){m=f[l];q=!0;for(var u=0;u<n.length;u++)d(m.p,n[u].p)&&(g!==u&&t.push({froms:g,
+tos:u,hole:l}),q?(q=!1,h[u].push(m)):s=!0);q&&h[g].push(m)}0<t.length&&(s||(p=h))}s=0;for(t=n.length;s<t;s++)for(h=n[s].s,k.push(h),g=p[s],e=0,f=g.length;e<f;e++)h.holes.push(g[e].h);return k};THREE.Shape=function(){THREE.Path.apply(this,arguments);this.holes=[]};THREE.Shape.prototype=Object.create(THREE.Path.prototype);THREE.Shape.prototype.constructor=THREE.Shape;THREE.Shape.prototype.extrude=function(a){return new THREE.ExtrudeGeometry(this,a)};
 THREE.Shape.prototype.makeGeometry=function(a){return new THREE.ShapeGeometry(this,a)};THREE.Shape.prototype.getPointsHoles=function(a){var b,c=this.holes.length,d=[];for(b=0;b<c;b++)d[b]=this.holes[b].getTransformedPoints(a,this.bends);return d};THREE.Shape.prototype.getSpacedPointsHoles=function(a){var b,c=this.holes.length,d=[];for(b=0;b<c;b++)d[b]=this.holes[b].getTransformedSpacedPoints(a,this.bends);return d};
 THREE.Shape.prototype.makeGeometry=function(a){return new THREE.ShapeGeometry(this,a)};THREE.Shape.prototype.getPointsHoles=function(a){var b,c=this.holes.length,d=[];for(b=0;b<c;b++)d[b]=this.holes[b].getTransformedPoints(a,this.bends);return d};THREE.Shape.prototype.getSpacedPointsHoles=function(a){var b,c=this.holes.length,d=[];for(b=0;b<c;b++)d[b]=this.holes[b].getTransformedSpacedPoints(a,this.bends);return d};
 THREE.Shape.prototype.extractAllPoints=function(a){return{shape:this.getTransformedPoints(a),holes:this.getPointsHoles(a)}};THREE.Shape.prototype.extractPoints=function(a){return this.useSpacedPoints?this.extractAllSpacedPoints(a):this.extractAllPoints(a)};THREE.Shape.prototype.extractAllSpacedPoints=function(a){return{shape:this.getTransformedSpacedPoints(a),holes:this.getSpacedPointsHoles(a)}};
 THREE.Shape.prototype.extractAllPoints=function(a){return{shape:this.getTransformedPoints(a),holes:this.getPointsHoles(a)}};THREE.Shape.prototype.extractPoints=function(a){return this.useSpacedPoints?this.extractAllSpacedPoints(a):this.extractAllPoints(a)};THREE.Shape.prototype.extractAllSpacedPoints=function(a){return{shape:this.getTransformedSpacedPoints(a),holes:this.getSpacedPointsHoles(a)}};
-THREE.Shape.Utils={triangulateShape:function(a,b){function c(a,b,c){return a.x!==b.x?a.x<b.x?a.x<=c.x&&c.x<=b.x:b.x<=c.x&&c.x<=a.x:a.y<b.y?a.y<=c.y&&c.y<=b.y:b.y<=c.y&&c.y<=a.y}function d(a,b,d,e,f){var g=b.x-a.x,h=b.y-a.y,k=e.x-d.x,l=e.y-d.y,n=a.x-d.x,p=a.y-d.y,v=h*k-g*l,E=h*n-g*p;if(1E-10<Math.abs(v)){if(0<v){if(0>E||E>v)return[];k=l*n-k*p;if(0>k||k>v)return[]}else{if(0<E||E<v)return[];k=l*n-k*p;if(0<k||k<v)return[]}if(0===k)return!f||0!==E&&E!==v?[a]:[];if(k===v)return!f||0!==E&&E!==v?[b]:[];if(0===
-E)return[d];if(E===v)return[e];f=k/v;return[{x:a.x+f*g,y:a.y+f*h}]}if(0!==E||l*n!==k*p)return[];h=0===g&&0===h;k=0===k&&0===l;if(h&&k)return a.x!==d.x||a.y!==d.y?[]:[a];if(h)return c(d,e,a)?[a]:[];if(k)return c(a,b,d)?[d]:[];0!==g?(a.x<b.x?(g=a,k=a.x,h=b,a=b.x):(g=b,k=b.x,h=a,a=a.x),d.x<e.x?(b=d,v=d.x,l=e,d=e.x):(b=e,v=e.x,l=d,d=d.x)):(a.y<b.y?(g=a,k=a.y,h=b,a=b.y):(g=b,k=b.y,h=a,a=a.y),d.y<e.y?(b=d,v=d.y,l=e,d=e.y):(b=e,v=e.y,l=d,d=d.y));return k<=v?a<v?[]:a===v?f?[]:[b]:a<=d?[b,h]:[b,l]:k>d?[]:
+THREE.Shape.Utils={triangulateShape:function(a,b){function c(a,b,c){return a.x!==b.x?a.x<b.x?a.x<=c.x&&c.x<=b.x:b.x<=c.x&&c.x<=a.x:a.y<b.y?a.y<=c.y&&c.y<=b.y:b.y<=c.y&&c.y<=a.y}function d(a,b,d,e,f){var g=b.x-a.x,h=b.y-a.y,k=e.x-d.x,l=e.y-d.y,n=a.x-d.x,p=a.y-d.y,v=h*k-g*l,D=h*n-g*p;if(1E-10<Math.abs(v)){if(0<v){if(0>D||D>v)return[];k=l*n-k*p;if(0>k||k>v)return[]}else{if(0<D||D<v)return[];k=l*n-k*p;if(0<k||k<v)return[]}if(0===k)return!f||0!==D&&D!==v?[a]:[];if(k===v)return!f||0!==D&&D!==v?[b]:[];if(0===
+D)return[d];if(D===v)return[e];f=k/v;return[{x:a.x+f*g,y:a.y+f*h}]}if(0!==D||l*n!==k*p)return[];h=0===g&&0===h;k=0===k&&0===l;if(h&&k)return a.x!==d.x||a.y!==d.y?[]:[a];if(h)return c(d,e,a)?[a]:[];if(k)return c(a,b,d)?[d]:[];0!==g?(a.x<b.x?(g=a,k=a.x,h=b,a=b.x):(g=b,k=b.x,h=a,a=a.x),d.x<e.x?(b=d,v=d.x,l=e,d=e.x):(b=e,v=e.x,l=d,d=d.x)):(a.y<b.y?(g=a,k=a.y,h=b,a=b.y):(g=b,k=b.y,h=a,a=a.y),d.y<e.y?(b=d,v=d.y,l=e,d=e.y):(b=e,v=e.y,l=d,d=d.y));return k<=v?a<v?[]:a===v?f?[]:[b]:a<=d?[b,h]:[b,l]:k>d?[]:
 k===d?f?[]:[g]:a<=d?[g,h]:[g,l]}function e(a,b,c,d){var e=b.x-a.x,f=b.y-a.y;b=c.x-a.x;c=c.y-a.y;var g=d.x-a.x;d=d.y-a.y;a=e*c-f*b;e=e*d-f*g;return 1E-10<Math.abs(a)?(b=g*c-d*b,0<a?0<=e&&0<=b:0<=e||0<=b):0<e}var f,g,h,k,l,n={};h=a.concat();f=0;for(g=b.length;f<g;f++)Array.prototype.push.apply(h,b[f]);f=0;for(g=h.length;f<g;f++)l=h[f].x+":"+h[f].y,void 0!==n[l]&&console.warn("THREE.Shape: Duplicate point",l),n[l]=f;f=function(a,b){function c(a,b){var d=h.length-1,f=a-1;0>f&&(f=d);var g=a+1;g>d&&(g=
 k===d?f?[]:[g]:a<=d?[g,h]:[g,l]}function e(a,b,c,d){var e=b.x-a.x,f=b.y-a.y;b=c.x-a.x;c=c.y-a.y;var g=d.x-a.x;d=d.y-a.y;a=e*c-f*b;e=e*d-f*g;return 1E-10<Math.abs(a)?(b=g*c-d*b,0<a?0<=e&&0<=b:0<=e||0<=b):0<e}var f,g,h,k,l,n={};h=a.concat();f=0;for(g=b.length;f<g;f++)Array.prototype.push.apply(h,b[f]);f=0;for(g=h.length;f<g;f++)l=h[f].x+":"+h[f].y,void 0!==n[l]&&console.warn("THREE.Shape: Duplicate point",l),n[l]=f;f=function(a,b){function c(a,b){var d=h.length-1,f=a-1;0>f&&(f=d);var g=a+1;g>d&&(g=
-0);d=e(h[a],h[f],h[g],k[b]);if(!d)return!1;d=k.length-1;f=b-1;0>f&&(f=d);g=b+1;g>d&&(g=0);return(d=e(k[b],k[f],k[g],h[a]))?!0:!1}function f(a,b){var c,e;for(c=0;c<h.length;c++)if(e=c+1,e%=h.length,e=d(a,b,h[c],h[e],!0),0<e.length)return!0;return!1}function g(a,c){var e,f,h,k;for(e=0;e<l.length;e++)for(f=b[l[e]],h=0;h<f.length;h++)if(k=h+1,k%=f.length,k=d(a,c,f[h],f[k],!0),0<k.length)return!0;return!1}var h=a.concat(),k,l=[],n,p,I,v,E,L=[],C,F,R,J=0;for(n=b.length;J<n;J++)l.push(J);C=0;for(var z=2*
-l.length;0<l.length;){z--;if(0>z){console.log("Infinite Loop! Holes left:"+l.length+", Probably Hole outside Shape!");break}for(p=C;p<h.length;p++){I=h[p];n=-1;for(J=0;J<l.length;J++)if(v=l[J],E=I.x+":"+I.y+":"+v,void 0===L[E]){k=b[v];for(F=0;F<k.length;F++)if(v=k[F],c(p,F)&&!f(I,v)&&!g(I,v)){n=F;l.splice(J,1);C=h.slice(0,p+1);v=h.slice(p);F=k.slice(n);R=k.slice(0,n+1);h=C.concat(F).concat(R).concat(v);C=p;break}if(0<=n)break;L[E]=!0}if(0<=n)break}}return h}(a,b);var p=THREE.FontUtils.Triangulate(f,
+0);d=e(h[a],h[f],h[g],k[b]);if(!d)return!1;d=k.length-1;f=b-1;0>f&&(f=d);g=b+1;g>d&&(g=0);return(d=e(k[b],k[f],k[g],h[a]))?!0:!1}function f(a,b){var c,e;for(c=0;c<h.length;c++)if(e=c+1,e%=h.length,e=d(a,b,h[c],h[e],!0),0<e.length)return!0;return!1}function g(a,c){var e,f,h,k;for(e=0;e<l.length;e++)for(f=b[l[e]],h=0;h<f.length;h++)if(k=h+1,k%=f.length,k=d(a,c,f[h],f[k],!0),0<k.length)return!0;return!1}var h=a.concat(),k,l=[],n,p,I,v,D,L=[],C,E,R,J=0;for(n=b.length;J<n;J++)l.push(J);C=0;for(var z=2*
+l.length;0<l.length;){z--;if(0>z){console.log("Infinite Loop! Holes left:"+l.length+", Probably Hole outside Shape!");break}for(p=C;p<h.length;p++){I=h[p];n=-1;for(J=0;J<l.length;J++)if(v=l[J],D=I.x+":"+I.y+":"+v,void 0===L[D]){k=b[v];for(E=0;E<k.length;E++)if(v=k[E],c(p,E)&&!f(I,v)&&!g(I,v)){n=E;l.splice(J,1);C=h.slice(0,p+1);v=h.slice(p);E=k.slice(n);R=k.slice(0,n+1);h=C.concat(E).concat(R).concat(v);C=p;break}if(0<=n)break;L[D]=!0}if(0<=n)break}}return h}(a,b);var p=THREE.FontUtils.Triangulate(f,
 !1);f=0;for(g=p.length;f<g;f++)for(k=p[f],h=0;3>h;h++)l=k[h].x+":"+k[h].y,l=n[l],void 0!==l&&(k[h]=l);return p.concat()},isClockWise:function(a){return 0>THREE.FontUtils.Triangulate.area(a)},b2p0:function(a,b){var c=1-a;return c*c*b},b2p1:function(a,b){return 2*(1-a)*a*b},b2p2:function(a,b){return a*a*b},b2:function(a,b,c,d){return this.b2p0(a,b)+this.b2p1(a,c)+this.b2p2(a,d)},b3p0:function(a,b){var c=1-a;return c*c*c*b},b3p1:function(a,b){var c=1-a;return 3*c*c*a*b},b3p2:function(a,b){return 3*(1-
 !1);f=0;for(g=p.length;f<g;f++)for(k=p[f],h=0;3>h;h++)l=k[h].x+":"+k[h].y,l=n[l],void 0!==l&&(k[h]=l);return p.concat()},isClockWise:function(a){return 0>THREE.FontUtils.Triangulate.area(a)},b2p0:function(a,b){var c=1-a;return c*c*b},b2p1:function(a,b){return 2*(1-a)*a*b},b2p2:function(a,b){return a*a*b},b2:function(a,b,c,d){return this.b2p0(a,b)+this.b2p1(a,c)+this.b2p2(a,d)},b3p0:function(a,b){var c=1-a;return c*c*c*b},b3p1:function(a,b){var c=1-a;return 3*c*c*a*b},b3p2:function(a,b){return 3*(1-
 a)*a*a*b},b3p3:function(a,b){return a*a*a*b},b3:function(a,b,c,d,e){return this.b3p0(a,b)+this.b3p1(a,c)+this.b3p2(a,d)+this.b3p3(a,e)}};THREE.LineCurve=function(a,b){this.v1=a;this.v2=b};THREE.LineCurve.prototype=Object.create(THREE.Curve.prototype);THREE.LineCurve.prototype.constructor=THREE.LineCurve;THREE.LineCurve.prototype.getPoint=function(a){var b=this.v2.clone().sub(this.v1);b.multiplyScalar(a).add(this.v1);return b};THREE.LineCurve.prototype.getPointAt=function(a){return this.getPoint(a)};
 a)*a*a*b},b3p3:function(a,b){return a*a*a*b},b3:function(a,b,c,d,e){return this.b3p0(a,b)+this.b3p1(a,c)+this.b3p2(a,d)+this.b3p3(a,e)}};THREE.LineCurve=function(a,b){this.v1=a;this.v2=b};THREE.LineCurve.prototype=Object.create(THREE.Curve.prototype);THREE.LineCurve.prototype.constructor=THREE.LineCurve;THREE.LineCurve.prototype.getPoint=function(a){var b=this.v2.clone().sub(this.v1);b.multiplyScalar(a).add(this.v1);return b};THREE.LineCurve.prototype.getPointAt=function(a){return this.getPoint(a)};
 THREE.LineCurve.prototype.getTangent=function(a){return this.v2.clone().sub(this.v1).normalize()};THREE.QuadraticBezierCurve=function(a,b,c){this.v0=a;this.v1=b;this.v2=c};THREE.QuadraticBezierCurve.prototype=Object.create(THREE.Curve.prototype);THREE.QuadraticBezierCurve.prototype.constructor=THREE.QuadraticBezierCurve;
 THREE.LineCurve.prototype.getTangent=function(a){return this.v2.clone().sub(this.v1).normalize()};THREE.QuadraticBezierCurve=function(a,b,c){this.v0=a;this.v1=b;this.v2=c};THREE.QuadraticBezierCurve.prototype=Object.create(THREE.Curve.prototype);THREE.QuadraticBezierCurve.prototype.constructor=THREE.QuadraticBezierCurve;
@@ -709,12 +709,12 @@ THREE.AnimationHandler={LINEAR:0,CATMULLROM:1,CATMULLROM_FORWARD:2,add:function(
 for(b=0;b<this.animations.length;b++)this.animations[b].update(a)}};THREE.Animation=function(a,b){this.root=a;this.data=THREE.AnimationHandler.init(b);this.hierarchy=THREE.AnimationHandler.parse(a);this.currentTime=0;this.timeScale=1;this.isPlaying=!1;this.loop=!0;this.weight=0;this.interpolationType=THREE.AnimationHandler.LINEAR};
 for(b=0;b<this.animations.length;b++)this.animations[b].update(a)}};THREE.Animation=function(a,b){this.root=a;this.data=THREE.AnimationHandler.init(b);this.hierarchy=THREE.AnimationHandler.parse(a);this.currentTime=0;this.timeScale=1;this.isPlaying=!1;this.loop=!0;this.weight=0;this.interpolationType=THREE.AnimationHandler.LINEAR};
 THREE.Animation.prototype={constructor:THREE.Animation,keyTypes:["pos","rot","scl"],play:function(a,b){this.currentTime=void 0!==a?a:0;this.weight=void 0!==b?b:1;this.isPlaying=!0;this.reset();THREE.AnimationHandler.play(this)},stop:function(){this.isPlaying=!1;THREE.AnimationHandler.stop(this)},reset:function(){for(var a=0,b=this.hierarchy.length;a<b;a++){var c=this.hierarchy[a];void 0===c.animationCache&&(c.animationCache={animations:{},blending:{positionWeight:0,quaternionWeight:0,scaleWeight:0}});
 THREE.Animation.prototype={constructor:THREE.Animation,keyTypes:["pos","rot","scl"],play:function(a,b){this.currentTime=void 0!==a?a:0;this.weight=void 0!==b?b:1;this.isPlaying=!0;this.reset();THREE.AnimationHandler.play(this)},stop:function(){this.isPlaying=!1;THREE.AnimationHandler.stop(this)},reset:function(){for(var a=0,b=this.hierarchy.length;a<b;a++){var c=this.hierarchy[a];void 0===c.animationCache&&(c.animationCache={animations:{},blending:{positionWeight:0,quaternionWeight:0,scaleWeight:0}});
 var d=this.data.name,e=c.animationCache.animations,f=e[d];void 0===f&&(f={prevKey:{pos:0,rot:0,scl:0},nextKey:{pos:0,rot:0,scl:0},originalMatrix:c.matrix},e[d]=f);for(c=0;3>c;c++){for(var d=this.keyTypes[c],e=this.data.hierarchy[a].keys[0],g=this.getNextKeyWith(d,a,1);g.time<this.currentTime&&g.index>e.index;)e=g,g=this.getNextKeyWith(d,a,g.index+1);f.prevKey[d]=e;f.nextKey[d]=g}}},resetBlendWeights:function(){for(var a=0,b=this.hierarchy.length;a<b;a++){var c=this.hierarchy[a].animationCache;void 0!==
 var d=this.data.name,e=c.animationCache.animations,f=e[d];void 0===f&&(f={prevKey:{pos:0,rot:0,scl:0},nextKey:{pos:0,rot:0,scl:0},originalMatrix:c.matrix},e[d]=f);for(c=0;3>c;c++){for(var d=this.keyTypes[c],e=this.data.hierarchy[a].keys[0],g=this.getNextKeyWith(d,a,1);g.time<this.currentTime&&g.index>e.index;)e=g,g=this.getNextKeyWith(d,a,g.index+1);f.prevKey[d]=e;f.nextKey[d]=g}}},resetBlendWeights:function(){for(var a=0,b=this.hierarchy.length;a<b;a++){var c=this.hierarchy[a].animationCache;void 0!==
-c&&(c=c.blending,c.positionWeight=0,c.quaternionWeight=0,c.scaleWeight=0)}},update:function(){var a=[],b=new THREE.Vector3,c=new THREE.Vector3,d=new THREE.Quaternion,e=function(a,b){var c=[],d=[],e,p,m,q,t,s;e=(a.length-1)*b;p=Math.floor(e);e-=p;c[0]=0===p?p:p-1;c[1]=p;c[2]=p>a.length-2?p:p+1;c[3]=p>a.length-3?p:p+2;p=a[c[0]];q=a[c[1]];t=a[c[2]];s=a[c[3]];c=e*e;m=e*c;d[0]=f(p[0],q[0],t[0],s[0],e,c,m);d[1]=f(p[1],q[1],t[1],s[1],e,c,m);d[2]=f(p[2],q[2],t[2],s[2],e,c,m);return d},f=function(a,b,c,d,
+c&&(c=c.blending,c.positionWeight=0,c.quaternionWeight=0,c.scaleWeight=0)}},update:function(){var a=[],b=new THREE.Vector3,c=new THREE.Vector3,d=new THREE.Quaternion,e=function(a,b){var c=[],d=[],e,p,m,q,s,t;e=(a.length-1)*b;p=Math.floor(e);e-=p;c[0]=0===p?p:p-1;c[1]=p;c[2]=p>a.length-2?p:p+1;c[3]=p>a.length-3?p:p+2;p=a[c[0]];q=a[c[1]];s=a[c[2]];t=a[c[3]];c=e*e;m=e*c;d[0]=f(p[0],q[0],s[0],t[0],e,c,m);d[1]=f(p[1],q[1],s[1],t[1],e,c,m);d[2]=f(p[2],q[2],s[2],t[2],e,c,m);return d},f=function(a,b,c,d,
 e,f,m){a=.5*(c-a);d=.5*(d-b);return(2*(b-c)+a+d)*m+(-3*(b-c)-2*a-d)*f+a*e+b};return function(f){if(!1!==this.isPlaying&&(this.currentTime+=f*this.timeScale,0!==this.weight)){f=this.data.length;if(this.currentTime>f||0>this.currentTime)this.loop?(this.currentTime%=f,0>this.currentTime&&(this.currentTime+=f),this.reset()):this.stop();f=0;for(var h=this.hierarchy.length;f<h;f++)for(var k=this.hierarchy[f],l=k.animationCache.animations[this.data.name],n=k.animationCache.blending,p=0;3>p;p++){var m=this.keyTypes[p],
 e,f,m){a=.5*(c-a);d=.5*(d-b);return(2*(b-c)+a+d)*m+(-3*(b-c)-2*a-d)*f+a*e+b};return function(f){if(!1!==this.isPlaying&&(this.currentTime+=f*this.timeScale,0!==this.weight)){f=this.data.length;if(this.currentTime>f||0>this.currentTime)this.loop?(this.currentTime%=f,0>this.currentTime&&(this.currentTime+=f),this.reset()):this.stop();f=0;for(var h=this.hierarchy.length;f<h;f++)for(var k=this.hierarchy[f],l=k.animationCache.animations[this.data.name],n=k.animationCache.blending,p=0;3>p;p++){var m=this.keyTypes[p],
-q=l.prevKey[m],t=l.nextKey[m];if(0<this.timeScale&&t.time<=this.currentTime||0>this.timeScale&&q.time>=this.currentTime){q=this.data.hierarchy[f].keys[0];for(t=this.getNextKeyWith(m,f,1);t.time<this.currentTime&&t.index>q.index;)q=t,t=this.getNextKeyWith(m,f,t.index+1);l.prevKey[m]=q;l.nextKey[m]=t}var s=(this.currentTime-q.time)/(t.time-q.time),u=q[m],w=t[m];0>s&&(s=0);1<s&&(s=1);if("pos"===m)if(this.interpolationType===THREE.AnimationHandler.LINEAR)c.x=u[0]+(w[0]-u[0])*s,c.y=u[1]+(w[1]-u[1])*s,
-c.z=u[2]+(w[2]-u[2])*s,q=this.weight/(this.weight+n.positionWeight),k.position.lerp(c,q),n.positionWeight+=this.weight;else{if(this.interpolationType===THREE.AnimationHandler.CATMULLROM||this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD)a[0]=this.getPrevKeyWith("pos",f,q.index-1).pos,a[1]=u,a[2]=w,a[3]=this.getNextKeyWith("pos",f,t.index+1).pos,s=.33*s+.33,t=e(a,s),q=this.weight/(this.weight+n.positionWeight),n.positionWeight+=this.weight,m=k.position,m.x+=(t[0]-m.x)*q,m.y+=(t[1]-
-m.y)*q,m.z+=(t[2]-m.z)*q,this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD&&(s=e(a,1.01*s),b.set(s[0],s[1],s[2]),b.sub(m),b.y=0,b.normalize(),s=Math.atan2(b.x,b.z),k.rotation.set(0,s,0))}else"rot"===m?(THREE.Quaternion.slerp(u,w,d,s),0===n.quaternionWeight?(k.quaternion.copy(d),n.quaternionWeight=this.weight):(q=this.weight/(this.weight+n.quaternionWeight),THREE.Quaternion.slerp(k.quaternion,d,k.quaternion,q),n.quaternionWeight+=this.weight)):"scl"===m&&(c.x=u[0]+(w[0]-u[0])*s,c.y=
-u[1]+(w[1]-u[1])*s,c.z=u[2]+(w[2]-u[2])*s,q=this.weight/(this.weight+n.scaleWeight),k.scale.lerp(c,q),n.scaleWeight+=this.weight)}return!0}}}(),getNextKeyWith:function(a,b,c){var d=this.data.hierarchy[b].keys;for(c=this.interpolationType===THREE.AnimationHandler.CATMULLROM||this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD?c<d.length-1?c:d.length-1:c%d.length;c<d.length;c++)if(void 0!==d[c][a])return d[c];return this.data.hierarchy[b].keys[0]},getPrevKeyWith:function(a,b,c){var d=
+q=l.prevKey[m],s=l.nextKey[m];if(0<this.timeScale&&s.time<=this.currentTime||0>this.timeScale&&q.time>=this.currentTime){q=this.data.hierarchy[f].keys[0];for(s=this.getNextKeyWith(m,f,1);s.time<this.currentTime&&s.index>q.index;)q=s,s=this.getNextKeyWith(m,f,s.index+1);l.prevKey[m]=q;l.nextKey[m]=s}var t=(this.currentTime-q.time)/(s.time-q.time),u=q[m],x=s[m];0>t&&(t=0);1<t&&(t=1);if("pos"===m)if(this.interpolationType===THREE.AnimationHandler.LINEAR)c.x=u[0]+(x[0]-u[0])*t,c.y=u[1]+(x[1]-u[1])*t,
+c.z=u[2]+(x[2]-u[2])*t,q=this.weight/(this.weight+n.positionWeight),k.position.lerp(c,q),n.positionWeight+=this.weight;else{if(this.interpolationType===THREE.AnimationHandler.CATMULLROM||this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD)a[0]=this.getPrevKeyWith("pos",f,q.index-1).pos,a[1]=u,a[2]=x,a[3]=this.getNextKeyWith("pos",f,s.index+1).pos,t=.33*t+.33,s=e(a,t),q=this.weight/(this.weight+n.positionWeight),n.positionWeight+=this.weight,m=k.position,m.x+=(s[0]-m.x)*q,m.y+=(s[1]-
+m.y)*q,m.z+=(s[2]-m.z)*q,this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD&&(t=e(a,1.01*t),b.set(t[0],t[1],t[2]),b.sub(m),b.y=0,b.normalize(),t=Math.atan2(b.x,b.z),k.rotation.set(0,t,0))}else"rot"===m?(THREE.Quaternion.slerp(u,x,d,t),0===n.quaternionWeight?(k.quaternion.copy(d),n.quaternionWeight=this.weight):(q=this.weight/(this.weight+n.quaternionWeight),THREE.Quaternion.slerp(k.quaternion,d,k.quaternion,q),n.quaternionWeight+=this.weight)):"scl"===m&&(c.x=u[0]+(x[0]-u[0])*t,c.y=
+u[1]+(x[1]-u[1])*t,c.z=u[2]+(x[2]-u[2])*t,q=this.weight/(this.weight+n.scaleWeight),k.scale.lerp(c,q),n.scaleWeight+=this.weight)}return!0}}}(),getNextKeyWith:function(a,b,c){var d=this.data.hierarchy[b].keys;for(c=this.interpolationType===THREE.AnimationHandler.CATMULLROM||this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD?c<d.length-1?c:d.length-1:c%d.length;c<d.length;c++)if(void 0!==d[c][a])return d[c];return this.data.hierarchy[b].keys[0]},getPrevKeyWith:function(a,b,c){var d=
 this.data.hierarchy[b].keys;for(c=this.interpolationType===THREE.AnimationHandler.CATMULLROM||this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD?0<c?c:0:0<=c?c:c+d.length;0<=c;c--)if(void 0!==d[c][a])return d[c];return this.data.hierarchy[b].keys[d.length-1]}};
 this.data.hierarchy[b].keys;for(c=this.interpolationType===THREE.AnimationHandler.CATMULLROM||this.interpolationType===THREE.AnimationHandler.CATMULLROM_FORWARD?0<c?c:0:0<=c?c:c+d.length;0<=c;c--)if(void 0!==d[c][a])return d[c];return this.data.hierarchy[b].keys[d.length-1]}};
 THREE.KeyFrameAnimation=function(a){this.root=a.node;this.data=THREE.AnimationHandler.init(a);this.hierarchy=THREE.AnimationHandler.parse(this.root);this.currentTime=0;this.timeScale=.001;this.isPlaying=!1;this.loop=this.isPaused=!0;a=0;for(var b=this.hierarchy.length;a<b;a++){var c=this.data.hierarchy[a].sids,d=this.hierarchy[a];if(this.data.hierarchy[a].keys.length&&c){for(var e=0;e<c.length;e++){var f=c[e],g=this.getNextKeyWith(f,a,0);g&&g.apply(f)}d.matrixAutoUpdate=!1;this.data.hierarchy[a].node.updateMatrix();
 THREE.KeyFrameAnimation=function(a){this.root=a.node;this.data=THREE.AnimationHandler.init(a);this.hierarchy=THREE.AnimationHandler.parse(this.root);this.currentTime=0;this.timeScale=.001;this.isPlaying=!1;this.loop=this.isPaused=!0;a=0;for(var b=this.hierarchy.length;a<b;a++){var c=this.data.hierarchy[a].sids,d=this.hierarchy[a];if(this.data.hierarchy[a].keys.length&&c){for(var e=0;e<c.length;e++){var f=c[e],g=this.getNextKeyWith(f,a,0);g&&g.apply(f)}d.matrixAutoUpdate=!1;this.data.hierarchy[a].node.updateMatrix();
 d.matrixWorldNeedsUpdate=!0}}};
 d.matrixWorldNeedsUpdate=!0}}};
@@ -725,74 +725,74 @@ f.interpolate(g,g.time);this.data.hierarchy[a].node.updateMatrix();c.matrixWorld
 THREE.MorphAnimation=function(a){this.mesh=a;this.frames=a.morphTargetInfluences.length;this.currentTime=0;this.duration=1E3;this.loop=!0;this.currentFrame=this.lastFrame=0;this.isPlaying=!1};
 THREE.MorphAnimation=function(a){this.mesh=a;this.frames=a.morphTargetInfluences.length;this.currentTime=0;this.duration=1E3;this.loop=!0;this.currentFrame=this.lastFrame=0;this.isPlaying=!1};
 THREE.MorphAnimation.prototype={constructor:THREE.MorphAnimation,play:function(){this.isPlaying=!0},pause:function(){this.isPlaying=!1},update:function(a){if(!1!==this.isPlaying){this.currentTime+=a;!0===this.loop&&this.currentTime>this.duration&&(this.currentTime%=this.duration);this.currentTime=Math.min(this.currentTime,this.duration);a=this.duration/this.frames;var b=Math.floor(this.currentTime/a),c=this.mesh.morphTargetInfluences;b!==this.currentFrame&&(c[this.lastFrame]=0,c[this.currentFrame]=
 THREE.MorphAnimation.prototype={constructor:THREE.MorphAnimation,play:function(){this.isPlaying=!0},pause:function(){this.isPlaying=!1},update:function(a){if(!1!==this.isPlaying){this.currentTime+=a;!0===this.loop&&this.currentTime>this.duration&&(this.currentTime%=this.duration);this.currentTime=Math.min(this.currentTime,this.duration);a=this.duration/this.frames;var b=Math.floor(this.currentTime/a),c=this.mesh.morphTargetInfluences;b!==this.currentFrame&&(c[this.lastFrame]=0,c[this.currentFrame]=
 1,c[b]=0,this.lastFrame=this.currentFrame,this.currentFrame=b);c[b]=this.currentTime%a/a;c[this.lastFrame]=1-c[b]}}};
 1,c[b]=0,this.lastFrame=this.currentFrame,this.currentFrame=b);c[b]=this.currentTime%a/a;c[this.lastFrame]=1-c[b]}}};
-THREE.BoxGeometry=function(a,b,c,d,e,f){function g(a,b,c,d,e,f,g){var s,u=h.widthSegments,w=h.heightSegments,x=e/2,A=f/2,y=h.vertices.length;if("x"===a&&"y"===b||"y"===a&&"x"===b)s="z";else if("x"===a&&"z"===b||"z"===a&&"x"===b)s="y",w=h.depthSegments;else if("z"===a&&"y"===b||"y"===a&&"z"===b)s="x",u=h.depthSegments;var D=u+1,I=w+1,v=e/u,E=f/w,L=new THREE.Vector3;L[s]=0<g?1:-1;for(e=0;e<I;e++)for(f=0;f<D;f++){var C=new THREE.Vector3;C[a]=(f*v-x)*c;C[b]=(e*E-A)*d;C[s]=g;h.vertices.push(C)}for(e=0;e<
-w;e++)for(f=0;f<u;f++)A=f+D*e,a=f+D*(e+1),b=f+1+D*(e+1),c=f+1+D*e,d=new THREE.Vector2(f/u,1-e/w),g=new THREE.Vector2(f/u,1-(e+1)/w),s=new THREE.Vector2((f+1)/u,1-(e+1)/w),x=new THREE.Vector2((f+1)/u,1-e/w),A=new THREE.Face3(A+y,a+y,c+y),A.normal.copy(L),A.vertexNormals.push(L.clone(),L.clone(),L.clone()),h.faces.push(A),h.faceVertexUvs[0].push([d,g,x]),A=new THREE.Face3(a+y,b+y,c+y),A.normal.copy(L),A.vertexNormals.push(L.clone(),L.clone(),L.clone()),h.faces.push(A),h.faceVertexUvs[0].push([g.clone(),
-s,x.clone()])}THREE.Geometry.call(this);this.type="BoxGeometry";this.parameters={width:a,height:b,depth:c,widthSegments:d,heightSegments:e,depthSegments:f};this.widthSegments=d||1;this.heightSegments=e||1;this.depthSegments=f||1;var h=this;d=a/2;e=b/2;f=c/2;g("z","y",-1,-1,c,b,d);g("z","y",1,-1,c,b,-d);g("x","z",1,1,a,c,e);g("x","z",1,-1,a,c,-e);g("x","y",1,-1,a,b,f);g("x","y",-1,-1,a,b,-f);this.mergeVertices()};THREE.BoxGeometry.prototype=Object.create(THREE.Geometry.prototype);
+THREE.BoxGeometry=function(a,b,c,d,e,f){function g(a,b,c,d,e,f,g){var t,u=h.widthSegments,x=h.heightSegments,w=e/2,A=f/2,y=h.vertices.length;if("x"===a&&"y"===b||"y"===a&&"x"===b)t="z";else if("x"===a&&"z"===b||"z"===a&&"x"===b)t="y",x=h.depthSegments;else if("z"===a&&"y"===b||"y"===a&&"z"===b)t="x",u=h.depthSegments;var G=u+1,I=x+1,v=e/u,D=f/x,L=new THREE.Vector3;L[t]=0<g?1:-1;for(e=0;e<I;e++)for(f=0;f<G;f++){var C=new THREE.Vector3;C[a]=(f*v-w)*c;C[b]=(e*D-A)*d;C[t]=g;h.vertices.push(C)}for(e=0;e<
+x;e++)for(f=0;f<u;f++)A=f+G*e,a=f+G*(e+1),b=f+1+G*(e+1),c=f+1+G*e,d=new THREE.Vector2(f/u,1-e/x),g=new THREE.Vector2(f/u,1-(e+1)/x),t=new THREE.Vector2((f+1)/u,1-(e+1)/x),w=new THREE.Vector2((f+1)/u,1-e/x),A=new THREE.Face3(A+y,a+y,c+y),A.normal.copy(L),A.vertexNormals.push(L.clone(),L.clone(),L.clone()),h.faces.push(A),h.faceVertexUvs[0].push([d,g,w]),A=new THREE.Face3(a+y,b+y,c+y),A.normal.copy(L),A.vertexNormals.push(L.clone(),L.clone(),L.clone()),h.faces.push(A),h.faceVertexUvs[0].push([g.clone(),
+t,w.clone()])}THREE.Geometry.call(this);this.type="BoxGeometry";this.parameters={width:a,height:b,depth:c,widthSegments:d,heightSegments:e,depthSegments:f};this.widthSegments=d||1;this.heightSegments=e||1;this.depthSegments=f||1;var h=this;d=a/2;e=b/2;f=c/2;g("z","y",-1,-1,c,b,d);g("z","y",1,-1,c,b,-d);g("x","z",1,1,a,c,e);g("x","z",1,-1,a,c,-e);g("x","y",1,-1,a,b,f);g("x","y",-1,-1,a,b,-f);this.mergeVertices()};THREE.BoxGeometry.prototype=Object.create(THREE.Geometry.prototype);
 THREE.BoxGeometry.prototype.constructor=THREE.BoxGeometry;THREE.CubeGeometry=THREE.BoxGeometry;
 THREE.BoxGeometry.prototype.constructor=THREE.BoxGeometry;THREE.CubeGeometry=THREE.BoxGeometry;
 THREE.CircleGeometry=function(a,b,c,d){THREE.Geometry.call(this);this.type="CircleGeometry";this.parameters={radius:a,segments:b,thetaStart:c,thetaLength:d};a=a||50;b=void 0!==b?Math.max(3,b):8;c=void 0!==c?c:0;d=void 0!==d?d:2*Math.PI;var e,f=[];e=new THREE.Vector3;var g=new THREE.Vector2(.5,.5);this.vertices.push(e);f.push(g);for(e=0;e<=b;e++){var h=new THREE.Vector3,k=c+e/b*d;h.x=a*Math.cos(k);h.y=a*Math.sin(k);this.vertices.push(h);f.push(new THREE.Vector2((h.x/a+1)/2,(h.y/a+1)/2))}c=new THREE.Vector3(0,
 THREE.CircleGeometry=function(a,b,c,d){THREE.Geometry.call(this);this.type="CircleGeometry";this.parameters={radius:a,segments:b,thetaStart:c,thetaLength:d};a=a||50;b=void 0!==b?Math.max(3,b):8;c=void 0!==c?c:0;d=void 0!==d?d:2*Math.PI;var e,f=[];e=new THREE.Vector3;var g=new THREE.Vector2(.5,.5);this.vertices.push(e);f.push(g);for(e=0;e<=b;e++){var h=new THREE.Vector3,k=c+e/b*d;h.x=a*Math.cos(k);h.y=a*Math.sin(k);this.vertices.push(h);f.push(new THREE.Vector2((h.x/a+1)/2,(h.y/a+1)/2))}c=new THREE.Vector3(0,
 0,1);for(e=1;e<=b;e++)this.faces.push(new THREE.Face3(e,e+1,0,[c.clone(),c.clone(),c.clone()])),this.faceVertexUvs[0].push([f[e].clone(),f[e+1].clone(),g.clone()]);this.computeFaceNormals();this.boundingSphere=new THREE.Sphere(new THREE.Vector3,a)};THREE.CircleGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.CircleGeometry.prototype.constructor=THREE.CircleGeometry;
 0,1);for(e=1;e<=b;e++)this.faces.push(new THREE.Face3(e,e+1,0,[c.clone(),c.clone(),c.clone()])),this.faceVertexUvs[0].push([f[e].clone(),f[e+1].clone(),g.clone()]);this.computeFaceNormals();this.boundingSphere=new THREE.Sphere(new THREE.Vector3,a)};THREE.CircleGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.CircleGeometry.prototype.constructor=THREE.CircleGeometry;
 THREE.CircleBufferGeometry=function(a,b,c,d){THREE.BufferGeometry.call(this);this.type="CircleBufferGeometry";this.parameters={radius:a,segments:b,thetaStart:c,thetaLength:d};a=a||50;b=void 0!==b?Math.max(3,b):8;c=void 0!==c?c:0;d=void 0!==d?d:2*Math.PI;var e=b+2,f=new Float32Array(3*e),g=new Float32Array(3*e),e=new Float32Array(2*e);g[3]=1;e[0]=.5;e[1]=.5;for(var h=0,k=3,l=2;h<=b;h++,k+=3,l+=2){var n=c+h/b*d;f[k]=a*Math.cos(n);f[k+1]=a*Math.sin(n);g[k+2]=1;e[l]=(f[k]/a+1)/2;e[l+1]=(f[k+1]/a+1)/2}c=
 THREE.CircleBufferGeometry=function(a,b,c,d){THREE.BufferGeometry.call(this);this.type="CircleBufferGeometry";this.parameters={radius:a,segments:b,thetaStart:c,thetaLength:d};a=a||50;b=void 0!==b?Math.max(3,b):8;c=void 0!==c?c:0;d=void 0!==d?d:2*Math.PI;var e=b+2,f=new Float32Array(3*e),g=new Float32Array(3*e),e=new Float32Array(2*e);g[3]=1;e[0]=.5;e[1]=.5;for(var h=0,k=3,l=2;h<=b;h++,k+=3,l+=2){var n=c+h/b*d;f[k]=a*Math.cos(n);f[k+1]=a*Math.sin(n);g[k+2]=1;e[l]=(f[k]/a+1)/2;e[l+1]=(f[k+1]/a+1)/2}c=
 [];for(k=1;k<=b;k++)c.push(k),c.push(k+1),c.push(0);this.addAttribute("index",new THREE.BufferAttribute(new Uint16Array(c),1));this.addAttribute("position",new THREE.BufferAttribute(f,3));this.addAttribute("normal",new THREE.BufferAttribute(g,3));this.addAttribute("uv",new THREE.BufferAttribute(e,2));this.boundingSphere=new THREE.Sphere(new THREE.Vector3,a)};THREE.CircleBufferGeometry.prototype=Object.create(THREE.BufferGeometry.prototype);THREE.CircleBufferGeometry.prototype.constructor=THREE.CircleBufferGeometry;
 [];for(k=1;k<=b;k++)c.push(k),c.push(k+1),c.push(0);this.addAttribute("index",new THREE.BufferAttribute(new Uint16Array(c),1));this.addAttribute("position",new THREE.BufferAttribute(f,3));this.addAttribute("normal",new THREE.BufferAttribute(g,3));this.addAttribute("uv",new THREE.BufferAttribute(e,2));this.boundingSphere=new THREE.Sphere(new THREE.Vector3,a)};THREE.CircleBufferGeometry.prototype=Object.create(THREE.BufferGeometry.prototype);THREE.CircleBufferGeometry.prototype.constructor=THREE.CircleBufferGeometry;
-THREE.CylinderGeometry=function(a,b,c,d,e,f,g,h){THREE.Geometry.call(this);this.type="CylinderGeometry";this.parameters={radiusTop:a,radiusBottom:b,height:c,radialSegments:d,heightSegments:e,openEnded:f,thetaStart:g,thetaLength:h};a=void 0!==a?a:20;b=void 0!==b?b:20;c=void 0!==c?c:100;d=d||8;e=e||1;f=void 0!==f?f:!1;g=void 0!==g?g:0;h=void 0!==h?h:2*Math.PI;var k=c/2,l,n,p=[],m=[];for(n=0;n<=e;n++){var q=[],t=[],s=n/e,u=s*(b-a)+a;for(l=0;l<=d;l++){var w=l/d,x=new THREE.Vector3;x.x=u*Math.sin(w*h+
-g);x.y=-s*c+k;x.z=u*Math.cos(w*h+g);this.vertices.push(x);q.push(this.vertices.length-1);t.push(new THREE.Vector2(w,1-s))}p.push(q);m.push(t)}c=(b-a)/c;for(l=0;l<d;l++)for(0!==a?(g=this.vertices[p[0][l]].clone(),h=this.vertices[p[0][l+1]].clone()):(g=this.vertices[p[1][l]].clone(),h=this.vertices[p[1][l+1]].clone()),g.setY(Math.sqrt(g.x*g.x+g.z*g.z)*c).normalize(),h.setY(Math.sqrt(h.x*h.x+h.z*h.z)*c).normalize(),n=0;n<e;n++){var q=p[n][l],t=p[n+1][l],s=p[n+1][l+1],u=p[n][l+1],w=g.clone(),x=g.clone(),
-A=h.clone(),y=h.clone(),D=m[n][l].clone(),I=m[n+1][l].clone(),v=m[n+1][l+1].clone(),E=m[n][l+1].clone();this.faces.push(new THREE.Face3(q,t,u,[w,x,y]));this.faceVertexUvs[0].push([D,I,E]);this.faces.push(new THREE.Face3(t,s,u,[x.clone(),A,y.clone()]));this.faceVertexUvs[0].push([I.clone(),v,E.clone()])}if(!1===f&&0<a)for(this.vertices.push(new THREE.Vector3(0,k,0)),l=0;l<d;l++)q=p[0][l],t=p[0][l+1],s=this.vertices.length-1,w=new THREE.Vector3(0,1,0),x=new THREE.Vector3(0,1,0),A=new THREE.Vector3(0,
-1,0),D=m[0][l].clone(),I=m[0][l+1].clone(),v=new THREE.Vector2(I.x,0),this.faces.push(new THREE.Face3(q,t,s,[w,x,A])),this.faceVertexUvs[0].push([D,I,v]);if(!1===f&&0<b)for(this.vertices.push(new THREE.Vector3(0,-k,0)),l=0;l<d;l++)q=p[e][l+1],t=p[e][l],s=this.vertices.length-1,w=new THREE.Vector3(0,-1,0),x=new THREE.Vector3(0,-1,0),A=new THREE.Vector3(0,-1,0),D=m[e][l+1].clone(),I=m[e][l].clone(),v=new THREE.Vector2(I.x,1),this.faces.push(new THREE.Face3(q,t,s,[w,x,A])),this.faceVertexUvs[0].push([D,
+THREE.CylinderGeometry=function(a,b,c,d,e,f,g,h){THREE.Geometry.call(this);this.type="CylinderGeometry";this.parameters={radiusTop:a,radiusBottom:b,height:c,radialSegments:d,heightSegments:e,openEnded:f,thetaStart:g,thetaLength:h};a=void 0!==a?a:20;b=void 0!==b?b:20;c=void 0!==c?c:100;d=d||8;e=e||1;f=void 0!==f?f:!1;g=void 0!==g?g:0;h=void 0!==h?h:2*Math.PI;var k=c/2,l,n,p=[],m=[];for(n=0;n<=e;n++){var q=[],s=[],t=n/e,u=t*(b-a)+a;for(l=0;l<=d;l++){var x=l/d,w=new THREE.Vector3;w.x=u*Math.sin(x*h+
+g);w.y=-t*c+k;w.z=u*Math.cos(x*h+g);this.vertices.push(w);q.push(this.vertices.length-1);s.push(new THREE.Vector2(x,1-t))}p.push(q);m.push(s)}c=(b-a)/c;for(l=0;l<d;l++)for(0!==a?(g=this.vertices[p[0][l]].clone(),h=this.vertices[p[0][l+1]].clone()):(g=this.vertices[p[1][l]].clone(),h=this.vertices[p[1][l+1]].clone()),g.setY(Math.sqrt(g.x*g.x+g.z*g.z)*c).normalize(),h.setY(Math.sqrt(h.x*h.x+h.z*h.z)*c).normalize(),n=0;n<e;n++){var q=p[n][l],s=p[n+1][l],t=p[n+1][l+1],u=p[n][l+1],x=g.clone(),w=g.clone(),
+A=h.clone(),y=h.clone(),G=m[n][l].clone(),I=m[n+1][l].clone(),v=m[n+1][l+1].clone(),D=m[n][l+1].clone();this.faces.push(new THREE.Face3(q,s,u,[x,w,y]));this.faceVertexUvs[0].push([G,I,D]);this.faces.push(new THREE.Face3(s,t,u,[w.clone(),A,y.clone()]));this.faceVertexUvs[0].push([I.clone(),v,D.clone()])}if(!1===f&&0<a)for(this.vertices.push(new THREE.Vector3(0,k,0)),l=0;l<d;l++)q=p[0][l],s=p[0][l+1],t=this.vertices.length-1,x=new THREE.Vector3(0,1,0),w=new THREE.Vector3(0,1,0),A=new THREE.Vector3(0,
+1,0),G=m[0][l].clone(),I=m[0][l+1].clone(),v=new THREE.Vector2(I.x,0),this.faces.push(new THREE.Face3(q,s,t,[x,w,A])),this.faceVertexUvs[0].push([G,I,v]);if(!1===f&&0<b)for(this.vertices.push(new THREE.Vector3(0,-k,0)),l=0;l<d;l++)q=p[e][l+1],s=p[e][l],t=this.vertices.length-1,x=new THREE.Vector3(0,-1,0),w=new THREE.Vector3(0,-1,0),A=new THREE.Vector3(0,-1,0),G=m[e][l+1].clone(),I=m[e][l].clone(),v=new THREE.Vector2(I.x,1),this.faces.push(new THREE.Face3(q,s,t,[x,w,A])),this.faceVertexUvs[0].push([G,
 I,v]);this.computeFaceNormals()};THREE.CylinderGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.CylinderGeometry.prototype.constructor=THREE.CylinderGeometry;
 I,v]);this.computeFaceNormals()};THREE.CylinderGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.CylinderGeometry.prototype.constructor=THREE.CylinderGeometry;
 THREE.EdgesGeometry=function(a,b){THREE.BufferGeometry.call(this);var c=Math.cos(THREE.Math.degToRad(void 0!==b?b:1)),d=[0,0],e={},f=function(a,b){return a-b},g=["a","b","c"],h;a instanceof THREE.BufferGeometry?(h=new THREE.Geometry,h.fromBufferGeometry(a)):h=a.clone();h.mergeVertices();h.computeFaceNormals();var k=h.vertices;h=h.faces;for(var l=0,n=h.length;l<n;l++)for(var p=h[l],m=0;3>m;m++){d[0]=p[g[m]];d[1]=p[g[(m+1)%3]];d.sort(f);var q=d.toString();void 0===e[q]?e[q]={vert1:d[0],vert2:d[1],face1:l,
 THREE.EdgesGeometry=function(a,b){THREE.BufferGeometry.call(this);var c=Math.cos(THREE.Math.degToRad(void 0!==b?b:1)),d=[0,0],e={},f=function(a,b){return a-b},g=["a","b","c"],h;a instanceof THREE.BufferGeometry?(h=new THREE.Geometry,h.fromBufferGeometry(a)):h=a.clone();h.mergeVertices();h.computeFaceNormals();var k=h.vertices;h=h.faces;for(var l=0,n=h.length;l<n;l++)for(var p=h[l],m=0;3>m;m++){d[0]=p[g[m]];d[1]=p[g[(m+1)%3]];d.sort(f);var q=d.toString();void 0===e[q]?e[q]={vert1:d[0],vert2:d[1],face1:l,
 face2:void 0}:e[q].face2=l}d=[];for(q in e)if(f=e[q],void 0===f.face2||h[f.face1].normal.dot(h[f.face2].normal)<=c)g=k[f.vert1],d.push(g.x),d.push(g.y),d.push(g.z),g=k[f.vert2],d.push(g.x),d.push(g.y),d.push(g.z);this.addAttribute("position",new THREE.BufferAttribute(new Float32Array(d),3))};THREE.EdgesGeometry.prototype=Object.create(THREE.BufferGeometry.prototype);THREE.EdgesGeometry.prototype.constructor=THREE.EdgesGeometry;
 face2:void 0}:e[q].face2=l}d=[];for(q in e)if(f=e[q],void 0===f.face2||h[f.face1].normal.dot(h[f.face2].normal)<=c)g=k[f.vert1],d.push(g.x),d.push(g.y),d.push(g.z),g=k[f.vert2],d.push(g.x),d.push(g.y),d.push(g.z);this.addAttribute("position",new THREE.BufferAttribute(new Float32Array(d),3))};THREE.EdgesGeometry.prototype=Object.create(THREE.BufferGeometry.prototype);THREE.EdgesGeometry.prototype.constructor=THREE.EdgesGeometry;
 THREE.ExtrudeGeometry=function(a,b){"undefined"!==typeof a&&(THREE.Geometry.call(this),this.type="ExtrudeGeometry",a=Array.isArray(a)?a:[a],this.addShapeList(a,b),this.computeFaceNormals())};THREE.ExtrudeGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.ExtrudeGeometry.prototype.constructor=THREE.ExtrudeGeometry;THREE.ExtrudeGeometry.prototype.addShapeList=function(a,b){for(var c=a.length,d=0;d<c;d++)this.addShape(a[d],b)};
 THREE.ExtrudeGeometry=function(a,b){"undefined"!==typeof a&&(THREE.Geometry.call(this),this.type="ExtrudeGeometry",a=Array.isArray(a)?a:[a],this.addShapeList(a,b),this.computeFaceNormals())};THREE.ExtrudeGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.ExtrudeGeometry.prototype.constructor=THREE.ExtrudeGeometry;THREE.ExtrudeGeometry.prototype.addShapeList=function(a,b){for(var c=a.length,d=0;d<c;d++)this.addShape(a[d],b)};
 THREE.ExtrudeGeometry.prototype.addShape=function(a,b){function c(a,b,c){b||console.error("THREE.ExtrudeGeometry: vec does not exist");return b.clone().multiplyScalar(c).add(a)}function d(a,b,c){var d=1,d=a.x-b.x,e=a.y-b.y,f=c.x-a.x,g=c.y-a.y,h=d*d+e*e;if(1E-10<Math.abs(d*g-e*f)){var k=Math.sqrt(h),l=Math.sqrt(f*f+g*g),h=b.x-e/k;b=b.y+d/k;f=((c.x-g/l-h)*g-(c.y+f/l-b)*f)/(d*g-e*f);c=h+d*f-a.x;a=b+e*f-a.y;d=c*c+a*a;if(2>=d)return new THREE.Vector2(c,a);d=Math.sqrt(d/2)}else a=!1,1E-10<d?1E-10<f&&(a=
 THREE.ExtrudeGeometry.prototype.addShape=function(a,b){function c(a,b,c){b||console.error("THREE.ExtrudeGeometry: vec does not exist");return b.clone().multiplyScalar(c).add(a)}function d(a,b,c){var d=1,d=a.x-b.x,e=a.y-b.y,f=c.x-a.x,g=c.y-a.y,h=d*d+e*e;if(1E-10<Math.abs(d*g-e*f)){var k=Math.sqrt(h),l=Math.sqrt(f*f+g*g),h=b.x-e/k;b=b.y+d/k;f=((c.x-g/l-h)*g-(c.y+f/l-b)*f)/(d*g-e*f);c=h+d*f-a.x;a=b+e*f-a.y;d=c*c+a*a;if(2>=d)return new THREE.Vector2(c,a);d=Math.sqrt(d/2)}else a=!1,1E-10<d?1E-10<f&&(a=
-!0):-1E-10>d?-1E-10>f&&(a=!0):Math.sign(e)===Math.sign(g)&&(a=!0),a?(c=-e,a=d,d=Math.sqrt(h)):(c=d,a=e,d=Math.sqrt(h/2));return new THREE.Vector2(c/d,a/d)}function e(a,b){var c,d;for(K=a.length;0<=--K;){c=K;d=K-1;0>d&&(d=a.length-1);for(var e=0,f=q+2*n,e=0;e<f;e++){var g=S*e,h=S*(e+1),k=b+c+g,g=b+d+g,l=b+d+h,h=b+c+h,k=k+C,g=g+C,l=l+C,h=h+C;L.faces.push(new THREE.Face3(k,g,h));L.faces.push(new THREE.Face3(g,l,h));k=w.generateSideWallUV(L,k,g,l,h);L.faceVertexUvs[0].push([k[0],k[1],k[3]]);L.faceVertexUvs[0].push([k[1],
-k[2],k[3]])}}}function f(a,b,c){L.vertices.push(new THREE.Vector3(a,b,c))}function g(a,b,c){a+=C;b+=C;c+=C;L.faces.push(new THREE.Face3(a,b,c));a=w.generateTopUV(L,a,b,c);L.faceVertexUvs[0].push(a)}var h=void 0!==b.amount?b.amount:100,k=void 0!==b.bevelThickness?b.bevelThickness:6,l=void 0!==b.bevelSize?b.bevelSize:k-2,n=void 0!==b.bevelSegments?b.bevelSegments:3,p=void 0!==b.bevelEnabled?b.bevelEnabled:!0,m=void 0!==b.curveSegments?b.curveSegments:12,q=void 0!==b.steps?b.steps:1,t=b.extrudePath,
-s,u=!1,w=void 0!==b.UVGenerator?b.UVGenerator:THREE.ExtrudeGeometry.WorldUVGenerator,x,A,y,D;t&&(s=t.getSpacedPoints(q),u=!0,p=!1,x=void 0!==b.frames?b.frames:new THREE.TubeGeometry.FrenetFrames(t,q,!1),A=new THREE.Vector3,y=new THREE.Vector3,D=new THREE.Vector3);p||(l=k=n=0);var I,v,E,L=this,C=this.vertices.length,t=a.extractPoints(m),m=t.shape,F=t.holes;if(t=!THREE.Shape.Utils.isClockWise(m)){m=m.reverse();v=0;for(E=F.length;v<E;v++)I=F[v],THREE.Shape.Utils.isClockWise(I)&&(F[v]=I.reverse());t=
-!1}var R=THREE.Shape.Utils.triangulateShape(m,F),J=m;v=0;for(E=F.length;v<E;v++)I=F[v],m=m.concat(I);var z,G,B,T,O,S=m.length,P,H=R.length,t=[],K=0;B=J.length;z=B-1;for(G=K+1;K<B;K++,z++,G++)z===B&&(z=0),G===B&&(G=0),t[K]=d(J[K],J[z],J[G]);var na=[],da,ka=t.concat();v=0;for(E=F.length;v<E;v++){I=F[v];da=[];K=0;B=I.length;z=B-1;for(G=K+1;K<B;K++,z++,G++)z===B&&(z=0),G===B&&(G=0),da[K]=d(I[K],I[z],I[G]);na.push(da);ka=ka.concat(da)}for(z=0;z<n;z++){B=z/n;T=k*(1-B);G=l*Math.sin(B*Math.PI/2);K=0;for(B=
-J.length;K<B;K++)O=c(J[K],t[K],G),f(O.x,O.y,-T);v=0;for(E=F.length;v<E;v++)for(I=F[v],da=na[v],K=0,B=I.length;K<B;K++)O=c(I[K],da[K],G),f(O.x,O.y,-T)}G=l;for(K=0;K<S;K++)O=p?c(m[K],ka[K],G):m[K],u?(y.copy(x.normals[0]).multiplyScalar(O.x),A.copy(x.binormals[0]).multiplyScalar(O.y),D.copy(s[0]).add(y).add(A),f(D.x,D.y,D.z)):f(O.x,O.y,0);for(B=1;B<=q;B++)for(K=0;K<S;K++)O=p?c(m[K],ka[K],G):m[K],u?(y.copy(x.normals[B]).multiplyScalar(O.x),A.copy(x.binormals[B]).multiplyScalar(O.y),D.copy(s[B]).add(y).add(A),
-f(D.x,D.y,D.z)):f(O.x,O.y,h/q*B);for(z=n-1;0<=z;z--){B=z/n;T=k*(1-B);G=l*Math.sin(B*Math.PI/2);K=0;for(B=J.length;K<B;K++)O=c(J[K],t[K],G),f(O.x,O.y,h+T);v=0;for(E=F.length;v<E;v++)for(I=F[v],da=na[v],K=0,B=I.length;K<B;K++)O=c(I[K],da[K],G),u?f(O.x,O.y+s[q-1].y,s[q-1].x+T):f(O.x,O.y,h+T)}(function(){if(p){var a;a=0*S;for(K=0;K<H;K++)P=R[K],g(P[2]+a,P[1]+a,P[0]+a);a=q+2*n;a*=S;for(K=0;K<H;K++)P=R[K],g(P[0]+a,P[1]+a,P[2]+a)}else{for(K=0;K<H;K++)P=R[K],g(P[2],P[1],P[0]);for(K=0;K<H;K++)P=R[K],g(P[0]+
-S*q,P[1]+S*q,P[2]+S*q)}})();(function(){var a=0;e(J,a);a+=J.length;v=0;for(E=F.length;v<E;v++)I=F[v],e(I,a),a+=I.length})()};
+!0):-1E-10>d?-1E-10>f&&(a=!0):Math.sign(e)===Math.sign(g)&&(a=!0),a?(c=-e,a=d,d=Math.sqrt(h)):(c=d,a=e,d=Math.sqrt(h/2));return new THREE.Vector2(c/d,a/d)}function e(a,b){var c,d;for(K=a.length;0<=--K;){c=K;d=K-1;0>d&&(d=a.length-1);for(var e=0,f=q+2*n,e=0;e<f;e++){var g=S*e,h=S*(e+1),k=b+c+g,g=b+d+g,l=b+d+h,h=b+c+h,k=k+C,g=g+C,l=l+C,h=h+C;L.faces.push(new THREE.Face3(k,g,h));L.faces.push(new THREE.Face3(g,l,h));k=x.generateSideWallUV(L,k,g,l,h);L.faceVertexUvs[0].push([k[0],k[1],k[3]]);L.faceVertexUvs[0].push([k[1],
+k[2],k[3]])}}}function f(a,b,c){L.vertices.push(new THREE.Vector3(a,b,c))}function g(a,b,c){a+=C;b+=C;c+=C;L.faces.push(new THREE.Face3(a,b,c));a=x.generateTopUV(L,a,b,c);L.faceVertexUvs[0].push(a)}var h=void 0!==b.amount?b.amount:100,k=void 0!==b.bevelThickness?b.bevelThickness:6,l=void 0!==b.bevelSize?b.bevelSize:k-2,n=void 0!==b.bevelSegments?b.bevelSegments:3,p=void 0!==b.bevelEnabled?b.bevelEnabled:!0,m=void 0!==b.curveSegments?b.curveSegments:12,q=void 0!==b.steps?b.steps:1,s=b.extrudePath,
+t,u=!1,x=void 0!==b.UVGenerator?b.UVGenerator:THREE.ExtrudeGeometry.WorldUVGenerator,w,A,y,G;s&&(t=s.getSpacedPoints(q),u=!0,p=!1,w=void 0!==b.frames?b.frames:new THREE.TubeGeometry.FrenetFrames(s,q,!1),A=new THREE.Vector3,y=new THREE.Vector3,G=new THREE.Vector3);p||(l=k=n=0);var I,v,D,L=this,C=this.vertices.length,s=a.extractPoints(m),m=s.shape,E=s.holes;if(s=!THREE.Shape.Utils.isClockWise(m)){m=m.reverse();v=0;for(D=E.length;v<D;v++)I=E[v],THREE.Shape.Utils.isClockWise(I)&&(E[v]=I.reverse());s=
+!1}var R=THREE.Shape.Utils.triangulateShape(m,E),J=m;v=0;for(D=E.length;v<D;v++)I=E[v],m=m.concat(I);var z,F,B,T,O,S=m.length,P,H=R.length,s=[],K=0;B=J.length;z=B-1;for(F=K+1;K<B;K++,z++,F++)z===B&&(z=0),F===B&&(F=0),s[K]=d(J[K],J[z],J[F]);var na=[],da,ka=s.concat();v=0;for(D=E.length;v<D;v++){I=E[v];da=[];K=0;B=I.length;z=B-1;for(F=K+1;K<B;K++,z++,F++)z===B&&(z=0),F===B&&(F=0),da[K]=d(I[K],I[z],I[F]);na.push(da);ka=ka.concat(da)}for(z=0;z<n;z++){B=z/n;T=k*(1-B);F=l*Math.sin(B*Math.PI/2);K=0;for(B=
+J.length;K<B;K++)O=c(J[K],s[K],F),f(O.x,O.y,-T);v=0;for(D=E.length;v<D;v++)for(I=E[v],da=na[v],K=0,B=I.length;K<B;K++)O=c(I[K],da[K],F),f(O.x,O.y,-T)}F=l;for(K=0;K<S;K++)O=p?c(m[K],ka[K],F):m[K],u?(y.copy(w.normals[0]).multiplyScalar(O.x),A.copy(w.binormals[0]).multiplyScalar(O.y),G.copy(t[0]).add(y).add(A),f(G.x,G.y,G.z)):f(O.x,O.y,0);for(B=1;B<=q;B++)for(K=0;K<S;K++)O=p?c(m[K],ka[K],F):m[K],u?(y.copy(w.normals[B]).multiplyScalar(O.x),A.copy(w.binormals[B]).multiplyScalar(O.y),G.copy(t[B]).add(y).add(A),
+f(G.x,G.y,G.z)):f(O.x,O.y,h/q*B);for(z=n-1;0<=z;z--){B=z/n;T=k*(1-B);F=l*Math.sin(B*Math.PI/2);K=0;for(B=J.length;K<B;K++)O=c(J[K],s[K],F),f(O.x,O.y,h+T);v=0;for(D=E.length;v<D;v++)for(I=E[v],da=na[v],K=0,B=I.length;K<B;K++)O=c(I[K],da[K],F),u?f(O.x,O.y+t[q-1].y,t[q-1].x+T):f(O.x,O.y,h+T)}(function(){if(p){var a;a=0*S;for(K=0;K<H;K++)P=R[K],g(P[2]+a,P[1]+a,P[0]+a);a=q+2*n;a*=S;for(K=0;K<H;K++)P=R[K],g(P[0]+a,P[1]+a,P[2]+a)}else{for(K=0;K<H;K++)P=R[K],g(P[2],P[1],P[0]);for(K=0;K<H;K++)P=R[K],g(P[0]+
+S*q,P[1]+S*q,P[2]+S*q)}})();(function(){var a=0;e(J,a);a+=J.length;v=0;for(D=E.length;v<D;v++)I=E[v],e(I,a),a+=I.length})()};
 THREE.ExtrudeGeometry.WorldUVGenerator={generateTopUV:function(a,b,c,d){a=a.vertices;b=a[b];c=a[c];d=a[d];return[new THREE.Vector2(b.x,b.y),new THREE.Vector2(c.x,c.y),new THREE.Vector2(d.x,d.y)]},generateSideWallUV:function(a,b,c,d,e){a=a.vertices;b=a[b];c=a[c];d=a[d];e=a[e];return.01>Math.abs(b.y-c.y)?[new THREE.Vector2(b.x,1-b.z),new THREE.Vector2(c.x,1-c.z),new THREE.Vector2(d.x,1-d.z),new THREE.Vector2(e.x,1-e.z)]:[new THREE.Vector2(b.y,1-b.z),new THREE.Vector2(c.y,1-c.z),new THREE.Vector2(d.y,
 THREE.ExtrudeGeometry.WorldUVGenerator={generateTopUV:function(a,b,c,d){a=a.vertices;b=a[b];c=a[c];d=a[d];return[new THREE.Vector2(b.x,b.y),new THREE.Vector2(c.x,c.y),new THREE.Vector2(d.x,d.y)]},generateSideWallUV:function(a,b,c,d,e){a=a.vertices;b=a[b];c=a[c];d=a[d];e=a[e];return.01>Math.abs(b.y-c.y)?[new THREE.Vector2(b.x,1-b.z),new THREE.Vector2(c.x,1-c.z),new THREE.Vector2(d.x,1-d.z),new THREE.Vector2(e.x,1-e.z)]:[new THREE.Vector2(b.y,1-b.z),new THREE.Vector2(c.y,1-c.z),new THREE.Vector2(d.y,
 1-d.z),new THREE.Vector2(e.y,1-e.z)]}};THREE.ShapeGeometry=function(a,b){THREE.Geometry.call(this);this.type="ShapeGeometry";!1===Array.isArray(a)&&(a=[a]);this.addShapeList(a,b);this.computeFaceNormals()};THREE.ShapeGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.ShapeGeometry.prototype.constructor=THREE.ShapeGeometry;THREE.ShapeGeometry.prototype.addShapeList=function(a,b){for(var c=0,d=a.length;c<d;c++)this.addShape(a[c],b);return this};
 1-d.z),new THREE.Vector2(e.y,1-e.z)]}};THREE.ShapeGeometry=function(a,b){THREE.Geometry.call(this);this.type="ShapeGeometry";!1===Array.isArray(a)&&(a=[a]);this.addShapeList(a,b);this.computeFaceNormals()};THREE.ShapeGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.ShapeGeometry.prototype.constructor=THREE.ShapeGeometry;THREE.ShapeGeometry.prototype.addShapeList=function(a,b){for(var c=0,d=a.length;c<d;c++)this.addShape(a[c],b);return this};
 THREE.ShapeGeometry.prototype.addShape=function(a,b){void 0===b&&(b={});var c=b.material,d=void 0===b.UVGenerator?THREE.ExtrudeGeometry.WorldUVGenerator:b.UVGenerator,e,f,g,h=this.vertices.length;e=a.extractPoints(void 0!==b.curveSegments?b.curveSegments:12);var k=e.shape,l=e.holes;if(!THREE.Shape.Utils.isClockWise(k))for(k=k.reverse(),e=0,f=l.length;e<f;e++)g=l[e],THREE.Shape.Utils.isClockWise(g)&&(l[e]=g.reverse());var n=THREE.Shape.Utils.triangulateShape(k,l);e=0;for(f=l.length;e<f;e++)g=l[e],
 THREE.ShapeGeometry.prototype.addShape=function(a,b){void 0===b&&(b={});var c=b.material,d=void 0===b.UVGenerator?THREE.ExtrudeGeometry.WorldUVGenerator:b.UVGenerator,e,f,g,h=this.vertices.length;e=a.extractPoints(void 0!==b.curveSegments?b.curveSegments:12);var k=e.shape,l=e.holes;if(!THREE.Shape.Utils.isClockWise(k))for(k=k.reverse(),e=0,f=l.length;e<f;e++)g=l[e],THREE.Shape.Utils.isClockWise(g)&&(l[e]=g.reverse());var n=THREE.Shape.Utils.triangulateShape(k,l);e=0;for(f=l.length;e<f;e++)g=l[e],
 k=k.concat(g);l=k.length;f=n.length;for(e=0;e<l;e++)g=k[e],this.vertices.push(new THREE.Vector3(g.x,g.y,0));for(e=0;e<f;e++)l=n[e],k=l[0]+h,g=l[1]+h,l=l[2]+h,this.faces.push(new THREE.Face3(k,g,l,null,null,c)),this.faceVertexUvs[0].push(d.generateTopUV(this,k,g,l))};
 k=k.concat(g);l=k.length;f=n.length;for(e=0;e<l;e++)g=k[e],this.vertices.push(new THREE.Vector3(g.x,g.y,0));for(e=0;e<f;e++)l=n[e],k=l[0]+h,g=l[1]+h,l=l[2]+h,this.faces.push(new THREE.Face3(k,g,l,null,null,c)),this.faceVertexUvs[0].push(d.generateTopUV(this,k,g,l))};
-THREE.LatheGeometry=function(a,b,c,d){THREE.Geometry.call(this);this.type="LatheGeometry";this.parameters={points:a,segments:b,phiStart:c,phiLength:d};b=b||12;c=c||0;d=d||2*Math.PI;for(var e=1/(a.length-1),f=1/b,g=0,h=b;g<=h;g++)for(var k=c+g*f*d,l=Math.cos(k),n=Math.sin(k),k=0,p=a.length;k<p;k++){var m=a[k],q=new THREE.Vector3;q.x=l*m.x-n*m.y;q.y=n*m.x+l*m.y;q.z=m.z;this.vertices.push(q)}c=a.length;g=0;for(h=b;g<h;g++)for(k=0,p=a.length-1;k<p;k++){b=n=k+c*g;d=n+c;var l=n+1+c,n=n+1,m=g*f,q=k*e,t=
-m+f,s=q+e;this.faces.push(new THREE.Face3(b,d,n));this.faceVertexUvs[0].push([new THREE.Vector2(m,q),new THREE.Vector2(t,q),new THREE.Vector2(m,s)]);this.faces.push(new THREE.Face3(d,l,n));this.faceVertexUvs[0].push([new THREE.Vector2(t,q),new THREE.Vector2(t,s),new THREE.Vector2(m,s)])}this.mergeVertices();this.computeFaceNormals();this.computeVertexNormals()};THREE.LatheGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.LatheGeometry.prototype.constructor=THREE.LatheGeometry;
+THREE.LatheGeometry=function(a,b,c,d){THREE.Geometry.call(this);this.type="LatheGeometry";this.parameters={points:a,segments:b,phiStart:c,phiLength:d};b=b||12;c=c||0;d=d||2*Math.PI;for(var e=1/(a.length-1),f=1/b,g=0,h=b;g<=h;g++)for(var k=c+g*f*d,l=Math.cos(k),n=Math.sin(k),k=0,p=a.length;k<p;k++){var m=a[k],q=new THREE.Vector3;q.x=l*m.x-n*m.y;q.y=n*m.x+l*m.y;q.z=m.z;this.vertices.push(q)}c=a.length;g=0;for(h=b;g<h;g++)for(k=0,p=a.length-1;k<p;k++){b=n=k+c*g;d=n+c;var l=n+1+c,n=n+1,m=g*f,q=k*e,s=
+m+f,t=q+e;this.faces.push(new THREE.Face3(b,d,n));this.faceVertexUvs[0].push([new THREE.Vector2(m,q),new THREE.Vector2(s,q),new THREE.Vector2(m,t)]);this.faces.push(new THREE.Face3(d,l,n));this.faceVertexUvs[0].push([new THREE.Vector2(s,q),new THREE.Vector2(s,t),new THREE.Vector2(m,t)])}this.mergeVertices();this.computeFaceNormals();this.computeVertexNormals()};THREE.LatheGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.LatheGeometry.prototype.constructor=THREE.LatheGeometry;
 THREE.PlaneGeometry=function(a,b,c,d){console.log("THREE.PlaneGeometry: Consider using THREE.PlaneBufferGeometry for lower memory footprint.");THREE.Geometry.call(this);this.type="PlaneGeometry";this.parameters={width:a,height:b,widthSegments:c,heightSegments:d};this.fromBufferGeometry(new THREE.PlaneBufferGeometry(a,b,c,d))};THREE.PlaneGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.PlaneGeometry.prototype.constructor=THREE.PlaneGeometry;
 THREE.PlaneGeometry=function(a,b,c,d){console.log("THREE.PlaneGeometry: Consider using THREE.PlaneBufferGeometry for lower memory footprint.");THREE.Geometry.call(this);this.type="PlaneGeometry";this.parameters={width:a,height:b,widthSegments:c,heightSegments:d};this.fromBufferGeometry(new THREE.PlaneBufferGeometry(a,b,c,d))};THREE.PlaneGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.PlaneGeometry.prototype.constructor=THREE.PlaneGeometry;
-THREE.PlaneBufferGeometry=function(a,b,c,d){THREE.BufferGeometry.call(this);this.type="PlaneBufferGeometry";this.parameters={width:a,height:b,widthSegments:c,heightSegments:d};var e=a/2,f=b/2;c=Math.floor(c)||1;d=Math.floor(d)||1;var g=c+1,h=d+1,k=a/c,l=b/d;b=new Float32Array(g*h*3);a=new Float32Array(g*h*3);for(var n=new Float32Array(g*h*2),p=0,m=0,q=0;q<h;q++)for(var t=q*l-f,s=0;s<g;s++)b[p]=s*k-e,b[p+1]=-t,a[p+2]=1,n[m]=s/c,n[m+1]=1-q/d,p+=3,m+=2;p=0;e=new (65535<b.length/3?Uint32Array:Uint16Array)(c*
-d*6);for(q=0;q<d;q++)for(s=0;s<c;s++)f=s+g*(q+1),h=s+1+g*(q+1),k=s+1+g*q,e[p]=s+g*q,e[p+1]=f,e[p+2]=k,e[p+3]=f,e[p+4]=h,e[p+5]=k,p+=6;this.addAttribute("index",new THREE.BufferAttribute(e,1));this.addAttribute("position",new THREE.BufferAttribute(b,3));this.addAttribute("normal",new THREE.BufferAttribute(a,3));this.addAttribute("uv",new THREE.BufferAttribute(n,2))};THREE.PlaneBufferGeometry.prototype=Object.create(THREE.BufferGeometry.prototype);THREE.PlaneBufferGeometry.prototype.constructor=THREE.PlaneBufferGeometry;
+THREE.PlaneBufferGeometry=function(a,b,c,d){THREE.BufferGeometry.call(this);this.type="PlaneBufferGeometry";this.parameters={width:a,height:b,widthSegments:c,heightSegments:d};var e=a/2,f=b/2;c=Math.floor(c)||1;d=Math.floor(d)||1;var g=c+1,h=d+1,k=a/c,l=b/d;b=new Float32Array(g*h*3);a=new Float32Array(g*h*3);for(var n=new Float32Array(g*h*2),p=0,m=0,q=0;q<h;q++)for(var s=q*l-f,t=0;t<g;t++)b[p]=t*k-e,b[p+1]=-s,a[p+2]=1,n[m]=t/c,n[m+1]=1-q/d,p+=3,m+=2;p=0;e=new (65535<b.length/3?Uint32Array:Uint16Array)(c*
+d*6);for(q=0;q<d;q++)for(t=0;t<c;t++)f=t+g*(q+1),h=t+1+g*(q+1),k=t+1+g*q,e[p]=t+g*q,e[p+1]=f,e[p+2]=k,e[p+3]=f,e[p+4]=h,e[p+5]=k,p+=6;this.addAttribute("index",new THREE.BufferAttribute(e,1));this.addAttribute("position",new THREE.BufferAttribute(b,3));this.addAttribute("normal",new THREE.BufferAttribute(a,3));this.addAttribute("uv",new THREE.BufferAttribute(n,2))};THREE.PlaneBufferGeometry.prototype=Object.create(THREE.BufferGeometry.prototype);THREE.PlaneBufferGeometry.prototype.constructor=THREE.PlaneBufferGeometry;
 THREE.RingGeometry=function(a,b,c,d,e,f){THREE.Geometry.call(this);this.type="RingGeometry";this.parameters={innerRadius:a,outerRadius:b,thetaSegments:c,phiSegments:d,thetaStart:e,thetaLength:f};a=a||0;b=b||50;e=void 0!==e?e:0;f=void 0!==f?f:2*Math.PI;c=void 0!==c?Math.max(3,c):8;d=void 0!==d?Math.max(1,d):8;var g,h=[],k=a,l=(b-a)/d;for(a=0;a<d+1;a++){for(g=0;g<c+1;g++){var n=new THREE.Vector3,p=e+g/c*f;n.x=k*Math.cos(p);n.y=k*Math.sin(p);this.vertices.push(n);h.push(new THREE.Vector2((n.x/b+1)/2,
 THREE.RingGeometry=function(a,b,c,d,e,f){THREE.Geometry.call(this);this.type="RingGeometry";this.parameters={innerRadius:a,outerRadius:b,thetaSegments:c,phiSegments:d,thetaStart:e,thetaLength:f};a=a||0;b=b||50;e=void 0!==e?e:0;f=void 0!==f?f:2*Math.PI;c=void 0!==c?Math.max(3,c):8;d=void 0!==d?Math.max(1,d):8;var g,h=[],k=a,l=(b-a)/d;for(a=0;a<d+1;a++){for(g=0;g<c+1;g++){var n=new THREE.Vector3,p=e+g/c*f;n.x=k*Math.cos(p);n.y=k*Math.sin(p);this.vertices.push(n);h.push(new THREE.Vector2((n.x/b+1)/2,
 (n.y/b+1)/2))}k+=l}b=new THREE.Vector3(0,0,1);for(a=0;a<d;a++)for(e=a*(c+1),g=0;g<c;g++)f=p=g+e,l=p+c+1,n=p+c+2,this.faces.push(new THREE.Face3(f,l,n,[b.clone(),b.clone(),b.clone()])),this.faceVertexUvs[0].push([h[f].clone(),h[l].clone(),h[n].clone()]),f=p,l=p+c+2,n=p+1,this.faces.push(new THREE.Face3(f,l,n,[b.clone(),b.clone(),b.clone()])),this.faceVertexUvs[0].push([h[f].clone(),h[l].clone(),h[n].clone()]);this.computeFaceNormals();this.boundingSphere=new THREE.Sphere(new THREE.Vector3,k)};
 (n.y/b+1)/2))}k+=l}b=new THREE.Vector3(0,0,1);for(a=0;a<d;a++)for(e=a*(c+1),g=0;g<c;g++)f=p=g+e,l=p+c+1,n=p+c+2,this.faces.push(new THREE.Face3(f,l,n,[b.clone(),b.clone(),b.clone()])),this.faceVertexUvs[0].push([h[f].clone(),h[l].clone(),h[n].clone()]),f=p,l=p+c+2,n=p+1,this.faces.push(new THREE.Face3(f,l,n,[b.clone(),b.clone(),b.clone()])),this.faceVertexUvs[0].push([h[f].clone(),h[l].clone(),h[n].clone()]);this.computeFaceNormals();this.boundingSphere=new THREE.Sphere(new THREE.Vector3,k)};
 THREE.RingGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.RingGeometry.prototype.constructor=THREE.RingGeometry;
 THREE.RingGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.RingGeometry.prototype.constructor=THREE.RingGeometry;
 THREE.SphereGeometry=function(a,b,c,d,e,f,g){console.log("THREE.SphereGeometry: Consider using THREE.SphereBufferGeometry for lower memory footprint.");THREE.Geometry.call(this);this.type="SphereGeometry";this.parameters={radius:a,widthSegments:b,heightSegments:c,phiStart:d,phiLength:e,thetaStart:f,thetaLength:g};a=a||50;b=Math.max(2,Math.floor(b)||8);c=Math.max(2,Math.floor(c)||6);d=void 0!==d?d:0;e=void 0!==e?e:2*Math.PI;f=void 0!==f?f:0;g=void 0!==g?g:Math.PI;var h,k,l=[],n=[];for(k=0;k<=c;k++){var p=
 THREE.SphereGeometry=function(a,b,c,d,e,f,g){console.log("THREE.SphereGeometry: Consider using THREE.SphereBufferGeometry for lower memory footprint.");THREE.Geometry.call(this);this.type="SphereGeometry";this.parameters={radius:a,widthSegments:b,heightSegments:c,phiStart:d,phiLength:e,thetaStart:f,thetaLength:g};a=a||50;b=Math.max(2,Math.floor(b)||8);c=Math.max(2,Math.floor(c)||6);d=void 0!==d?d:0;e=void 0!==e?e:2*Math.PI;f=void 0!==f?f:0;g=void 0!==g?g:Math.PI;var h,k,l=[],n=[];for(k=0;k<=c;k++){var p=
-[],m=[];for(h=0;h<=b;h++){var q=h/b,t=k/c,s=new THREE.Vector3;s.x=-a*Math.cos(d+q*e)*Math.sin(f+t*g);s.y=a*Math.cos(f+t*g);s.z=a*Math.sin(d+q*e)*Math.sin(f+t*g);this.vertices.push(s);p.push(this.vertices.length-1);m.push(new THREE.Vector2(q,1-t))}l.push(p);n.push(m)}for(k=0;k<c;k++)for(h=0;h<b;h++){d=l[k][h+1];e=l[k][h];f=l[k+1][h];g=l[k+1][h+1];var p=this.vertices[d].clone().normalize(),m=this.vertices[e].clone().normalize(),q=this.vertices[f].clone().normalize(),t=this.vertices[g].clone().normalize(),
-s=n[k][h+1].clone(),u=n[k][h].clone(),w=n[k+1][h].clone(),x=n[k+1][h+1].clone();Math.abs(this.vertices[d].y)===a?(s.x=(s.x+u.x)/2,this.faces.push(new THREE.Face3(d,f,g,[p,q,t])),this.faceVertexUvs[0].push([s,w,x])):Math.abs(this.vertices[f].y)===a?(w.x=(w.x+x.x)/2,this.faces.push(new THREE.Face3(d,e,f,[p,m,q])),this.faceVertexUvs[0].push([s,u,w])):(this.faces.push(new THREE.Face3(d,e,g,[p,m,t])),this.faceVertexUvs[0].push([s,u,x]),this.faces.push(new THREE.Face3(e,f,g,[m.clone(),q,t.clone()])),this.faceVertexUvs[0].push([u.clone(),
-w,x.clone()]))}this.computeFaceNormals();this.boundingSphere=new THREE.Sphere(new THREE.Vector3,a)};THREE.SphereGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.SphereGeometry.prototype.constructor=THREE.SphereGeometry;
+[],m=[];for(h=0;h<=b;h++){var q=h/b,s=k/c,t=new THREE.Vector3;t.x=-a*Math.cos(d+q*e)*Math.sin(f+s*g);t.y=a*Math.cos(f+s*g);t.z=a*Math.sin(d+q*e)*Math.sin(f+s*g);this.vertices.push(t);p.push(this.vertices.length-1);m.push(new THREE.Vector2(q,1-s))}l.push(p);n.push(m)}for(k=0;k<c;k++)for(h=0;h<b;h++){d=l[k][h+1];e=l[k][h];f=l[k+1][h];g=l[k+1][h+1];var p=this.vertices[d].clone().normalize(),m=this.vertices[e].clone().normalize(),q=this.vertices[f].clone().normalize(),s=this.vertices[g].clone().normalize(),
+t=n[k][h+1].clone(),u=n[k][h].clone(),x=n[k+1][h].clone(),w=n[k+1][h+1].clone();Math.abs(this.vertices[d].y)===a?(t.x=(t.x+u.x)/2,this.faces.push(new THREE.Face3(d,f,g,[p,q,s])),this.faceVertexUvs[0].push([t,x,w])):Math.abs(this.vertices[f].y)===a?(x.x=(x.x+w.x)/2,this.faces.push(new THREE.Face3(d,e,f,[p,m,q])),this.faceVertexUvs[0].push([t,u,x])):(this.faces.push(new THREE.Face3(d,e,g,[p,m,s])),this.faceVertexUvs[0].push([t,u,w]),this.faces.push(new THREE.Face3(e,f,g,[m.clone(),q,s.clone()])),this.faceVertexUvs[0].push([u.clone(),
+x,w.clone()]))}this.computeFaceNormals();this.boundingSphere=new THREE.Sphere(new THREE.Vector3,a)};THREE.SphereGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.SphereGeometry.prototype.constructor=THREE.SphereGeometry;
 THREE.SphereBufferGeometry=function(a,b,c,d,e,f,g){THREE.BufferGeometry.call(this);this.type="SphereBufferGeometry";this.parameters={radius:a,widthSegments:b,heightSegments:c,phiStart:d,phiLength:e,thetaStart:f,thetaLength:g};a=a||50;b=Math.max(2,Math.floor(b)||8);c=Math.max(2,Math.floor(c)||6);d=void 0!==d?d:0;e=void 0!==e?e:2*Math.PI;f=void 0!==f?f:0;g=void 0!==g?g:Math.PI;for(var h=(b+1)*(c+1),k=new THREE.BufferAttribute(new Float32Array(3*h),3),l=new THREE.BufferAttribute(new Float32Array(3*h),
 THREE.SphereBufferGeometry=function(a,b,c,d,e,f,g){THREE.BufferGeometry.call(this);this.type="SphereBufferGeometry";this.parameters={radius:a,widthSegments:b,heightSegments:c,phiStart:d,phiLength:e,thetaStart:f,thetaLength:g};a=a||50;b=Math.max(2,Math.floor(b)||8);c=Math.max(2,Math.floor(c)||6);d=void 0!==d?d:0;e=void 0!==e?e:2*Math.PI;f=void 0!==f?f:0;g=void 0!==g?g:Math.PI;for(var h=(b+1)*(c+1),k=new THREE.BufferAttribute(new Float32Array(3*h),3),l=new THREE.BufferAttribute(new Float32Array(3*h),
-3),h=new THREE.BufferAttribute(new Float32Array(2*h),2),n=0,p=[],m=new THREE.Vector3,q=0;q<=c;q++){for(var t=[],s=q/c,u=0;u<=b;u++){var w=u/b,x=-a*Math.cos(d+w*e)*Math.sin(f+s*g),A=a*Math.cos(f+s*g),y=a*Math.sin(d+w*e)*Math.sin(f+s*g);m.set(x,A,y).normalize();k.setXYZ(n,x,A,y);l.setXYZ(n,m.x,m.y,m.z);h.setXY(n,w,1-s);t.push(n);n++}p.push(t)}d=[];for(q=0;q<c;q++)for(u=0;u<b;u++)e=p[q][u+1],f=p[q][u],g=p[q+1][u],n=p[q+1][u+1],0!==q&&d.push(e,f,n),q!==c-1&&d.push(f,g,n);this.addAttribute("index",new THREE.BufferAttribute(new Uint16Array(d),
+3),h=new THREE.BufferAttribute(new Float32Array(2*h),2),n=0,p=[],m=new THREE.Vector3,q=0;q<=c;q++){for(var s=[],t=q/c,u=0;u<=b;u++){var x=u/b,w=-a*Math.cos(d+x*e)*Math.sin(f+t*g),A=a*Math.cos(f+t*g),y=a*Math.sin(d+x*e)*Math.sin(f+t*g);m.set(w,A,y).normalize();k.setXYZ(n,w,A,y);l.setXYZ(n,m.x,m.y,m.z);h.setXY(n,x,1-t);s.push(n);n++}p.push(s)}d=[];for(q=0;q<c;q++)for(u=0;u<b;u++)e=p[q][u+1],f=p[q][u],g=p[q+1][u],n=p[q+1][u+1],0!==q&&d.push(e,f,n),q!==c-1&&d.push(f,g,n);this.addAttribute("index",new THREE.BufferAttribute(new Uint16Array(d),
 1));this.addAttribute("position",k);this.addAttribute("normal",l);this.addAttribute("uv",h);this.boundingSphere=new THREE.Sphere(new THREE.Vector3,a)};THREE.SphereBufferGeometry.prototype=Object.create(THREE.BufferGeometry.prototype);THREE.SphereBufferGeometry.prototype.constructor=THREE.SphereBufferGeometry;
 1));this.addAttribute("position",k);this.addAttribute("normal",l);this.addAttribute("uv",h);this.boundingSphere=new THREE.Sphere(new THREE.Vector3,a)};THREE.SphereBufferGeometry.prototype=Object.create(THREE.BufferGeometry.prototype);THREE.SphereBufferGeometry.prototype.constructor=THREE.SphereBufferGeometry;
 THREE.TextGeometry=function(a,b){b=b||{};var c=THREE.FontUtils.generateShapes(a,b);b.amount=void 0!==b.height?b.height:50;void 0===b.bevelThickness&&(b.bevelThickness=10);void 0===b.bevelSize&&(b.bevelSize=8);void 0===b.bevelEnabled&&(b.bevelEnabled=!1);THREE.ExtrudeGeometry.call(this,c,b);this.type="TextGeometry"};THREE.TextGeometry.prototype=Object.create(THREE.ExtrudeGeometry.prototype);THREE.TextGeometry.prototype.constructor=THREE.TextGeometry;
 THREE.TextGeometry=function(a,b){b=b||{};var c=THREE.FontUtils.generateShapes(a,b);b.amount=void 0!==b.height?b.height:50;void 0===b.bevelThickness&&(b.bevelThickness=10);void 0===b.bevelSize&&(b.bevelSize=8);void 0===b.bevelEnabled&&(b.bevelEnabled=!1);THREE.ExtrudeGeometry.call(this,c,b);this.type="TextGeometry"};THREE.TextGeometry.prototype=Object.create(THREE.ExtrudeGeometry.prototype);THREE.TextGeometry.prototype.constructor=THREE.TextGeometry;
 THREE.TorusGeometry=function(a,b,c,d,e){THREE.Geometry.call(this);this.type="TorusGeometry";this.parameters={radius:a,tube:b,radialSegments:c,tubularSegments:d,arc:e};a=a||100;b=b||40;c=c||8;d=d||6;e=e||2*Math.PI;for(var f=new THREE.Vector3,g=[],h=[],k=0;k<=c;k++)for(var l=0;l<=d;l++){var n=l/d*e,p=k/c*Math.PI*2;f.x=a*Math.cos(n);f.y=a*Math.sin(n);var m=new THREE.Vector3;m.x=(a+b*Math.cos(p))*Math.cos(n);m.y=(a+b*Math.cos(p))*Math.sin(n);m.z=b*Math.sin(p);this.vertices.push(m);g.push(new THREE.Vector2(l/
 THREE.TorusGeometry=function(a,b,c,d,e){THREE.Geometry.call(this);this.type="TorusGeometry";this.parameters={radius:a,tube:b,radialSegments:c,tubularSegments:d,arc:e};a=a||100;b=b||40;c=c||8;d=d||6;e=e||2*Math.PI;for(var f=new THREE.Vector3,g=[],h=[],k=0;k<=c;k++)for(var l=0;l<=d;l++){var n=l/d*e,p=k/c*Math.PI*2;f.x=a*Math.cos(n);f.y=a*Math.sin(n);var m=new THREE.Vector3;m.x=(a+b*Math.cos(p))*Math.cos(n);m.y=(a+b*Math.cos(p))*Math.sin(n);m.z=b*Math.sin(p);this.vertices.push(m);g.push(new THREE.Vector2(l/
 d,k/c));h.push(m.clone().sub(f).normalize())}for(k=1;k<=c;k++)for(l=1;l<=d;l++)a=(d+1)*k+l-1,b=(d+1)*(k-1)+l-1,e=(d+1)*(k-1)+l,f=(d+1)*k+l,n=new THREE.Face3(a,b,f,[h[a].clone(),h[b].clone(),h[f].clone()]),this.faces.push(n),this.faceVertexUvs[0].push([g[a].clone(),g[b].clone(),g[f].clone()]),n=new THREE.Face3(b,e,f,[h[b].clone(),h[e].clone(),h[f].clone()]),this.faces.push(n),this.faceVertexUvs[0].push([g[b].clone(),g[e].clone(),g[f].clone()]);this.computeFaceNormals()};
 d,k/c));h.push(m.clone().sub(f).normalize())}for(k=1;k<=c;k++)for(l=1;l<=d;l++)a=(d+1)*k+l-1,b=(d+1)*(k-1)+l-1,e=(d+1)*(k-1)+l,f=(d+1)*k+l,n=new THREE.Face3(a,b,f,[h[a].clone(),h[b].clone(),h[f].clone()]),this.faces.push(n),this.faceVertexUvs[0].push([g[a].clone(),g[b].clone(),g[f].clone()]),n=new THREE.Face3(b,e,f,[h[b].clone(),h[e].clone(),h[f].clone()]),this.faces.push(n),this.faceVertexUvs[0].push([g[b].clone(),g[e].clone(),g[f].clone()]);this.computeFaceNormals()};
 THREE.TorusGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.TorusGeometry.prototype.constructor=THREE.TorusGeometry;
 THREE.TorusGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.TorusGeometry.prototype.constructor=THREE.TorusGeometry;
 THREE.TorusKnotGeometry=function(a,b,c,d,e,f,g){function h(a,b,c,d,e){var f=Math.cos(a),g=Math.sin(a);a*=b/c;b=Math.cos(a);f*=d*(2+b)*.5;g=d*(2+b)*g*.5;d=e*d*Math.sin(a)*.5;return new THREE.Vector3(f,g,d)}THREE.Geometry.call(this);this.type="TorusKnotGeometry";this.parameters={radius:a,tube:b,radialSegments:c,tubularSegments:d,p:e,q:f,heightScale:g};a=a||100;b=b||40;c=c||64;d=d||8;e=e||2;f=f||3;g=g||1;for(var k=Array(c),l=new THREE.Vector3,n=new THREE.Vector3,p=new THREE.Vector3,m=0;m<c;++m){k[m]=
 THREE.TorusKnotGeometry=function(a,b,c,d,e,f,g){function h(a,b,c,d,e){var f=Math.cos(a),g=Math.sin(a);a*=b/c;b=Math.cos(a);f*=d*(2+b)*.5;g=d*(2+b)*g*.5;d=e*d*Math.sin(a)*.5;return new THREE.Vector3(f,g,d)}THREE.Geometry.call(this);this.type="TorusKnotGeometry";this.parameters={radius:a,tube:b,radialSegments:c,tubularSegments:d,p:e,q:f,heightScale:g};a=a||100;b=b||40;c=c||64;d=d||8;e=e||2;f=f||3;g=g||1;for(var k=Array(c),l=new THREE.Vector3,n=new THREE.Vector3,p=new THREE.Vector3,m=0;m<c;++m){k[m]=
-Array(d);var q=m/c*2*e*Math.PI,t=h(q,f,e,a,g),q=h(q+.01,f,e,a,g);l.subVectors(q,t);n.addVectors(q,t);p.crossVectors(l,n);n.crossVectors(p,l);p.normalize();n.normalize();for(q=0;q<d;++q){var s=q/d*2*Math.PI,u=-b*Math.cos(s),s=b*Math.sin(s),w=new THREE.Vector3;w.x=t.x+u*n.x+s*p.x;w.y=t.y+u*n.y+s*p.y;w.z=t.z+u*n.z+s*p.z;k[m][q]=this.vertices.push(w)-1}}for(m=0;m<c;++m)for(q=0;q<d;++q)e=(m+1)%c,f=(q+1)%d,a=k[m][q],b=k[e][q],e=k[e][f],f=k[m][f],g=new THREE.Vector2(m/c,q/d),l=new THREE.Vector2((m+1)/c,
+Array(d);var q=m/c*2*e*Math.PI,s=h(q,f,e,a,g),q=h(q+.01,f,e,a,g);l.subVectors(q,s);n.addVectors(q,s);p.crossVectors(l,n);n.crossVectors(p,l);p.normalize();n.normalize();for(q=0;q<d;++q){var t=q/d*2*Math.PI,u=-b*Math.cos(t),t=b*Math.sin(t),x=new THREE.Vector3;x.x=s.x+u*n.x+t*p.x;x.y=s.y+u*n.y+t*p.y;x.z=s.z+u*n.z+t*p.z;k[m][q]=this.vertices.push(x)-1}}for(m=0;m<c;++m)for(q=0;q<d;++q)e=(m+1)%c,f=(q+1)%d,a=k[m][q],b=k[e][q],e=k[e][f],f=k[m][f],g=new THREE.Vector2(m/c,q/d),l=new THREE.Vector2((m+1)/c,
 q/d),n=new THREE.Vector2((m+1)/c,(q+1)/d),p=new THREE.Vector2(m/c,(q+1)/d),this.faces.push(new THREE.Face3(a,b,f)),this.faceVertexUvs[0].push([g,l,p]),this.faces.push(new THREE.Face3(b,e,f)),this.faceVertexUvs[0].push([l.clone(),n,p.clone()]);this.computeFaceNormals();this.computeVertexNormals()};THREE.TorusKnotGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.TorusKnotGeometry.prototype.constructor=THREE.TorusKnotGeometry;
 q/d),n=new THREE.Vector2((m+1)/c,(q+1)/d),p=new THREE.Vector2(m/c,(q+1)/d),this.faces.push(new THREE.Face3(a,b,f)),this.faceVertexUvs[0].push([g,l,p]),this.faces.push(new THREE.Face3(b,e,f)),this.faceVertexUvs[0].push([l.clone(),n,p.clone()]);this.computeFaceNormals();this.computeVertexNormals()};THREE.TorusKnotGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.TorusKnotGeometry.prototype.constructor=THREE.TorusKnotGeometry;
-THREE.TubeGeometry=function(a,b,c,d,e,f){THREE.Geometry.call(this);this.type="TubeGeometry";this.parameters={path:a,segments:b,radius:c,radialSegments:d,closed:e};b=b||64;c=c||1;d=d||8;e=e||!1;f=f||THREE.TubeGeometry.NoTaper;var g=[],h,k,l=b+1,n,p,m,q,t,s=new THREE.Vector3,u,w,x;u=new THREE.TubeGeometry.FrenetFrames(a,b,e);w=u.normals;x=u.binormals;this.tangents=u.tangents;this.normals=w;this.binormals=x;for(u=0;u<l;u++)for(g[u]=[],n=u/(l-1),t=a.getPointAt(n),h=w[u],k=x[u],m=c*f(n),n=0;n<d;n++)p=
-n/d*2*Math.PI,q=-m*Math.cos(p),p=m*Math.sin(p),s.copy(t),s.x+=q*h.x+p*k.x,s.y+=q*h.y+p*k.y,s.z+=q*h.z+p*k.z,g[u][n]=this.vertices.push(new THREE.Vector3(s.x,s.y,s.z))-1;for(u=0;u<b;u++)for(n=0;n<d;n++)f=e?(u+1)%b:u+1,l=(n+1)%d,a=g[u][n],c=g[f][n],f=g[f][l],l=g[u][l],s=new THREE.Vector2(u/b,n/d),w=new THREE.Vector2((u+1)/b,n/d),x=new THREE.Vector2((u+1)/b,(n+1)/d),h=new THREE.Vector2(u/b,(n+1)/d),this.faces.push(new THREE.Face3(a,c,l)),this.faceVertexUvs[0].push([s,w,h]),this.faces.push(new THREE.Face3(c,
-f,l)),this.faceVertexUvs[0].push([w.clone(),x,h.clone()]);this.computeFaceNormals();this.computeVertexNormals()};THREE.TubeGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.TubeGeometry.prototype.constructor=THREE.TubeGeometry;THREE.TubeGeometry.NoTaper=function(a){return 1};THREE.TubeGeometry.SinusoidalTaper=function(a){return Math.sin(Math.PI*a)};
+THREE.TubeGeometry=function(a,b,c,d,e,f){THREE.Geometry.call(this);this.type="TubeGeometry";this.parameters={path:a,segments:b,radius:c,radialSegments:d,closed:e};b=b||64;c=c||1;d=d||8;e=e||!1;f=f||THREE.TubeGeometry.NoTaper;var g=[],h,k,l=b+1,n,p,m,q,s,t=new THREE.Vector3,u,x,w;u=new THREE.TubeGeometry.FrenetFrames(a,b,e);x=u.normals;w=u.binormals;this.tangents=u.tangents;this.normals=x;this.binormals=w;for(u=0;u<l;u++)for(g[u]=[],n=u/(l-1),s=a.getPointAt(n),h=x[u],k=w[u],m=c*f(n),n=0;n<d;n++)p=
+n/d*2*Math.PI,q=-m*Math.cos(p),p=m*Math.sin(p),t.copy(s),t.x+=q*h.x+p*k.x,t.y+=q*h.y+p*k.y,t.z+=q*h.z+p*k.z,g[u][n]=this.vertices.push(new THREE.Vector3(t.x,t.y,t.z))-1;for(u=0;u<b;u++)for(n=0;n<d;n++)f=e?(u+1)%b:u+1,l=(n+1)%d,a=g[u][n],c=g[f][n],f=g[f][l],l=g[u][l],t=new THREE.Vector2(u/b,n/d),x=new THREE.Vector2((u+1)/b,n/d),w=new THREE.Vector2((u+1)/b,(n+1)/d),h=new THREE.Vector2(u/b,(n+1)/d),this.faces.push(new THREE.Face3(a,c,l)),this.faceVertexUvs[0].push([t,x,h]),this.faces.push(new THREE.Face3(c,
+f,l)),this.faceVertexUvs[0].push([x.clone(),w,h.clone()]);this.computeFaceNormals();this.computeVertexNormals()};THREE.TubeGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.TubeGeometry.prototype.constructor=THREE.TubeGeometry;THREE.TubeGeometry.NoTaper=function(a){return 1};THREE.TubeGeometry.SinusoidalTaper=function(a){return Math.sin(Math.PI*a)};
 THREE.TubeGeometry.FrenetFrames=function(a,b,c){var d=new THREE.Vector3,e=[],f=[],g=[],h=new THREE.Vector3,k=new THREE.Matrix4;b+=1;var l,n,p;this.tangents=e;this.normals=f;this.binormals=g;for(l=0;l<b;l++)n=l/(b-1),e[l]=a.getTangentAt(n),e[l].normalize();f[0]=new THREE.Vector3;g[0]=new THREE.Vector3;a=Number.MAX_VALUE;l=Math.abs(e[0].x);n=Math.abs(e[0].y);p=Math.abs(e[0].z);l<=a&&(a=l,d.set(1,0,0));n<=a&&(a=n,d.set(0,1,0));p<=a&&d.set(0,0,1);h.crossVectors(e[0],d).normalize();f[0].crossVectors(e[0],
 THREE.TubeGeometry.FrenetFrames=function(a,b,c){var d=new THREE.Vector3,e=[],f=[],g=[],h=new THREE.Vector3,k=new THREE.Matrix4;b+=1;var l,n,p;this.tangents=e;this.normals=f;this.binormals=g;for(l=0;l<b;l++)n=l/(b-1),e[l]=a.getTangentAt(n),e[l].normalize();f[0]=new THREE.Vector3;g[0]=new THREE.Vector3;a=Number.MAX_VALUE;l=Math.abs(e[0].x);n=Math.abs(e[0].y);p=Math.abs(e[0].z);l<=a&&(a=l,d.set(1,0,0));n<=a&&(a=n,d.set(0,1,0));p<=a&&d.set(0,0,1);h.crossVectors(e[0],d).normalize();f[0].crossVectors(e[0],
 h);g[0].crossVectors(e[0],f[0]);for(l=1;l<b;l++)f[l]=f[l-1].clone(),g[l]=g[l-1].clone(),h.crossVectors(e[l-1],e[l]),1E-4<h.length()&&(h.normalize(),d=Math.acos(THREE.Math.clamp(e[l-1].dot(e[l]),-1,1)),f[l].applyMatrix4(k.makeRotationAxis(h,d))),g[l].crossVectors(e[l],f[l]);if(c)for(d=Math.acos(THREE.Math.clamp(f[0].dot(f[b-1]),-1,1)),d/=b-1,0<e[0].dot(h.crossVectors(f[0],f[b-1]))&&(d=-d),l=1;l<b;l++)f[l].applyMatrix4(k.makeRotationAxis(e[l],d*l)),g[l].crossVectors(e[l],f[l])};
 h);g[0].crossVectors(e[0],f[0]);for(l=1;l<b;l++)f[l]=f[l-1].clone(),g[l]=g[l-1].clone(),h.crossVectors(e[l-1],e[l]),1E-4<h.length()&&(h.normalize(),d=Math.acos(THREE.Math.clamp(e[l-1].dot(e[l]),-1,1)),f[l].applyMatrix4(k.makeRotationAxis(h,d))),g[l].crossVectors(e[l],f[l]);if(c)for(d=Math.acos(THREE.Math.clamp(f[0].dot(f[b-1]),-1,1)),d/=b-1,0<e[0].dot(h.crossVectors(f[0],f[b-1]))&&(d=-d),l=1;l<b;l++)f[l].applyMatrix4(k.makeRotationAxis(e[l],d*l)),g[l].crossVectors(e[l],f[l])};
 THREE.PolyhedronGeometry=function(a,b,c,d){function e(a){var b=a.normalize().clone();b.index=k.vertices.push(b)-1;var c=Math.atan2(a.z,-a.x)/2/Math.PI+.5;a=Math.atan2(-a.y,Math.sqrt(a.x*a.x+a.z*a.z))/Math.PI+.5;b.uv=new THREE.Vector2(c,1-a);return b}function f(a,b,c){var d=new THREE.Face3(a.index,b.index,c.index,[a.clone(),b.clone(),c.clone()]);k.faces.push(d);u.copy(a).add(b).add(c).divideScalar(3);d=Math.atan2(u.z,-u.x);k.faceVertexUvs[0].push([h(a.uv,a,d),h(b.uv,b,d),h(c.uv,c,d)])}function g(a,
 THREE.PolyhedronGeometry=function(a,b,c,d){function e(a){var b=a.normalize().clone();b.index=k.vertices.push(b)-1;var c=Math.atan2(a.z,-a.x)/2/Math.PI+.5;a=Math.atan2(-a.y,Math.sqrt(a.x*a.x+a.z*a.z))/Math.PI+.5;b.uv=new THREE.Vector2(c,1-a);return b}function f(a,b,c){var d=new THREE.Face3(a.index,b.index,c.index,[a.clone(),b.clone(),c.clone()]);k.faces.push(d);u.copy(a).add(b).add(c).divideScalar(3);d=Math.atan2(u.z,-u.x);k.faceVertexUvs[0].push([h(a.uv,a,d),h(b.uv,b,d),h(c.uv,c,d)])}function g(a,
 b){for(var c=Math.pow(2,b),d=e(k.vertices[a.a]),g=e(k.vertices[a.b]),h=e(k.vertices[a.c]),l=[],m=0;m<=c;m++){l[m]=[];for(var n=e(d.clone().lerp(h,m/c)),p=e(g.clone().lerp(h,m/c)),q=c-m,s=0;s<=q;s++)l[m][s]=0===s&&m===c?n:e(n.clone().lerp(p,s/q))}for(m=0;m<c;m++)for(s=0;s<2*(c-m)-1;s++)d=Math.floor(s/2),0===s%2?f(l[m][d+1],l[m+1][d],l[m][d]):f(l[m][d+1],l[m+1][d+1],l[m+1][d])}function h(a,b,c){0>c&&1===a.x&&(a=new THREE.Vector2(a.x-1,a.y));0===b.x&&0===b.z&&(a=new THREE.Vector2(c/2/Math.PI+.5,a.y));
 b){for(var c=Math.pow(2,b),d=e(k.vertices[a.a]),g=e(k.vertices[a.b]),h=e(k.vertices[a.c]),l=[],m=0;m<=c;m++){l[m]=[];for(var n=e(d.clone().lerp(h,m/c)),p=e(g.clone().lerp(h,m/c)),q=c-m,s=0;s<=q;s++)l[m][s]=0===s&&m===c?n:e(n.clone().lerp(p,s/q))}for(m=0;m<c;m++)for(s=0;s<2*(c-m)-1;s++)d=Math.floor(s/2),0===s%2?f(l[m][d+1],l[m+1][d],l[m][d]):f(l[m][d+1],l[m+1][d+1],l[m+1][d])}function h(a,b,c){0>c&&1===a.x&&(a=new THREE.Vector2(a.x-1,a.y));0===b.x&&0===b.z&&(a=new THREE.Vector2(c/2/Math.PI+.5,a.y));
-return a.clone()}THREE.Geometry.call(this);this.type="PolyhedronGeometry";this.parameters={vertices:a,indices:b,radius:c,detail:d};c=c||1;d=d||0;for(var k=this,l=0,n=a.length;l<n;l+=3)e(new THREE.Vector3(a[l],a[l+1],a[l+2]));a=this.vertices;for(var p=[],m=l=0,n=b.length;l<n;l+=3,m++){var q=a[b[l]],t=a[b[l+1]],s=a[b[l+2]];p[m]=new THREE.Face3(q.index,t.index,s.index,[q.clone(),t.clone(),s.clone()])}for(var u=new THREE.Vector3,l=0,n=p.length;l<n;l++)g(p[l],d);l=0;for(n=this.faceVertexUvs[0].length;l<
+return a.clone()}THREE.Geometry.call(this);this.type="PolyhedronGeometry";this.parameters={vertices:a,indices:b,radius:c,detail:d};c=c||1;d=d||0;for(var k=this,l=0,n=a.length;l<n;l+=3)e(new THREE.Vector3(a[l],a[l+1],a[l+2]));a=this.vertices;for(var p=[],m=l=0,n=b.length;l<n;l+=3,m++){var q=a[b[l]],s=a[b[l+1]],t=a[b[l+2]];p[m]=new THREE.Face3(q.index,s.index,t.index,[q.clone(),s.clone(),t.clone()])}for(var u=new THREE.Vector3,l=0,n=p.length;l<n;l++)g(p[l],d);l=0;for(n=this.faceVertexUvs[0].length;l<
 n;l++)b=this.faceVertexUvs[0][l],d=b[0].x,a=b[1].x,p=b[2].x,m=Math.max(d,Math.max(a,p)),q=Math.min(d,Math.min(a,p)),.9<m&&.1>q&&(.2>d&&(b[0].x+=1),.2>a&&(b[1].x+=1),.2>p&&(b[2].x+=1));l=0;for(n=this.vertices.length;l<n;l++)this.vertices[l].multiplyScalar(c);this.mergeVertices();this.computeFaceNormals();this.boundingSphere=new THREE.Sphere(new THREE.Vector3,c)};THREE.PolyhedronGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.PolyhedronGeometry.prototype.constructor=THREE.PolyhedronGeometry;
 n;l++)b=this.faceVertexUvs[0][l],d=b[0].x,a=b[1].x,p=b[2].x,m=Math.max(d,Math.max(a,p)),q=Math.min(d,Math.min(a,p)),.9<m&&.1>q&&(.2>d&&(b[0].x+=1),.2>a&&(b[1].x+=1),.2>p&&(b[2].x+=1));l=0;for(n=this.vertices.length;l<n;l++)this.vertices[l].multiplyScalar(c);this.mergeVertices();this.computeFaceNormals();this.boundingSphere=new THREE.Sphere(new THREE.Vector3,c)};THREE.PolyhedronGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.PolyhedronGeometry.prototype.constructor=THREE.PolyhedronGeometry;
 THREE.DodecahedronGeometry=function(a,b){this.parameters={radius:a,detail:b};var c=(1+Math.sqrt(5))/2,d=1/c;THREE.PolyhedronGeometry.call(this,[-1,-1,-1,-1,-1,1,-1,1,-1,-1,1,1,1,-1,-1,1,-1,1,1,1,-1,1,1,1,0,-d,-c,0,-d,c,0,d,-c,0,d,c,-d,-c,0,-d,c,0,d,-c,0,d,c,0,-c,0,-d,c,0,-d,-c,0,d,c,0,d],[3,11,7,3,7,15,3,15,13,7,19,17,7,17,6,7,6,15,17,4,8,17,8,10,17,10,6,8,0,16,8,16,2,8,2,10,0,12,1,0,1,18,0,18,16,6,10,2,6,2,13,6,13,15,2,16,18,2,18,3,2,3,13,18,1,9,18,9,11,18,11,3,4,14,12,4,12,0,4,0,8,11,9,5,11,5,19,
 THREE.DodecahedronGeometry=function(a,b){this.parameters={radius:a,detail:b};var c=(1+Math.sqrt(5))/2,d=1/c;THREE.PolyhedronGeometry.call(this,[-1,-1,-1,-1,-1,1,-1,1,-1,-1,1,1,1,-1,-1,1,-1,1,1,1,-1,1,1,1,0,-d,-c,0,-d,c,0,d,-c,0,d,c,-d,-c,0,-d,c,0,d,-c,0,d,c,0,-c,0,-d,c,0,-d,-c,0,d,c,0,d],[3,11,7,3,7,15,3,15,13,7,19,17,7,17,6,7,6,15,17,4,8,17,8,10,17,10,6,8,0,16,8,16,2,8,2,10,0,12,1,0,1,18,0,18,16,6,10,2,6,2,13,6,13,15,2,16,18,2,18,3,2,3,13,18,1,9,18,9,11,18,11,3,4,14,12,4,12,0,4,0,8,11,9,5,11,5,19,
 11,19,7,19,5,14,19,14,4,19,4,17,1,12,14,1,14,5,1,5,9],a,b)};THREE.DodecahedronGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.DodecahedronGeometry.prototype.constructor=THREE.DodecahedronGeometry;
 11,19,7,19,5,14,19,14,4,19,4,17,1,12,14,1,14,5,1,5,9],a,b)};THREE.DodecahedronGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.DodecahedronGeometry.prototype.constructor=THREE.DodecahedronGeometry;
 THREE.IcosahedronGeometry=function(a,b){var c=(1+Math.sqrt(5))/2;THREE.PolyhedronGeometry.call(this,[-1,c,0,1,c,0,-1,-c,0,1,-c,0,0,-1,c,0,1,c,0,-1,-c,0,1,-c,c,0,-1,c,0,1,-c,0,-1,-c,0,1],[0,11,5,0,5,1,0,1,7,0,7,10,0,10,11,1,5,9,5,11,4,11,10,2,10,7,6,7,1,8,3,9,4,3,4,2,3,2,6,3,6,8,3,8,9,4,9,5,2,4,11,6,2,10,8,6,7,9,8,1],a,b);this.type="IcosahedronGeometry";this.parameters={radius:a,detail:b}};THREE.IcosahedronGeometry.prototype=Object.create(THREE.Geometry.prototype);
 THREE.IcosahedronGeometry=function(a,b){var c=(1+Math.sqrt(5))/2;THREE.PolyhedronGeometry.call(this,[-1,c,0,1,c,0,-1,-c,0,1,-c,0,0,-1,c,0,1,c,0,-1,-c,0,1,-c,c,0,-1,c,0,1,-c,0,-1,-c,0,1],[0,11,5,0,5,1,0,1,7,0,7,10,0,10,11,1,5,9,5,11,4,11,10,2,10,7,6,7,1,8,3,9,4,3,4,2,3,2,6,3,6,8,3,8,9,4,9,5,2,4,11,6,2,10,8,6,7,9,8,1],a,b);this.type="IcosahedronGeometry";this.parameters={radius:a,detail:b}};THREE.IcosahedronGeometry.prototype=Object.create(THREE.Geometry.prototype);
 THREE.IcosahedronGeometry.prototype.constructor=THREE.IcosahedronGeometry;THREE.OctahedronGeometry=function(a,b){this.parameters={radius:a,detail:b};THREE.PolyhedronGeometry.call(this,[1,0,0,-1,0,0,0,1,0,0,-1,0,0,0,1,0,0,-1],[0,2,4,0,4,3,0,3,5,0,5,2,1,2,5,1,5,3,1,3,4,1,4,2],a,b);this.type="OctahedronGeometry";this.parameters={radius:a,detail:b}};THREE.OctahedronGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.OctahedronGeometry.prototype.constructor=THREE.OctahedronGeometry;
 THREE.IcosahedronGeometry.prototype.constructor=THREE.IcosahedronGeometry;THREE.OctahedronGeometry=function(a,b){this.parameters={radius:a,detail:b};THREE.PolyhedronGeometry.call(this,[1,0,0,-1,0,0,0,1,0,0,-1,0,0,0,1,0,0,-1],[0,2,4,0,4,3,0,3,5,0,5,2,1,2,5,1,5,3,1,3,4,1,4,2],a,b);this.type="OctahedronGeometry";this.parameters={radius:a,detail:b}};THREE.OctahedronGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.OctahedronGeometry.prototype.constructor=THREE.OctahedronGeometry;
 THREE.TetrahedronGeometry=function(a,b){THREE.PolyhedronGeometry.call(this,[1,1,1,-1,-1,1,-1,1,-1,1,-1,-1],[2,1,0,0,3,2,1,3,0,2,3,1],a,b);this.type="TetrahedronGeometry";this.parameters={radius:a,detail:b}};THREE.TetrahedronGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.TetrahedronGeometry.prototype.constructor=THREE.TetrahedronGeometry;
 THREE.TetrahedronGeometry=function(a,b){THREE.PolyhedronGeometry.call(this,[1,1,1,-1,-1,1,-1,1,-1,1,-1,-1],[2,1,0,0,3,2,1,3,0,2,3,1],a,b);this.type="TetrahedronGeometry";this.parameters={radius:a,detail:b}};THREE.TetrahedronGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.TetrahedronGeometry.prototype.constructor=THREE.TetrahedronGeometry;
-THREE.ParametricGeometry=function(a,b,c){THREE.Geometry.call(this);this.type="ParametricGeometry";this.parameters={func:a,slices:b,stacks:c};var d=this.vertices,e=this.faces,f=this.faceVertexUvs[0],g,h,k,l,n=b+1;for(g=0;g<=c;g++)for(l=g/c,h=0;h<=b;h++)k=h/b,k=a(k,l),d.push(k);var p,m,q,t;for(g=0;g<c;g++)for(h=0;h<b;h++)a=g*n+h,d=g*n+h+1,l=(g+1)*n+h+1,k=(g+1)*n+h,p=new THREE.Vector2(h/b,g/c),m=new THREE.Vector2((h+1)/b,g/c),q=new THREE.Vector2((h+1)/b,(g+1)/c),t=new THREE.Vector2(h/b,(g+1)/c),e.push(new THREE.Face3(a,
-d,k)),f.push([p,m,t]),e.push(new THREE.Face3(d,l,k)),f.push([m.clone(),q,t.clone()]);this.computeFaceNormals();this.computeVertexNormals()};THREE.ParametricGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.ParametricGeometry.prototype.constructor=THREE.ParametricGeometry;
+THREE.ParametricGeometry=function(a,b,c){THREE.Geometry.call(this);this.type="ParametricGeometry";this.parameters={func:a,slices:b,stacks:c};var d=this.vertices,e=this.faces,f=this.faceVertexUvs[0],g,h,k,l,n=b+1;for(g=0;g<=c;g++)for(l=g/c,h=0;h<=b;h++)k=h/b,k=a(k,l),d.push(k);var p,m,q,s;for(g=0;g<c;g++)for(h=0;h<b;h++)a=g*n+h,d=g*n+h+1,l=(g+1)*n+h+1,k=(g+1)*n+h,p=new THREE.Vector2(h/b,g/c),m=new THREE.Vector2((h+1)/b,g/c),q=new THREE.Vector2((h+1)/b,(g+1)/c),s=new THREE.Vector2(h/b,(g+1)/c),e.push(new THREE.Face3(a,
+d,k)),f.push([p,m,s]),e.push(new THREE.Face3(d,l,k)),f.push([m.clone(),q,s.clone()]);this.computeFaceNormals();this.computeVertexNormals()};THREE.ParametricGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.ParametricGeometry.prototype.constructor=THREE.ParametricGeometry;
 THREE.WireframeGeometry=function(a){THREE.BufferGeometry.call(this);var b=[0,0],c={},d=function(a,b){return a-b},e=["a","b","c"];if(a instanceof THREE.Geometry){var f=a.vertices,g=a.faces,h=0,k=new Uint32Array(6*g.length);a=0;for(var l=g.length;a<l;a++)for(var n=g[a],p=0;3>p;p++){b[0]=n[e[p]];b[1]=n[e[(p+1)%3]];b.sort(d);var m=b.toString();void 0===c[m]&&(k[2*h]=b[0],k[2*h+1]=b[1],c[m]=!0,h++)}b=new Float32Array(6*h);a=0;for(l=h;a<l;a++)for(p=0;2>p;p++)h=f[k[2*a+p]],e=6*a+3*p,b[e+0]=h.x,b[e+1]=h.y,
 THREE.WireframeGeometry=function(a){THREE.BufferGeometry.call(this);var b=[0,0],c={},d=function(a,b){return a-b},e=["a","b","c"];if(a instanceof THREE.Geometry){var f=a.vertices,g=a.faces,h=0,k=new Uint32Array(6*g.length);a=0;for(var l=g.length;a<l;a++)for(var n=g[a],p=0;3>p;p++){b[0]=n[e[p]];b[1]=n[e[(p+1)%3]];b.sort(d);var m=b.toString();void 0===c[m]&&(k[2*h]=b[0],k[2*h+1]=b[1],c[m]=!0,h++)}b=new Float32Array(6*h);a=0;for(l=h;a<l;a++)for(p=0;2>p;p++)h=f[k[2*a+p]],e=6*a+3*p,b[e+0]=h.x,b[e+1]=h.y,
-b[e+2]=h.z;this.addAttribute("position",new THREE.BufferAttribute(b,3))}else if(a instanceof THREE.BufferGeometry){if(void 0!==a.attributes.index){f=a.attributes.position;l=a.attributes.index.array;g=a.drawcalls;h=0;0===g.length&&(g=[{count:l.length,index:0,start:0}]);for(var k=new Uint32Array(2*l.length),n=0,q=g.length;n<q;++n){p=g[n].start;m=g[n].count;e=g[n].index;a=p;for(var t=p+m;a<t;a+=3)for(p=0;3>p;p++)b[0]=e+l[a+p],b[1]=e+l[a+(p+1)%3],b.sort(d),m=b.toString(),void 0===c[m]&&(k[2*h]=b[0],k[2*
+b[e+2]=h.z;this.addAttribute("position",new THREE.BufferAttribute(b,3))}else if(a instanceof THREE.BufferGeometry){if(void 0!==a.attributes.index){f=a.attributes.position;l=a.attributes.index.array;g=a.drawcalls;h=0;0===g.length&&(g=[{count:l.length,index:0,start:0}]);for(var k=new Uint32Array(2*l.length),n=0,q=g.length;n<q;++n){p=g[n].start;m=g[n].count;e=g[n].index;a=p;for(var s=p+m;a<s;a+=3)for(p=0;3>p;p++)b[0]=e+l[a+p],b[1]=e+l[a+(p+1)%3],b.sort(d),m=b.toString(),void 0===c[m]&&(k[2*h]=b[0],k[2*
 h+1]=b[1],c[m]=!0,h++)}b=new Float32Array(6*h);a=0;for(l=h;a<l;a++)for(p=0;2>p;p++)e=6*a+3*p,h=k[2*a+p],b[e+0]=f.getX(h),b[e+1]=f.getY(h),b[e+2]=f.getZ(h)}else for(f=a.attributes.position.array,h=f.length/3,k=h/3,b=new Float32Array(6*h),a=0,l=k;a<l;a++)for(p=0;3>p;p++)e=18*a+6*p,k=9*a+3*p,b[e+0]=f[k],b[e+1]=f[k+1],b[e+2]=f[k+2],h=9*a+(p+1)%3*3,b[e+3]=f[h],b[e+4]=f[h+1],b[e+5]=f[h+2];this.addAttribute("position",new THREE.BufferAttribute(b,3))}};THREE.WireframeGeometry.prototype=Object.create(THREE.BufferGeometry.prototype);
 h+1]=b[1],c[m]=!0,h++)}b=new Float32Array(6*h);a=0;for(l=h;a<l;a++)for(p=0;2>p;p++)e=6*a+3*p,h=k[2*a+p],b[e+0]=f.getX(h),b[e+1]=f.getY(h),b[e+2]=f.getZ(h)}else for(f=a.attributes.position.array,h=f.length/3,k=h/3,b=new Float32Array(6*h),a=0,l=k;a<l;a++)for(p=0;3>p;p++)e=18*a+6*p,k=9*a+3*p,b[e+0]=f[k],b[e+1]=f[k+1],b[e+2]=f[k+2],h=9*a+(p+1)%3*3,b[e+3]=f[h],b[e+4]=f[h+1],b[e+5]=f[h+2];this.addAttribute("position",new THREE.BufferAttribute(b,3))}};THREE.WireframeGeometry.prototype=Object.create(THREE.BufferGeometry.prototype);
 THREE.WireframeGeometry.prototype.constructor=THREE.WireframeGeometry;THREE.AxisHelper=function(a){a=a||1;var b=new Float32Array([0,0,0,a,0,0,0,0,0,0,a,0,0,0,0,0,0,a]),c=new Float32Array([1,0,0,1,.6,0,0,1,0,.6,1,0,0,0,1,0,.6,1]);a=new THREE.BufferGeometry;a.addAttribute("position",new THREE.BufferAttribute(b,3));a.addAttribute("color",new THREE.BufferAttribute(c,3));b=new THREE.LineBasicMaterial({vertexColors:THREE.VertexColors});THREE.LineSegments.call(this,a,b)};THREE.AxisHelper.prototype=Object.create(THREE.LineSegments.prototype);
 THREE.WireframeGeometry.prototype.constructor=THREE.WireframeGeometry;THREE.AxisHelper=function(a){a=a||1;var b=new Float32Array([0,0,0,a,0,0,0,0,0,0,a,0,0,0,0,0,0,a]),c=new Float32Array([1,0,0,1,.6,0,0,1,0,.6,1,0,0,0,1,0,.6,1]);a=new THREE.BufferGeometry;a.addAttribute("position",new THREE.BufferAttribute(b,3));a.addAttribute("color",new THREE.BufferAttribute(c,3));b=new THREE.LineBasicMaterial({vertexColors:THREE.VertexColors});THREE.LineSegments.call(this,a,b)};THREE.AxisHelper.prototype=Object.create(THREE.LineSegments.prototype);
 THREE.AxisHelper.prototype.constructor=THREE.AxisHelper;
 THREE.AxisHelper.prototype.constructor=THREE.AxisHelper;

+ 2 - 2
docs/api/CONTRIBUTING.md

@@ -2,6 +2,6 @@ Contributing to the documentation
 =================================
 =================================
 
 
 - To link to the page for `ClassName`, use `[page:ClassName link title]` (or just `[page:ClassName]`). Use `[page:ClassName.memberName]` to link to a class member (a property or method) called `memberName` on the page for `ClassName`. You can write `[page:.memberName]` to link to a property or method called `memberName` on the same page.
 - To link to the page for `ClassName`, use `[page:ClassName link title]` (or just `[page:ClassName]`). Use `[page:ClassName.memberName]` to link to a class member (a property or method) called `memberName` on the page for `ClassName`. You can write `[page:.memberName]` to link to a property or method called `memberName` on the same page.
-- Use `[example:exampleName title]` (ot just `[example:exampleName]`) to link to the example `threejs.org/examples/#exampleName`.
+- Use `[example:exampleName title]` (not just `[example:exampleName]`) to link to the example `threejs.org/examples/#exampleName`.
 - Document a property by writing `<h3>[property:TypeName propertyName]</h3>`.
 - Document a property by writing `<h3>[property:TypeName propertyName]</h3>`.
-- Document a method using `<h3>[method:ReturnType methodName]</h3>`.
+- Document a method using `<h3>[method:ReturnType methodName]</h3>`.

+ 15 - 0
docs/api/cameras/Camera.html

@@ -34,6 +34,14 @@
 
 
 
 
 		<h2>Methods</h2>
 		<h2>Methods</h2>
+		
+		<h3>[method:Vector3 getWorldDirection]([page:Vector3 vector])</h3>
+		<div>
+		vector — (optional)<br />
+		<br />
+		It returns a vector representing the direction in which the camera is looking, in world space.
+		</div>
+		
 
 
 		<h3>[method:null lookAt]( [page:Vector3 vector] )</h3>
 		<h3>[method:null lookAt]( [page:Vector3 vector] )</h3>
 		<div>
 		<div>
@@ -41,6 +49,13 @@
 		<br />
 		<br />
 		This makes the camera look at the vector position in the global space as long as the parent of this camera is the scene or at position (0,0,0).
 		This makes the camera look at the vector position in the global space as long as the parent of this camera is the scene or at position (0,0,0).
 		</div>
 		</div>
+		
+		<h3>[method:Camera clone]( [page:Camera camera] )</h3>
+		<div>
+		camera — camera to clone<br />
+		<br />
+		It returns a clone of camera.
+		</div>
 
 
 
 
 		<h2>Source</h2>
 		<h2>Source</h2>

+ 1 - 1
docs/api/cameras/CubeCamera.html

@@ -17,7 +17,7 @@
 		
 		
 		<div>[example:webgl_materials_cubemap_dynamic materials / cubemap / dynamic ]</div>
 		<div>[example:webgl_materials_cubemap_dynamic materials / cubemap / dynamic ]</div>
 		<div>[example:webgl_materials_cubemap_dynamic2 materials / cubemap / dynamic2 ]</div>
 		<div>[example:webgl_materials_cubemap_dynamic2 materials / cubemap / dynamic2 ]</div>
-		<div>[example:webgl_materials_cubemap_dynamic2 shading / physical ]</div>
+		<div>[example:webgl_shading_physical shading / physical ]</div>
 		
 		
 		<code>//Create cube camera
 		<code>//Create cube camera
 		var cubeCamera = new THREE.CubeCamera( 1, 100000, 128 );
 		var cubeCamera = new THREE.CubeCamera( 1, 100000, 128 );

+ 30 - 1
docs/api/cameras/OrthographicCamera.html

@@ -15,7 +15,21 @@
 
 
 
 
 		<h2>Example</h2>
 		<h2>Example</h2>
-
+		
+		<div>[example:canvas_camera_orthographic camera / orthographic ]</div>
+		<div>[example:canvas_camera_orthographic2 camera / orthographic2 ]</div>
+		<div>[example:webgl_camera camera ]</div>
+		<div>[example:webgl_interactive_cubes_ortho interactive / cubes / ortho ]</div>
+		<div>[example:webgl_materials_cubemap_dynamic materials / cubemap / dynamic ]</div>
+		<div>[example:webgl_materials_normaldisplacementmap materials / normaldisplacementmap ]</div>
+		<div>[example:webgl_postprocessing_advanced postprocessing / advanced ]</div>
+		<div>[example:webgl_postprocessing_dof2 postprocessing / dof2 ]</div>
+		<div>[example:webgl_postprocessing_godrays postprocessing / godrays ]</div>
+		<div>[example:webgl_rtt rtt ]</div>
+		<div>[example:webgl_shaders_tonemapping shaders / tonemapping ]</div>
+		<div>[example:webgl_shadowmap shadowmap ]</div>
+		<div>[example:webgl_terrain_dynamic terrain / dynamic ]</div>
+		
 		<code>var camera = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, 1, 1000 );
 		<code>var camera = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, 1, 1000 );
 scene.add( camera );</code>
 scene.add( camera );</code>
 
 
@@ -36,6 +50,9 @@ scene.add( camera );</code>
 
 
 		<h2>Properties</h2>
 		<h2>Properties</h2>
 
 
+		<h3>[property:number zoom]</h3>
+		<div>Gets or sets the zoom factor of the camera. </div>
+		
 		<h3>[property:Float left]</h3>
 		<h3>[property:Float left]</h3>
 		<div>Camera frustum left plane.</div>
 		<div>Camera frustum left plane.</div>
 
 
@@ -61,6 +78,18 @@ scene.add( camera );</code>
 		<div>
 		<div>
 		Updates the camera projection matrix. Must be called after change of parameters.
 		Updates the camera projection matrix. Must be called after change of parameters.
 		</div>
 		</div>
+		
+		<h3>[method:OrthographicCamera clone]()</h3>
+		<div>
+		<br />
+		It returns a clone of OrthographicCamera.
+		</div>
+
+		
+		<h3>[method:JSON toJSON]()</h3>
+		<div>
+		Return camera data in JSON format.
+		</div>
 
 
 
 
 		<h2>Source</h2>
 		<h2>Source</h2>

+ 23 - 2
docs/api/cameras/PerspectiveCamera.html

@@ -15,7 +15,15 @@
 
 
 
 
 		<h2>Example</h2>
 		<h2>Example</h2>
-
+		
+		<div>[example:canvas_effects_stereo effects / stereo ]</div>
+		<div>[example:canvas_geometry_birds geometry / birds ]</div>
+		<div>[example:canvas_geometry_cube geometry / cube ]</div>
+		<div>[example:webgl_animation_skinning_blending animation / skinning / blending ]</div>
+		<div>[example:webgl_animation_skinning_morph animation / skinning / blending ]</div>
+		<div>[example:webgl_interactive_cubes interactive / cubes ]</div>
+		<div>[example:webgl_loader_collada_skinning loader / collada / skinning ]</div>
+		
 		<code>var camera = new THREE.PerspectiveCamera( 45, width / height, 1, 1000 );
 		<code>var camera = new THREE.PerspectiveCamera( 45, width / height, 1, 1000 );
 scene.add( camera );</code>
 scene.add( camera );</code>
 
 
@@ -33,6 +41,9 @@ scene.add( camera );</code>
 
 
 		<h2>Properties</h2>
 		<h2>Properties</h2>
 
 
+		<h3>[property:number zoom]</h3>
+		<div>Gets or sets the zoom factor of the camera. </div>
+		
 		<h3>[property:Float fov]</h3>
 		<h3>[property:Float fov]</h3>
 		<div>Camera frustum vertical field of view, from bottom to top of view, in degrees.</div>
 		<div>Camera frustum vertical field of view, from bottom to top of view, in degrees.</div>
 
 
@@ -110,7 +121,17 @@ camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 1, w, h );
 		<div>
 		<div>
 		Updates the camera projection matrix. Must be called after change of parameters.
 		Updates the camera projection matrix. Must be called after change of parameters.
 		</div>
 		</div>
-
+		
+		<h3>[method:PerspectiveCamera clone]()</h3>
+		<div>
+		<br />
+		It returns a clone of PerspectiveCamera.
+		</div>
+		
+		<h3>[method:JSON toJSON]()</h3>
+		<div>
+		Return camera data in JSON format.
+		</div>
 
 
 		<h2>Source</h2>
 		<h2>Source</h2>
 
 

+ 1 - 1
docs/api/core/Object3D.html

@@ -66,7 +66,7 @@
 
 
 		<h3>[property:Vector3 up]</h3>
 		<h3>[property:Vector3 up]</h3>
 		<div>
 		<div>
-		Up direction.
+		Up direction. Default is THREE.Vector3( 0, 1, 0 ).
 		</div>
 		</div>
 
 
 		<h3>[property:Matrix4 matrix]</h3>
 		<h3>[property:Matrix4 matrix]</h3>

+ 14 - 2
docs/api/examples/cameras/CombinedCamera.html

@@ -16,7 +16,14 @@
  		Use this only if you do not wish to manage
  		Use this only if you do not wish to manage
  		both an Orthographic and Perspective Camera</div>
  		both an Orthographic and Perspective Camera</div>
 
 
-
+		<h2>Examples</h2>
+		
+		<div>[example:canvas_camera_orthographic2 camera / orthographic2 ]</div>
+		
+		<code>//Create combined camera
+		camera = new THREE.CombinedCamera( window.innerWidth / 2, window.innerHeight / 2, 70, 1, 1000, - 500, 1000 );
+		</code>
+		
 		<h2>Constructor</h2>
 		<h2>Constructor</h2>
 
 
 
 
@@ -79,6 +86,11 @@
 		Gets camera frustum far plane.
 		Gets camera frustum far plane.
 		</div> 
 		</div> 
 
 
+		<h3>[property:Matrix4 projectionMatrix]</h3>
+		<div>
+		This is the matrix which contains the projection.
+		</div>
+		
 		<h3>[property:OrthographicCamera cameraO]</h3>
 		<h3>[property:OrthographicCamera cameraO]</h3>
 		<div>
 		<div>
 		Gets or sets the internal OrthographicCamera used as camera.
 		Gets or sets the internal OrthographicCamera used as camera.
@@ -182,6 +194,6 @@
 
 
 		<h2>Source</h2>
 		<h2>Source</h2>
 
 
-		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+		[link:https://github.com/mrdoob/three.js/blob/master/examples/js/cameras/CombinedCamera.js examples/cameras/CombinedCamera.js]
 	</body>
 	</body>
 </html>
 </html>

+ 10 - 3
docs/api/extras/geometries/BoxGeometry.html

@@ -39,9 +39,16 @@
 
 
 		<h2>Properties</h2>
 		<h2>Properties</h2>
 
 
-		<div>
-		Each of the constructor parameters is accessible as a property of the same name. Any modification of these properties after instantiation does not change the geometry.
-		</div>
+		<h3>.parameters</h3>
+ 		<div>
+			<p>Using the above example code above as our basis:</p>
+			<code>
+				geometry.parameters; // outputs an object {width: 1, height: 1, depth: 1, widthSegments: undefined, heightSegments: undefined}
+				cube.geometry.parameters; // as above
+				cube.geometry.parameters.width; // === 1
+				cube.geometry.parameters.widthSegments // === undefined.
+			</code>
+ 		</div>
 
 
 		<h2>Source</h2>
 		<h2>Source</h2>
 
 

+ 9 - 9
docs/api/renderers/webgl/WebGLProgram.html

@@ -109,12 +109,6 @@
 
 
 		<h2>Properties</h2>
 		<h2>Properties</h2>
 
 
-		<h3>[property:Object uniforms]</h3>
-		<div></div> 
-
-		<h3>[property:Object attributes]</h3>
-		<div></div> 
-
 		<h3>[property:String id]</h3>
 		<h3>[property:String id]</h3>
 		<div></div> 
 		<div></div> 
 
 
@@ -133,11 +127,17 @@
 		<h3>[property:WebGLShader fragmentShader]</h3>
 		<h3>[property:WebGLShader fragmentShader]</h3>
 		<div></div> 
 		<div></div> 
 
 
-
 		<h2>Methods</h2>
 		<h2>Methods</h2>
 		
 		
-		<h3>none</h3>
-		<div></div>
+		<h3>[method:Object getUniforms]()</h3>
+		<div>
+		Returns a name-value mapping of all active uniform locations.
+		</div>
+
+		<h3>[method:Object getAttributes]()</h3>
+		<div>
+		Returns a name-value mapping of all active vertex attribute locations.
+		</div>
 
 
 		<h2>Source</h2>
 		<h2>Source</h2>
 
 

+ 1 - 1
docs/page.js

@@ -35,7 +35,7 @@ var onDocumentLoad = function ( event ) {
 	text = text.replace(/\*([\w|\d|\"|\-|\(][\w|\d|\ |\-|\/|\+|\-|\(|\)|\=|\,|\.\"]*[\w|\d|\"|\)]|\w)\*/gi, "<strong>$1</strong>" ); // *
 	text = text.replace(/\*([\w|\d|\"|\-|\(][\w|\d|\ |\-|\/|\+|\-|\(|\)|\=|\,|\.\"]*[\w|\d|\"|\)]|\w)\*/gi, "<strong>$1</strong>" ); // *
 
 
 	text = text.replace(/\[example:([\w\_]+)\]/gi, "[example:$1 $1]" ); // [example:name] to [example:name title]
 	text = text.replace(/\[example:([\w\_]+)\]/gi, "[example:$1 $1]" ); // [example:name] to [example:name title]
-	text = text.replace(/\[example:([\w\_]+) ([\w\:\/\.\-\_ \s]+)\]/gi, "<a href=\"../../../examples/#$1\"  target=\"_blank\">$2</a>" ); // [example:name title]
+	text = text.replace(/\[example:([\w\_]+) ([\w\:\/\.\-\_ \s]+)\]/gi, "<a href=\"../../../../examples/#$1\"  target=\"_blank\">$2</a>" ); // [example:name title]
 
 
 
 
 	document.body.innerHTML = text;
 	document.body.innerHTML = text;

+ 18 - 0
editor/index.html

@@ -47,6 +47,24 @@
 
 
 		<script src="js/libs/codemirror/mode/glsl.js"></script>
 		<script src="js/libs/codemirror/mode/glsl.js"></script>
 
 
+		<link rel="stylesheet" href="js/libs/codemirror/addon/dialog.css">
+		<link rel="stylesheet" href="js/libs/codemirror/addon/show-hint.css">
+		<link rel="stylesheet" href="js/libs/codemirror/addon/tern.css">
+		<script src="js/libs/codemirror/addon/dialog.js"></script>
+		<script src="js/libs/codemirror/addon/show-hint.js"></script>
+		<script src="js/libs/codemirror/addon/tern.js"></script>
+		<script src="js/libs/acorn/acorn.js"></script>
+		<script src="js/libs/acorn/acorn_loose.js"></script>
+		<script src="js/libs/acorn/walk.js"></script>
+		<script src="js/libs/ternjs/polyfill.js"></script>
+		<script src="js/libs/ternjs/signal.js"></script>
+		<script src="js/libs/ternjs/tern.js"></script>
+		<script src="js/libs/ternjs/def.js"></script>
+		<script src="js/libs/ternjs/comment.js"></script>
+		<script src="js/libs/ternjs/infer.js"></script>
+		<script src="js/libs/ternjs/doc_comment.js"></script>
+		<script src="js/libs/tern-threejs/threejs.js"></script>
+
 		<script src="js/libs/jszip.min.js"></script>
 		<script src="js/libs/jszip.min.js"></script>
 		<script src="js/libs/sortable.min.js"></script>
 		<script src="js/libs/sortable.min.js"></script>
 		<script src="js/libs/signals.min.js"></script>
 		<script src="js/libs/signals.min.js"></script>

+ 41 - 2
editor/js/Script.js

@@ -53,7 +53,10 @@ var Script = function ( editor ) {
 		matchBrackets: true,
 		matchBrackets: true,
 		indentWithTabs: true,
 		indentWithTabs: true,
 		tabSize: 4,
 		tabSize: 4,
-		indentUnit: 4
+		indentUnit: 4,
+		hintOptions: {
+			completeSingle: false
+		}
 	} );
 	} );
 	codemirror.setOption( 'theme', 'monokai' );
 	codemirror.setOption( 'theme', 'monokai' );
 	codemirror.on( 'change', function () {
 	codemirror.on( 'change', function () {
@@ -108,7 +111,6 @@ var Script = function ( editor ) {
 
 
 	} );
 	} );
 
 
-
 	// validate
 	// validate
 
 
 	var errorLines = [];
 	var errorLines = [];
@@ -223,6 +225,43 @@ var Script = function ( editor ) {
 
 
 	};
 	};
 
 
+	// tern js autocomplete
+
+	var server = new CodeMirror.TernServer( {
+		caseInsensitive: true,
+		plugins: { threejs: null }
+	} );
+
+	codemirror.setOption( 'extraKeys', {
+		'Ctrl-Space': function(cm) { server.complete(cm); },
+		'Ctrl-I': function(cm) { server.showType(cm); },
+		'Ctrl-O': function(cm) { server.showDocs(cm); },
+		'Alt-.': function(cm) { server.jumpToDef(cm); },
+		'Alt-,': function(cm) { server.jumpBack(cm); },
+		'Ctrl-Q': function(cm) { server.rename(cm); },
+		'Ctrl-.': function(cm) { server.selectName(cm); }
+	} );
+
+	codemirror.on( 'cursorActivity', function( cm ) {
+
+		if ( currentMode !== 'javascript' ) return;
+		server.updateArgHints( cm );
+
+	} );
+
+	codemirror.on( 'keypress', function( cm, kb ) {
+
+		if ( currentMode !== 'javascript' ) return;
+		var typed = String.fromCharCode( kb.which || kb.keyCode );
+		if ( /[\w\.]/.exec( typed ) ) {
+
+			server.complete( cm );
+
+		}
+
+	} );
+
+
 	//
 	//
 
 
 	signals.editorCleared.add( function () {
 	signals.editorCleared.add( function () {

+ 1 - 1
editor/js/Sidebar.Material.js

@@ -642,7 +642,7 @@ Sidebar.Material = function ( editor ) {
 			'emissive': materialEmissiveRow,
 			'emissive': materialEmissiveRow,
 			'specular': materialSpecularRow,
 			'specular': materialSpecularRow,
 			'shininess': materialShininessRow,
 			'shininess': materialShininessRow,
-			'program': materialProgramRow,
+			'vertexShader': materialProgramRow,
 			'vertexColors': materialVertexColorsRow,
 			'vertexColors': materialVertexColorsRow,
 			'skinning': materialSkinningRow,
 			'skinning': materialSkinningRow,
 			'map': materialMapRow,
 			'map': materialMapRow,

File diff suppressed because it is too large
+ 877 - 0
editor/js/libs/acorn/acorn.js


+ 1299 - 0
editor/js/libs/acorn/acorn_loose.js

@@ -0,0 +1,1299 @@
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}(g.acorn || (g.acorn = {})).loose = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
+"use strict";
+
+var _interopRequireWildcard = function (obj) { return obj && obj.__esModule ? obj : { "default": obj }; };
+
+exports.parse_dammit = parse_dammit;
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+// Acorn: Loose parser
+//
+// This module provides an alternative parser (`parse_dammit`) that
+// exposes that same interface as `parse`, but will try to parse
+// anything as JavaScript, repairing syntax error the best it can.
+// There are circumstances in which it will raise an error and give
+// up, but they are very rare. The resulting AST will be a mostly
+// valid JavaScript AST (as per the [Mozilla parser API][api], except
+// that:
+//
+// - Return outside functions is allowed
+//
+// - Label consistency (no conflicts, break only to existing labels)
+//   is not enforced.
+//
+// - Bogus Identifier nodes with a name of `"✖"` are inserted whenever
+//   the parser got too confused to return anything meaningful.
+//
+// [api]: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API
+//
+// The expected use for this is to *first* try `acorn.parse`, and only
+// if that fails switch to `parse_dammit`. The loose parser might
+// parse badly indented code incorrectly, so **don't** use it as
+// your default parser.
+//
+// Quite a lot of acorn.js is duplicated here. The alternative was to
+// add a *lot* of extra cruft to that file, making it less readable
+// and slower. Copying and editing the code allowed me to make
+// invasive changes and simplifications without creating a complicated
+// tangle.
+
+var acorn = _interopRequireWildcard(require(".."));
+
+var _state = require("./state");
+
+var LooseParser = _state.LooseParser;
+
+require("./tokenize");
+
+require("./parseutil");
+
+require("./statement");
+
+require("./expression");
+
+exports.LooseParser = _state.LooseParser;
+
+acorn.defaultOptions.tabSize = 4;
+
+function parse_dammit(input, options) {
+  var p = new LooseParser(input, options);
+  p.next();
+  return p.parseTopLevel();
+}
+
+acorn.parse_dammit = parse_dammit;
+acorn.LooseParser = LooseParser;
+
+},{"..":2,"./expression":3,"./parseutil":4,"./state":5,"./statement":6,"./tokenize":7}],2:[function(require,module,exports){
+"use strict";
+
+module.exports = typeof window != "undefined" ? window.acorn : require(("suppress", "./acorn"));
+
+},{}],3:[function(require,module,exports){
+"use strict";
+
+var LooseParser = require("./state").LooseParser;
+
+var isDummy = require("./parseutil").isDummy;
+
+var tt = require("..").tokTypes;
+
+var lp = LooseParser.prototype;
+
+lp.checkLVal = function (expr) {
+  if (!expr) return expr;
+  switch (expr.type) {
+    case "Identifier":
+    case "MemberExpression":
+    case "ObjectPattern":
+    case "ArrayPattern":
+    case "RestElement":
+    case "AssignmentPattern":
+      return expr;
+
+    default:
+      return this.dummyIdent();
+  }
+};
+
+lp.parseExpression = function (noIn) {
+  var start = this.storeCurrentPos();
+  var expr = this.parseMaybeAssign(noIn);
+  if (this.tok.type === tt.comma) {
+    var node = this.startNodeAt(start);
+    node.expressions = [expr];
+    while (this.eat(tt.comma)) node.expressions.push(this.parseMaybeAssign(noIn));
+    return this.finishNode(node, "SequenceExpression");
+  }
+  return expr;
+};
+
+lp.parseParenExpression = function () {
+  this.pushCx();
+  this.expect(tt.parenL);
+  var val = this.parseExpression();
+  this.popCx();
+  this.expect(tt.parenR);
+  return val;
+};
+
+lp.parseMaybeAssign = function (noIn) {
+  var start = this.storeCurrentPos();
+  var left = this.parseMaybeConditional(noIn);
+  if (this.tok.type.isAssign) {
+    var node = this.startNodeAt(start);
+    node.operator = this.tok.value;
+    node.left = this.tok.type === tt.eq ? this.toAssignable(left) : this.checkLVal(left);
+    this.next();
+    node.right = this.parseMaybeAssign(noIn);
+    return this.finishNode(node, "AssignmentExpression");
+  }
+  return left;
+};
+
+lp.parseMaybeConditional = function (noIn) {
+  var start = this.storeCurrentPos();
+  var expr = this.parseExprOps(noIn);
+  if (this.eat(tt.question)) {
+    var node = this.startNodeAt(start);
+    node.test = expr;
+    node.consequent = this.parseMaybeAssign();
+    node.alternate = this.expect(tt.colon) ? this.parseMaybeAssign(noIn) : this.dummyIdent();
+    return this.finishNode(node, "ConditionalExpression");
+  }
+  return expr;
+};
+
+lp.parseExprOps = function (noIn) {
+  var start = this.storeCurrentPos();
+  var indent = this.curIndent,
+      line = this.curLineStart;
+  return this.parseExprOp(this.parseMaybeUnary(noIn), start, -1, noIn, indent, line);
+};
+
+lp.parseExprOp = function (left, start, minPrec, noIn, indent, line) {
+  if (this.curLineStart != line && this.curIndent < indent && this.tokenStartsLine()) return left;
+  var prec = this.tok.type.binop;
+  if (prec != null && (!noIn || this.tok.type !== tt._in)) {
+    if (prec > minPrec) {
+      var node = this.startNodeAt(start);
+      node.left = left;
+      node.operator = this.tok.value;
+      this.next();
+      if (this.curLineStart != line && this.curIndent < indent && this.tokenStartsLine()) {
+        node.right = this.dummyIdent();
+      } else {
+        var rightStart = this.storeCurrentPos();
+        node.right = this.parseExprOp(this.parseMaybeUnary(noIn), rightStart, prec, noIn, indent, line);
+      }
+      this.finishNode(node, /&&|\|\|/.test(node.operator) ? "LogicalExpression" : "BinaryExpression");
+      return this.parseExprOp(node, start, minPrec, noIn, indent, line);
+    }
+  }
+  return left;
+};
+
+lp.parseMaybeUnary = function (noIn) {
+  if (this.tok.type.prefix) {
+    var node = this.startNode(),
+        update = this.tok.type === tt.incDec;
+    node.operator = this.tok.value;
+    node.prefix = true;
+    this.next();
+    node.argument = this.parseMaybeUnary(noIn);
+    if (update) node.argument = this.checkLVal(node.argument);
+    return this.finishNode(node, update ? "UpdateExpression" : "UnaryExpression");
+  } else if (this.tok.type === tt.ellipsis) {
+    var node = this.startNode();
+    this.next();
+    node.argument = this.parseMaybeUnary(noIn);
+    return this.finishNode(node, "SpreadElement");
+  }
+  var start = this.storeCurrentPos();
+  var expr = this.parseExprSubscripts();
+  while (this.tok.type.postfix && !this.canInsertSemicolon()) {
+    var node = this.startNodeAt(start);
+    node.operator = this.tok.value;
+    node.prefix = false;
+    node.argument = this.checkLVal(expr);
+    this.next();
+    expr = this.finishNode(node, "UpdateExpression");
+  }
+  return expr;
+};
+
+lp.parseExprSubscripts = function () {
+  var start = this.storeCurrentPos();
+  return this.parseSubscripts(this.parseExprAtom(), start, false, this.curIndent, this.curLineStart);
+};
+
+lp.parseSubscripts = function (base, start, noCalls, startIndent, line) {
+  for (;;) {
+    if (this.curLineStart != line && this.curIndent <= startIndent && this.tokenStartsLine()) {
+      if (this.tok.type == tt.dot && this.curIndent == startIndent) --startIndent;else return base;
+    }
+
+    if (this.eat(tt.dot)) {
+      var node = this.startNodeAt(start);
+      node.object = base;
+      if (this.curLineStart != line && this.curIndent <= startIndent && this.tokenStartsLine()) node.property = this.dummyIdent();else node.property = this.parsePropertyAccessor() || this.dummyIdent();
+      node.computed = false;
+      base = this.finishNode(node, "MemberExpression");
+    } else if (this.tok.type == tt.bracketL) {
+      this.pushCx();
+      this.next();
+      var node = this.startNodeAt(start);
+      node.object = base;
+      node.property = this.parseExpression();
+      node.computed = true;
+      this.popCx();
+      this.expect(tt.bracketR);
+      base = this.finishNode(node, "MemberExpression");
+    } else if (!noCalls && this.tok.type == tt.parenL) {
+      this.pushCx();
+      var node = this.startNodeAt(start);
+      node.callee = base;
+      node.arguments = this.parseExprList(tt.parenR);
+      base = this.finishNode(node, "CallExpression");
+    } else if (this.tok.type == tt.backQuote) {
+      var node = this.startNodeAt(start);
+      node.tag = base;
+      node.quasi = this.parseTemplate();
+      base = this.finishNode(node, "TaggedTemplateExpression");
+    } else {
+      return base;
+    }
+  }
+};
+
+lp.parseExprAtom = function () {
+  var node = undefined;
+  switch (this.tok.type) {
+    case tt._this:
+    case tt._super:
+      var type = this.tok.type === tt._this ? "ThisExpression" : "Super";
+      node = this.startNode();
+      this.next();
+      return this.finishNode(node, type);
+
+    case tt.name:
+      var start = this.storeCurrentPos();
+      var id = this.parseIdent();
+      return this.eat(tt.arrow) ? this.parseArrowExpression(this.startNodeAt(start), [id]) : id;
+
+    case tt.regexp:
+      node = this.startNode();
+      var val = this.tok.value;
+      node.regex = { pattern: val.pattern, flags: val.flags };
+      node.value = val.value;
+      node.raw = this.input.slice(this.tok.start, this.tok.end);
+      this.next();
+      return this.finishNode(node, "Literal");
+
+    case tt.num:case tt.string:
+      node = this.startNode();
+      node.value = this.tok.value;
+      node.raw = this.input.slice(this.tok.start, this.tok.end);
+      this.next();
+      return this.finishNode(node, "Literal");
+
+    case tt._null:case tt._true:case tt._false:
+      node = this.startNode();
+      node.value = this.tok.type === tt._null ? null : this.tok.type === tt._true;
+      node.raw = this.tok.type.keyword;
+      this.next();
+      return this.finishNode(node, "Literal");
+
+    case tt.parenL:
+      var parenStart = this.storeCurrentPos();
+      this.next();
+      var inner = this.parseExpression();
+      this.expect(tt.parenR);
+      if (this.eat(tt.arrow)) {
+        return this.parseArrowExpression(this.startNodeAt(parenStart), inner.expressions || (isDummy(inner) ? [] : [inner]));
+      }
+      if (this.options.preserveParens) {
+        var par = this.startNodeAt(parenStart);
+        par.expression = inner;
+        inner = this.finishNode(par, "ParenthesizedExpression");
+      }
+      return inner;
+
+    case tt.bracketL:
+      node = this.startNode();
+      this.pushCx();
+      node.elements = this.parseExprList(tt.bracketR, true);
+      return this.finishNode(node, "ArrayExpression");
+
+    case tt.braceL:
+      return this.parseObj();
+
+    case tt._class:
+      return this.parseClass();
+
+    case tt._function:
+      node = this.startNode();
+      this.next();
+      return this.parseFunction(node, false);
+
+    case tt._new:
+      return this.parseNew();
+
+    case tt._yield:
+      node = this.startNode();
+      this.next();
+      if (this.semicolon() || this.canInsertSemicolon() || this.tok.type != tt.star && !this.tok.type.startsExpr) {
+        node.delegate = false;
+        node.argument = null;
+      } else {
+        node.delegate = this.eat(tt.star);
+        node.argument = this.parseMaybeAssign();
+      }
+      return this.finishNode(node, "YieldExpression");
+
+    case tt.backQuote:
+      return this.parseTemplate();
+
+    default:
+      return this.dummyIdent();
+  }
+};
+
+lp.parseNew = function () {
+  var node = this.startNode(),
+      startIndent = this.curIndent,
+      line = this.curLineStart;
+  var meta = this.parseIdent(true);
+  if (this.options.ecmaVersion >= 6 && this.eat(tt.dot)) {
+    node.meta = meta;
+    node.property = this.parseIdent(true);
+    return this.finishNode(node, "MetaProperty");
+  }
+  var start = this.storeCurrentPos();
+  node.callee = this.parseSubscripts(this.parseExprAtom(), start, true, startIndent, line);
+  if (this.tok.type == tt.parenL) {
+    this.pushCx();
+    node.arguments = this.parseExprList(tt.parenR);
+  } else {
+    node.arguments = [];
+  }
+  return this.finishNode(node, "NewExpression");
+};
+
+lp.parseTemplateElement = function () {
+  var elem = this.startNode();
+  elem.value = {
+    raw: this.input.slice(this.tok.start, this.tok.end),
+    cooked: this.tok.value
+  };
+  this.next();
+  elem.tail = this.tok.type === tt.backQuote;
+  return this.finishNode(elem, "TemplateElement");
+};
+
+lp.parseTemplate = function () {
+  var node = this.startNode();
+  this.next();
+  node.expressions = [];
+  var curElt = this.parseTemplateElement();
+  node.quasis = [curElt];
+  while (!curElt.tail) {
+    this.next();
+    node.expressions.push(this.parseExpression());
+    if (this.expect(tt.braceR)) {
+      curElt = this.parseTemplateElement();
+    } else {
+      curElt = this.startNode();
+      curElt.value = { cooked: "", raw: "" };
+      curElt.tail = true;
+    }
+    node.quasis.push(curElt);
+  }
+  this.expect(tt.backQuote);
+  return this.finishNode(node, "TemplateLiteral");
+};
+
+lp.parseObj = function () {
+  var node = this.startNode();
+  node.properties = [];
+  this.pushCx();
+  var indent = this.curIndent + 1,
+      line = this.curLineStart;
+  this.eat(tt.braceL);
+  if (this.curIndent + 1 < indent) {
+    indent = this.curIndent;line = this.curLineStart;
+  }
+  while (!this.closes(tt.braceR, indent, line)) {
+    var prop = this.startNode(),
+        isGenerator = undefined,
+        start = undefined;
+    if (this.options.ecmaVersion >= 6) {
+      start = this.storeCurrentPos();
+      prop.method = false;
+      prop.shorthand = false;
+      isGenerator = this.eat(tt.star);
+    }
+    this.parsePropertyName(prop);
+    if (isDummy(prop.key)) {
+      if (isDummy(this.parseMaybeAssign())) this.next();this.eat(tt.comma);continue;
+    }
+    if (this.eat(tt.colon)) {
+      prop.kind = "init";
+      prop.value = this.parseMaybeAssign();
+    } else if (this.options.ecmaVersion >= 6 && (this.tok.type === tt.parenL || this.tok.type === tt.braceL)) {
+      prop.kind = "init";
+      prop.method = true;
+      prop.value = this.parseMethod(isGenerator);
+    } else if (this.options.ecmaVersion >= 5 && prop.key.type === "Identifier" && !prop.computed && (prop.key.name === "get" || prop.key.name === "set") && (this.tok.type != tt.comma && this.tok.type != tt.braceR)) {
+      prop.kind = prop.key.name;
+      this.parsePropertyName(prop);
+      prop.value = this.parseMethod(false);
+    } else {
+      prop.kind = "init";
+      if (this.options.ecmaVersion >= 6) {
+        if (this.eat(tt.eq)) {
+          var assign = this.startNodeAt(start);
+          assign.operator = "=";
+          assign.left = prop.key;
+          assign.right = this.parseMaybeAssign();
+          prop.value = this.finishNode(assign, "AssignmentExpression");
+        } else {
+          prop.value = prop.key;
+        }
+      } else {
+        prop.value = this.dummyIdent();
+      }
+      prop.shorthand = true;
+    }
+    node.properties.push(this.finishNode(prop, "Property"));
+    this.eat(tt.comma);
+  }
+  this.popCx();
+  if (!this.eat(tt.braceR)) {
+    // If there is no closing brace, make the node span to the start
+    // of the next token (this is useful for Tern)
+    this.last.end = this.tok.start;
+    if (this.options.locations) this.last.loc.end = this.tok.loc.start;
+  }
+  return this.finishNode(node, "ObjectExpression");
+};
+
+lp.parsePropertyName = function (prop) {
+  if (this.options.ecmaVersion >= 6) {
+    if (this.eat(tt.bracketL)) {
+      prop.computed = true;
+      prop.key = this.parseExpression();
+      this.expect(tt.bracketR);
+      return;
+    } else {
+      prop.computed = false;
+    }
+  }
+  var key = this.tok.type === tt.num || this.tok.type === tt.string ? this.parseExprAtom() : this.parseIdent();
+  prop.key = key || this.dummyIdent();
+};
+
+lp.parsePropertyAccessor = function () {
+  if (this.tok.type === tt.name || this.tok.type.keyword) return this.parseIdent();
+};
+
+lp.parseIdent = function () {
+  var name = this.tok.type === tt.name ? this.tok.value : this.tok.type.keyword;
+  if (!name) return this.dummyIdent();
+  var node = this.startNode();
+  this.next();
+  node.name = name;
+  return this.finishNode(node, "Identifier");
+};
+
+lp.initFunction = function (node) {
+  node.id = null;
+  node.params = [];
+  if (this.options.ecmaVersion >= 6) {
+    node.generator = false;
+    node.expression = false;
+  }
+};
+
+// Convert existing expression atom to assignable pattern
+// if possible.
+
+lp.toAssignable = function (node) {
+  if (this.options.ecmaVersion >= 6 && node) {
+    switch (node.type) {
+      case "ObjectExpression":
+        node.type = "ObjectPattern";
+        var props = node.properties;
+        for (var i = 0; i < props.length; i++) {
+          this.toAssignable(props[i].value);
+        }break;
+
+      case "ArrayExpression":
+        node.type = "ArrayPattern";
+        this.toAssignableList(node.elements);
+        break;
+
+      case "SpreadElement":
+        node.type = "RestElement";
+        node.argument = this.toAssignable(node.argument);
+        break;
+
+      case "AssignmentExpression":
+        node.type = "AssignmentPattern";
+        break;
+    }
+  }
+  return this.checkLVal(node);
+};
+
+lp.toAssignableList = function (exprList) {
+  for (var i = 0; i < exprList.length; i++) {
+    this.toAssignable(exprList[i]);
+  }return exprList;
+};
+
+lp.parseFunctionParams = function (params) {
+  this.pushCx();
+  params = this.parseExprList(tt.parenR);
+  return this.toAssignableList(params);
+};
+
+lp.parseMethod = function (isGenerator) {
+  var node = this.startNode();
+  this.initFunction(node);
+  node.params = this.parseFunctionParams();
+  node.generator = isGenerator || false;
+  node.expression = this.options.ecmaVersion >= 6 && this.tok.type !== tt.braceL;
+  node.body = node.expression ? this.parseMaybeAssign() : this.parseBlock();
+  return this.finishNode(node, "FunctionExpression");
+};
+
+lp.parseArrowExpression = function (node, params) {
+  this.initFunction(node);
+  node.params = this.toAssignableList(params);
+  node.expression = this.tok.type !== tt.braceL;
+  node.body = node.expression ? this.parseMaybeAssign() : this.parseBlock();
+  return this.finishNode(node, "ArrowFunctionExpression");
+};
+
+lp.parseExprList = function (close, allowEmpty) {
+  var indent = this.curIndent,
+      line = this.curLineStart,
+      elts = [];
+  this.next(); // Opening bracket
+  while (!this.closes(close, indent + 1, line)) {
+    if (this.eat(tt.comma)) {
+      elts.push(allowEmpty ? null : this.dummyIdent());
+      continue;
+    }
+    var elt = this.parseMaybeAssign();
+    if (isDummy(elt)) {
+      if (this.closes(close, indent, line)) break;
+      this.next();
+    } else {
+      elts.push(elt);
+    }
+    this.eat(tt.comma);
+  }
+  this.popCx();
+  if (!this.eat(close)) {
+    // If there is no closing brace, make the node span to the start
+    // of the next token (this is useful for Tern)
+    this.last.end = this.tok.start;
+    if (this.options.locations) this.last.loc.end = this.tok.loc.start;
+  }
+  return elts;
+};
+
+},{"..":2,"./parseutil":4,"./state":5}],4:[function(require,module,exports){
+"use strict";
+
+exports.isDummy = isDummy;
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+
+var LooseParser = require("./state").LooseParser;
+
+var _ = require("..");
+
+var Node = _.Node;
+var SourceLocation = _.SourceLocation;
+var lineBreak = _.lineBreak;
+var isNewLine = _.isNewLine;
+var tt = _.tokTypes;
+
+var lp = LooseParser.prototype;
+
+lp.startNode = function () {
+  var node = new Node();
+  node.start = this.tok.start;
+  if (this.options.locations) node.loc = new SourceLocation(this.toks, this.tok.loc.start);
+  if (this.options.directSourceFile) node.sourceFile = this.options.directSourceFile;
+  if (this.options.ranges) node.range = [this.tok.start, 0];
+  return node;
+};
+
+lp.storeCurrentPos = function () {
+  return this.options.locations ? [this.tok.start, this.tok.loc.start] : this.tok.start;
+};
+
+lp.startNodeAt = function (pos) {
+  var node = new Node();
+  if (this.options.locations) {
+    node.start = pos[0];
+    node.loc = new SourceLocation(this.toks, pos[1]);
+    pos = pos[0];
+  } else {
+    node.start = pos;
+  }
+  if (this.options.directSourceFile) node.sourceFile = this.options.directSourceFile;
+  if (this.options.ranges) node.range = [pos, 0];
+  return node;
+};
+
+lp.finishNode = function (node, type) {
+  node.type = type;
+  node.end = this.last.end;
+  if (this.options.locations) node.loc.end = this.last.loc.end;
+  if (this.options.ranges) node.range[1] = this.last.end;
+  return node;
+};
+
+lp.dummyIdent = function () {
+  var dummy = this.startNode();
+  dummy.name = "✖";
+  return this.finishNode(dummy, "Identifier");
+};
+
+function isDummy(node) {
+  return node.name == "✖";
+}
+
+lp.eat = function (type) {
+  if (this.tok.type === type) {
+    this.next();
+    return true;
+  } else {
+    return false;
+  }
+};
+
+lp.isContextual = function (name) {
+  return this.tok.type === tt.name && this.tok.value === name;
+};
+
+lp.eatContextual = function (name) {
+  return this.tok.value === name && this.eat(tt.name);
+};
+
+lp.canInsertSemicolon = function () {
+  return this.tok.type === tt.eof || this.tok.type === tt.braceR || lineBreak.test(this.input.slice(this.last.end, this.tok.start));
+};
+
+lp.semicolon = function () {
+  return this.eat(tt.semi);
+};
+
+lp.expect = function (type) {
+  if (this.eat(type)) return true;
+  for (var i = 1; i <= 2; i++) {
+    if (this.lookAhead(i).type == type) {
+      for (var j = 0; j < i; j++) {
+        this.next();
+      }return true;
+    }
+  }
+};
+
+lp.pushCx = function () {
+  this.context.push(this.curIndent);
+};
+lp.popCx = function () {
+  this.curIndent = this.context.pop();
+};
+
+lp.lineEnd = function (pos) {
+  while (pos < this.input.length && !isNewLine(this.input.charCodeAt(pos))) ++pos;
+  return pos;
+};
+
+lp.indentationAfter = function (pos) {
+  for (var count = 0;; ++pos) {
+    var ch = this.input.charCodeAt(pos);
+    if (ch === 32) ++count;else if (ch === 9) count += this.options.tabSize;else return count;
+  }
+};
+
+lp.closes = function (closeTok, indent, line, blockHeuristic) {
+  if (this.tok.type === closeTok || this.tok.type === tt.eof) return true;
+  return line != this.curLineStart && this.curIndent < indent && this.tokenStartsLine() && (!blockHeuristic || this.nextLineStart >= this.input.length || this.indentationAfter(this.nextLineStart) < indent);
+};
+
+lp.tokenStartsLine = function () {
+  for (var p = this.tok.start - 1; p >= this.curLineStart; --p) {
+    var ch = this.input.charCodeAt(p);
+    if (ch !== 9 && ch !== 32) return false;
+  }
+  return true;
+};
+
+},{"..":2,"./state":5}],5:[function(require,module,exports){
+"use strict";
+
+exports.LooseParser = LooseParser;
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+
+var _ = require("..");
+
+var tokenizer = _.tokenizer;
+var SourceLocation = _.SourceLocation;
+var tt = _.tokTypes;
+
+function LooseParser(input, options) {
+  this.toks = tokenizer(input, options);
+  this.options = this.toks.options;
+  this.input = this.toks.input;
+  this.tok = this.last = { type: tt.eof, start: 0, end: 0 };
+  if (this.options.locations) {
+    var here = this.toks.curPosition();
+    this.tok.loc = new SourceLocation(this.toks, here, here);
+  }
+  this.ahead = []; // Tokens ahead
+  this.context = []; // Indentation contexted
+  this.curIndent = 0;
+  this.curLineStart = 0;
+  this.nextLineStart = this.lineEnd(this.curLineStart) + 1;
+}
+
+},{"..":2}],6:[function(require,module,exports){
+"use strict";
+
+var LooseParser = require("./state").LooseParser;
+
+var isDummy = require("./parseutil").isDummy;
+
+var _ = require("..");
+
+var getLineInfo = _.getLineInfo;
+var tt = _.tokTypes;
+
+var lp = LooseParser.prototype;
+
+lp.parseTopLevel = function () {
+  var node = this.startNodeAt(this.options.locations ? [0, getLineInfo(this.input, 0)] : 0);
+  node.body = [];
+  while (this.tok.type !== tt.eof) node.body.push(this.parseStatement());
+  this.last = this.tok;
+  if (this.options.ecmaVersion >= 6) {
+    node.sourceType = this.options.sourceType;
+  }
+  return this.finishNode(node, "Program");
+};
+
+lp.parseStatement = function () {
+  var starttype = this.tok.type,
+      node = this.startNode();
+
+  switch (starttype) {
+    case tt._break:case tt._continue:
+      this.next();
+      var isBreak = starttype === tt._break;
+      if (this.semicolon() || this.canInsertSemicolon()) {
+        node.label = null;
+      } else {
+        node.label = this.tok.type === tt.name ? this.parseIdent() : null;
+        this.semicolon();
+      }
+      return this.finishNode(node, isBreak ? "BreakStatement" : "ContinueStatement");
+
+    case tt._debugger:
+      this.next();
+      this.semicolon();
+      return this.finishNode(node, "DebuggerStatement");
+
+    case tt._do:
+      this.next();
+      node.body = this.parseStatement();
+      node.test = this.eat(tt._while) ? this.parseParenExpression() : this.dummyIdent();
+      this.semicolon();
+      return this.finishNode(node, "DoWhileStatement");
+
+    case tt._for:
+      this.next();
+      this.pushCx();
+      this.expect(tt.parenL);
+      if (this.tok.type === tt.semi) return this.parseFor(node, null);
+      if (this.tok.type === tt._var || this.tok.type === tt._let || this.tok.type === tt._const) {
+        var _init = this.parseVar(true);
+        if (_init.declarations.length === 1 && (this.tok.type === tt._in || this.isContextual("of"))) {
+          return this.parseForIn(node, _init);
+        }
+        return this.parseFor(node, _init);
+      }
+      var init = this.parseExpression(true);
+      if (this.tok.type === tt._in || this.isContextual("of")) return this.parseForIn(node, this.toAssignable(init));
+      return this.parseFor(node, init);
+
+    case tt._function:
+      this.next();
+      return this.parseFunction(node, true);
+
+    case tt._if:
+      this.next();
+      node.test = this.parseParenExpression();
+      node.consequent = this.parseStatement();
+      node.alternate = this.eat(tt._else) ? this.parseStatement() : null;
+      return this.finishNode(node, "IfStatement");
+
+    case tt._return:
+      this.next();
+      if (this.eat(tt.semi) || this.canInsertSemicolon()) node.argument = null;else {
+        node.argument = this.parseExpression();this.semicolon();
+      }
+      return this.finishNode(node, "ReturnStatement");
+
+    case tt._switch:
+      var blockIndent = this.curIndent,
+          line = this.curLineStart;
+      this.next();
+      node.discriminant = this.parseParenExpression();
+      node.cases = [];
+      this.pushCx();
+      this.expect(tt.braceL);
+
+      var cur = undefined;
+      while (!this.closes(tt.braceR, blockIndent, line, true)) {
+        if (this.tok.type === tt._case || this.tok.type === tt._default) {
+          var isCase = this.tok.type === tt._case;
+          if (cur) this.finishNode(cur, "SwitchCase");
+          node.cases.push(cur = this.startNode());
+          cur.consequent = [];
+          this.next();
+          if (isCase) cur.test = this.parseExpression();else cur.test = null;
+          this.expect(tt.colon);
+        } else {
+          if (!cur) {
+            node.cases.push(cur = this.startNode());
+            cur.consequent = [];
+            cur.test = null;
+          }
+          cur.consequent.push(this.parseStatement());
+        }
+      }
+      if (cur) this.finishNode(cur, "SwitchCase");
+      this.popCx();
+      this.eat(tt.braceR);
+      return this.finishNode(node, "SwitchStatement");
+
+    case tt._throw:
+      this.next();
+      node.argument = this.parseExpression();
+      this.semicolon();
+      return this.finishNode(node, "ThrowStatement");
+
+    case tt._try:
+      this.next();
+      node.block = this.parseBlock();
+      node.handler = null;
+      if (this.tok.type === tt._catch) {
+        var clause = this.startNode();
+        this.next();
+        this.expect(tt.parenL);
+        clause.param = this.toAssignable(this.parseExprAtom());
+        this.expect(tt.parenR);
+        clause.guard = null;
+        clause.body = this.parseBlock();
+        node.handler = this.finishNode(clause, "CatchClause");
+      }
+      node.finalizer = this.eat(tt._finally) ? this.parseBlock() : null;
+      if (!node.handler && !node.finalizer) return node.block;
+      return this.finishNode(node, "TryStatement");
+
+    case tt._var:
+    case tt._let:
+    case tt._const:
+      return this.parseVar();
+
+    case tt._while:
+      this.next();
+      node.test = this.parseParenExpression();
+      node.body = this.parseStatement();
+      return this.finishNode(node, "WhileStatement");
+
+    case tt._with:
+      this.next();
+      node.object = this.parseParenExpression();
+      node.body = this.parseStatement();
+      return this.finishNode(node, "WithStatement");
+
+    case tt.braceL:
+      return this.parseBlock();
+
+    case tt.semi:
+      this.next();
+      return this.finishNode(node, "EmptyStatement");
+
+    case tt._class:
+      return this.parseClass(true);
+
+    case tt._import:
+      return this.parseImport();
+
+    case tt._export:
+      return this.parseExport();
+
+    default:
+      var expr = this.parseExpression();
+      if (isDummy(expr)) {
+        this.next();
+        if (this.tok.type === tt.eof) return this.finishNode(node, "EmptyStatement");
+        return this.parseStatement();
+      } else if (starttype === tt.name && expr.type === "Identifier" && this.eat(tt.colon)) {
+        node.body = this.parseStatement();
+        node.label = expr;
+        return this.finishNode(node, "LabeledStatement");
+      } else {
+        node.expression = expr;
+        this.semicolon();
+        return this.finishNode(node, "ExpressionStatement");
+      }
+  }
+};
+
+lp.parseBlock = function () {
+  var node = this.startNode();
+  this.pushCx();
+  this.expect(tt.braceL);
+  var blockIndent = this.curIndent,
+      line = this.curLineStart;
+  node.body = [];
+  while (!this.closes(tt.braceR, blockIndent, line, true)) node.body.push(this.parseStatement());
+  this.popCx();
+  this.eat(tt.braceR);
+  return this.finishNode(node, "BlockStatement");
+};
+
+lp.parseFor = function (node, init) {
+  node.init = init;
+  node.test = node.update = null;
+  if (this.eat(tt.semi) && this.tok.type !== tt.semi) node.test = this.parseExpression();
+  if (this.eat(tt.semi) && this.tok.type !== tt.parenR) node.update = this.parseExpression();
+  this.popCx();
+  this.expect(tt.parenR);
+  node.body = this.parseStatement();
+  return this.finishNode(node, "ForStatement");
+};
+
+lp.parseForIn = function (node, init) {
+  var type = this.tok.type === tt._in ? "ForInStatement" : "ForOfStatement";
+  this.next();
+  node.left = init;
+  node.right = this.parseExpression();
+  this.popCx();
+  this.expect(tt.parenR);
+  node.body = this.parseStatement();
+  return this.finishNode(node, type);
+};
+
+lp.parseVar = function (noIn) {
+  var node = this.startNode();
+  node.kind = this.tok.type.keyword;
+  this.next();
+  node.declarations = [];
+  do {
+    var decl = this.startNode();
+    decl.id = this.options.ecmaVersion >= 6 ? this.toAssignable(this.parseExprAtom()) : this.parseIdent();
+    decl.init = this.eat(tt.eq) ? this.parseMaybeAssign(noIn) : null;
+    node.declarations.push(this.finishNode(decl, "VariableDeclarator"));
+  } while (this.eat(tt.comma));
+  if (!node.declarations.length) {
+    var decl = this.startNode();
+    decl.id = this.dummyIdent();
+    node.declarations.push(this.finishNode(decl, "VariableDeclarator"));
+  }
+  if (!noIn) this.semicolon();
+  return this.finishNode(node, "VariableDeclaration");
+};
+
+lp.parseClass = function (isStatement) {
+  var node = this.startNode();
+  this.next();
+  if (this.tok.type === tt.name) node.id = this.parseIdent();else if (isStatement) node.id = this.dummyIdent();else node.id = null;
+  node.superClass = this.eat(tt._extends) ? this.parseExpression() : null;
+  node.body = this.startNode();
+  node.body.body = [];
+  this.pushCx();
+  var indent = this.curIndent + 1,
+      line = this.curLineStart;
+  this.eat(tt.braceL);
+  if (this.curIndent + 1 < indent) {
+    indent = this.curIndent;line = this.curLineStart;
+  }
+  while (!this.closes(tt.braceR, indent, line)) {
+    if (this.semicolon()) continue;
+    var method = this.startNode(),
+        isGenerator = undefined,
+        start = undefined;
+    if (this.options.ecmaVersion >= 6) {
+      method["static"] = false;
+      isGenerator = this.eat(tt.star);
+    }
+    this.parsePropertyName(method);
+    if (isDummy(method.key)) {
+      if (isDummy(this.parseMaybeAssign())) this.next();this.eat(tt.comma);continue;
+    }
+    if (method.key.type === "Identifier" && !method.computed && method.key.name === "static" && (this.tok.type != tt.parenL && this.tok.type != tt.braceL)) {
+      method["static"] = true;
+      isGenerator = this.eat(tt.star);
+      this.parsePropertyName(method);
+    } else {
+      method["static"] = false;
+    }
+    if (this.options.ecmaVersion >= 5 && method.key.type === "Identifier" && !method.computed && (method.key.name === "get" || method.key.name === "set") && this.tok.type !== tt.parenL && this.tok.type !== tt.braceL) {
+      method.kind = method.key.name;
+      this.parsePropertyName(method);
+      method.value = this.parseMethod(false);
+    } else {
+      if (!method.computed && !method["static"] && !isGenerator && (method.key.type === "Identifier" && method.key.name === "constructor" || method.key.type === "Literal" && method.key.value === "constructor")) {
+        method.kind = "constructor";
+      } else {
+        method.kind = "method";
+      }
+      method.value = this.parseMethod(isGenerator);
+    }
+    node.body.body.push(this.finishNode(method, "MethodDefinition"));
+  }
+  this.popCx();
+  if (!this.eat(tt.braceR)) {
+    // If there is no closing brace, make the node span to the start
+    // of the next token (this is useful for Tern)
+    this.last.end = this.tok.start;
+    if (this.options.locations) this.last.loc.end = this.tok.loc.start;
+  }
+  this.semicolon();
+  this.finishNode(node.body, "ClassBody");
+  return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression");
+};
+
+lp.parseFunction = function (node, isStatement) {
+  this.initFunction(node);
+  if (this.options.ecmaVersion >= 6) {
+    node.generator = this.eat(tt.star);
+  }
+  if (this.tok.type === tt.name) node.id = this.parseIdent();else if (isStatement) node.id = this.dummyIdent();
+  node.params = this.parseFunctionParams();
+  node.body = this.parseBlock();
+  return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression");
+};
+
+lp.parseExport = function () {
+  var node = this.startNode();
+  this.next();
+  if (this.eat(tt.star)) {
+    node.source = this.eatContextual("from") ? this.parseExprAtom() : null;
+    return this.finishNode(node, "ExportAllDeclaration");
+  }
+  if (this.eat(tt._default)) {
+    var expr = this.parseMaybeAssign();
+    if (expr.id) {
+      switch (expr.type) {
+        case "FunctionExpression":
+          expr.type = "FunctionDeclaration";break;
+        case "ClassExpression":
+          expr.type = "ClassDeclaration";break;
+      }
+    }
+    node.declaration = expr;
+    this.semicolon();
+    return this.finishNode(node, "ExportDefaultDeclaration");
+  }
+  if (this.tok.type.keyword) {
+    node.declaration = this.parseStatement();
+    node.specifiers = [];
+    node.source = null;
+  } else {
+    node.declaration = null;
+    node.specifiers = this.parseExportSpecifierList();
+    node.source = this.eatContextual("from") ? this.parseExprAtom() : null;
+    this.semicolon();
+  }
+  return this.finishNode(node, "ExportNamedDeclaration");
+};
+
+lp.parseImport = function () {
+  var node = this.startNode();
+  this.next();
+  if (this.tok.type === tt.string) {
+    node.specifiers = [];
+    node.source = this.parseExprAtom();
+    node.kind = "";
+  } else {
+    var elt = undefined;
+    if (this.tok.type === tt.name && this.tok.value !== "from") {
+      elt = this.startNode();
+      elt.local = this.parseIdent();
+      this.finishNode(elt, "ImportDefaultSpecifier");
+      this.eat(tt.comma);
+    }
+    node.specifiers = this.parseImportSpecifierList();
+    node.source = this.eatContextual("from") ? this.parseExprAtom() : null;
+    if (elt) node.specifiers.unshift(elt);
+  }
+  this.semicolon();
+  return this.finishNode(node, "ImportDeclaration");
+};
+
+lp.parseImportSpecifierList = function () {
+  var elts = [];
+  if (this.tok.type === tt.star) {
+    var elt = this.startNode();
+    this.next();
+    if (this.eatContextual("as")) elt.local = this.parseIdent();
+    elts.push(this.finishNode(elt, "ImportNamespaceSpecifier"));
+  } else {
+    var indent = this.curIndent,
+        line = this.curLineStart,
+        continuedLine = this.nextLineStart;
+    this.pushCx();
+    this.eat(tt.braceL);
+    if (this.curLineStart > continuedLine) continuedLine = this.curLineStart;
+    while (!this.closes(tt.braceR, indent + (this.curLineStart <= continuedLine ? 1 : 0), line)) {
+      var elt = this.startNode();
+      if (this.eat(tt.star)) {
+        if (this.eatContextual("as")) elt.local = this.parseIdent();
+        this.finishNode(elt, "ImportNamespaceSpecifier");
+      } else {
+        if (this.isContextual("from")) break;
+        elt.imported = this.parseIdent();
+        elt.local = this.eatContextual("as") ? this.parseIdent() : elt.imported;
+        this.finishNode(elt, "ImportSpecifier");
+      }
+      elts.push(elt);
+      this.eat(tt.comma);
+    }
+    this.eat(tt.braceR);
+    this.popCx();
+  }
+  return elts;
+};
+
+lp.parseExportSpecifierList = function () {
+  var elts = [];
+  var indent = this.curIndent,
+      line = this.curLineStart,
+      continuedLine = this.nextLineStart;
+  this.pushCx();
+  this.eat(tt.braceL);
+  if (this.curLineStart > continuedLine) continuedLine = this.curLineStart;
+  while (!this.closes(tt.braceR, indent + (this.curLineStart <= continuedLine ? 1 : 0), line)) {
+    if (this.isContextual("from")) break;
+    var elt = this.startNode();
+    elt.local = this.parseIdent();
+    elt.exported = this.eatContextual("as") ? this.parseIdent() : elt.local;
+    this.finishNode(elt, "ExportSpecifier");
+    elts.push(elt);
+    this.eat(tt.comma);
+  }
+  this.eat(tt.braceR);
+  this.popCx();
+  return elts;
+};
+
+},{"..":2,"./parseutil":4,"./state":5}],7:[function(require,module,exports){
+"use strict";
+
+var _ = require("..");
+
+var tt = _.tokTypes;
+var Token = _.Token;
+var isNewLine = _.isNewLine;
+var SourceLocation = _.SourceLocation;
+var getLineInfo = _.getLineInfo;
+var lineBreakG = _.lineBreakG;
+
+var LooseParser = require("./state").LooseParser;
+
+var lp = LooseParser.prototype;
+
+function isSpace(ch) {
+  return ch < 14 && ch > 8 || ch === 32 || ch === 160 || isNewLine(ch);
+}
+
+lp.next = function () {
+  this.last = this.tok;
+  if (this.ahead.length) this.tok = this.ahead.shift();else this.tok = this.readToken();
+
+  if (this.tok.start >= this.nextLineStart) {
+    while (this.tok.start >= this.nextLineStart) {
+      this.curLineStart = this.nextLineStart;
+      this.nextLineStart = this.lineEnd(this.curLineStart) + 1;
+    }
+    this.curIndent = this.indentationAfter(this.curLineStart);
+  }
+};
+
+lp.readToken = function () {
+  for (;;) {
+    try {
+      this.toks.next();
+      if (this.toks.type === tt.dot && this.input.substr(this.toks.end, 1) === "." && this.options.ecmaVersion >= 6) {
+        this.toks.end++;
+        this.toks.type = tt.ellipsis;
+      }
+      return new Token(this.toks);
+    } catch (e) {
+      if (!(e instanceof SyntaxError)) throw e;
+
+      // Try to skip some text, based on the error message, and then continue
+      var msg = e.message,
+          pos = e.raisedAt,
+          replace = true;
+      if (/unterminated/i.test(msg)) {
+        pos = this.lineEnd(e.pos + 1);
+        if (/string/.test(msg)) {
+          replace = { start: e.pos, end: pos, type: tt.string, value: this.input.slice(e.pos + 1, pos) };
+        } else if (/regular expr/i.test(msg)) {
+          var re = this.input.slice(e.pos, pos);
+          try {
+            re = new RegExp(re);
+          } catch (e) {}
+          replace = { start: e.pos, end: pos, type: tt.regexp, value: re };
+        } else if (/template/.test(msg)) {
+          replace = { start: e.pos, end: pos,
+            type: tt.template,
+            value: this.input.slice(e.pos, pos) };
+        } else {
+          replace = false;
+        }
+      } else if (/invalid (unicode|regexp|number)|expecting unicode|octal literal|is reserved|directly after number/i.test(msg)) {
+        while (pos < this.input.length && !isSpace(this.input.charCodeAt(pos))) ++pos;
+      } else if (/character escape|expected hexadecimal/i.test(msg)) {
+        while (pos < this.input.length) {
+          var ch = this.input.charCodeAt(pos++);
+          if (ch === 34 || ch === 39 || isNewLine(ch)) break;
+        }
+      } else if (/unexpected character/i.test(msg)) {
+        pos++;
+        replace = false;
+      } else if (/regular expression/i.test(msg)) {
+        replace = true;
+      } else {
+        throw e;
+      }
+      this.resetTo(pos);
+      if (replace === true) replace = { start: pos, end: pos, type: tt.name, value: "✖" };
+      if (replace) {
+        if (this.options.locations) replace.loc = new SourceLocation(this.toks, getLineInfo(this.input, replace.start), getLineInfo(this.input, replace.end));
+        return replace;
+      }
+    }
+  }
+};
+
+lp.resetTo = function (pos) {
+  this.toks.pos = pos;
+  var ch = this.input.charAt(pos - 1);
+  this.toks.exprAllowed = !ch || /[\[\{\(,;:?\/*=+\-~!|&%^<>]/.test(ch) || /[enwfd]/.test(ch) && /\b(keywords|case|else|return|throw|new|in|(instance|type)of|delete|void)$/.test(this.input.slice(pos - 10, pos));
+
+  if (this.options.locations) {
+    this.toks.curLine = 1;
+    this.toks.lineStart = lineBreakG.lastIndex = 0;
+    var match = undefined;
+    while ((match = lineBreakG.exec(this.input)) && match.index < pos) {
+      ++this.toks.curLine;
+      this.toks.lineStart = match.index + match[0].length;
+    }
+  }
+};
+
+lp.lookAhead = function (n) {
+  while (n > this.ahead.length) this.ahead.push(this.readToken());
+  return this.ahead[n - 1];
+};
+
+},{"..":2,"./state":5}]},{},[1])(1)
+});

+ 344 - 0
editor/js/libs/acorn/walk.js

@@ -0,0 +1,344 @@
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}(g.acorn || (g.acorn = {})).walk = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
+"use strict";
+
+var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } };
+
+// AST walker module for Mozilla Parser API compatible trees
+
+// A simple walk is one where you simply specify callbacks to be
+// called on specific nodes. The last two arguments are optional. A
+// simple use would be
+//
+//     walk.simple(myTree, {
+//         Expression: function(node) { ... }
+//     });
+//
+// to do something with all expressions. All Parser API node types
+// can be used to identify node types, as well as Expression,
+// Statement, and ScopeBody, which denote categories of nodes.
+//
+// The base argument can be used to pass a custom (recursive)
+// walker, and state can be used to give this walked an initial
+// state.
+
+exports.simple = simple;
+
+// An ancestor walk builds up an array of ancestor nodes (including
+// the current node) and passes them to the callback as the state parameter.
+exports.ancestor = ancestor;
+
+// A recursive walk is one where your functions override the default
+// walkers. They can modify and replace the state parameter that's
+// threaded through the walk, and can opt how and whether to walk
+// their child nodes (by calling their third argument on these
+// nodes).
+exports.recursive = recursive;
+
+// Find a node with a given start, end, and type (all are optional,
+// null can be used as wildcard). Returns a {node, state} object, or
+// undefined when it doesn't find a matching node.
+exports.findNodeAt = findNodeAt;
+
+// Find the innermost node of a given type that contains the given
+// position. Interface similar to findNodeAt.
+exports.findNodeAround = findNodeAround;
+
+// Find the outermost matching node after a given position.
+exports.findNodeAfter = findNodeAfter;
+
+// Find the outermost matching node before a given position.
+exports.findNodeBefore = findNodeBefore;
+
+// Used to create a custom walker. Will fill in all missing node
+// type properties with the defaults.
+exports.make = make;
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+
+function simple(node, visitors, base, state) {
+  if (!base) base = exports.base;(function c(node, st, override) {
+    var type = override || node.type,
+        found = visitors[type];
+    base[type](node, st, c);
+    if (found) found(node, st);
+  })(node, state);
+}
+
+function ancestor(node, visitors, base, state) {
+  if (!base) base = exports.base;
+  if (!state) state = [];(function c(node, st, override) {
+    var type = override || node.type,
+        found = visitors[type];
+    if (node != st[st.length - 1]) {
+      st = st.slice();
+      st.push(node);
+    }
+    base[type](node, st, c);
+    if (found) found(node, st);
+  })(node, state);
+}
+
+function recursive(node, state, funcs, base) {
+  var visitor = funcs ? exports.make(funcs, base) : base;(function c(node, st, override) {
+    visitor[override || node.type](node, st, c);
+  })(node, state);
+}
+
+function makeTest(test) {
+  if (typeof test == "string") {
+    return function (type) {
+      return type == test;
+    };
+  } else if (!test) {
+    return function () {
+      return true;
+    };
+  } else {
+    return test;
+  }
+}
+
+var Found = function Found(node, state) {
+  _classCallCheck(this, Found);
+
+  this.node = node;this.state = state;
+};
+
+function findNodeAt(node, start, end, test, base, state) {
+  test = makeTest(test);
+  if (!base) base = exports.base;
+  try {
+    ;(function c(node, st, override) {
+      var type = override || node.type;
+      if ((start == null || node.start <= start) && (end == null || node.end >= end)) base[type](node, st, c);
+      if (test(type, node) && (start == null || node.start == start) && (end == null || node.end == end)) throw new Found(node, st);
+    })(node, state);
+  } catch (e) {
+    if (e instanceof Found) {
+      return e;
+    }throw e;
+  }
+}
+
+function findNodeAround(node, pos, test, base, state) {
+  test = makeTest(test);
+  if (!base) base = exports.base;
+  try {
+    ;(function c(node, st, override) {
+      var type = override || node.type;
+      if (node.start > pos || node.end < pos) {
+        return;
+      }base[type](node, st, c);
+      if (test(type, node)) throw new Found(node, st);
+    })(node, state);
+  } catch (e) {
+    if (e instanceof Found) {
+      return e;
+    }throw e;
+  }
+}
+
+function findNodeAfter(node, pos, test, base, state) {
+  test = makeTest(test);
+  if (!base) base = exports.base;
+  try {
+    ;(function c(node, st, override) {
+      if (node.end < pos) {
+        return;
+      }var type = override || node.type;
+      if (node.start >= pos && test(type, node)) throw new Found(node, st);
+      base[type](node, st, c);
+    })(node, state);
+  } catch (e) {
+    if (e instanceof Found) {
+      return e;
+    }throw e;
+  }
+}
+
+function findNodeBefore(node, pos, test, base, state) {
+  test = makeTest(test);
+  if (!base) base = exports.base;
+  var max = undefined;(function c(node, st, override) {
+    if (node.start > pos) {
+      return;
+    }var type = override || node.type;
+    if (node.end <= pos && (!max || max.node.end < node.end) && test(type, node)) max = new Found(node, st);
+    base[type](node, st, c);
+  })(node, state);
+  return max;
+}
+
+function make(funcs, base) {
+  if (!base) base = exports.base;
+  var visitor = {};
+  for (var type in base) visitor[type] = base[type];
+  for (var type in funcs) visitor[type] = funcs[type];
+  return visitor;
+}
+
+function skipThrough(node, st, c) {
+  c(node, st);
+}
+function ignore(_node, _st, _c) {}
+
+// Node walkers.
+
+var base = {};
+
+exports.base = base;
+base.Program = base.BlockStatement = function (node, st, c) {
+  for (var i = 0; i < node.body.length; ++i) {
+    c(node.body[i], st, "Statement");
+  }
+};
+base.Statement = skipThrough;
+base.EmptyStatement = ignore;
+base.ExpressionStatement = base.ParenthesizedExpression = function (node, st, c) {
+  return c(node.expression, st, "Expression");
+};
+base.IfStatement = function (node, st, c) {
+  c(node.test, st, "Expression");
+  c(node.consequent, st, "Statement");
+  if (node.alternate) c(node.alternate, st, "Statement");
+};
+base.LabeledStatement = function (node, st, c) {
+  return c(node.body, st, "Statement");
+};
+base.BreakStatement = base.ContinueStatement = ignore;
+base.WithStatement = function (node, st, c) {
+  c(node.object, st, "Expression");
+  c(node.body, st, "Statement");
+};
+base.SwitchStatement = function (node, st, c) {
+  c(node.discriminant, st, "Expression");
+  for (var i = 0; i < node.cases.length; ++i) {
+    var cs = node.cases[i];
+    if (cs.test) c(cs.test, st, "Expression");
+    for (var j = 0; j < cs.consequent.length; ++j) {
+      c(cs.consequent[j], st, "Statement");
+    }
+  }
+};
+base.ReturnStatement = base.YieldExpression = function (node, st, c) {
+  if (node.argument) c(node.argument, st, "Expression");
+};
+base.ThrowStatement = base.SpreadElement = base.RestElement = function (node, st, c) {
+  return c(node.argument, st, "Expression");
+};
+base.TryStatement = function (node, st, c) {
+  c(node.block, st, "Statement");
+  if (node.handler) c(node.handler.body, st, "ScopeBody");
+  if (node.finalizer) c(node.finalizer, st, "Statement");
+};
+base.WhileStatement = base.DoWhileStatement = function (node, st, c) {
+  c(node.test, st, "Expression");
+  c(node.body, st, "Statement");
+};
+base.ForStatement = function (node, st, c) {
+  if (node.init) c(node.init, st, "ForInit");
+  if (node.test) c(node.test, st, "Expression");
+  if (node.update) c(node.update, st, "Expression");
+  c(node.body, st, "Statement");
+};
+base.ForInStatement = base.ForOfStatement = function (node, st, c) {
+  c(node.left, st, "ForInit");
+  c(node.right, st, "Expression");
+  c(node.body, st, "Statement");
+};
+base.ForInit = function (node, st, c) {
+  if (node.type == "VariableDeclaration") c(node, st);else c(node, st, "Expression");
+};
+base.DebuggerStatement = ignore;
+
+base.FunctionDeclaration = function (node, st, c) {
+  return c(node, st, "Function");
+};
+base.VariableDeclaration = function (node, st, c) {
+  for (var i = 0; i < node.declarations.length; ++i) {
+    var decl = node.declarations[i];
+    if (decl.init) c(decl.init, st, "Expression");
+  }
+};
+
+base.Function = function (node, st, c) {
+  return c(node.body, st, "ScopeBody");
+};
+base.ScopeBody = function (node, st, c) {
+  return c(node, st, "Statement");
+};
+
+base.Expression = skipThrough;
+base.ThisExpression = base.Super = base.MetaProperty = ignore;
+base.ArrayExpression = base.ArrayPattern = function (node, st, c) {
+  for (var i = 0; i < node.elements.length; ++i) {
+    var elt = node.elements[i];
+    if (elt) c(elt, st, "Expression");
+  }
+};
+base.ObjectExpression = base.ObjectPattern = function (node, st, c) {
+  for (var i = 0; i < node.properties.length; ++i) {
+    c(node.properties[i], st);
+  }
+};
+base.FunctionExpression = base.ArrowFunctionExpression = base.FunctionDeclaration;
+base.SequenceExpression = base.TemplateLiteral = function (node, st, c) {
+  for (var i = 0; i < node.expressions.length; ++i) {
+    c(node.expressions[i], st, "Expression");
+  }
+};
+base.UnaryExpression = base.UpdateExpression = function (node, st, c) {
+  c(node.argument, st, "Expression");
+};
+base.BinaryExpression = base.AssignmentExpression = base.AssignmentPattern = base.LogicalExpression = function (node, st, c) {
+  c(node.left, st, "Expression");
+  c(node.right, st, "Expression");
+};
+base.ConditionalExpression = function (node, st, c) {
+  c(node.test, st, "Expression");
+  c(node.consequent, st, "Expression");
+  c(node.alternate, st, "Expression");
+};
+base.NewExpression = base.CallExpression = function (node, st, c) {
+  c(node.callee, st, "Expression");
+  if (node.arguments) for (var i = 0; i < node.arguments.length; ++i) {
+    c(node.arguments[i], st, "Expression");
+  }
+};
+base.MemberExpression = function (node, st, c) {
+  c(node.object, st, "Expression");
+  if (node.computed) c(node.property, st, "Expression");
+};
+base.ExportDeclaration = function (node, st, c) {
+  return c(node.declaration, st);
+};
+base.ImportDeclaration = function (node, st, c) {
+  for (var i = 0; i < node.specifiers.length; i++) {
+    c(node.specifiers[i], st);
+  }
+};
+base.ImportSpecifier = base.ImportBatchSpecifier = base.Identifier = base.Literal = ignore;
+
+base.TaggedTemplateExpression = function (node, st, c) {
+  c(node.tag, st, "Expression");
+  c(node.quasi, st);
+};
+base.ClassDeclaration = base.ClassExpression = function (node, st, c) {
+  if (node.superClass) c(node.superClass, st, "Expression");
+  for (var i = 0; i < node.body.body.length; i++) {
+    c(node.body.body[i], st);
+  }
+};
+base.MethodDefinition = base.Property = function (node, st, c) {
+  if (node.computed) c(node.key, st, "Expression");
+  c(node.value, st, "Expression");
+};
+base.ComprehensionExpression = function (node, st, c) {
+  for (var i = 0; i < node.blocks.length; i++) {
+    c(node.blocks[i].right, st, "Expression");
+  }c(node.body, st, "Expression");
+};
+
+},{}]},{},[1])(1)
+});

+ 32 - 0
editor/js/libs/codemirror/addon/dialog.css

@@ -0,0 +1,32 @@
+.CodeMirror-dialog {
+  position: absolute;
+  left: 0; right: 0;
+  background: inherit;
+  z-index: 15;
+  padding: .1em .8em;
+  overflow: hidden;
+  color: inherit;
+}
+
+.CodeMirror-dialog-top {
+  border-bottom: 1px solid #eee;
+  top: 0;
+}
+
+.CodeMirror-dialog-bottom {
+  border-top: 1px solid #eee;
+  bottom: 0;
+}
+
+.CodeMirror-dialog input {
+  border: none;
+  outline: none;
+  background: transparent;
+  width: 20em;
+  color: inherit;
+  font-family: monospace;
+}
+
+.CodeMirror-dialog button {
+  font-size: 70%;
+}

+ 157 - 0
editor/js/libs/codemirror/addon/dialog.js

@@ -0,0 +1,157 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+// Open simple dialogs on top of an editor. Relies on dialog.css.
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+  function dialogDiv(cm, template, bottom) {
+    var wrap = cm.getWrapperElement();
+    var dialog;
+    dialog = wrap.appendChild(document.createElement("div"));
+    if (bottom)
+      dialog.className = "CodeMirror-dialog CodeMirror-dialog-bottom";
+    else
+      dialog.className = "CodeMirror-dialog CodeMirror-dialog-top";
+
+    if (typeof template == "string") {
+      dialog.innerHTML = template;
+    } else { // Assuming it's a detached DOM element.
+      dialog.appendChild(template);
+    }
+    return dialog;
+  }
+
+  function closeNotification(cm, newVal) {
+    if (cm.state.currentNotificationClose)
+      cm.state.currentNotificationClose();
+    cm.state.currentNotificationClose = newVal;
+  }
+
+  CodeMirror.defineExtension("openDialog", function(template, callback, options) {
+    if (!options) options = {};
+
+    closeNotification(this, null);
+
+    var dialog = dialogDiv(this, template, options.bottom);
+    var closed = false, me = this;
+    function close(newVal) {
+      if (typeof newVal == 'string') {
+        inp.value = newVal;
+      } else {
+        if (closed) return;
+        closed = true;
+        dialog.parentNode.removeChild(dialog);
+        me.focus();
+
+        if (options.onClose) options.onClose(dialog);
+      }
+    }
+
+    var inp = dialog.getElementsByTagName("input")[0], button;
+    if (inp) {
+      if (options.value) {
+        inp.value = options.value;
+        if (options.selectValueOnOpen !== false) {
+          inp.select();
+        }
+      }
+
+      if (options.onInput)
+        CodeMirror.on(inp, "input", function(e) { options.onInput(e, inp.value, close);});
+      if (options.onKeyUp)
+        CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value, close);});
+
+      CodeMirror.on(inp, "keydown", function(e) {
+        if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; }
+        if (e.keyCode == 27 || (options.closeOnEnter !== false && e.keyCode == 13)) {
+          inp.blur();
+          CodeMirror.e_stop(e);
+          close();
+        }
+        if (e.keyCode == 13) callback(inp.value, e);
+      });
+
+      if (options.closeOnBlur !== false) CodeMirror.on(inp, "blur", close);
+
+      inp.focus();
+    } else if (button = dialog.getElementsByTagName("button")[0]) {
+      CodeMirror.on(button, "click", function() {
+        close();
+        me.focus();
+      });
+
+      if (options.closeOnBlur !== false) CodeMirror.on(button, "blur", close);
+
+      button.focus();
+    }
+    return close;
+  });
+
+  CodeMirror.defineExtension("openConfirm", function(template, callbacks, options) {
+    closeNotification(this, null);
+    var dialog = dialogDiv(this, template, options && options.bottom);
+    var buttons = dialog.getElementsByTagName("button");
+    var closed = false, me = this, blurring = 1;
+    function close() {
+      if (closed) return;
+      closed = true;
+      dialog.parentNode.removeChild(dialog);
+      me.focus();
+    }
+    buttons[0].focus();
+    for (var i = 0; i < buttons.length; ++i) {
+      var b = buttons[i];
+      (function(callback) {
+        CodeMirror.on(b, "click", function(e) {
+          CodeMirror.e_preventDefault(e);
+          close();
+          if (callback) callback(me);
+        });
+      })(callbacks[i]);
+      CodeMirror.on(b, "blur", function() {
+        --blurring;
+        setTimeout(function() { if (blurring <= 0) close(); }, 200);
+      });
+      CodeMirror.on(b, "focus", function() { ++blurring; });
+    }
+  });
+
+  /*
+   * openNotification
+   * Opens a notification, that can be closed with an optional timer
+   * (default 5000ms timer) and always closes on click.
+   *
+   * If a notification is opened while another is opened, it will close the
+   * currently opened one and open the new one immediately.
+   */
+  CodeMirror.defineExtension("openNotification", function(template, options) {
+    closeNotification(this, close);
+    var dialog = dialogDiv(this, template, options && options.bottom);
+    var closed = false, doneTimer;
+    var duration = options && typeof options.duration !== "undefined" ? options.duration : 5000;
+
+    function close() {
+      if (closed) return;
+      closed = true;
+      clearTimeout(doneTimer);
+      dialog.parentNode.removeChild(dialog);
+    }
+
+    CodeMirror.on(dialog, 'click', function(e) {
+      CodeMirror.e_preventDefault(e);
+      close();
+    });
+
+    if (duration)
+      doneTimer = setTimeout(close, duration);
+
+    return close;
+  });
+});

+ 38 - 0
editor/js/libs/codemirror/addon/show-hint.css

@@ -0,0 +1,38 @@
+.CodeMirror-hints {
+  position: absolute;
+  z-index: 10;
+  overflow: hidden;
+  list-style: none;
+
+  margin: 0;
+  padding: 2px;
+
+  -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
+  -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
+  box-shadow: 2px 3px 5px rgba(0,0,0,.2);
+  border-radius: 3px;
+  border: 1px solid silver;
+
+  background: white;
+  font-size: 90%;
+  font-family: monospace;
+
+  max-height: 20em;
+  overflow-y: auto;
+}
+
+.CodeMirror-hint {
+  margin: 0;
+  padding: 0 4px;
+  border-radius: 2px;
+  max-width: 19em;
+  overflow: hidden;
+  white-space: pre;
+  color: black;
+  cursor: pointer;
+}
+
+li.CodeMirror-hint-active {
+  background: #08f;
+  color: white;
+}

+ 383 - 0
editor/js/libs/codemirror/addon/show-hint.js

@@ -0,0 +1,383 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+  "use strict";
+
+  var HINT_ELEMENT_CLASS        = "CodeMirror-hint";
+  var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active";
+
+  // This is the old interface, kept around for now to stay
+  // backwards-compatible.
+  CodeMirror.showHint = function(cm, getHints, options) {
+    if (!getHints) return cm.showHint(options);
+    if (options && options.async) getHints.async = true;
+    var newOpts = {hint: getHints};
+    if (options) for (var prop in options) newOpts[prop] = options[prop];
+    return cm.showHint(newOpts);
+  };
+
+  CodeMirror.defineExtension("showHint", function(options) {
+    // We want a single cursor position.
+    if (this.listSelections().length > 1 || this.somethingSelected()) return;
+
+    if (this.state.completionActive) this.state.completionActive.close();
+    var completion = this.state.completionActive = new Completion(this, options);
+    if (!completion.options.hint) return;
+
+    CodeMirror.signal(this, "startCompletion", this);
+    completion.update(true);
+  });
+
+  function Completion(cm, options) {
+    this.cm = cm;
+    this.options = this.buildOptions(options);
+    this.widget = null;
+    this.debounce = 0;
+    this.tick = 0;
+    this.startPos = this.cm.getCursor();
+    this.startLen = this.cm.getLine(this.startPos.line).length;
+
+    var self = this;
+    cm.on("cursorActivity", this.activityFunc = function() { self.cursorActivity(); });
+  }
+
+  var requestAnimationFrame = window.requestAnimationFrame || function(fn) {
+    return setTimeout(fn, 1000/60);
+  };
+  var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;
+
+  Completion.prototype = {
+    close: function() {
+      if (!this.active()) return;
+      this.cm.state.completionActive = null;
+      this.tick = null;
+      this.cm.off("cursorActivity", this.activityFunc);
+
+      if (this.widget && this.data) CodeMirror.signal(this.data, "close");
+      if (this.widget) this.widget.close();
+      CodeMirror.signal(this.cm, "endCompletion", this.cm);
+    },
+
+    active: function() {
+      return this.cm.state.completionActive == this;
+    },
+
+    pick: function(data, i) {
+      var completion = data.list[i];
+      if (completion.hint) completion.hint(this.cm, data, completion);
+      else this.cm.replaceRange(getText(completion), completion.from || data.from,
+                                completion.to || data.to, "complete");
+      CodeMirror.signal(data, "pick", completion);
+      this.close();
+    },
+
+    cursorActivity: function() {
+      if (this.debounce) {
+        cancelAnimationFrame(this.debounce);
+        this.debounce = 0;
+      }
+
+      var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line);
+      if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch ||
+          pos.ch < this.startPos.ch || this.cm.somethingSelected() ||
+          (pos.ch && this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) {
+        this.close();
+      } else {
+        var self = this;
+        this.debounce = requestAnimationFrame(function() {self.update();});
+        if (this.widget) this.widget.disable();
+      }
+    },
+
+    update: function(first) {
+      if (this.tick == null) return;
+      if (this.data) CodeMirror.signal(this.data, "update");
+      if (!this.options.hint.async) {
+        this.finishUpdate(this.options.hint(this.cm, this.options), first);
+      } else {
+        var myTick = ++this.tick, self = this;
+        this.options.hint(this.cm, function(data) {
+          if (self.tick == myTick) self.finishUpdate(data, first);
+        }, this.options);
+      }
+    },
+
+    finishUpdate: function(data, first) {
+      this.data = data;
+
+      var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle);
+      if (this.widget) this.widget.close();
+      if (data && data.list.length) {
+        if (picked && data.list.length == 1) {
+          this.pick(data, 0);
+        } else {
+          this.widget = new Widget(this, data);
+          CodeMirror.signal(data, "shown");
+        }
+      }
+    },
+
+    buildOptions: function(options) {
+      var editor = this.cm.options.hintOptions;
+      var out = {};
+      for (var prop in defaultOptions) out[prop] = defaultOptions[prop];
+      if (editor) for (var prop in editor)
+        if (editor[prop] !== undefined) out[prop] = editor[prop];
+      if (options) for (var prop in options)
+        if (options[prop] !== undefined) out[prop] = options[prop];
+      return out;
+    }
+  };
+
+  function getText(completion) {
+    if (typeof completion == "string") return completion;
+    else return completion.text;
+  }
+
+  function buildKeyMap(completion, handle) {
+    var baseMap = {
+      Up: function() {handle.moveFocus(-1);},
+      Down: function() {handle.moveFocus(1);},
+      PageUp: function() {handle.moveFocus(-handle.menuSize() + 1, true);},
+      PageDown: function() {handle.moveFocus(handle.menuSize() - 1, true);},
+      Home: function() {handle.setFocus(0);},
+      End: function() {handle.setFocus(handle.length - 1);},
+      Enter: handle.pick,
+      Tab: handle.pick,
+      Esc: handle.close
+    };
+    var custom = completion.options.customKeys;
+    var ourMap = custom ? {} : baseMap;
+    function addBinding(key, val) {
+      var bound;
+      if (typeof val != "string")
+        bound = function(cm) { return val(cm, handle); };
+      // This mechanism is deprecated
+      else if (baseMap.hasOwnProperty(val))
+        bound = baseMap[val];
+      else
+        bound = val;
+      ourMap[key] = bound;
+    }
+    if (custom)
+      for (var key in custom) if (custom.hasOwnProperty(key))
+        addBinding(key, custom[key]);
+    var extra = completion.options.extraKeys;
+    if (extra)
+      for (var key in extra) if (extra.hasOwnProperty(key))
+        addBinding(key, extra[key]);
+    return ourMap;
+  }
+
+  function getHintElement(hintsElement, el) {
+    while (el && el != hintsElement) {
+      if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el;
+      el = el.parentNode;
+    }
+  }
+
+  function Widget(completion, data) {
+    this.completion = completion;
+    this.data = data;
+    this.picked = false;
+    var widget = this, cm = completion.cm;
+
+    var hints = this.hints = document.createElement("ul");
+    hints.className = "CodeMirror-hints";
+    this.selectedHint = data.selectedHint || 0;
+
+    var completions = data.list;
+    for (var i = 0; i < completions.length; ++i) {
+      var elt = hints.appendChild(document.createElement("li")), cur = completions[i];
+      var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS);
+      if (cur.className != null) className = cur.className + " " + className;
+      elt.className = className;
+      if (cur.render) cur.render(elt, data, cur);
+      else elt.appendChild(document.createTextNode(cur.displayText || getText(cur)));
+      elt.hintId = i;
+    }
+
+    var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null);
+    var left = pos.left, top = pos.bottom, below = true;
+    hints.style.left = left + "px";
+    hints.style.top = top + "px";
+    // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor.
+    var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth);
+    var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight);
+    (completion.options.container || document.body).appendChild(hints);
+    var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH;
+    if (overlapY > 0) {
+      var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top);
+      if (curTop - height > 0) { // Fits above cursor
+        hints.style.top = (top = pos.top - height) + "px";
+        below = false;
+      } else if (height > winH) {
+        hints.style.height = (winH - 5) + "px";
+        hints.style.top = (top = pos.bottom - box.top) + "px";
+        var cursor = cm.getCursor();
+        if (data.from.ch != cursor.ch) {
+          pos = cm.cursorCoords(cursor);
+          hints.style.left = (left = pos.left) + "px";
+          box = hints.getBoundingClientRect();
+        }
+      }
+    }
+    var overlapX = box.right - winW;
+    if (overlapX > 0) {
+      if (box.right - box.left > winW) {
+        hints.style.width = (winW - 5) + "px";
+        overlapX -= (box.right - box.left) - winW;
+      }
+      hints.style.left = (left = pos.left - overlapX) + "px";
+    }
+
+    cm.addKeyMap(this.keyMap = buildKeyMap(completion, {
+      moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); },
+      setFocus: function(n) { widget.changeActive(n); },
+      menuSize: function() { return widget.screenAmount(); },
+      length: completions.length,
+      close: function() { completion.close(); },
+      pick: function() { widget.pick(); },
+      data: data
+    }));
+
+    if (completion.options.closeOnUnfocus) {
+      var closingOnBlur;
+      cm.on("blur", this.onBlur = function() { closingOnBlur = setTimeout(function() { completion.close(); }, 100); });
+      cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); });
+    }
+
+    var startScroll = cm.getScrollInfo();
+    cm.on("scroll", this.onScroll = function() {
+      var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect();
+      var newTop = top + startScroll.top - curScroll.top;
+      var point = newTop - (window.pageYOffset || (document.documentElement || document.body).scrollTop);
+      if (!below) point += hints.offsetHeight;
+      if (point <= editor.top || point >= editor.bottom) return completion.close();
+      hints.style.top = newTop + "px";
+      hints.style.left = (left + startScroll.left - curScroll.left) + "px";
+    });
+
+    CodeMirror.on(hints, "dblclick", function(e) {
+      var t = getHintElement(hints, e.target || e.srcElement);
+      if (t && t.hintId != null) {widget.changeActive(t.hintId); widget.pick();}
+    });
+
+    CodeMirror.on(hints, "click", function(e) {
+      var t = getHintElement(hints, e.target || e.srcElement);
+      if (t && t.hintId != null) {
+        widget.changeActive(t.hintId);
+        if (completion.options.completeOnSingleClick) widget.pick();
+      }
+    });
+
+    CodeMirror.on(hints, "mousedown", function() {
+      setTimeout(function(){cm.focus();}, 20);
+    });
+
+    CodeMirror.signal(data, "select", completions[0], hints.firstChild);
+    return true;
+  }
+
+  Widget.prototype = {
+    close: function() {
+      if (this.completion.widget != this) return;
+      this.completion.widget = null;
+      this.hints.parentNode.removeChild(this.hints);
+      this.completion.cm.removeKeyMap(this.keyMap);
+
+      var cm = this.completion.cm;
+      if (this.completion.options.closeOnUnfocus) {
+        cm.off("blur", this.onBlur);
+        cm.off("focus", this.onFocus);
+      }
+      cm.off("scroll", this.onScroll);
+    },
+
+    disable: function() {
+      this.completion.cm.removeKeyMap(this.keyMap);
+      var widget = this;
+      this.keyMap = {Enter: function() { widget.picked = true; }};
+      this.completion.cm.addKeyMap(this.keyMap);
+    },
+
+    pick: function() {
+      this.completion.pick(this.data, this.selectedHint);
+    },
+
+    changeActive: function(i, avoidWrap) {
+      if (i >= this.data.list.length)
+        i = avoidWrap ? this.data.list.length - 1 : 0;
+      else if (i < 0)
+        i = avoidWrap ? 0  : this.data.list.length - 1;
+      if (this.selectedHint == i) return;
+      var node = this.hints.childNodes[this.selectedHint];
+      node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, "");
+      node = this.hints.childNodes[this.selectedHint = i];
+      node.className += " " + ACTIVE_HINT_ELEMENT_CLASS;
+      if (node.offsetTop < this.hints.scrollTop)
+        this.hints.scrollTop = node.offsetTop - 3;
+      else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight)
+        this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3;
+      CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node);
+    },
+
+    screenAmount: function() {
+      return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1;
+    }
+  };
+
+  CodeMirror.registerHelper("hint", "auto", function(cm, options) {
+    var helpers = cm.getHelpers(cm.getCursor(), "hint"), words;
+    if (helpers.length) {
+      for (var i = 0; i < helpers.length; i++) {
+        var cur = helpers[i](cm, options);
+        if (cur && cur.list.length) return cur;
+      }
+    } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) {
+      if (words) return CodeMirror.hint.fromList(cm, {words: words});
+    } else if (CodeMirror.hint.anyword) {
+      return CodeMirror.hint.anyword(cm, options);
+    }
+  });
+
+  CodeMirror.registerHelper("hint", "fromList", function(cm, options) {
+    var cur = cm.getCursor(), token = cm.getTokenAt(cur);
+    var found = [];
+    for (var i = 0; i < options.words.length; i++) {
+      var word = options.words[i];
+      if (word.slice(0, token.string.length) == token.string)
+        found.push(word);
+    }
+
+    if (found.length) return {
+      list: found,
+      from: CodeMirror.Pos(cur.line, token.start),
+            to: CodeMirror.Pos(cur.line, token.end)
+    };
+  });
+
+  CodeMirror.commands.autocomplete = CodeMirror.showHint;
+
+  var defaultOptions = {
+    hint: CodeMirror.hint.auto,
+    completeSingle: true,
+    alignWithWord: true,
+    closeCharacters: /[\s()\[\]{};:>,]/,
+    closeOnUnfocus: true,
+    completeOnSingleClick: false,
+    container: null,
+    customKeys: null,
+    extraKeys: null
+  };
+
+  CodeMirror.defineOption("hintOptions", null);
+});

+ 86 - 0
editor/js/libs/codemirror/addon/tern.css

@@ -0,0 +1,86 @@
+.CodeMirror-Tern-completion {
+  padding-left: 22px;
+  position: relative;
+}
+.CodeMirror-Tern-completion:before {
+  position: absolute;
+  left: 2px;
+  bottom: 2px;
+  border-radius: 50%;
+  font-size: 12px;
+  font-weight: bold;
+  height: 15px;
+  width: 15px;
+  line-height: 16px;
+  text-align: center;
+  color: white;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+}
+.CodeMirror-Tern-completion-unknown:before {
+  content: "?";
+  background: #4bb;
+}
+.CodeMirror-Tern-completion-object:before {
+  content: "O";
+  background: #77c;
+}
+.CodeMirror-Tern-completion-fn:before {
+  content: "F";
+  background: #7c7;
+}
+.CodeMirror-Tern-completion-array:before {
+  content: "A";
+  background: #c66;
+}
+.CodeMirror-Tern-completion-number:before {
+  content: "1";
+  background: #999;
+}
+.CodeMirror-Tern-completion-string:before {
+  content: "S";
+  background: #999;
+}
+.CodeMirror-Tern-completion-bool:before {
+  content: "B";
+  background: #999;
+}
+
+.CodeMirror-Tern-completion-guess {
+  color: #999;
+}
+
+.CodeMirror-Tern-tooltip {
+  border: 1px solid silver;
+  border-radius: 3px;
+  color: #444;
+  padding: 2px 5px;
+  font-size: 90%;
+  font-family: monospace;
+  background-color: white;
+  white-space: pre-wrap;
+
+  max-width: 40em;
+  position: absolute;
+  z-index: 10;
+  -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
+  -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
+  box-shadow: 2px 3px 5px rgba(0,0,0,.2);
+
+  transition: opacity 1s;
+  -moz-transition: opacity 1s;
+  -webkit-transition: opacity 1s;
+  -o-transition: opacity 1s;
+  -ms-transition: opacity 1s;
+}
+
+.CodeMirror-Tern-hint-doc {
+  max-width: 25em;
+  margin-top: -3px;
+}
+
+.CodeMirror-Tern-fname { color: black; }
+.CodeMirror-Tern-farg { color: #70a; }
+.CodeMirror-Tern-farg-current { text-decoration: underline; }
+.CodeMirror-Tern-type { color: #07c; }
+.CodeMirror-Tern-fhint-guess { opacity: .7; }

+ 698 - 0
editor/js/libs/codemirror/addon/tern.js

@@ -0,0 +1,698 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+// Glue code between CodeMirror and Tern.
+//
+// Create a CodeMirror.TernServer to wrap an actual Tern server,
+// register open documents (CodeMirror.Doc instances) with it, and
+// call its methods to activate the assisting functions that Tern
+// provides.
+//
+// Options supported (all optional):
+// * defs: An array of JSON definition data structures.
+// * plugins: An object mapping plugin names to configuration
+//   options.
+// * getFile: A function(name, c) that can be used to access files in
+//   the project that haven't been loaded yet. Simply do c(null) to
+//   indicate that a file is not available.
+// * fileFilter: A function(value, docName, doc) that will be applied
+//   to documents before passing them on to Tern.
+// * switchToDoc: A function(name, doc) that should, when providing a
+//   multi-file view, switch the view or focus to the named file.
+// * showError: A function(editor, message) that can be used to
+//   override the way errors are displayed.
+// * completionTip: Customize the content in tooltips for completions.
+//   Is passed a single argument—the completion's data as returned by
+//   Tern—and may return a string, DOM node, or null to indicate that
+//   no tip should be shown. By default the docstring is shown.
+// * typeTip: Like completionTip, but for the tooltips shown for type
+//   queries.
+// * responseFilter: A function(doc, query, request, error, data) that
+//   will be applied to the Tern responses before treating them
+// * caseInsensitive: boolean to send case insensitive querys to tern
+//
+//
+// It is possible to run the Tern server in a web worker by specifying
+// these additional options:
+// * useWorker: Set to true to enable web worker mode. You'll probably
+//   want to feature detect the actual value you use here, for example
+//   !!window.Worker.
+// * workerScript: The main script of the worker. Point this to
+//   wherever you are hosting worker.js from this directory.
+// * workerDeps: An array of paths pointing (relative to workerScript)
+//   to the Acorn and Tern libraries and any Tern plugins you want to
+//   load. Or, if you minified those into a single script and included
+//   them in the workerScript, simply leave this undefined.
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+  "use strict";
+  // declare global: tern
+
+  CodeMirror.TernServer = function(options) {
+    var self = this;
+    this.options = options || {};
+    var plugins = this.options.plugins || (this.options.plugins = {});
+    if (!plugins.doc_comment) plugins.doc_comment = true;
+    if (this.options.useWorker) {
+      this.server = new WorkerServer(this);
+    } else {
+      this.server = new tern.Server({
+        getFile: function(name, c) { return getFile(self, name, c); },
+        async: true,
+        defs: this.options.defs || [],
+        plugins: plugins
+      });
+    }
+    this.docs = Object.create(null);
+    this.trackChange = function(doc, change) { trackChange(self, doc, change); };
+
+    this.cachedArgHints = null;
+    this.activeArgHints = null;
+    this.jumpStack = [];
+
+    this.getHint = function(cm, c) { return hint(self, cm, c); };
+    this.getHint.async = true;
+  };
+
+  CodeMirror.TernServer.prototype = {
+    addDoc: function(name, doc) {
+      var data = {doc: doc, name: name, changed: null};
+      this.server.addFile(name, docValue(this, data));
+      CodeMirror.on(doc, "change", this.trackChange);
+      return this.docs[name] = data;
+    },
+
+    delDoc: function(id) {
+      var found = resolveDoc(this, id);
+      if (!found) return;
+      CodeMirror.off(found.doc, "change", this.trackChange);
+      delete this.docs[found.name];
+      this.server.delFile(found.name);
+    },
+
+    hideDoc: function(id) {
+      closeArgHints(this);
+      var found = resolveDoc(this, id);
+      if (found && found.changed) sendDoc(this, found);
+    },
+
+    complete: function(cm) {
+      cm.showHint({hint: this.getHint});
+    },
+
+    showType: function(cm, pos, c) { showContextInfo(this, cm, pos, "type", c); },
+
+    showDocs: function(cm, pos, c) { showContextInfo(this, cm, pos, "documentation", c); },
+
+    updateArgHints: function(cm) { updateArgHints(this, cm); },
+
+    jumpToDef: function(cm) { jumpToDef(this, cm); },
+
+    jumpBack: function(cm) { jumpBack(this, cm); },
+
+    rename: function(cm) { rename(this, cm); },
+
+    selectName: function(cm) { selectName(this, cm); },
+
+    request: function (cm, query, c, pos) {
+      var self = this;
+      var doc = findDoc(this, cm.getDoc());
+      var request = buildRequest(this, doc, query, pos);
+
+      this.server.request(request, function (error, data) {
+        if (!error && self.options.responseFilter)
+          data = self.options.responseFilter(doc, query, request, error, data);
+        c(error, data);
+      });
+    },
+
+    destroy: function () {
+      if (this.worker) {
+        this.worker.terminate();
+        this.worker = null;
+      }
+    }
+  };
+
+  var Pos = CodeMirror.Pos;
+  var cls = "CodeMirror-Tern-";
+  var bigDoc = 250;
+
+  function getFile(ts, name, c) {
+    var buf = ts.docs[name];
+    if (buf)
+      c(docValue(ts, buf));
+    else if (ts.options.getFile)
+      ts.options.getFile(name, c);
+    else
+      c(null);
+  }
+
+  function findDoc(ts, doc, name) {
+    for (var n in ts.docs) {
+      var cur = ts.docs[n];
+      if (cur.doc == doc) return cur;
+    }
+    if (!name) for (var i = 0;; ++i) {
+      n = "[doc" + (i || "") + "]";
+      if (!ts.docs[n]) { name = n; break; }
+    }
+    return ts.addDoc(name, doc);
+  }
+
+  function resolveDoc(ts, id) {
+    if (typeof id == "string") return ts.docs[id];
+    if (id instanceof CodeMirror) id = id.getDoc();
+    if (id instanceof CodeMirror.Doc) return findDoc(ts, id);
+  }
+
+  function trackChange(ts, doc, change) {
+    var data = findDoc(ts, doc);
+
+    var argHints = ts.cachedArgHints;
+    if (argHints && argHints.doc == doc && cmpPos(argHints.start, change.to) <= 0)
+      ts.cachedArgHints = null;
+
+    var changed = data.changed;
+    if (changed == null)
+      data.changed = changed = {from: change.from.line, to: change.from.line};
+    var end = change.from.line + (change.text.length - 1);
+    if (change.from.line < changed.to) changed.to = changed.to - (change.to.line - end);
+    if (end >= changed.to) changed.to = end + 1;
+    if (changed.from > change.from.line) changed.from = change.from.line;
+
+    if (doc.lineCount() > bigDoc && change.to - changed.from > 100) setTimeout(function() {
+      if (data.changed && data.changed.to - data.changed.from > 100) sendDoc(ts, data);
+    }, 200);
+  }
+
+  function sendDoc(ts, doc) {
+    ts.server.request({files: [{type: "full", name: doc.name, text: docValue(ts, doc)}]}, function(error) {
+      if (error) window.console.error(error);
+      else doc.changed = null;
+    });
+  }
+
+  // Completion
+
+  function hint(ts, cm, c) {
+    ts.request(cm, {type: "completions", types: true, docs: true, urls: true, caseInsensitive: ts.options.caseInsensitive}, function(error, data) {
+      if (error) return showError(ts, cm, error);
+      var completions = [], after = "";
+      var from = data.start, to = data.end;
+      if (cm.getRange(Pos(from.line, from.ch - 2), from) == "[\"" &&
+          cm.getRange(to, Pos(to.line, to.ch + 2)) != "\"]")
+        after = "\"]";
+
+      for (var i = 0; i < data.completions.length; ++i) {
+        var completion = data.completions[i], className = typeToIcon(completion.type);
+        if (data.guess) className += " " + cls + "guess";
+        completions.push({text: completion.name + after,
+                          displayText: completion.name,
+                          className: className,
+                          data: completion});
+      }
+
+      var obj = {from: from, to: to, list: completions};
+      var tooltip = null;
+      CodeMirror.on(obj, "close", function() { remove(tooltip); });
+      CodeMirror.on(obj, "update", function() { remove(tooltip); });
+      CodeMirror.on(obj, "select", function(cur, node) {
+        remove(tooltip);
+        var content = ts.options.completionTip ? ts.options.completionTip(cur.data) : cur.data.doc;
+        if (content) {
+          tooltip = makeTooltip(node.parentNode.getBoundingClientRect().right + window.pageXOffset,
+                                node.getBoundingClientRect().top + window.pageYOffset, content);
+          tooltip.className += " " + cls + "hint-doc";
+        }
+      });
+      c(obj);
+    });
+  }
+
+  function typeToIcon(type) {
+    var suffix;
+    if (type == "?") suffix = "unknown";
+    else if (type == "number" || type == "string" || type == "bool") suffix = type;
+    else if (/^fn\(/.test(type)) suffix = "fn";
+    else if (/^\[/.test(type)) suffix = "array";
+    else suffix = "object";
+    return cls + "completion " + cls + "completion-" + suffix;
+  }
+
+  // Type queries
+
+  function showContextInfo(ts, cm, pos, queryName, c) {
+    ts.request(cm, queryName, function(error, data) {
+      if (error) return showError(ts, cm, error);
+      if (ts.options.typeTip) {
+        var tip = ts.options.typeTip(data);
+      } else {
+        var tip = elt("span", null, elt("strong", null, data.type || "not found"));
+        if (data.doc)
+          tip.appendChild(document.createTextNode(" — " + data.doc));
+        if (data.url) {
+          tip.appendChild(document.createTextNode(" "));
+          var child = tip.appendChild(elt("a", null, "[docs]"));
+          child.href = data.url;
+          child.target = "_blank";
+        }
+      }
+      tempTooltip(cm, tip);
+      if (c) c();
+    }, pos);
+  }
+
+  // Maintaining argument hints
+
+  function updateArgHints(ts, cm) {
+    closeArgHints(ts);
+
+    if (cm.somethingSelected()) return;
+    var state = cm.getTokenAt(cm.getCursor()).state;
+    var inner = CodeMirror.innerMode(cm.getMode(), state);
+    if (inner.mode.name != "javascript") return;
+    var lex = inner.state.lexical;
+    if (lex.info != "call") return;
+
+    var ch, argPos = lex.pos || 0, tabSize = cm.getOption("tabSize");
+    for (var line = cm.getCursor().line, e = Math.max(0, line - 9), found = false; line >= e; --line) {
+      var str = cm.getLine(line), extra = 0;
+      for (var pos = 0;;) {
+        var tab = str.indexOf("\t", pos);
+        if (tab == -1) break;
+        extra += tabSize - (tab + extra) % tabSize - 1;
+        pos = tab + 1;
+      }
+      ch = lex.column - extra;
+      if (str.charAt(ch) == "(") {found = true; break;}
+    }
+    if (!found) return;
+
+    var start = Pos(line, ch);
+    var cache = ts.cachedArgHints;
+    if (cache && cache.doc == cm.getDoc() && cmpPos(start, cache.start) == 0)
+      return showArgHints(ts, cm, argPos);
+
+    ts.request(cm, {type: "type", preferFunction: true, end: start}, function(error, data) {
+      if (error || !data.type || !(/^fn\(/).test(data.type)) return;
+      ts.cachedArgHints = {
+        start: pos,
+        type: parseFnType(data.type),
+        name: data.exprName || data.name || "fn",
+        guess: data.guess,
+        doc: cm.getDoc()
+      };
+      showArgHints(ts, cm, argPos);
+    });
+  }
+
+  function showArgHints(ts, cm, pos) {
+    closeArgHints(ts);
+
+    var cache = ts.cachedArgHints, tp = cache.type;
+    var tip = elt("span", cache.guess ? cls + "fhint-guess" : null,
+                  elt("span", cls + "fname", cache.name), "(");
+    for (var i = 0; i < tp.args.length; ++i) {
+      if (i) tip.appendChild(document.createTextNode(", "));
+      var arg = tp.args[i];
+      tip.appendChild(elt("span", cls + "farg" + (i == pos ? " " + cls + "farg-current" : ""), arg.name || "?"));
+      if (arg.type != "?") {
+        tip.appendChild(document.createTextNode(":\u00a0"));
+        tip.appendChild(elt("span", cls + "type", arg.type));
+      }
+    }
+    tip.appendChild(document.createTextNode(tp.rettype ? ") ->\u00a0" : ")"));
+    if (tp.rettype) tip.appendChild(elt("span", cls + "type", tp.rettype));
+    var place = cm.cursorCoords(null, "page");
+    ts.activeArgHints = makeTooltip(place.right + 1, place.bottom, tip);
+  }
+
+  function parseFnType(text) {
+    var args = [], pos = 3;
+
+    function skipMatching(upto) {
+      var depth = 0, start = pos;
+      for (;;) {
+        var next = text.charAt(pos);
+        if (upto.test(next) && !depth) return text.slice(start, pos);
+        if (/[{\[\(]/.test(next)) ++depth;
+        else if (/[}\]\)]/.test(next)) --depth;
+        ++pos;
+      }
+    }
+
+    // Parse arguments
+    if (text.charAt(pos) != ")") for (;;) {
+      var name = text.slice(pos).match(/^([^, \(\[\{]+): /);
+      if (name) {
+        pos += name[0].length;
+        name = name[1];
+      }
+      args.push({name: name, type: skipMatching(/[\),]/)});
+      if (text.charAt(pos) == ")") break;
+      pos += 2;
+    }
+
+    var rettype = text.slice(pos).match(/^\) -> (.*)$/);
+
+    return {args: args, rettype: rettype && rettype[1]};
+  }
+
+  // Moving to the definition of something
+
+  function jumpToDef(ts, cm) {
+    function inner(varName) {
+      var req = {type: "definition", variable: varName || null};
+      var doc = findDoc(ts, cm.getDoc());
+      ts.server.request(buildRequest(ts, doc, req), function(error, data) {
+        if (error) return showError(ts, cm, error);
+        if (!data.file && data.url) { window.open(data.url); return; }
+
+        if (data.file) {
+          var localDoc = ts.docs[data.file], found;
+          if (localDoc && (found = findContext(localDoc.doc, data))) {
+            ts.jumpStack.push({file: doc.name,
+                               start: cm.getCursor("from"),
+                               end: cm.getCursor("to")});
+            moveTo(ts, doc, localDoc, found.start, found.end);
+            return;
+          }
+        }
+        showError(ts, cm, "Could not find a definition.");
+      });
+    }
+
+    if (!atInterestingExpression(cm))
+      dialog(cm, "Jump to variable", function(name) { if (name) inner(name); });
+    else
+      inner();
+  }
+
+  function jumpBack(ts, cm) {
+    var pos = ts.jumpStack.pop(), doc = pos && ts.docs[pos.file];
+    if (!doc) return;
+    moveTo(ts, findDoc(ts, cm.getDoc()), doc, pos.start, pos.end);
+  }
+
+  function moveTo(ts, curDoc, doc, start, end) {
+    doc.doc.setSelection(start, end);
+    if (curDoc != doc && ts.options.switchToDoc) {
+      closeArgHints(ts);
+      ts.options.switchToDoc(doc.name, doc.doc);
+    }
+  }
+
+  // The {line,ch} representation of positions makes this rather awkward.
+  function findContext(doc, data) {
+    var before = data.context.slice(0, data.contextOffset).split("\n");
+    var startLine = data.start.line - (before.length - 1);
+    var start = Pos(startLine, (before.length == 1 ? data.start.ch : doc.getLine(startLine).length) - before[0].length);
+
+    var text = doc.getLine(startLine).slice(start.ch);
+    for (var cur = startLine + 1; cur < doc.lineCount() && text.length < data.context.length; ++cur)
+      text += "\n" + doc.getLine(cur);
+    if (text.slice(0, data.context.length) == data.context) return data;
+
+    var cursor = doc.getSearchCursor(data.context, 0, false);
+    var nearest, nearestDist = Infinity;
+    while (cursor.findNext()) {
+      var from = cursor.from(), dist = Math.abs(from.line - start.line) * 10000;
+      if (!dist) dist = Math.abs(from.ch - start.ch);
+      if (dist < nearestDist) { nearest = from; nearestDist = dist; }
+    }
+    if (!nearest) return null;
+
+    if (before.length == 1)
+      nearest.ch += before[0].length;
+    else
+      nearest = Pos(nearest.line + (before.length - 1), before[before.length - 1].length);
+    if (data.start.line == data.end.line)
+      var end = Pos(nearest.line, nearest.ch + (data.end.ch - data.start.ch));
+    else
+      var end = Pos(nearest.line + (data.end.line - data.start.line), data.end.ch);
+    return {start: nearest, end: end};
+  }
+
+  function atInterestingExpression(cm) {
+    var pos = cm.getCursor("end"), tok = cm.getTokenAt(pos);
+    if (tok.start < pos.ch && (tok.type == "comment" || tok.type == "string")) return false;
+    return /[\w)\]]/.test(cm.getLine(pos.line).slice(Math.max(pos.ch - 1, 0), pos.ch + 1));
+  }
+
+  // Variable renaming
+
+  function rename(ts, cm) {
+    var token = cm.getTokenAt(cm.getCursor());
+    if (!/\w/.test(token.string)) return showError(ts, cm, "Not at a variable");
+    dialog(cm, "New name for " + token.string, function(newName) {
+      ts.request(cm, {type: "rename", newName: newName, fullDocs: true}, function(error, data) {
+        if (error) return showError(ts, cm, error);
+        applyChanges(ts, data.changes);
+      });
+    });
+  }
+
+  function selectName(ts, cm) {
+    var name = findDoc(ts, cm.doc).name;
+    ts.request(cm, {type: "refs"}, function(error, data) {
+      if (error) return showError(ts, cm, error);
+      var ranges = [], cur = 0;
+      for (var i = 0; i < data.refs.length; i++) {
+        var ref = data.refs[i];
+        if (ref.file == name) {
+          ranges.push({anchor: ref.start, head: ref.end});
+          if (cmpPos(cur, ref.start) >= 0 && cmpPos(cur, ref.end) <= 0)
+            cur = ranges.length - 1;
+        }
+      }
+      cm.setSelections(ranges, cur);
+    });
+  }
+
+  var nextChangeOrig = 0;
+  function applyChanges(ts, changes) {
+    var perFile = Object.create(null);
+    for (var i = 0; i < changes.length; ++i) {
+      var ch = changes[i];
+      (perFile[ch.file] || (perFile[ch.file] = [])).push(ch);
+    }
+    for (var file in perFile) {
+      var known = ts.docs[file], chs = perFile[file];;
+      if (!known) continue;
+      chs.sort(function(a, b) { return cmpPos(b.start, a.start); });
+      var origin = "*rename" + (++nextChangeOrig);
+      for (var i = 0; i < chs.length; ++i) {
+        var ch = chs[i];
+        known.doc.replaceRange(ch.text, ch.start, ch.end, origin);
+      }
+    }
+  }
+
+  // Generic request-building helper
+
+  function buildRequest(ts, doc, query, pos) {
+    var files = [], offsetLines = 0, allowFragments = !query.fullDocs;
+    if (!allowFragments) delete query.fullDocs;
+    if (typeof query == "string") query = {type: query};
+    query.lineCharPositions = true;
+    if (query.end == null) {
+      query.end = pos || doc.doc.getCursor("end");
+      if (doc.doc.somethingSelected())
+        query.start = doc.doc.getCursor("start");
+    }
+    var startPos = query.start || query.end;
+
+    if (doc.changed) {
+      if (doc.doc.lineCount() > bigDoc && allowFragments !== false &&
+          doc.changed.to - doc.changed.from < 100 &&
+          doc.changed.from <= startPos.line && doc.changed.to > query.end.line) {
+        files.push(getFragmentAround(doc, startPos, query.end));
+        query.file = "#0";
+        var offsetLines = files[0].offsetLines;
+        if (query.start != null) query.start = Pos(query.start.line - -offsetLines, query.start.ch);
+        query.end = Pos(query.end.line - offsetLines, query.end.ch);
+      } else {
+        files.push({type: "full",
+                    name: doc.name,
+                    text: docValue(ts, doc)});
+        query.file = doc.name;
+        doc.changed = null;
+      }
+    } else {
+      query.file = doc.name;
+    }
+    for (var name in ts.docs) {
+      var cur = ts.docs[name];
+      if (cur.changed && cur != doc) {
+        files.push({type: "full", name: cur.name, text: docValue(ts, cur)});
+        cur.changed = null;
+      }
+    }
+
+    return {query: query, files: files};
+  }
+
+  function getFragmentAround(data, start, end) {
+    var doc = data.doc;
+    var minIndent = null, minLine = null, endLine, tabSize = 4;
+    for (var p = start.line - 1, min = Math.max(0, p - 50); p >= min; --p) {
+      var line = doc.getLine(p), fn = line.search(/\bfunction\b/);
+      if (fn < 0) continue;
+      var indent = CodeMirror.countColumn(line, null, tabSize);
+      if (minIndent != null && minIndent <= indent) continue;
+      minIndent = indent;
+      minLine = p;
+    }
+    if (minLine == null) minLine = min;
+    var max = Math.min(doc.lastLine(), end.line + 20);
+    if (minIndent == null || minIndent == CodeMirror.countColumn(doc.getLine(start.line), null, tabSize))
+      endLine = max;
+    else for (endLine = end.line + 1; endLine < max; ++endLine) {
+      var indent = CodeMirror.countColumn(doc.getLine(endLine), null, tabSize);
+      if (indent <= minIndent) break;
+    }
+    var from = Pos(minLine, 0);
+
+    return {type: "part",
+            name: data.name,
+            offsetLines: from.line,
+            text: doc.getRange(from, Pos(endLine, 0))};
+  }
+
+  // Generic utilities
+
+  var cmpPos = CodeMirror.cmpPos;
+
+  function elt(tagname, cls /*, ... elts*/) {
+    var e = document.createElement(tagname);
+    if (cls) e.className = cls;
+    for (var i = 2; i < arguments.length; ++i) {
+      var elt = arguments[i];
+      if (typeof elt == "string") elt = document.createTextNode(elt);
+      e.appendChild(elt);
+    }
+    return e;
+  }
+
+  function dialog(cm, text, f) {
+    if (cm.openDialog)
+      cm.openDialog(text + ": <input type=text>", f);
+    else
+      f(prompt(text, ""));
+  }
+
+  // Tooltips
+
+  function tempTooltip(cm, content) {
+    if (cm.state.ternTooltip) remove(cm.state.ternTooltip);
+    var where = cm.cursorCoords();
+    var tip = cm.state.ternTooltip = makeTooltip(where.right + 1, where.bottom, content);
+    function maybeClear() {
+      old = true;
+      if (!mouseOnTip) clear();
+    }
+    function clear() {
+      cm.state.ternTooltip = null;
+      if (!tip.parentNode) return;
+      cm.off("cursorActivity", clear);
+      cm.off('blur', clear);
+      cm.off('scroll', clear);
+      fadeOut(tip);
+    }
+    var mouseOnTip = false, old = false;
+    CodeMirror.on(tip, "mousemove", function() { mouseOnTip = true; });
+    CodeMirror.on(tip, "mouseout", function(e) {
+      if (!CodeMirror.contains(tip, e.relatedTarget || e.toElement)) {
+        if (old) clear();
+        else mouseOnTip = false;
+      }
+    });
+    setTimeout(maybeClear, 1700);
+    cm.on("cursorActivity", clear);
+    cm.on('blur', clear);
+    cm.on('scroll', clear);
+  }
+
+  function makeTooltip(x, y, content) {
+    var node = elt("div", cls + "tooltip", content);
+    node.style.left = x + "px";
+    node.style.top = y + "px";
+    document.body.appendChild(node);
+    return node;
+  }
+
+  function remove(node) {
+    var p = node && node.parentNode;
+    if (p) p.removeChild(node);
+  }
+
+  function fadeOut(tooltip) {
+    tooltip.style.opacity = "0";
+    setTimeout(function() { remove(tooltip); }, 1100);
+  }
+
+  function showError(ts, cm, msg) {
+    if (ts.options.showError)
+      ts.options.showError(cm, msg);
+    else
+      tempTooltip(cm, String(msg));
+  }
+
+  function closeArgHints(ts) {
+    if (ts.activeArgHints) { remove(ts.activeArgHints); ts.activeArgHints = null; }
+  }
+
+  function docValue(ts, doc) {
+    var val = doc.doc.getValue();
+    if (ts.options.fileFilter) val = ts.options.fileFilter(val, doc.name, doc.doc);
+    return val;
+  }
+
+  // Worker wrapper
+
+  function WorkerServer(ts) {
+    var worker = ts.worker = new Worker(ts.options.workerScript);
+    worker.postMessage({type: "init",
+                        defs: ts.options.defs,
+                        plugins: ts.options.plugins,
+                        scripts: ts.options.workerDeps});
+    var msgId = 0, pending = {};
+
+    function send(data, c) {
+      if (c) {
+        data.id = ++msgId;
+        pending[msgId] = c;
+      }
+      worker.postMessage(data);
+    }
+    worker.onmessage = function(e) {
+      var data = e.data;
+      if (data.type == "getFile") {
+        getFile(ts, data.name, function(err, text) {
+          send({type: "getFile", err: String(err), text: text, id: data.id});
+        });
+      } else if (data.type == "debug") {
+        window.console.log(data.message);
+      } else if (data.id && pending[data.id]) {
+        pending[data.id](data.err, data.body);
+        delete pending[data.id];
+      }
+    };
+    worker.onerror = function(e) {
+      for (var id in pending) pending[id](e);
+      pending = {};
+    };
+
+    this.addFile = function(name, text) { send({type: "add", name: name, text: text}); };
+    this.delFile = function(name) { send({type: "del", name: name}); };
+    this.request = function(body, c) { send({type: "req", body: body}, c); };
+  }
+});

File diff suppressed because it is too large
+ 276 - 0
editor/js/libs/tern-threejs/threejs.js


+ 87 - 0
editor/js/libs/ternjs/comment.js

@@ -0,0 +1,87 @@
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    return mod(exports);
+  if (typeof define == "function" && define.amd) // AMD
+    return define(["exports"], mod);
+  mod(tern.comment || (tern.comment = {}));
+})(function(exports) {
+  function isSpace(ch) {
+    return (ch < 14 && ch > 8) || ch === 32 || ch === 160;
+  }
+
+  function onOwnLine(text, pos) {
+    for (; pos > 0; --pos) {
+      var ch = text.charCodeAt(pos - 1);
+      if (ch == 10) break;
+      if (!isSpace(ch)) return false;
+    }
+    return true;
+  }
+
+  // Gather comments directly before a function
+  exports.commentsBefore = function(text, pos) {
+    var found = null, emptyLines = 0, topIsLineComment;
+    out: while (pos > 0) {
+      var prev = text.charCodeAt(pos - 1);
+      if (prev == 10) {
+        for (var scan = --pos, sawNonWS = false; scan > 0; --scan) {
+          prev = text.charCodeAt(scan - 1);
+          if (prev == 47 && text.charCodeAt(scan - 2) == 47) {
+            if (!onOwnLine(text, scan - 2)) break out;
+            var content = text.slice(scan, pos);
+            if (!emptyLines && topIsLineComment) found[0] = content + "\n" + found[0];
+            else (found || (found = [])).unshift(content);
+            topIsLineComment = true;
+            emptyLines = 0;
+            pos = scan - 2;
+            break;
+          } else if (prev == 10) {
+            if (!sawNonWS && ++emptyLines > 1) break out;
+            break;
+          } else if (!sawNonWS && !isSpace(prev)) {
+            sawNonWS = true;
+          }
+        }
+      } else if (prev == 47 && text.charCodeAt(pos - 2) == 42) {
+        for (var scan = pos - 2; scan > 1; --scan) {
+          if (text.charCodeAt(scan - 1) == 42 && text.charCodeAt(scan - 2) == 47) {
+            if (!onOwnLine(text, scan - 2)) break out;
+            (found || (found = [])).unshift(text.slice(scan, pos - 2));
+            topIsLineComment = false;
+            emptyLines = 0;
+            break;
+          }
+        }
+        pos = scan - 2;
+      } else if (isSpace(prev)) {
+        --pos;
+      } else {
+        break;
+      }
+    }
+    return found;
+  };
+
+  exports.commentAfter = function(text, pos) {
+    while (pos < text.length) {
+      var next = text.charCodeAt(pos);
+      if (next == 47) {
+        var after = text.charCodeAt(pos + 1), end;
+        if (after == 47) // line comment
+          end = text.indexOf("\n", pos + 2);
+        else if (after == 42) // block comment
+          end = text.indexOf("*/", pos + 2);
+        else
+          return;
+        return text.slice(pos + 2, end < 0 ? text.length : end);
+      } else if (isSpace(next)) {
+        ++pos;
+      }
+    }
+  };
+
+  exports.ensureCommentsBefore = function(text, node) {
+    if (node.hasOwnProperty("commentsBefore")) return node.commentsBefore;
+    return node.commentsBefore = exports.commentsBefore(text, node.start);
+  };
+});

+ 589 - 0
editor/js/libs/ternjs/def.js

@@ -0,0 +1,589 @@
+// Type description parser
+//
+// Type description JSON files (such as ecma5.json and browser.json)
+// are used to
+//
+// A) describe types that come from native code
+//
+// B) to cheaply load the types for big libraries, or libraries that
+//    can't be inferred well
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    return exports.init = mod;
+  if (typeof define == "function" && define.amd) // AMD
+    return define({init: mod});
+  tern.def = {init: mod};
+})(function(exports, infer) {
+  "use strict";
+
+  function hop(obj, prop) {
+    return Object.prototype.hasOwnProperty.call(obj, prop);
+  }
+
+  var TypeParser = exports.TypeParser = function(spec, start, base, forceNew) {
+    this.pos = start || 0;
+    this.spec = spec;
+    this.base = base;
+    this.forceNew = forceNew;
+  };
+
+  function unwrapType(type, self, args) {
+    return type.call ? type(self, args) : type;
+  }
+
+  function extractProp(type, prop) {
+    if (prop == "!ret") {
+      if (type.retval) return type.retval;
+      var rv = new infer.AVal;
+      type.propagate(new infer.IsCallee(infer.ANull, [], null, rv));
+      return rv;
+    } else {
+      return type.getProp(prop);
+    }
+  }
+
+  function computedFunc(args, retType) {
+    return function(self, cArgs) {
+      var realArgs = [];
+      for (var i = 0; i < args.length; i++) realArgs.push(unwrapType(args[i], self, cArgs));
+      return new infer.Fn(name, infer.ANull, realArgs, unwrapType(retType, self, cArgs));
+    };
+  }
+  function computedUnion(types) {
+    return function(self, args) {
+      var union = new infer.AVal;
+      for (var i = 0; i < types.length; i++) unwrapType(types[i], self, args).propagate(union);
+      return union;
+    };
+  }
+  function computedArray(inner) {
+    return function(self, args) {
+      return new infer.Arr(inner(self, args));
+    };
+  }
+
+  TypeParser.prototype = {
+    eat: function(str) {
+      if (str.length == 1 ? this.spec.charAt(this.pos) == str : this.spec.indexOf(str, this.pos) == this.pos) {
+        this.pos += str.length;
+        return true;
+      }
+    },
+    word: function(re) {
+      var word = "", ch, re = re || /[\w$]/;
+      while ((ch = this.spec.charAt(this.pos)) && re.test(ch)) { word += ch; ++this.pos; }
+      return word;
+    },
+    error: function() {
+      throw new Error("Unrecognized type spec: " + this.spec + " (at " + this.pos + ")");
+    },
+    parseFnType: function(comp, name, top) {
+      var args = [], names = [], computed = false;
+      if (!this.eat(")")) for (var i = 0; ; ++i) {
+        var colon = this.spec.indexOf(": ", this.pos), argname;
+        if (colon != -1) {
+          argname = this.spec.slice(this.pos, colon);
+          if (/^[$\w?]+$/.test(argname))
+            this.pos = colon + 2;
+          else
+            argname = null;
+        }
+        names.push(argname);
+        var argType = this.parseType(comp);
+        if (argType.call) computed = true;
+        args.push(argType);
+        if (!this.eat(", ")) {
+          this.eat(")") || this.error();
+          break;
+        }
+      }
+      var retType, computeRet, computeRetStart, fn;
+      if (this.eat(" -> ")) {
+        var retStart = this.pos;
+        retType = this.parseType(true);
+        if (retType.call) {
+          if (top) {
+            computeRet = retType;
+            retType = infer.ANull;
+            computeRetStart = retStart;
+          } else {
+            computed = true;
+          }
+        }
+      } else {
+        retType = infer.ANull;
+      }
+      if (computed) return computedFunc(args, retType);
+
+      if (top && (fn = this.base))
+        infer.Fn.call(this.base, name, infer.ANull, args, names, retType);
+      else
+        fn = new infer.Fn(name, infer.ANull, args, names, retType);
+      if (computeRet) fn.computeRet = computeRet;
+      if (computeRetStart != null) fn.computeRetSource = this.spec.slice(computeRetStart, this.pos);
+      return fn;
+    },
+    parseType: function(comp, name, top) {
+      var main = this.parseTypeMaybeProp(comp, name, top);
+      if (!this.eat("|")) return main;
+      var types = [main], computed = main.call;
+      for (;;) {
+        var next = this.parseTypeMaybeProp(comp, name, top);
+        types.push(next);
+        if (next.call) computed = true;
+        if (!this.eat("|")) break;
+      }
+      if (computed) return computedUnion(types);
+      var union = new infer.AVal;
+      for (var i = 0; i < types.length; i++) types[i].propagate(union);
+      return union;
+    },
+    parseTypeMaybeProp: function(comp, name, top) {
+      var result = this.parseTypeInner(comp, name, top);
+      while (comp && this.eat(".")) result = this.extendWithProp(result);
+      return result;
+    },
+    extendWithProp: function(base) {
+      var propName = this.word(/[\w<>$!]/) || this.error();
+      if (base.apply) return function(self, args) {
+        return extractProp(base(self, args), propName);
+      };
+      return extractProp(base, propName);
+    },
+    parseTypeInner: function(comp, name, top) {
+      if (this.eat("fn(")) {
+        return this.parseFnType(comp, name, top);
+      } else if (this.eat("[")) {
+        var inner = this.parseType(comp);
+        this.eat("]") || this.error();
+        if (inner.call) return computedArray(inner);
+        if (top && this.base) {
+          infer.Arr.call(this.base, inner);
+          return this.base;
+        }
+        return new infer.Arr(inner);
+      } else if (this.eat("+")) {
+        var path = this.word(/[\w$<>\.!]/);
+        var base = parsePath(path + ".prototype");
+        var type;
+        if (!(base instanceof infer.Obj)) base = parsePath(path);
+        if (!(base instanceof infer.Obj)) return base;
+        if (comp && this.eat("[")) return this.parsePoly(base);
+        if (top && this.forceNew) return new infer.Obj(base);
+        return infer.getInstance(base);
+      } else if (comp && this.eat("!")) {
+        var arg = this.word(/\d/);
+        if (arg) {
+          arg = Number(arg);
+          return function(_self, args) {return args[arg] || infer.ANull;};
+        } else if (this.eat("this")) {
+          return function(self) {return self;};
+        } else if (this.eat("custom:")) {
+          var fname = this.word(/[\w$]/);
+          return customFunctions[fname] || function() { return infer.ANull; };
+        } else {
+          return this.fromWord("!" + this.word(/[\w$<>\.!]/));
+        }
+      } else if (this.eat("?")) {
+        return infer.ANull;
+      } else {
+        return this.fromWord(this.word(/[\w$<>\.!`]/));
+      }
+    },
+    fromWord: function(spec) {
+      var cx = infer.cx();
+      switch (spec) {
+      case "number": return cx.num;
+      case "string": return cx.str;
+      case "bool": return cx.bool;
+      case "<top>": return cx.topScope;
+      }
+      if (cx.localDefs && spec in cx.localDefs) return cx.localDefs[spec];
+      return parsePath(spec);
+    },
+    parsePoly: function(base) {
+      var propName = "<i>", match;
+      if (match = this.spec.slice(this.pos).match(/^\s*(\w+)\s*=\s*/)) {
+        propName = match[1];
+        this.pos += match[0].length;
+      }
+      var value = this.parseType(true);
+      if (!this.eat("]")) this.error();
+      if (value.call) return function(self, args) {
+        var instance = infer.getInstance(base);
+        value(self, args).propagate(instance.defProp(propName));
+        return instance;
+      };
+      var instance = infer.getInstance(base);
+      value.propagate(instance.defProp(propName));
+      return instance;
+    }
+  };
+
+  function parseType(spec, name, base, forceNew) {
+    var type = new TypeParser(spec, null, base, forceNew).parseType(false, name, true);
+    if (/^fn\(/.test(spec)) for (var i = 0; i < type.args.length; ++i) (function(i) {
+      var arg = type.args[i];
+      if (arg instanceof infer.Fn && arg.args && arg.args.length) addEffect(type, function(_self, fArgs) {
+        var fArg = fArgs[i];
+        if (fArg) fArg.propagate(new infer.IsCallee(infer.cx().topScope, arg.args, null, infer.ANull));
+      });
+    })(i);
+    return type;
+  }
+
+  function addEffect(fn, handler, replaceRet) {
+    var oldCmp = fn.computeRet, rv = fn.retval;
+    fn.computeRet = function(self, args, argNodes) {
+      var handled = handler(self, args, argNodes);
+      var old = oldCmp ? oldCmp(self, args, argNodes) : rv;
+      return replaceRet ? handled : old;
+    };
+  }
+
+  var parseEffect = exports.parseEffect = function(effect, fn) {
+    var m;
+    if (effect.indexOf("propagate ") == 0) {
+      var p = new TypeParser(effect, 10);
+      var origin = p.parseType(true);
+      if (!p.eat(" ")) p.error();
+      var target = p.parseType(true);
+      addEffect(fn, function(self, args) {
+        unwrapType(origin, self, args).propagate(unwrapType(target, self, args));
+      });
+    } else if (effect.indexOf("call ") == 0) {
+      var andRet = effect.indexOf("and return ", 5) == 5;
+      var p = new TypeParser(effect, andRet ? 16 : 5);
+      var getCallee = p.parseType(true), getSelf = null, getArgs = [];
+      if (p.eat(" this=")) getSelf = p.parseType(true);
+      while (p.eat(" ")) getArgs.push(p.parseType(true));
+      addEffect(fn, function(self, args) {
+        var callee = unwrapType(getCallee, self, args);
+        var slf = getSelf ? unwrapType(getSelf, self, args) : infer.ANull, as = [];
+        for (var i = 0; i < getArgs.length; ++i) as.push(unwrapType(getArgs[i], self, args));
+        var result = andRet ? new infer.AVal : infer.ANull;
+        callee.propagate(new infer.IsCallee(slf, as, null, result));
+        return result;
+      }, andRet);
+    } else if (m = effect.match(/^custom (\S+)\s*(.*)/)) {
+      var customFunc = customFunctions[m[1]];
+      if (customFunc) addEffect(fn, m[2] ? customFunc(m[2]) : customFunc);
+    } else if (effect.indexOf("copy ") == 0) {
+      var p = new TypeParser(effect, 5);
+      var getFrom = p.parseType(true);
+      p.eat(" ");
+      var getTo = p.parseType(true);
+      addEffect(fn, function(self, args) {
+        var from = unwrapType(getFrom, self, args), to = unwrapType(getTo, self, args);
+        from.forAllProps(function(prop, val, local) {
+          if (local && prop != "<i>")
+            to.propagate(new infer.PropHasSubset(prop, val));
+        });
+      });
+    } else {
+      throw new Error("Unknown effect type: " + effect);
+    }
+  };
+
+  var currentTopScope;
+
+  var parsePath = exports.parsePath = function(path, scope) {
+    var cx = infer.cx(), cached = cx.paths[path], origPath = path;
+    if (cached != null) return cached;
+    cx.paths[path] = infer.ANull;
+
+    var base = scope || currentTopScope || cx.topScope;
+
+    if (cx.localDefs) for (var name in cx.localDefs) {
+      if (path.indexOf(name) == 0) {
+        if (path == name) return cx.paths[path] = cx.localDefs[path];
+        if (path.charAt(name.length) == ".") {
+          base = cx.localDefs[name];
+          path = path.slice(name.length + 1);
+          break;
+        }
+      }
+    }
+
+    var parts = path.split(".");
+    for (var i = 0; i < parts.length && base != infer.ANull; ++i) {
+      var prop = parts[i];
+      if (prop.charAt(0) == "!") {
+        if (prop == "!proto") {
+          base = (base instanceof infer.Obj && base.proto) || infer.ANull;
+        } else {
+          var fn = base.getFunctionType();
+          if (!fn) {
+            base = infer.ANull;
+          } else if (prop == "!ret") {
+            base = fn.retval && fn.retval.getType(false) || infer.ANull;
+          } else {
+            var arg = fn.args && fn.args[Number(prop.slice(1))];
+            base = (arg && arg.getType(false)) || infer.ANull;
+          }
+        }
+      } else if (base instanceof infer.Obj) {
+        var propVal = (prop == "prototype" && base instanceof infer.Fn) ? base.getProp(prop) : base.props[prop];
+        if (!propVal || propVal.isEmpty())
+          base = infer.ANull;
+        else
+          base = propVal.types[0];
+      }
+    }
+    // Uncomment this to get feedback on your poorly written .json files
+    // if (base == infer.ANull) console.error("bad path: " + origPath + " (" + cx.curOrigin + ")");
+    cx.paths[origPath] = base == infer.ANull ? null : base;
+    return base;
+  };
+
+  function emptyObj(ctor) {
+    var empty = Object.create(ctor.prototype);
+    empty.props = Object.create(null);
+    empty.isShell = true;
+    return empty;
+  }
+
+  function isSimpleAnnotation(spec) {
+    if (!spec["!type"] || /^(fn\(|\[)/.test(spec["!type"])) return false;
+    for (var prop in spec)
+      if (prop != "!type" && prop != "!doc" && prop != "!url" && prop != "!span" && prop != "!data")
+        return false;
+    return true;
+  }
+
+  function passOne(base, spec, path) {
+    if (!base) {
+      var tp = spec["!type"];
+      if (tp) {
+        if (/^fn\(/.test(tp)) base = emptyObj(infer.Fn);
+        else if (tp.charAt(0) == "[") base = emptyObj(infer.Arr);
+        else throw new Error("Invalid !type spec: " + tp);
+      } else if (spec["!stdProto"]) {
+        base = infer.cx().protos[spec["!stdProto"]];
+      } else {
+        base = emptyObj(infer.Obj);
+      }
+      base.name = path;
+    }
+
+    for (var name in spec) if (hop(spec, name) && name.charCodeAt(0) != 33) {
+      var inner = spec[name];
+      if (typeof inner == "string" || isSimpleAnnotation(inner)) continue;
+      var prop = base.defProp(name);
+      passOne(prop.getObjType(), inner, path ? path + "." + name : name).propagate(prop);
+    }
+    return base;
+  }
+
+  function passTwo(base, spec, path) {
+    if (base.isShell) {
+      delete base.isShell;
+      var tp = spec["!type"];
+      if (tp) {
+        parseType(tp, path, base);
+      } else {
+        var proto = spec["!proto"] && parseType(spec["!proto"]);
+        infer.Obj.call(base, proto instanceof infer.Obj ? proto : true, path);
+      }
+    }
+
+    var effects = spec["!effects"];
+    if (effects && base instanceof infer.Fn) for (var i = 0; i < effects.length; ++i)
+      parseEffect(effects[i], base);
+    copyInfo(spec, base);
+
+    for (var name in spec) if (hop(spec, name) && name.charCodeAt(0) != 33) {
+      var inner = spec[name], known = base.defProp(name), innerPath = path ? path + "." + name : name;
+      if (typeof inner == "string") {
+        if (known.isEmpty()) parseType(inner, innerPath).propagate(known);
+      } else {
+        if (!isSimpleAnnotation(inner))
+          passTwo(known.getObjType(), inner, innerPath);
+        else if (known.isEmpty())
+          parseType(inner["!type"], innerPath, null, true).propagate(known);
+        else
+          continue;
+        if (inner["!doc"]) known.doc = inner["!doc"];
+        if (inner["!url"]) known.url = inner["!url"];
+        if (inner["!span"]) known.span = inner["!span"];
+      }
+    }
+    return base;
+  }
+
+  function copyInfo(spec, type) {
+    if (spec["!doc"]) type.doc = spec["!doc"];
+    if (spec["!url"]) type.url = spec["!url"];
+    if (spec["!span"]) type.span = spec["!span"];
+    if (spec["!data"]) type.metaData = spec["!data"];
+  }
+
+  function runPasses(type, arg) {
+    var parent = infer.cx().parent, pass = parent && parent.passes && parent.passes[type];
+    if (pass) for (var i = 0; i < pass.length; i++) pass[i](arg);
+  }
+
+  function doLoadEnvironment(data, scope) {
+    var cx = infer.cx();
+
+    infer.addOrigin(cx.curOrigin = data["!name"] || "env#" + cx.origins.length);
+    cx.localDefs = cx.definitions[cx.curOrigin] = Object.create(null);
+
+    runPasses("preLoadDef", data);
+
+    passOne(scope, data);
+
+    var def = data["!define"];
+    if (def) {
+      for (var name in def) {
+        var spec = def[name];
+        cx.localDefs[name] = typeof spec == "string" ? parsePath(spec) : passOne(null, spec, name);
+      }
+      for (var name in def) {
+        var spec = def[name];
+        if (typeof spec != "string") passTwo(cx.localDefs[name], def[name], name);
+      }
+    }
+
+    passTwo(scope, data);
+
+    runPasses("postLoadDef", data);
+
+    cx.curOrigin = cx.localDefs = null;
+  }
+
+  exports.load = function(data, scope) {
+    if (!scope) scope = infer.cx().topScope;
+    var oldScope = currentTopScope;
+    currentTopScope = scope;
+    try {
+      doLoadEnvironment(data, scope);
+    } finally {
+      currentTopScope = oldScope;
+    }
+  };
+
+  exports.parse = function(data, origin, path) {
+    var cx = infer.cx();
+    if (origin) {
+      cx.origin = origin;
+      cx.localDefs = cx.definitions[origin];
+    }
+
+    try {
+      if (typeof data == "string")
+        return parseType(data, path);
+      else
+        return passTwo(passOne(null, data, path), data, path);
+    } finally {
+      if (origin) cx.origin = cx.localDefs = null;
+    }
+  };
+
+  // Used to register custom logic for more involved effect or type
+  // computation.
+  var customFunctions = Object.create(null);
+  infer.registerFunction = function(name, f) { customFunctions[name] = f; };
+
+  var IsCreated = infer.constraint("created, target, spec", {
+    addType: function(tp) {
+      if (tp instanceof infer.Obj && this.created++ < 5) {
+        var derived = new infer.Obj(tp), spec = this.spec;
+        if (spec instanceof infer.AVal) spec = spec.getObjType(false);
+        if (spec instanceof infer.Obj) for (var prop in spec.props) {
+          var cur = spec.props[prop].types[0];
+          var p = derived.defProp(prop);
+          if (cur && cur instanceof infer.Obj && cur.props.value) {
+            var vtp = cur.props.value.getType(false);
+            if (vtp) p.addType(vtp);
+          }
+        }
+        this.target.addType(derived);
+      }
+    }
+  });
+
+  infer.registerFunction("Object_create", function(_self, args, argNodes) {
+    if (argNodes && argNodes.length && argNodes[0].type == "Literal" && argNodes[0].value == null)
+      return new infer.Obj();
+
+    var result = new infer.AVal;
+    if (args[0]) args[0].propagate(new IsCreated(0, result, args[1]));
+    return result;
+  });
+
+  var PropSpec = infer.constraint("target", {
+    addType: function(tp) {
+      if (!(tp instanceof infer.Obj)) return;
+      if (tp.hasProp("value"))
+        tp.getProp("value").propagate(this.target);
+      else if (tp.hasProp("get"))
+        tp.getProp("get").propagate(new infer.IsCallee(infer.ANull, [], null, this.target));
+    }
+  });
+
+  infer.registerFunction("Object_defineProperty", function(_self, args, argNodes) {
+    if (argNodes && argNodes.length >= 3 && argNodes[1].type == "Literal" &&
+        typeof argNodes[1].value == "string") {
+      var obj = args[0], connect = new infer.AVal;
+      obj.propagate(new infer.PropHasSubset(argNodes[1].value, connect, argNodes[1]));
+      args[2].propagate(new PropSpec(connect));
+    }
+    return infer.ANull;
+  });
+
+  infer.registerFunction("Object_defineProperties", function(_self, args, argNodes) {
+    if (args.length >= 2) {
+      var obj = args[0];
+      args[1].forAllProps(function(prop, val, local) {
+        if (!local) return;
+        var connect = new infer.AVal;
+        obj.propagate(new infer.PropHasSubset(prop, connect, argNodes && argNodes[1]));
+        val.propagate(new PropSpec(connect));
+      });
+    }
+    return infer.ANull;
+  });
+
+  var IsBound = infer.constraint("self, args, target", {
+    addType: function(tp) {
+      if (!(tp instanceof infer.Fn)) return;
+      this.target.addType(new infer.Fn(tp.name, infer.ANull, tp.args.slice(this.args.length),
+                                       tp.argNames.slice(this.args.length), tp.retval));
+      this.self.propagate(tp.self);
+      for (var i = 0; i < Math.min(tp.args.length, this.args.length); ++i)
+        this.args[i].propagate(tp.args[i]);
+    }
+  });
+
+  infer.registerFunction("Function_bind", function(self, args) {
+    if (!args.length) return infer.ANull;
+    var result = new infer.AVal;
+    self.propagate(new IsBound(args[0], args.slice(1), result));
+    return result;
+  });
+
+  infer.registerFunction("Array_ctor", function(_self, args) {
+    var arr = new infer.Arr;
+    if (args.length != 1 || !args[0].hasType(infer.cx().num)) {
+      var content = arr.getProp("<i>");
+      for (var i = 0; i < args.length; ++i) args[i].propagate(content);
+    }
+    return arr;
+  });
+
+  infer.registerFunction("Promise_ctor", function(_self, args, argNodes) {
+    if (args.length < 1) return infer.ANull;
+    var self = new infer.Obj(infer.cx().definitions.ecma6["Promise.prototype"]);
+    var valProp = self.defProp("value", argNodes && argNodes[0]);
+    var valArg = new infer.AVal;
+    valArg.propagate(valProp);
+    var exec = new infer.Fn("execute", infer.ANull, [valArg], ["value"], infer.ANull);
+    var reject = infer.cx().definitions.ecma6.promiseReject;
+    args[0].propagate(new infer.IsCallee(infer.ANull, [exec, reject], null, infer.ANull));
+    return self;
+  });
+
+  return exports;
+});

+ 402 - 0
editor/js/libs/ternjs/doc_comment.js

@@ -0,0 +1,402 @@
+// Parses comments above variable declarations, function declarations,
+// and object properties as docstrings and JSDoc-style type
+// annotations.
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    return mod(require("../lib/infer"), require("../lib/tern"), require("../lib/comment"),
+               require("acorn"), require("acorn/dist/walk"));
+  if (typeof define == "function" && define.amd) // AMD
+    return define(["../lib/infer", "../lib/tern", "../lib/comment", "acorn/dist/acorn", "acorn/dist/walk"], mod);
+  mod(tern, tern, tern.comment, acorn, acorn.walk);
+})(function(infer, tern, comment, acorn, walk) {
+  "use strict";
+
+  var WG_MADEUP = 1, WG_STRONG = 101;
+
+  tern.registerPlugin("doc_comment", function(server, options) {
+    server.jsdocTypedefs = Object.create(null);
+    server.on("reset", function() {
+      server.jsdocTypedefs = Object.create(null);
+    });
+    server._docComment = {
+      weight: options && options.strong ? WG_STRONG : undefined,
+      fullDocs: options && options.fullDocs
+    };
+
+    return {
+      passes: {
+        postParse: postParse,
+        postInfer: postInfer,
+        postLoadDef: postLoadDef
+      }
+    };
+  });
+
+  function postParse(ast, text) {
+    function attachComments(node) { comment.ensureCommentsBefore(text, node); }
+
+    walk.simple(ast, {
+      VariableDeclaration: attachComments,
+      FunctionDeclaration: attachComments,
+      AssignmentExpression: function(node) {
+        if (node.operator == "=") attachComments(node);
+      },
+      ObjectExpression: function(node) {
+        for (var i = 0; i < node.properties.length; ++i)
+          attachComments(node.properties[i]);
+      },
+      CallExpression: function(node) {
+        if (isDefinePropertyCall(node)) attachComments(node);
+      }
+    });
+  }
+
+  function isDefinePropertyCall(node) {
+    return node.callee.type == "MemberExpression" &&
+      node.callee.object.name == "Object" &&
+      node.callee.property.name == "defineProperty" &&
+      node.arguments.length >= 3 &&
+      typeof node.arguments[1].value == "string";
+  }
+
+  function postInfer(ast, scope) {
+    jsdocParseTypedefs(ast.sourceFile.text, scope);
+
+    walk.simple(ast, {
+      VariableDeclaration: function(node, scope) {
+        if (node.commentsBefore)
+          interpretComments(node, node.commentsBefore, scope,
+                            scope.getProp(node.declarations[0].id.name));
+      },
+      FunctionDeclaration: function(node, scope) {
+        if (node.commentsBefore)
+          interpretComments(node, node.commentsBefore, scope,
+                            scope.getProp(node.id.name),
+                            node.body.scope.fnType);
+      },
+      AssignmentExpression: function(node, scope) {
+        if (node.commentsBefore)
+          interpretComments(node, node.commentsBefore, scope,
+                            infer.expressionType({node: node.left, state: scope}));
+      },
+      ObjectExpression: function(node, scope) {
+        for (var i = 0; i < node.properties.length; ++i) {
+          var prop = node.properties[i];
+          if (prop.commentsBefore)
+            interpretComments(prop, prop.commentsBefore, scope,
+                              node.objType.getProp(prop.key.name));
+        }
+      },
+      CallExpression: function(node, scope) {
+        if (node.commentsBefore && isDefinePropertyCall(node)) {
+          var type = infer.expressionType({node: node.arguments[0], state: scope}).getObjType();
+          if (type && type instanceof infer.Obj) {
+            var prop = type.props[node.arguments[1].value];
+            if (prop) interpretComments(node, node.commentsBefore, scope, prop);
+          }
+        }
+      }
+    }, infer.searchVisitor, scope);
+  }
+
+  function postLoadDef(data) {
+    var defs = data["!typedef"];
+    var cx = infer.cx(), orig = data["!name"];
+    if (defs) for (var name in defs)
+      cx.parent.jsdocTypedefs[name] =
+        maybeInstance(infer.def.parse(defs[name], orig, name), name);
+  }
+
+  // COMMENT INTERPRETATION
+
+  function interpretComments(node, comments, scope, aval, type) {
+    jsdocInterpretComments(node, scope, aval, comments);
+    var cx = infer.cx();
+
+    if (!type && aval instanceof infer.AVal && aval.types.length) {
+      type = aval.types[aval.types.length - 1];
+      if (!(type instanceof infer.Obj) || type.origin != cx.curOrigin || type.doc)
+        type = null;
+    }
+
+    var result = comments[comments.length - 1];
+    if (cx.parent._docComment.fullDocs) {
+      result = result.trim().replace(/\n[ \t]*\* ?/g, "\n");
+    } else {
+      var dot = result.search(/\.\s/);
+      if (dot > 5) result = result.slice(0, dot + 1);
+      result = result.trim().replace(/\s*\n\s*\*\s*|\s{1,}/g, " ");
+    }
+    result = result.replace(/^\s*\*+\s*/, "");
+
+    if (aval instanceof infer.AVal) aval.doc = result;
+    if (type) type.doc = result;
+  }
+
+  // Parses a subset of JSDoc-style comments in order to include the
+  // explicitly defined types in the analysis.
+
+  function skipSpace(str, pos) {
+    while (/\s/.test(str.charAt(pos))) ++pos;
+    return pos;
+  }
+
+  function isIdentifier(string) {
+    if (!acorn.isIdentifierStart(string.charCodeAt(0))) return false;
+    for (var i = 1; i < string.length; i++)
+      if (!acorn.isIdentifierChar(string.charCodeAt(i))) return false;
+    return true;
+  }
+
+  function parseLabelList(scope, str, pos, close) {
+    var labels = [], types = [], madeUp = false;
+    for (var first = true; ; first = false) {
+      pos = skipSpace(str, pos);
+      if (first && str.charAt(pos) == close) break;
+      var colon = str.indexOf(":", pos);
+      if (colon < 0) return null;
+      var label = str.slice(pos, colon);
+      if (!isIdentifier(label)) return null;
+      labels.push(label);
+      pos = colon + 1;
+      var type = parseType(scope, str, pos);
+      if (!type) return null;
+      pos = type.end;
+      madeUp = madeUp || type.madeUp;
+      types.push(type.type);
+      pos = skipSpace(str, pos);
+      var next = str.charAt(pos);
+      ++pos;
+      if (next == close) break;
+      if (next != ",") return null;
+    }
+    return {labels: labels, types: types, end: pos, madeUp: madeUp};
+  }
+
+  function parseType(scope, str, pos) {
+    var type, union = false, madeUp = false;
+    for (;;) {
+      var inner = parseTypeInner(scope, str, pos);
+      if (!inner) return null;
+      madeUp = madeUp || inner.madeUp;
+      if (union) inner.type.propagate(union);
+      else type = inner.type;
+      pos = skipSpace(str, inner.end);
+      if (str.charAt(pos) != "|") break;
+      pos++;
+      if (!union) {
+        union = new infer.AVal;
+        type.propagate(union);
+        type = union;
+      }
+    }
+    var isOptional = false;
+    if (str.charAt(pos) == "=") {
+      ++pos;
+      isOptional = true;
+    }
+    return {type: type, end: pos, isOptional: isOptional, madeUp: madeUp};
+  }
+
+  function parseTypeInner(scope, str, pos) {
+    pos = skipSpace(str, pos);
+    var type, madeUp = false;
+
+    if (str.indexOf("function(", pos) == pos) {
+      var args = parseLabelList(scope, str, pos + 9, ")"), ret = infer.ANull;
+      if (!args) return null;
+      pos = skipSpace(str, args.end);
+      if (str.charAt(pos) == ":") {
+        ++pos;
+        var retType = parseType(scope, str, pos + 1);
+        if (!retType) return null;
+        pos = retType.end;
+        ret = retType.type;
+        madeUp = retType.madeUp;
+      }
+      type = new infer.Fn(null, infer.ANull, args.types, args.labels, ret);
+    } else if (str.charAt(pos) == "[") {
+      var inner = parseType(scope, str, pos + 1);
+      if (!inner) return null;
+      pos = skipSpace(str, inner.end);
+      madeUp = inner.madeUp;
+      if (str.charAt(pos) != "]") return null;
+      ++pos;
+      type = new infer.Arr(inner.type);
+    } else if (str.charAt(pos) == "{") {
+      var fields = parseLabelList(scope, str, pos + 1, "}");
+      if (!fields) return null;
+      type = new infer.Obj(true);
+      for (var i = 0; i < fields.types.length; ++i) {
+        var field = type.defProp(fields.labels[i]);
+        field.initializer = true;
+        fields.types[i].propagate(field);
+      }
+      pos = fields.end;
+      madeUp = fields.madeUp;
+    } else if (str.charAt(pos) == "(") {
+      var inner = parseType(scope, str, pos + 1);
+      if (!inner) return null;
+      pos = skipSpace(str, inner.end);
+      if (str.charAt(pos) != ")") return null;
+      ++pos;
+      type = inner.type;
+    } else {
+      var start = pos;
+      if (!acorn.isIdentifierStart(str.charCodeAt(pos))) return null;
+      while (acorn.isIdentifierChar(str.charCodeAt(pos))) ++pos;
+      if (start == pos) return null;
+      var word = str.slice(start, pos);
+      if (/^(number|integer)$/i.test(word)) type = infer.cx().num;
+      else if (/^bool(ean)?$/i.test(word)) type = infer.cx().bool;
+      else if (/^string$/i.test(word)) type = infer.cx().str;
+      else if (/^(null|undefined)$/i.test(word)) type = infer.ANull;
+      else if (/^array$/i.test(word)) {
+        var inner = null;
+        if (str.charAt(pos) == "." && str.charAt(pos + 1) == "<") {
+          var inAngles = parseType(scope, str, pos + 2);
+          if (!inAngles) return null;
+          pos = skipSpace(str, inAngles.end);
+          madeUp = inAngles.madeUp;
+          if (str.charAt(pos++) != ">") return null;
+          inner = inAngles.type;
+        }
+        type = new infer.Arr(inner);
+      } else if (/^object$/i.test(word)) {
+        type = new infer.Obj(true);
+        if (str.charAt(pos) == "." && str.charAt(pos + 1) == "<") {
+          var key = parseType(scope, str, pos + 2);
+          if (!key) return null;
+          pos = skipSpace(str, key.end);
+          madeUp = madeUp || key.madeUp;
+          if (str.charAt(pos++) != ",") return null;
+          var val = parseType(scope, str, pos);
+          if (!val) return null;
+          pos = skipSpace(str, val.end);
+          madeUp = key.madeUp || val.madeUp;
+          if (str.charAt(pos++) != ">") return null;
+          val.type.propagate(type.defProp("<i>"));
+        }
+      } else {
+        while (str.charCodeAt(pos) == 46 ||
+               acorn.isIdentifierChar(str.charCodeAt(pos))) ++pos;
+        var path = str.slice(start, pos);
+        var cx = infer.cx(), defs = cx.parent && cx.parent.jsdocTypedefs, found;
+        if (defs && (path in defs)) {
+          type = defs[path];
+        } else if (found = infer.def.parsePath(path, scope).getObjType()) {
+          type = maybeInstance(found, path);
+        } else {
+          if (!cx.jsdocPlaceholders) cx.jsdocPlaceholders = Object.create(null);
+          if (!(path in cx.jsdocPlaceholders))
+            type = cx.jsdocPlaceholders[path] = new infer.Obj(null, path);
+          else
+            type = cx.jsdocPlaceholders[path];
+          madeUp = true;
+        }
+      }
+    }
+
+    return {type: type, end: pos, madeUp: madeUp};
+  }
+
+  function maybeInstance(type, path) {
+    if (type instanceof infer.Fn && /^[A-Z]/.test(path)) {
+      var proto = type.getProp("prototype").getObjType();
+      if (proto instanceof infer.Obj) return infer.getInstance(proto);
+    }
+    return type;
+  }
+
+  function parseTypeOuter(scope, str, pos) {
+    pos = skipSpace(str, pos || 0);
+    if (str.charAt(pos) != "{") return null;
+    var result = parseType(scope, str, pos + 1);
+    if (!result) return null;
+    var end = skipSpace(str, result.end);
+    if (str.charAt(end) != "}") return null;
+    result.end = end + 1;
+    return result;
+  }
+
+  function jsdocInterpretComments(node, scope, aval, comments) {
+    var type, args, ret, foundOne, self, parsed;
+
+    for (var i = 0; i < comments.length; ++i) {
+      var comment = comments[i];
+      var decl = /(?:\n|$|\*)\s*@(type|param|arg(?:ument)?|returns?|this)\s+(.*)/g, m;
+      while (m = decl.exec(comment)) {
+        if (m[1] == "this" && (parsed = parseType(scope, m[2], 0))) {
+          self = parsed;
+          foundOne = true;
+          continue;
+        }
+
+        if (!(parsed = parseTypeOuter(scope, m[2]))) continue;
+        foundOne = true;
+
+        switch(m[1]) {
+        case "returns": case "return":
+          ret = parsed; break;
+        case "type":
+          type = parsed; break;
+        case "param": case "arg": case "argument":
+            var name = m[2].slice(parsed.end).match(/^\s*(\[?)\s*([^\]\s=]+)\s*(?:=[^\]]+\s*)?(\]?).*/);
+            if (!name) continue;
+            var argname = name[2] + (parsed.isOptional || (name[1] === '[' && name[3] === ']') ? "?" : "");
+          (args || (args = Object.create(null)))[argname] = parsed;
+          break;
+        }
+      }
+    }
+
+    if (foundOne) applyType(type, self, args, ret, node, aval);
+  };
+
+  function jsdocParseTypedefs(text, scope) {
+    var cx = infer.cx();
+
+    var re = /\s@typedef\s+(.*)/g, m;
+    while (m = re.exec(text)) {
+      var parsed = parseTypeOuter(scope, m[1]);
+      var name = parsed && m[1].slice(parsed.end).match(/^\s*(\S+)/);
+      if (name)
+        cx.parent.jsdocTypedefs[name[1]] = parsed.type;
+    }
+  }
+
+  function propagateWithWeight(type, target) {
+    var weight = infer.cx().parent._docComment.weight;
+    type.type.propagate(target, weight || (type.madeUp ? WG_MADEUP : undefined));
+  }
+
+  function applyType(type, self, args, ret, node, aval) {
+    var fn;
+    if (node.type == "VariableDeclaration") {
+      var decl = node.declarations[0];
+      if (decl.init && decl.init.type == "FunctionExpression") fn = decl.init.body.scope.fnType;
+    } else if (node.type == "FunctionDeclaration") {
+      fn = node.body.scope.fnType;
+    } else if (node.type == "AssignmentExpression") {
+      if (node.right.type == "FunctionExpression")
+        fn = node.right.body.scope.fnType;
+    } else if (node.type == "CallExpression") {
+    } else { // An object property
+      if (node.value.type == "FunctionExpression") fn = node.value.body.scope.fnType;
+    }
+
+    if (fn && (args || ret || self)) {
+      if (args) for (var i = 0; i < fn.argNames.length; ++i) {
+        var name = fn.argNames[i], known = args[name];
+        if (!known && (known = args[name + "?"]))
+          fn.argNames[i] += "?";
+        if (known) propagateWithWeight(known, fn.args[i]);
+      }
+      if (ret) propagateWithWeight(ret, fn.retval);
+      if (self) propagateWithWeight(self, fn.self);
+    } else if (type) {
+      propagateWithWeight(type, aval);
+    }
+  };
+});

+ 1635 - 0
editor/js/libs/ternjs/infer.js

@@ -0,0 +1,1635 @@
+// Main type inference engine
+
+// Walks an AST, building up a graph of abstract values and constraints
+// that cause types to flow from one node to another. Also defines a
+// number of utilities for accessing ASTs and scopes.
+
+// Analysis is done in a context, which is tracked by the dynamically
+// bound cx variable. Use withContext to set the current context.
+
+// For memory-saving reasons, individual types export an interface
+// similar to abstract values (which can hold multiple types), and can
+// thus be used in place abstract values that only ever contain a
+// single type.
+
+(function(root, mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    return mod(exports, require("acorn"), require("acorn/dist/acorn_loose"), require("acorn/dist/walk"),
+               require("./def"), require("./signal"));
+  if (typeof define == "function" && define.amd) // AMD
+    return define(["exports", "acorn/dist/acorn", "acorn/dist/acorn_loose", "acorn/dist/walk", "./def", "./signal"], mod);
+  mod(root.tern || (root.tern = {}), acorn, acorn, acorn.walk, tern.def, tern.signal); // Plain browser env
+})(this, function(exports, acorn, acorn_loose, walk, def, signal) {
+  "use strict";
+
+  var toString = exports.toString = function(type, maxDepth, parent) {
+    if (!type || type == parent || maxDepth && maxDepth < -3) return "?";
+    return type.toString(maxDepth, parent);
+  };
+
+  // A variant of AVal used for unknown, dead-end values. Also serves
+  // as prototype for AVals, Types, and Constraints because it
+  // implements 'empty' versions of all the methods that the code
+  // expects.
+  var ANull = exports.ANull = signal.mixin({
+    addType: function() {},
+    propagate: function() {},
+    getProp: function() { return ANull; },
+    forAllProps: function() {},
+    hasType: function() { return false; },
+    isEmpty: function() { return true; },
+    getFunctionType: function() {},
+    getObjType: function() {},
+    getType: function() {},
+    gatherProperties: function() {},
+    propagatesTo: function() {},
+    typeHint: function() {},
+    propHint: function() {},
+    toString: function() { return "?"; }
+  });
+
+  function extend(proto, props) {
+    var obj = Object.create(proto);
+    if (props) for (var prop in props) obj[prop] = props[prop];
+    return obj;
+  }
+
+  // ABSTRACT VALUES
+
+  var WG_DEFAULT = 100, WG_NEW_INSTANCE = 90, WG_MADEUP_PROTO = 10, WG_MULTI_MEMBER = 5,
+      WG_CATCH_ERROR = 5, WG_GLOBAL_THIS = 90, WG_SPECULATIVE_THIS = 2;
+
+  var AVal = exports.AVal = function() {
+    this.types = [];
+    this.forward = null;
+    this.maxWeight = 0;
+  };
+  AVal.prototype = extend(ANull, {
+    addType: function(type, weight) {
+      weight = weight || WG_DEFAULT;
+      if (this.maxWeight < weight) {
+        this.maxWeight = weight;
+        if (this.types.length == 1 && this.types[0] == type) return;
+        this.types.length = 0;
+      } else if (this.maxWeight > weight || this.types.indexOf(type) > -1) {
+        return;
+      }
+
+      this.signal("addType", type);
+      this.types.push(type);
+      var forward = this.forward;
+      if (forward) withWorklist(function(add) {
+        for (var i = 0; i < forward.length; ++i) add(type, forward[i], weight);
+      });
+    },
+
+    propagate: function(target, weight) {
+      if (target == ANull || (target instanceof Type && this.forward && this.forward.length > 2)) return;
+      if (weight && weight != WG_DEFAULT) target = new Muffle(target, weight);
+      (this.forward || (this.forward = [])).push(target);
+      var types = this.types;
+      if (types.length) withWorklist(function(add) {
+        for (var i = 0; i < types.length; ++i) add(types[i], target, weight);
+      });
+    },
+
+    getProp: function(prop) {
+      if (prop == "__proto__" || prop == "✖") return ANull;
+      var found = (this.props || (this.props = Object.create(null)))[prop];
+      if (!found) {
+        found = this.props[prop] = new AVal;
+        this.propagate(new PropIsSubset(prop, found));
+      }
+      return found;
+    },
+
+    forAllProps: function(c) {
+      this.propagate(new ForAllProps(c));
+    },
+
+    hasType: function(type) {
+      return this.types.indexOf(type) > -1;
+    },
+    isEmpty: function() { return this.types.length === 0; },
+    getFunctionType: function() {
+      for (var i = this.types.length - 1; i >= 0; --i)
+        if (this.types[i] instanceof Fn) return this.types[i];
+    },
+    getObjType: function() {
+      var seen = null;
+      for (var i = this.types.length - 1; i >= 0; --i) {
+        var type = this.types[i];
+        if (!(type instanceof Obj)) continue;
+        if (type.name) return type;
+        if (!seen) seen = type;
+      }
+      return seen;
+    },
+
+    getType: function(guess) {
+      if (this.types.length === 0 && guess !== false) return this.makeupType();
+      if (this.types.length === 1) return this.types[0];
+      return canonicalType(this.types);
+    },
+
+    toString: function(maxDepth, parent) {
+      if (this.types.length == 0) return toString(this.makeupType(), maxDepth, parent);
+      if (this.types.length == 1) return toString(this.types[0], maxDepth, parent);
+      var simplified = simplifyTypes(this.types);
+      if (simplified.length > 2) return "?";
+      return simplified.map(function(tp) { return toString(tp, maxDepth, parent); }).join("|");
+    },
+
+    computedPropType: function() {
+      if (!this.propertyOf) return null;
+      if (this.propertyOf.hasProp("<i>")) {
+        var computedProp = this.propertyOf.getProp("<i>");
+        if (computedProp == this) return null;
+        return computedProp.getType();
+      } else if (this.propertyOf.maybeProps && this.propertyOf.maybeProps["<i>"] == this) {
+        for (var prop in this.propertyOf.props) {
+          var val = this.propertyOf.props[prop];
+          if (!val.isEmpty()) return val;
+        }
+        return null;
+      }
+    },
+
+    makeupType: function() {
+      var computed = this.computedPropType();
+      if (computed) return computed;
+
+      if (!this.forward) return null;
+      for (var i = this.forward.length - 1; i >= 0; --i) {
+        var hint = this.forward[i].typeHint();
+        if (hint && !hint.isEmpty()) {guessing = true; return hint;}
+      }
+
+      var props = Object.create(null), foundProp = null;
+      for (var i = 0; i < this.forward.length; ++i) {
+        var prop = this.forward[i].propHint();
+        if (prop && prop != "length" && prop != "<i>" && prop != "✖" && prop != cx.completingProperty) {
+          props[prop] = true;
+          foundProp = prop;
+        }
+      }
+      if (!foundProp) return null;
+
+      var objs = objsWithProp(foundProp);
+      if (objs) {
+        var matches = [];
+        search: for (var i = 0; i < objs.length; ++i) {
+          var obj = objs[i];
+          for (var prop in props) if (!obj.hasProp(prop)) continue search;
+          if (obj.hasCtor) obj = getInstance(obj);
+          matches.push(obj);
+        }
+        var canon = canonicalType(matches);
+        if (canon) {guessing = true; return canon;}
+      }
+    },
+
+    typeHint: function() { return this.types.length ? this.getType() : null; },
+    propagatesTo: function() { return this; },
+
+    gatherProperties: function(f, depth) {
+      for (var i = 0; i < this.types.length; ++i)
+        this.types[i].gatherProperties(f, depth);
+    },
+
+    guessProperties: function(f) {
+      if (this.forward) for (var i = 0; i < this.forward.length; ++i) {
+        var prop = this.forward[i].propHint();
+        if (prop) f(prop, null, 0);
+      }
+      var guessed = this.makeupType();
+      if (guessed) guessed.gatherProperties(f);
+    }
+  });
+
+  function similarAVal(a, b, depth) {
+    var typeA = a.getType(false), typeB = b.getType(false);
+    if (!typeA || !typeB) return true;
+    return similarType(typeA, typeB, depth);
+  }
+
+  function similarType(a, b, depth) {
+    if (!a || depth >= 5) return b;
+    if (!a || a == b) return a;
+    if (!b) return a;
+    if (a.constructor != b.constructor) return false;
+    if (a.constructor == Arr) {
+      var innerA = a.getProp("<i>").getType(false);
+      if (!innerA) return b;
+      var innerB = b.getProp("<i>").getType(false);
+      if (!innerB || similarType(innerA, innerB, depth + 1)) return b;
+    } else if (a.constructor == Obj) {
+      var propsA = 0, propsB = 0, same = 0;
+      for (var prop in a.props) {
+        propsA++;
+        if (prop in b.props && similarAVal(a.props[prop], b.props[prop], depth + 1))
+          same++;
+      }
+      for (var prop in b.props) propsB++;
+      if (propsA && propsB && same < Math.max(propsA, propsB) / 2) return false;
+      return propsA > propsB ? a : b;
+    } else if (a.constructor == Fn) {
+      if (a.args.length != b.args.length ||
+          !a.args.every(function(tp, i) { return similarAVal(tp, b.args[i], depth + 1); }) ||
+          !similarAVal(a.retval, b.retval, depth + 1) || !similarAVal(a.self, b.self, depth + 1))
+        return false;
+      return a;
+    } else {
+      return false;
+    }
+  }
+
+  var simplifyTypes = exports.simplifyTypes = function(types) {
+    var found = [];
+    outer: for (var i = 0; i < types.length; ++i) {
+      var tp = types[i];
+      for (var j = 0; j < found.length; j++) {
+        var similar = similarType(tp, found[j], 0);
+        if (similar) {
+          found[j] = similar;
+          continue outer;
+        }
+      }
+      found.push(tp);
+    }
+    return found;
+  };
+
+  function canonicalType(types) {
+    var arrays = 0, fns = 0, objs = 0, prim = null;
+    for (var i = 0; i < types.length; ++i) {
+      var tp = types[i];
+      if (tp instanceof Arr) ++arrays;
+      else if (tp instanceof Fn) ++fns;
+      else if (tp instanceof Obj) ++objs;
+      else if (tp instanceof Prim) {
+        if (prim && tp.name != prim.name) return null;
+        prim = tp;
+      }
+    }
+    var kinds = (arrays && 1) + (fns && 1) + (objs && 1) + (prim && 1);
+    if (kinds > 1) return null;
+    if (prim) return prim;
+
+    var maxScore = 0, maxTp = null;
+    for (var i = 0; i < types.length; ++i) {
+      var tp = types[i], score = 0;
+      if (arrays) {
+        score = tp.getProp("<i>").isEmpty() ? 1 : 2;
+      } else if (fns) {
+        score = 1;
+        for (var j = 0; j < tp.args.length; ++j) if (!tp.args[j].isEmpty()) ++score;
+        if (!tp.retval.isEmpty()) ++score;
+      } else if (objs) {
+        score = tp.name ? 100 : 2;
+      }
+      if (score >= maxScore) { maxScore = score; maxTp = tp; }
+    }
+    return maxTp;
+  }
+
+  // PROPAGATION STRATEGIES
+
+  function Constraint() {}
+  Constraint.prototype = extend(ANull, {
+    init: function() { this.origin = cx.curOrigin; }
+  });
+
+  var constraint = exports.constraint = function(props, methods) {
+    var body = "this.init();";
+    props = props ? props.split(", ") : [];
+    for (var i = 0; i < props.length; ++i)
+      body += "this." + props[i] + " = " + props[i] + ";";
+    var ctor = Function.apply(null, props.concat([body]));
+    ctor.prototype = Object.create(Constraint.prototype);
+    for (var m in methods) if (methods.hasOwnProperty(m)) ctor.prototype[m] = methods[m];
+    return ctor;
+  };
+
+  var PropIsSubset = constraint("prop, target", {
+    addType: function(type, weight) {
+      if (type.getProp)
+        type.getProp(this.prop).propagate(this.target, weight);
+    },
+    propHint: function() { return this.prop; },
+    propagatesTo: function() {
+      if (this.prop == "<i>" || !/[^\w_]/.test(this.prop))
+        return {target: this.target, pathExt: "." + this.prop};
+    }
+  });
+
+  var PropHasSubset = exports.PropHasSubset = constraint("prop, type, originNode", {
+    addType: function(type, weight) {
+      if (!(type instanceof Obj)) return;
+      var prop = type.defProp(this.prop, this.originNode);
+      if (!prop.origin) prop.origin = this.origin;
+      this.type.propagate(prop, weight);
+    },
+    propHint: function() { return this.prop; }
+  });
+
+  var ForAllProps = constraint("c", {
+    addType: function(type) {
+      if (!(type instanceof Obj)) return;
+      type.forAllProps(this.c);
+    }
+  });
+
+  function withDisabledComputing(fn, body) {
+    cx.disabledComputing = {fn: fn, prev: cx.disabledComputing};
+    try {
+      return body();
+    } finally {
+      cx.disabledComputing = cx.disabledComputing.prev;
+    }
+  }
+  var IsCallee = exports.IsCallee = constraint("self, args, argNodes, retval", {
+    init: function() {
+      Constraint.prototype.init.call(this);
+      this.disabled = cx.disabledComputing;
+    },
+    addType: function(fn, weight) {
+      if (!(fn instanceof Fn)) return;
+      for (var i = 0; i < this.args.length; ++i) {
+        if (i < fn.args.length) this.args[i].propagate(fn.args[i], weight);
+        if (fn.arguments) this.args[i].propagate(fn.arguments, weight);
+      }
+      this.self.propagate(fn.self, this.self == cx.topScope ? WG_GLOBAL_THIS : weight);
+      var compute = fn.computeRet;
+      if (compute) for (var d = this.disabled; d; d = d.prev)
+        if (d.fn == fn || fn.originNode && d.fn.originNode == fn.originNode) compute = null;
+      if (compute)
+        compute(this.self, this.args, this.argNodes).propagate(this.retval, weight);
+      else
+        fn.retval.propagate(this.retval, weight);
+    },
+    typeHint: function() {
+      var names = [];
+      for (var i = 0; i < this.args.length; ++i) names.push("?");
+      return new Fn(null, this.self, this.args, names, ANull);
+    },
+    propagatesTo: function() {
+      return {target: this.retval, pathExt: ".!ret"};
+    }
+  });
+
+  var HasMethodCall = constraint("propName, args, argNodes, retval", {
+    init: function() {
+      Constraint.prototype.init.call(this);
+      this.disabled = cx.disabledComputing;
+    },
+    addType: function(obj, weight) {
+      var callee = new IsCallee(obj, this.args, this.argNodes, this.retval);
+      callee.disabled = this.disabled;
+      obj.getProp(this.propName).propagate(callee, weight);
+    },
+    propHint: function() { return this.propName; }
+  });
+
+  var IsCtor = exports.IsCtor = constraint("target, noReuse", {
+    addType: function(f, weight) {
+      if (!(f instanceof Fn)) return;
+      if (cx.parent && !cx.parent.options.reuseInstances) this.noReuse = true;
+      f.getProp("prototype").propagate(new IsProto(this.noReuse ? false : f, this.target), weight);
+    }
+  });
+
+  var getInstance = exports.getInstance = function(obj, ctor) {
+    if (ctor === false) return new Obj(obj);
+
+    if (!ctor) ctor = obj.hasCtor;
+    if (!obj.instances) obj.instances = [];
+    for (var i = 0; i < obj.instances.length; ++i) {
+      var cur = obj.instances[i];
+      if (cur.ctor == ctor) return cur.instance;
+    }
+    var instance = new Obj(obj, ctor && ctor.name);
+    instance.origin = obj.origin;
+    obj.instances.push({ctor: ctor, instance: instance});
+    return instance;
+  };
+
+  var IsProto = exports.IsProto = constraint("ctor, target", {
+    addType: function(o, _weight) {
+      if (!(o instanceof Obj)) return;
+      if ((this.count = (this.count || 0) + 1) > 8) return;
+      if (o == cx.protos.Array)
+        this.target.addType(new Arr);
+      else
+        this.target.addType(getInstance(o, this.ctor));
+    }
+  });
+
+  var FnPrototype = constraint("fn", {
+    addType: function(o, _weight) {
+      if (o instanceof Obj && !o.hasCtor) {
+        o.hasCtor = this.fn;
+        var adder = new SpeculativeThis(o, this.fn);
+        adder.addType(this.fn);
+        o.forAllProps(function(_prop, val, local) {
+          if (local) val.propagate(adder);
+        });
+      }
+    }
+  });
+
+  var IsAdded = constraint("other, target", {
+    addType: function(type, weight) {
+      if (type == cx.str)
+        this.target.addType(cx.str, weight);
+      else if (type == cx.num && this.other.hasType(cx.num))
+        this.target.addType(cx.num, weight);
+    },
+    typeHint: function() { return this.other; }
+  });
+
+  var IfObj = exports.IfObj = constraint("target", {
+    addType: function(t, weight) {
+      if (t instanceof Obj) this.target.addType(t, weight);
+    },
+    propagatesTo: function() { return this.target; }
+  });
+
+  var SpeculativeThis = constraint("obj, ctor", {
+    addType: function(tp) {
+      if (tp instanceof Fn && tp.self && tp.self.isEmpty())
+        tp.self.addType(getInstance(this.obj, this.ctor), WG_SPECULATIVE_THIS);
+    }
+  });
+
+  var Muffle = constraint("inner, weight", {
+    addType: function(tp, weight) {
+      this.inner.addType(tp, Math.min(weight, this.weight));
+    },
+    propagatesTo: function() { return this.inner.propagatesTo(); },
+    typeHint: function() { return this.inner.typeHint(); },
+    propHint: function() { return this.inner.propHint(); }
+  });
+
+  // TYPE OBJECTS
+
+  var Type = exports.Type = function() {};
+  Type.prototype = extend(ANull, {
+    constructor: Type,
+    propagate: function(c, w) { c.addType(this, w); },
+    hasType: function(other) { return other == this; },
+    isEmpty: function() { return false; },
+    typeHint: function() { return this; },
+    getType: function() { return this; }
+  });
+
+  var Prim = exports.Prim = function(proto, name) { this.name = name; this.proto = proto; };
+  Prim.prototype = extend(Type.prototype, {
+    constructor: Prim,
+    toString: function() { return this.name; },
+    getProp: function(prop) {return this.proto.hasProp(prop) || ANull;},
+    gatherProperties: function(f, depth) {
+      if (this.proto) this.proto.gatherProperties(f, depth);
+    }
+  });
+
+  var Obj = exports.Obj = function(proto, name) {
+    if (!this.props) this.props = Object.create(null);
+    this.proto = proto === true ? cx.protos.Object : proto;
+    if (proto && !name && proto.name && !(this instanceof Fn)) {
+      var match = /^(.*)\.prototype$/.exec(this.proto.name);
+      if (match) name = match[1];
+    }
+    this.name = name;
+    this.maybeProps = null;
+    this.origin = cx.curOrigin;
+  };
+  Obj.prototype = extend(Type.prototype, {
+    constructor: Obj,
+    toString: function(maxDepth) {
+      if (maxDepth == null) maxDepth = 0;
+      if (maxDepth <= 0 && this.name) return this.name;
+      var props = [], etc = false;
+      for (var prop in this.props) if (prop != "<i>") {
+        if (props.length > 5) { etc = true; break; }
+        if (maxDepth)
+          props.push(prop + ": " + toString(this.props[prop], maxDepth - 1, this));
+        else
+          props.push(prop);
+      }
+      props.sort();
+      if (etc) props.push("...");
+      return "{" + props.join(", ") + "}";
+    },
+    hasProp: function(prop, searchProto) {
+      var found = this.props[prop];
+      if (searchProto !== false)
+        for (var p = this.proto; p && !found; p = p.proto) found = p.props[prop];
+      return found;
+    },
+    defProp: function(prop, originNode) {
+      var found = this.hasProp(prop, false);
+      if (found) {
+        if (originNode && !found.originNode) found.originNode = originNode;
+        return found;
+      }
+      if (prop == "__proto__" || prop == "✖") return ANull;
+
+      var av = this.maybeProps && this.maybeProps[prop];
+      if (av) {
+        delete this.maybeProps[prop];
+        this.maybeUnregProtoPropHandler();
+      } else {
+        av = new AVal;
+        av.propertyOf = this;
+      }
+
+      this.props[prop] = av;
+      av.originNode = originNode;
+      av.origin = cx.curOrigin;
+      this.broadcastProp(prop, av, true);
+      return av;
+    },
+    getProp: function(prop) {
+      var found = this.hasProp(prop, true) || (this.maybeProps && this.maybeProps[prop]);
+      if (found) return found;
+      if (prop == "__proto__" || prop == "✖") return ANull;
+      var av = this.ensureMaybeProps()[prop] = new AVal;
+      av.propertyOf = this;
+      return av;
+    },
+    broadcastProp: function(prop, val, local) {
+      if (local) {
+        this.signal("addProp", prop, val);
+        // If this is a scope, it shouldn't be registered
+        if (!(this instanceof Scope)) registerProp(prop, this);
+      }
+
+      if (this.onNewProp) for (var i = 0; i < this.onNewProp.length; ++i) {
+        var h = this.onNewProp[i];
+        h.onProtoProp ? h.onProtoProp(prop, val, local) : h(prop, val, local);
+      }
+    },
+    onProtoProp: function(prop, val, _local) {
+      var maybe = this.maybeProps && this.maybeProps[prop];
+      if (maybe) {
+        delete this.maybeProps[prop];
+        this.maybeUnregProtoPropHandler();
+        this.proto.getProp(prop).propagate(maybe);
+      }
+      this.broadcastProp(prop, val, false);
+    },
+    ensureMaybeProps: function() {
+      if (!this.maybeProps) {
+        if (this.proto) this.proto.forAllProps(this);
+        this.maybeProps = Object.create(null);
+      }
+      return this.maybeProps;
+    },
+    removeProp: function(prop) {
+      var av = this.props[prop];
+      delete this.props[prop];
+      this.ensureMaybeProps()[prop] = av;
+      av.types.length = 0;
+    },
+    forAllProps: function(c) {
+      if (!this.onNewProp) {
+        this.onNewProp = [];
+        if (this.proto) this.proto.forAllProps(this);
+      }
+      this.onNewProp.push(c);
+      for (var o = this; o; o = o.proto) for (var prop in o.props) {
+        if (c.onProtoProp)
+          c.onProtoProp(prop, o.props[prop], o == this);
+        else
+          c(prop, o.props[prop], o == this);
+      }
+    },
+    maybeUnregProtoPropHandler: function() {
+      if (this.maybeProps) {
+        for (var _n in this.maybeProps) return;
+        this.maybeProps = null;
+      }
+      if (!this.proto || this.onNewProp && this.onNewProp.length) return;
+      this.proto.unregPropHandler(this);
+    },
+    unregPropHandler: function(handler) {
+      for (var i = 0; i < this.onNewProp.length; ++i)
+        if (this.onNewProp[i] == handler) { this.onNewProp.splice(i, 1); break; }
+      this.maybeUnregProtoPropHandler();
+    },
+    gatherProperties: function(f, depth) {
+      for (var prop in this.props) if (prop != "<i>")
+        f(prop, this, depth);
+      if (this.proto) this.proto.gatherProperties(f, depth + 1);
+    },
+    getObjType: function() { return this; }
+  });
+
+  var Fn = exports.Fn = function(name, self, args, argNames, retval) {
+    Obj.call(this, cx.protos.Function, name);
+    this.self = self;
+    this.args = args;
+    this.argNames = argNames;
+    this.retval = retval;
+  };
+  Fn.prototype = extend(Obj.prototype, {
+    constructor: Fn,
+    toString: function(maxDepth) {
+      if (maxDepth == null) maxDepth = 0;
+      var str = "fn(";
+      for (var i = 0; i < this.args.length; ++i) {
+        if (i) str += ", ";
+        var name = this.argNames[i];
+        if (name && name != "?") str += name + ": ";
+        str += maxDepth > -3 ? toString(this.args[i], maxDepth - 1, this) : "?";
+      }
+      str += ")";
+      if (!this.retval.isEmpty())
+        str += " -> " + (maxDepth > -3 ? toString(this.retval, maxDepth - 1, this) : "?");
+      return str;
+    },
+    getProp: function(prop) {
+      if (prop == "prototype") {
+        var known = this.hasProp(prop, false);
+        if (!known) {
+          known = this.defProp(prop);
+          var proto = new Obj(true, this.name && this.name + ".prototype");
+          proto.origin = this.origin;
+          known.addType(proto, WG_MADEUP_PROTO);
+        }
+        return known;
+      }
+      return Obj.prototype.getProp.call(this, prop);
+    },
+    defProp: function(prop, originNode) {
+      if (prop == "prototype") {
+        var found = this.hasProp(prop, false);
+        if (found) return found;
+        found = Obj.prototype.defProp.call(this, prop, originNode);
+        found.origin = this.origin;
+        found.propagate(new FnPrototype(this));
+        return found;
+      }
+      return Obj.prototype.defProp.call(this, prop, originNode);
+    },
+    getFunctionType: function() { return this; }
+  });
+
+  var Arr = exports.Arr = function(contentType) {
+    Obj.call(this, cx.protos.Array);
+    var content = this.defProp("<i>");
+    if (contentType) contentType.propagate(content);
+  };
+  Arr.prototype = extend(Obj.prototype, {
+    constructor: Arr,
+    toString: function(maxDepth) {
+      if (maxDepth == null) maxDepth = 0;
+      return "[" + (maxDepth > -3 ? toString(this.getProp("<i>"), maxDepth - 1, this) : "?") + "]";
+    }
+  });
+
+  // THE PROPERTY REGISTRY
+
+  function registerProp(prop, obj) {
+    var data = cx.props[prop] || (cx.props[prop] = []);
+    data.push(obj);
+  }
+
+  function objsWithProp(prop) {
+    return cx.props[prop];
+  }
+
+  // INFERENCE CONTEXT
+
+  exports.Context = function(defs, parent) {
+    this.parent = parent;
+    this.props = Object.create(null);
+    this.protos = Object.create(null);
+    this.origins = [];
+    this.curOrigin = "ecma5";
+    this.paths = Object.create(null);
+    this.definitions = Object.create(null);
+    this.purgeGen = 0;
+    this.workList = null;
+    this.disabledComputing = null;
+
+    exports.withContext(this, function() {
+      cx.protos.Object = new Obj(null, "Object.prototype");
+      cx.topScope = new Scope();
+      cx.topScope.name = "<top>";
+      cx.protos.Array = new Obj(true, "Array.prototype");
+      cx.protos.Function = new Obj(true, "Function.prototype");
+      cx.protos.RegExp = new Obj(true, "RegExp.prototype");
+      cx.protos.String = new Obj(true, "String.prototype");
+      cx.protos.Number = new Obj(true, "Number.prototype");
+      cx.protos.Boolean = new Obj(true, "Boolean.prototype");
+      cx.str = new Prim(cx.protos.String, "string");
+      cx.bool = new Prim(cx.protos.Boolean, "bool");
+      cx.num = new Prim(cx.protos.Number, "number");
+      cx.curOrigin = null;
+
+      if (defs) for (var i = 0; i < defs.length; ++i)
+        def.load(defs[i]);
+    });
+  };
+
+  var cx = null;
+  exports.cx = function() { return cx; };
+
+  exports.withContext = function(context, f) {
+    var old = cx;
+    cx = context;
+    try { return f(); }
+    finally { cx = old; }
+  };
+
+  exports.TimedOut = function() {
+    this.message = "Timed out";
+    this.stack = (new Error()).stack;
+  };
+  exports.TimedOut.prototype = Object.create(Error.prototype);
+  exports.TimedOut.prototype.name = "infer.TimedOut";
+
+  var timeout;
+  exports.withTimeout = function(ms, f) {
+    var end = +new Date + ms;
+    var oldEnd = timeout;
+    if (oldEnd && oldEnd < end) return f();
+    timeout = end;
+    try { return f(); }
+    finally { timeout = oldEnd; }
+  };
+
+  exports.addOrigin = function(origin) {
+    if (cx.origins.indexOf(origin) < 0) cx.origins.push(origin);
+  };
+
+  var baseMaxWorkDepth = 20, reduceMaxWorkDepth = 0.0001;
+  function withWorklist(f) {
+    if (cx.workList) return f(cx.workList);
+
+    var list = [], depth = 0;
+    var add = cx.workList = function(type, target, weight) {
+      if (depth < baseMaxWorkDepth - reduceMaxWorkDepth * list.length)
+        list.push(type, target, weight, depth);
+    };
+    try {
+      var ret = f(add);
+      for (var i = 0; i < list.length; i += 4) {
+        if (timeout && +new Date >= timeout)
+          throw new exports.TimedOut();
+        depth = list[i + 3] + 1;
+        list[i + 1].addType(list[i], list[i + 2]);
+      }
+      return ret;
+    } finally {
+      cx.workList = null;
+    }
+  }
+
+  // SCOPES
+
+  var Scope = exports.Scope = function(prev) {
+    Obj.call(this, prev || true);
+    this.prev = prev;
+  };
+  Scope.prototype = extend(Obj.prototype, {
+    constructor: Scope,
+    defVar: function(name, originNode) {
+      for (var s = this; ; s = s.proto) {
+        var found = s.props[name];
+        if (found) return found;
+        if (!s.prev) return s.defProp(name, originNode);
+      }
+    }
+  });
+
+  // RETVAL COMPUTATION HEURISTICS
+
+  function maybeInstantiate(scope, score) {
+    if (scope.fnType)
+      scope.fnType.instantiateScore = (scope.fnType.instantiateScore || 0) + score;
+  }
+
+  var NotSmaller = {};
+  function nodeSmallerThan(node, n) {
+    try {
+      walk.simple(node, {Expression: function() { if (--n <= 0) throw NotSmaller; }});
+      return true;
+    } catch(e) {
+      if (e == NotSmaller) return false;
+      throw e;
+    }
+  }
+
+  function maybeTagAsInstantiated(node, scope) {
+    var score = scope.fnType.instantiateScore;
+    if (!cx.disabledComputing && score && scope.fnType.args.length && nodeSmallerThan(node, score * 5)) {
+      maybeInstantiate(scope.prev, score / 2);
+      setFunctionInstantiated(node, scope);
+      return true;
+    } else {
+      scope.fnType.instantiateScore = null;
+    }
+  }
+
+  function setFunctionInstantiated(node, scope) {
+    var fn = scope.fnType;
+    // Disconnect the arg avals, so that we can add info to them without side effects
+    for (var i = 0; i < fn.args.length; ++i) fn.args[i] = new AVal;
+    fn.self = new AVal;
+    fn.computeRet = function(self, args) {
+      // Prevent recursion
+      return withDisabledComputing(fn, function() {
+        var oldOrigin = cx.curOrigin;
+        cx.curOrigin = fn.origin;
+        var scopeCopy = new Scope(scope.prev);
+        scopeCopy.originNode = scope.originNode;
+        for (var v in scope.props) {
+          var local = scopeCopy.defProp(v, scope.props[v].originNode);
+          for (var i = 0; i < args.length; ++i) if (fn.argNames[i] == v && i < args.length)
+            args[i].propagate(local);
+        }
+        var argNames = fn.argNames.length != args.length ? fn.argNames.slice(0, args.length) : fn.argNames;
+        while (argNames.length < args.length) argNames.push("?");
+        scopeCopy.fnType = new Fn(fn.name, self, args, argNames, ANull);
+        scopeCopy.fnType.originNode = fn.originNode;
+        if (fn.arguments) {
+          var argset = scopeCopy.fnType.arguments = new AVal;
+          scopeCopy.defProp("arguments").addType(new Arr(argset));
+          for (var i = 0; i < args.length; ++i) args[i].propagate(argset);
+        }
+        node.body.scope = scopeCopy;
+        walk.recursive(node.body, scopeCopy, null, scopeGatherer);
+        walk.recursive(node.body, scopeCopy, null, inferWrapper);
+        cx.curOrigin = oldOrigin;
+        return scopeCopy.fnType.retval;
+      });
+    };
+  }
+
+  function maybeTagAsGeneric(scope) {
+    var fn = scope.fnType, target = fn.retval;
+    if (target == ANull) return;
+    var targetInner, asArray;
+    if (!target.isEmpty() && (targetInner = target.getType()) instanceof Arr)
+      target = asArray = targetInner.getProp("<i>");
+
+    function explore(aval, path, depth) {
+      if (depth > 3 || !aval.forward) return;
+      for (var i = 0; i < aval.forward.length; ++i) {
+        var prop = aval.forward[i].propagatesTo();
+        if (!prop) continue;
+        var newPath = path, dest;
+        if (prop instanceof AVal) {
+          dest = prop;
+        } else if (prop.target instanceof AVal) {
+          newPath += prop.pathExt;
+          dest = prop.target;
+        } else continue;
+        if (dest == target) return newPath;
+        var found = explore(dest, newPath, depth + 1);
+        if (found) return found;
+      }
+    }
+
+    var foundPath = explore(fn.self, "!this", 0);
+    for (var i = 0; !foundPath && i < fn.args.length; ++i)
+      foundPath = explore(fn.args[i], "!" + i, 0);
+
+    if (foundPath) {
+      if (asArray) foundPath = "[" + foundPath + "]";
+      var p = new def.TypeParser(foundPath);
+      var parsed = p.parseType(true);
+      fn.computeRet = parsed.apply ? parsed : function() { return parsed; };
+      fn.computeRetSource = foundPath;
+      return true;
+    }
+  }
+
+  // SCOPE GATHERING PASS
+
+  function addVar(scope, nameNode) {
+    return scope.defProp(nameNode.name, nameNode);
+  }
+
+  var scopeGatherer = walk.make({
+    Function: function(node, scope, c) {
+      var inner = node.body.scope = new Scope(scope);
+      inner.originNode = node;
+      var argVals = [], argNames = [];
+      for (var i = 0; i < node.params.length; ++i) {
+        var param = node.params[i];
+        argNames.push(param.name);
+        argVals.push(addVar(inner, param));
+      }
+      inner.fnType = new Fn(node.id && node.id.name, new AVal, argVals, argNames, ANull);
+      inner.fnType.originNode = node;
+      if (node.id) {
+        var decl = node.type == "FunctionDeclaration";
+        addVar(decl ? scope : inner, node.id);
+      }
+      c(node.body, inner, "ScopeBody");
+    },
+    TryStatement: function(node, scope, c) {
+      c(node.block, scope, "Statement");
+      if (node.handler) {
+        var v = addVar(scope, node.handler.param);
+        c(node.handler.body, scope, "ScopeBody");
+        var e5 = cx.definitions.ecma5;
+        if (e5 && v.isEmpty()) getInstance(e5["Error.prototype"]).propagate(v, WG_CATCH_ERROR);
+      }
+      if (node.finalizer) c(node.finalizer, scope, "Statement");
+    },
+    VariableDeclaration: function(node, scope, c) {
+      for (var i = 0; i < node.declarations.length; ++i) {
+        var decl = node.declarations[i];
+        addVar(scope, decl.id);
+        if (decl.init) c(decl.init, scope, "Expression");
+      }
+    }
+  });
+
+  // CONSTRAINT GATHERING PASS
+
+  function propName(node, scope, c) {
+    var prop = node.property;
+    if (!node.computed) return prop.name;
+    if (prop.type == "Literal" && typeof prop.value == "string") return prop.value;
+    if (c) infer(prop, scope, c, ANull);
+    return "<i>";
+  }
+
+  function unopResultType(op) {
+    switch (op) {
+    case "+": case "-": case "~": return cx.num;
+    case "!": return cx.bool;
+    case "typeof": return cx.str;
+    case "void": case "delete": return ANull;
+    }
+  }
+  function binopIsBoolean(op) {
+    switch (op) {
+    case "==": case "!=": case "===": case "!==": case "<": case ">": case ">=": case "<=":
+    case "in": case "instanceof": return true;
+    }
+  }
+  function literalType(node) {
+    if (node.regex) return getInstance(cx.protos.RegExp);
+    switch (typeof node.value) {
+    case "boolean": return cx.bool;
+    case "number": return cx.num;
+    case "string": return cx.str;
+    case "object":
+    case "function":
+      if (!node.value) return ANull;
+      return getInstance(cx.protos.RegExp);
+    }
+  }
+
+  function ret(f) {
+    return function(node, scope, c, out, name) {
+      var r = f(node, scope, c, name);
+      if (out) r.propagate(out);
+      return r;
+    };
+  }
+  function fill(f) {
+    return function(node, scope, c, out, name) {
+      if (!out) out = new AVal;
+      f(node, scope, c, out, name);
+      return out;
+    };
+  }
+
+  var inferExprVisitor = {
+    ArrayExpression: ret(function(node, scope, c) {
+      var eltval = new AVal;
+      for (var i = 0; i < node.elements.length; ++i) {
+        var elt = node.elements[i];
+        if (elt) infer(elt, scope, c, eltval);
+      }
+      return new Arr(eltval);
+    }),
+    ObjectExpression: ret(function(node, scope, c, name) {
+      var obj = node.objType = new Obj(true, name);
+      obj.originNode = node;
+
+      for (var i = 0; i < node.properties.length; ++i) {
+        var prop = node.properties[i], key = prop.key, name;
+        if (prop.value.name == "✖") continue;
+
+        if (key.type == "Identifier") {
+          name = key.name;
+        } else if (typeof key.value == "string") {
+          name = key.value;
+        }
+        if (!name || prop.kind == "set") {
+          infer(prop.value, scope, c, ANull);
+          continue;
+        }
+
+        var val = obj.defProp(name, key), out = val;
+        val.initializer = true;
+        if (prop.kind == "get")
+          out = new IsCallee(obj, [], null, val);
+        infer(prop.value, scope, c, out, name);
+      }
+      return obj;
+    }),
+    FunctionExpression: ret(function(node, scope, c, name) {
+      var inner = node.body.scope, fn = inner.fnType;
+      if (name && !fn.name) fn.name = name;
+      c(node.body, scope, "ScopeBody");
+      maybeTagAsInstantiated(node, inner) || maybeTagAsGeneric(inner);
+      if (node.id) inner.getProp(node.id.name).addType(fn);
+      return fn;
+    }),
+    SequenceExpression: ret(function(node, scope, c) {
+      for (var i = 0, l = node.expressions.length - 1; i < l; ++i)
+        infer(node.expressions[i], scope, c, ANull);
+      return infer(node.expressions[l], scope, c);
+    }),
+    UnaryExpression: ret(function(node, scope, c) {
+      infer(node.argument, scope, c, ANull);
+      return unopResultType(node.operator);
+    }),
+    UpdateExpression: ret(function(node, scope, c) {
+      infer(node.argument, scope, c, ANull);
+      return cx.num;
+    }),
+    BinaryExpression: ret(function(node, scope, c) {
+      if (node.operator == "+") {
+        var lhs = infer(node.left, scope, c);
+        var rhs = infer(node.right, scope, c);
+        if (lhs.hasType(cx.str) || rhs.hasType(cx.str)) return cx.str;
+        if (lhs.hasType(cx.num) && rhs.hasType(cx.num)) return cx.num;
+        var result = new AVal;
+        lhs.propagate(new IsAdded(rhs, result));
+        rhs.propagate(new IsAdded(lhs, result));
+        return result;
+      } else {
+        infer(node.left, scope, c, ANull);
+        infer(node.right, scope, c, ANull);
+        return binopIsBoolean(node.operator) ? cx.bool : cx.num;
+      }
+    }),
+    AssignmentExpression: ret(function(node, scope, c) {
+      var rhs, name, pName;
+      if (node.left.type == "MemberExpression") {
+        pName = propName(node.left, scope, c);
+        if (node.left.object.type == "Identifier")
+          name = node.left.object.name + "." + pName;
+      } else {
+        name = node.left.name;
+      }
+
+      if (node.operator != "=" && node.operator != "+=") {
+        infer(node.right, scope, c, ANull);
+        rhs = cx.num;
+      } else {
+        rhs = infer(node.right, scope, c, null, name);
+      }
+
+      if (node.left.type == "MemberExpression") {
+        var obj = infer(node.left.object, scope, c);
+        if (pName == "prototype") maybeInstantiate(scope, 20);
+        if (pName == "<i>") {
+          // This is a hack to recognize for/in loops that copy
+          // properties, and do the copying ourselves, insofar as we
+          // manage, because such loops tend to be relevant for type
+          // information.
+          var v = node.left.property.name, local = scope.props[v], over = local && local.iteratesOver;
+          if (over) {
+            maybeInstantiate(scope, 20);
+            var fromRight = node.right.type == "MemberExpression" && node.right.computed && node.right.property.name == v;
+            over.forAllProps(function(prop, val, local) {
+              if (local && prop != "prototype" && prop != "<i>")
+                obj.propagate(new PropHasSubset(prop, fromRight ? val : ANull));
+            });
+            return rhs;
+          }
+        }
+        obj.propagate(new PropHasSubset(pName, rhs, node.left.property));
+      } else { // Identifier
+        rhs.propagate(scope.defVar(node.left.name, node.left));
+      }
+      return rhs;
+    }),
+    LogicalExpression: fill(function(node, scope, c, out) {
+      infer(node.left, scope, c, out);
+      infer(node.right, scope, c, out);
+    }),
+    ConditionalExpression: fill(function(node, scope, c, out) {
+      infer(node.test, scope, c, ANull);
+      infer(node.consequent, scope, c, out);
+      infer(node.alternate, scope, c, out);
+    }),
+    NewExpression: fill(function(node, scope, c, out, name) {
+      if (node.callee.type == "Identifier" && node.callee.name in scope.props)
+        maybeInstantiate(scope, 20);
+
+      for (var i = 0, args = []; i < node.arguments.length; ++i)
+        args.push(infer(node.arguments[i], scope, c));
+      var callee = infer(node.callee, scope, c);
+      var self = new AVal;
+      callee.propagate(new IsCtor(self, name && /\.prototype$/.test(name)));
+      self.propagate(out, WG_NEW_INSTANCE);
+      callee.propagate(new IsCallee(self, args, node.arguments, new IfObj(out)));
+    }),
+    CallExpression: fill(function(node, scope, c, out) {
+      for (var i = 0, args = []; i < node.arguments.length; ++i)
+        args.push(infer(node.arguments[i], scope, c));
+      if (node.callee.type == "MemberExpression") {
+        var self = infer(node.callee.object, scope, c);
+        var pName = propName(node.callee, scope, c);
+        if ((pName == "call" || pName == "apply") &&
+            scope.fnType && scope.fnType.args.indexOf(self) > -1)
+          maybeInstantiate(scope, 30);
+        self.propagate(new HasMethodCall(pName, args, node.arguments, out));
+      } else {
+        var callee = infer(node.callee, scope, c);
+        if (scope.fnType && scope.fnType.args.indexOf(callee) > -1)
+          maybeInstantiate(scope, 30);
+        var knownFn = callee.getFunctionType();
+        if (knownFn && knownFn.instantiateScore && scope.fnType)
+          maybeInstantiate(scope, knownFn.instantiateScore / 5);
+        callee.propagate(new IsCallee(cx.topScope, args, node.arguments, out));
+      }
+    }),
+    MemberExpression: fill(function(node, scope, c, out) {
+      var name = propName(node, scope);
+      var obj = infer(node.object, scope, c);
+      var prop = obj.getProp(name);
+      if (name == "<i>") {
+        var propType = infer(node.property, scope, c);
+        if (!propType.hasType(cx.num))
+          return prop.propagate(out, WG_MULTI_MEMBER);
+      }
+      prop.propagate(out);
+    }),
+    Identifier: ret(function(node, scope) {
+      if (node.name == "arguments" && scope.fnType && !(node.name in scope.props))
+        scope.defProp(node.name, scope.fnType.originNode)
+          .addType(new Arr(scope.fnType.arguments = new AVal));
+      return scope.getProp(node.name);
+    }),
+    ThisExpression: ret(function(_node, scope) {
+      return scope.fnType ? scope.fnType.self : cx.topScope;
+    }),
+    Literal: ret(function(node) {
+      return literalType(node);
+    })
+  };
+
+  function infer(node, scope, c, out, name) {
+    return inferExprVisitor[node.type](node, scope, c, out, name);
+  }
+
+  var inferWrapper = walk.make({
+    Expression: function(node, scope, c) {
+      infer(node, scope, c, ANull);
+    },
+
+    FunctionDeclaration: function(node, scope, c) {
+      var inner = node.body.scope, fn = inner.fnType;
+      c(node.body, scope, "ScopeBody");
+      maybeTagAsInstantiated(node, inner) || maybeTagAsGeneric(inner);
+      var prop = scope.getProp(node.id.name);
+      prop.addType(fn);
+    },
+
+    VariableDeclaration: function(node, scope, c) {
+      for (var i = 0; i < node.declarations.length; ++i) {
+        var decl = node.declarations[i], prop = scope.getProp(decl.id.name);
+        if (decl.init)
+          infer(decl.init, scope, c, prop, decl.id.name);
+      }
+    },
+
+    ReturnStatement: function(node, scope, c) {
+      if (!node.argument) return;
+      var output = ANull;
+      if (scope.fnType) {
+        if (scope.fnType.retval == ANull) scope.fnType.retval = new AVal;
+        output = scope.fnType.retval;
+      }
+      infer(node.argument, scope, c, output);
+    },
+
+    ForInStatement: function(node, scope, c) {
+      var source = infer(node.right, scope, c);
+      if ((node.right.type == "Identifier" && node.right.name in scope.props) ||
+          (node.right.type == "MemberExpression" && node.right.property.name == "prototype")) {
+        maybeInstantiate(scope, 5);
+        var varName;
+        if (node.left.type == "Identifier") {
+          varName = node.left.name;
+        } else if (node.left.type == "VariableDeclaration") {
+          varName = node.left.declarations[0].id.name;
+        }
+        if (varName && varName in scope.props)
+          scope.getProp(varName).iteratesOver = source;
+      }
+      c(node.body, scope, "Statement");
+    },
+
+    ScopeBody: function(node, scope, c) { c(node, node.scope || scope); }
+  });
+
+  // PARSING
+
+  function runPasses(passes, pass) {
+    var arr = passes && passes[pass];
+    var args = Array.prototype.slice.call(arguments, 2);
+    if (arr) for (var i = 0; i < arr.length; ++i) arr[i].apply(null, args);
+  }
+
+  var parse = exports.parse = function(text, passes, options) {
+    var ast;
+    try { ast = acorn.parse(text, options); }
+    catch(e) { ast = acorn_loose.parse_dammit(text, options); }
+    runPasses(passes, "postParse", ast, text);
+    return ast;
+  };
+
+  // ANALYSIS INTERFACE
+
+  exports.analyze = function(ast, name, scope, passes) {
+    if (typeof ast == "string") ast = parse(ast);
+
+    if (!name) name = "file#" + cx.origins.length;
+    exports.addOrigin(cx.curOrigin = name);
+
+    if (!scope) scope = cx.topScope;
+    walk.recursive(ast, scope, null, scopeGatherer);
+    runPasses(passes, "preInfer", ast, scope);
+    walk.recursive(ast, scope, null, inferWrapper);
+    runPasses(passes, "postInfer", ast, scope);
+
+    cx.curOrigin = null;
+  };
+
+  // PURGING
+
+  exports.purge = function(origins, start, end) {
+    var test = makePredicate(origins, start, end);
+    ++cx.purgeGen;
+    cx.topScope.purge(test);
+    for (var prop in cx.props) {
+      var list = cx.props[prop];
+      for (var i = 0; i < list.length; ++i) {
+        var obj = list[i], av = obj.props[prop];
+        if (!av || test(av, av.originNode)) list.splice(i--, 1);
+      }
+      if (!list.length) delete cx.props[prop];
+    }
+  };
+
+  function makePredicate(origins, start, end) {
+    var arr = Array.isArray(origins);
+    if (arr && origins.length == 1) { origins = origins[0]; arr = false; }
+    if (arr) {
+      if (end == null) return function(n) { return origins.indexOf(n.origin) > -1; };
+      return function(n, pos) { return pos && pos.start >= start && pos.end <= end && origins.indexOf(n.origin) > -1; };
+    } else {
+      if (end == null) return function(n) { return n.origin == origins; };
+      return function(n, pos) { return pos && pos.start >= start && pos.end <= end && n.origin == origins; };
+    }
+  }
+
+  AVal.prototype.purge = function(test) {
+    if (this.purgeGen == cx.purgeGen) return;
+    this.purgeGen = cx.purgeGen;
+    for (var i = 0; i < this.types.length; ++i) {
+      var type = this.types[i];
+      if (test(type, type.originNode))
+        this.types.splice(i--, 1);
+      else
+        type.purge(test);
+    }
+    if (this.forward) for (var i = 0; i < this.forward.length; ++i) {
+      var f = this.forward[i];
+      if (test(f)) {
+        this.forward.splice(i--, 1);
+        if (this.props) this.props = null;
+      } else if (f.purge) {
+        f.purge(test);
+      }
+    }
+  };
+  ANull.purge = function() {};
+  Obj.prototype.purge = function(test) {
+    if (this.purgeGen == cx.purgeGen) return true;
+    this.purgeGen = cx.purgeGen;
+    for (var p in this.props) {
+      var av = this.props[p];
+      if (test(av, av.originNode))
+        this.removeProp(p);
+      av.purge(test);
+    }
+  };
+  Fn.prototype.purge = function(test) {
+    if (Obj.prototype.purge.call(this, test)) return;
+    this.self.purge(test);
+    this.retval.purge(test);
+    for (var i = 0; i < this.args.length; ++i) this.args[i].purge(test);
+  };
+
+  // EXPRESSION TYPE DETERMINATION
+
+  function findByPropertyName(name) {
+    guessing = true;
+    var found = objsWithProp(name);
+    if (found) for (var i = 0; i < found.length; ++i) {
+      var val = found[i].getProp(name);
+      if (!val.isEmpty()) return val;
+    }
+    return ANull;
+  }
+
+  var typeFinder = {
+    ArrayExpression: function(node, scope) {
+      var eltval = new AVal;
+      for (var i = 0; i < node.elements.length; ++i) {
+        var elt = node.elements[i];
+        if (elt) findType(elt, scope).propagate(eltval);
+      }
+      return new Arr(eltval);
+    },
+    ObjectExpression: function(node) {
+      return node.objType;
+    },
+    FunctionExpression: function(node) {
+      return node.body.scope.fnType;
+    },
+    SequenceExpression: function(node, scope) {
+      return findType(node.expressions[node.expressions.length-1], scope);
+    },
+    UnaryExpression: function(node) {
+      return unopResultType(node.operator);
+    },
+    UpdateExpression: function() {
+      return cx.num;
+    },
+    BinaryExpression: function(node, scope) {
+      if (binopIsBoolean(node.operator)) return cx.bool;
+      if (node.operator == "+") {
+        var lhs = findType(node.left, scope);
+        var rhs = findType(node.right, scope);
+        if (lhs.hasType(cx.str) || rhs.hasType(cx.str)) return cx.str;
+      }
+      return cx.num;
+    },
+    AssignmentExpression: function(node, scope) {
+      return findType(node.right, scope);
+    },
+    LogicalExpression: function(node, scope) {
+      var lhs = findType(node.left, scope);
+      return lhs.isEmpty() ? findType(node.right, scope) : lhs;
+    },
+    ConditionalExpression: function(node, scope) {
+      var lhs = findType(node.consequent, scope);
+      return lhs.isEmpty() ? findType(node.alternate, scope) : lhs;
+    },
+    NewExpression: function(node, scope) {
+      var f = findType(node.callee, scope).getFunctionType();
+      var proto = f && f.getProp("prototype").getObjType();
+      if (!proto) return ANull;
+      return getInstance(proto, f);
+    },
+    CallExpression: function(node, scope) {
+      var f = findType(node.callee, scope).getFunctionType();
+      if (!f) return ANull;
+      if (f.computeRet) {
+        for (var i = 0, args = []; i < node.arguments.length; ++i)
+          args.push(findType(node.arguments[i], scope));
+        var self = ANull;
+        if (node.callee.type == "MemberExpression")
+          self = findType(node.callee.object, scope);
+        return f.computeRet(self, args, node.arguments);
+      } else {
+        return f.retval;
+      }
+    },
+    MemberExpression: function(node, scope) {
+      var propN = propName(node, scope), obj = findType(node.object, scope).getType();
+      if (obj) return obj.getProp(propN);
+      if (propN == "<i>") return ANull;
+      return findByPropertyName(propN);
+    },
+    Identifier: function(node, scope) {
+      return scope.hasProp(node.name) || ANull;
+    },
+    ThisExpression: function(_node, scope) {
+      return scope.fnType ? scope.fnType.self : cx.topScope;
+    },
+    Literal: function(node) {
+      return literalType(node);
+    }
+  };
+
+  function findType(node, scope) {
+    return typeFinder[node.type](node, scope);
+  }
+
+  var searchVisitor = exports.searchVisitor = walk.make({
+    Function: function(node, _st, c) {
+      var scope = node.body.scope;
+      if (node.id) c(node.id, scope);
+      for (var i = 0; i < node.params.length; ++i)
+        c(node.params[i], scope);
+      c(node.body, scope, "ScopeBody");
+    },
+    TryStatement: function(node, st, c) {
+      if (node.handler)
+        c(node.handler.param, st);
+      walk.base.TryStatement(node, st, c);
+    },
+    VariableDeclaration: function(node, st, c) {
+      for (var i = 0; i < node.declarations.length; ++i) {
+        var decl = node.declarations[i];
+        c(decl.id, st);
+        if (decl.init) c(decl.init, st, "Expression");
+      }
+    }
+  });
+  exports.fullVisitor = walk.make({
+    MemberExpression: function(node, st, c) {
+      c(node.object, st, "Expression");
+      c(node.property, st, node.computed ? "Expression" : null);
+    },
+    ObjectExpression: function(node, st, c) {
+      for (var i = 0; i < node.properties.length; ++i) {
+        c(node.properties[i].value, st, "Expression");
+        c(node.properties[i].key, st);
+      }
+    }
+  }, searchVisitor);
+
+  exports.findExpressionAt = function(ast, start, end, defaultScope, filter) {
+    var test = filter || function(_t, node) {
+      if (node.type == "Identifier" && node.name == "✖") return false;
+      return typeFinder.hasOwnProperty(node.type);
+    };
+    return walk.findNodeAt(ast, start, end, test, searchVisitor, defaultScope || cx.topScope);
+  };
+
+  exports.findExpressionAround = function(ast, start, end, defaultScope, filter) {
+    var test = filter || function(_t, node) {
+      if (start != null && node.start > start) return false;
+      if (node.type == "Identifier" && node.name == "✖") return false;
+      return typeFinder.hasOwnProperty(node.type);
+    };
+    return walk.findNodeAround(ast, end, test, searchVisitor, defaultScope || cx.topScope);
+  };
+
+  exports.expressionType = function(found) {
+    return findType(found.node, found.state);
+  };
+
+  // Finding the expected type of something, from context
+
+  exports.parentNode = function(child, ast) {
+    var stack = [];
+    function c(node, st, override) {
+      if (node.start <= child.start && node.end >= child.end) {
+        var top = stack[stack.length - 1];
+        if (node == child) throw {found: top};
+        if (top != node) stack.push(node);
+        walk.base[override || node.type](node, st, c);
+        if (top != node) stack.pop();
+      }
+    }
+    try {
+      c(ast, null);
+    } catch (e) {
+      if (e.found) return e.found;
+      throw e;
+    }
+  };
+
+  var findTypeFromContext = {
+    ArrayExpression: function(parent, _, get) { return get(parent, true).getProp("<i>"); },
+    ObjectExpression: function(parent, node, get) {
+      for (var i = 0; i < parent.properties.length; ++i) {
+        var prop = node.properties[i];
+        if (prop.value == node)
+          return get(parent, true).getProp(prop.key.name);
+      }
+    },
+    UnaryExpression: function(parent) { return unopResultType(parent.operator); },
+    UpdateExpression: function() { return cx.num; },
+    BinaryExpression: function(parent) { return binopIsBoolean(parent.operator) ? cx.bool : cx.num; },
+    AssignmentExpression: function(parent, _, get) { return get(parent.left); },
+    LogicalExpression: function(parent, _, get) { return get(parent, true); },
+    ConditionalExpression: function(parent, node, get) {
+      if (parent.consequent == node || parent.alternate == node) return get(parent, true);
+    },
+    NewExpression: function(parent, node, get) {
+      return this.CallExpression(parent, node, get);
+    },
+    CallExpression: function(parent, node, get) {
+      for (var i = 0; i < parent.arguments.length; i++) {
+        var arg = parent.arguments[i];
+        if (arg == node) {
+          var calleeType = get(parent.callee).getFunctionType();
+          if (calleeType instanceof Fn)
+            return calleeType.args[i];
+          break;
+        }
+      }
+    },
+    ReturnStatement: function(_parent, node, get) {
+      var fnNode = walk.findNodeAround(node.sourceFile.ast, node.start, "Function");
+      if (fnNode) {
+        var fnType = fnNode.node.type == "FunctionExpression"
+          ? get(fnNode.node, true).getFunctionType()
+          : fnNode.node.body.scope.fnType;
+        if (fnType) return fnType.retval.getType();
+      }
+    },
+    VariableDeclaration: function(parent, node, get) {
+      for (var i = 0; i < parent.declarations.length; i++) {
+        var decl = parent.declarations[i];
+        if (decl.init == node) return get(decl.id);
+      }
+    }
+  };
+
+  exports.typeFromContext = function(ast, found) {
+    var parent = exports.parentNode(found.node, ast);
+    var type = null;
+    if (findTypeFromContext.hasOwnProperty(parent.type)) {
+      type = findTypeFromContext[parent.type](parent, found.node, function(node, fromContext) {
+        var obj = {node: node, state: found.state};
+        var tp = fromContext ? exports.typeFromContext(ast, obj) : exports.expressionType(obj);
+        return tp || ANull;
+      });
+    }
+    return type || exports.expressionType(found);
+  };
+
+  // Flag used to indicate that some wild guessing was used to produce
+  // a type or set of completions.
+  var guessing = false;
+
+  exports.resetGuessing = function(val) { guessing = val; };
+  exports.didGuess = function() { return guessing; };
+
+  exports.forAllPropertiesOf = function(type, f) {
+    type.gatherProperties(f, 0);
+  };
+
+  var refFindWalker = walk.make({}, searchVisitor);
+
+  exports.findRefs = function(ast, baseScope, name, refScope, f) {
+    refFindWalker.Identifier = function(node, scope) {
+      if (node.name != name) return;
+      for (var s = scope; s; s = s.prev) {
+        if (s == refScope) f(node, scope);
+        if (name in s.props) return;
+      }
+    };
+    walk.recursive(ast, baseScope, null, refFindWalker);
+  };
+
+  var simpleWalker = walk.make({
+    Function: function(node, _st, c) { c(node.body, node.body.scope, "ScopeBody"); }
+  });
+
+  exports.findPropRefs = function(ast, scope, objType, propName, f) {
+    walk.simple(ast, {
+      MemberExpression: function(node, scope) {
+        if (node.computed || node.property.name != propName) return;
+        if (findType(node.object, scope).getType() == objType) f(node.property);
+      },
+      ObjectExpression: function(node, scope) {
+        if (findType(node, scope).getType() != objType) return;
+        for (var i = 0; i < node.properties.length; ++i)
+          if (node.properties[i].key.name == propName) f(node.properties[i].key);
+      }
+    }, simpleWalker, scope);
+  };
+
+  // LOCAL-VARIABLE QUERIES
+
+  var scopeAt = exports.scopeAt = function(ast, pos, defaultScope) {
+    var found = walk.findNodeAround(ast, pos, function(tp, node) {
+      return tp == "ScopeBody" && node.scope;
+    });
+    if (found) return found.node.scope;
+    else return defaultScope || cx.topScope;
+  };
+
+  exports.forAllLocalsAt = function(ast, pos, defaultScope, f) {
+    var scope = scopeAt(ast, pos, defaultScope);
+    scope.gatherProperties(f, 0);
+  };
+
+  // INIT DEF MODULE
+
+  // Delayed initialization because of cyclic dependencies.
+  def = exports.def = def.init({}, exports);
+});

+ 80 - 0
editor/js/libs/ternjs/polyfill.js

@@ -0,0 +1,80 @@
+// Shims to fill in enough of ECMAScript 5 to make Tern run. Does not
+// supply standard-compliant methods, in that some functionality is
+// left out (such as second argument to Object.create, self args in
+// array methods, etc). WILL clash with other ECMA5 polyfills in a
+// probably disruptive way.
+
+(function() {
+  Object.create = Object.create || (function() {
+    if (!({__proto__: null} instanceof Object))
+      return function(base) { return {__proto__: base}; };
+    function ctor() {}
+    var frame = document.body.appendChild(document.createElement("iframe"));
+    frame.src = "javascript:";
+    var empty = frame.contentWindow.Object.prototype;
+    delete empty.hasOwnProperty;
+    delete empty.isPrototypeOf;
+    delete empty.propertyIsEnumerable;
+    delete empty.valueOf;
+    delete empty.toString;
+    delete empty.toLocaleString;
+    delete empty.constructor;
+    return function(base) { ctor.prototype = base || empty; return new ctor(); };
+  })();
+
+  // Array methods
+
+  var AP = Array.prototype;
+
+  AP.some = AP.some || function(pred) {
+    for (var i = 0; i < this.length; ++i) if (pred(this[i], i)) return true;
+  };
+
+  AP.forEach = AP.forEach || function(f) {
+    for (var i = 0; i < this.length; ++i) f(this[i], i);
+  };
+
+  AP.indexOf = AP.indexOf || function(x, start) {
+    for (var i = start || 0; i < this.length; ++i) if (this[i] === x) return i;
+    return -1;
+  };
+
+  AP.lastIndexOf = AP.lastIndexOf || function(x, start) {
+    for (var i = start == null ? this.length - 1 : start; i >= 0; ++i) if (this[i] === x) return i;
+    return -1;
+  };
+
+  AP.map = AP.map || function(f) {
+    for (var r = [], i = 0; i < this.length; ++i) r.push(f(this[i], i));
+    return r;
+  };
+
+  Array.isArray = Array.isArray || function(v) {
+    return Object.prototype.toString.call(v) == "[object Array]";
+  };
+
+  String.prototype.trim = String.prototype.trim || function() {
+    var from = 0, to = this.length;
+    while (/\s/.test(this.charAt(from))) ++from;
+    while (/\s/.test(this.charAt(to - 1))) --to;
+    return this.slice(from, to);
+  };
+
+/*! JSON v3.2.4 | http://bestiejs.github.com/json3 | Copyright 2012, Kit Cambridge | http://kit.mit-license.org */
+if (!window.JSON) (function(){var e=void 0,i=!0,k=null,l={}.toString,m,n,p="function"===typeof define&&define.c,q=!p&&"object"==typeof exports&&exports;q||p?"object"==typeof JSON&&JSON?p?q=JSON:(q.stringify=JSON.stringify,q.parse=JSON.parse):p&&(q=this.JSON={}):q=this.JSON||(this.JSON={});var r,t,u,x,z,B,C,D,E,F,G,H,I,J=new Date(-3509827334573292),K,O,P;try{J=-109252==J.getUTCFullYear()&&0===J.getUTCMonth()&&1==J.getUTCDate()&&10==J.getUTCHours()&&37==J.getUTCMinutes()&&6==J.getUTCSeconds()&&708==J.getUTCMilliseconds()}catch(Q){}
+function R(b){var c,a,d,j=b=="json";if(j||b=="json-stringify"||b=="json-parse"){if(b=="json-stringify"||j){if(c=typeof q.stringify=="function"&&J){(d=function(){return 1}).toJSON=d;try{c=q.stringify(0)==="0"&&q.stringify(new Number)==="0"&&q.stringify(new String)=='""'&&q.stringify(l)===e&&q.stringify(e)===e&&q.stringify()===e&&q.stringify(d)==="1"&&q.stringify([d])=="[1]"&&q.stringify([e])=="[null]"&&q.stringify(k)=="null"&&q.stringify([e,l,k])=="[null,null,null]"&&q.stringify({A:[d,i,false,k,"\x00\u0008\n\u000c\r\t"]})==
+'{"A":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}'&&q.stringify(k,d)==="1"&&q.stringify([1,2],k,1)=="[\n 1,\n 2\n]"&&q.stringify(new Date(-864E13))=='"-271821-04-20T00:00:00.000Z"'&&q.stringify(new Date(864E13))=='"+275760-09-13T00:00:00.000Z"'&&q.stringify(new Date(-621987552E5))=='"-000001-01-01T00:00:00.000Z"'&&q.stringify(new Date(-1))=='"1969-12-31T23:59:59.999Z"'}catch(f){c=false}}if(!j)return c}if(b=="json-parse"||j){if(typeof q.parse=="function")try{if(q.parse("0")===0&&!q.parse(false)){d=
+q.parse('{"A":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}');if(a=d.a.length==5&&d.a[0]==1){try{a=!q.parse('"\t"')}catch(o){}if(a)try{a=q.parse("01")!=1}catch(g){}}}}catch(h){a=false}if(!j)return a}return c&&a}}
+if(!R("json")){J||(K=Math.floor,O=[0,31,59,90,120,151,181,212,243,273,304,334],P=function(b,c){return O[c]+365*(b-1970)+K((b-1969+(c=+(c>1)))/4)-K((b-1901+c)/100)+K((b-1601+c)/400)});if(!(m={}.hasOwnProperty))m=function(b){var c={},a;if((c.__proto__=k,c.__proto__={toString:1},c).toString!=l)m=function(a){var b=this.__proto__,a=a in(this.__proto__=k,this);this.__proto__=b;return a};else{a=c.constructor;m=function(b){var c=(this.constructor||a).prototype;return b in this&&!(b in c&&this[b]===c[b])}}c=
+k;return m.call(this,b)};n=function(b,c){var a=0,d,j,f;(d=function(){this.valueOf=0}).prototype.valueOf=0;j=new d;for(f in j)m.call(j,f)&&a++;d=j=k;if(a)a=a==2?function(a,b){var c={},d=l.call(a)=="[object Function]",f;for(f in a)!(d&&f=="prototype")&&!m.call(c,f)&&(c[f]=1)&&m.call(a,f)&&b(f)}:function(a,b){var c=l.call(a)=="[object Function]",d,f;for(d in a)!(c&&d=="prototype")&&m.call(a,d)&&!(f=d==="constructor")&&b(d);(f||m.call(a,d="constructor"))&&b(d)};else{j=["valueOf","toString","toLocaleString",
+"propertyIsEnumerable","isPrototypeOf","hasOwnProperty","constructor"];a=function(a,b){var c=l.call(a)=="[object Function]",d;for(d in a)!(c&&d=="prototype")&&m.call(a,d)&&b(d);for(c=j.length;d=j[--c];m.call(a,d)&&b(d));}}a(b,c)};R("json-stringify")||(r={"\\":"\\\\",'"':'\\"',"\u0008":"\\b","\u000c":"\\f","\n":"\\n","\r":"\\r","\t":"\\t"},t=function(b,c){return("000000"+(c||0)).slice(-b)},u=function(b){for(var c='"',a=0,d;d=b.charAt(a);a++)c=c+('\\"\u0008\u000c\n\r\t'.indexOf(d)>-1?r[d]:r[d]=d<" "?
+"\\u00"+t(2,d.charCodeAt(0).toString(16)):d);return c+'"'},x=function(b,c,a,d,j,f,o){var g=c[b],h,s,v,w,L,M,N,y,A;if(typeof g=="object"&&g){h=l.call(g);if(h=="[object Date]"&&!m.call(g,"toJSON"))if(g>-1/0&&g<1/0){if(P){v=K(g/864E5);for(h=K(v/365.2425)+1970-1;P(h+1,0)<=v;h++);for(s=K((v-P(h,0))/30.42);P(h,s+1)<=v;s++);v=1+v-P(h,s);w=(g%864E5+864E5)%864E5;L=K(w/36E5)%24;M=K(w/6E4)%60;N=K(w/1E3)%60;w=w%1E3}else{h=g.getUTCFullYear();s=g.getUTCMonth();v=g.getUTCDate();L=g.getUTCHours();M=g.getUTCMinutes();
+N=g.getUTCSeconds();w=g.getUTCMilliseconds()}g=(h<=0||h>=1E4?(h<0?"-":"+")+t(6,h<0?-h:h):t(4,h))+"-"+t(2,s+1)+"-"+t(2,v)+"T"+t(2,L)+":"+t(2,M)+":"+t(2,N)+"."+t(3,w)+"Z"}else g=k;else if(typeof g.toJSON=="function"&&(h!="[object Number]"&&h!="[object String]"&&h!="[object Array]"||m.call(g,"toJSON")))g=g.toJSON(b)}a&&(g=a.call(c,b,g));if(g===k)return"null";h=l.call(g);if(h=="[object Boolean]")return""+g;if(h=="[object Number]")return g>-1/0&&g<1/0?""+g:"null";if(h=="[object String]")return u(g);if(typeof g==
+"object"){for(b=o.length;b--;)if(o[b]===g)throw TypeError();o.push(g);y=[];c=f;f=f+j;if(h=="[object Array]"){s=0;for(b=g.length;s<b;A||(A=i),s++){h=x(s,g,a,d,j,f,o);y.push(h===e?"null":h)}b=A?j?"[\n"+f+y.join(",\n"+f)+"\n"+c+"]":"["+y.join(",")+"]":"[]"}else{n(d||g,function(b){var c=x(b,g,a,d,j,f,o);c!==e&&y.push(u(b)+":"+(j?" ":"")+c);A||(A=i)});b=A?j?"{\n"+f+y.join(",\n"+f)+"\n"+c+"}":"{"+y.join(",")+"}":"{}"}o.pop();return b}},q.stringify=function(b,c,a){var d,j,f,o,g,h;if(typeof c=="function"||
+typeof c=="object"&&c)if(l.call(c)=="[object Function]")j=c;else if(l.call(c)=="[object Array]"){f={};o=0;for(g=c.length;o<g;h=c[o++],(l.call(h)=="[object String]"||l.call(h)=="[object Number]")&&(f[h]=1));}if(a)if(l.call(a)=="[object Number]"){if((a=a-a%1)>0){d="";for(a>10&&(a=10);d.length<a;d=d+" ");}}else l.call(a)=="[object String]"&&(d=a.length<=10?a:a.slice(0,10));return x("",(h={},h[""]=b,h),j,f,d,"",[])});R("json-parse")||(z=String.fromCharCode,B={"\\":"\\",'"':'"',"/":"/",b:"\u0008",t:"\t",
+n:"\n",f:"\u000c",r:"\r"},C=function(){H=I=k;throw SyntaxError();},D=function(){for(var b=I,c=b.length,a,d,j,f,o;H<c;){a=b.charAt(H);if("\t\r\n ".indexOf(a)>-1)H++;else{if("{}[]:,".indexOf(a)>-1){H++;return a}if(a=='"'){d="@";for(H++;H<c;){a=b.charAt(H);if(a<" ")C();else if(a=="\\"){a=b.charAt(++H);if('\\"/btnfr'.indexOf(a)>-1){d=d+B[a];H++}else if(a=="u"){j=++H;for(f=H+4;H<f;H++){a=b.charAt(H);a>="0"&&a<="9"||a>="a"&&a<="f"||a>="A"&&a<="F"||C()}d=d+z("0x"+b.slice(j,H))}else C()}else{if(a=='"')break;
+d=d+a;H++}}if(b.charAt(H)=='"'){H++;return d}}else{j=H;if(a=="-"){o=i;a=b.charAt(++H)}if(a>="0"&&a<="9"){for(a=="0"&&(a=b.charAt(H+1),a>="0"&&a<="9")&&C();H<c&&(a=b.charAt(H),a>="0"&&a<="9");H++);if(b.charAt(H)=="."){for(f=++H;f<c&&(a=b.charAt(f),a>="0"&&a<="9");f++);f==H&&C();H=f}a=b.charAt(H);if(a=="e"||a=="E"){a=b.charAt(++H);(a=="+"||a=="-")&&H++;for(f=H;f<c&&(a=b.charAt(f),a>="0"&&a<="9");f++);f==H&&C();H=f}return+b.slice(j,H)}o&&C();if(b.slice(H,H+4)=="true"){H=H+4;return i}if(b.slice(H,H+5)==
+"false"){H=H+5;return false}if(b.slice(H,H+4)=="null"){H=H+4;return k}}C()}}return"$"},E=function(b){var c,a;b=="$"&&C();if(typeof b=="string"){if(b.charAt(0)=="@")return b.slice(1);if(b=="["){for(c=[];;a||(a=i)){b=D();if(b=="]")break;if(a)if(b==","){b=D();b=="]"&&C()}else C();b==","&&C();c.push(E(b))}return c}if(b=="{"){for(c={};;a||(a=i)){b=D();if(b=="}")break;if(a)if(b==","){b=D();b=="}"&&C()}else C();(b==","||typeof b!="string"||b.charAt(0)!="@"||D()!=":")&&C();c[b.slice(1)]=E(D())}return c}C()}return b},
+G=function(b,c,a){a=F(b,c,a);a===e?delete b[c]:b[c]=a},F=function(b,c,a){var d=b[c],j;if(typeof d=="object"&&d)if(l.call(d)=="[object Array]")for(j=d.length;j--;)G(d,j,a);else n(d,function(b){G(d,b,a)});return a.call(b,c,d)},q.parse=function(b,c){var a,d;H=0;I=b;a=E(D());D()!="$"&&C();H=I=k;return c&&l.call(c)=="[object Function]"?F((d={},d[""]=a,d),"",c):a})}p&&define(function(){return q});
+}());
+})();

+ 26 - 0
editor/js/libs/ternjs/signal.js

@@ -0,0 +1,26 @@
+(function(root, mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    return mod(exports);
+  if (typeof define == "function" && define.amd) // AMD
+    return define(["exports"], mod);
+  mod((root.tern || (root.tern = {})).signal = {}); // Plain browser env
+})(this, function(exports) {
+  function on(type, f) {
+    var handlers = this._handlers || (this._handlers = Object.create(null));
+    (handlers[type] || (handlers[type] = [])).push(f);
+  }
+  function off(type, f) {
+    var arr = this._handlers && this._handlers[type];
+    if (arr) for (var i = 0; i < arr.length; ++i)
+      if (arr[i] == f) { arr.splice(i, 1); break; }
+  }
+  function signal(type, a1, a2, a3, a4) {
+    var arr = this._handlers && this._handlers[type];
+    if (arr) for (var i = 0; i < arr.length; ++i) arr[i].call(this, a1, a2, a3, a4);
+  }
+
+  exports.mixin = function(obj) {
+    obj.on = on; obj.off = off; obj.signal = signal;
+    return obj;
+  };
+});

+ 994 - 0
editor/js/libs/ternjs/tern.js

@@ -0,0 +1,994 @@
+// The Tern server object
+
+// A server is a stateful object that manages the analysis for a
+// project, and defines an interface for querying the code in the
+// project.
+
+(function(root, mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    return mod(exports, require("./infer"), require("./signal"),
+               require("acorn"), require("acorn/dist/walk"));
+  if (typeof define == "function" && define.amd) // AMD
+    return define(["exports", "./infer", "./signal", "acorn/dist/acorn", "acorn/dist/walk"], mod);
+  mod(root.tern || (root.tern = {}), tern, tern.signal, acorn, acorn.walk); // Plain browser env
+})(this, function(exports, infer, signal, acorn, walk) {
+  "use strict";
+
+  var plugins = Object.create(null);
+  exports.registerPlugin = function(name, init) { plugins[name] = init; };
+
+  var defaultOptions = exports.defaultOptions = {
+    debug: false,
+    async: false,
+    getFile: function(_f, c) { if (this.async) c(null, null); },
+    defs: [],
+    plugins: {},
+    fetchTimeout: 1000,
+    dependencyBudget: 20000,
+    reuseInstances: true,
+    stripCRs: false
+  };
+
+  var queryTypes = {
+    completions: {
+      takesFile: true,
+      run: findCompletions
+    },
+    properties: {
+      run: findProperties
+    },
+    type: {
+      takesFile: true,
+      run: findTypeAt
+    },
+    documentation: {
+      takesFile: true,
+      run: findDocs
+    },
+    definition: {
+      takesFile: true,
+      run: findDef
+    },
+    refs: {
+      takesFile: true,
+      fullFile: true,
+      run: findRefs
+    },
+    rename: {
+      takesFile: true,
+      fullFile: true,
+      run: buildRename
+    },
+    files: {
+      run: listFiles
+    }
+  };
+
+  exports.defineQueryType = function(name, desc) { queryTypes[name] = desc; };
+
+  function File(name, parent) {
+    this.name = name;
+    this.parent = parent;
+    this.scope = this.text = this.ast = this.lineOffsets = null;
+  }
+  File.prototype.asLineChar = function(pos) { return asLineChar(this, pos); };
+
+  function updateText(file, text, srv) {
+    file.text = srv.options.stripCRs ? text.replace(/\r\n/g, "\n") : text;
+    infer.withContext(srv.cx, function() {
+      file.ast = infer.parse(file.text, srv.passes, {directSourceFile: file, allowReturnOutsideFunction: true});
+    });
+    file.lineOffsets = null;
+  }
+
+  var Server = exports.Server = function(options) {
+    this.cx = null;
+    this.options = options || {};
+    for (var o in defaultOptions) if (!options.hasOwnProperty(o))
+      options[o] = defaultOptions[o];
+
+    this.handlers = Object.create(null);
+    this.files = [];
+    this.fileMap = Object.create(null);
+    this.needsPurge = [];
+    this.budgets = Object.create(null);
+    this.uses = 0;
+    this.pending = 0;
+    this.asyncError = null;
+    this.passes = Object.create(null);
+
+    this.defs = options.defs.slice(0);
+    for (var plugin in options.plugins) if (options.plugins.hasOwnProperty(plugin) && plugin in plugins) {
+      var init = plugins[plugin](this, options.plugins[plugin]);
+      if (init && init.defs) {
+        if (init.loadFirst) this.defs.unshift(init.defs);
+        else this.defs.push(init.defs);
+      }
+      if (init && init.passes) for (var type in init.passes) if (init.passes.hasOwnProperty(type))
+        (this.passes[type] || (this.passes[type] = [])).push(init.passes[type]);
+    }
+
+    this.reset();
+  };
+  Server.prototype = signal.mixin({
+    addFile: function(name, /*optional*/ text, parent) {
+      // Don't crash when sloppy plugins pass non-existent parent ids
+      if (parent && !(parent in this.fileMap)) parent = null;
+      ensureFile(this, name, parent, text);
+    },
+    delFile: function(name) {
+      var file = this.findFile(name);
+      if (file) {
+        this.needsPurge.push(file.name);
+        this.files.splice(this.files.indexOf(file), 1);
+        delete this.fileMap[name];
+      }
+    },
+    reset: function() {
+      this.signal("reset");
+      this.cx = new infer.Context(this.defs, this);
+      this.uses = 0;
+      this.budgets = Object.create(null);
+      for (var i = 0; i < this.files.length; ++i) {
+        var file = this.files[i];
+        file.scope = null;
+      }
+    },
+
+    request: function(doc, c) {
+      var inv = invalidDoc(doc);
+      if (inv) return c(inv);
+
+      var self = this;
+      doRequest(this, doc, function(err, data) {
+        c(err, data);
+        if (self.uses > 40) {
+          self.reset();
+          analyzeAll(self, null, function(){});
+        }
+      });
+    },
+
+    findFile: function(name) {
+      return this.fileMap[name];
+    },
+
+    flush: function(c) {
+      var cx = this.cx;
+      analyzeAll(this, null, function(err) {
+        if (err) return c(err);
+        infer.withContext(cx, c);
+      });
+    },
+
+    startAsyncAction: function() {
+      ++this.pending;
+    },
+    finishAsyncAction: function(err) {
+      if (err) this.asyncError = err;
+      if (--this.pending === 0) this.signal("everythingFetched");
+    }
+  });
+
+  function doRequest(srv, doc, c) {
+    if (doc.query && !queryTypes.hasOwnProperty(doc.query.type))
+      return c("No query type '" + doc.query.type + "' defined");
+
+    var query = doc.query;
+    // Respond as soon as possible when this just uploads files
+    if (!query) c(null, {});
+
+    var files = doc.files || [];
+    if (files.length) ++srv.uses;
+    for (var i = 0; i < files.length; ++i) {
+      var file = files[i];
+      if (file.type == "delete")
+        srv.delFile(file.name);
+      else
+        ensureFile(srv, file.name, null, file.type == "full" ? file.text : null);
+    }
+
+    var timeBudget = typeof doc.timeout == "number" ? [doc.timeout] : null;
+    if (!query) {
+      analyzeAll(srv, timeBudget, function(){});
+      return;
+    }
+
+    var queryType = queryTypes[query.type];
+    if (queryType.takesFile) {
+      if (typeof query.file != "string") return c(".query.file must be a string");
+      if (!/^#/.test(query.file)) ensureFile(srv, query.file, null);
+    }
+
+    analyzeAll(srv, timeBudget, function(err) {
+      if (err) return c(err);
+      var file = queryType.takesFile && resolveFile(srv, files, query.file);
+      if (queryType.fullFile && file.type == "part")
+        return c("Can't run a " + query.type + " query on a file fragment");
+
+      function run() {
+        var result;
+        try {
+          result = queryType.run(srv, query, file);
+        } catch (e) {
+          if (srv.options.debug && e.name != "TernError") console.error(e.stack);
+          return c(e);
+        }
+        c(null, result);
+      }
+      infer.withContext(srv.cx, timeBudget ? function() { infer.withTimeout(timeBudget[0], run); } : run);
+    });
+  }
+
+  function analyzeFile(srv, file) {
+    infer.withContext(srv.cx, function() {
+      file.scope = srv.cx.topScope;
+      srv.signal("beforeLoad", file);
+      infer.analyze(file.ast, file.name, file.scope, srv.passes);
+      srv.signal("afterLoad", file);
+    });
+    return file;
+  }
+
+  function ensureFile(srv, name, parent, text) {
+    var known = srv.findFile(name);
+    if (known) {
+      if (text != null) {
+        if (known.scope) {
+          srv.needsPurge.push(name);
+          known.scope = null;
+        }
+        updateText(known, text, srv);
+      }
+      if (parentDepth(srv, known.parent) > parentDepth(srv, parent)) {
+        known.parent = parent;
+        if (known.excluded) known.excluded = null;
+      }
+      return;
+    }
+
+    var file = new File(name, parent);
+    srv.files.push(file);
+    srv.fileMap[name] = file;
+    if (text != null) {
+      updateText(file, text, srv);
+    } else if (srv.options.async) {
+      srv.startAsyncAction();
+      srv.options.getFile(name, function(err, text) {
+        updateText(file, text || "", srv);
+        srv.finishAsyncAction(err);
+      });
+    } else {
+      updateText(file, srv.options.getFile(name) || "", srv);
+    }
+  }
+
+  function fetchAll(srv, c) {
+    var done = true, returned = false;
+    srv.files.forEach(function(file) {
+      if (file.text != null) return;
+      if (srv.options.async) {
+        done = false;
+        srv.options.getFile(file.name, function(err, text) {
+          if (err && !returned) { returned = true; return c(err); }
+          updateText(file, text || "", srv);
+          fetchAll(srv, c);
+        });
+      } else {
+        try {
+          updateText(file, srv.options.getFile(file.name) || "", srv);
+        } catch (e) { return c(e); }
+      }
+    });
+    if (done) c();
+  }
+
+  function waitOnFetch(srv, timeBudget, c) {
+    var done = function() {
+      srv.off("everythingFetched", done);
+      clearTimeout(timeout);
+      analyzeAll(srv, timeBudget, c);
+    };
+    srv.on("everythingFetched", done);
+    var timeout = setTimeout(done, srv.options.fetchTimeout);
+  }
+
+  function analyzeAll(srv, timeBudget, c) {
+    if (srv.pending) return waitOnFetch(srv, timeBudget, c);
+
+    var e = srv.fetchError;
+    if (e) { srv.fetchError = null; return c(e); }
+
+    if (srv.needsPurge.length > 0) infer.withContext(srv.cx, function() {
+      infer.purge(srv.needsPurge);
+      srv.needsPurge.length = 0;
+    });
+
+    var done = true;
+    // The second inner loop might add new files. The outer loop keeps
+    // repeating both inner loops until all files have been looked at.
+    for (var i = 0; i < srv.files.length;) {
+      var toAnalyze = [];
+      for (; i < srv.files.length; ++i) {
+        var file = srv.files[i];
+        if (file.text == null) done = false;
+        else if (file.scope == null && !file.excluded) toAnalyze.push(file);
+      }
+      toAnalyze.sort(function(a, b) {
+        return parentDepth(srv, a.parent) - parentDepth(srv, b.parent);
+      });
+      for (var j = 0; j < toAnalyze.length; j++) {
+        var file = toAnalyze[j];
+        if (file.parent && !chargeOnBudget(srv, file)) {
+          file.excluded = true;
+        } else if (timeBudget) {
+          var startTime = +new Date;
+          infer.withTimeout(timeBudget[0], function() { analyzeFile(srv, file); });
+          timeBudget[0] -= +new Date - startTime;
+        } else {
+          analyzeFile(srv, file);
+        }
+      }
+    }
+    if (done) c();
+    else waitOnFetch(srv, timeBudget, c);
+  }
+
+  function firstLine(str) {
+    var end = str.indexOf("\n");
+    if (end < 0) return str;
+    return str.slice(0, end);
+  }
+
+  function findMatchingPosition(line, file, near) {
+    var pos = Math.max(0, near - 500), closest = null;
+    if (!/^\s*$/.test(line)) for (;;) {
+      var found = file.indexOf(line, pos);
+      if (found < 0 || found > near + 500) break;
+      if (closest == null || Math.abs(closest - near) > Math.abs(found - near))
+        closest = found;
+      pos = found + line.length;
+    }
+    return closest;
+  }
+
+  function scopeDepth(s) {
+    for (var i = 0; s; ++i, s = s.prev) {}
+    return i;
+  }
+
+  function ternError(msg) {
+    var err = new Error(msg);
+    err.name = "TernError";
+    return err;
+  }
+
+  function resolveFile(srv, localFiles, name) {
+    var isRef = name.match(/^#(\d+)$/);
+    if (!isRef) return srv.findFile(name);
+
+    var file = localFiles[isRef[1]];
+    if (!file || file.type == "delete") throw ternError("Reference to unknown file " + name);
+    if (file.type == "full") return srv.findFile(file.name);
+
+    // This is a partial file
+
+    var realFile = file.backing = srv.findFile(file.name);
+    var offset = file.offset;
+    if (file.offsetLines) offset = {line: file.offsetLines, ch: 0};
+    file.offset = offset = resolvePos(realFile, file.offsetLines == null ? file.offset : {line: file.offsetLines, ch: 0}, true);
+    var line = firstLine(file.text);
+    var foundPos = findMatchingPosition(line, realFile.text, offset);
+    var pos = foundPos == null ? Math.max(0, realFile.text.lastIndexOf("\n", offset)) : foundPos;
+    var inObject, atFunction;
+
+    infer.withContext(srv.cx, function() {
+      infer.purge(file.name, pos, pos + file.text.length);
+
+      var text = file.text, m;
+      if (m = text.match(/(?:"([^"]*)"|([\w$]+))\s*:\s*function\b/)) {
+        var objNode = walk.findNodeAround(file.backing.ast, pos, "ObjectExpression");
+        if (objNode && objNode.node.objType)
+          inObject = {type: objNode.node.objType, prop: m[2] || m[1]};
+      }
+      if (foundPos && (m = line.match(/^(.*?)\bfunction\b/))) {
+        var cut = m[1].length, white = "";
+        for (var i = 0; i < cut; ++i) white += " ";
+        text = white + text.slice(cut);
+        atFunction = true;
+      }
+
+      var scopeStart = infer.scopeAt(realFile.ast, pos, realFile.scope);
+      var scopeEnd = infer.scopeAt(realFile.ast, pos + text.length, realFile.scope);
+      var scope = file.scope = scopeDepth(scopeStart) < scopeDepth(scopeEnd) ? scopeEnd : scopeStart;
+      file.ast = infer.parse(text, srv.passes, {directSourceFile: file, allowReturnOutsideFunction: true});
+      infer.analyze(file.ast, file.name, scope, srv.passes);
+
+      // This is a kludge to tie together the function types (if any)
+      // outside and inside of the fragment, so that arguments and
+      // return values have some information known about them.
+      tieTogether: if (inObject || atFunction) {
+        var newInner = infer.scopeAt(file.ast, line.length, scopeStart);
+        if (!newInner.fnType) break tieTogether;
+        if (inObject) {
+          var prop = inObject.type.getProp(inObject.prop);
+          prop.addType(newInner.fnType);
+        } else if (atFunction) {
+          var inner = infer.scopeAt(realFile.ast, pos + line.length, realFile.scope);
+          if (inner == scopeStart || !inner.fnType) break tieTogether;
+          var fOld = inner.fnType, fNew = newInner.fnType;
+          if (!fNew || (fNew.name != fOld.name && fOld.name)) break tieTogether;
+          for (var i = 0, e = Math.min(fOld.args.length, fNew.args.length); i < e; ++i)
+            fOld.args[i].propagate(fNew.args[i]);
+          fOld.self.propagate(fNew.self);
+          fNew.retval.propagate(fOld.retval);
+        }
+      }
+    });
+    return file;
+  }
+
+  // Budget management
+
+  function astSize(node) {
+    var size = 0;
+    walk.simple(node, {Expression: function() { ++size; }});
+    return size;
+  }
+
+  function parentDepth(srv, parent) {
+    var depth = 0;
+    while (parent) {
+      parent = srv.findFile(parent).parent;
+      ++depth;
+    }
+    return depth;
+  }
+
+  function budgetName(srv, file) {
+    for (;;) {
+      var parent = srv.findFile(file.parent);
+      if (!parent.parent) break;
+      file = parent;
+    }
+    return file.name;
+  }
+
+  function chargeOnBudget(srv, file) {
+    var bName = budgetName(srv, file);
+    var size = astSize(file.ast);
+    var known = srv.budgets[bName];
+    if (known == null)
+      known = srv.budgets[bName] = srv.options.dependencyBudget;
+    if (known < size) return false;
+    srv.budgets[bName] = known - size;
+    return true;
+  }
+
+  // Query helpers
+
+  function isPosition(val) {
+    return typeof val == "number" || typeof val == "object" &&
+      typeof val.line == "number" && typeof val.ch == "number";
+  }
+
+  // Baseline query document validation
+  function invalidDoc(doc) {
+    if (doc.query) {
+      if (typeof doc.query.type != "string") return ".query.type must be a string";
+      if (doc.query.start && !isPosition(doc.query.start)) return ".query.start must be a position";
+      if (doc.query.end && !isPosition(doc.query.end)) return ".query.end must be a position";
+    }
+    if (doc.files) {
+      if (!Array.isArray(doc.files)) return "Files property must be an array";
+      for (var i = 0; i < doc.files.length; ++i) {
+        var file = doc.files[i];
+        if (typeof file != "object") return ".files[n] must be objects";
+        else if (typeof file.name != "string") return ".files[n].name must be a string";
+        else if (file.type == "delete") continue;
+        else if (typeof file.text != "string") return ".files[n].text must be a string";
+        else if (file.type == "part") {
+          if (!isPosition(file.offset) && typeof file.offsetLines != "number")
+            return ".files[n].offset must be a position";
+        } else if (file.type != "full") return ".files[n].type must be \"full\" or \"part\"";
+      }
+    }
+  }
+
+  var offsetSkipLines = 25;
+
+  function findLineStart(file, line) {
+    var text = file.text, offsets = file.lineOffsets || (file.lineOffsets = [0]);
+    var pos = 0, curLine = 0;
+    var storePos = Math.min(Math.floor(line / offsetSkipLines), offsets.length - 1);
+    var pos = offsets[storePos], curLine = storePos * offsetSkipLines;
+
+    while (curLine < line) {
+      ++curLine;
+      pos = text.indexOf("\n", pos) + 1;
+      if (pos === 0) return null;
+      if (curLine % offsetSkipLines === 0) offsets.push(pos);
+    }
+    return pos;
+  }
+
+  var resolvePos = exports.resolvePos = function(file, pos, tolerant) {
+    if (typeof pos != "number") {
+      var lineStart = findLineStart(file, pos.line);
+      if (lineStart == null) {
+        if (tolerant) pos = file.text.length;
+        else throw ternError("File doesn't contain a line " + pos.line);
+      } else {
+        pos = lineStart + pos.ch;
+      }
+    }
+    if (pos > file.text.length) {
+      if (tolerant) pos = file.text.length;
+      else throw ternError("Position " + pos + " is outside of file.");
+    }
+    return pos;
+  };
+
+  function asLineChar(file, pos) {
+    if (!file) return {line: 0, ch: 0};
+    var offsets = file.lineOffsets || (file.lineOffsets = [0]);
+    var text = file.text, line, lineStart;
+    for (var i = offsets.length - 1; i >= 0; --i) if (offsets[i] <= pos) {
+      line = i * offsetSkipLines;
+      lineStart = offsets[i];
+    }
+    for (;;) {
+      var eol = text.indexOf("\n", lineStart);
+      if (eol >= pos || eol < 0) break;
+      lineStart = eol + 1;
+      ++line;
+    }
+    return {line: line, ch: pos - lineStart};
+  }
+
+  var outputPos = exports.outputPos = function(query, file, pos) {
+    if (query.lineCharPositions) {
+      var out = asLineChar(file, pos);
+      if (file.type == "part")
+        out.line += file.offsetLines != null ? file.offsetLines : asLineChar(file.backing, file.offset).line;
+      return out;
+    } else {
+      return pos + (file.type == "part" ? file.offset : 0);
+    }
+  };
+
+  // Delete empty fields from result objects
+  function clean(obj) {
+    for (var prop in obj) if (obj[prop] == null) delete obj[prop];
+    return obj;
+  }
+  function maybeSet(obj, prop, val) {
+    if (val != null) obj[prop] = val;
+  }
+
+  // Built-in query types
+
+  function compareCompletions(a, b) {
+    if (typeof a != "string") { a = a.name; b = b.name; }
+    var aUp = /^[A-Z]/.test(a), bUp = /^[A-Z]/.test(b);
+    if (aUp == bUp) return a < b ? -1 : a == b ? 0 : 1;
+    else return aUp ? 1 : -1;
+  }
+
+  function isStringAround(node, start, end) {
+    return node.type == "Literal" && typeof node.value == "string" &&
+      node.start == start - 1 && node.end <= end + 1;
+  }
+
+  function pointInProp(objNode, point) {
+    for (var i = 0; i < objNode.properties.length; i++) {
+      var curProp = objNode.properties[i];
+      if (curProp.key.start <= point && curProp.key.end >= point)
+        return curProp;
+    }
+  }
+
+  var jsKeywords = ("break do instanceof typeof case else new var " +
+    "catch finally return void continue for switch while debugger " +
+    "function this with default if throw delete in try").split(" ");
+
+  function findCompletions(srv, query, file) {
+    if (query.end == null) throw ternError("missing .query.end field");
+    if (srv.passes.completion) for (var i = 0; i < srv.passes.completion.length; i++) {
+      var result = srv.passes.completion[i](file, query);
+      if (result) return result;
+    }
+
+    var wordStart = resolvePos(file, query.end), wordEnd = wordStart, text = file.text;
+    while (wordStart && acorn.isIdentifierChar(text.charCodeAt(wordStart - 1))) --wordStart;
+    if (query.expandWordForward !== false)
+      while (wordEnd < text.length && acorn.isIdentifierChar(text.charCodeAt(wordEnd))) ++wordEnd;
+    var word = text.slice(wordStart, wordEnd), completions = [], ignoreObj;
+    if (query.caseInsensitive) word = word.toLowerCase();
+    var wrapAsObjs = query.types || query.depths || query.docs || query.urls || query.origins;
+
+    function gather(prop, obj, depth, addInfo) {
+      // 'hasOwnProperty' and such are usually just noise, leave them
+      // out when no prefix is provided.
+      if ((objLit || query.omitObjectPrototype !== false) && obj == srv.cx.protos.Object && !word) return;
+      if (query.filter !== false && word &&
+          (query.caseInsensitive ? prop.toLowerCase() : prop).indexOf(word) !== 0) return;
+      if (ignoreObj && ignoreObj.props[prop]) return;
+      for (var i = 0; i < completions.length; ++i) {
+        var c = completions[i];
+        if ((wrapAsObjs ? c.name : c) == prop) return;
+      }
+      var rec = wrapAsObjs ? {name: prop} : prop;
+      completions.push(rec);
+
+      if (obj && (query.types || query.docs || query.urls || query.origins)) {
+        var val = obj.props[prop];
+        infer.resetGuessing();
+        var type = val.getType();
+        rec.guess = infer.didGuess();
+        if (query.types)
+          rec.type = infer.toString(val);
+        if (query.docs)
+          maybeSet(rec, "doc", val.doc || type && type.doc);
+        if (query.urls)
+          maybeSet(rec, "url", val.url || type && type.url);
+        if (query.origins)
+          maybeSet(rec, "origin", val.origin || type && type.origin);
+      }
+      if (query.depths) rec.depth = depth;
+      if (wrapAsObjs && addInfo) addInfo(rec);
+    }
+
+    var hookname, prop, objType, isKey;
+
+    var exprAt = infer.findExpressionAround(file.ast, null, wordStart, file.scope);
+    var memberExpr, objLit;
+    // Decide whether this is an object property, either in a member
+    // expression or an object literal.
+    if (exprAt) {
+      if (exprAt.node.type == "MemberExpression" && exprAt.node.object.end < wordStart) {
+        memberExpr = exprAt;
+      } else if (isStringAround(exprAt.node, wordStart, wordEnd)) {
+        var parent = infer.parentNode(exprAt.node, file.ast);
+        if (parent.type == "MemberExpression" && parent.property == exprAt.node)
+          memberExpr = {node: parent, state: exprAt.state};
+      } else if (exprAt.node.type == "ObjectExpression") {
+        var objProp = pointInProp(exprAt.node, wordEnd);
+        if (objProp) {
+          objLit = exprAt;
+          prop = isKey = objProp.key.name;
+        } else if (!word && !/:\s*$/.test(file.text.slice(0, wordStart))) {
+          objLit = exprAt;
+          prop = isKey = true;
+        }
+      }
+    }
+
+    if (objLit) {
+      // Since we can't use the type of the literal itself to complete
+      // its properties (it doesn't contain the information we need),
+      // we have to try asking the surrounding expression for type info.
+      objType = infer.typeFromContext(file.ast, objLit);
+      ignoreObj = objLit.node.objType;
+    } else if (memberExpr) {
+      prop = memberExpr.node.property;
+      prop = prop.type == "Literal" ? prop.value.slice(1) : prop.name;
+      memberExpr.node = memberExpr.node.object;
+      objType = infer.expressionType(memberExpr);
+    } else if (text.charAt(wordStart - 1) == ".") {
+      var pathStart = wordStart - 1;
+      while (pathStart && (text.charAt(pathStart - 1) == "." || acorn.isIdentifierChar(text.charCodeAt(pathStart - 1)))) pathStart--;
+      var path = text.slice(pathStart, wordStart - 1);
+      if (path) {
+        objType = infer.def.parsePath(path, file.scope).getObjType();
+        prop = word;
+      }
+    }
+
+    if (prop != null) {
+      srv.cx.completingProperty = prop;
+
+      if (objType) infer.forAllPropertiesOf(objType, gather);
+
+      if (!completions.length && query.guess !== false && objType && objType.guessProperties)
+        objType.guessProperties(function(p, o, d) {if (p != prop && p != "✖") gather(p, o, d);});
+      if (!completions.length && word.length >= 2 && query.guess !== false)
+        for (var prop in srv.cx.props) gather(prop, srv.cx.props[prop][0], 0);
+      hookname = "memberCompletion";
+    } else {
+      infer.forAllLocalsAt(file.ast, wordStart, file.scope, gather);
+      if (query.includeKeywords) jsKeywords.forEach(function(kw) {
+        gather(kw, null, 0, function(rec) { rec.isKeyword = true; });
+      });
+      hookname = "variableCompletion";
+    }
+    if (srv.passes[hookname])
+      srv.passes[hookname].forEach(function(hook) {hook(file, wordStart, wordEnd, gather);});
+
+    if (query.sort !== false) completions.sort(compareCompletions);
+    srv.cx.completingProperty = null;
+
+    return {start: outputPos(query, file, wordStart),
+            end: outputPos(query, file, wordEnd),
+            isProperty: !!prop,
+            isObjectKey: !!isKey,
+            completions: completions};
+  }
+
+  function findProperties(srv, query) {
+    var prefix = query.prefix, found = [];
+    for (var prop in srv.cx.props)
+      if (prop != "<i>" && (!prefix || prop.indexOf(prefix) === 0)) found.push(prop);
+    if (query.sort !== false) found.sort(compareCompletions);
+    return {completions: found};
+  }
+
+  var findExpr = exports.findQueryExpr = function(file, query, wide) {
+    if (query.end == null) throw ternError("missing .query.end field");
+
+    if (query.variable) {
+      var scope = infer.scopeAt(file.ast, resolvePos(file, query.end), file.scope);
+      return {node: {type: "Identifier", name: query.variable, start: query.end, end: query.end + 1},
+              state: scope};
+    } else {
+      var start = query.start && resolvePos(file, query.start), end = resolvePos(file, query.end);
+      var expr = infer.findExpressionAt(file.ast, start, end, file.scope);
+      if (expr) return expr;
+      expr = infer.findExpressionAround(file.ast, start, end, file.scope);
+      if (expr && (expr.node.type == "ObjectExpression" || wide ||
+                   (start == null ? end : start) - expr.node.start < 20 || expr.node.end - end < 20))
+        return expr;
+      return null;
+    }
+  };
+
+  function findExprOrThrow(file, query, wide) {
+    var expr = findExpr(file, query, wide);
+    if (expr) return expr;
+    throw ternError("No expression at the given position.");
+  }
+
+  function ensureObj(tp) {
+    if (!tp || !(tp = tp.getType()) || !(tp instanceof infer.Obj)) return null;
+    return tp;
+  }
+
+  function findExprType(srv, query, file, expr) {
+    var type;
+    if (expr) {
+      infer.resetGuessing();
+      type = infer.expressionType(expr);
+    }
+    if (srv.passes["typeAt"]) {
+      var pos = resolvePos(file, query.end);
+      srv.passes["typeAt"].forEach(function(hook) {
+        type = hook(file, pos, expr, type);
+      });
+    }
+    if (!type) throw ternError("No type found at the given position.");
+
+    var objProp;
+    if (expr.node.type == "ObjectExpression" && query.end != null &&
+        (objProp = pointInProp(expr.node, resolvePos(file, query.end)))) {
+      var name = objProp.key.name;
+      var fromCx = ensureObj(infer.typeFromContext(file.ast, expr));
+      if (fromCx && fromCx.hasProp(name)) {
+        type = fromCx.hasProp(name);
+      } else {
+        var fromLocal = ensureObj(type);
+        if (fromLocal && fromLocal.hasProp(name))
+          type = fromLocal.hasProp(name);
+      }
+    }
+    return type;
+  };
+
+  function findTypeAt(srv, query, file) {
+    var expr = findExpr(file, query), exprName;
+    var type = findExprType(srv, query, file, expr), exprType = type;
+    if (query.preferFunction)
+      type = type.getFunctionType() || type.getType();
+    else
+      type = type.getType();
+
+    if (expr) {
+      if (expr.node.type == "Identifier")
+        exprName = expr.node.name;
+      else if (expr.node.type == "MemberExpression" && !expr.node.computed)
+        exprName = expr.node.property.name;
+    }
+
+    if (query.depth != null && typeof query.depth != "number")
+      throw ternError(".query.depth must be a number");
+
+    var result = {guess: infer.didGuess(),
+                  type: infer.toString(exprType, query.depth),
+                  name: type && type.name,
+                  exprName: exprName};
+    if (type) storeTypeDocs(type, result);
+    if (!result.doc && exprType.doc) result.doc = exprType.doc;
+
+    return clean(result);
+  }
+
+  function findDocs(srv, query, file) {
+    var expr = findExpr(file, query);
+    var type = findExprType(srv, query, file, expr);
+    var result = {url: type.url, doc: type.doc, type: infer.toString(type)};
+    var inner = type.getType();
+    if (inner) storeTypeDocs(inner, result);
+    return clean(result);
+  }
+
+  function storeTypeDocs(type, out) {
+    if (!out.url) out.url = type.url;
+    if (!out.doc) out.doc = type.doc;
+    if (!out.origin) out.origin = type.origin;
+    var ctor, boring = infer.cx().protos;
+    if (!out.url && !out.doc && type.proto && (ctor = type.proto.hasCtor) &&
+        type.proto != boring.Object && type.proto != boring.Function && type.proto != boring.Array) {
+      out.url = ctor.url;
+      out.doc = ctor.doc;
+    }
+  }
+
+  var getSpan = exports.getSpan = function(obj) {
+    if (!obj.origin) return;
+    if (obj.originNode) {
+      var node = obj.originNode;
+      if (/^Function/.test(node.type) && node.id) node = node.id;
+      return {origin: obj.origin, node: node};
+    }
+    if (obj.span) return {origin: obj.origin, span: obj.span};
+  };
+
+  var storeSpan = exports.storeSpan = function(srv, query, span, target) {
+    target.origin = span.origin;
+    if (span.span) {
+      var m = /^(\d+)\[(\d+):(\d+)\]-(\d+)\[(\d+):(\d+)\]$/.exec(span.span);
+      target.start = query.lineCharPositions ? {line: Number(m[2]), ch: Number(m[3])} : Number(m[1]);
+      target.end = query.lineCharPositions ? {line: Number(m[5]), ch: Number(m[6])} : Number(m[4]);
+    } else {
+      var file = srv.findFile(span.origin);
+      target.start = outputPos(query, file, span.node.start);
+      target.end = outputPos(query, file, span.node.end);
+    }
+  };
+
+  function findDef(srv, query, file) {
+    var expr = findExpr(file, query);
+    var type = findExprType(srv, query, file, expr);
+    if (infer.didGuess()) return {};
+
+    var span = getSpan(type);
+    var result = {url: type.url, doc: type.doc, origin: type.origin};
+
+    if (type.types) for (var i = type.types.length - 1; i >= 0; --i) {
+      var tp = type.types[i];
+      storeTypeDocs(tp, result);
+      if (!span) span = getSpan(tp);
+    }
+
+    if (span && span.node) { // refers to a loaded file
+      var spanFile = span.node.sourceFile || srv.findFile(span.origin);
+      var start = outputPos(query, spanFile, span.node.start), end = outputPos(query, spanFile, span.node.end);
+      result.start = start; result.end = end;
+      result.file = span.origin;
+      var cxStart = Math.max(0, span.node.start - 50);
+      result.contextOffset = span.node.start - cxStart;
+      result.context = spanFile.text.slice(cxStart, cxStart + 50);
+    } else if (span) { // external
+      result.file = span.origin;
+      storeSpan(srv, query, span, result);
+    }
+    return clean(result);
+  }
+
+  function findRefsToVariable(srv, query, file, expr, checkShadowing) {
+    var name = expr.node.name;
+
+    for (var scope = expr.state; scope && !(name in scope.props); scope = scope.prev) {}
+    if (!scope) throw ternError("Could not find a definition for " + name + " " + !!srv.cx.topScope.props.x);
+
+    var type, refs = [];
+    function storeRef(file) {
+      return function(node, scopeHere) {
+        if (checkShadowing) for (var s = scopeHere; s != scope; s = s.prev) {
+          var exists = s.hasProp(checkShadowing);
+          if (exists)
+            throw ternError("Renaming `" + name + "` to `" + checkShadowing + "` would make a variable at line " +
+                            (asLineChar(file, node.start).line + 1) + " point to the definition at line " +
+                            (asLineChar(file, exists.name.start).line + 1));
+        }
+        refs.push({file: file.name,
+                   start: outputPos(query, file, node.start),
+                   end: outputPos(query, file, node.end)});
+      };
+    }
+
+    if (scope.originNode) {
+      type = "local";
+      if (checkShadowing) {
+        for (var prev = scope.prev; prev; prev = prev.prev)
+          if (checkShadowing in prev.props) break;
+        if (prev) infer.findRefs(scope.originNode, scope, checkShadowing, prev, function(node) {
+          throw ternError("Renaming `" + name + "` to `" + checkShadowing + "` would shadow the definition used at line " +
+                          (asLineChar(file, node.start).line + 1));
+        });
+      }
+      infer.findRefs(scope.originNode, scope, name, scope, storeRef(file));
+    } else {
+      type = "global";
+      for (var i = 0; i < srv.files.length; ++i) {
+        var cur = srv.files[i];
+        infer.findRefs(cur.ast, cur.scope, name, scope, storeRef(cur));
+      }
+    }
+
+    return {refs: refs, type: type, name: name};
+  }
+
+  function findRefsToProperty(srv, query, expr, prop) {
+    var objType = infer.expressionType(expr).getObjType();
+    if (!objType) throw ternError("Couldn't determine type of base object.");
+
+    var refs = [];
+    function storeRef(file) {
+      return function(node) {
+        refs.push({file: file.name,
+                   start: outputPos(query, file, node.start),
+                   end: outputPos(query, file, node.end)});
+      };
+    }
+    for (var i = 0; i < srv.files.length; ++i) {
+      var cur = srv.files[i];
+      infer.findPropRefs(cur.ast, cur.scope, objType, prop.name, storeRef(cur));
+    }
+
+    return {refs: refs, name: prop.name};
+  }
+
+  function findRefs(srv, query, file) {
+    var expr = findExprOrThrow(file, query, true);
+    if (expr && expr.node.type == "Identifier") {
+      return findRefsToVariable(srv, query, file, expr);
+    } else if (expr && expr.node.type == "MemberExpression" && !expr.node.computed) {
+      var p = expr.node.property;
+      expr.node = expr.node.object;
+      return findRefsToProperty(srv, query, expr, p);
+    } else if (expr && expr.node.type == "ObjectExpression") {
+      var pos = resolvePos(file, query.end);
+      for (var i = 0; i < expr.node.properties.length; ++i) {
+        var k = expr.node.properties[i].key;
+        if (k.start <= pos && k.end >= pos)
+          return findRefsToProperty(srv, query, expr, k);
+      }
+    }
+    throw ternError("Not at a variable or property name.");
+  }
+
+  function buildRename(srv, query, file) {
+    if (typeof query.newName != "string") throw ternError(".query.newName should be a string");
+    var expr = findExprOrThrow(file, query);
+    if (!expr || expr.node.type != "Identifier") throw ternError("Not at a variable.");
+
+    var data = findRefsToVariable(srv, query, file, expr, query.newName), refs = data.refs;
+    delete data.refs;
+    data.files = srv.files.map(function(f){return f.name;});
+
+    var changes = data.changes = [];
+    for (var i = 0; i < refs.length; ++i) {
+      var use = refs[i];
+      use.text = query.newName;
+      changes.push(use);
+    }
+
+    return data;
+  }
+
+  function listFiles(srv) {
+    return {files: srv.files.map(function(f){return f.name;})};
+  }
+
+  exports.version = "0.11.1";
+});

+ 2 - 0
examples/index.html

@@ -312,6 +312,7 @@
 				"webgl_multiple_canvases_circle",
 				"webgl_multiple_canvases_circle",
 				"webgl_multiple_canvases_complex",
 				"webgl_multiple_canvases_complex",
 				"webgl_multiple_canvases_grid",
 				"webgl_multiple_canvases_grid",
+				"webgl_multiple_elements",
 				"webgl_multiple_views",
 				"webgl_multiple_views",
 				"webgl_nearestneighbour",
 				"webgl_nearestneighbour",
 				"webgl_octree",
 				"webgl_octree",
@@ -359,6 +360,7 @@
 				"webgl_buffergeometry",
 				"webgl_buffergeometry",
 				"webgl_buffergeometry_custom_attributes_particles",
 				"webgl_buffergeometry_custom_attributes_particles",
 				"webgl_buffergeometry_drawcalls",
 				"webgl_buffergeometry_drawcalls",
+				"webgl_buffergeometry_constructed_from_geometry",
 				"webgl_buffergeometry_instancing",
 				"webgl_buffergeometry_instancing",
 				"webgl_buffergeometry_instancing_dynamic",
 				"webgl_buffergeometry_instancing_dynamic",
 				"webgl_buffergeometry_instancing_billboards",
 				"webgl_buffergeometry_instancing_billboards",

+ 2 - 0
examples/js/exporters/OBJExporter.js

@@ -136,7 +136,9 @@ THREE.OBJExporter.prototype = {
 		};
 		};
 
 
 		object.traverse( function ( child ) {
 		object.traverse( function ( child ) {
+
 			if ( child instanceof THREE.Mesh ) parseMesh( child );
 			if ( child instanceof THREE.Mesh ) parseMesh( child );
+
 		} );
 		} );
 
 
 		return output;
 		return output;

+ 4 - 5
examples/js/libs/stats.min.js

@@ -1,6 +1,5 @@
 // stats.js - http://github.com/mrdoob/stats.js
 // stats.js - http://github.com/mrdoob/stats.js
-var Stats=function(){var l=Date.now(),m=l,g=0,n=Infinity,o=0,h=0,p=Infinity,q=0,r=0,s=0,f=document.createElement("div");f.id="stats";f.addEventListener("mousedown",function(b){b.preventDefault();t(++s%2)},!1);f.style.cssText="width:80px;opacity:0.9;cursor:pointer";var a=document.createElement("div");a.id="fps";a.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#002";f.appendChild(a);var i=document.createElement("div");i.id="fpsText";i.style.cssText="color:#0ff;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px";
-i.innerHTML="FPS";a.appendChild(i);var c=document.createElement("div");c.id="fpsGraph";c.style.cssText="position:relative;width:74px;height:30px;background-color:#0ff";for(a.appendChild(c);74>c.children.length;){var j=document.createElement("span");j.style.cssText="width:1px;height:30px;float:left;background-color:#113";c.appendChild(j)}var d=document.createElement("div");d.id="ms";d.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#020;display:none";f.appendChild(d);var k=document.createElement("div");
-k.id="msText";k.style.cssText="color:#0f0;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px";k.innerHTML="MS";d.appendChild(k);var e=document.createElement("div");e.id="msGraph";e.style.cssText="position:relative;width:74px;height:30px;background-color:#0f0";for(d.appendChild(e);74>e.children.length;)j=document.createElement("span"),j.style.cssText="width:1px;height:30px;float:left;background-color:#131",e.appendChild(j);var t=function(b){s=b;switch(s){case 0:a.style.display=
-"block";d.style.display="none";break;case 1:a.style.display="none",d.style.display="block"}};return{REVISION:11,domElement:f,setMode:t,begin:function(){l=Date.now()},end:function(){var b=Date.now();g=b-l;n=Math.min(n,g);o=Math.max(o,g);k.textContent=g+" MS ("+n+"-"+o+")";var a=Math.min(30,30-30*(g/200));e.appendChild(e.firstChild).style.height=a+"px";r++;b>m+1E3&&(h=Math.round(1E3*r/(b-m)),p=Math.min(p,h),q=Math.max(q,h),i.textContent=h+" FPS ("+p+"-"+q+")",a=Math.min(30,30-30*(h/100)),c.appendChild(c.firstChild).style.height=
-a+"px",m=b,r=0);return b},update:function(){l=this.end()}}};
+var Stats=function(){function f(a,e,b){a=document.createElement(a);a.id=e;a.style.cssText=b;return a}function l(a,e,b){var c=f("div",a,"padding:0 0 3px 3px;text-align:left;background:"+b),d=f("div",a+"Text","font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px;color:"+e);d.innerHTML=a.toUpperCase();c.appendChild(d);a=f("div",a+"Graph","width:74px;height:30px;background:"+e);c.appendChild(a);for(e=0;74>e;e++)a.appendChild(f("span","","width:1px;height:30px;float:left;opacity:0.9;background:"+
+b));return c}function m(a){for(var b=c.children,d=0;d<b.length;d++)b[d].style.display=d===a?"block":"none";n=a}function p(a,b){a.appendChild(a.firstChild).style.height=Math.min(30,30-30*b)+"px"}var q=performance&&performance.now?performance.now.bind(performance):Date.now,k=q(),r=k,t=0,n=0,c=f("div","stats","width:80px;opacity:0.9;cursor:pointer");c.addEventListener("mousedown",function(a){a.preventDefault();m(++n%c.children.length)},!1);var d=0,u=Infinity,v=0,b=l("fps","#0ff","#002"),A=b.children[0],
+B=b.children[1];c.appendChild(b);var g=0,w=Infinity,x=0,b=l("ms","#0f0","#020"),C=b.children[0],D=b.children[1];c.appendChild(b);if(performance&&performance.memory){var h=0,y=Infinity,z=0,b=l("mb","#f08","#201"),E=b.children[0],F=b.children[1];c.appendChild(b)}m(n);return{REVISION:14,domElement:c,setMode:m,begin:function(){k=q()},end:function(){var a=q();g=a-k;w=Math.min(w,g);x=Math.max(x,g);C.textContent=(g|0)+" MS ("+(w|0)+"-"+(x|0)+")";p(D,g/200);t++;if(a>r+1E3&&(d=Math.round(1E3*t/(a-r)),u=Math.min(u,
+d),v=Math.max(v,d),A.textContent=d+" FPS ("+u+"-"+v+")",p(B,d/100),r=a,t=0,void 0!==h)){var b=performance.memory.usedJSHeapSize,c=performance.memory.jsHeapSizeLimit;h=Math.round(9.54E-7*b);y=Math.min(y,h);z=Math.max(z,h);E.textContent=h+" MB ("+y+"-"+z+")";p(F,b/c)}return a},update:function(){k=this.end()}}};"object"===typeof module&&(module.exports=Stats);

+ 2 - 1
examples/js/loaders/STLLoader.js

@@ -44,12 +44,13 @@ THREE.STLLoader.prototype = {
 		var loader = new THREE.XHRLoader( scope.manager );
 		var loader = new THREE.XHRLoader( scope.manager );
 		loader.setCrossOrigin( this.crossOrigin );
 		loader.setCrossOrigin( this.crossOrigin );
 		loader.setResponseType('arraybuffer');
 		loader.setResponseType('arraybuffer');
-		loader.load( url, function ( text ) {
+		var request = loader.load( url, function ( text ) {
 
 
 			onLoad( scope.parse( text ) );
 			onLoad( scope.parse( text ) );
 
 
 		}, onProgress, onError );
 		}, onProgress, onError );
 
 
+		return request;
 	},
 	},
 
 
 	parse: function ( data ) {
 	parse: function ( data ) {

+ 7 - 6
examples/js/renderers/Projector.js

@@ -274,18 +274,19 @@ THREE.Projector = function () {
 				_face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3;
 				_face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3;
 				_face.renderOrder = object.renderOrder;
 				_face.renderOrder = object.renderOrder;
 
 
+				// use first vertex normal as face normal
+
+				_face.normalModel.fromArray( normals, a * 3 );
+				_face.normalModel.applyMatrix3( normalMatrix ).normalize();
+
 				for ( var i = 0; i < 3; i ++ ) {
 				for ( var i = 0; i < 3; i ++ ) {
 
 
-					var offset = arguments[ i ] * 3;
 					var normal = _face.vertexNormalsModel[ i ];
 					var normal = _face.vertexNormalsModel[ i ];
-
-					normal.set( normals[ offset ], normals[ offset + 1 ], normals[ offset + 2 ] );
+					normal.fromArray( normals, arguments[ i ] * 3 );
 					normal.applyMatrix3( normalMatrix ).normalize();
 					normal.applyMatrix3( normalMatrix ).normalize();
 
 
-					var offset2 = arguments[ i ] * 2;
-
 					var uv = _face.uvs[ i ];
 					var uv = _face.uvs[ i ];
-					uv.set( uvs[ offset2 ], uvs[ offset2 + 1 ] );
+					uv.fromArray( uvs, arguments[ i ] * 2 );
 
 
 				}
 				}
 
 

+ 251 - 0
examples/webgl_buffergeometry_constructed_from_geometry.html

@@ -0,0 +1,251 @@
+<!DOCTYPE html>
+<html>
+	<head>
+	<title>three.js - BufferGeometry constructed from Geometry Example</title>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+	<meta content="initial-scale=1.0, maximum-scale=1.0" name="viewport">
+	<meta name="Generator" content="https://callum.com">
+	<style>
+		body {
+			background-color: #000;
+			font-family: Monospace;
+			margin: 0;
+			color: #000;
+			overflow: hidden;
+		}
+		#title {
+			position: absolute;
+			width: 100%;
+			top: 0;
+			padding: 0;
+			text-align: center;
+			font-size: 1.1em;
+			background-color: rgba(64,96,64,0.7);
+			color: #fff;
+		}
+		#title a {color:#ff0;}
+	</style>
+	<script type="text/javascript" src="../build/three.min.js"></script>
+	<script type="text/javascript" src="js/Detector.js"></script>
+	<script type="text/javascript" src="js/libs/stats.min.js"></script>
+	<script type="text/javascript" src="js/controls/TrackballControls.js"></script>
+	</head>
+	<body onload="app()">
+		<div id="title"></div>
+		<script>
+		var camera, scene, renderer, controls, stats;
+
+		function app() {
+
+			if ( ! Detector.webgl ) {
+
+				Detector.addGetWebGLMessage();
+
+			}
+
+			init();
+			animate();
+
+		}
+
+		function init() {
+
+			renderer = new THREE.WebGLRenderer( {
+				antialias: true
+			} );
+			renderer.setClearColor( 0x000000, 0.0 );
+			renderer.setPixelRatio( window.devicePixelRatio );
+			renderer.setSize( window.innerWidth, window.innerHeight );
+
+			document.body.appendChild( renderer.domElement );
+
+			scene = new THREE.Scene();
+
+			camera = new THREE.PerspectiveCamera( 45.0, window.innerWidth / window.innerHeight, 100, 1500.0 );
+			camera.position.z = 480.0;
+
+			scene.add( new THREE.AmbientLight( 0x444444 ) );
+
+			var light1 = new THREE.DirectionalLight( 0x999999, 0.1 );
+			light1.position.set( 1, 1, 1 );
+			scene.add( light1 );
+
+			var light2 = new THREE.DirectionalLight( 0x999999, 1.5 );
+			light2.position.set( 0, -1, 0 );
+			scene.add( light2 );
+
+			controls = new THREE.TrackballControls( camera, renderer.domElement );
+			controls.minDistance = 100.0;
+			controls.maxDistance = 800.0;
+			controls.dynamicDampingFactor = 0.1;
+
+			stats = new Stats();
+			stats.domElement.style.position = 'absolute';
+			stats.domElement.style.top = '24px';
+			document.body.appendChild( stats.domElement );
+
+			window.addEventListener( 'resize', onWindowResize, false );
+
+			createScene();
+
+		}
+
+		function createGeometry() {
+
+			var heart_shape = new THREE.Shape(); // From http://blog.burlock.org/html5/130-paths
+			var x = 0,
+				y = 0;
+			heart_shape.moveTo( x + 25, y + 25 );
+			heart_shape.bezierCurveTo( x + 25, y + 25, x + 20, y, x, y );
+			heart_shape.bezierCurveTo( x - 30, y, x - 30, y + 35, x - 30, y + 35 );
+			heart_shape.bezierCurveTo( x - 30, y + 55, x - 10, y + 77, x + 25, y + 95 );
+			heart_shape.bezierCurveTo( x + 60, y + 77, x + 80, y + 55, x + 80, y + 35 );
+			heart_shape.bezierCurveTo( x + 80, y + 35, x + 80, y, x + 50, y );
+			heart_shape.bezierCurveTo( x + 35, y, x + 25, y + 25, x + 25, y + 25 );
+			var extrudeSettings = {
+				amount: 16,
+				bevelEnabled: true,
+				bevelSegments: 1,
+				steps: 2,
+				bevelSize: 1,
+				bevelThickness: 1
+			};
+			var geom = new THREE.ExtrudeGeometry( heart_shape, extrudeSettings );
+			geom.applyMatrix( new THREE.Matrix4().makeRotationX( -THREE.Math.degToRad( 90 ) ) );
+			geom.applyMatrix( new THREE.Matrix4().makeScale( 0.1, 0.1, 0.1 ) );
+			geom.applyMatrix( new THREE.Matrix4().makeScale( 4, 4, 4 ) );
+			return geom;
+
+		}
+
+		function createScene() {
+
+			var buffer_geometry = new THREE.BufferGeometry();
+			var radius = 100.0;
+			var positions = 0;
+			var normals = 0;
+			var colors = 0;
+			var shape_density = 14;
+
+			for ( var num_lat = 0; num_lat < shape_density / 2; ++ num_lat ) {
+
+				var lat_lhs = ( num_lat + 0 ) * 180 / ( shape_density / 2 );
+				var lat_rhs = ( num_lat + 1 ) * 180 / ( shape_density / 2 );
+				var lat = ( lat_lhs + lat_rhs ) / 2.0;
+
+				for ( var num_lng = 0; num_lng < shape_density; ++ num_lng ) {
+
+					var lng_lhs = ( num_lng + 0 ) * 360 / shape_density;
+					var lng_rhs = ( num_lng + 1 ) * 360 / shape_density;
+					var lng = ( lng_lhs + lng_rhs ) / 2.0;
+
+					var height = 30.0;
+
+					var phi = lat * Math.PI / 180.0;
+					var theta = lng * Math.PI / 180.0;
+					var x = radius * Math.sin( phi ) * Math.cos( theta );
+					var y = radius * Math.cos( phi );
+					var z = radius * Math.sin( phi ) * Math.sin( theta );
+
+					var geometry = createGeometry();
+
+					geometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, height / 2, 0 ) );
+					geometry.applyMatrix( new THREE.Matrix4().makeRotationX( -THREE.Math.degToRad( 90 ) ) );
+					geometry.applyMatrix( new THREE.Matrix4().lookAt( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( x, y, z ), new THREE.Vector3( 0, 1, 0 ) ) );
+					geometry.applyMatrix( new THREE.Matrix4().makeTranslation( x, y, z ) );
+
+					var color = new THREE.Color( 0xffffff );
+					color.setHSL( lat / 180.0, 1.0, 0.7 );
+
+					if ( positions === 0 ) {
+
+						var num_stacks = shape_density * shape_density / 2;
+
+						var str = 'BufferGeometry constructed from Geometry Example - ' + parseInt( num_stacks * geometry.faces.length, 10 ) + ' triangles (<a target="_blank" href="http://callum.com">author</a>)';
+						document.getElementById( 'title' ).innerHTML = str.replace( /\B(?=(\d{3})+(?!\d))/g, "," );
+
+						positions = new Float32Array( num_stacks * geometry.faces.length * 3 * 3 );
+						normals = new Float32Array( num_stacks * geometry.faces.length * 3 * 3 );
+						colors = new Float32Array( num_stacks * geometry.faces.length * 3 * 3 );
+
+					}
+
+					geometry.faces.forEach( function ( face, index ) {
+
+						var cur_element = ( ( num_lng + num_lat * shape_density ) * geometry.faces.length + index );
+
+						positions[ cur_element * 9 + 0 ] = geometry.vertices[ face.a ].x;
+						positions[ cur_element * 9 + 1 ] = geometry.vertices[ face.a ].y;
+						positions[ cur_element * 9 + 2 ] = geometry.vertices[ face.a ].z;
+						positions[ cur_element * 9 + 3 ] = geometry.vertices[ face.b ].x;
+						positions[ cur_element * 9 + 4 ] = geometry.vertices[ face.b ].y;
+						positions[ cur_element * 9 + 5 ] = geometry.vertices[ face.b ].z;
+						positions[ cur_element * 9 + 6 ] = geometry.vertices[ face.c ].x;
+						positions[ cur_element * 9 + 7 ] = geometry.vertices[ face.c ].y;
+						positions[ cur_element * 9 + 8 ] = geometry.vertices[ face.c ].z;
+
+						normals[ cur_element * 9 + 0 ] = face.normal.x;
+						normals[ cur_element * 9 + 1 ] = face.normal.y;
+						normals[ cur_element * 9 + 2 ] = face.normal.z;
+						normals[ cur_element * 9 + 3 ] = face.normal.x;
+						normals[ cur_element * 9 + 4 ] = face.normal.y;
+						normals[ cur_element * 9 + 5 ] = face.normal.z;
+						normals[ cur_element * 9 + 6 ] = face.normal.x;
+						normals[ cur_element * 9 + 7 ] = face.normal.y;
+						normals[ cur_element * 9 + 8 ] = face.normal.z;
+
+						colors[ cur_element * 9 + 0 ] = color.r;
+						colors[ cur_element * 9 + 1 ] = color.g;
+						colors[ cur_element * 9 + 2 ] = color.b;
+						colors[ cur_element * 9 + 3 ] = color.r;
+						colors[ cur_element * 9 + 4 ] = color.g;
+						colors[ cur_element * 9 + 5 ] = color.b;
+						colors[ cur_element * 9 + 6 ] = color.r;
+						colors[ cur_element * 9 + 7 ] = color.g;
+						colors[ cur_element * 9 + 8 ] = color.b;
+
+					} );
+
+				}
+
+			}
+
+			buffer_geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
+			buffer_geometry.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );
+			buffer_geometry.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) );
+
+			buffer_geometry.computeBoundingSphere();
+
+			var buffer_material = new THREE.MeshPhongMaterial( {
+				color: 0x999999,
+				specular: 0x333333,
+				shininess: 50,
+				side: THREE.DoubleSide,
+				vertexColors: THREE.VertexColors,
+				shading: THREE.SmoothShading
+			} );
+
+			var buffer_mesh = new THREE.Mesh( buffer_geometry, buffer_material );
+			scene.add( buffer_mesh );
+
+		}
+
+		function onWindowResize() {
+
+			camera.aspect = window.innerWidth / window.innerHeight;
+			camera.updateProjectionMatrix();
+			renderer.setSize( window.innerWidth, window.innerHeight );
+
+		}
+
+		function animate( time ) {
+
+			requestAnimationFrame( animate );
+			controls.update();
+			stats.update();
+			renderer.render( scene, camera );
+
+		}
+		</script>
+	</body>
+</html>

+ 1 - 7
examples/webgl_morphtargets_horse.html

@@ -62,13 +62,7 @@
 				var loader = new THREE.JSONLoader( true );
 				var loader = new THREE.JSONLoader( true );
 				loader.load( "models/animated/horse.js", function( geometry ) {
 				loader.load( "models/animated/horse.js", function( geometry ) {
 
 
-					var material = new THREE.MeshPhongMaterial( {
-						color: 0x606060,
-						shading: THREE.FlatShading,
-						morphTargets: true
-					} );
-
-					mesh = new THREE.Mesh( geometry, material );
+					mesh = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial( { color: 0x606060, morphTargets: true } ) );
 					mesh.scale.set( 1.5, 1.5, 1.5 );
 					mesh.scale.set( 1.5, 1.5, 1.5 );
 					scene.add( mesh );
 					scene.add( mesh );
 
 

+ 20 - 60
examples/webgl_multiple_elements.html

@@ -30,11 +30,10 @@
 				position: absolute;
 				position: absolute;
 				top: 0px; width: 100%;
 				top: 0px; width: 100%;
 				z-index: 1;
 				z-index: 1;
-				padding: 2em;
+				padding: 3em 0 0 0;
 			}
 			}
 
 
 			a {
 			a {
-
 				color: #0080ff;
 				color: #0080ff;
 			}
 			}
 
 
@@ -46,47 +45,30 @@
 			}
 			}
 
 
 			.list-item {
 			.list-item {
+				display: inline-block;
 				margin: 1em;
 				margin: 1em;
-				padding: 2em;
-				display: -webkit-flex;
-				display: flex;
-				flex-direction: row;
-				-webkit-flex-direction: row;
+				padding: 1em;
+				box-shadow: 1px 2px 4px 0px rgba(0,0,0,0.25);
 			}
 			}
 
 
 			.list-item .scene {
 			.list-item .scene {
 				width: 200px;
 				width: 200px;
 				height: 200px;
 				height: 200px;
-				flex: 0 0 auto;
-				-webkit-flex: 0 0 auto;
 			}
 			}
+
 			.list-item .description {
 			.list-item .description {
+				color: #888;
 				font-family: sans-serif;
 				font-family: sans-serif;
 				font-size: large;
 				font-size: large;
-				padding-left: 2em;
-				flex: 1 1 auto;
-				-webkit-flex: 1 1 auto;
-			}
-
-			@media only screen and (max-width : 600px) {
-				#content {
-					width: 100%;
-				}
-				.list-item {
-					margin: 0.5em;
-					padding: 0.5em;
-					flex-direction: column;
-					-webkit-flex-direction: column;
-				}
-				.list-item .description {
-					padding-left: 0em;
-				}
+				width: 200px;
+				margin-top: 0.5em;
 			}
 			}
 		</style>
 		</style>
 	</head>
 	</head>
 	<body>
 	<body>
 
 
 		<canvas id="c"></canvas>
 		<canvas id="c"></canvas>
+
 		<div id="content">
 		<div id="content">
 			<div id="info"><a href="http://threejs.org" target="_blank">three.js</a> - multiple elements - webgl</div>
 			<div id="info"><a href="http://threejs.org" target="_blank">three.js</a> - multiple elements - webgl</div>
 		</div>
 		</div>
@@ -97,7 +79,7 @@
 
 
 		<script id="template" type="notjs">
 		<script id="template" type="notjs">
 			<div class="scene"></div>
 			<div class="scene"></div>
-			<div class="description">some random text about this object, scene, whatever</div>
+			<div class="description">Scene $</div>
 		</script>
 		</script>
 		<script>
 		<script>
 
 
@@ -114,8 +96,8 @@
 
 
 				canvas = document.getElementById( "c" );
 				canvas = document.getElementById( "c" );
 
 
-				camera = new THREE.PerspectiveCamera( 75, 1, 0.1, 100 );
-				camera.position.z = 1.5;
+				camera = new THREE.PerspectiveCamera( 50, 1, 0.1, 100 );
+				camera.position.z = 2;
 
 
 				var geometries = [
 				var geometries = [
 					new THREE.BoxGeometry( 1, 1, 1 ),
 					new THREE.BoxGeometry( 1, 1, 1 ),
@@ -129,37 +111,32 @@
 
 
 				var emptyScene = new THREE.Scene();
 				var emptyScene = new THREE.Scene();
 
 
-				var numScenes = 100;
-
-				for ( var ii =  0; ii < numScenes; ++ii ) {
+				for ( var i =  0; i < 100; i ++ ) {
 
 
 					var scene = new THREE.Scene();
 					var scene = new THREE.Scene();
 
 
-					// make a list item.
+					// make a list item
 					var element = document.createElement( "div" );
 					var element = document.createElement( "div" );
-					element.innerHTML = template;
 					element.className = "list-item";
 					element.className = "list-item";
+					element.innerHTML = template.replace('$', i + 1 );
 
 
 					// Look up the element that represents the area
 					// Look up the element that represents the area
 					// we want to render the scene
 					// we want to render the scene
 					scene.element = element.querySelector(".scene");
 					scene.element = element.querySelector(".scene");
-					content.appendChild(element);
+					content.appendChild( element );
 
 
 					// add one random mesh to each scene
 					// add one random mesh to each scene
 					var geometry = geometries[ geometries.length * Math.random() | 0 ];
 					var geometry = geometries[ geometries.length * Math.random() | 0 ];
-					var material = new THREE.MeshLambertMaterial( { color: randColor() } );
+					var material = new THREE.MeshLambertMaterial( { color: 0xffffff * Math.random() } );
 
 
 					scene.add( new THREE.Mesh( geometry, material ) );
 					scene.add( new THREE.Mesh( geometry, material ) );
 
 
-					light = new THREE.DirectionalLight( 0xffffff );
-					light.position.set( 0.5, 0.8, 1 );
-					scene.add( light );
-
-					light = new THREE.DirectionalLight( 0xffffff );
-					light.position.set( -0.5, -0.8, -1 );
+					light = new THREE.HemisphereLight( 0xffbbbb, 0x444488 );
+					light.position.set( - 0.5, 0.8, 1 );
 					scene.add( light );
 					scene.add( light );
 
 
 					scenes.push( scene );
 					scenes.push( scene );
+
 				}
 				}
 
 
 
 
@@ -232,23 +209,6 @@
 
 
 			}
 			}
 
 
-			function rand( min, max ) {
-				if ( max == undefined ) {
-					max = min;
-					min = 0;
-				}
-
-				return Math.random() * ( max - min ) + min;
-			}
-
-			function randColor() {
-				var colors = [ rand( 256 ), rand ( 256 ), rand( 256 ) ];
-				colors[ Math.random() * 3 | 0 ] = 255;
-				return ( colors[0] << 16 ) |
-					   ( colors[1] <<  8 ) |
-					   ( colors[2] <<  0 ) ;
-			}
-
 		</script>
 		</script>
 
 
 	</body>
 	</body>

+ 7 - 6
examples/webgl_particles_sprites.html

@@ -86,12 +86,13 @@
 
 
 				}
 				}
 
 
-				parameters = [ [ [1.0, 0.2, 0.5], sprite2, 20 ],
-							   [ [0.95, 0.1, 0.5], sprite3, 15 ],
-							   [ [0.90, 0.05, 0.5], sprite1, 10 ],
-							   [ [0.85, 0, 0.5], sprite5, 8 ],
-							   [ [0.80, 0, 0.5], sprite4, 5 ],
-							   ];
+				parameters = [
+					[ [1.0, 0.2, 0.5], sprite2, 20 ],
+					[ [0.95, 0.1, 0.5], sprite3, 15 ],
+					[ [0.90, 0.05, 0.5], sprite1, 10 ],
+					[ [0.85, 0, 0.5], sprite5, 8 ],
+					[ [0.80, 0, 0.5], sprite4, 5 ]
+				];
 
 
 				for ( i = 0; i < parameters.length; i ++ ) {
 				for ( i = 0; i < parameters.length; i ++ ) {
 
 

+ 2 - 2
src/core/BufferGeometry.js

@@ -253,9 +253,9 @@ THREE.BufferGeometry.prototype = {
 
 
 	},
 	},
 
 
-	fromGeometry: function ( geometry, material ) {
+	fromGeometry: function ( geometry ) {
 
 
-		geometry.__directGeometry = new THREE.DirectGeometry().fromGeometry( geometry, material );
+		geometry.__directGeometry = new THREE.DirectGeometry().fromGeometry( geometry );
 
 
 		return this.fromDirectGeometry( geometry.__directGeometry );
 		return this.fromDirectGeometry( geometry.__directGeometry );
 
 

+ 3 - 6
src/core/DirectGeometry.js

@@ -61,14 +61,11 @@ THREE.DirectGeometry.prototype = {
 
 
 	},
 	},
 
 
-	fromGeometry: function ( geometry, material ) {
-
-		material = material || { 'vertexColors': THREE.NoColors };
+	fromGeometry: function ( geometry ) {
 
 
 		var faces = geometry.faces;
 		var faces = geometry.faces;
 		var vertices = geometry.vertices;
 		var vertices = geometry.vertices;
 		var faceVertexUvs = geometry.faceVertexUvs;
 		var faceVertexUvs = geometry.faceVertexUvs;
-		var materialVertexColors = material.vertexColors;
 
 
 		var hasFaceVertexUv = faceVertexUvs[ 0 ] && faceVertexUvs[ 0 ].length > 0;
 		var hasFaceVertexUv = faceVertexUvs[ 0 ] && faceVertexUvs[ 0 ].length > 0;
 		var hasFaceVertexUv2 = faceVertexUvs[ 1 ] && faceVertexUvs[ 1 ].length > 0;
 		var hasFaceVertexUv2 = faceVertexUvs[ 1 ] && faceVertexUvs[ 1 ].length > 0;
@@ -134,11 +131,11 @@ THREE.DirectGeometry.prototype = {
 
 
 			var vertexColors = face.vertexColors;
 			var vertexColors = face.vertexColors;
 
 
-			if ( materialVertexColors === THREE.VertexColors ) {
+			if ( vertexColors.length === 3 ) {
 
 
 				this.colors.push( vertexColors[ 0 ], vertexColors[ 1 ], vertexColors[ 2 ] );
 				this.colors.push( vertexColors[ 0 ], vertexColors[ 1 ], vertexColors[ 2 ] );
 
 
-			} else if ( materialVertexColors === THREE.FaceColors ) {
+			} else {
 
 
 				var color = face.color;
 				var color = face.color;
 
 

+ 0 - 2
src/extras/geometries/PlaneGeometry.js

@@ -5,8 +5,6 @@
 
 
 THREE.PlaneGeometry = function ( width, height, widthSegments, heightSegments ) {
 THREE.PlaneGeometry = function ( width, height, widthSegments, heightSegments ) {
 
 
-	console.log( 'THREE.PlaneGeometry: Consider using THREE.PlaneBufferGeometry for lower memory footprint.' );
-
 	THREE.Geometry.call( this );
 	THREE.Geometry.call( this );
 
 
 	this.type = 'PlaneGeometry';
 	this.type = 'PlaneGeometry';

+ 2 - 0
src/loaders/XHRLoader.js

@@ -65,6 +65,8 @@ THREE.XHRLoader.prototype = {
 
 
 		scope.manager.itemStart( url );
 		scope.manager.itemStart( url );
 
 
+		return request;
+
 	},
 	},
 
 
 	setResponseType: function ( value ) {
 	setResponseType: function ( value ) {

+ 34 - 19
src/renderers/WebGLRenderer.js

@@ -779,14 +779,15 @@ THREE.WebGLRenderer = function ( parameters ) {
 		if ( object.hasUvs && ! object.__webglUvBuffer ) object.__webglUvBuffer = _gl.createBuffer();
 		if ( object.hasUvs && ! object.__webglUvBuffer ) object.__webglUvBuffer = _gl.createBuffer();
 		if ( object.hasColors && ! object.__webglColorBuffer ) object.__webglColorBuffer = _gl.createBuffer();
 		if ( object.hasColors && ! object.__webglColorBuffer ) object.__webglColorBuffer = _gl.createBuffer();
 
 
+		var attributes = program.getAttributes();
+
 		if ( object.hasPositions ) {
 		if ( object.hasPositions ) {
 
 
 			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglVertexBuffer );
 			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglVertexBuffer );
 			_gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW );
 			_gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW );
 
 
-			state.enableAttribute( program.attributes.position );
-
-			_gl.vertexAttribPointer( program.attributes.position, 3, _gl.FLOAT, false, 0, 0 );
+			state.enableAttribute( attributes.position );
+			_gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 );
 
 
 		}
 		}
 
 
@@ -839,9 +840,9 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 			_gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW );
 			_gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW );
 
 
-			state.enableAttribute( program.attributes.normal );
+			state.enableAttribute( attributes.normal );
 
 
-			_gl.vertexAttribPointer( program.attributes.normal, 3, _gl.FLOAT, false, 0, 0 );
+			_gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 );
 
 
 		}
 		}
 
 
@@ -850,9 +851,9 @@ THREE.WebGLRenderer = function ( parameters ) {
 			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglUvBuffer );
 			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglUvBuffer );
 			_gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW );
 			_gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW );
 
 
-			state.enableAttribute( program.attributes.uv );
+			state.enableAttribute( attributes.uv );
 
 
-			_gl.vertexAttribPointer( program.attributes.uv, 2, _gl.FLOAT, false, 0, 0 );
+			_gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 );
 
 
 		}
 		}
 
 
@@ -861,9 +862,9 @@ THREE.WebGLRenderer = function ( parameters ) {
 			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglColorBuffer );
 			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglColorBuffer );
 			_gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW );
 			_gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW );
 
 
-			state.enableAttribute( program.attributes.color );
+			state.enableAttribute( attributes.color );
 
 
-			_gl.vertexAttribPointer( program.attributes.color, 3, _gl.FLOAT, false, 0, 0 );
+			_gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 );
 
 
 		}
 		}
 
 
@@ -893,7 +894,10 @@ THREE.WebGLRenderer = function ( parameters ) {
 		}
 		}
 
 
 		var geometryAttributes = geometry.attributes;
 		var geometryAttributes = geometry.attributes;
-		var programAttributes = program.attributes;
+
+		var programAttributes = program.getAttributes();
+
+		var materialDefaultAttributeValues = material.defaultAttributeValues;
 
 
 		for ( var name in programAttributes ) {
 		for ( var name in programAttributes ) {
 
 
@@ -962,17 +966,27 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 					}
 					}
 
 
-				} else if ( material.defaultAttributeValues !== undefined ) {
+				} else if ( materialDefaultAttributeValues !== undefined ) {
+
+					var value = materialDefaultAttributeValues[ name ];
+					if ( value !== undefined ) {
 
 
-					if ( material.defaultAttributeValues[ name ] !== undefined ) {
+						switch ( value.length ) {
 
 
-						if ( material.defaultAttributeValues[ name ].length === 2 ) {
+							case 2:
+								_gl.vertexAttrib2fv( programAttribute, value );
+								break;
 
 
-							_gl.vertexAttrib2fv( programAttribute, material.defaultAttributeValues[ name ] );
+							case 3:
+								_gl.vertexAttrib3fv( programAttribute, value );
+								break;
 
 
-						} else if ( material.defaultAttributeValues[ name ].length === 3 ) {
+							case 4:
+								_gl.vertexAttrib4fv( programAttribute, value );
+								break;
 
 
-							_gl.vertexAttrib3fv( programAttribute, material.defaultAttributeValues[ name ] );
+							default:
+								_gl.vertexAttrib1fv( programAttribute, value );
 
 
 						}
 						}
 
 
@@ -1983,7 +1997,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 		material.program = program;
 		material.program = program;
 
 
-		var attributes = program.attributes;
+		var attributes = program.getAttributes();
 
 
 		if ( material.morphTargets ) {
 		if ( material.morphTargets ) {
 
 
@@ -2019,9 +2033,10 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 
 		material.uniformsList = [];
 		material.uniformsList = [];
 
 
+		var uniformLocations = material.program.getUniforms();
 		for ( var u in material.__webglShader.uniforms ) {
 		for ( var u in material.__webglShader.uniforms ) {
 
 
-			var location = material.program.uniforms[ u ];
+			var location = uniformLocations[ u ];
 
 
 			if ( location ) {
 			if ( location ) {
 				material.uniformsList.push( [ material.__webglShader.uniforms[ u ], location ] );
 				material.uniformsList.push( [ material.__webglShader.uniforms[ u ], location ] );
@@ -2067,7 +2082,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 		var refreshLights = false;
 		var refreshLights = false;
 
 
 		var program = material.program,
 		var program = material.program,
-			p_uniforms = program.uniforms,
+			p_uniforms = program.getUniforms(),
 			m_uniforms = material.__webglShader.uniforms;
 			m_uniforms = material.__webglShader.uniforms;
 
 
 		if ( program.id !== _currentProgram ) {
 		if ( program.id !== _currentProgram ) {

+ 4 - 2
src/renderers/webgl/WebGLObjects.js

@@ -160,9 +160,11 @@ THREE.WebGLObjects = function ( gl, info ) {
 
 
 			if ( material.program !== undefined ) {
 			if ( material.program !== undefined ) {
 
 
-				if ( material.program.uniforms.morphTargetInfluences !== null ) {
+				var uniforms = material.program.getUniforms();
 
 
-					gl.uniform1fv( material.program.uniforms.morphTargetInfluences, morphInfluences );
+				if ( uniforms.morphTargetInfluences !== null ) {
+
+					gl.uniform1fv( uniforms.morphTargetInfluences, morphInfluences );
 
 
 				}
 				}
 
 

+ 70 - 80
src/renderers/webgl/WebGLProgram.js

@@ -20,14 +20,29 @@ THREE.WebGLProgram = ( function () {
 
 
 	}
 	}
 
 
-	function cacheUniformLocations( gl, program, identifiers ) {
+	function fetchUniformLocations( gl, program, identifiers ) {
+
 
 
 		var uniforms = {};
 		var uniforms = {};
 
 
-		for ( var i = 0, l = identifiers.length; i < l; i ++ ) {
+		var n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS );
+
+		for ( var i = 0; i < n; i ++ ) {
+
+			var info = gl.getActiveUniform( program , i );
+			var name = info.name;
+			var location = gl.getUniformLocation( program, name );
+
+			//console.log("THREE.WebGLProgram: ACTIVE UNIFORM:", name);
+
+			var suffixPos = name.lastIndexOf( '[0]' );
+			if ( suffixPos !== -1 && suffixPos === name.length - 3 ) {
 
 
-			var id = identifiers[ i ];
-			uniforms[ id ] = gl.getUniformLocation( program, id );
+				uniforms[ name.substr( 0, suffixPos ) ] = location;
+
+			}
+
+			uniforms[ name ] = location;
 
 
 		}
 		}
 
 
@@ -35,14 +50,20 @@ THREE.WebGLProgram = ( function () {
 
 
 	}
 	}
 
 
-	function cacheAttributeLocations( gl, program, identifiers ) {
+	function fetchAttributeLocations( gl, program, identifiers ) {
 
 
 		var attributes = {};
 		var attributes = {};
 
 
-		for ( var i = 0, l = identifiers.length; i < l; i ++ ) {
+		var n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES );
+
+		for ( var i = 0; i < n; i ++ ) {
 
 
-			var id = identifiers[ i ];
-			attributes[ id ] = gl.getAttribLocation( program, id );
+			var info = gl.getActiveAttrib( program , i );
+			var name = info.name;
+
+			//console.log("THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:", name);
+
+			attributes[ name ] = gl.getAttribLocation( program, name );
 
 
 		}
 		}
 
 
@@ -154,16 +175,16 @@ THREE.WebGLProgram = ( function () {
 
 
 		var program = gl.createProgram();
 		var program = gl.createProgram();
 
 
-		var prefix_vertex, prefix_fragment;
+		var prefixVertex, prefixFragment;
 
 
 		if ( material instanceof THREE.RawShaderMaterial ) {
 		if ( material instanceof THREE.RawShaderMaterial ) {
 
 
-			prefix_vertex = '';
-			prefix_fragment = '';
+			prefixVertex = '';
+			prefixFragment = '';
 
 
 		} else {
 		} else {
 
 
-			prefix_vertex = [
+			prefixVertex = [
 
 
 				'precision ' + parameters.precision + ' float;',
 				'precision ' + parameters.precision + ' float;',
 				'precision ' + parameters.precision + ' int;',
 				'precision ' + parameters.precision + ' int;',
@@ -270,7 +291,7 @@ THREE.WebGLProgram = ( function () {
 
 
 			].filter( filterEmptyLine ).join( '\n' );
 			].filter( filterEmptyLine ).join( '\n' );
 
 
-			prefix_fragment = [
+			prefixFragment = [
 
 
 				( parameters.bumpMap || parameters.normalMap || parameters.flatShading || material.derivatives ) ? '#extension GL_OES_standard_derivatives : enable' : '',
 				( parameters.bumpMap || parameters.normalMap || parameters.flatShading || material.derivatives ) ? '#extension GL_OES_standard_derivatives : enable' : '',
 
 
@@ -331,8 +352,11 @@ THREE.WebGLProgram = ( function () {
 
 
 		}
 		}
 
 
-		var glVertexShader = new THREE.WebGLShader( gl, gl.VERTEX_SHADER, prefix_vertex + vertexShader );
-		var glFragmentShader = new THREE.WebGLShader( gl, gl.FRAGMENT_SHADER, prefix_fragment + fragmentShader );
+		var vertexGlsl = prefixVertex + vertexShader;
+		var fragmentGlsl = prefixFragment + fragmentShader;
+
+		var glVertexShader = new THREE.WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl );
+		var glFragmentShader = new THREE.WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl );
 
 
 		gl.attachShader( program, glVertexShader );
 		gl.attachShader( program, glVertexShader );
 		gl.attachShader( program, glFragmentShader );
 		gl.attachShader( program, glFragmentShader );
@@ -370,91 +394,57 @@ THREE.WebGLProgram = ( function () {
 		gl.deleteShader( glVertexShader );
 		gl.deleteShader( glVertexShader );
 		gl.deleteShader( glFragmentShader );
 		gl.deleteShader( glFragmentShader );
 
 
-		// cache uniform locations
-
-		var identifiers = [
-
-			'viewMatrix',
-			'modelViewMatrix',
-			'projectionMatrix',
-			'normalMatrix',
-			'modelMatrix',
-			'cameraPosition',
-			'morphTargetInfluences',
-			'bindMatrix',
-			'bindMatrixInverse'
-
-		];
-
-		if ( parameters.useVertexTexture ) {
-
-			identifiers.push( 'boneTexture', 'boneTextureWidth', 'boneTextureHeight' );
-
-		} else {
-
-			identifiers.push( 'boneGlobalMatrices' );
-
-		}
-
-		if ( parameters.logarithmicDepthBuffer ) {
-
-			identifiers.push( 'logDepthBufFC' );
-
-		}
-
-		for ( var u in uniforms ) {
+		// set up caching for uniform locations
 
 
-			identifiers.push( u );
+		var getUniforms = function() { return this._cachedUniforms; };
 
 
-		}
+		this.getUniforms = function() {
 
 
-		this.uniforms = cacheUniformLocations( gl, program, identifiers );
+			// fetch, cache, and next time just use a dumb accessor
+			var uniforms = fetchUniformLocations( gl, program );
+			this._cachedUniforms = uniforms;
+			this.getUniforms = getUniforms;
+			return uniforms;
 
 
-		// cache attributes locations
+		};
 
 
-		if ( material instanceof THREE.RawShaderMaterial ) {
+		// set up caching for attribute locations
 
 
-			identifiers = attributes;
+		var getAttributes = function() { return this._cachedAttributes; };
 
 
-		} else {
+		this.getAttributes = function() {
 
 
-			identifiers = [
+			var attributes = fetchAttributeLocations( gl, program );
+			this._cachedAttributes = attributes;
+			this.getAttributes = getAttributes;
+			return attributes;
 
 
-				'position',
-				'normal',
-				'uv',
-				'uv2',
-				'tangent',
-				'color',
-				'skinIndex',
-				'skinWeight',
-				'lineDistance'
+		};
 
 
-			];
+		// DEPRECATED
 
 
-			for ( var i = 0; i < parameters.maxMorphTargets; i ++ ) {
+		Object.defineProperties( this, {
 
 
-				identifiers.push( 'morphTarget' + i );
+			uniforms: {
+				get: function() {
 
 
-			}
+					console.warn( 'THREE.WebGLProgram: .uniforms is now .getUniforms().' );
+					return this.getUniforms();
 
 
-			for ( var i = 0; i < parameters.maxMorphNormals; i ++ ) {
+				}
+			},
 
 
-				identifiers.push( 'morphNormal' + i );
+			attributes: {
+				get: function() {
 
 
-			}
-
-			// ShaderMaterial attributes
-
-			if ( Array.isArray( attributes ) ) {
-
-				identifiers = identifiers.concat( attributes );
+					console.warn( 'THREE.WebGLProgram: .attributes is now .getAttributes().' );
+					return this.getAttributes();
 
 
+				}
 			}
 			}
 
 
-		}
+		});
 
 
-		this.attributes = cacheAttributeLocations( gl, program, identifiers );
 
 
 		//
 		//
 
 

+ 35 - 21
src/textures/Texture.js

@@ -103,6 +103,36 @@ THREE.Texture.prototype = {
 
 
 		}
 		}
 
 
+		function getDataURL( image ) {
+
+			var canvas;
+
+			if ( image.toDataURL !== undefined ) {
+
+				canvas = image;
+
+			} else {
+
+				canvas = document.createElement( 'canvas' );
+				canvas.width = image.width;
+				canvas.height = image.height;
+
+				canvas.getContext( '2d' ).drawImage( image, 0, 0, image.width, image.height );
+
+			}
+
+			if ( canvas.width > 2048 || canvas.height > 2048 ) {
+
+				return canvas.toDataURL( 'image/jpeg', 0.6 );
+
+			} else {
+
+				return canvas.toDataURL( 'image/png' );
+
+			}
+
+		}
+
 		var output = {
 		var output = {
 			metadata: {
 			metadata: {
 				version: 4.4,
 				version: 4.4,
@@ -136,28 +166,12 @@ THREE.Texture.prototype = {
 
 
 			}
 			}
 
 
-			if ( meta.images[ this.image.uuid ] === undefined ) {
-
-				var canvas = document.createElement( 'canvas' );
-				canvas.width = image.width;
-				canvas.height = image.height;
-
-				var context = canvas.getContext( '2d' );
-				context.drawImage( image, 0, 0, image.width, image.height );
-
-				var src;
-
-				if ( image.width > 2048 || image.height > 2048 ) {
-
-					src = canvas.toDataURL( 'image/jpeg', 0.6 );
-
-				} else {
-
-					src = canvas.toDataURL( 'image/png' );
-
-				}
+			if ( meta.images[ image.uuid ] === undefined ) {
 
 
-				meta.images[ this.image.uuid ] = { uuid: this.image.uuid, url: src };
+				meta.images[ image.uuid ] = {
+					uuid: image.uuid,
+					url: getDataURL( image )
+				};
 
 
 			}
 			}
 
 

+ 8 - 1
utils/servers/python_server.sh

@@ -1,4 +1,11 @@
 #!/bin/sh
 #!/bin/sh
 
 
 cd `dirname $0`/../../
 cd `dirname $0`/../../
-python -m SimpleHTTPServer
+
+ret=`python -c 'import sys; print("%i" % (sys.version_info[0]))'`
+
+if [ $ret -eq 2 ]; then
+	python -m SimpleHTTPServer # Python 2
+else
+	python -m http.server # Python 3
+fi

Some files were not shown because too many files changed in this diff