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",
-	"version": "0.0.71",
 	"homepage": "http://threejs.org/",
 	"description": "JavaScript 3D library",
 	"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 vertices = geometry.vertices;
 		var faceVertexUvs = geometry.faceVertexUvs;
-		var materialVertexColors = material.vertexColors;
 
 		var hasFaceVertexUv = faceVertexUvs[ 0 ] && faceVertexUvs[ 0 ].length > 0;
 		var hasFaceVertexUv2 = faceVertexUvs[ 1 ] && faceVertexUvs[ 1 ].length > 0;
@@ -10085,11 +10082,11 @@ THREE.DirectGeometry.prototype = {
 
 			var vertexColors = face.vertexColors;
 
-			if ( materialVertexColors === THREE.VertexColors ) {
+			if ( vertexColors.length === 3 ) {
 
 				this.colors.push( vertexColors[ 0 ], vertexColors[ 1 ], vertexColors[ 2 ] );
 
-			} else if ( materialVertexColors === THREE.FaceColors ) {
+			} else {
 
 				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 );
 
@@ -12696,6 +12693,8 @@ THREE.XHRLoader.prototype = {
 
 		scope.manager.itemStart( url );
 
+		return request;
+
 	},
 
 	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 = {
 			metadata: {
 				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.hasColors && ! object.__webglColorBuffer ) object.__webglColorBuffer = _gl.createBuffer();
 
+		var attributes = program.getAttributes();
+
 		if ( object.hasPositions ) {
 
 			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglVertexBuffer );
 			_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 );
 
-			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.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.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 programAttributes = program.attributes;
+
+		var programAttributes = program.getAttributes();
+
+		var materialDefaultAttributeValues = material.defaultAttributeValues;
 
 		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;
 
-		var attributes = program.attributes;
+		var attributes = program.getAttributes();
 
 		if ( material.morphTargets ) {
 
@@ -20930,9 +20957,10 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		material.uniformsList = [];
 
+		var uniformLocations = material.program.getUniforms();
 		for ( var u in material.__webglShader.uniforms ) {
 
-			var location = material.program.uniforms[ u ];
+			var location = uniformLocations[ u ];
 
 			if ( location ) {
 				material.uniformsList.push( [ material.__webglShader.uniforms[ u ], location ] );
@@ -20978,7 +21006,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 		var refreshLights = false;
 
 		var program = material.program,
-			p_uniforms = program.uniforms,
+			p_uniforms = program.getUniforms(),
 			m_uniforms = material.__webglShader.uniforms;
 
 		if ( program.id !== _currentProgram ) {
@@ -23309,9 +23337,11 @@ THREE.WebGLObjects = function ( gl, info ) {
 
 			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 = {};
 
-		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 = {};
 
-		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 prefix_vertex, prefix_fragment;
+		var prefixVertex, prefixFragment;
 
 		if ( material instanceof THREE.RawShaderMaterial ) {
 
-			prefix_vertex = '';
-			prefix_fragment = '';
+			prefixVertex = '';
+			prefixFragment = '';
 
 		} else {
 
-			prefix_vertex = [
+			prefixVertex = [
 
 				'precision ' + parameters.precision + ' float;',
 				'precision ' + parameters.precision + ' int;',
@@ -23675,7 +23726,7 @@ THREE.WebGLProgram = ( function () {
 
 			].filter( filterEmptyLine ).join( '\n' );
 
-			prefix_fragment = [
+			prefixFragment = [
 
 				( 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, glFragmentShader );
@@ -23775,91 +23829,57 @@ THREE.WebGLProgram = ( function () {
 		gl.deleteShader( glVertexShader );
 		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},
 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.")};
-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],
 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*
 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,
 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.");
 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*
 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=
-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.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,
@@ -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);
 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.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}}(),
 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,
@@ -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}};
 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=
-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)}}();
 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}}();
@@ -194,55 +194,55 @@ THREE.Geometry=function(){Object.defineProperty(this,"id",{value:THREE.GeometryI
 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=
 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;
 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?
 (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;
-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,
-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=
 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"})}};
 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=
 !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.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,
 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=
 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.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));
@@ -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.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,
-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);
 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.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.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},
 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=
 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+
 ") 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}};
@@ -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;
 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};
-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};
 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.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.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),
 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"};
@@ -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.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=
-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.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),
@@ -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,
 "}"].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.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.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=
@@ -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.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,
-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.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.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}",
 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}"},
-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.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.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");
-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}};
 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]=
-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};
-(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);
 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};
@@ -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.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.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&&
 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.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=
-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-
 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;
@@ -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};
 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!==
-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],
-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]}};
 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}}};
@@ -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.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]}}};
-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.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;
 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;
-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;
 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;
 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=
-!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,
 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],
 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.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,
 (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.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),
-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;
 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/
 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.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;
-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],
 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,
 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;
 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;
 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.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,
-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);
 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;

+ 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.
-- 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 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>
+		
+		<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>
 		<div>
@@ -41,6 +49,13 @@
 		<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).
 		</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>

+ 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_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
 		var cubeCamera = new THREE.CubeCamera( 1, 100000, 128 );

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

@@ -15,7 +15,21 @@
 
 
 		<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 );
 scene.add( camera );</code>
 
@@ -36,6 +50,9 @@ scene.add( camera );</code>
 
 		<h2>Properties</h2>
 
+		<h3>[property:number zoom]</h3>
+		<div>Gets or sets the zoom factor of the camera. </div>
+		
 		<h3>[property:Float left]</h3>
 		<div>Camera frustum left plane.</div>
 
@@ -61,6 +78,18 @@ scene.add( camera );</code>
 		<div>
 		Updates the camera projection matrix. Must be called after change of parameters.
 		</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>

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

@@ -15,7 +15,15 @@
 
 
 		<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 );
 scene.add( camera );</code>
 
@@ -33,6 +41,9 @@ scene.add( camera );</code>
 
 		<h2>Properties</h2>
 
+		<h3>[property:number zoom]</h3>
+		<div>Gets or sets the zoom factor of the camera. </div>
+		
 		<h3>[property:Float fov]</h3>
 		<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>
 		Updates the camera projection matrix. Must be called after change of parameters.
 		</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>
 

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

@@ -66,7 +66,7 @@
 
 		<h3>[property:Vector3 up]</h3>
 		<div>
-		Up direction.
+		Up direction. Default is THREE.Vector3( 0, 1, 0 ).
 		</div>
 
 		<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
  		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>
 
 
@@ -79,6 +86,11 @@
 		Gets camera frustum far plane.
 		</div> 
 
+		<h3>[property:Matrix4 projectionMatrix]</h3>
+		<div>
+		This is the matrix which contains the projection.
+		</div>
+		
 		<h3>[property:OrthographicCamera cameraO]</h3>
 		<div>
 		Gets or sets the internal OrthographicCamera used as camera.
@@ -182,6 +194,6 @@
 
 		<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>
 </html>

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

@@ -39,9 +39,16 @@
 
 		<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>
 

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

@@ -109,12 +109,6 @@
 
 		<h2>Properties</h2>
 
-		<h3>[property:Object uniforms]</h3>
-		<div></div> 
-
-		<h3>[property:Object attributes]</h3>
-		<div></div> 
-
 		<h3>[property:String id]</h3>
 		<div></div> 
 
@@ -133,11 +127,17 @@
 		<h3>[property:WebGLShader fragmentShader]</h3>
 		<div></div> 
 
-
 		<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>
 

+ 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(/\[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;

+ 18 - 0
editor/index.html

@@ -47,6 +47,24 @@
 
 		<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/sortable.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,
 		indentWithTabs: true,
 		tabSize: 4,
-		indentUnit: 4
+		indentUnit: 4,
+		hintOptions: {
+			completeSingle: false
+		}
 	} );
 	codemirror.setOption( 'theme', 'monokai' );
 	codemirror.on( 'change', function () {
@@ -108,7 +111,6 @@ var Script = function ( editor ) {
 
 	} );
 
-
 	// validate
 
 	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 () {

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

@@ -642,7 +642,7 @@ Sidebar.Material = function ( editor ) {
 			'emissive': materialEmissiveRow,
 			'specular': materialSpecularRow,
 			'shininess': materialShininessRow,
-			'program': materialProgramRow,
+			'vertexShader': materialProgramRow,
 			'vertexColors': materialVertexColorsRow,
 			'skinning': materialSkinningRow,
 			'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_complex",
 				"webgl_multiple_canvases_grid",
+				"webgl_multiple_elements",
 				"webgl_multiple_views",
 				"webgl_nearestneighbour",
 				"webgl_octree",
@@ -359,6 +360,7 @@
 				"webgl_buffergeometry",
 				"webgl_buffergeometry_custom_attributes_particles",
 				"webgl_buffergeometry_drawcalls",
+				"webgl_buffergeometry_constructed_from_geometry",
 				"webgl_buffergeometry_instancing",
 				"webgl_buffergeometry_instancing_dynamic",
 				"webgl_buffergeometry_instancing_billboards",

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

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

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

@@ -1,6 +1,5 @@
 // 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 );
 		loader.setCrossOrigin( this.crossOrigin );
 		loader.setResponseType('arraybuffer');
-		loader.load( url, function ( text ) {
+		var request = loader.load( url, function ( text ) {
 
 			onLoad( scope.parse( text ) );
 
 		}, onProgress, onError );
 
+		return request;
 	},
 
 	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.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 ++ ) {
 
-					var offset = arguments[ i ] * 3;
 					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();
 
-					var offset2 = arguments[ i ] * 2;
-
 					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 );
 				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 );
 					scene.add( mesh );
 

+ 20 - 60
examples/webgl_multiple_elements.html

@@ -30,11 +30,10 @@
 				position: absolute;
 				top: 0px; width: 100%;
 				z-index: 1;
-				padding: 2em;
+				padding: 3em 0 0 0;
 			}
 
 			a {
-
 				color: #0080ff;
 			}
 
@@ -46,47 +45,30 @@
 			}
 
 			.list-item {
+				display: inline-block;
 				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 {
 				width: 200px;
 				height: 200px;
-				flex: 0 0 auto;
-				-webkit-flex: 0 0 auto;
 			}
+
 			.list-item .description {
+				color: #888;
 				font-family: sans-serif;
 				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>
 	</head>
 	<body>
 
 		<canvas id="c"></canvas>
+
 		<div id="content">
 			<div id="info"><a href="http://threejs.org" target="_blank">three.js</a> - multiple elements - webgl</div>
 		</div>
@@ -97,7 +79,7 @@
 
 		<script id="template" type="notjs">
 			<div class="scene"></div>
-			<div class="description">some random text about this object, scene, whatever</div>
+			<div class="description">Scene $</div>
 		</script>
 		<script>
 
@@ -114,8 +96,8 @@
 
 				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 = [
 					new THREE.BoxGeometry( 1, 1, 1 ),
@@ -129,37 +111,32 @@
 
 				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();
 
-					// make a list item.
+					// make a list item
 					var element = document.createElement( "div" );
-					element.innerHTML = template;
 					element.className = "list-item";
+					element.innerHTML = template.replace('$', i + 1 );
 
 					// Look up the element that represents the area
 					// we want to render the scene
 					scene.element = element.querySelector(".scene");
-					content.appendChild(element);
+					content.appendChild( element );
 
 					// add one random mesh to each scene
 					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 ) );
 
-					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 );
 
 					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>
 
 	</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 ++ ) {
 

+ 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 );
 

+ 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 vertices = geometry.vertices;
 		var faceVertexUvs = geometry.faceVertexUvs;
-		var materialVertexColors = material.vertexColors;
 
 		var hasFaceVertexUv = faceVertexUvs[ 0 ] && faceVertexUvs[ 0 ].length > 0;
 		var hasFaceVertexUv2 = faceVertexUvs[ 1 ] && faceVertexUvs[ 1 ].length > 0;
@@ -134,11 +131,11 @@ THREE.DirectGeometry.prototype = {
 
 			var vertexColors = face.vertexColors;
 
-			if ( materialVertexColors === THREE.VertexColors ) {
+			if ( vertexColors.length === 3 ) {
 
 				this.colors.push( vertexColors[ 0 ], vertexColors[ 1 ], vertexColors[ 2 ] );
 
-			} else if ( materialVertexColors === THREE.FaceColors ) {
+			} else {
 
 				var color = face.color;
 

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

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

+ 2 - 0
src/loaders/XHRLoader.js

@@ -65,6 +65,8 @@ THREE.XHRLoader.prototype = {
 
 		scope.manager.itemStart( url );
 
+		return request;
+
 	},
 
 	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.hasColors && ! object.__webglColorBuffer ) object.__webglColorBuffer = _gl.createBuffer();
 
+		var attributes = program.getAttributes();
+
 		if ( object.hasPositions ) {
 
 			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglVertexBuffer );
 			_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 );
 
-			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.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.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 programAttributes = program.attributes;
+
+		var programAttributes = program.getAttributes();
+
+		var materialDefaultAttributeValues = material.defaultAttributeValues;
 
 		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;
 
-		var attributes = program.attributes;
+		var attributes = program.getAttributes();
 
 		if ( material.morphTargets ) {
 
@@ -2019,9 +2033,10 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		material.uniformsList = [];
 
+		var uniformLocations = material.program.getUniforms();
 		for ( var u in material.__webglShader.uniforms ) {
 
-			var location = material.program.uniforms[ u ];
+			var location = uniformLocations[ u ];
 
 			if ( location ) {
 				material.uniformsList.push( [ material.__webglShader.uniforms[ u ], location ] );
@@ -2067,7 +2082,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 		var refreshLights = false;
 
 		var program = material.program,
-			p_uniforms = program.uniforms,
+			p_uniforms = program.getUniforms(),
 			m_uniforms = material.__webglShader.uniforms;
 
 		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.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 = {};
 
-		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 = {};
 
-		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 prefix_vertex, prefix_fragment;
+		var prefixVertex, prefixFragment;
 
 		if ( material instanceof THREE.RawShaderMaterial ) {
 
-			prefix_vertex = '';
-			prefix_fragment = '';
+			prefixVertex = '';
+			prefixFragment = '';
 
 		} else {
 
-			prefix_vertex = [
+			prefixVertex = [
 
 				'precision ' + parameters.precision + ' float;',
 				'precision ' + parameters.precision + ' int;',
@@ -270,7 +291,7 @@ THREE.WebGLProgram = ( function () {
 
 			].filter( filterEmptyLine ).join( '\n' );
 
-			prefix_fragment = [
+			prefixFragment = [
 
 				( 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, glFragmentShader );
@@ -370,91 +394,57 @@ THREE.WebGLProgram = ( function () {
 		gl.deleteShader( glVertexShader );
 		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 = {
 			metadata: {
 				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
 
 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