{"version":3,"file":"polyfills.71e3f4c32b1aad00.js","sources":["./node_modules/aframe-auth-obj-model/dist/index.js","./node_modules/aframe-light-probe/dist/index.js","./node_modules/aframe-orbit-controls/index.js","./node_modules/aframe-orbit-controls/lib/OrbitControls.js","./node_modules/aframe/dist/aframe-master.js","./node_modules/zone.js/fesm2015/zone.js","./node_modules/@babel/runtime/helpers/asyncToGenerator.js"],"sourceRoot":"webpack:///","sourcesContent":["!function(t){var e={};function r(i){if(e[i])return e[i].exports;var a=e[i]={i:i,l:!1,exports:{}};return t[i].call(a.exports,a,a.exports,r),a.l=!0,a.exports}r.m=t,r.c=e,r.d=function(t,e,i){r.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:i})},r.r=function(t){\"undefined\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(t,\"__esModule\",{value:!0})},r.t=function(t,e){if(1&e&&(t=r(t)),8&e)return t;if(4&e&&\"object\"==typeof t&&t&&t.__esModule)return t;var i=Object.create(null);if(r.r(i),Object.defineProperty(i,\"default\",{enumerable:!0,value:t}),2&e&&\"string\"!=typeof t)for(var a in t)r.d(i,a,function(e){return t[e]}.bind(null,a));return i},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,\"a\",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p=\"\",r(r.s=0)}([function(t,e,r){r(1),r(2),t.exports=r(3)},function(t,e){THREE.AuthOBJLoader=function(){var t=/^[og]\\s*(.+)?/,e=/^mtllib /,r=/^usemtl /;function i(){var t={objects:[],object:{},vertices:[],normals:[],colors:[],uvs:[],materialLibraries:[],startObject:function(t,e){if(this.object&&!1===this.object.fromDeclaration)return this.object.name=t,void(this.object.fromDeclaration=!1!==e);var r=this.object&&\"function\"==typeof this.object.currentMaterial?this.object.currentMaterial():void 0;if(this.object&&\"function\"==typeof this.object._finalize&&this.object._finalize(!0),this.object={name:t||\"\",fromDeclaration:!1!==e,geometry:{vertices:[],normals:[],colors:[],uvs:[]},materials:[],smooth:!0,startMaterial:function(t,e){var r=this._finalize(!1);r&&(r.inherited||r.groupCount<=0)&&this.materials.splice(r.index,1);var i={index:this.materials.length,name:t||\"\",mtllib:Array.isArray(e)&&e.length>0?e[e.length-1]:\"\",smooth:void 0!==r?r.smooth:this.smooth,groupStart:void 0!==r?r.groupEnd:0,groupEnd:-1,groupCount:-1,inherited:!1,clone:function(t){var e={index:\"number\"==typeof t?t:this.index,name:this.name,mtllib:this.mtllib,smooth:this.smooth,groupStart:0,groupEnd:-1,groupCount:-1,inherited:!1};return e.clone=this.clone.bind(e),e}};return this.materials.push(i),i},currentMaterial:function(){if(this.materials.length>0)return this.materials[this.materials.length-1]},_finalize:function(t){var e=this.currentMaterial();if(e&&-1===e.groupEnd&&(e.groupEnd=this.geometry.vertices.length/3,e.groupCount=e.groupEnd-e.groupStart,e.inherited=!1),t&&this.materials.length>1)for(var r=this.materials.length-1;r>=0;r--)this.materials[r].groupCount<=0&&this.materials.splice(r,1);return t&&0===this.materials.length&&this.materials.push({name:\"\",smooth:this.smooth}),e}},r&&r.name&&\"function\"==typeof r.clone){var i=r.clone(0);i.inherited=!0,this.object.materials.push(i)}this.objects.push(this.object)},finalize:function(){this.object&&\"function\"==typeof this.object._finalize&&this.object._finalize(!0)},parseVertexIndex:function(t,e){var r=parseInt(t,10);return 3*(r>=0?r-1:r+e/3)},parseNormalIndex:function(t,e){var r=parseInt(t,10);return 3*(r>=0?r-1:r+e/3)},parseUVIndex:function(t,e){var r=parseInt(t,10);return 2*(r>=0?r-1:r+e/2)},addVertex:function(t,e,r){var i=this.vertices,a=this.object.geometry.vertices;a.push(i[t+0],i[t+1],i[t+2]),a.push(i[e+0],i[e+1],i[e+2]),a.push(i[r+0],i[r+1],i[r+2])},addVertexPoint:function(t){var e=this.vertices;this.object.geometry.vertices.push(e[t+0],e[t+1],e[t+2])},addVertexLine:function(t){var e=this.vertices;this.object.geometry.vertices.push(e[t+0],e[t+1],e[t+2])},addNormal:function(t,e,r){var i=this.normals,a=this.object.geometry.normals;a.push(i[t+0],i[t+1],i[t+2]),a.push(i[e+0],i[e+1],i[e+2]),a.push(i[r+0],i[r+1],i[r+2])},addColor:function(t,e,r){var i=this.colors,a=this.object.geometry.colors;a.push(i[t+0],i[t+1],i[t+2]),a.push(i[e+0],i[e+1],i[e+2]),a.push(i[r+0],i[r+1],i[r+2])},addUV:function(t,e,r){var i=this.uvs,a=this.object.geometry.uvs;a.push(i[t+0],i[t+1]),a.push(i[e+0],i[e+1]),a.push(i[r+0],i[r+1])},addUVLine:function(t){var e=this.uvs;this.object.geometry.uvs.push(e[t+0],e[t+1])},addFace:function(t,e,r,i,a,s,o,n,l){var h=this.vertices.length,u=this.parseVertexIndex(t,h),c=this.parseVertexIndex(e,h),p=this.parseVertexIndex(r,h);if(this.addVertex(u,c,p),void 0!==i&&\"\"!==i){var d=this.uvs.length;u=this.parseUVIndex(i,d),c=this.parseUVIndex(a,d),p=this.parseUVIndex(s,d),this.addUV(u,c,p)}if(void 0!==o&&\"\"!==o){var f=this.normals.length;u=this.parseNormalIndex(o,f),c=o===n?u:this.parseNormalIndex(n,f),p=o===l?u:this.parseNormalIndex(l,f),this.addNormal(u,c,p)}this.colors.length>0&&this.addColor(u,c,p)},addPointGeometry:function(t){this.object.geometry.type=\"Points\";for(var e=this.vertices.length,r=0,i=t.length;r0){var E=b.split(\"/\");m.push(E)}}var L=m[0];for(g=1,v=m.length-1;g1){var k=h[1].trim().toLowerCase();s.object.smooth=\"0\"!==k&&\"off\"!==k}else s.object.smooth=!0;(N=s.object.currentMaterial())&&(N.smooth=s.object.smooth)}s.finalize();var F=new THREE.Group;F.materialLibraries=[].concat(s.materialLibraries);for(c=0,p=s.objects.length;c0?z.addAttribute(\"normal\",new THREE.Float32BufferAttribute(C.normals,3)):z.computeVertexNormals(),C.colors.length>0&&(_=!0,z.addAttribute(\"color\",new THREE.Float32BufferAttribute(C.colors,3))),C.uvs.length>0&&z.addAttribute(\"uv\",new THREE.Float32BufferAttribute(C.uvs,2));for(var S,U=[],q=0,D=I.length;q1){for(q=0,D=I.length;q=0?o.substring(0,n):o;l=l.toLowerCase();var h=n>=0?o.substring(n+1):\"\";if(h=h.trim(),\"newmtl\"===l)r={name:h},a[h]=r;else if(r)if(\"ka\"===l||\"kd\"===l||\"ks\"===l){var u=h.split(i,3);r[l]=[parseFloat(u[0]),parseFloat(u[1]),parseFloat(u[2])]}else r[l]=h}}var c=new THREE.AuthMTLLoader.MaterialCreator(this.texturePath||this.path,this.materialOptions,this.textureLoading);return c.setCrossOrigin(this.crossOrigin),c.setManager(this.manager),c.setMaterials(a),c}},THREE.AuthMTLLoader.MaterialCreator=function(t,e,r=!1){this.baseUrl=t||\"\",this.options=e,this.materialsInfo={},this.materials={},this.materialsArray=[],this.nameLookup={},this.side=this.options&&this.options.side?this.options.side:THREE.FrontSide,this.wrap=this.options&&this.options.wrap?this.options.wrap:THREE.RepeatWrapping,this.textureLoading=r},THREE.AuthMTLLoader.MaterialCreator.prototype={constructor:THREE.AuthMTLLoader.MaterialCreator,crossOrigin:\"Anonymous\",setCrossOrigin:function(t){this.crossOrigin=t},setManager:function(t){this.manager=t},setMaterials:function(t){this.materialsInfo=this.convert(t),this.materials={},this.materialsArray=[],this.nameLookup={}},convert:function(t){if(!this.options)return t;var e={};for(var r in t){var i=t[r],a={};for(var s in e[r]=a,i){var o=!0,n=i[s],l=s.toLowerCase();switch(l){case\"kd\":case\"ka\":case\"ks\":this.options&&this.options.normalizeRGB&&(n=[n[0]/255,n[1]/255,n[2]/255]),this.options&&this.options.ignoreZeroRGBs&&0===n[0]&&0===n[1]&&0===n[2]&&(o=!1)}o&&(a[l]=n)}}return e},preload:function(){for(var t in this.materialsInfo)this.create(t)},getIndex:function(t){return this.nameLookup[t]},getAsArray:function(){var t=0;for(var e in this.materialsInfo)this.materialsArray[t]=this.create(e),this.nameLookup[e]=t,t++;return this.materialsArray},create:function(t){return void 0===this.materials[t]&&this.createMaterial_(t),this.materials[t]},createMaterial_:function(t){var e=this,r=this.materialsInfo[t],i={name:t,side:this.side};function a(t,r){if(!i[t]){var a,s,o=e.getTextureParams(r,i),n=e.loadTexture((a=e.baseUrl,\"string\"!=typeof(s=o.url)||\"\"===s?\"\":/^https?:\\/\\//i.test(s)?s:a+s));n.repeat.copy(o.scale),n.offset.copy(o.offset),n.wrapS=e.wrap,n.wrapT=e.wrap,i[t]=n}}for(var s in r){var o,n=r[s];if(\"\"!==n)switch(s.toLowerCase()){case\"kd\":i.color=(new THREE.Color).fromArray(n);break;case\"ks\":i.specular=(new THREE.Color).fromArray(n);break;case\"map_kd\":e.textureLoading&&a(\"map\",n);break;case\"map_ks\":e.textureLoading&&a(\"specularMap\",n);break;case\"map_ns\":e.textureLoading&&a(\"roughnessMap\",n);break;case\"refl\":e.textureLoading&&a(\"metalnessMap\",n);break;case\"norm\":e.textureLoading&&a(\"normalMap\",n);break;case\"map_bump\":case\"bump\":e.textureLoading&&a(\"bumpMap\",n);break;case\"ns\":i.shininess=parseFloat(n);break;case\"d\":(o=parseFloat(n))<1&&(i.opacity=o,i.transparent=!0);break;case\"tr\":o=parseFloat(n),this.options&&this.options.invertTrProperty&&(o=1-o),o<1&&(i.opacity=o,i.transparent=!0)}}return this.materials[t]=this.textureLoading?new THREE.MeshBasicMaterial(i):new THREE.MeshPhongMaterial(i),this.materials[t]},getTextureParams:function(t,e){var r,i={scale:new THREE.Vector2(1,1),offset:new THREE.Vector2(0,0)},a=t.split(/\\s+/);return(r=a.indexOf(\"-bm\"))>=0&&(e.bumpScale=parseFloat(a[r+1]),a.splice(r,2)),(r=a.indexOf(\"-s\"))>=0&&(i.scale.set(parseFloat(a[r+1]),parseFloat(a[r+2])),a.splice(r,4)),(r=a.indexOf(\"-o\"))>=0&&(i.offset.set(parseFloat(a[r+1]),parseFloat(a[r+2])),a.splice(r,4)),i.url=a.join(\" \").trim(),i},loadTexture:function(t,e,r,i,a){var s,o=THREE.Loader.Handlers.get(t),n=void 0!==this.manager?this.manager:THREE.DefaultLoadingManager;return null===o&&(o=new THREE.TextureLoader(n)),o.setCrossOrigin&&o.setCrossOrigin(this.crossOrigin),s=o.load(t,r,i,a),void 0!==e&&(s.mapping=e),s}}},function(t,e){if(\"undefined\"==typeof AFRAME)throw new Error(\"Component attempted to register before AFRAME was available.\");AFRAME.registerComponent(\"auth-obj-model\",{schema:{mtl:{type:\"string\"},obj:{type:\"string\"},textures:{type:\"string\"},token:{type:\"string\"}},init:function(){THREE.Cache.enabled=!0,this.model=null,this.objLoader=new THREE.AuthOBJLoader,this.mtlLoader=new THREE.AuthMTLLoader(this.objLoader.manager),this.mtlLoader.crossOrigin=\"\"},update:function(){var t=this.data;this.objLoader.setToken(t.token),this.mtlLoader.setToken(t.token),this.mtlLoader.setTextureLoading(t.textures.length>0),t.obj&&(this.resetMesh(),this.loadObj(t.obj,t.mtl,t.textures))},abort:function(){this.objLoader&&this.objLoader.request&&\"function\"==typeof this.objLoader.request.abort&&this.objLoader.request.abort(),this.mtlLoader&&this.mtlLoader.request&&\"function\"==typeof this.mtlLoader.request.abort&&this.mtlLoader.request.abort()},remove:function(){this.model&&this.resetMesh()},resetMesh:function(){this.el.removeObject3D(\"mesh\")},loadObj:function(t,e,r){var i=this,a=this.el,s=this.mtlLoader,o=this.objLoader;if(e)return a.hasAttribute(\"material\")&&warn(\"Material component properties are ignored when a .MTL is provided\"),s.setTexturePath(r||e.substr(0,e.lastIndexOf(\"/\")+1)),void s.load(e,function(e){e.preload(),o.setMaterials(e),o.load(t,function(t){i.model=t,a.setObject3D(\"mesh\",t),a.emit(\"model-loaded\",{format:\"obj\",model:t})})});o.load(t,function(t){var e=a.components.material;e&&t.traverse(function(t){t instanceof THREE.Mesh&&(t.material=e.material)}),i.model=t,a.setObject3D(\"mesh\",t),a.emit(\"model-loaded\",{format:\"obj\",model:t})})}})}]);","!function(e){var t={};function r(o){if(t[o])return t[o].exports;var n=t[o]={i:o,l:!1,exports:{}};return e[o].call(n.exports,n,n.exports,r),n.l=!0,n.exports}r.m=e,r.c=t,r.d=function(e,t,o){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},r.r=function(e){\"undefined\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(e,\"__esModule\",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&\"object\"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(r.r(o),Object.defineProperty(o,\"default\",{enumerable:!0,value:e}),2&t&&\"string\"!=typeof e)for(var n in e)r.d(o,n,function(t){return e[t]}.bind(null,n));return o},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,\"a\",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p=\"\",r(r.s=0)}([function(e,t,r){r(1),e.exports=r(2)},function(e,t){THREE.LightProbeGenerator={fromCubeTexture:function(e){for(var t,r,o,n=0,i=new THREE.Vector3,a=new THREE.Vector3,u=new THREE.Color,c=[0,0,0,0,0,0,0,0,0],s=new THREE.SphericalHarmonics3,l=s.coefficients,f=0;f<6;f++){var h=e.image[f],b=h.width,d=h.height,g=document.createElement(\"canvas\");g.width=b,g.height=d;var p=g.getContext(\"2d\");p.drawImage(h,0,0,b,d);for(var E=p.getImageData(0,0,b,d),m=E.data,v=E.width,y=2/v,T=0,P=m.length;T EPS\n\t\t\t// using small-angle approximation cos(x/2) = 1 - x^2 / 8\n\n\t\t\tif ( zoomChanged ||\n\t\t\t\tlastPosition.distanceToSquared( scope.object.position ) > EPS ||\n\t\t\t\t8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS ) {\n\n\t\t\t\tscope.dispatchEvent( changeEvent );\n\n\t\t\t\tlastPosition.copy( scope.object.position );\n\t\t\t\tlastQuaternion.copy( scope.object.quaternion );\n\t\t\t\tzoomChanged = false;\n\n\t\t\t\treturn true;\n\n\t\t\t}\n\n\t\t\treturn false;\n\n\t\t};\n\n\t}();\n\n\tthis.dispose = function () {\n\n\t\tscope.domElement.removeEventListener( 'contextmenu', onContextMenu, false );\n\t\tscope.domElement.removeEventListener( 'mousedown', onMouseDown, false );\n\t\tscope.domElement.removeEventListener( 'wheel', onMouseWheel, false );\n\n\t\tscope.domElement.removeEventListener( 'touchstart', onTouchStart, false );\n\t\tscope.domElement.removeEventListener( 'touchend', onTouchEnd, false );\n\t\tscope.domElement.removeEventListener( 'touchmove', onTouchMove, false );\n\n\t\tdocument.removeEventListener( 'mousemove', onMouseMove, false );\n\t\tdocument.removeEventListener( 'mouseup', onMouseUp, false );\n\n\t\twindow.removeEventListener( 'keydown', onKeyDown, false );\n\n\t\t//scope.dispatchEvent( { type: 'dispose' } ); // should this be added here?\n\n\t};\n\n\t//\n\t// internals\n\t//\n\n\tvar scope = this;\n\n\tvar changeEvent = { type: 'change' };\n\tvar startEvent = { type: 'start' };\n\tvar endEvent = { type: 'end' };\n\n\tvar STATE = { NONE: - 1, ROTATE: 0, DOLLY: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_DOLLY: 4, TOUCH_PAN: 5 };\n\n\tvar state = STATE.NONE;\n\n\tvar EPS = 0.000001;\n\n\t// current position in spherical coordinates\n\tvar spherical = new THREE.Spherical();\n\tvar sphericalDelta = new THREE.Spherical();\n\n\tvar scale = 1;\n\tvar panOffset = new THREE.Vector3();\n\tvar zoomChanged = false;\n\n\tvar rotateStart = new THREE.Vector2();\n\tvar rotateEnd = new THREE.Vector2();\n\tvar rotateDelta = new THREE.Vector2();\n\n\tvar panStart = new THREE.Vector2();\n\tvar panEnd = new THREE.Vector2();\n\tvar panDelta = new THREE.Vector2();\n\n\tvar dollyStart = new THREE.Vector2();\n\tvar dollyEnd = new THREE.Vector2();\n\tvar dollyDelta = new THREE.Vector2();\n\n\tfunction getAutoRotationAngle() {\n\n\t\treturn 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;\n\n\t}\n\n\tfunction getZoomScale() {\n\n\t\treturn Math.pow( 0.95, scope.zoomSpeed );\n\n\t}\n\n\tfunction rotateLeft( angle ) {\n\n\t\tsphericalDelta.theta -= angle;\n\n\t}\n\n\tfunction rotateUp( angle ) {\n\n\t\tsphericalDelta.phi -= angle;\n\n\t}\n\n\tvar panLeft = function () {\n\n\t\tvar v = new THREE.Vector3();\n\n\t\treturn function panLeft( distance, objectMatrix ) {\n\n\t\t\tv.setFromMatrixColumn( objectMatrix, 0 ); // get X column of objectMatrix\n\t\t\tv.multiplyScalar( - distance );\n\n\t\t\tpanOffset.add( v );\n\n\t\t};\n\n\t}();\n\n\tvar panUp = function () {\n\n\t\tvar v = new THREE.Vector3();\n\n\t\treturn function panUp( distance, objectMatrix ) {\n\n\t\t\tv.setFromMatrixColumn( objectMatrix, 1 ); // get Y column of objectMatrix\n\t\t\tv.multiplyScalar( distance );\n\n\t\t\tpanOffset.add( v );\n\n\t\t};\n\n\t}();\n\n\t// deltaX and deltaY are in pixels; right and down are positive\n\tvar pan = function () {\n\n\t\tvar offset = new THREE.Vector3();\n\n\t\treturn function pan( deltaX, deltaY ) {\n\n\t\t\tvar element = scope.domElement === document ? scope.domElement.body : scope.domElement;\n\n\t\t\tif ( scope.object.isPerspectiveCamera ) {\n\n\t\t\t\t// perspective\n\t\t\t\tvar position = scope.object.position;\n\t\t\t\toffset.copy( position ).sub( scope.target );\n\t\t\t\tvar targetDistance = offset.length();\n\n\t\t\t\t// half of the fov is center to top of screen\n\t\t\t\ttargetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 );\n\n\t\t\t\t// we actually don't use screenWidth, since perspective camera is fixed to screen height\n\t\t\t\tpanLeft( 2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix );\n\t\t\t\tpanUp( 2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix );\n\n\t\t\t} else if ( scope.object.isOrthographicCamera ) {\n\n\t\t\t\t// orthographic\n\t\t\t\tpanLeft( deltaX * ( scope.object.right - scope.object.left ) / scope.object.zoom / element.clientWidth, scope.object.matrix );\n\t\t\t\tpanUp( deltaY * ( scope.object.top - scope.object.bottom ) / scope.object.zoom / element.clientHeight, scope.object.matrix );\n\n\t\t\t} else {\n\n\t\t\t\t// camera neither orthographic nor perspective\n\t\t\t\tconsole.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' );\n\t\t\t\tscope.enablePan = false;\n\n\t\t\t}\n\n\t\t};\n\n\t}();\n\n\tfunction dollyIn( dollyScale ) {\n\n\t\tif ( scope.object.isPerspectiveCamera ) {\n\n\t\t\tscale /= dollyScale;\n\n\t\t} else if ( scope.object.isOrthographicCamera ) {\n\n\t\t\tscope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom * dollyScale ) );\n\t\t\tscope.object.updateProjectionMatrix();\n\t\t\tzoomChanged = true;\n\n\t\t} else {\n\n\t\t\tconsole.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );\n\t\t\tscope.enableZoom = false;\n\n\t\t}\n\n\t}\n\n\tfunction dollyOut( dollyScale ) {\n\n\t\tif ( scope.object.isPerspectiveCamera ) {\n\n\t\t\tscale *= dollyScale;\n\n\t\t} else if ( scope.object.isOrthographicCamera ) {\n\n\t\t\tscope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / dollyScale ) );\n\t\t\tscope.object.updateProjectionMatrix();\n\t\t\tzoomChanged = true;\n\n\t\t} else {\n\n\t\t\tconsole.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );\n\t\t\tscope.enableZoom = false;\n\n\t\t}\n\n\t}\n\n\t//\n\t// event callbacks - update the object state\n\t//\n\n\tfunction handleMouseDownRotate( event ) {\n\n\t\t//console.log( 'handleMouseDownRotate' );\n\n\t\trotateStart.set( event.clientX, event.clientY );\n\n\t}\n\n\tfunction handleMouseDownDolly( event ) {\n\n\t\t//console.log( 'handleMouseDownDolly' );\n\n\t\tdollyStart.set( event.clientX, event.clientY );\n\n\t}\n\n\tfunction handleMouseDownPan( event ) {\n\n\t\t//console.log( 'handleMouseDownPan' );\n\n\t\tpanStart.set( event.clientX, event.clientY );\n\n\t}\n\n\tfunction handleMouseMoveRotate( event ) {\n\n\t\t//console.log( 'handleMouseMoveRotate' );\n\n\t\trotateEnd.set( event.clientX, event.clientY );\n\t\trotateDelta.subVectors( rotateEnd, rotateStart );\n\n\t\tvar element = scope.domElement === document ? scope.domElement.body : scope.domElement;\n\n\t\t// rotating across whole screen goes 360 degrees around\n\t\trotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );\n\n\t\t// rotating up and down along whole screen attempts to go 360, but limited to 180\n\t\trotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );\n\n\t\trotateStart.copy( rotateEnd );\n\n\t\tscope.update();\n\n\t}\n\n\tfunction handleMouseMoveDolly( event ) {\n\n\t\t//console.log( 'handleMouseMoveDolly' );\n\n\t\tdollyEnd.set( event.clientX, event.clientY );\n\n\t\tdollyDelta.subVectors( dollyEnd, dollyStart );\n\n\t\tif ( dollyDelta.y > 0 ) {\n\n\t\t\tdollyIn( getZoomScale() );\n\n\t\t} else if ( dollyDelta.y < 0 ) {\n\n\t\t\tdollyOut( getZoomScale() );\n\n\t\t}\n\n\t\tdollyStart.copy( dollyEnd );\n\n\t\tscope.update();\n\n\t}\n\n\tfunction handleMouseMovePan( event ) {\n\n\t\t//console.log( 'handleMouseMovePan' );\n\n\t\tpanEnd.set( event.clientX, event.clientY );\n\n\t\tpanDelta.subVectors( panEnd, panStart );\n\n\t\tpan( panDelta.x, panDelta.y );\n\n\t\tpanStart.copy( panEnd );\n\n\t\tscope.update();\n\n\t}\n\n\tfunction handleMouseUp( event ) {\n\n\t\t// console.log( 'handleMouseUp' );\n\n\t}\n\n\tfunction handleMouseWheel( event ) {\n\n\t\t// console.log( 'handleMouseWheel' );\n\n\t\tif ( event.deltaY < 0 ) {\n\n\t\t\tdollyOut( getZoomScale() );\n\n\t\t} else if ( event.deltaY > 0 ) {\n\n\t\t\tdollyIn( getZoomScale() );\n\n\t\t}\n\n\t\tscope.update();\n\n\t}\n\n\tfunction handleKeyDown( event ) {\n\n\t\t//console.log( 'handleKeyDown' );\n\n\t\tswitch ( event.keyCode ) {\n\n\t\t\tcase scope.keys.UP:\n\t\t\t\tpan( 0, scope.keyPanSpeed );\n\t\t\t\tscope.update();\n\t\t\t\tbreak;\n\n\t\t\tcase scope.keys.BOTTOM:\n\t\t\t\tpan( 0, - scope.keyPanSpeed );\n\t\t\t\tscope.update();\n\t\t\t\tbreak;\n\n\t\t\tcase scope.keys.LEFT:\n\t\t\t\tpan( scope.keyPanSpeed, 0 );\n\t\t\t\tscope.update();\n\t\t\t\tbreak;\n\n\t\t\tcase scope.keys.RIGHT:\n\t\t\t\tpan( - scope.keyPanSpeed, 0 );\n\t\t\t\tscope.update();\n\t\t\t\tbreak;\n\n\t\t}\n\n\t}\n\n\tfunction handleTouchStartRotate( event ) {\n\n\t\t//console.log( 'handleTouchStartRotate' );\n\n\t\trotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );\n\n\t}\n\n\tfunction handleTouchStartDolly( event ) {\n\n\t\t//console.log( 'handleTouchStartDolly' );\n\n\t\tvar dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;\n\t\tvar dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;\n\n\t\tvar distance = Math.sqrt( dx * dx + dy * dy );\n\n\t\tdollyStart.set( 0, distance );\n\n\t}\n\n\tfunction handleTouchStartPan( event ) {\n\n\t\t//console.log( 'handleTouchStartPan' );\n\n\t\tpanStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );\n\n\t}\n\n\tfunction handleTouchMoveRotate( event ) {\n\n\t\t//console.log( 'handleTouchMoveRotate' );\n\n\t\trotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );\n\t\trotateDelta.subVectors( rotateEnd, rotateStart );\n\n\t\tvar element = scope.domElement === document ? scope.domElement.body : scope.domElement;\n\n\t\t// rotating across whole screen goes 360 degrees around\n\t\trotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );\n\n\t\t// rotating up and down along whole screen attempts to go 360, but limited to 180\n\t\trotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );\n\n\t\trotateStart.copy( rotateEnd );\n\n\t\tscope.update();\n\n\t}\n\n\tfunction handleTouchMoveDolly( event ) {\n\n\t\t//console.log( 'handleTouchMoveDolly' );\n\n\t\tvar dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;\n\t\tvar dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;\n\n\t\tvar distance = Math.sqrt( dx * dx + dy * dy );\n\n\t\tdollyEnd.set( 0, distance );\n\n\t\tdollyDelta.subVectors( dollyEnd, dollyStart );\n\n\t\tif ( dollyDelta.y > 0 ) {\n\n\t\t\tdollyOut( getZoomScale() );\n\n\t\t} else if ( dollyDelta.y < 0 ) {\n\n\t\t\tdollyIn( getZoomScale() );\n\n\t\t}\n\n\t\tdollyStart.copy( dollyEnd );\n\n\t\tscope.update();\n\n\t}\n\n\tfunction handleTouchMovePan( event ) {\n\n\t\t//console.log( 'handleTouchMovePan' );\n\n\t\tpanEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );\n\n\t\tpanDelta.subVectors( panEnd, panStart );\n\n\t\tpan( panDelta.x, panDelta.y );\n\n\t\tpanStart.copy( panEnd );\n\n\t\tscope.update();\n\n\t}\n\n\tfunction handleTouchEnd( event ) {\n\n\t\t//console.log( 'handleTouchEnd' );\n\n\t}\n\n\t//\n\t// event handlers - FSM: listen for events and reset state\n\t//\n\n\tfunction onMouseDown( event ) {\n\n\t\tif ( scope.enabled === false ) return;\n\n\t\tevent.preventDefault();\n\n\t\tswitch ( event.button ) {\n\n\t\t\tcase scope.mouseButtons.ORBIT:\n\n\t\t\t\tif ( scope.enableRotate === false ) return;\n\n\t\t\t\thandleMouseDownRotate( event );\n\n\t\t\t\tstate = STATE.ROTATE;\n\n\t\t\t\tbreak;\n\n\t\t\tcase scope.mouseButtons.ZOOM:\n\n\t\t\t\tif ( scope.enableZoom === false ) return;\n\n\t\t\t\thandleMouseDownDolly( event );\n\n\t\t\t\tstate = STATE.DOLLY;\n\n\t\t\t\tbreak;\n\n\t\t\tcase scope.mouseButtons.PAN:\n\n\t\t\t\tif ( scope.enablePan === false ) return;\n\n\t\t\t\thandleMouseDownPan( event );\n\n\t\t\t\tstate = STATE.PAN;\n\n\t\t\t\tbreak;\n\n\t\t}\n\n\t\tif ( state !== STATE.NONE ) {\n\n\t\t\tdocument.addEventListener( 'mousemove', onMouseMove, false );\n\t\t\tdocument.addEventListener( 'mouseup', onMouseUp, false );\n\n\t\t\tscope.dispatchEvent( startEvent );\n\n\t\t}\n\n\t}\n\n\tfunction onMouseMove( event ) {\n\n\t\tif ( scope.enabled === false ) return;\n\n\t\tevent.preventDefault();\n\n\t\tswitch ( state ) {\n\n\t\t\tcase STATE.ROTATE:\n\n\t\t\t\tif ( scope.enableRotate === false ) return;\n\n\t\t\t\thandleMouseMoveRotate( event );\n\n\t\t\t\tbreak;\n\n\t\t\tcase STATE.DOLLY:\n\n\t\t\t\tif ( scope.enableZoom === false ) return;\n\n\t\t\t\thandleMouseMoveDolly( event );\n\n\t\t\t\tbreak;\n\n\t\t\tcase STATE.PAN:\n\n\t\t\t\tif ( scope.enablePan === false ) return;\n\n\t\t\t\thandleMouseMovePan( event );\n\n\t\t\t\tbreak;\n\n\t\t}\n\n\t}\n\n\tfunction onMouseUp( event ) {\n\n\t\tif ( scope.enabled === false ) return;\n\n\t\thandleMouseUp( event );\n\n\t\tdocument.removeEventListener( 'mousemove', onMouseMove, false );\n\t\tdocument.removeEventListener( 'mouseup', onMouseUp, false );\n\n\t\tscope.dispatchEvent( endEvent );\n\n\t\tstate = STATE.NONE;\n\n\t}\n\n\tfunction onMouseWheel( event ) {\n\n\t\tif ( scope.enabled === false || scope.enableZoom === false || ( state !== STATE.NONE && state !== STATE.ROTATE ) ) return;\n\n\t\tevent.preventDefault();\n\t\tevent.stopPropagation();\n\n\t\tscope.dispatchEvent( startEvent );\n\n\t\thandleMouseWheel( event );\n\n\t\tscope.dispatchEvent( endEvent );\n\n\t}\n\n\tfunction onKeyDown( event ) {\n\n\t\tif ( scope.enabled === false || scope.enableKeys === false || scope.enablePan === false ) return;\n\n\t\thandleKeyDown( event );\n\n\t}\n\n\tfunction onTouchStart( event ) {\n\n\t\tif ( scope.enabled === false ) return;\n\n\t\tswitch ( event.touches.length ) {\n\n\t\t\tcase 1:\t// one-fingered touch: rotate\n\n\t\t\t\tif ( scope.enableRotate === false ) return;\n\n\t\t\t\thandleTouchStartRotate( event );\n\n\t\t\t\tstate = STATE.TOUCH_ROTATE;\n\n\t\t\t\tbreak;\n\n\t\t\tcase 2:\t// two-fingered touch: dolly\n\n\t\t\t\tif ( scope.enableZoom === false ) return;\n\n\t\t\t\thandleTouchStartDolly( event );\n\n\t\t\t\tstate = STATE.TOUCH_DOLLY;\n\n\t\t\t\tbreak;\n\n\t\t\tcase 3: // three-fingered touch: pan\n\n\t\t\t\tif ( scope.enablePan === false ) return;\n\n\t\t\t\thandleTouchStartPan( event );\n\n\t\t\t\tstate = STATE.TOUCH_PAN;\n\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\n\t\t\t\tstate = STATE.NONE;\n\n\t\t}\n\n\t\tif ( state !== STATE.NONE ) {\n\n\t\t\tscope.dispatchEvent( startEvent );\n\n\t\t}\n\n\t}\n\n\tfunction onTouchMove( event ) {\n\n\t\tif ( scope.enabled === false ) return;\n\n\t\tevent.preventDefault();\n\t\tevent.stopPropagation();\n\n\t\tswitch ( event.touches.length ) {\n\n\t\t\tcase 1: // one-fingered touch: rotate\n\n\t\t\t\tif ( scope.enableRotate === false ) return;\n\t\t\t\tif ( state !== STATE.TOUCH_ROTATE ) return; // is this needed?...\n\n\t\t\t\thandleTouchMoveRotate( event );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 2: // two-fingered touch: dolly\n\n\t\t\t\tif ( scope.enableZoom === false ) return;\n\t\t\t\tif ( state !== STATE.TOUCH_DOLLY ) return; // is this needed?...\n\n\t\t\t\thandleTouchMoveDolly( event );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 3: // three-fingered touch: pan\n\n\t\t\t\tif ( scope.enablePan === false ) return;\n\t\t\t\tif ( state !== STATE.TOUCH_PAN ) return; // is this needed?...\n\n\t\t\t\thandleTouchMovePan( event );\n\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\n\t\t\t\tstate = STATE.NONE;\n\n\t\t}\n\n\t}\n\n\tfunction onTouchEnd( event ) {\n\n\t\tif ( scope.enabled === false ) return;\n\n\t\thandleTouchEnd( event );\n\n\t\tscope.dispatchEvent( endEvent );\n\n\t\tstate = STATE.NONE;\n\n\t}\n\n\tfunction onContextMenu( event ) {\n\n\t\tif ( scope.enabled === false ) return;\n\n\t\tevent.preventDefault();\n\n\t}\n\n\t//\n\n\tscope.domElement.addEventListener( 'contextmenu', onContextMenu, false );\n\n\tscope.domElement.addEventListener( 'mousedown', onMouseDown, false );\n\tscope.domElement.addEventListener( 'wheel', onMouseWheel, false );\n\n\tscope.domElement.addEventListener( 'touchstart', onTouchStart, false );\n\tscope.domElement.addEventListener( 'touchend', onTouchEnd, false );\n\tscope.domElement.addEventListener( 'touchmove', onTouchMove, false );\n\n\twindow.addEventListener( 'keydown', onKeyDown, false );\n\n\t// force an update at start\n\n\tthis.update();\n\n};\n\nTHREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype );\nTHREE.OrbitControls.prototype.constructor = THREE.OrbitControls;\n\nObject.defineProperties( THREE.OrbitControls.prototype, {\n\n\tcenter: {\n\n\t\tget: function () {\n\n\t\t\tconsole.warn( 'THREE.OrbitControls: .center has been renamed to .target' );\n\t\t\treturn this.target;\n\n\t\t}\n\n\t},\n\n\t// backward compatibility\n\n\tnoZoom: {\n\n\t\tget: function () {\n\n\t\t\tconsole.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' );\n\t\t\treturn ! this.enableZoom;\n\n\t\t},\n\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' );\n\t\t\tthis.enableZoom = ! value;\n\n\t\t}\n\n\t},\n\n\tnoRotate: {\n\n\t\tget: function () {\n\n\t\t\tconsole.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' );\n\t\t\treturn ! this.enableRotate;\n\n\t\t},\n\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' );\n\t\t\tthis.enableRotate = ! value;\n\n\t\t}\n\n\t},\n\n\tnoPan: {\n\n\t\tget: function () {\n\n\t\t\tconsole.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' );\n\t\t\treturn ! this.enablePan;\n\n\t\t},\n\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' );\n\t\t\tthis.enablePan = ! value;\n\n\t\t}\n\n\t},\n\n\tnoKeys: {\n\n\t\tget: function () {\n\n\t\t\tconsole.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' );\n\t\t\treturn ! this.enableKeys;\n\n\t\t},\n\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' );\n\t\t\tthis.enableKeys = ! value;\n\n\t\t}\n\n\t},\n\n\tstaticMoving: {\n\n\t\tget: function () {\n\n\t\t\tconsole.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' );\n\t\t\treturn ! this.enableDamping;\n\n\t\t},\n\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' );\n\t\t\tthis.enableDamping = ! value;\n\n\t\t}\n\n\t},\n\n\tdynamicDampingFactor: {\n\n\t\tget: function () {\n\n\t\t\tconsole.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' );\n\t\t\treturn this.dampingFactor;\n\n\t\t},\n\n\t\tset: function ( value ) {\n\n\t\t\tconsole.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' );\n\t\t\tthis.dampingFactor = value;\n\n\t\t}\n\n\t}\n\n} );\n","(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"AFRAME\"] = factory();\n\telse\n\t\troot[\"AFRAME\"] = factory();\n})(self, () => {\nreturn /******/ (() => { // webpackBootstrap\n/******/ \tvar __webpack_modules__ = ({\n\n/***/ \"./node_modules/an-array/index.js\":\n/*!****************************************!*\\\n !*** ./node_modules/an-array/index.js ***!\n \\****************************************/\n/***/ ((module) => {\n\nvar str = Object.prototype.toString;\nmodule.exports = anArray;\nfunction anArray(arr) {\n return arr.BYTES_PER_ELEMENT && str.call(arr.buffer) === '[object ArrayBuffer]' || Array.isArray(arr);\n}\n\n/***/ }),\n\n/***/ \"./node_modules/as-number/index.js\":\n/*!*****************************************!*\\\n !*** ./node_modules/as-number/index.js ***!\n \\*****************************************/\n/***/ ((module) => {\n\nmodule.exports = function numtype(num, def) {\n return typeof num === 'number' ? num : typeof def === 'number' ? def : 0;\n};\n\n/***/ }),\n\n/***/ \"./node_modules/base64-js/index.js\":\n/*!*****************************************!*\\\n !*** ./node_modules/base64-js/index.js ***!\n \\*****************************************/\n/***/ ((__unused_webpack_module, exports) => {\n\n\"use strict\";\n\n\nexports.byteLength = byteLength;\nexports.toByteArray = toByteArray;\nexports.fromByteArray = fromByteArray;\nvar lookup = [];\nvar revLookup = [];\nvar Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array;\nvar code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\nfor (var i = 0, len = code.length; i < len; ++i) {\n lookup[i] = code[i];\n revLookup[code.charCodeAt(i)] = i;\n}\n\n// Support decoding URL-safe base64 strings, as Node.js does.\n// See: https://en.wikipedia.org/wiki/Base64#URL_applications\nrevLookup['-'.charCodeAt(0)] = 62;\nrevLookup['_'.charCodeAt(0)] = 63;\nfunction getLens(b64) {\n var len = b64.length;\n if (len % 4 > 0) {\n throw new Error('Invalid string. Length must be a multiple of 4');\n }\n\n // Trim off extra bytes after placeholder bytes are found\n // See: https://github.com/beatgammit/base64-js/issues/42\n var validLen = b64.indexOf('=');\n if (validLen === -1) validLen = len;\n var placeHoldersLen = validLen === len ? 0 : 4 - validLen % 4;\n return [validLen, placeHoldersLen];\n}\n\n// base64 is 4/3 + up to two characters of the original data\nfunction byteLength(b64) {\n var lens = getLens(b64);\n var validLen = lens[0];\n var placeHoldersLen = lens[1];\n return (validLen + placeHoldersLen) * 3 / 4 - placeHoldersLen;\n}\nfunction _byteLength(b64, validLen, placeHoldersLen) {\n return (validLen + placeHoldersLen) * 3 / 4 - placeHoldersLen;\n}\nfunction toByteArray(b64) {\n var tmp;\n var lens = getLens(b64);\n var validLen = lens[0];\n var placeHoldersLen = lens[1];\n var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen));\n var curByte = 0;\n\n // if there are placeholders, only get up to the last complete 4 chars\n var len = placeHoldersLen > 0 ? validLen - 4 : validLen;\n var i;\n for (i = 0; i < len; i += 4) {\n tmp = revLookup[b64.charCodeAt(i)] << 18 | revLookup[b64.charCodeAt(i + 1)] << 12 | revLookup[b64.charCodeAt(i + 2)] << 6 | revLookup[b64.charCodeAt(i + 3)];\n arr[curByte++] = tmp >> 16 & 0xFF;\n arr[curByte++] = tmp >> 8 & 0xFF;\n arr[curByte++] = tmp & 0xFF;\n }\n if (placeHoldersLen === 2) {\n tmp = revLookup[b64.charCodeAt(i)] << 2 | revLookup[b64.charCodeAt(i + 1)] >> 4;\n arr[curByte++] = tmp & 0xFF;\n }\n if (placeHoldersLen === 1) {\n tmp = revLookup[b64.charCodeAt(i)] << 10 | revLookup[b64.charCodeAt(i + 1)] << 4 | revLookup[b64.charCodeAt(i + 2)] >> 2;\n arr[curByte++] = tmp >> 8 & 0xFF;\n arr[curByte++] = tmp & 0xFF;\n }\n return arr;\n}\nfunction tripletToBase64(num) {\n return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F];\n}\nfunction encodeChunk(uint8, start, end) {\n var tmp;\n var output = [];\n for (var i = start; i < end; i += 3) {\n tmp = (uint8[i] << 16 & 0xFF0000) + (uint8[i + 1] << 8 & 0xFF00) + (uint8[i + 2] & 0xFF);\n output.push(tripletToBase64(tmp));\n }\n return output.join('');\n}\nfunction fromByteArray(uint8) {\n var tmp;\n var len = uint8.length;\n var extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes\n var parts = [];\n var maxChunkLength = 16383; // must be multiple of 3\n\n // go through the array every three bytes, we'll deal with trailing stuff later\n for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {\n parts.push(encodeChunk(uint8, i, i + maxChunkLength > len2 ? len2 : i + maxChunkLength));\n }\n\n // pad the end with zeros, but make sure to not forget the extra bytes\n if (extraBytes === 1) {\n tmp = uint8[len - 1];\n parts.push(lookup[tmp >> 2] + lookup[tmp << 4 & 0x3F] + '==');\n } else if (extraBytes === 2) {\n tmp = (uint8[len - 2] << 8) + uint8[len - 1];\n parts.push(lookup[tmp >> 10] + lookup[tmp >> 4 & 0x3F] + lookup[tmp << 2 & 0x3F] + '=');\n }\n return parts.join('');\n}\n\n/***/ }),\n\n/***/ \"./node_modules/buffer-equal/index.js\":\n/*!********************************************!*\\\n !*** ./node_modules/buffer-equal/index.js ***!\n \\********************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar Buffer = (__webpack_require__(/*! buffer */ \"./node_modules/buffer/index.js\").Buffer); // for use with browserify\n\nmodule.exports = function (a, b) {\n if (!Buffer.isBuffer(a)) return undefined;\n if (!Buffer.isBuffer(b)) return undefined;\n if (typeof a.equals === 'function') return a.equals(b);\n if (a.length !== b.length) return false;\n for (var i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n};\n\n/***/ }),\n\n/***/ \"./node_modules/buffer/index.js\":\n/*!**************************************!*\\\n !*** ./node_modules/buffer/index.js ***!\n \\**************************************/\n/***/ ((__unused_webpack_module, exports, __webpack_require__) => {\n\n\"use strict\";\n/*!\n * The buffer module from node.js, for the browser.\n *\n * @author Feross Aboukhadijeh \n * @license MIT\n */\n/* eslint-disable no-proto */\n\n\n\nconst base64 = __webpack_require__(/*! base64-js */ \"./node_modules/base64-js/index.js\");\nconst ieee754 = __webpack_require__(/*! ieee754 */ \"./node_modules/ieee754/index.js\");\nconst customInspectSymbol = typeof Symbol === 'function' && typeof Symbol['for'] === 'function' // eslint-disable-line dot-notation\n? Symbol['for']('nodejs.util.inspect.custom') // eslint-disable-line dot-notation\n: null;\nexports.Buffer = Buffer;\nexports.SlowBuffer = SlowBuffer;\nexports.INSPECT_MAX_BYTES = 50;\nconst K_MAX_LENGTH = 0x7fffffff;\nexports.kMaxLength = K_MAX_LENGTH;\n\n/**\n * If `Buffer.TYPED_ARRAY_SUPPORT`:\n * === true Use Uint8Array implementation (fastest)\n * === false Print warning and recommend using `buffer` v4.x which has an Object\n * implementation (most compatible, even IE6)\n *\n * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,\n * Opera 11.6+, iOS 4.2+.\n *\n * We report that the browser does not support typed arrays if the are not subclassable\n * using __proto__. Firefox 4-29 lacks support for adding new properties to `Uint8Array`\n * (See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438). IE 10 lacks support\n * for __proto__ and has a buggy typed array implementation.\n */\nBuffer.TYPED_ARRAY_SUPPORT = typedArraySupport();\nif (!Buffer.TYPED_ARRAY_SUPPORT && typeof console !== 'undefined' && typeof console.error === 'function') {\n console.error('This browser lacks typed array (Uint8Array) support which is required by ' + '`buffer` v5.x. Use `buffer` v4.x if you require old browser support.');\n}\nfunction typedArraySupport() {\n // Can typed array instances can be augmented?\n try {\n const arr = new Uint8Array(1);\n const proto = {\n foo: function () {\n return 42;\n }\n };\n Object.setPrototypeOf(proto, Uint8Array.prototype);\n Object.setPrototypeOf(arr, proto);\n return arr.foo() === 42;\n } catch (e) {\n return false;\n }\n}\nObject.defineProperty(Buffer.prototype, 'parent', {\n enumerable: true,\n get: function () {\n if (!Buffer.isBuffer(this)) return undefined;\n return this.buffer;\n }\n});\nObject.defineProperty(Buffer.prototype, 'offset', {\n enumerable: true,\n get: function () {\n if (!Buffer.isBuffer(this)) return undefined;\n return this.byteOffset;\n }\n});\nfunction createBuffer(length) {\n if (length > K_MAX_LENGTH) {\n throw new RangeError('The value \"' + length + '\" is invalid for option \"size\"');\n }\n // Return an augmented `Uint8Array` instance\n const buf = new Uint8Array(length);\n Object.setPrototypeOf(buf, Buffer.prototype);\n return buf;\n}\n\n/**\n * The Buffer constructor returns instances of `Uint8Array` that have their\n * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of\n * `Uint8Array`, so the returned instances will have all the node `Buffer` methods\n * and the `Uint8Array` methods. Square bracket notation works as expected -- it\n * returns a single octet.\n *\n * The `Uint8Array` prototype remains unmodified.\n */\n\nfunction Buffer(arg, encodingOrOffset, length) {\n // Common case.\n if (typeof arg === 'number') {\n if (typeof encodingOrOffset === 'string') {\n throw new TypeError('The \"string\" argument must be of type string. Received type number');\n }\n return allocUnsafe(arg);\n }\n return from(arg, encodingOrOffset, length);\n}\nBuffer.poolSize = 8192; // not used by this implementation\n\nfunction from(value, encodingOrOffset, length) {\n if (typeof value === 'string') {\n return fromString(value, encodingOrOffset);\n }\n if (ArrayBuffer.isView(value)) {\n return fromArrayView(value);\n }\n if (value == null) {\n throw new TypeError('The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' + 'or Array-like Object. Received type ' + typeof value);\n }\n if (isInstance(value, ArrayBuffer) || value && isInstance(value.buffer, ArrayBuffer)) {\n return fromArrayBuffer(value, encodingOrOffset, length);\n }\n if (typeof SharedArrayBuffer !== 'undefined' && (isInstance(value, SharedArrayBuffer) || value && isInstance(value.buffer, SharedArrayBuffer))) {\n return fromArrayBuffer(value, encodingOrOffset, length);\n }\n if (typeof value === 'number') {\n throw new TypeError('The \"value\" argument must not be of type number. Received type number');\n }\n const valueOf = value.valueOf && value.valueOf();\n if (valueOf != null && valueOf !== value) {\n return Buffer.from(valueOf, encodingOrOffset, length);\n }\n const b = fromObject(value);\n if (b) return b;\n if (typeof Symbol !== 'undefined' && Symbol.toPrimitive != null && typeof value[Symbol.toPrimitive] === 'function') {\n return Buffer.from(value[Symbol.toPrimitive]('string'), encodingOrOffset, length);\n }\n throw new TypeError('The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' + 'or Array-like Object. Received type ' + typeof value);\n}\n\n/**\n * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError\n * if value is a number.\n * Buffer.from(str[, encoding])\n * Buffer.from(array)\n * Buffer.from(buffer)\n * Buffer.from(arrayBuffer[, byteOffset[, length]])\n **/\nBuffer.from = function (value, encodingOrOffset, length) {\n return from(value, encodingOrOffset, length);\n};\n\n// Note: Change prototype *after* Buffer.from is defined to workaround Chrome bug:\n// https://github.com/feross/buffer/pull/148\nObject.setPrototypeOf(Buffer.prototype, Uint8Array.prototype);\nObject.setPrototypeOf(Buffer, Uint8Array);\nfunction assertSize(size) {\n if (typeof size !== 'number') {\n throw new TypeError('\"size\" argument must be of type number');\n } else if (size < 0) {\n throw new RangeError('The value \"' + size + '\" is invalid for option \"size\"');\n }\n}\nfunction alloc(size, fill, encoding) {\n assertSize(size);\n if (size <= 0) {\n return createBuffer(size);\n }\n if (fill !== undefined) {\n // Only pay attention to encoding if it's a string. This\n // prevents accidentally sending in a number that would\n // be interpreted as a start offset.\n return typeof encoding === 'string' ? createBuffer(size).fill(fill, encoding) : createBuffer(size).fill(fill);\n }\n return createBuffer(size);\n}\n\n/**\n * Creates a new filled Buffer instance.\n * alloc(size[, fill[, encoding]])\n **/\nBuffer.alloc = function (size, fill, encoding) {\n return alloc(size, fill, encoding);\n};\nfunction allocUnsafe(size) {\n assertSize(size);\n return createBuffer(size < 0 ? 0 : checked(size) | 0);\n}\n\n/**\n * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.\n * */\nBuffer.allocUnsafe = function (size) {\n return allocUnsafe(size);\n};\n/**\n * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.\n */\nBuffer.allocUnsafeSlow = function (size) {\n return allocUnsafe(size);\n};\nfunction fromString(string, encoding) {\n if (typeof encoding !== 'string' || encoding === '') {\n encoding = 'utf8';\n }\n if (!Buffer.isEncoding(encoding)) {\n throw new TypeError('Unknown encoding: ' + encoding);\n }\n const length = byteLength(string, encoding) | 0;\n let buf = createBuffer(length);\n const actual = buf.write(string, encoding);\n if (actual !== length) {\n // Writing a hex string, for example, that contains invalid characters will\n // cause everything after the first invalid character to be ignored. (e.g.\n // 'abxxcd' will be treated as 'ab')\n buf = buf.slice(0, actual);\n }\n return buf;\n}\nfunction fromArrayLike(array) {\n const length = array.length < 0 ? 0 : checked(array.length) | 0;\n const buf = createBuffer(length);\n for (let i = 0; i < length; i += 1) {\n buf[i] = array[i] & 255;\n }\n return buf;\n}\nfunction fromArrayView(arrayView) {\n if (isInstance(arrayView, Uint8Array)) {\n const copy = new Uint8Array(arrayView);\n return fromArrayBuffer(copy.buffer, copy.byteOffset, copy.byteLength);\n }\n return fromArrayLike(arrayView);\n}\nfunction fromArrayBuffer(array, byteOffset, length) {\n if (byteOffset < 0 || array.byteLength < byteOffset) {\n throw new RangeError('\"offset\" is outside of buffer bounds');\n }\n if (array.byteLength < byteOffset + (length || 0)) {\n throw new RangeError('\"length\" is outside of buffer bounds');\n }\n let buf;\n if (byteOffset === undefined && length === undefined) {\n buf = new Uint8Array(array);\n } else if (length === undefined) {\n buf = new Uint8Array(array, byteOffset);\n } else {\n buf = new Uint8Array(array, byteOffset, length);\n }\n\n // Return an augmented `Uint8Array` instance\n Object.setPrototypeOf(buf, Buffer.prototype);\n return buf;\n}\nfunction fromObject(obj) {\n if (Buffer.isBuffer(obj)) {\n const len = checked(obj.length) | 0;\n const buf = createBuffer(len);\n if (buf.length === 0) {\n return buf;\n }\n obj.copy(buf, 0, 0, len);\n return buf;\n }\n if (obj.length !== undefined) {\n if (typeof obj.length !== 'number' || numberIsNaN(obj.length)) {\n return createBuffer(0);\n }\n return fromArrayLike(obj);\n }\n if (obj.type === 'Buffer' && Array.isArray(obj.data)) {\n return fromArrayLike(obj.data);\n }\n}\nfunction checked(length) {\n // Note: cannot use `length < K_MAX_LENGTH` here because that fails when\n // length is NaN (which is otherwise coerced to zero.)\n if (length >= K_MAX_LENGTH) {\n throw new RangeError('Attempt to allocate Buffer larger than maximum ' + 'size: 0x' + K_MAX_LENGTH.toString(16) + ' bytes');\n }\n return length | 0;\n}\nfunction SlowBuffer(length) {\n if (+length != length) {\n // eslint-disable-line eqeqeq\n length = 0;\n }\n return Buffer.alloc(+length);\n}\nBuffer.isBuffer = function isBuffer(b) {\n return b != null && b._isBuffer === true && b !== Buffer.prototype; // so Buffer.isBuffer(Buffer.prototype) will be false\n};\n\nBuffer.compare = function compare(a, b) {\n if (isInstance(a, Uint8Array)) a = Buffer.from(a, a.offset, a.byteLength);\n if (isInstance(b, Uint8Array)) b = Buffer.from(b, b.offset, b.byteLength);\n if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {\n throw new TypeError('The \"buf1\", \"buf2\" arguments must be one of type Buffer or Uint8Array');\n }\n if (a === b) return 0;\n let x = a.length;\n let y = b.length;\n for (let i = 0, len = Math.min(x, y); i < len; ++i) {\n if (a[i] !== b[i]) {\n x = a[i];\n y = b[i];\n break;\n }\n }\n if (x < y) return -1;\n if (y < x) return 1;\n return 0;\n};\nBuffer.isEncoding = function isEncoding(encoding) {\n switch (String(encoding).toLowerCase()) {\n case 'hex':\n case 'utf8':\n case 'utf-8':\n case 'ascii':\n case 'latin1':\n case 'binary':\n case 'base64':\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return true;\n default:\n return false;\n }\n};\nBuffer.concat = function concat(list, length) {\n if (!Array.isArray(list)) {\n throw new TypeError('\"list\" argument must be an Array of Buffers');\n }\n if (list.length === 0) {\n return Buffer.alloc(0);\n }\n let i;\n if (length === undefined) {\n length = 0;\n for (i = 0; i < list.length; ++i) {\n length += list[i].length;\n }\n }\n const buffer = Buffer.allocUnsafe(length);\n let pos = 0;\n for (i = 0; i < list.length; ++i) {\n let buf = list[i];\n if (isInstance(buf, Uint8Array)) {\n if (pos + buf.length > buffer.length) {\n if (!Buffer.isBuffer(buf)) buf = Buffer.from(buf);\n buf.copy(buffer, pos);\n } else {\n Uint8Array.prototype.set.call(buffer, buf, pos);\n }\n } else if (!Buffer.isBuffer(buf)) {\n throw new TypeError('\"list\" argument must be an Array of Buffers');\n } else {\n buf.copy(buffer, pos);\n }\n pos += buf.length;\n }\n return buffer;\n};\nfunction byteLength(string, encoding) {\n if (Buffer.isBuffer(string)) {\n return string.length;\n }\n if (ArrayBuffer.isView(string) || isInstance(string, ArrayBuffer)) {\n return string.byteLength;\n }\n if (typeof string !== 'string') {\n throw new TypeError('The \"string\" argument must be one of type string, Buffer, or ArrayBuffer. ' + 'Received type ' + typeof string);\n }\n const len = string.length;\n const mustMatch = arguments.length > 2 && arguments[2] === true;\n if (!mustMatch && len === 0) return 0;\n\n // Use a for loop to avoid recursion\n let loweredCase = false;\n for (;;) {\n switch (encoding) {\n case 'ascii':\n case 'latin1':\n case 'binary':\n return len;\n case 'utf8':\n case 'utf-8':\n return utf8ToBytes(string).length;\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return len * 2;\n case 'hex':\n return len >>> 1;\n case 'base64':\n return base64ToBytes(string).length;\n default:\n if (loweredCase) {\n return mustMatch ? -1 : utf8ToBytes(string).length; // assume utf8\n }\n\n encoding = ('' + encoding).toLowerCase();\n loweredCase = true;\n }\n }\n}\nBuffer.byteLength = byteLength;\nfunction slowToString(encoding, start, end) {\n let loweredCase = false;\n\n // No need to verify that \"this.length <= MAX_UINT32\" since it's a read-only\n // property of a typed array.\n\n // This behaves neither like String nor Uint8Array in that we set start/end\n // to their upper/lower bounds if the value passed is out of range.\n // undefined is handled specially as per ECMA-262 6th Edition,\n // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.\n if (start === undefined || start < 0) {\n start = 0;\n }\n // Return early if start > this.length. Done here to prevent potential uint32\n // coercion fail below.\n if (start > this.length) {\n return '';\n }\n if (end === undefined || end > this.length) {\n end = this.length;\n }\n if (end <= 0) {\n return '';\n }\n\n // Force coercion to uint32. This will also coerce falsey/NaN values to 0.\n end >>>= 0;\n start >>>= 0;\n if (end <= start) {\n return '';\n }\n if (!encoding) encoding = 'utf8';\n while (true) {\n switch (encoding) {\n case 'hex':\n return hexSlice(this, start, end);\n case 'utf8':\n case 'utf-8':\n return utf8Slice(this, start, end);\n case 'ascii':\n return asciiSlice(this, start, end);\n case 'latin1':\n case 'binary':\n return latin1Slice(this, start, end);\n case 'base64':\n return base64Slice(this, start, end);\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return utf16leSlice(this, start, end);\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding);\n encoding = (encoding + '').toLowerCase();\n loweredCase = true;\n }\n }\n}\n\n// This property is used by `Buffer.isBuffer` (and the `is-buffer` npm package)\n// to detect a Buffer instance. It's not possible to use `instanceof Buffer`\n// reliably in a browserify context because there could be multiple different\n// copies of the 'buffer' package in use. This method works even for Buffer\n// instances that were created from another copy of the `buffer` package.\n// See: https://github.com/feross/buffer/issues/154\nBuffer.prototype._isBuffer = true;\nfunction swap(b, n, m) {\n const i = b[n];\n b[n] = b[m];\n b[m] = i;\n}\nBuffer.prototype.swap16 = function swap16() {\n const len = this.length;\n if (len % 2 !== 0) {\n throw new RangeError('Buffer size must be a multiple of 16-bits');\n }\n for (let i = 0; i < len; i += 2) {\n swap(this, i, i + 1);\n }\n return this;\n};\nBuffer.prototype.swap32 = function swap32() {\n const len = this.length;\n if (len % 4 !== 0) {\n throw new RangeError('Buffer size must be a multiple of 32-bits');\n }\n for (let i = 0; i < len; i += 4) {\n swap(this, i, i + 3);\n swap(this, i + 1, i + 2);\n }\n return this;\n};\nBuffer.prototype.swap64 = function swap64() {\n const len = this.length;\n if (len % 8 !== 0) {\n throw new RangeError('Buffer size must be a multiple of 64-bits');\n }\n for (let i = 0; i < len; i += 8) {\n swap(this, i, i + 7);\n swap(this, i + 1, i + 6);\n swap(this, i + 2, i + 5);\n swap(this, i + 3, i + 4);\n }\n return this;\n};\nBuffer.prototype.toString = function toString() {\n const length = this.length;\n if (length === 0) return '';\n if (arguments.length === 0) return utf8Slice(this, 0, length);\n return slowToString.apply(this, arguments);\n};\nBuffer.prototype.toLocaleString = Buffer.prototype.toString;\nBuffer.prototype.equals = function equals(b) {\n if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer');\n if (this === b) return true;\n return Buffer.compare(this, b) === 0;\n};\nBuffer.prototype.inspect = function inspect() {\n let str = '';\n const max = exports.INSPECT_MAX_BYTES;\n str = this.toString('hex', 0, max).replace(/(.{2})/g, '$1 ').trim();\n if (this.length > max) str += ' ... ';\n return '';\n};\nif (customInspectSymbol) {\n Buffer.prototype[customInspectSymbol] = Buffer.prototype.inspect;\n}\nBuffer.prototype.compare = function compare(target, start, end, thisStart, thisEnd) {\n if (isInstance(target, Uint8Array)) {\n target = Buffer.from(target, target.offset, target.byteLength);\n }\n if (!Buffer.isBuffer(target)) {\n throw new TypeError('The \"target\" argument must be one of type Buffer or Uint8Array. ' + 'Received type ' + typeof target);\n }\n if (start === undefined) {\n start = 0;\n }\n if (end === undefined) {\n end = target ? target.length : 0;\n }\n if (thisStart === undefined) {\n thisStart = 0;\n }\n if (thisEnd === undefined) {\n thisEnd = this.length;\n }\n if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {\n throw new RangeError('out of range index');\n }\n if (thisStart >= thisEnd && start >= end) {\n return 0;\n }\n if (thisStart >= thisEnd) {\n return -1;\n }\n if (start >= end) {\n return 1;\n }\n start >>>= 0;\n end >>>= 0;\n thisStart >>>= 0;\n thisEnd >>>= 0;\n if (this === target) return 0;\n let x = thisEnd - thisStart;\n let y = end - start;\n const len = Math.min(x, y);\n const thisCopy = this.slice(thisStart, thisEnd);\n const targetCopy = target.slice(start, end);\n for (let i = 0; i < len; ++i) {\n if (thisCopy[i] !== targetCopy[i]) {\n x = thisCopy[i];\n y = targetCopy[i];\n break;\n }\n }\n if (x < y) return -1;\n if (y < x) return 1;\n return 0;\n};\n\n// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`,\n// OR the last index of `val` in `buffer` at offset <= `byteOffset`.\n//\n// Arguments:\n// - buffer - a Buffer to search\n// - val - a string, Buffer, or number\n// - byteOffset - an index into `buffer`; will be clamped to an int32\n// - encoding - an optional encoding, relevant is val is a string\n// - dir - true for indexOf, false for lastIndexOf\nfunction bidirectionalIndexOf(buffer, val, byteOffset, encoding, dir) {\n // Empty buffer means no match\n if (buffer.length === 0) return -1;\n\n // Normalize byteOffset\n if (typeof byteOffset === 'string') {\n encoding = byteOffset;\n byteOffset = 0;\n } else if (byteOffset > 0x7fffffff) {\n byteOffset = 0x7fffffff;\n } else if (byteOffset < -0x80000000) {\n byteOffset = -0x80000000;\n }\n byteOffset = +byteOffset; // Coerce to Number.\n if (numberIsNaN(byteOffset)) {\n // byteOffset: it it's undefined, null, NaN, \"foo\", etc, search whole buffer\n byteOffset = dir ? 0 : buffer.length - 1;\n }\n\n // Normalize byteOffset: negative offsets start from the end of the buffer\n if (byteOffset < 0) byteOffset = buffer.length + byteOffset;\n if (byteOffset >= buffer.length) {\n if (dir) return -1;else byteOffset = buffer.length - 1;\n } else if (byteOffset < 0) {\n if (dir) byteOffset = 0;else return -1;\n }\n\n // Normalize val\n if (typeof val === 'string') {\n val = Buffer.from(val, encoding);\n }\n\n // Finally, search either indexOf (if dir is true) or lastIndexOf\n if (Buffer.isBuffer(val)) {\n // Special case: looking for empty string/buffer always fails\n if (val.length === 0) {\n return -1;\n }\n return arrayIndexOf(buffer, val, byteOffset, encoding, dir);\n } else if (typeof val === 'number') {\n val = val & 0xFF; // Search for a byte value [0-255]\n if (typeof Uint8Array.prototype.indexOf === 'function') {\n if (dir) {\n return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset);\n } else {\n return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset);\n }\n }\n return arrayIndexOf(buffer, [val], byteOffset, encoding, dir);\n }\n throw new TypeError('val must be string, number or Buffer');\n}\nfunction arrayIndexOf(arr, val, byteOffset, encoding, dir) {\n let indexSize = 1;\n let arrLength = arr.length;\n let valLength = val.length;\n if (encoding !== undefined) {\n encoding = String(encoding).toLowerCase();\n if (encoding === 'ucs2' || encoding === 'ucs-2' || encoding === 'utf16le' || encoding === 'utf-16le') {\n if (arr.length < 2 || val.length < 2) {\n return -1;\n }\n indexSize = 2;\n arrLength /= 2;\n valLength /= 2;\n byteOffset /= 2;\n }\n }\n function read(buf, i) {\n if (indexSize === 1) {\n return buf[i];\n } else {\n return buf.readUInt16BE(i * indexSize);\n }\n }\n let i;\n if (dir) {\n let foundIndex = -1;\n for (i = byteOffset; i < arrLength; i++) {\n if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {\n if (foundIndex === -1) foundIndex = i;\n if (i - foundIndex + 1 === valLength) return foundIndex * indexSize;\n } else {\n if (foundIndex !== -1) i -= i - foundIndex;\n foundIndex = -1;\n }\n }\n } else {\n if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength;\n for (i = byteOffset; i >= 0; i--) {\n let found = true;\n for (let j = 0; j < valLength; j++) {\n if (read(arr, i + j) !== read(val, j)) {\n found = false;\n break;\n }\n }\n if (found) return i;\n }\n }\n return -1;\n}\nBuffer.prototype.includes = function includes(val, byteOffset, encoding) {\n return this.indexOf(val, byteOffset, encoding) !== -1;\n};\nBuffer.prototype.indexOf = function indexOf(val, byteOffset, encoding) {\n return bidirectionalIndexOf(this, val, byteOffset, encoding, true);\n};\nBuffer.prototype.lastIndexOf = function lastIndexOf(val, byteOffset, encoding) {\n return bidirectionalIndexOf(this, val, byteOffset, encoding, false);\n};\nfunction hexWrite(buf, string, offset, length) {\n offset = Number(offset) || 0;\n const remaining = buf.length - offset;\n if (!length) {\n length = remaining;\n } else {\n length = Number(length);\n if (length > remaining) {\n length = remaining;\n }\n }\n const strLen = string.length;\n if (length > strLen / 2) {\n length = strLen / 2;\n }\n let i;\n for (i = 0; i < length; ++i) {\n const parsed = parseInt(string.substr(i * 2, 2), 16);\n if (numberIsNaN(parsed)) return i;\n buf[offset + i] = parsed;\n }\n return i;\n}\nfunction utf8Write(buf, string, offset, length) {\n return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length);\n}\nfunction asciiWrite(buf, string, offset, length) {\n return blitBuffer(asciiToBytes(string), buf, offset, length);\n}\nfunction base64Write(buf, string, offset, length) {\n return blitBuffer(base64ToBytes(string), buf, offset, length);\n}\nfunction ucs2Write(buf, string, offset, length) {\n return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length);\n}\nBuffer.prototype.write = function write(string, offset, length, encoding) {\n // Buffer#write(string)\n if (offset === undefined) {\n encoding = 'utf8';\n length = this.length;\n offset = 0;\n // Buffer#write(string, encoding)\n } else if (length === undefined && typeof offset === 'string') {\n encoding = offset;\n length = this.length;\n offset = 0;\n // Buffer#write(string, offset[, length][, encoding])\n } else if (isFinite(offset)) {\n offset = offset >>> 0;\n if (isFinite(length)) {\n length = length >>> 0;\n if (encoding === undefined) encoding = 'utf8';\n } else {\n encoding = length;\n length = undefined;\n }\n } else {\n throw new Error('Buffer.write(string, encoding, offset[, length]) is no longer supported');\n }\n const remaining = this.length - offset;\n if (length === undefined || length > remaining) length = remaining;\n if (string.length > 0 && (length < 0 || offset < 0) || offset > this.length) {\n throw new RangeError('Attempt to write outside buffer bounds');\n }\n if (!encoding) encoding = 'utf8';\n let loweredCase = false;\n for (;;) {\n switch (encoding) {\n case 'hex':\n return hexWrite(this, string, offset, length);\n case 'utf8':\n case 'utf-8':\n return utf8Write(this, string, offset, length);\n case 'ascii':\n case 'latin1':\n case 'binary':\n return asciiWrite(this, string, offset, length);\n case 'base64':\n // Warning: maxLength not taken into account in base64Write\n return base64Write(this, string, offset, length);\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return ucs2Write(this, string, offset, length);\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding);\n encoding = ('' + encoding).toLowerCase();\n loweredCase = true;\n }\n }\n};\nBuffer.prototype.toJSON = function toJSON() {\n return {\n type: 'Buffer',\n data: Array.prototype.slice.call(this._arr || this, 0)\n };\n};\nfunction base64Slice(buf, start, end) {\n if (start === 0 && end === buf.length) {\n return base64.fromByteArray(buf);\n } else {\n return base64.fromByteArray(buf.slice(start, end));\n }\n}\nfunction utf8Slice(buf, start, end) {\n end = Math.min(buf.length, end);\n const res = [];\n let i = start;\n while (i < end) {\n const firstByte = buf[i];\n let codePoint = null;\n let bytesPerSequence = firstByte > 0xEF ? 4 : firstByte > 0xDF ? 3 : firstByte > 0xBF ? 2 : 1;\n if (i + bytesPerSequence <= end) {\n let secondByte, thirdByte, fourthByte, tempCodePoint;\n switch (bytesPerSequence) {\n case 1:\n if (firstByte < 0x80) {\n codePoint = firstByte;\n }\n break;\n case 2:\n secondByte = buf[i + 1];\n if ((secondByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0x1F) << 0x6 | secondByte & 0x3F;\n if (tempCodePoint > 0x7F) {\n codePoint = tempCodePoint;\n }\n }\n break;\n case 3:\n secondByte = buf[i + 1];\n thirdByte = buf[i + 2];\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | thirdByte & 0x3F;\n if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {\n codePoint = tempCodePoint;\n }\n }\n break;\n case 4:\n secondByte = buf[i + 1];\n thirdByte = buf[i + 2];\n fourthByte = buf[i + 3];\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | fourthByte & 0x3F;\n if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {\n codePoint = tempCodePoint;\n }\n }\n }\n }\n if (codePoint === null) {\n // we did not generate a valid codePoint so insert a\n // replacement char (U+FFFD) and advance only 1 byte\n codePoint = 0xFFFD;\n bytesPerSequence = 1;\n } else if (codePoint > 0xFFFF) {\n // encode to utf16 (surrogate pair dance)\n codePoint -= 0x10000;\n res.push(codePoint >>> 10 & 0x3FF | 0xD800);\n codePoint = 0xDC00 | codePoint & 0x3FF;\n }\n res.push(codePoint);\n i += bytesPerSequence;\n }\n return decodeCodePointsArray(res);\n}\n\n// Based on http://stackoverflow.com/a/22747272/680742, the browser with\n// the lowest limit is Chrome, with 0x10000 args.\n// We go 1 magnitude less, for safety\nconst MAX_ARGUMENTS_LENGTH = 0x1000;\nfunction decodeCodePointsArray(codePoints) {\n const len = codePoints.length;\n if (len <= MAX_ARGUMENTS_LENGTH) {\n return String.fromCharCode.apply(String, codePoints); // avoid extra slice()\n }\n\n // Decode in chunks to avoid \"call stack size exceeded\".\n let res = '';\n let i = 0;\n while (i < len) {\n res += String.fromCharCode.apply(String, codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH));\n }\n return res;\n}\nfunction asciiSlice(buf, start, end) {\n let ret = '';\n end = Math.min(buf.length, end);\n for (let i = start; i < end; ++i) {\n ret += String.fromCharCode(buf[i] & 0x7F);\n }\n return ret;\n}\nfunction latin1Slice(buf, start, end) {\n let ret = '';\n end = Math.min(buf.length, end);\n for (let i = start; i < end; ++i) {\n ret += String.fromCharCode(buf[i]);\n }\n return ret;\n}\nfunction hexSlice(buf, start, end) {\n const len = buf.length;\n if (!start || start < 0) start = 0;\n if (!end || end < 0 || end > len) end = len;\n let out = '';\n for (let i = start; i < end; ++i) {\n out += hexSliceLookupTable[buf[i]];\n }\n return out;\n}\nfunction utf16leSlice(buf, start, end) {\n const bytes = buf.slice(start, end);\n let res = '';\n // If bytes.length is odd, the last 8 bits must be ignored (same as node.js)\n for (let i = 0; i < bytes.length - 1; i += 2) {\n res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256);\n }\n return res;\n}\nBuffer.prototype.slice = function slice(start, end) {\n const len = this.length;\n start = ~~start;\n end = end === undefined ? len : ~~end;\n if (start < 0) {\n start += len;\n if (start < 0) start = 0;\n } else if (start > len) {\n start = len;\n }\n if (end < 0) {\n end += len;\n if (end < 0) end = 0;\n } else if (end > len) {\n end = len;\n }\n if (end < start) end = start;\n const newBuf = this.subarray(start, end);\n // Return an augmented `Uint8Array` instance\n Object.setPrototypeOf(newBuf, Buffer.prototype);\n return newBuf;\n};\n\n/*\n * Need to make sure that buffer isn't trying to write out of bounds.\n */\nfunction checkOffset(offset, ext, length) {\n if (offset % 1 !== 0 || offset < 0) throw new RangeError('offset is not uint');\n if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length');\n}\nBuffer.prototype.readUintLE = Buffer.prototype.readUIntLE = function readUIntLE(offset, byteLength, noAssert) {\n offset = offset >>> 0;\n byteLength = byteLength >>> 0;\n if (!noAssert) checkOffset(offset, byteLength, this.length);\n let val = this[offset];\n let mul = 1;\n let i = 0;\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul;\n }\n return val;\n};\nBuffer.prototype.readUintBE = Buffer.prototype.readUIntBE = function readUIntBE(offset, byteLength, noAssert) {\n offset = offset >>> 0;\n byteLength = byteLength >>> 0;\n if (!noAssert) {\n checkOffset(offset, byteLength, this.length);\n }\n let val = this[offset + --byteLength];\n let mul = 1;\n while (byteLength > 0 && (mul *= 0x100)) {\n val += this[offset + --byteLength] * mul;\n }\n return val;\n};\nBuffer.prototype.readUint8 = Buffer.prototype.readUInt8 = function readUInt8(offset, noAssert) {\n offset = offset >>> 0;\n if (!noAssert) checkOffset(offset, 1, this.length);\n return this[offset];\n};\nBuffer.prototype.readUint16LE = Buffer.prototype.readUInt16LE = function readUInt16LE(offset, noAssert) {\n offset = offset >>> 0;\n if (!noAssert) checkOffset(offset, 2, this.length);\n return this[offset] | this[offset + 1] << 8;\n};\nBuffer.prototype.readUint16BE = Buffer.prototype.readUInt16BE = function readUInt16BE(offset, noAssert) {\n offset = offset >>> 0;\n if (!noAssert) checkOffset(offset, 2, this.length);\n return this[offset] << 8 | this[offset + 1];\n};\nBuffer.prototype.readUint32LE = Buffer.prototype.readUInt32LE = function readUInt32LE(offset, noAssert) {\n offset = offset >>> 0;\n if (!noAssert) checkOffset(offset, 4, this.length);\n return (this[offset] | this[offset + 1] << 8 | this[offset + 2] << 16) + this[offset + 3] * 0x1000000;\n};\nBuffer.prototype.readUint32BE = Buffer.prototype.readUInt32BE = function readUInt32BE(offset, noAssert) {\n offset = offset >>> 0;\n if (!noAssert) checkOffset(offset, 4, this.length);\n return this[offset] * 0x1000000 + (this[offset + 1] << 16 | this[offset + 2] << 8 | this[offset + 3]);\n};\nBuffer.prototype.readBigUInt64LE = defineBigIntMethod(function readBigUInt64LE(offset) {\n offset = offset >>> 0;\n validateNumber(offset, 'offset');\n const first = this[offset];\n const last = this[offset + 7];\n if (first === undefined || last === undefined) {\n boundsError(offset, this.length - 8);\n }\n const lo = first + this[++offset] * 2 ** 8 + this[++offset] * 2 ** 16 + this[++offset] * 2 ** 24;\n const hi = this[++offset] + this[++offset] * 2 ** 8 + this[++offset] * 2 ** 16 + last * 2 ** 24;\n return BigInt(lo) + (BigInt(hi) << BigInt(32));\n});\nBuffer.prototype.readBigUInt64BE = defineBigIntMethod(function readBigUInt64BE(offset) {\n offset = offset >>> 0;\n validateNumber(offset, 'offset');\n const first = this[offset];\n const last = this[offset + 7];\n if (first === undefined || last === undefined) {\n boundsError(offset, this.length - 8);\n }\n const hi = first * 2 ** 24 + this[++offset] * 2 ** 16 + this[++offset] * 2 ** 8 + this[++offset];\n const lo = this[++offset] * 2 ** 24 + this[++offset] * 2 ** 16 + this[++offset] * 2 ** 8 + last;\n return (BigInt(hi) << BigInt(32)) + BigInt(lo);\n});\nBuffer.prototype.readIntLE = function readIntLE(offset, byteLength, noAssert) {\n offset = offset >>> 0;\n byteLength = byteLength >>> 0;\n if (!noAssert) checkOffset(offset, byteLength, this.length);\n let val = this[offset];\n let mul = 1;\n let i = 0;\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul;\n }\n mul *= 0x80;\n if (val >= mul) val -= Math.pow(2, 8 * byteLength);\n return val;\n};\nBuffer.prototype.readIntBE = function readIntBE(offset, byteLength, noAssert) {\n offset = offset >>> 0;\n byteLength = byteLength >>> 0;\n if (!noAssert) checkOffset(offset, byteLength, this.length);\n let i = byteLength;\n let mul = 1;\n let val = this[offset + --i];\n while (i > 0 && (mul *= 0x100)) {\n val += this[offset + --i] * mul;\n }\n mul *= 0x80;\n if (val >= mul) val -= Math.pow(2, 8 * byteLength);\n return val;\n};\nBuffer.prototype.readInt8 = function readInt8(offset, noAssert) {\n offset = offset >>> 0;\n if (!noAssert) checkOffset(offset, 1, this.length);\n if (!(this[offset] & 0x80)) return this[offset];\n return (0xff - this[offset] + 1) * -1;\n};\nBuffer.prototype.readInt16LE = function readInt16LE(offset, noAssert) {\n offset = offset >>> 0;\n if (!noAssert) checkOffset(offset, 2, this.length);\n const val = this[offset] | this[offset + 1] << 8;\n return val & 0x8000 ? val | 0xFFFF0000 : val;\n};\nBuffer.prototype.readInt16BE = function readInt16BE(offset, noAssert) {\n offset = offset >>> 0;\n if (!noAssert) checkOffset(offset, 2, this.length);\n const val = this[offset + 1] | this[offset] << 8;\n return val & 0x8000 ? val | 0xFFFF0000 : val;\n};\nBuffer.prototype.readInt32LE = function readInt32LE(offset, noAssert) {\n offset = offset >>> 0;\n if (!noAssert) checkOffset(offset, 4, this.length);\n return this[offset] | this[offset + 1] << 8 | this[offset + 2] << 16 | this[offset + 3] << 24;\n};\nBuffer.prototype.readInt32BE = function readInt32BE(offset, noAssert) {\n offset = offset >>> 0;\n if (!noAssert) checkOffset(offset, 4, this.length);\n return this[offset] << 24 | this[offset + 1] << 16 | this[offset + 2] << 8 | this[offset + 3];\n};\nBuffer.prototype.readBigInt64LE = defineBigIntMethod(function readBigInt64LE(offset) {\n offset = offset >>> 0;\n validateNumber(offset, 'offset');\n const first = this[offset];\n const last = this[offset + 7];\n if (first === undefined || last === undefined) {\n boundsError(offset, this.length - 8);\n }\n const val = this[offset + 4] + this[offset + 5] * 2 ** 8 + this[offset + 6] * 2 ** 16 + (last << 24); // Overflow\n\n return (BigInt(val) << BigInt(32)) + BigInt(first + this[++offset] * 2 ** 8 + this[++offset] * 2 ** 16 + this[++offset] * 2 ** 24);\n});\nBuffer.prototype.readBigInt64BE = defineBigIntMethod(function readBigInt64BE(offset) {\n offset = offset >>> 0;\n validateNumber(offset, 'offset');\n const first = this[offset];\n const last = this[offset + 7];\n if (first === undefined || last === undefined) {\n boundsError(offset, this.length - 8);\n }\n const val = (first << 24) +\n // Overflow\n this[++offset] * 2 ** 16 + this[++offset] * 2 ** 8 + this[++offset];\n return (BigInt(val) << BigInt(32)) + BigInt(this[++offset] * 2 ** 24 + this[++offset] * 2 ** 16 + this[++offset] * 2 ** 8 + last);\n});\nBuffer.prototype.readFloatLE = function readFloatLE(offset, noAssert) {\n offset = offset >>> 0;\n if (!noAssert) checkOffset(offset, 4, this.length);\n return ieee754.read(this, offset, true, 23, 4);\n};\nBuffer.prototype.readFloatBE = function readFloatBE(offset, noAssert) {\n offset = offset >>> 0;\n if (!noAssert) checkOffset(offset, 4, this.length);\n return ieee754.read(this, offset, false, 23, 4);\n};\nBuffer.prototype.readDoubleLE = function readDoubleLE(offset, noAssert) {\n offset = offset >>> 0;\n if (!noAssert) checkOffset(offset, 8, this.length);\n return ieee754.read(this, offset, true, 52, 8);\n};\nBuffer.prototype.readDoubleBE = function readDoubleBE(offset, noAssert) {\n offset = offset >>> 0;\n if (!noAssert) checkOffset(offset, 8, this.length);\n return ieee754.read(this, offset, false, 52, 8);\n};\nfunction checkInt(buf, value, offset, ext, max, min) {\n if (!Buffer.isBuffer(buf)) throw new TypeError('\"buffer\" argument must be a Buffer instance');\n if (value > max || value < min) throw new RangeError('\"value\" argument is out of bounds');\n if (offset + ext > buf.length) throw new RangeError('Index out of range');\n}\nBuffer.prototype.writeUintLE = Buffer.prototype.writeUIntLE = function writeUIntLE(value, offset, byteLength, noAssert) {\n value = +value;\n offset = offset >>> 0;\n byteLength = byteLength >>> 0;\n if (!noAssert) {\n const maxBytes = Math.pow(2, 8 * byteLength) - 1;\n checkInt(this, value, offset, byteLength, maxBytes, 0);\n }\n let mul = 1;\n let i = 0;\n this[offset] = value & 0xFF;\n while (++i < byteLength && (mul *= 0x100)) {\n this[offset + i] = value / mul & 0xFF;\n }\n return offset + byteLength;\n};\nBuffer.prototype.writeUintBE = Buffer.prototype.writeUIntBE = function writeUIntBE(value, offset, byteLength, noAssert) {\n value = +value;\n offset = offset >>> 0;\n byteLength = byteLength >>> 0;\n if (!noAssert) {\n const maxBytes = Math.pow(2, 8 * byteLength) - 1;\n checkInt(this, value, offset, byteLength, maxBytes, 0);\n }\n let i = byteLength - 1;\n let mul = 1;\n this[offset + i] = value & 0xFF;\n while (--i >= 0 && (mul *= 0x100)) {\n this[offset + i] = value / mul & 0xFF;\n }\n return offset + byteLength;\n};\nBuffer.prototype.writeUint8 = Buffer.prototype.writeUInt8 = function writeUInt8(value, offset, noAssert) {\n value = +value;\n offset = offset >>> 0;\n if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0);\n this[offset] = value & 0xff;\n return offset + 1;\n};\nBuffer.prototype.writeUint16LE = Buffer.prototype.writeUInt16LE = function writeUInt16LE(value, offset, noAssert) {\n value = +value;\n offset = offset >>> 0;\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0);\n this[offset] = value & 0xff;\n this[offset + 1] = value >>> 8;\n return offset + 2;\n};\nBuffer.prototype.writeUint16BE = Buffer.prototype.writeUInt16BE = function writeUInt16BE(value, offset, noAssert) {\n value = +value;\n offset = offset >>> 0;\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0);\n this[offset] = value >>> 8;\n this[offset + 1] = value & 0xff;\n return offset + 2;\n};\nBuffer.prototype.writeUint32LE = Buffer.prototype.writeUInt32LE = function writeUInt32LE(value, offset, noAssert) {\n value = +value;\n offset = offset >>> 0;\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0);\n this[offset + 3] = value >>> 24;\n this[offset + 2] = value >>> 16;\n this[offset + 1] = value >>> 8;\n this[offset] = value & 0xff;\n return offset + 4;\n};\nBuffer.prototype.writeUint32BE = Buffer.prototype.writeUInt32BE = function writeUInt32BE(value, offset, noAssert) {\n value = +value;\n offset = offset >>> 0;\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0);\n this[offset] = value >>> 24;\n this[offset + 1] = value >>> 16;\n this[offset + 2] = value >>> 8;\n this[offset + 3] = value & 0xff;\n return offset + 4;\n};\nfunction wrtBigUInt64LE(buf, value, offset, min, max) {\n checkIntBI(value, min, max, buf, offset, 7);\n let lo = Number(value & BigInt(0xffffffff));\n buf[offset++] = lo;\n lo = lo >> 8;\n buf[offset++] = lo;\n lo = lo >> 8;\n buf[offset++] = lo;\n lo = lo >> 8;\n buf[offset++] = lo;\n let hi = Number(value >> BigInt(32) & BigInt(0xffffffff));\n buf[offset++] = hi;\n hi = hi >> 8;\n buf[offset++] = hi;\n hi = hi >> 8;\n buf[offset++] = hi;\n hi = hi >> 8;\n buf[offset++] = hi;\n return offset;\n}\nfunction wrtBigUInt64BE(buf, value, offset, min, max) {\n checkIntBI(value, min, max, buf, offset, 7);\n let lo = Number(value & BigInt(0xffffffff));\n buf[offset + 7] = lo;\n lo = lo >> 8;\n buf[offset + 6] = lo;\n lo = lo >> 8;\n buf[offset + 5] = lo;\n lo = lo >> 8;\n buf[offset + 4] = lo;\n let hi = Number(value >> BigInt(32) & BigInt(0xffffffff));\n buf[offset + 3] = hi;\n hi = hi >> 8;\n buf[offset + 2] = hi;\n hi = hi >> 8;\n buf[offset + 1] = hi;\n hi = hi >> 8;\n buf[offset] = hi;\n return offset + 8;\n}\nBuffer.prototype.writeBigUInt64LE = defineBigIntMethod(function writeBigUInt64LE(value, offset = 0) {\n return wrtBigUInt64LE(this, value, offset, BigInt(0), BigInt('0xffffffffffffffff'));\n});\nBuffer.prototype.writeBigUInt64BE = defineBigIntMethod(function writeBigUInt64BE(value, offset = 0) {\n return wrtBigUInt64BE(this, value, offset, BigInt(0), BigInt('0xffffffffffffffff'));\n});\nBuffer.prototype.writeIntLE = function writeIntLE(value, offset, byteLength, noAssert) {\n value = +value;\n offset = offset >>> 0;\n if (!noAssert) {\n const limit = Math.pow(2, 8 * byteLength - 1);\n checkInt(this, value, offset, byteLength, limit - 1, -limit);\n }\n let i = 0;\n let mul = 1;\n let sub = 0;\n this[offset] = value & 0xFF;\n while (++i < byteLength && (mul *= 0x100)) {\n if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {\n sub = 1;\n }\n this[offset + i] = (value / mul >> 0) - sub & 0xFF;\n }\n return offset + byteLength;\n};\nBuffer.prototype.writeIntBE = function writeIntBE(value, offset, byteLength, noAssert) {\n value = +value;\n offset = offset >>> 0;\n if (!noAssert) {\n const limit = Math.pow(2, 8 * byteLength - 1);\n checkInt(this, value, offset, byteLength, limit - 1, -limit);\n }\n let i = byteLength - 1;\n let mul = 1;\n let sub = 0;\n this[offset + i] = value & 0xFF;\n while (--i >= 0 && (mul *= 0x100)) {\n if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {\n sub = 1;\n }\n this[offset + i] = (value / mul >> 0) - sub & 0xFF;\n }\n return offset + byteLength;\n};\nBuffer.prototype.writeInt8 = function writeInt8(value, offset, noAssert) {\n value = +value;\n offset = offset >>> 0;\n if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80);\n if (value < 0) value = 0xff + value + 1;\n this[offset] = value & 0xff;\n return offset + 1;\n};\nBuffer.prototype.writeInt16LE = function writeInt16LE(value, offset, noAssert) {\n value = +value;\n offset = offset >>> 0;\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000);\n this[offset] = value & 0xff;\n this[offset + 1] = value >>> 8;\n return offset + 2;\n};\nBuffer.prototype.writeInt16BE = function writeInt16BE(value, offset, noAssert) {\n value = +value;\n offset = offset >>> 0;\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000);\n this[offset] = value >>> 8;\n this[offset + 1] = value & 0xff;\n return offset + 2;\n};\nBuffer.prototype.writeInt32LE = function writeInt32LE(value, offset, noAssert) {\n value = +value;\n offset = offset >>> 0;\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000);\n this[offset] = value & 0xff;\n this[offset + 1] = value >>> 8;\n this[offset + 2] = value >>> 16;\n this[offset + 3] = value >>> 24;\n return offset + 4;\n};\nBuffer.prototype.writeInt32BE = function writeInt32BE(value, offset, noAssert) {\n value = +value;\n offset = offset >>> 0;\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000);\n if (value < 0) value = 0xffffffff + value + 1;\n this[offset] = value >>> 24;\n this[offset + 1] = value >>> 16;\n this[offset + 2] = value >>> 8;\n this[offset + 3] = value & 0xff;\n return offset + 4;\n};\nBuffer.prototype.writeBigInt64LE = defineBigIntMethod(function writeBigInt64LE(value, offset = 0) {\n return wrtBigUInt64LE(this, value, offset, -BigInt('0x8000000000000000'), BigInt('0x7fffffffffffffff'));\n});\nBuffer.prototype.writeBigInt64BE = defineBigIntMethod(function writeBigInt64BE(value, offset = 0) {\n return wrtBigUInt64BE(this, value, offset, -BigInt('0x8000000000000000'), BigInt('0x7fffffffffffffff'));\n});\nfunction checkIEEE754(buf, value, offset, ext, max, min) {\n if (offset + ext > buf.length) throw new RangeError('Index out of range');\n if (offset < 0) throw new RangeError('Index out of range');\n}\nfunction writeFloat(buf, value, offset, littleEndian, noAssert) {\n value = +value;\n offset = offset >>> 0;\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38);\n }\n ieee754.write(buf, value, offset, littleEndian, 23, 4);\n return offset + 4;\n}\nBuffer.prototype.writeFloatLE = function writeFloatLE(value, offset, noAssert) {\n return writeFloat(this, value, offset, true, noAssert);\n};\nBuffer.prototype.writeFloatBE = function writeFloatBE(value, offset, noAssert) {\n return writeFloat(this, value, offset, false, noAssert);\n};\nfunction writeDouble(buf, value, offset, littleEndian, noAssert) {\n value = +value;\n offset = offset >>> 0;\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308);\n }\n ieee754.write(buf, value, offset, littleEndian, 52, 8);\n return offset + 8;\n}\nBuffer.prototype.writeDoubleLE = function writeDoubleLE(value, offset, noAssert) {\n return writeDouble(this, value, offset, true, noAssert);\n};\nBuffer.prototype.writeDoubleBE = function writeDoubleBE(value, offset, noAssert) {\n return writeDouble(this, value, offset, false, noAssert);\n};\n\n// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)\nBuffer.prototype.copy = function copy(target, targetStart, start, end) {\n if (!Buffer.isBuffer(target)) throw new TypeError('argument should be a Buffer');\n if (!start) start = 0;\n if (!end && end !== 0) end = this.length;\n if (targetStart >= target.length) targetStart = target.length;\n if (!targetStart) targetStart = 0;\n if (end > 0 && end < start) end = start;\n\n // Copy 0 bytes; we're done\n if (end === start) return 0;\n if (target.length === 0 || this.length === 0) return 0;\n\n // Fatal error conditions\n if (targetStart < 0) {\n throw new RangeError('targetStart out of bounds');\n }\n if (start < 0 || start >= this.length) throw new RangeError('Index out of range');\n if (end < 0) throw new RangeError('sourceEnd out of bounds');\n\n // Are we oob?\n if (end > this.length) end = this.length;\n if (target.length - targetStart < end - start) {\n end = target.length - targetStart + start;\n }\n const len = end - start;\n if (this === target && typeof Uint8Array.prototype.copyWithin === 'function') {\n // Use built-in when available, missing from IE11\n this.copyWithin(targetStart, start, end);\n } else {\n Uint8Array.prototype.set.call(target, this.subarray(start, end), targetStart);\n }\n return len;\n};\n\n// Usage:\n// buffer.fill(number[, offset[, end]])\n// buffer.fill(buffer[, offset[, end]])\n// buffer.fill(string[, offset[, end]][, encoding])\nBuffer.prototype.fill = function fill(val, start, end, encoding) {\n // Handle string cases:\n if (typeof val === 'string') {\n if (typeof start === 'string') {\n encoding = start;\n start = 0;\n end = this.length;\n } else if (typeof end === 'string') {\n encoding = end;\n end = this.length;\n }\n if (encoding !== undefined && typeof encoding !== 'string') {\n throw new TypeError('encoding must be a string');\n }\n if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {\n throw new TypeError('Unknown encoding: ' + encoding);\n }\n if (val.length === 1) {\n const code = val.charCodeAt(0);\n if (encoding === 'utf8' && code < 128 || encoding === 'latin1') {\n // Fast path: If `val` fits into a single byte, use that numeric value.\n val = code;\n }\n }\n } else if (typeof val === 'number') {\n val = val & 255;\n } else if (typeof val === 'boolean') {\n val = Number(val);\n }\n\n // Invalid ranges are not set to a default, so can range check early.\n if (start < 0 || this.length < start || this.length < end) {\n throw new RangeError('Out of range index');\n }\n if (end <= start) {\n return this;\n }\n start = start >>> 0;\n end = end === undefined ? this.length : end >>> 0;\n if (!val) val = 0;\n let i;\n if (typeof val === 'number') {\n for (i = start; i < end; ++i) {\n this[i] = val;\n }\n } else {\n const bytes = Buffer.isBuffer(val) ? val : Buffer.from(val, encoding);\n const len = bytes.length;\n if (len === 0) {\n throw new TypeError('The value \"' + val + '\" is invalid for argument \"value\"');\n }\n for (i = 0; i < end - start; ++i) {\n this[i + start] = bytes[i % len];\n }\n }\n return this;\n};\n\n// CUSTOM ERRORS\n// =============\n\n// Simplified versions from Node, changed for Buffer-only usage\nconst errors = {};\nfunction E(sym, getMessage, Base) {\n errors[sym] = class NodeError extends Base {\n constructor() {\n super();\n Object.defineProperty(this, 'message', {\n value: getMessage.apply(this, arguments),\n writable: true,\n configurable: true\n });\n\n // Add the error code to the name to include it in the stack trace.\n this.name = `${this.name} [${sym}]`;\n // Access the stack to generate the error message including the error code\n // from the name.\n this.stack; // eslint-disable-line no-unused-expressions\n // Reset the name to the actual name.\n delete this.name;\n }\n get code() {\n return sym;\n }\n set code(value) {\n Object.defineProperty(this, 'code', {\n configurable: true,\n enumerable: true,\n value,\n writable: true\n });\n }\n toString() {\n return `${this.name} [${sym}]: ${this.message}`;\n }\n };\n}\nE('ERR_BUFFER_OUT_OF_BOUNDS', function (name) {\n if (name) {\n return `${name} is outside of buffer bounds`;\n }\n return 'Attempt to access memory outside buffer bounds';\n}, RangeError);\nE('ERR_INVALID_ARG_TYPE', function (name, actual) {\n return `The \"${name}\" argument must be of type number. Received type ${typeof actual}`;\n}, TypeError);\nE('ERR_OUT_OF_RANGE', function (str, range, input) {\n let msg = `The value of \"${str}\" is out of range.`;\n let received = input;\n if (Number.isInteger(input) && Math.abs(input) > 2 ** 32) {\n received = addNumericalSeparator(String(input));\n } else if (typeof input === 'bigint') {\n received = String(input);\n if (input > BigInt(2) ** BigInt(32) || input < -(BigInt(2) ** BigInt(32))) {\n received = addNumericalSeparator(received);\n }\n received += 'n';\n }\n msg += ` It must be ${range}. Received ${received}`;\n return msg;\n}, RangeError);\nfunction addNumericalSeparator(val) {\n let res = '';\n let i = val.length;\n const start = val[0] === '-' ? 1 : 0;\n for (; i >= start + 4; i -= 3) {\n res = `_${val.slice(i - 3, i)}${res}`;\n }\n return `${val.slice(0, i)}${res}`;\n}\n\n// CHECK FUNCTIONS\n// ===============\n\nfunction checkBounds(buf, offset, byteLength) {\n validateNumber(offset, 'offset');\n if (buf[offset] === undefined || buf[offset + byteLength] === undefined) {\n boundsError(offset, buf.length - (byteLength + 1));\n }\n}\nfunction checkIntBI(value, min, max, buf, offset, byteLength) {\n if (value > max || value < min) {\n const n = typeof min === 'bigint' ? 'n' : '';\n let range;\n if (byteLength > 3) {\n if (min === 0 || min === BigInt(0)) {\n range = `>= 0${n} and < 2${n} ** ${(byteLength + 1) * 8}${n}`;\n } else {\n range = `>= -(2${n} ** ${(byteLength + 1) * 8 - 1}${n}) and < 2 ** ` + `${(byteLength + 1) * 8 - 1}${n}`;\n }\n } else {\n range = `>= ${min}${n} and <= ${max}${n}`;\n }\n throw new errors.ERR_OUT_OF_RANGE('value', range, value);\n }\n checkBounds(buf, offset, byteLength);\n}\nfunction validateNumber(value, name) {\n if (typeof value !== 'number') {\n throw new errors.ERR_INVALID_ARG_TYPE(name, 'number', value);\n }\n}\nfunction boundsError(value, length, type) {\n if (Math.floor(value) !== value) {\n validateNumber(value, type);\n throw new errors.ERR_OUT_OF_RANGE(type || 'offset', 'an integer', value);\n }\n if (length < 0) {\n throw new errors.ERR_BUFFER_OUT_OF_BOUNDS();\n }\n throw new errors.ERR_OUT_OF_RANGE(type || 'offset', `>= ${type ? 1 : 0} and <= ${length}`, value);\n}\n\n// HELPER FUNCTIONS\n// ================\n\nconst INVALID_BASE64_RE = /[^+/0-9A-Za-z-_]/g;\nfunction base64clean(str) {\n // Node takes equal signs as end of the Base64 encoding\n str = str.split('=')[0];\n // Node strips out invalid characters like \\n and \\t from the string, base64-js does not\n str = str.trim().replace(INVALID_BASE64_RE, '');\n // Node converts strings with length < 2 to ''\n if (str.length < 2) return '';\n // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not\n while (str.length % 4 !== 0) {\n str = str + '=';\n }\n return str;\n}\nfunction utf8ToBytes(string, units) {\n units = units || Infinity;\n let codePoint;\n const length = string.length;\n let leadSurrogate = null;\n const bytes = [];\n for (let i = 0; i < length; ++i) {\n codePoint = string.charCodeAt(i);\n\n // is surrogate component\n if (codePoint > 0xD7FF && codePoint < 0xE000) {\n // last char was a lead\n if (!leadSurrogate) {\n // no lead yet\n if (codePoint > 0xDBFF) {\n // unexpected trail\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);\n continue;\n } else if (i + 1 === length) {\n // unpaired lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);\n continue;\n }\n\n // valid lead\n leadSurrogate = codePoint;\n continue;\n }\n\n // 2 leads in a row\n if (codePoint < 0xDC00) {\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);\n leadSurrogate = codePoint;\n continue;\n }\n\n // valid surrogate pair\n codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000;\n } else if (leadSurrogate) {\n // valid bmp char, but last char was a lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);\n }\n leadSurrogate = null;\n\n // encode utf8\n if (codePoint < 0x80) {\n if ((units -= 1) < 0) break;\n bytes.push(codePoint);\n } else if (codePoint < 0x800) {\n if ((units -= 2) < 0) break;\n bytes.push(codePoint >> 0x6 | 0xC0, codePoint & 0x3F | 0x80);\n } else if (codePoint < 0x10000) {\n if ((units -= 3) < 0) break;\n bytes.push(codePoint >> 0xC | 0xE0, codePoint >> 0x6 & 0x3F | 0x80, codePoint & 0x3F | 0x80);\n } else if (codePoint < 0x110000) {\n if ((units -= 4) < 0) break;\n bytes.push(codePoint >> 0x12 | 0xF0, codePoint >> 0xC & 0x3F | 0x80, codePoint >> 0x6 & 0x3F | 0x80, codePoint & 0x3F | 0x80);\n } else {\n throw new Error('Invalid code point');\n }\n }\n return bytes;\n}\nfunction asciiToBytes(str) {\n const byteArray = [];\n for (let i = 0; i < str.length; ++i) {\n // Node's code seems to be doing this and not & 0x7F..\n byteArray.push(str.charCodeAt(i) & 0xFF);\n }\n return byteArray;\n}\nfunction utf16leToBytes(str, units) {\n let c, hi, lo;\n const byteArray = [];\n for (let i = 0; i < str.length; ++i) {\n if ((units -= 2) < 0) break;\n c = str.charCodeAt(i);\n hi = c >> 8;\n lo = c % 256;\n byteArray.push(lo);\n byteArray.push(hi);\n }\n return byteArray;\n}\nfunction base64ToBytes(str) {\n return base64.toByteArray(base64clean(str));\n}\nfunction blitBuffer(src, dst, offset, length) {\n let i;\n for (i = 0; i < length; ++i) {\n if (i + offset >= dst.length || i >= src.length) break;\n dst[i + offset] = src[i];\n }\n return i;\n}\n\n// ArrayBuffer or Uint8Array objects from other contexts (i.e. iframes) do not pass\n// the `instanceof` check but they should be treated as of that type.\n// See: https://github.com/feross/buffer/issues/166\nfunction isInstance(obj, type) {\n return obj instanceof type || obj != null && obj.constructor != null && obj.constructor.name != null && obj.constructor.name === type.name;\n}\nfunction numberIsNaN(obj) {\n // For IE11 support\n return obj !== obj; // eslint-disable-line no-self-compare\n}\n\n// Create lookup table for `toString('hex')`\n// See: https://github.com/feross/buffer/issues/219\nconst hexSliceLookupTable = function () {\n const alphabet = '0123456789abcdef';\n const table = new Array(256);\n for (let i = 0; i < 16; ++i) {\n const i16 = i * 16;\n for (let j = 0; j < 16; ++j) {\n table[i16 + j] = alphabet[i] + alphabet[j];\n }\n }\n return table;\n}();\n\n// Return not function with Error if BigInt not supported\nfunction defineBigIntMethod(fn) {\n return typeof BigInt === 'undefined' ? BufferBigIntNotDefined : fn;\n}\nfunction BufferBigIntNotDefined() {\n throw new Error('BigInt not supported');\n}\n\n/***/ }),\n\n/***/ \"./node_modules/css-loader/dist/runtime/api.js\":\n/*!*****************************************************!*\\\n !*** ./node_modules/css-loader/dist/runtime/api.js ***!\n \\*****************************************************/\n/***/ ((module) => {\n\n\"use strict\";\n\n\n/*\n MIT License http://www.opensource.org/licenses/mit-license.php\n Author Tobias Koppers @sokra\n*/\nmodule.exports = function (cssWithMappingToString) {\n var list = [];\n\n // return the list of modules as css string\n list.toString = function toString() {\n return this.map(function (item) {\n var content = \"\";\n var needLayer = typeof item[5] !== \"undefined\";\n if (item[4]) {\n content += \"@supports (\".concat(item[4], \") {\");\n }\n if (item[2]) {\n content += \"@media \".concat(item[2], \" {\");\n }\n if (needLayer) {\n content += \"@layer\".concat(item[5].length > 0 ? \" \".concat(item[5]) : \"\", \" {\");\n }\n content += cssWithMappingToString(item);\n if (needLayer) {\n content += \"}\";\n }\n if (item[2]) {\n content += \"}\";\n }\n if (item[4]) {\n content += \"}\";\n }\n return content;\n }).join(\"\");\n };\n\n // import a list of modules into the list\n list.i = function i(modules, media, dedupe, supports, layer) {\n if (typeof modules === \"string\") {\n modules = [[null, modules, undefined]];\n }\n var alreadyImportedModules = {};\n if (dedupe) {\n for (var k = 0; k < this.length; k++) {\n var id = this[k][0];\n if (id != null) {\n alreadyImportedModules[id] = true;\n }\n }\n }\n for (var _k = 0; _k < modules.length; _k++) {\n var item = [].concat(modules[_k]);\n if (dedupe && alreadyImportedModules[item[0]]) {\n continue;\n }\n if (typeof layer !== \"undefined\") {\n if (typeof item[5] === \"undefined\") {\n item[5] = layer;\n } else {\n item[1] = \"@layer\".concat(item[5].length > 0 ? \" \".concat(item[5]) : \"\", \" {\").concat(item[1], \"}\");\n item[5] = layer;\n }\n }\n if (media) {\n if (!item[2]) {\n item[2] = media;\n } else {\n item[1] = \"@media \".concat(item[2], \" {\").concat(item[1], \"}\");\n item[2] = media;\n }\n }\n if (supports) {\n if (!item[4]) {\n item[4] = \"\".concat(supports);\n } else {\n item[1] = \"@supports (\".concat(item[4], \") {\").concat(item[1], \"}\");\n item[4] = supports;\n }\n }\n list.push(item);\n }\n };\n return list;\n};\n\n/***/ }),\n\n/***/ \"./node_modules/css-loader/dist/runtime/getUrl.js\":\n/*!********************************************************!*\\\n !*** ./node_modules/css-loader/dist/runtime/getUrl.js ***!\n \\********************************************************/\n/***/ ((module) => {\n\n\"use strict\";\n\n\nmodule.exports = function (url, options) {\n if (!options) {\n options = {};\n }\n if (!url) {\n return url;\n }\n url = String(url.__esModule ? url.default : url);\n\n // If url is already wrapped in quotes, remove them\n if (/^['\"].*['\"]$/.test(url)) {\n url = url.slice(1, -1);\n }\n if (options.hash) {\n url += options.hash;\n }\n\n // Should url be wrapped?\n // See https://drafts.csswg.org/css-values-3/#urls\n if (/[\"'() \\t\\n]|(%20)/.test(url) || options.needQuotes) {\n return \"\\\"\".concat(url.replace(/\"/g, '\\\\\"').replace(/\\n/g, \"\\\\n\"), \"\\\"\");\n }\n return url;\n};\n\n/***/ }),\n\n/***/ \"./node_modules/css-loader/dist/runtime/sourceMaps.js\":\n/*!************************************************************!*\\\n !*** ./node_modules/css-loader/dist/runtime/sourceMaps.js ***!\n \\************************************************************/\n/***/ ((module) => {\n\n\"use strict\";\n\n\nmodule.exports = function (item) {\n var content = item[1];\n var cssMapping = item[3];\n if (!cssMapping) {\n return content;\n }\n if (typeof btoa === \"function\") {\n var base64 = btoa(unescape(encodeURIComponent(JSON.stringify(cssMapping))));\n var data = \"sourceMappingURL=data:application/json;charset=utf-8;base64,\".concat(base64);\n var sourceMapping = \"/*# \".concat(data, \" */\");\n return [content].concat([sourceMapping]).join(\"\\n\");\n }\n return [content].join(\"\\n\");\n};\n\n/***/ }),\n\n/***/ \"./node_modules/debug/src/browser.js\":\n/*!*******************************************!*\\\n !*** ./node_modules/debug/src/browser.js ***!\n \\*******************************************/\n/***/ ((module, exports, __webpack_require__) => {\n\n/* eslint-env browser */\n\n/**\n * This is the web browser implementation of `debug()`.\n */\n\nexports.formatArgs = formatArgs;\nexports.save = save;\nexports.load = load;\nexports.useColors = useColors;\nexports.storage = localstorage();\nexports.destroy = (() => {\n let warned = false;\n return () => {\n if (!warned) {\n warned = true;\n console.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');\n }\n };\n})();\n\n/**\n * Colors.\n */\n\nexports.colors = ['#0000CC', '#0000FF', '#0033CC', '#0033FF', '#0066CC', '#0066FF', '#0099CC', '#0099FF', '#00CC00', '#00CC33', '#00CC66', '#00CC99', '#00CCCC', '#00CCFF', '#3300CC', '#3300FF', '#3333CC', '#3333FF', '#3366CC', '#3366FF', '#3399CC', '#3399FF', '#33CC00', '#33CC33', '#33CC66', '#33CC99', '#33CCCC', '#33CCFF', '#6600CC', '#6600FF', '#6633CC', '#6633FF', '#66CC00', '#66CC33', '#9900CC', '#9900FF', '#9933CC', '#9933FF', '#99CC00', '#99CC33', '#CC0000', '#CC0033', '#CC0066', '#CC0099', '#CC00CC', '#CC00FF', '#CC3300', '#CC3333', '#CC3366', '#CC3399', '#CC33CC', '#CC33FF', '#CC6600', '#CC6633', '#CC9900', '#CC9933', '#CCCC00', '#CCCC33', '#FF0000', '#FF0033', '#FF0066', '#FF0099', '#FF00CC', '#FF00FF', '#FF3300', '#FF3333', '#FF3366', '#FF3399', '#FF33CC', '#FF33FF', '#FF6600', '#FF6633', '#FF9900', '#FF9933', '#FFCC00', '#FFCC33'];\n\n/**\n * Currently only WebKit-based Web Inspectors, Firefox >= v31,\n * and the Firebug extension (any Firefox version) are known\n * to support \"%c\" CSS customizations.\n *\n * TODO: add a `localStorage` variable to explicitly enable/disable colors\n */\n\n// eslint-disable-next-line complexity\nfunction useColors() {\n // NB: In an Electron preload script, document will be defined but not fully\n // initialized. Since we know we're in Chrome, we'll just detect this case\n // explicitly\n if (typeof window !== 'undefined' && window.process && (window.process.type === 'renderer' || window.process.__nwjs)) {\n return true;\n }\n\n // Internet Explorer and Edge do not support colors.\n if (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\\/(\\d+)/)) {\n return false;\n }\n\n // Is webkit? http://stackoverflow.com/a/16459606/376773\n // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632\n return typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance ||\n // Is firebug? http://stackoverflow.com/a/398120/376773\n typeof window !== 'undefined' && window.console && (window.console.firebug || window.console.exception && window.console.table) ||\n // Is firefox >= v31?\n // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages\n typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\\/(\\d+)/) && parseInt(RegExp.$1, 10) >= 31 ||\n // Double check webkit in userAgent just in case we are in a worker\n typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\\/(\\d+)/);\n}\n\n/**\n * Colorize log arguments if enabled.\n *\n * @api public\n */\n\nfunction formatArgs(args) {\n args[0] = (this.useColors ? '%c' : '') + this.namespace + (this.useColors ? ' %c' : ' ') + args[0] + (this.useColors ? '%c ' : ' ') + '+' + module.exports.humanize(this.diff);\n if (!this.useColors) {\n return;\n }\n const c = 'color: ' + this.color;\n args.splice(1, 0, c, 'color: inherit');\n\n // The final \"%c\" is somewhat tricky, because there could be other\n // arguments passed either before or after the %c, so we need to\n // figure out the correct index to insert the CSS into\n let index = 0;\n let lastC = 0;\n args[0].replace(/%[a-zA-Z%]/g, match => {\n if (match === '%%') {\n return;\n }\n index++;\n if (match === '%c') {\n // We only are interested in the *last* %c\n // (the user may have provided their own)\n lastC = index;\n }\n });\n args.splice(lastC, 0, c);\n}\n\n/**\n * Invokes `console.debug()` when available.\n * No-op when `console.debug` is not a \"function\".\n * If `console.debug` is not available, falls back\n * to `console.log`.\n *\n * @api public\n */\nexports.log = console.debug || console.log || (() => {});\n\n/**\n * Save `namespaces`.\n *\n * @param {String} namespaces\n * @api private\n */\nfunction save(namespaces) {\n try {\n if (namespaces) {\n exports.storage.setItem('debug', namespaces);\n } else {\n exports.storage.removeItem('debug');\n }\n } catch (error) {\n // Swallow\n // XXX (@Qix-) should we be logging these?\n }\n}\n\n/**\n * Load `namespaces`.\n *\n * @return {String} returns the previously persisted debug modes\n * @api private\n */\nfunction load() {\n let r;\n try {\n r = exports.storage.getItem('debug');\n } catch (error) {\n // Swallow\n // XXX (@Qix-) should we be logging these?\n }\n\n // If debug isn't set in LS, and we're in Electron, try to load $DEBUG\n if (!r && typeof process !== 'undefined' && 'env' in process) {\n r = process.env.DEBUG;\n }\n return r;\n}\n\n/**\n * Localstorage attempts to return the localstorage.\n *\n * This is necessary because safari throws\n * when a user disables cookies/localstorage\n * and you attempt to access it.\n *\n * @return {LocalStorage}\n * @api private\n */\n\nfunction localstorage() {\n try {\n // TVMLKit (Apple TV JS Runtime) does not have a window object, just localStorage in the global context\n // The Browser also has localStorage in the global context.\n return localStorage;\n } catch (error) {\n // Swallow\n // XXX (@Qix-) should we be logging these?\n }\n}\nmodule.exports = __webpack_require__(/*! ./common */ \"./node_modules/debug/src/common.js\")(exports);\nconst {\n formatters\n} = module.exports;\n\n/**\n * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.\n */\n\nformatters.j = function (v) {\n try {\n return JSON.stringify(v);\n } catch (error) {\n return '[UnexpectedJSONParseError]: ' + error.message;\n }\n};\n\n/***/ }),\n\n/***/ \"./node_modules/debug/src/common.js\":\n/*!******************************************!*\\\n !*** ./node_modules/debug/src/common.js ***!\n \\******************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\n/**\n * This is the common logic for both the Node.js and web browser\n * implementations of `debug()`.\n */\n\nfunction setup(env) {\n createDebug.debug = createDebug;\n createDebug.default = createDebug;\n createDebug.coerce = coerce;\n createDebug.disable = disable;\n createDebug.enable = enable;\n createDebug.enabled = enabled;\n createDebug.humanize = __webpack_require__(/*! ms */ \"./node_modules/ms/index.js\");\n createDebug.destroy = destroy;\n Object.keys(env).forEach(key => {\n createDebug[key] = env[key];\n });\n\n /**\n * The currently active debug mode names, and names to skip.\n */\n\n createDebug.names = [];\n createDebug.skips = [];\n\n /**\n * Map of special \"%n\" handling functions, for the debug \"format\" argument.\n *\n * Valid key names are a single, lower or upper-case letter, i.e. \"n\" and \"N\".\n */\n createDebug.formatters = {};\n\n /**\n * Selects a color for a debug namespace\n * @param {String} namespace The namespace string for the debug instance to be colored\n * @return {Number|String} An ANSI color code for the given namespace\n * @api private\n */\n function selectColor(namespace) {\n let hash = 0;\n for (let i = 0; i < namespace.length; i++) {\n hash = (hash << 5) - hash + namespace.charCodeAt(i);\n hash |= 0; // Convert to 32bit integer\n }\n\n return createDebug.colors[Math.abs(hash) % createDebug.colors.length];\n }\n createDebug.selectColor = selectColor;\n\n /**\n * Create a debugger with the given `namespace`.\n *\n * @param {String} namespace\n * @return {Function}\n * @api public\n */\n function createDebug(namespace) {\n let prevTime;\n let enableOverride = null;\n let namespacesCache;\n let enabledCache;\n function debug(...args) {\n // Disabled?\n if (!debug.enabled) {\n return;\n }\n const self = debug;\n\n // Set `diff` timestamp\n const curr = Number(new Date());\n const ms = curr - (prevTime || curr);\n self.diff = ms;\n self.prev = prevTime;\n self.curr = curr;\n prevTime = curr;\n args[0] = createDebug.coerce(args[0]);\n if (typeof args[0] !== 'string') {\n // Anything else let's inspect with %O\n args.unshift('%O');\n }\n\n // Apply any `formatters` transformations\n let index = 0;\n args[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format) => {\n // If we encounter an escaped % then don't increase the array index\n if (match === '%%') {\n return '%';\n }\n index++;\n const formatter = createDebug.formatters[format];\n if (typeof formatter === 'function') {\n const val = args[index];\n match = formatter.call(self, val);\n\n // Now we need to remove `args[index]` since it's inlined in the `format`\n args.splice(index, 1);\n index--;\n }\n return match;\n });\n\n // Apply env-specific formatting (colors, etc.)\n createDebug.formatArgs.call(self, args);\n const logFn = self.log || createDebug.log;\n logFn.apply(self, args);\n }\n debug.namespace = namespace;\n debug.useColors = createDebug.useColors();\n debug.color = createDebug.selectColor(namespace);\n debug.extend = extend;\n debug.destroy = createDebug.destroy; // XXX Temporary. Will be removed in the next major release.\n\n Object.defineProperty(debug, 'enabled', {\n enumerable: true,\n configurable: false,\n get: () => {\n if (enableOverride !== null) {\n return enableOverride;\n }\n if (namespacesCache !== createDebug.namespaces) {\n namespacesCache = createDebug.namespaces;\n enabledCache = createDebug.enabled(namespace);\n }\n return enabledCache;\n },\n set: v => {\n enableOverride = v;\n }\n });\n\n // Env-specific initialization logic for debug instances\n if (typeof createDebug.init === 'function') {\n createDebug.init(debug);\n }\n return debug;\n }\n function extend(namespace, delimiter) {\n const newDebug = createDebug(this.namespace + (typeof delimiter === 'undefined' ? ':' : delimiter) + namespace);\n newDebug.log = this.log;\n return newDebug;\n }\n\n /**\n * Enables a debug mode by namespaces. This can include modes\n * separated by a colon and wildcards.\n *\n * @param {String} namespaces\n * @api public\n */\n function enable(namespaces) {\n createDebug.save(namespaces);\n createDebug.namespaces = namespaces;\n createDebug.names = [];\n createDebug.skips = [];\n let i;\n const split = (typeof namespaces === 'string' ? namespaces : '').split(/[\\s,]+/);\n const len = split.length;\n for (i = 0; i < len; i++) {\n if (!split[i]) {\n // ignore empty strings\n continue;\n }\n namespaces = split[i].replace(/\\*/g, '.*?');\n if (namespaces[0] === '-') {\n createDebug.skips.push(new RegExp('^' + namespaces.slice(1) + '$'));\n } else {\n createDebug.names.push(new RegExp('^' + namespaces + '$'));\n }\n }\n }\n\n /**\n * Disable debug output.\n *\n * @return {String} namespaces\n * @api public\n */\n function disable() {\n const namespaces = [...createDebug.names.map(toNamespace), ...createDebug.skips.map(toNamespace).map(namespace => '-' + namespace)].join(',');\n createDebug.enable('');\n return namespaces;\n }\n\n /**\n * Returns true if the given mode name is enabled, false otherwise.\n *\n * @param {String} name\n * @return {Boolean}\n * @api public\n */\n function enabled(name) {\n if (name[name.length - 1] === '*') {\n return true;\n }\n let i;\n let len;\n for (i = 0, len = createDebug.skips.length; i < len; i++) {\n if (createDebug.skips[i].test(name)) {\n return false;\n }\n }\n for (i = 0, len = createDebug.names.length; i < len; i++) {\n if (createDebug.names[i].test(name)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Convert regexp to namespace\n *\n * @param {RegExp} regxep\n * @return {String} namespace\n * @api private\n */\n function toNamespace(regexp) {\n return regexp.toString().substring(2, regexp.toString().length - 2).replace(/\\.\\*\\?$/, '*');\n }\n\n /**\n * Coerce `val`.\n *\n * @param {Mixed} val\n * @return {Mixed}\n * @api private\n */\n function coerce(val) {\n if (val instanceof Error) {\n return val.stack || val.message;\n }\n return val;\n }\n\n /**\n * XXX DO NOT USE. This is a temporary stub function.\n * XXX It WILL be removed in the next major release.\n */\n function destroy() {\n console.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');\n }\n createDebug.enable(createDebug.load());\n return createDebug;\n}\nmodule.exports = setup;\n\n/***/ }),\n\n/***/ \"./node_modules/deep-assign/index.js\":\n/*!*******************************************!*\\\n !*** ./node_modules/deep-assign/index.js ***!\n \\*******************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\n\"use strict\";\n\n\nvar isObj = __webpack_require__(/*! is-obj */ \"./node_modules/is-obj/index.js\");\nvar hasOwnProperty = Object.prototype.hasOwnProperty;\nvar propIsEnumerable = Object.prototype.propertyIsEnumerable;\nfunction toObject(val) {\n if (val === null || val === undefined) {\n throw new TypeError('Sources cannot be null or undefined');\n }\n return Object(val);\n}\nfunction assignKey(to, from, key) {\n var val = from[key];\n if (val === undefined || val === null) {\n return;\n }\n if (hasOwnProperty.call(to, key)) {\n if (to[key] === undefined || to[key] === null) {\n throw new TypeError('Cannot convert undefined or null to object (' + key + ')');\n }\n }\n if (!hasOwnProperty.call(to, key) || !isObj(val)) {\n to[key] = val;\n } else {\n to[key] = assign(Object(to[key]), from[key]);\n }\n}\nfunction assign(to, from) {\n if (to === from) {\n return to;\n }\n from = Object(from);\n for (var key in from) {\n if (hasOwnProperty.call(from, key)) {\n assignKey(to, from, key);\n }\n }\n if (Object.getOwnPropertySymbols) {\n var symbols = Object.getOwnPropertySymbols(from);\n for (var i = 0; i < symbols.length; i++) {\n if (propIsEnumerable.call(from, symbols[i])) {\n assignKey(to, from, symbols[i]);\n }\n }\n }\n return to;\n}\nmodule.exports = function deepAssign(target) {\n target = toObject(target);\n for (var s = 1; s < arguments.length; s++) {\n assign(target, arguments[s]);\n }\n return target;\n};\n\n/***/ }),\n\n/***/ \"./node_modules/dtype/index.js\":\n/*!*************************************!*\\\n !*** ./node_modules/dtype/index.js ***!\n \\*************************************/\n/***/ ((module) => {\n\nmodule.exports = function (dtype) {\n switch (dtype) {\n case 'int8':\n return Int8Array;\n case 'int16':\n return Int16Array;\n case 'int32':\n return Int32Array;\n case 'uint8':\n return Uint8Array;\n case 'uint16':\n return Uint16Array;\n case 'uint32':\n return Uint32Array;\n case 'float32':\n return Float32Array;\n case 'float64':\n return Float64Array;\n case 'array':\n return Array;\n case 'uint8_clamped':\n return Uint8ClampedArray;\n }\n};\n\n/***/ }),\n\n/***/ \"./node_modules/global/window.js\":\n/*!***************************************!*\\\n !*** ./node_modules/global/window.js ***!\n \\***************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar win;\nif (typeof window !== \"undefined\") {\n win = window;\n} else if (typeof __webpack_require__.g !== \"undefined\") {\n win = __webpack_require__.g;\n} else if (typeof self !== \"undefined\") {\n win = self;\n} else {\n win = {};\n}\nmodule.exports = win;\n\n/***/ }),\n\n/***/ \"./node_modules/ieee754/index.js\":\n/*!***************************************!*\\\n !*** ./node_modules/ieee754/index.js ***!\n \\***************************************/\n/***/ ((__unused_webpack_module, exports) => {\n\n/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh */\nexports.read = function (buffer, offset, isLE, mLen, nBytes) {\n var e, m;\n var eLen = nBytes * 8 - mLen - 1;\n var eMax = (1 << eLen) - 1;\n var eBias = eMax >> 1;\n var nBits = -7;\n var i = isLE ? nBytes - 1 : 0;\n var d = isLE ? -1 : 1;\n var s = buffer[offset + i];\n i += d;\n e = s & (1 << -nBits) - 1;\n s >>= -nBits;\n nBits += eLen;\n for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n m = e & (1 << -nBits) - 1;\n e >>= -nBits;\n nBits += mLen;\n for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n if (e === 0) {\n e = 1 - eBias;\n } else if (e === eMax) {\n return m ? NaN : (s ? -1 : 1) * Infinity;\n } else {\n m = m + Math.pow(2, mLen);\n e = e - eBias;\n }\n return (s ? -1 : 1) * m * Math.pow(2, e - mLen);\n};\nexports.write = function (buffer, value, offset, isLE, mLen, nBytes) {\n var e, m, c;\n var eLen = nBytes * 8 - mLen - 1;\n var eMax = (1 << eLen) - 1;\n var eBias = eMax >> 1;\n var rt = mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0;\n var i = isLE ? 0 : nBytes - 1;\n var d = isLE ? 1 : -1;\n var s = value < 0 || value === 0 && 1 / value < 0 ? 1 : 0;\n value = Math.abs(value);\n if (isNaN(value) || value === Infinity) {\n m = isNaN(value) ? 1 : 0;\n e = eMax;\n } else {\n e = Math.floor(Math.log(value) / Math.LN2);\n if (value * (c = Math.pow(2, -e)) < 1) {\n e--;\n c *= 2;\n }\n if (e + eBias >= 1) {\n value += rt / c;\n } else {\n value += rt * Math.pow(2, 1 - eBias);\n }\n if (value * c >= 2) {\n e++;\n c /= 2;\n }\n if (e + eBias >= eMax) {\n m = 0;\n e = eMax;\n } else if (e + eBias >= 1) {\n m = (value * c - 1) * Math.pow(2, mLen);\n e = e + eBias;\n } else {\n m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);\n e = 0;\n }\n }\n for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}\n e = e << mLen | m;\n eLen += mLen;\n for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}\n buffer[offset + i - d] |= s * 128;\n};\n\n/***/ }),\n\n/***/ \"./node_modules/is-buffer/index.js\":\n/*!*****************************************!*\\\n !*** ./node_modules/is-buffer/index.js ***!\n \\*****************************************/\n/***/ ((module) => {\n\n/*!\n * Determine if an object is a Buffer\n *\n * @author Feross Aboukhadijeh \n * @license MIT\n */\n\n// The _isBuffer check is for Safari 5-7 support, because it's missing\n// Object.prototype.constructor. Remove this eventually\nmodule.exports = function (obj) {\n return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer);\n};\nfunction isBuffer(obj) {\n return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj);\n}\n\n// For Node v0.10 support. Remove this eventually.\nfunction isSlowBuffer(obj) {\n return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0));\n}\n\n/***/ }),\n\n/***/ \"./node_modules/is-function/index.js\":\n/*!*******************************************!*\\\n !*** ./node_modules/is-function/index.js ***!\n \\*******************************************/\n/***/ ((module) => {\n\nmodule.exports = isFunction;\nvar toString = Object.prototype.toString;\nfunction isFunction(fn) {\n if (!fn) {\n return false;\n }\n var string = toString.call(fn);\n return string === '[object Function]' || typeof fn === 'function' && string !== '[object RegExp]' || typeof window !== 'undefined' && (\n // IE8 and below\n fn === window.setTimeout || fn === window.alert || fn === window.confirm || fn === window.prompt);\n}\n;\n\n/***/ }),\n\n/***/ \"./node_modules/is-obj/index.js\":\n/*!**************************************!*\\\n !*** ./node_modules/is-obj/index.js ***!\n \\**************************************/\n/***/ ((module) => {\n\n\"use strict\";\n\n\nmodule.exports = function (x) {\n var type = typeof x;\n return x !== null && (type === 'object' || type === 'function');\n};\n\n/***/ }),\n\n/***/ \"./node_modules/layout-bmfont-text/index.js\":\n/*!**************************************************!*\\\n !*** ./node_modules/layout-bmfont-text/index.js ***!\n \\**************************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar wordWrap = __webpack_require__(/*! word-wrapper */ \"./node_modules/word-wrapper/index.js\");\nvar xtend = __webpack_require__(/*! xtend */ \"./node_modules/xtend/immutable.js\");\nvar number = __webpack_require__(/*! as-number */ \"./node_modules/as-number/index.js\");\nvar X_HEIGHTS = ['x', 'e', 'a', 'o', 'n', 's', 'r', 'c', 'u', 'm', 'v', 'w', 'z'];\nvar M_WIDTHS = ['m', 'w'];\nvar CAP_HEIGHTS = ['H', 'I', 'N', 'E', 'F', 'K', 'L', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];\nvar TAB_ID = '\\t'.charCodeAt(0);\nvar SPACE_ID = ' '.charCodeAt(0);\nvar ALIGN_LEFT = 0,\n ALIGN_CENTER = 1,\n ALIGN_RIGHT = 2;\nmodule.exports = function createLayout(opt) {\n return new TextLayout(opt);\n};\nfunction TextLayout(opt) {\n this.glyphs = [];\n this._measure = this.computeMetrics.bind(this);\n this.update(opt);\n}\nTextLayout.prototype.update = function (opt) {\n opt = xtend({\n measure: this._measure\n }, opt);\n this._opt = opt;\n this._opt.tabSize = number(this._opt.tabSize, 4);\n if (!opt.font) throw new Error('must provide a valid bitmap font');\n var glyphs = this.glyphs;\n var text = opt.text || '';\n var font = opt.font;\n this._setupSpaceGlyphs(font);\n var lines = wordWrap.lines(text, opt);\n var minWidth = opt.width || 0;\n\n //clear glyphs\n glyphs.length = 0;\n\n //get max line width\n var maxLineWidth = lines.reduce(function (prev, line) {\n return Math.max(prev, line.width, minWidth);\n }, 0);\n\n //the pen position\n var x = 0;\n var y = 0;\n var lineHeight = number(opt.lineHeight, font.common.lineHeight);\n var baseline = font.common.base;\n var descender = lineHeight - baseline;\n var letterSpacing = opt.letterSpacing || 0;\n var height = lineHeight * lines.length - descender;\n var align = getAlignType(this._opt.align);\n\n //draw text along baseline\n y -= height;\n\n //the metrics for this text layout\n this._width = maxLineWidth;\n this._height = height;\n this._descender = lineHeight - baseline;\n this._baseline = baseline;\n this._xHeight = getXHeight(font);\n this._capHeight = getCapHeight(font);\n this._lineHeight = lineHeight;\n this._ascender = lineHeight - descender - this._xHeight;\n\n //layout each glyph\n var self = this;\n lines.forEach(function (line, lineIndex) {\n var start = line.start;\n var end = line.end;\n var lineWidth = line.width;\n var lastGlyph;\n\n //for each glyph in that line...\n for (var i = start; i < end; i++) {\n var id = text.charCodeAt(i);\n var glyph = self.getGlyph(font, id);\n if (glyph) {\n if (lastGlyph) x += getKerning(font, lastGlyph.id, glyph.id);\n var tx = x;\n if (align === ALIGN_CENTER) tx += (maxLineWidth - lineWidth) / 2;else if (align === ALIGN_RIGHT) tx += maxLineWidth - lineWidth;\n glyphs.push({\n position: [tx, y],\n data: glyph,\n index: i,\n line: lineIndex\n });\n\n //move pen forward\n x += glyph.xadvance + letterSpacing;\n lastGlyph = glyph;\n }\n }\n\n //next line down\n y += lineHeight;\n x = 0;\n });\n this._linesTotal = lines.length;\n};\nTextLayout.prototype._setupSpaceGlyphs = function (font) {\n //These are fallbacks, when the font doesn't include\n //' ' or '\\t' glyphs\n this._fallbackSpaceGlyph = null;\n this._fallbackTabGlyph = null;\n if (!font.chars || font.chars.length === 0) return;\n\n //try to get space glyph\n //then fall back to the 'm' or 'w' glyphs\n //then fall back to the first glyph available\n var space = getGlyphById(font, SPACE_ID) || getMGlyph(font) || font.chars[0];\n\n //and create a fallback for tab\n var tabWidth = this._opt.tabSize * space.xadvance;\n this._fallbackSpaceGlyph = space;\n this._fallbackTabGlyph = xtend(space, {\n x: 0,\n y: 0,\n xadvance: tabWidth,\n id: TAB_ID,\n xoffset: 0,\n yoffset: 0,\n width: 0,\n height: 0\n });\n};\nTextLayout.prototype.getGlyph = function (font, id) {\n var glyph = getGlyphById(font, id);\n if (glyph) return glyph;else if (id === TAB_ID) return this._fallbackTabGlyph;else if (id === SPACE_ID) return this._fallbackSpaceGlyph;\n return null;\n};\nTextLayout.prototype.computeMetrics = function (text, start, end, width) {\n var letterSpacing = this._opt.letterSpacing || 0;\n var font = this._opt.font;\n var curPen = 0;\n var curWidth = 0;\n var count = 0;\n var glyph;\n var lastGlyph;\n if (!font.chars || font.chars.length === 0) {\n return {\n start: start,\n end: start,\n width: 0\n };\n }\n end = Math.min(text.length, end);\n for (var i = start; i < end; i++) {\n var id = text.charCodeAt(i);\n var glyph = this.getGlyph(font, id);\n if (glyph) {\n //move pen forward\n var xoff = glyph.xoffset;\n var kern = lastGlyph ? getKerning(font, lastGlyph.id, glyph.id) : 0;\n curPen += kern;\n var nextPen = curPen + glyph.xadvance + letterSpacing;\n var nextWidth = curPen + glyph.width;\n\n //we've hit our limit; we can't move onto the next glyph\n if (nextWidth >= width || nextPen >= width) break;\n\n //otherwise continue along our line\n curPen = nextPen;\n curWidth = nextWidth;\n lastGlyph = glyph;\n }\n count++;\n }\n\n //make sure rightmost edge lines up with rendered glyphs\n if (lastGlyph) curWidth += lastGlyph.xoffset;\n return {\n start: start,\n end: start + count,\n width: curWidth\n };\n}\n\n//getters for the private vars\n;\n['width', 'height', 'descender', 'ascender', 'xHeight', 'baseline', 'capHeight', 'lineHeight'].forEach(addGetter);\nfunction addGetter(name) {\n Object.defineProperty(TextLayout.prototype, name, {\n get: wrapper(name),\n configurable: true\n });\n}\n\n//create lookups for private vars\nfunction wrapper(name) {\n return new Function(['return function ' + name + '() {', ' return this._' + name, '}'].join('\\n'))();\n}\nfunction getGlyphById(font, id) {\n if (!font.chars || font.chars.length === 0) return null;\n var glyphIdx = findChar(font.chars, id);\n if (glyphIdx >= 0) return font.chars[glyphIdx];\n return null;\n}\nfunction getXHeight(font) {\n for (var i = 0; i < X_HEIGHTS.length; i++) {\n var id = X_HEIGHTS[i].charCodeAt(0);\n var idx = findChar(font.chars, id);\n if (idx >= 0) return font.chars[idx].height;\n }\n return 0;\n}\nfunction getMGlyph(font) {\n for (var i = 0; i < M_WIDTHS.length; i++) {\n var id = M_WIDTHS[i].charCodeAt(0);\n var idx = findChar(font.chars, id);\n if (idx >= 0) return font.chars[idx];\n }\n return 0;\n}\nfunction getCapHeight(font) {\n for (var i = 0; i < CAP_HEIGHTS.length; i++) {\n var id = CAP_HEIGHTS[i].charCodeAt(0);\n var idx = findChar(font.chars, id);\n if (idx >= 0) return font.chars[idx].height;\n }\n return 0;\n}\nfunction getKerning(font, left, right) {\n if (!font.kernings || font.kernings.length === 0) return 0;\n var table = font.kernings;\n for (var i = 0; i < table.length; i++) {\n var kern = table[i];\n if (kern.first === left && kern.second === right) return kern.amount;\n }\n return 0;\n}\nfunction getAlignType(align) {\n if (align === 'center') return ALIGN_CENTER;else if (align === 'right') return ALIGN_RIGHT;\n return ALIGN_LEFT;\n}\nfunction findChar(array, value, start) {\n start = start || 0;\n for (var i = start; i < array.length; i++) {\n if (array[i].id === value) {\n return i;\n }\n }\n return -1;\n}\n\n/***/ }),\n\n/***/ \"./node_modules/load-bmfont/browser.js\":\n/*!*********************************************!*\\\n !*** ./node_modules/load-bmfont/browser.js ***!\n \\*********************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\n/* provided dependency */ var Buffer = __webpack_require__(/*! buffer */ \"./node_modules/buffer/index.js\")[\"Buffer\"];\nvar xhr = __webpack_require__(/*! xhr */ \"./node_modules/xhr/index.js\");\nvar noop = function () {};\nvar parseASCII = __webpack_require__(/*! parse-bmfont-ascii */ \"./node_modules/parse-bmfont-ascii/index.js\");\nvar parseXML = __webpack_require__(/*! parse-bmfont-xml */ \"./node_modules/parse-bmfont-xml/lib/browser.js\");\nvar readBinary = __webpack_require__(/*! parse-bmfont-binary */ \"./node_modules/parse-bmfont-binary/index.js\");\nvar isBinaryFormat = __webpack_require__(/*! ./lib/is-binary */ \"./node_modules/load-bmfont/lib/is-binary.js\");\nvar xtend = __webpack_require__(/*! xtend */ \"./node_modules/xtend/immutable.js\");\nvar xml2 = function hasXML2() {\n return self.XMLHttpRequest && \"withCredentials\" in new XMLHttpRequest();\n}();\nmodule.exports = function (opt, cb) {\n cb = typeof cb === 'function' ? cb : noop;\n if (typeof opt === 'string') opt = {\n uri: opt\n };else if (!opt) opt = {};\n var expectBinary = opt.binary;\n if (expectBinary) opt = getBinaryOpts(opt);\n xhr(opt, function (err, res, body) {\n if (err) return cb(err);\n if (!/^2/.test(res.statusCode)) return cb(new Error('http status code: ' + res.statusCode));\n if (!body) return cb(new Error('no body result'));\n var binary = false;\n\n //if the response type is an array buffer,\n //we need to convert it into a regular Buffer object\n if (isArrayBuffer(body)) {\n var array = new Uint8Array(body);\n body = Buffer.from(array, 'binary');\n }\n\n //now check the string/Buffer response\n //and see if it has a binary BMF header\n if (isBinaryFormat(body)) {\n binary = true;\n //if we have a string, turn it into a Buffer\n if (typeof body === 'string') body = Buffer.from(body, 'binary');\n }\n\n //we are not parsing a binary format, just ASCII/XML/etc\n if (!binary) {\n //might still be a buffer if responseType is 'arraybuffer'\n if (Buffer.isBuffer(body)) body = body.toString(opt.encoding);\n body = body.trim();\n }\n var result;\n try {\n var type = res.headers['content-type'];\n if (binary) result = readBinary(body);else if (/json/.test(type) || body.charAt(0) === '{') result = JSON.parse(body);else if (/xml/.test(type) || body.charAt(0) === '<') result = parseXML(body);else result = parseASCII(body);\n } catch (e) {\n cb(new Error('error parsing font ' + e.message));\n cb = noop;\n }\n cb(null, result);\n });\n};\nfunction isArrayBuffer(arr) {\n var str = Object.prototype.toString;\n return str.call(arr) === '[object ArrayBuffer]';\n}\nfunction getBinaryOpts(opt) {\n //IE10+ and other modern browsers support array buffers\n if (xml2) return xtend(opt, {\n responseType: 'arraybuffer'\n });\n if (typeof self.XMLHttpRequest === 'undefined') throw new Error('your browser does not support XHR loading');\n\n //IE9 and XML1 browsers could still use an override\n var req = new self.XMLHttpRequest();\n req.overrideMimeType('text/plain; charset=x-user-defined');\n return xtend({\n xhr: req\n }, opt);\n}\n\n/***/ }),\n\n/***/ \"./node_modules/load-bmfont/lib/is-binary.js\":\n/*!***************************************************!*\\\n !*** ./node_modules/load-bmfont/lib/is-binary.js ***!\n \\***************************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\n/* provided dependency */ var Buffer = __webpack_require__(/*! buffer */ \"./node_modules/buffer/index.js\")[\"Buffer\"];\nvar equal = __webpack_require__(/*! buffer-equal */ \"./node_modules/buffer-equal/index.js\");\nvar HEADER = Buffer.from([66, 77, 70, 3]);\nmodule.exports = function (buf) {\n if (typeof buf === 'string') return buf.substring(0, 3) === 'BMF';\n return buf.length > 4 && equal(buf.slice(0, 4), HEADER);\n};\n\n/***/ }),\n\n/***/ \"./node_modules/ms/index.js\":\n/*!**********************************!*\\\n !*** ./node_modules/ms/index.js ***!\n \\**********************************/\n/***/ ((module) => {\n\n/**\n * Helpers.\n */\n\nvar s = 1000;\nvar m = s * 60;\nvar h = m * 60;\nvar d = h * 24;\nvar w = d * 7;\nvar y = d * 365.25;\n\n/**\n * Parse or format the given `val`.\n *\n * Options:\n *\n * - `long` verbose formatting [false]\n *\n * @param {String|Number} val\n * @param {Object} [options]\n * @throws {Error} throw an error if val is not a non-empty string or a number\n * @return {String|Number}\n * @api public\n */\n\nmodule.exports = function (val, options) {\n options = options || {};\n var type = typeof val;\n if (type === 'string' && val.length > 0) {\n return parse(val);\n } else if (type === 'number' && isFinite(val)) {\n return options.long ? fmtLong(val) : fmtShort(val);\n }\n throw new Error('val is not a non-empty string or a valid number. val=' + JSON.stringify(val));\n};\n\n/**\n * Parse the given `str` and return milliseconds.\n *\n * @param {String} str\n * @return {Number}\n * @api private\n */\n\nfunction parse(str) {\n str = String(str);\n if (str.length > 100) {\n return;\n }\n var match = /^(-?(?:\\d+)?\\.?\\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(str);\n if (!match) {\n return;\n }\n var n = parseFloat(match[1]);\n var type = (match[2] || 'ms').toLowerCase();\n switch (type) {\n case 'years':\n case 'year':\n case 'yrs':\n case 'yr':\n case 'y':\n return n * y;\n case 'weeks':\n case 'week':\n case 'w':\n return n * w;\n case 'days':\n case 'day':\n case 'd':\n return n * d;\n case 'hours':\n case 'hour':\n case 'hrs':\n case 'hr':\n case 'h':\n return n * h;\n case 'minutes':\n case 'minute':\n case 'mins':\n case 'min':\n case 'm':\n return n * m;\n case 'seconds':\n case 'second':\n case 'secs':\n case 'sec':\n case 's':\n return n * s;\n case 'milliseconds':\n case 'millisecond':\n case 'msecs':\n case 'msec':\n case 'ms':\n return n;\n default:\n return undefined;\n }\n}\n\n/**\n * Short format for `ms`.\n *\n * @param {Number} ms\n * @return {String}\n * @api private\n */\n\nfunction fmtShort(ms) {\n var msAbs = Math.abs(ms);\n if (msAbs >= d) {\n return Math.round(ms / d) + 'd';\n }\n if (msAbs >= h) {\n return Math.round(ms / h) + 'h';\n }\n if (msAbs >= m) {\n return Math.round(ms / m) + 'm';\n }\n if (msAbs >= s) {\n return Math.round(ms / s) + 's';\n }\n return ms + 'ms';\n}\n\n/**\n * Long format for `ms`.\n *\n * @param {Number} ms\n * @return {String}\n * @api private\n */\n\nfunction fmtLong(ms) {\n var msAbs = Math.abs(ms);\n if (msAbs >= d) {\n return plural(ms, msAbs, d, 'day');\n }\n if (msAbs >= h) {\n return plural(ms, msAbs, h, 'hour');\n }\n if (msAbs >= m) {\n return plural(ms, msAbs, m, 'minute');\n }\n if (msAbs >= s) {\n return plural(ms, msAbs, s, 'second');\n }\n return ms + ' ms';\n}\n\n/**\n * Pluralization helper.\n */\n\nfunction plural(ms, msAbs, n, name) {\n var isPlural = msAbs >= n * 1.5;\n return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : '');\n}\n\n/***/ }),\n\n/***/ \"./node_modules/parse-bmfont-ascii/index.js\":\n/*!**************************************************!*\\\n !*** ./node_modules/parse-bmfont-ascii/index.js ***!\n \\**************************************************/\n/***/ ((module) => {\n\nmodule.exports = function parseBMFontAscii(data) {\n if (!data) throw new Error('no data provided');\n data = data.toString().trim();\n var output = {\n pages: [],\n chars: [],\n kernings: []\n };\n var lines = data.split(/\\r\\n?|\\n/g);\n if (lines.length === 0) throw new Error('no data in BMFont file');\n for (var i = 0; i < lines.length; i++) {\n var lineData = splitLine(lines[i], i);\n if (!lineData)\n //skip empty lines\n continue;\n if (lineData.key === 'page') {\n if (typeof lineData.data.id !== 'number') throw new Error('malformed file at line ' + i + ' -- needs page id=N');\n if (typeof lineData.data.file !== 'string') throw new Error('malformed file at line ' + i + ' -- needs page file=\"path\"');\n output.pages[lineData.data.id] = lineData.data.file;\n } else if (lineData.key === 'chars' || lineData.key === 'kernings') {\n //... do nothing for these two ...\n } else if (lineData.key === 'char') {\n output.chars.push(lineData.data);\n } else if (lineData.key === 'kerning') {\n output.kernings.push(lineData.data);\n } else {\n output[lineData.key] = lineData.data;\n }\n }\n return output;\n};\nfunction splitLine(line, idx) {\n line = line.replace(/\\t+/g, ' ').trim();\n if (!line) return null;\n var space = line.indexOf(' ');\n if (space === -1) throw new Error(\"no named row at line \" + idx);\n var key = line.substring(0, space);\n line = line.substring(space + 1);\n //clear \"letter\" field as it is non-standard and\n //requires additional complexity to parse \" / = symbols\n line = line.replace(/letter=[\\'\\\"]\\S+[\\'\\\"]/gi, '');\n line = line.split(\"=\");\n line = line.map(function (str) {\n return str.trim().match(/(\".*?\"|[^\"\\s]+)+(?=\\s*|\\s*$)/g);\n });\n var data = [];\n for (var i = 0; i < line.length; i++) {\n var dt = line[i];\n if (i === 0) {\n data.push({\n key: dt[0],\n data: \"\"\n });\n } else if (i === line.length - 1) {\n data[data.length - 1].data = parseData(dt[0]);\n } else {\n data[data.length - 1].data = parseData(dt[0]);\n data.push({\n key: dt[1],\n data: \"\"\n });\n }\n }\n var out = {\n key: key,\n data: {}\n };\n data.forEach(function (v) {\n out.data[v.key] = v.data;\n });\n return out;\n}\nfunction parseData(data) {\n if (!data || data.length === 0) return \"\";\n if (data.indexOf('\"') === 0 || data.indexOf(\"'\") === 0) return data.substring(1, data.length - 1);\n if (data.indexOf(',') !== -1) return parseIntList(data);\n return parseInt(data, 10);\n}\nfunction parseIntList(data) {\n return data.split(',').map(function (val) {\n return parseInt(val, 10);\n });\n}\n\n/***/ }),\n\n/***/ \"./node_modules/parse-bmfont-binary/index.js\":\n/*!***************************************************!*\\\n !*** ./node_modules/parse-bmfont-binary/index.js ***!\n \\***************************************************/\n/***/ ((module) => {\n\nvar HEADER = [66, 77, 70];\nmodule.exports = function readBMFontBinary(buf) {\n if (buf.length < 6) throw new Error('invalid buffer length for BMFont');\n var header = HEADER.every(function (byte, i) {\n return buf.readUInt8(i) === byte;\n });\n if (!header) throw new Error('BMFont missing BMF byte header');\n var i = 3;\n var vers = buf.readUInt8(i++);\n if (vers > 3) throw new Error('Only supports BMFont Binary v3 (BMFont App v1.10)');\n var target = {\n kernings: [],\n chars: []\n };\n for (var b = 0; b < 5; b++) i += readBlock(target, buf, i);\n return target;\n};\nfunction readBlock(target, buf, i) {\n if (i > buf.length - 1) return 0;\n var blockID = buf.readUInt8(i++);\n var blockSize = buf.readInt32LE(i);\n i += 4;\n switch (blockID) {\n case 1:\n target.info = readInfo(buf, i);\n break;\n case 2:\n target.common = readCommon(buf, i);\n break;\n case 3:\n target.pages = readPages(buf, i, blockSize);\n break;\n case 4:\n target.chars = readChars(buf, i, blockSize);\n break;\n case 5:\n target.kernings = readKernings(buf, i, blockSize);\n break;\n }\n return 5 + blockSize;\n}\nfunction readInfo(buf, i) {\n var info = {};\n info.size = buf.readInt16LE(i);\n var bitField = buf.readUInt8(i + 2);\n info.smooth = bitField >> 7 & 1;\n info.unicode = bitField >> 6 & 1;\n info.italic = bitField >> 5 & 1;\n info.bold = bitField >> 4 & 1;\n\n //fixedHeight is only mentioned in binary spec \n if (bitField >> 3 & 1) info.fixedHeight = 1;\n info.charset = buf.readUInt8(i + 3) || '';\n info.stretchH = buf.readUInt16LE(i + 4);\n info.aa = buf.readUInt8(i + 6);\n info.padding = [buf.readInt8(i + 7), buf.readInt8(i + 8), buf.readInt8(i + 9), buf.readInt8(i + 10)];\n info.spacing = [buf.readInt8(i + 11), buf.readInt8(i + 12)];\n info.outline = buf.readUInt8(i + 13);\n info.face = readStringNT(buf, i + 14);\n return info;\n}\nfunction readCommon(buf, i) {\n var common = {};\n common.lineHeight = buf.readUInt16LE(i);\n common.base = buf.readUInt16LE(i + 2);\n common.scaleW = buf.readUInt16LE(i + 4);\n common.scaleH = buf.readUInt16LE(i + 6);\n common.pages = buf.readUInt16LE(i + 8);\n var bitField = buf.readUInt8(i + 10);\n common.packed = 0;\n common.alphaChnl = buf.readUInt8(i + 11);\n common.redChnl = buf.readUInt8(i + 12);\n common.greenChnl = buf.readUInt8(i + 13);\n common.blueChnl = buf.readUInt8(i + 14);\n return common;\n}\nfunction readPages(buf, i, size) {\n var pages = [];\n var text = readNameNT(buf, i);\n var len = text.length + 1;\n var count = size / len;\n for (var c = 0; c < count; c++) {\n pages[c] = buf.slice(i, i + text.length).toString('utf8');\n i += len;\n }\n return pages;\n}\nfunction readChars(buf, i, blockSize) {\n var chars = [];\n var count = blockSize / 20;\n for (var c = 0; c < count; c++) {\n var char = {};\n var off = c * 20;\n char.id = buf.readUInt32LE(i + 0 + off);\n char.x = buf.readUInt16LE(i + 4 + off);\n char.y = buf.readUInt16LE(i + 6 + off);\n char.width = buf.readUInt16LE(i + 8 + off);\n char.height = buf.readUInt16LE(i + 10 + off);\n char.xoffset = buf.readInt16LE(i + 12 + off);\n char.yoffset = buf.readInt16LE(i + 14 + off);\n char.xadvance = buf.readInt16LE(i + 16 + off);\n char.page = buf.readUInt8(i + 18 + off);\n char.chnl = buf.readUInt8(i + 19 + off);\n chars[c] = char;\n }\n return chars;\n}\nfunction readKernings(buf, i, blockSize) {\n var kernings = [];\n var count = blockSize / 10;\n for (var c = 0; c < count; c++) {\n var kern = {};\n var off = c * 10;\n kern.first = buf.readUInt32LE(i + 0 + off);\n kern.second = buf.readUInt32LE(i + 4 + off);\n kern.amount = buf.readInt16LE(i + 8 + off);\n kernings[c] = kern;\n }\n return kernings;\n}\nfunction readNameNT(buf, offset) {\n var pos = offset;\n for (; pos < buf.length; pos++) {\n if (buf[pos] === 0x00) break;\n }\n return buf.slice(offset, pos);\n}\nfunction readStringNT(buf, offset) {\n return readNameNT(buf, offset).toString('utf8');\n}\n\n/***/ }),\n\n/***/ \"./node_modules/parse-bmfont-xml/lib/browser.js\":\n/*!******************************************************!*\\\n !*** ./node_modules/parse-bmfont-xml/lib/browser.js ***!\n \\******************************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar parseAttributes = __webpack_require__(/*! ./parse-attribs */ \"./node_modules/parse-bmfont-xml/lib/parse-attribs.js\");\nvar parseFromString = __webpack_require__(/*! xml-parse-from-string */ \"./node_modules/xml-parse-from-string/index.js\");\n\n//In some cases element.attribute.nodeName can return\n//all lowercase values.. so we need to map them to the correct \n//case\nvar NAME_MAP = {\n scaleh: 'scaleH',\n scalew: 'scaleW',\n stretchh: 'stretchH',\n lineheight: 'lineHeight',\n alphachnl: 'alphaChnl',\n redchnl: 'redChnl',\n greenchnl: 'greenChnl',\n bluechnl: 'blueChnl'\n};\nmodule.exports = function parse(data) {\n data = data.toString();\n var xmlRoot = parseFromString(data);\n var output = {\n pages: [],\n chars: [],\n kernings: []\n }\n\n //get config settings\n ;\n ['info', 'common'].forEach(function (key) {\n var element = xmlRoot.getElementsByTagName(key)[0];\n if (element) output[key] = parseAttributes(getAttribs(element));\n });\n\n //get page info\n var pageRoot = xmlRoot.getElementsByTagName('pages')[0];\n if (!pageRoot) throw new Error('malformed file -- no element');\n var pages = pageRoot.getElementsByTagName('page');\n for (var i = 0; i < pages.length; i++) {\n var p = pages[i];\n var id = parseInt(p.getAttribute('id'), 10);\n var file = p.getAttribute('file');\n if (isNaN(id)) throw new Error('malformed file -- page \"id\" attribute is NaN');\n if (!file) throw new Error('malformed file -- needs page \"file\" attribute');\n output.pages[parseInt(id, 10)] = file;\n }\n\n //get kernings / chars\n ;\n ['chars', 'kernings'].forEach(function (key) {\n var element = xmlRoot.getElementsByTagName(key)[0];\n if (!element) return;\n var childTag = key.substring(0, key.length - 1);\n var children = element.getElementsByTagName(childTag);\n for (var i = 0; i < children.length; i++) {\n var child = children[i];\n output[key].push(parseAttributes(getAttribs(child)));\n }\n });\n return output;\n};\nfunction getAttribs(element) {\n var attribs = getAttribList(element);\n return attribs.reduce(function (dict, attrib) {\n var key = mapName(attrib.nodeName);\n dict[key] = attrib.nodeValue;\n return dict;\n }, {});\n}\nfunction getAttribList(element) {\n //IE8+ and modern browsers\n var attribs = [];\n for (var i = 0; i < element.attributes.length; i++) attribs.push(element.attributes[i]);\n return attribs;\n}\nfunction mapName(nodeName) {\n return NAME_MAP[nodeName.toLowerCase()] || nodeName;\n}\n\n/***/ }),\n\n/***/ \"./node_modules/parse-bmfont-xml/lib/parse-attribs.js\":\n/*!************************************************************!*\\\n !*** ./node_modules/parse-bmfont-xml/lib/parse-attribs.js ***!\n \\************************************************************/\n/***/ ((module) => {\n\n//Some versions of GlyphDesigner have a typo\n//that causes some bugs with parsing. \n//Need to confirm with recent version of the software\n//to see whether this is still an issue or not.\nvar GLYPH_DESIGNER_ERROR = 'chasrset';\nmodule.exports = function parseAttributes(obj) {\n if (GLYPH_DESIGNER_ERROR in obj) {\n obj['charset'] = obj[GLYPH_DESIGNER_ERROR];\n delete obj[GLYPH_DESIGNER_ERROR];\n }\n for (var k in obj) {\n if (k === 'face' || k === 'charset') continue;else if (k === 'padding' || k === 'spacing') obj[k] = parseIntList(obj[k]);else obj[k] = parseInt(obj[k], 10);\n }\n return obj;\n};\nfunction parseIntList(data) {\n return data.split(',').map(function (val) {\n return parseInt(val, 10);\n });\n}\n\n/***/ }),\n\n/***/ \"./node_modules/parse-headers/parse-headers.js\":\n/*!*****************************************************!*\\\n !*** ./node_modules/parse-headers/parse-headers.js ***!\n \\*****************************************************/\n/***/ ((module) => {\n\nvar trim = function (string) {\n return string.replace(/^\\s+|\\s+$/g, '');\n },\n isArray = function (arg) {\n return Object.prototype.toString.call(arg) === '[object Array]';\n };\nmodule.exports = function (headers) {\n if (!headers) return {};\n var result = {};\n var headersArr = trim(headers).split('\\n');\n for (var i = 0; i < headersArr.length; i++) {\n var row = headersArr[i];\n var index = row.indexOf(':'),\n key = trim(row.slice(0, index)).toLowerCase(),\n value = trim(row.slice(index + 1));\n if (typeof result[key] === 'undefined') {\n result[key] = value;\n } else if (isArray(result[key])) {\n result[key].push(value);\n } else {\n result[key] = [result[key], value];\n }\n }\n return result;\n};\n\n/***/ }),\n\n/***/ \"./node_modules/quad-indices/index.js\":\n/*!********************************************!*\\\n !*** ./node_modules/quad-indices/index.js ***!\n \\********************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar dtype = __webpack_require__(/*! dtype */ \"./node_modules/dtype/index.js\");\nvar anArray = __webpack_require__(/*! an-array */ \"./node_modules/an-array/index.js\");\nvar isBuffer = __webpack_require__(/*! is-buffer */ \"./node_modules/is-buffer/index.js\");\nvar CW = [0, 2, 3];\nvar CCW = [2, 1, 3];\nmodule.exports = function createQuadElements(array, opt) {\n //if user didn't specify an output array\n if (!array || !(anArray(array) || isBuffer(array))) {\n opt = array || {};\n array = null;\n }\n if (typeof opt === 'number')\n //backwards-compatible\n opt = {\n count: opt\n };else opt = opt || {};\n var type = typeof opt.type === 'string' ? opt.type : 'uint16';\n var count = typeof opt.count === 'number' ? opt.count : 1;\n var start = opt.start || 0;\n var dir = opt.clockwise !== false ? CW : CCW,\n a = dir[0],\n b = dir[1],\n c = dir[2];\n var numIndices = count * 6;\n var indices = array || new (dtype(type))(numIndices);\n for (var i = 0, j = 0; i < numIndices; i += 6, j += 4) {\n var x = i + start;\n indices[x + 0] = j + 0;\n indices[x + 1] = j + 1;\n indices[x + 2] = j + 2;\n indices[x + 3] = j + a;\n indices[x + 4] = j + b;\n indices[x + 5] = j + c;\n }\n return indices;\n};\n\n/***/ }),\n\n/***/ \"./node_modules/super-animejs/lib/anime.es.js\":\n/*!****************************************************!*\\\n !*** ./node_modules/super-animejs/lib/anime.es.js ***!\n \\****************************************************/\n/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {\n\n\"use strict\";\n__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/*\n * anime.js v3.0.0\n * (c) 2019 Julian Garnier\n * Released under the MIT license\n * animejs.com\n */\n\n// Defaults\n\nvar defaultInstanceSettings = {\n update: null,\n begin: null,\n loopBegin: null,\n changeBegin: null,\n change: null,\n changeComplete: null,\n loopComplete: null,\n complete: null,\n loop: 1,\n direction: 'normal',\n autoplay: true,\n timelineOffset: 0\n};\nvar defaultTweenSettings = {\n duration: 1000,\n delay: 0,\n endDelay: 0,\n easing: 'easeOutElastic(1, .5)',\n round: 0\n};\nvar validTransforms = ['translateX', 'translateY', 'translateZ', 'rotate', 'rotateX', 'rotateY', 'rotateZ', 'scale', 'scaleX', 'scaleY', 'scaleZ', 'skew', 'skewX', 'skewY', 'perspective'];\n\n// Caching\n\nvar cache = {\n CSS: {},\n springs: {}\n};\n\n// Utils\n\nfunction minMax(val, min, max) {\n return Math.min(Math.max(val, min), max);\n}\nfunction stringContains(str, text) {\n return str.indexOf(text) > -1;\n}\nfunction applyArguments(func, args) {\n return func.apply(null, args);\n}\nvar hexRegex = /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i;\nvar rgbPrefixRegex = /^rgb/;\nvar hslRegex = /^hsl/;\nvar is = {\n arr: function (a) {\n return Array.isArray(a);\n },\n obj: function (a) {\n return stringContains(Object.prototype.toString.call(a), 'Object');\n },\n pth: function (a) {\n return is.obj(a) && a.hasOwnProperty('totalLength');\n },\n svg: function (a) {\n return a instanceof SVGElement;\n },\n inp: function (a) {\n return a instanceof HTMLInputElement;\n },\n dom: function (a) {\n return a.nodeType || is.svg(a);\n },\n str: function (a) {\n return typeof a === 'string';\n },\n fnc: function (a) {\n return typeof a === 'function';\n },\n und: function (a) {\n return typeof a === 'undefined';\n },\n hex: function (a) {\n return hexRegex.test(a);\n },\n rgb: function (a) {\n return rgbPrefixRegex.test(a);\n },\n hsl: function (a) {\n return hslRegex.test(a);\n },\n col: function (a) {\n return is.hex(a) || is.rgb(a) || is.hsl(a);\n },\n key: function (a) {\n return !defaultInstanceSettings.hasOwnProperty(a) && !defaultTweenSettings.hasOwnProperty(a) && a !== 'targets' && a !== 'keyframes';\n }\n};\n\n// Easings\n\nvar easingFunctionRegex = /\\(([^)]+)\\)/;\nfunction parseEasingParameters(string) {\n var match = easingFunctionRegex.exec(string);\n return match ? match[1].split(',').map(function (p) {\n return parseFloat(p);\n }) : [];\n}\n\n// Spring solver inspired by Webkit Copyright © 2016 Apple Inc. All rights reserved. https://webkit.org/demos/spring/spring.js\n\nfunction spring(string, duration) {\n var params = parseEasingParameters(string);\n var mass = minMax(is.und(params[0]) ? 1 : params[0], .1, 100);\n var stiffness = minMax(is.und(params[1]) ? 100 : params[1], .1, 100);\n var damping = minMax(is.und(params[2]) ? 10 : params[2], .1, 100);\n var velocity = minMax(is.und(params[3]) ? 0 : params[3], .1, 100);\n var w0 = Math.sqrt(stiffness / mass);\n var zeta = damping / (2 * Math.sqrt(stiffness * mass));\n var wd = zeta < 1 ? w0 * Math.sqrt(1 - zeta * zeta) : 0;\n var a = 1;\n var b = zeta < 1 ? (zeta * w0 + -velocity) / wd : -velocity + w0;\n function solver(t) {\n var progress = duration ? duration * t / 1000 : t;\n if (zeta < 1) {\n progress = Math.exp(-progress * zeta * w0) * (a * Math.cos(wd * progress) + b * Math.sin(wd * progress));\n } else {\n progress = (a + b * progress) * Math.exp(-progress * w0);\n }\n if (t === 0 || t === 1) {\n return t;\n }\n return 1 - progress;\n }\n function getDuration() {\n var cached = cache.springs[string];\n if (cached) {\n return cached;\n }\n var frame = 1 / 6;\n var elapsed = 0;\n var rest = 0;\n while (true) {\n elapsed += frame;\n if (solver(elapsed) === 1) {\n rest++;\n if (rest >= 16) {\n break;\n }\n } else {\n rest = 0;\n }\n }\n var duration = elapsed * frame * 1000;\n cache.springs[string] = duration;\n return duration;\n }\n return duration ? solver : getDuration;\n}\n\n// Elastic easing adapted from jQueryUI http://api.jqueryui.com/easings/\n\nfunction elastic(amplitude, period) {\n if (amplitude === void 0) amplitude = 1;\n if (period === void 0) period = .5;\n var a = minMax(amplitude, 1, 10);\n var p = minMax(period, .1, 2);\n return function (t) {\n return t === 0 || t === 1 ? t : -a * Math.pow(2, 10 * (t - 1)) * Math.sin((t - 1 - p / (Math.PI * 2) * Math.asin(1 / a)) * (Math.PI * 2) / p);\n };\n}\n\n// Basic steps easing implementation https://developer.mozilla.org/fr/docs/Web/CSS/transition-timing-function\n\nfunction steps(steps) {\n if (steps === void 0) steps = 10;\n return function (t) {\n return Math.round(t * steps) * (1 / steps);\n };\n}\n\n// BezierEasing https://github.com/gre/bezier-easing\n\nvar bezier = function () {\n var kSplineTableSize = 11;\n var kSampleStepSize = 1.0 / (kSplineTableSize - 1.0);\n function A(aA1, aA2) {\n return 1.0 - 3.0 * aA2 + 3.0 * aA1;\n }\n function B(aA1, aA2) {\n return 3.0 * aA2 - 6.0 * aA1;\n }\n function C(aA1) {\n return 3.0 * aA1;\n }\n function calcBezier(aT, aA1, aA2) {\n return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT;\n }\n function getSlope(aT, aA1, aA2) {\n return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1);\n }\n function binarySubdivide(aX, aA, aB, mX1, mX2) {\n var currentX,\n currentT,\n i = 0;\n do {\n currentT = aA + (aB - aA) / 2.0;\n currentX = calcBezier(currentT, mX1, mX2) - aX;\n if (currentX > 0.0) {\n aB = currentT;\n } else {\n aA = currentT;\n }\n } while (Math.abs(currentX) > 0.0000001 && ++i < 10);\n return currentT;\n }\n function newtonRaphsonIterate(aX, aGuessT, mX1, mX2) {\n for (var i = 0; i < 4; ++i) {\n var currentSlope = getSlope(aGuessT, mX1, mX2);\n if (currentSlope === 0.0) {\n return aGuessT;\n }\n var currentX = calcBezier(aGuessT, mX1, mX2) - aX;\n aGuessT -= currentX / currentSlope;\n }\n return aGuessT;\n }\n function bezier(mX1, mY1, mX2, mY2) {\n if (!(0 <= mX1 && mX1 <= 1 && 0 <= mX2 && mX2 <= 1)) {\n return;\n }\n var sampleValues = new Float32Array(kSplineTableSize);\n if (mX1 !== mY1 || mX2 !== mY2) {\n for (var i = 0; i < kSplineTableSize; ++i) {\n sampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2);\n }\n }\n function getTForX(aX) {\n var intervalStart = 0;\n var currentSample = 1;\n var lastSample = kSplineTableSize - 1;\n for (; currentSample !== lastSample && sampleValues[currentSample] <= aX; ++currentSample) {\n intervalStart += kSampleStepSize;\n }\n --currentSample;\n var dist = (aX - sampleValues[currentSample]) / (sampleValues[currentSample + 1] - sampleValues[currentSample]);\n var guessForT = intervalStart + dist * kSampleStepSize;\n var initialSlope = getSlope(guessForT, mX1, mX2);\n if (initialSlope >= 0.001) {\n return newtonRaphsonIterate(aX, guessForT, mX1, mX2);\n } else if (initialSlope === 0.0) {\n return guessForT;\n } else {\n return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize, mX1, mX2);\n }\n }\n return function (x) {\n if (mX1 === mY1 && mX2 === mY2) {\n return x;\n }\n if (x === 0 || x === 1) {\n return x;\n }\n return calcBezier(getTForX(x), mY1, mY2);\n };\n }\n return bezier;\n}();\nvar penner = function () {\n var names = ['Quad', 'Cubic', 'Quart', 'Quint', 'Sine', 'Expo', 'Circ', 'Back', 'Elastic'];\n\n // Approximated Penner equations http://matthewlein.com/ceaser/\n\n var curves = {\n In: [[0.550, 0.085, 0.680, 0.530], /* inQuad */\n [0.550, 0.055, 0.675, 0.190], /* inCubic */\n [0.895, 0.030, 0.685, 0.220], /* inQuart */\n [0.755, 0.050, 0.855, 0.060], /* inQuint */\n [0.470, 0.000, 0.745, 0.715], /* inSine */\n [0.950, 0.050, 0.795, 0.035], /* inExpo */\n [0.600, 0.040, 0.980, 0.335], /* inCirc */\n [0.600, -0.280, 0.735, 0.045], /* inBack */\n elastic /* inElastic */],\n\n Out: [[0.250, 0.460, 0.450, 0.940], /* outQuad */\n [0.215, 0.610, 0.355, 1.000], /* outCubic */\n [0.165, 0.840, 0.440, 1.000], /* outQuart */\n [0.230, 1.000, 0.320, 1.000], /* outQuint */\n [0.390, 0.575, 0.565, 1.000], /* outSine */\n [0.190, 1.000, 0.220, 1.000], /* outExpo */\n [0.075, 0.820, 0.165, 1.000], /* outCirc */\n [0.175, 0.885, 0.320, 1.275], /* outBack */\n function (a, p) {\n return function (t) {\n return 1 - elastic(a, p)(1 - t);\n };\n } /* outElastic */],\n\n InOut: [[0.455, 0.030, 0.515, 0.955], /* inOutQuad */\n [0.645, 0.045, 0.355, 1.000], /* inOutCubic */\n [0.770, 0.000, 0.175, 1.000], /* inOutQuart */\n [0.860, 0.000, 0.070, 1.000], /* inOutQuint */\n [0.445, 0.050, 0.550, 0.950], /* inOutSine */\n [1.000, 0.000, 0.000, 1.000], /* inOutExpo */\n [0.785, 0.135, 0.150, 0.860], /* inOutCirc */\n [0.680, -0.550, 0.265, 1.550], /* inOutBack */\n function (a, p) {\n return function (t) {\n return t < .5 ? elastic(a, p)(t * 2) / 2 : 1 - elastic(a, p)(t * -2 + 2) / 2;\n };\n } /* inOutElastic */]\n };\n\n var eases = {\n linear: [0.250, 0.250, 0.750, 0.750]\n };\n for (var coords in curves) {\n for (var i = 0, len = curves[coords].length; i < len; i++) {\n eases['ease' + coords + names[i]] = curves[coords][i];\n }\n }\n return eases;\n}();\nfunction parseEasings(easing, duration) {\n if (is.fnc(easing)) {\n return easing;\n }\n var name = easing.split('(')[0];\n var ease = penner[name];\n var args = parseEasingParameters(easing);\n switch (name) {\n case 'spring':\n return spring(easing, duration);\n case 'cubicBezier':\n return applyArguments(bezier, args);\n case 'steps':\n return applyArguments(steps, args);\n default:\n return is.fnc(ease) ? applyArguments(ease, args) : applyArguments(bezier, ease);\n }\n}\n\n// Strings\n\nfunction selectString(str) {\n try {\n var nodes = document.querySelectorAll(str);\n return nodes;\n } catch (e) {\n return;\n }\n}\n\n// Arrays\n\nvar auxArrayFilter = [];\nfunction filterArray(arr, callback) {\n var result = auxArrayFilter;\n var len = arr.length;\n var thisArg = arguments.length >= 2 ? arguments[1] : void 0;\n for (var i = 0; i < len; i++) {\n if (i in arr) {\n var val = arr[i];\n if (callback.call(thisArg, val, i, arr)) {\n result.push(val);\n }\n }\n }\n\n // arr turns into the auxArray and we return the previously aux array.\n auxArrayFilter = arr;\n auxArrayFilter.length = 0;\n return result;\n}\nfunction flattenArray(arr, result) {\n if (!result) {\n result = [];\n }\n for (var i = 0, length = arr.length; i < length; i++) {\n var value = arr[i];\n if (Array.isArray(value)) {\n flattenArray(value, result);\n } else {\n result.push(value);\n }\n }\n return result;\n}\nfunction toArray(o) {\n if (is.arr(o)) {\n return o;\n }\n if (is.str(o)) {\n o = selectString(o) || o;\n }\n if (o instanceof NodeList || o instanceof HTMLCollection) {\n return [].slice.call(o);\n }\n return [o];\n}\nfunction arrayContains(arr, val) {\n return arr.some(function (a) {\n return a === val;\n });\n}\n\n// Objects\n\nfunction cloneObject(o) {\n var clone = {};\n for (var p in o) {\n clone[p] = o[p];\n }\n return clone;\n}\nfunction replaceObjectProps(o1, o2) {\n var o = cloneObject(o1);\n for (var p in o1) {\n o[p] = o2.hasOwnProperty(p) ? o2[p] : o1[p];\n }\n return o;\n}\nfunction mergeObjects(o1, o2) {\n var o = cloneObject(o1);\n for (var p in o2) {\n o[p] = is.und(o1[p]) ? o2[p] : o1[p];\n }\n return o;\n}\n\n// Colors\n\nvar rgbRegex = /rgb\\((\\d+,\\s*[\\d]+,\\s*[\\d]+)\\)/g;\nfunction rgbToRgba(rgbValue) {\n var rgb = rgbRegex.exec(rgbValue);\n return rgb ? \"rgba(\" + rgb[1] + \",1)\" : rgbValue;\n}\nvar hexToRgbaHexRegex = /^#?([a-f\\d])([a-f\\d])([a-f\\d])$/i;\nvar hexToRgbaRgbRegex = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i;\nfunction hexToRgba(hexValue) {\n var hex = hexValue.replace(hexToRgbaHexRegex, function (m, r, g, b) {\n return r + r + g + g + b + b;\n });\n var rgb = hexToRgbaRgbRegex.exec(hex);\n var r = parseInt(rgb[1], 16);\n var g = parseInt(rgb[2], 16);\n var b = parseInt(rgb[3], 16);\n return \"rgba(\" + r + \",\" + g + \",\" + b + \",1)\";\n}\nvar hslToRgbaHsl1Regex = /hsl\\((\\d+),\\s*([\\d.]+)%,\\s*([\\d.]+)%\\)/g;\nvar hslToRgbaHsl2Regex = /hsla\\((\\d+),\\s*([\\d.]+)%,\\s*([\\d.]+)%,\\s*([\\d.]+)\\)/g;\nfunction hslToRgba(hslValue) {\n var hsl = hslToRgbaHsl1Regex.exec(hslValue) || hslToRgbaHsl2Regex.exec(hslValue);\n var h = parseInt(hsl[1], 10) / 360;\n var s = parseInt(hsl[2], 10) / 100;\n var l = parseInt(hsl[3], 10) / 100;\n var a = hsl[4] || 1;\n function hue2rgb(p, q, t) {\n if (t < 0) {\n t += 1;\n }\n if (t > 1) {\n t -= 1;\n }\n if (t < 1 / 6) {\n return p + (q - p) * 6 * t;\n }\n if (t < 1 / 2) {\n return q;\n }\n if (t < 2 / 3) {\n return p + (q - p) * (2 / 3 - t) * 6;\n }\n return p;\n }\n var r, g, b;\n if (s == 0) {\n r = g = b = l;\n } else {\n var q = l < 0.5 ? l * (1 + s) : l + s - l * s;\n var p = 2 * l - q;\n r = hue2rgb(p, q, h + 1 / 3);\n g = hue2rgb(p, q, h);\n b = hue2rgb(p, q, h - 1 / 3);\n }\n return \"rgba(\" + r * 255 + \",\" + g * 255 + \",\" + b * 255 + \",\" + a + \")\";\n}\nfunction colorToRgb(val) {\n if (is.rgb(val)) {\n return rgbToRgba(val);\n }\n if (is.hex(val)) {\n return hexToRgba(val);\n }\n if (is.hsl(val)) {\n return hslToRgba(val);\n }\n}\n\n// Units\n\nvar unitRegex = /([\\+\\-]?[0-9#\\.]+)(%|px|pt|em|rem|in|cm|mm|ex|ch|pc|vw|vh|vmin|vmax|deg|rad|turn)?$/;\nfunction getUnit(val) {\n var split = unitRegex.exec(val);\n if (split) {\n return split[2];\n }\n}\nfunction getTransformUnit(propName) {\n if (stringContains(propName, 'translate') || propName === 'perspective') {\n return 'px';\n }\n if (stringContains(propName, 'rotate') || stringContains(propName, 'skew')) {\n return 'deg';\n }\n}\n\n// Values\n\nfunction getFunctionValue(val, animatable) {\n if (!is.fnc(val)) {\n return val;\n }\n return val(animatable.target, animatable.id, animatable.total);\n}\nfunction getAttribute(el, prop) {\n return el.getAttribute(prop);\n}\nfunction convertPxToUnit(el, value, unit) {\n var valueUnit = getUnit(value);\n if (arrayContains([unit, 'deg', 'rad', 'turn'], valueUnit)) {\n return value;\n }\n var cached = cache.CSS[value + unit];\n if (!is.und(cached)) {\n return cached;\n }\n var baseline = 100;\n var tempEl = document.createElement(el.tagName);\n var parentEl = el.parentNode && el.parentNode !== document ? el.parentNode : document.body;\n parentEl.appendChild(tempEl);\n tempEl.style.position = 'absolute';\n tempEl.style.width = baseline + unit;\n var factor = baseline / tempEl.offsetWidth;\n parentEl.removeChild(tempEl);\n var convertedUnit = factor * parseFloat(value);\n cache.CSS[value + unit] = convertedUnit;\n return convertedUnit;\n}\nfunction getCSSValue(el, prop, unit) {\n if (prop in el.style) {\n var uppercasePropName = prop.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();\n var value = el.style[prop] || getComputedStyle(el).getPropertyValue(uppercasePropName) || '0';\n return unit ? convertPxToUnit(el, value, unit) : value;\n }\n}\nfunction getAnimationType(el, prop) {\n if (is.dom(el) && !is.inp(el) && (getAttribute(el, prop) || is.svg(el) && el[prop])) {\n return 'attribute';\n }\n if (is.dom(el) && arrayContains(validTransforms, prop)) {\n return 'transform';\n }\n if (is.dom(el) && prop !== 'transform' && getCSSValue(el, prop)) {\n return 'css';\n }\n if (el[prop] != null) {\n return 'object';\n }\n}\nvar transformRegex = /(\\w+)\\(([^)]*)\\)/g;\nfunction getElementTransforms(el) {\n if (!is.dom(el)) {\n return;\n }\n var str = el.style.transform || '';\n var transforms = new Map();\n var m;\n while (m = transformRegex.exec(str)) {\n transforms.set(m[1], m[2]);\n }\n return transforms;\n}\nfunction getTransformValue(el, propName, animatable, unit) {\n var defaultVal = stringContains(propName, 'scale') ? 1 : 0 + getTransformUnit(propName);\n var value = getElementTransforms(el).get(propName) || defaultVal;\n if (animatable) {\n animatable.transforms.list.set(propName, value);\n animatable.transforms['last'] = propName;\n }\n return unit ? convertPxToUnit(el, value, unit) : value;\n}\nfunction getOriginalTargetValue(target, propName, unit, animatable) {\n switch (getAnimationType(target, propName)) {\n case 'transform':\n return getTransformValue(target, propName, animatable, unit);\n case 'css':\n return getCSSValue(target, propName, unit);\n case 'attribute':\n return getAttribute(target, propName);\n default:\n return target[propName] || 0;\n }\n}\nvar operatorRegex = /^(\\*=|\\+=|-=)/;\nfunction getRelativeValue(to, from) {\n var operator = operatorRegex.exec(to);\n if (!operator) {\n return to;\n }\n var u = getUnit(to) || 0;\n var x = parseFloat(from);\n var y = parseFloat(to.replace(operator[0], ''));\n switch (operator[0][0]) {\n case '+':\n return x + y + u;\n case '-':\n return x - y + u;\n case '*':\n return x * y + u;\n }\n}\nvar whitespaceRegex = /\\s/g;\nfunction validateValue(val, unit) {\n if (is.col(val)) {\n return colorToRgb(val);\n }\n var originalUnit = getUnit(val);\n var unitLess = originalUnit ? val.substr(0, val.length - originalUnit.length) : val;\n return unit && !whitespaceRegex.test(val) ? unitLess + unit : unitLess;\n}\n\n// getTotalLength() equivalent for circle, rect, polyline, polygon and line shapes\n// adapted from https://gist.github.com/SebLambla/3e0550c496c236709744\n\nfunction getDistance(p1, p2) {\n return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));\n}\nfunction getCircleLength(el) {\n return Math.PI * 2 * getAttribute(el, 'r');\n}\nfunction getRectLength(el) {\n return getAttribute(el, 'width') * 2 + getAttribute(el, 'height') * 2;\n}\nfunction getLineLength(el) {\n return getDistance({\n x: getAttribute(el, 'x1'),\n y: getAttribute(el, 'y1')\n }, {\n x: getAttribute(el, 'x2'),\n y: getAttribute(el, 'y2')\n });\n}\nfunction getPolylineLength(el) {\n var points = el.points;\n var totalLength = 0;\n var previousPos;\n for (var i = 0; i < points.numberOfItems; i++) {\n var currentPos = points.getItem(i);\n if (i > 0) {\n totalLength += getDistance(previousPos, currentPos);\n }\n previousPos = currentPos;\n }\n return totalLength;\n}\nfunction getPolygonLength(el) {\n var points = el.points;\n return getPolylineLength(el) + getDistance(points.getItem(points.numberOfItems - 1), points.getItem(0));\n}\n\n// Path animation\n\nfunction getTotalLength(el) {\n if (el.getTotalLength) {\n return el.getTotalLength();\n }\n switch (el.tagName.toLowerCase()) {\n case 'circle':\n return getCircleLength(el);\n case 'rect':\n return getRectLength(el);\n case 'line':\n return getLineLength(el);\n case 'polyline':\n return getPolylineLength(el);\n case 'polygon':\n return getPolygonLength(el);\n }\n}\nfunction setDashoffset(el) {\n var pathLength = getTotalLength(el);\n el.setAttribute('stroke-dasharray', pathLength);\n return pathLength;\n}\n\n// Motion path\n\nfunction getParentSvgEl(el) {\n var parentEl = el.parentNode;\n while (is.svg(parentEl)) {\n parentEl = parentEl.parentNode;\n if (!is.svg(parentEl.parentNode)) {\n break;\n }\n }\n return parentEl;\n}\nfunction getParentSvg(pathEl, svgData) {\n var svg = svgData || {};\n var parentSvgEl = svg.el || getParentSvgEl(pathEl);\n var rect = parentSvgEl.getBoundingClientRect();\n var viewBoxAttr = getAttribute(parentSvgEl, 'viewBox');\n var width = rect.width;\n var height = rect.height;\n var viewBox = svg.viewBox || (viewBoxAttr ? viewBoxAttr.split(' ') : [0, 0, width, height]);\n return {\n el: parentSvgEl,\n viewBox: viewBox,\n x: viewBox[0] / 1,\n y: viewBox[1] / 1,\n w: width / viewBox[2],\n h: height / viewBox[3]\n };\n}\nfunction getPath(path, percent) {\n var pathEl = is.str(path) ? selectString(path)[0] : path;\n var p = percent || 100;\n return function (property) {\n return {\n property: property,\n el: pathEl,\n svg: getParentSvg(pathEl),\n totalLength: getTotalLength(pathEl) * (p / 100)\n };\n };\n}\nfunction getPathProgress(path, progress) {\n function point(offset) {\n if (offset === void 0) offset = 0;\n var l = progress + offset >= 1 ? progress + offset : 0;\n return path.el.getPointAtLength(l);\n }\n var svg = getParentSvg(path.el, path.svg);\n var p = point();\n var p0 = point(-1);\n var p1 = point(+1);\n switch (path.property) {\n case 'x':\n return (p.x - svg.x) * svg.w;\n case 'y':\n return (p.y - svg.y) * svg.h;\n case 'angle':\n return Math.atan2(p1.y - p0.y, p1.x - p0.x) * 180 / Math.PI;\n }\n}\n\n// Decompose value\n\nvar valueRegex = /-?\\d*\\.?\\d+/g;\nfunction decomposeValue(val, unit) {\n var value = validateValue(is.pth(val) ? val.totalLength : val, unit) + '';\n return {\n original: value,\n numbers: value.match(valueRegex) ? value.match(valueRegex).map(Number) : [0],\n strings: is.str(val) || unit ? value.split(valueRegex) : []\n };\n}\n\n// Animatables\n\nfunction parseTargets(targets) {\n var targetsArray = targets ? flattenArray(is.arr(targets) ? targets.map(toArray) : toArray(targets)) : [];\n return filterArray(targetsArray, function (item, pos, self) {\n return self.indexOf(item) === pos;\n });\n}\nfunction getAnimatables(targets) {\n var parsed = parseTargets(targets);\n return parsed.map(function (t, i) {\n return {\n target: t,\n id: i,\n total: parsed.length,\n transforms: {\n list: getElementTransforms(t)\n }\n };\n });\n}\n\n// Properties\n\nvar springRegex = /^spring/;\nfunction normalizePropertyTweens(prop, tweenSettings) {\n var settings = cloneObject(tweenSettings);\n // Override duration if easing is a spring\n if (springRegex.test(settings.easing)) {\n settings.duration = spring(settings.easing);\n }\n if (is.arr(prop)) {\n var l = prop.length;\n var isFromTo = l === 2 && !is.obj(prop[0]);\n if (!isFromTo) {\n // Duration divided by the number of tweens\n if (!is.fnc(tweenSettings.duration)) {\n settings.duration = tweenSettings.duration / l;\n }\n } else {\n // Transform [from, to] values shorthand to a valid tween value\n prop = {\n value: prop\n };\n }\n }\n var propArray = is.arr(prop) ? prop : [prop];\n return propArray.map(function (v, i) {\n var obj = is.obj(v) && !is.pth(v) ? v : {\n value: v\n };\n // Default delay value should only be applied to the first tween\n if (is.und(obj.delay)) {\n obj.delay = !i ? tweenSettings.delay : 0;\n }\n // Default endDelay value should only be applied to the last tween\n if (is.und(obj.endDelay)) {\n obj.endDelay = i === propArray.length - 1 ? tweenSettings.endDelay : 0;\n }\n return obj;\n }).map(function (k) {\n return mergeObjects(k, settings);\n });\n}\nfunction flattenKeyframes(keyframes) {\n var propertyNames = filterArray(flattenArray(keyframes.map(function (key) {\n return Object.keys(key);\n })), function (p) {\n return is.key(p);\n }).reduce(function (a, b) {\n if (a.indexOf(b) < 0) {\n a.push(b);\n }\n return a;\n }, []);\n var properties = {};\n var loop = function (i) {\n var propName = propertyNames[i];\n properties[propName] = keyframes.map(function (key) {\n var newKey = {};\n for (var p in key) {\n if (is.key(p)) {\n if (p == propName) {\n newKey.value = key[p];\n }\n } else {\n newKey[p] = key[p];\n }\n }\n return newKey;\n });\n };\n for (var i = 0; i < propertyNames.length; i++) loop(i);\n return properties;\n}\nfunction getProperties(tweenSettings, params) {\n var properties = [];\n var keyframes = params.keyframes;\n if (keyframes) {\n params = mergeObjects(flattenKeyframes(keyframes), params);\n }\n for (var p in params) {\n if (is.key(p)) {\n properties.push({\n name: p,\n tweens: normalizePropertyTweens(params[p], tweenSettings)\n });\n }\n }\n return properties;\n}\n\n// Tweens\n\nfunction normalizeTweenValues(tween, animatable) {\n var t = {};\n for (var p in tween) {\n var value = getFunctionValue(tween[p], animatable);\n if (is.arr(value)) {\n value = value.map(function (v) {\n return getFunctionValue(v, animatable);\n });\n if (value.length === 1) {\n value = value[0];\n }\n }\n t[p] = value;\n }\n t.duration = parseFloat(t.duration);\n t.delay = parseFloat(t.delay);\n return t;\n}\nfunction normalizeTweens(prop, animatable) {\n var previousTween;\n return prop.tweens.map(function (t) {\n var tween = normalizeTweenValues(t, animatable);\n var tweenValue = tween.value;\n var to = is.arr(tweenValue) ? tweenValue[1] : tweenValue;\n var toUnit = getUnit(to);\n var originalValue = getOriginalTargetValue(animatable.target, prop.name, toUnit, animatable);\n var previousValue = previousTween ? previousTween.to.original : originalValue;\n var from = is.arr(tweenValue) ? tweenValue[0] : previousValue;\n var fromUnit = getUnit(from) || getUnit(originalValue);\n var unit = toUnit || fromUnit;\n if (is.und(to)) {\n to = previousValue;\n }\n tween.from = decomposeValue(from, unit);\n tween.to = decomposeValue(getRelativeValue(to, from), unit);\n tween.start = previousTween ? previousTween.end : 0;\n tween.end = tween.start + tween.delay + tween.duration + tween.endDelay;\n tween.easing = parseEasings(tween.easing, tween.duration);\n tween.isPath = is.pth(tweenValue);\n tween.isColor = is.col(tween.from.original);\n if (tween.isColor) {\n tween.round = 1;\n }\n previousTween = tween;\n return tween;\n });\n}\n\n// Tween progress\n\nvar setProgressValue = {\n css: function (t, p, v) {\n return t.style[p] = v;\n },\n attribute: function (t, p, v) {\n return t.setAttribute(p, v);\n },\n object: function (t, p, v) {\n return t[p] = v;\n },\n transform: function (t, p, v, transforms, manual) {\n transforms.list.set(p, v);\n if (p === transforms.last || manual) {\n var str = '';\n transforms.list.forEach(function (value, prop) {\n str += prop + \"(\" + value + \") \";\n });\n t.style.transform = str;\n }\n }\n};\n\n// Set Value helper\n\nfunction setTargetsValue(targets, properties) {\n var animatables = getAnimatables(targets);\n for (var i = 0, len = animatables.length; i < len; i++) {\n var animatable = animatables[i];\n for (var property in properties) {\n var value = getFunctionValue(properties[property], animatable);\n var target = animatable.target;\n var valueUnit = getUnit(value);\n var originalValue = getOriginalTargetValue(target, property, valueUnit, animatable);\n var unit = valueUnit || getUnit(originalValue);\n var to = getRelativeValue(validateValue(value, unit), originalValue);\n var animType = getAnimationType(target, property);\n setProgressValue[animType](target, property, to, animatable.transforms, true);\n }\n }\n}\n\n// Animations\n\nfunction createAnimation(animatable, prop) {\n var animType = getAnimationType(animatable.target, prop.name);\n if (animType) {\n var tweens = normalizeTweens(prop, animatable);\n var lastTween = tweens[tweens.length - 1];\n return {\n type: animType,\n property: prop.name,\n animatable: animatable,\n tweens: tweens,\n duration: lastTween.end,\n delay: tweens[0].delay,\n endDelay: lastTween.endDelay\n };\n }\n}\nfunction getAnimations(animatables, properties) {\n return filterArray(flattenArray(animatables.map(function (animatable) {\n return properties.map(function (prop) {\n return createAnimation(animatable, prop);\n });\n })), function (a) {\n return !is.und(a);\n });\n}\n\n// Create Instance\n\nfunction getInstanceTimings(animations, tweenSettings) {\n var animLength = animations.length;\n var getTlOffset = function (anim) {\n return anim.timelineOffset ? anim.timelineOffset : 0;\n };\n var timings = {};\n timings.duration = animLength ? Math.max.apply(Math, animations.map(function (anim) {\n return getTlOffset(anim) + anim.duration;\n })) : tweenSettings.duration;\n timings.delay = animLength ? Math.min.apply(Math, animations.map(function (anim) {\n return getTlOffset(anim) + anim.delay;\n })) : tweenSettings.delay;\n timings.endDelay = animLength ? timings.duration - Math.max.apply(Math, animations.map(function (anim) {\n return getTlOffset(anim) + anim.duration - anim.endDelay;\n })) : tweenSettings.endDelay;\n return timings;\n}\nvar instanceID = 0;\nfunction createNewInstance(params) {\n var instanceSettings = replaceObjectProps(defaultInstanceSettings, params);\n var tweenSettings = replaceObjectProps(defaultTweenSettings, params);\n var properties = getProperties(tweenSettings, params);\n var animatables = getAnimatables(params.targets);\n var animations = getAnimations(animatables, properties);\n var timings = getInstanceTimings(animations, tweenSettings);\n var id = instanceID;\n instanceID++;\n return mergeObjects(instanceSettings, {\n id: id,\n children: [],\n animatables: animatables,\n animations: animations,\n duration: timings.duration,\n delay: timings.delay,\n endDelay: timings.endDelay\n });\n}\n\n// Core\n\nvar activeInstances = [];\nvar pausedInstances = [];\nvar raf;\nvar engine = function () {\n function play() {\n raf = requestAnimationFrame(step);\n }\n function step(t) {\n var activeInstancesLength = activeInstances.length;\n if (activeInstancesLength) {\n var i = 0;\n while (i < activeInstancesLength) {\n var activeInstance = activeInstances[i];\n if (!activeInstance.paused) {\n activeInstance.tick(t);\n } else {\n var instanceIndex = activeInstances.indexOf(activeInstance);\n if (instanceIndex > -1) {\n activeInstances.splice(instanceIndex, 1);\n activeInstancesLength = activeInstances.length;\n }\n }\n i++;\n }\n play();\n } else {\n raf = cancelAnimationFrame(raf);\n }\n }\n return play;\n}();\nfunction handleVisibilityChange() {\n if (document.hidden) {\n for (var i = 0, len = activeInstances.length; i < len; i++) {\n activeInstance[i].pause();\n }\n pausedInstances = activeInstances.slice(0);\n activeInstances = [];\n } else {\n for (var i$1 = 0, len$1 = pausedInstances.length; i$1 < len$1; i$1++) {\n pausedInstances[i$1].play();\n }\n }\n}\ndocument.addEventListener('visibilitychange', handleVisibilityChange);\n\n// Public Instance\n\nfunction anime(params) {\n if (params === void 0) params = {};\n var startTime = 0,\n lastTime = 0,\n now = 0;\n var children,\n childrenLength = 0;\n var resolve = null;\n function makePromise() {\n return window.Promise && new Promise(function (_resolve) {\n return resolve = _resolve;\n });\n }\n var promise = makePromise();\n var instance = createNewInstance(params);\n function toggleInstanceDirection() {\n instance.reversed = !instance.reversed;\n for (var i = 0, len = children.length; i < len; i++) {\n children[i].reversed = instance.reversed;\n }\n }\n function adjustTime(time) {\n return instance.reversed ? instance.duration - time : time;\n }\n function resetTime() {\n startTime = 0;\n lastTime = adjustTime(instance.currentTime) * (1 / anime.speed);\n }\n function seekCild(time, child) {\n if (child) {\n child.seek(time - child.timelineOffset);\n }\n }\n function syncInstanceChildren(time) {\n if (!instance.reversePlayback) {\n for (var i = 0; i < childrenLength; i++) {\n seekCild(time, children[i]);\n }\n } else {\n for (var i$1 = childrenLength; i$1--;) {\n seekCild(time, children[i$1]);\n }\n }\n }\n function setAnimationsProgress(insTime) {\n var i = 0;\n var animations = instance.animations;\n var animationsLength = animations.length;\n while (i < animationsLength) {\n var anim = animations[i];\n var animatable = anim.animatable;\n var tweens = anim.tweens;\n var tweenLength = tweens.length - 1;\n var tween = tweens[tweenLength];\n // Only check for keyframes if there is more than one tween\n if (tweenLength) {\n tween = filterArray(tweens, function (t) {\n return insTime < t.end;\n })[0] || tween;\n }\n var elapsed = minMax(insTime - tween.start - tween.delay, 0, tween.duration) / tween.duration;\n var eased = isNaN(elapsed) ? 1 : tween.easing(elapsed);\n var strings = tween.to.strings;\n var round = tween.round;\n var numbers = [];\n var toNumbersLength = tween.to.numbers.length;\n var progress = void 0;\n for (var n = 0; n < toNumbersLength; n++) {\n var value = void 0;\n var toNumber = tween.to.numbers[n];\n var fromNumber = tween.from.numbers[n] || 0;\n if (!tween.isPath) {\n value = fromNumber + eased * (toNumber - fromNumber);\n } else {\n value = getPathProgress(tween.value, eased * toNumber);\n }\n if (round) {\n if (!(tween.isColor && n > 2)) {\n value = Math.round(value * round) / round;\n }\n }\n numbers.push(value);\n }\n // Manual Array.reduce for better performances\n var stringsLength = strings.length;\n if (!stringsLength) {\n progress = numbers[0];\n } else {\n progress = strings[0];\n for (var s = 0; s < stringsLength; s++) {\n var a = strings[s];\n var b = strings[s + 1];\n var n$1 = numbers[s];\n if (!isNaN(n$1)) {\n if (!b) {\n progress += n$1 + ' ';\n } else {\n progress += n$1 + b;\n }\n }\n }\n }\n setProgressValue[anim.type](animatable.target, anim.property, progress, animatable.transforms);\n anim.currentValue = progress;\n i++;\n }\n }\n function setCallback(cb) {\n if (instance[cb] && !instance.passThrough) {\n instance[cb](instance);\n }\n }\n function countIteration() {\n if (instance.remaining && instance.remaining !== true) {\n instance.remaining--;\n }\n }\n function setInstanceProgress(engineTime) {\n var insDuration = instance.duration;\n var insDelay = instance.delay;\n var insEndDelay = insDuration - instance.endDelay;\n var insTime = adjustTime(engineTime);\n instance.progress = minMax(insTime / insDuration * 100, 0, 100);\n instance.reversePlayback = insTime < instance.currentTime;\n if (children) {\n syncInstanceChildren(insTime);\n }\n if (!instance.began && instance.currentTime > 0) {\n instance.began = true;\n setCallback('begin');\n setCallback('loopBegin');\n }\n if (insTime <= insDelay && instance.currentTime !== 0) {\n setAnimationsProgress(0);\n }\n if (insTime >= insEndDelay && instance.currentTime !== insDuration || !insDuration) {\n setAnimationsProgress(insDuration);\n }\n if (insTime > insDelay && insTime < insEndDelay) {\n if (!instance.changeBegan) {\n instance.changeBegan = true;\n instance.changeCompleted = false;\n setCallback('changeBegin');\n }\n setCallback('change');\n setAnimationsProgress(insTime);\n } else {\n if (instance.changeBegan) {\n instance.changeCompleted = true;\n instance.changeBegan = false;\n setCallback('changeComplete');\n }\n }\n instance.currentTime = minMax(insTime, 0, insDuration);\n if (instance.began) {\n setCallback('update');\n }\n if (engineTime >= insDuration) {\n lastTime = 0;\n countIteration();\n if (instance.remaining) {\n startTime = now;\n setCallback('loopComplete');\n setCallback('loopBegin');\n if (instance.direction === 'alternate') {\n toggleInstanceDirection();\n }\n } else {\n instance.paused = true;\n if (!instance.completed) {\n instance.completed = true;\n setCallback('loopComplete');\n setCallback('complete');\n if ('Promise' in window) {\n resolve();\n promise = makePromise();\n }\n }\n }\n }\n }\n instance.reset = function () {\n var direction = instance.direction;\n instance.passThrough = false;\n instance.currentTime = 0;\n instance.progress = 0;\n instance.paused = true;\n instance.began = false;\n instance.changeBegan = false;\n instance.completed = false;\n instance.changeCompleted = false;\n instance.reversePlayback = false;\n instance.reversed = direction === 'reverse';\n instance.remaining = instance.loop;\n children = instance.children;\n childrenLength = children.length;\n for (var i = childrenLength; i--;) {\n instance.children[i].reset();\n }\n if (instance.reversed && instance.loop !== true || direction === 'alternate' && instance.loop === 1) {\n instance.remaining++;\n }\n setAnimationsProgress(0);\n };\n\n // Set Value helper\n\n instance.set = function (targets, properties) {\n setTargetsValue(targets, properties);\n return instance;\n };\n instance.tick = function (t) {\n now = t;\n if (!startTime) {\n startTime = now;\n }\n setInstanceProgress((now + (lastTime - startTime)) * anime.speed);\n };\n instance.seek = function (time) {\n setInstanceProgress(adjustTime(time));\n };\n instance.pause = function () {\n instance.paused = true;\n resetTime();\n };\n instance.play = function () {\n if (!instance.paused) {\n return;\n }\n instance.paused = false;\n activeInstances.push(instance);\n resetTime();\n if (!raf) {\n engine();\n }\n };\n instance.reverse = function () {\n toggleInstanceDirection();\n resetTime();\n };\n instance.restart = function () {\n instance.reset();\n instance.play();\n };\n instance.finished = promise;\n instance.reset();\n if (instance.autoplay) {\n instance.play();\n }\n return instance;\n}\n\n// Remove targets from animation\n\nfunction removeTargetsFromAnimations(targetsArray, animations) {\n for (var a = animations.length; a--;) {\n if (arrayContains(targetsArray, animations[a].animatable.target)) {\n animations.splice(a, 1);\n }\n }\n}\nfunction removeTargets(targets) {\n var targetsArray = parseTargets(targets);\n for (var i = activeInstances.length; i--;) {\n var instance = activeInstances[i];\n var animations = instance.animations;\n var children = instance.children;\n removeTargetsFromAnimations(targetsArray, animations);\n for (var c = children.length; c--;) {\n var child = children[c];\n var childAnimations = child.animations;\n removeTargetsFromAnimations(targetsArray, childAnimations);\n if (!childAnimations.length && !child.children.length) {\n children.splice(c, 1);\n }\n }\n if (!animations.length && !children.length) {\n instance.pause();\n }\n }\n}\n\n// Stagger helpers\n\nfunction stagger(val, params) {\n if (params === void 0) params = {};\n var direction = params.direction || 'normal';\n var easing = params.easing ? parseEasings(params.easing) : null;\n var grid = params.grid;\n var axis = params.axis;\n var fromIndex = params.from || 0;\n var fromFirst = fromIndex === 'first';\n var fromCenter = fromIndex === 'center';\n var fromLast = fromIndex === 'last';\n var isRange = is.arr(val);\n var val1 = isRange ? parseFloat(val[0]) : parseFloat(val);\n var val2 = isRange ? parseFloat(val[1]) : 0;\n var unit = getUnit(isRange ? val[1] : val) || 0;\n var start = params.start || 0 + (isRange ? val1 : 0);\n var values = [];\n var maxValue = 0;\n return function (el, i, t) {\n if (fromFirst) {\n fromIndex = 0;\n }\n if (fromCenter) {\n fromIndex = (t - 1) / 2;\n }\n if (fromLast) {\n fromIndex = t - 1;\n }\n if (!values.length) {\n for (var index = 0; index < t; index++) {\n if (!grid) {\n values.push(Math.abs(fromIndex - index));\n } else {\n var fromX = !fromCenter ? fromIndex % grid[0] : (grid[0] - 1) / 2;\n var fromY = !fromCenter ? Math.floor(fromIndex / grid[0]) : (grid[1] - 1) / 2;\n var toX = index % grid[0];\n var toY = Math.floor(index / grid[0]);\n var distanceX = fromX - toX;\n var distanceY = fromY - toY;\n var value = Math.sqrt(distanceX * distanceX + distanceY * distanceY);\n if (axis === 'x') {\n value = -distanceX;\n }\n if (axis === 'y') {\n value = -distanceY;\n }\n values.push(value);\n }\n maxValue = Math.max.apply(Math, values);\n }\n if (easing) {\n values = values.map(function (val) {\n return easing(val / maxValue) * maxValue;\n });\n }\n if (direction === 'reverse') {\n values = values.map(function (val) {\n return axis ? val < 0 ? val * -1 : -val : Math.abs(maxValue - val);\n });\n }\n }\n var spacing = isRange ? (val2 - val1) / maxValue : val1;\n return start + spacing * (Math.round(values[i] * 100) / 100) + unit;\n };\n}\n\n// Timeline\n\nfunction timeline(params) {\n if (params === void 0) params = {};\n var tl = anime(params);\n tl.duration = 0;\n tl.add = function (instanceParams, timelineOffset) {\n var tlIndex = activeInstances.indexOf(tl);\n var children = tl.children;\n if (tlIndex > -1) {\n activeInstances.splice(tlIndex, 1);\n }\n function passThrough(ins) {\n ins.passThrough = true;\n }\n for (var i = 0; i < children.length; i++) {\n passThrough(children[i]);\n }\n var insParams = mergeObjects(instanceParams, replaceObjectProps(defaultTweenSettings, params));\n insParams.targets = insParams.targets || params.targets;\n var tlDuration = tl.duration;\n insParams.autoplay = false;\n insParams.direction = tl.direction;\n insParams.timelineOffset = is.und(timelineOffset) ? tlDuration : getRelativeValue(timelineOffset, tlDuration);\n passThrough(tl);\n tl.seek(insParams.timelineOffset);\n var ins = anime(insParams);\n passThrough(ins);\n children.push(ins);\n var timings = getInstanceTimings(children, params);\n tl.delay = timings.delay;\n tl.endDelay = timings.endDelay;\n tl.duration = timings.duration;\n tl.seek(0);\n tl.reset();\n if (tl.autoplay) {\n tl.play();\n }\n return tl;\n };\n return tl;\n}\nanime.version = '3.0.0';\nanime.speed = 1;\nanime.running = activeInstances;\nanime.remove = removeTargets;\nanime.get = getOriginalTargetValue;\nanime.set = setTargetsValue;\nanime.convertPx = convertPxToUnit;\nanime.path = getPath;\nanime.setDashoffset = setDashoffset;\nanime.stagger = stagger;\nanime.timeline = timeline;\nanime.easing = parseEasings;\nanime.penner = penner;\nanime.random = function (min, max) {\n return Math.floor(Math.random() * (max - min + 1)) + min;\n};\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (anime);\n\n/***/ }),\n\n/***/ \"./node_modules/three-bmfont-text/index.js\":\n/*!*************************************************!*\\\n !*** ./node_modules/three-bmfont-text/index.js ***!\n \\*************************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar createLayout = __webpack_require__(/*! layout-bmfont-text */ \"./node_modules/layout-bmfont-text/index.js\");\nvar createIndices = __webpack_require__(/*! quad-indices */ \"./node_modules/quad-indices/index.js\");\nvar vertices = __webpack_require__(/*! ./lib/vertices */ \"./node_modules/three-bmfont-text/lib/vertices.js\");\nvar utils = __webpack_require__(/*! ./lib/utils */ \"./node_modules/three-bmfont-text/lib/utils.js\");\nmodule.exports = function createTextGeometry(opt) {\n return new TextGeometry(opt);\n};\nclass TextGeometry extends THREE.BufferGeometry {\n constructor(opt) {\n super();\n if (typeof opt === 'string') {\n opt = {\n text: opt\n };\n }\n\n // use these as default values for any subsequent\n // calls to update()\n this._opt = Object.assign({}, opt);\n\n // also do an initial setup...\n if (opt) this.update(opt);\n }\n update(opt) {\n if (typeof opt === 'string') {\n opt = {\n text: opt\n };\n }\n\n // use constructor defaults\n opt = Object.assign({}, this._opt, opt);\n if (!opt.font) {\n throw new TypeError('must specify a { font } in options');\n }\n this.layout = createLayout(opt);\n\n // get vec2 texcoords\n var flipY = opt.flipY !== false;\n\n // the desired BMFont data\n var font = opt.font;\n\n // determine texture size from font file\n var texWidth = font.common.scaleW;\n var texHeight = font.common.scaleH;\n\n // get visible glyphs\n var glyphs = this.layout.glyphs.filter(function (glyph) {\n var bitmap = glyph.data;\n return bitmap.width * bitmap.height > 0;\n });\n\n // provide visible glyphs for convenience\n this.visibleGlyphs = glyphs;\n\n // get common vertex data\n var positions = vertices.positions(glyphs);\n var uvs = vertices.uvs(glyphs, texWidth, texHeight, flipY);\n var indices = createIndices([], {\n clockwise: true,\n type: 'uint16',\n count: glyphs.length\n });\n\n // update vertex data\n this.setIndex(indices);\n this.setAttribute('position', new THREE.BufferAttribute(positions, 2));\n this.setAttribute('uv', new THREE.BufferAttribute(uvs, 2));\n\n // update multipage data\n if (!opt.multipage && 'page' in this.attributes) {\n // disable multipage rendering\n this.removeAttribute('page');\n } else if (opt.multipage) {\n // enable multipage rendering\n var pages = vertices.pages(glyphs);\n this.setAttribute('page', new THREE.BufferAttribute(pages, 1));\n }\n\n // recompute bounding box and sphere, if present\n if (this.boundingBox !== null) {\n this.computeBoundingBox();\n }\n if (this.boundingSphere !== null) {\n this.computeBoundingSphere();\n }\n }\n computeBoundingSphere() {\n if (this.boundingSphere === null) {\n this.boundingSphere = new THREE.Sphere();\n }\n var positions = this.attributes.position.array;\n var itemSize = this.attributes.position.itemSize;\n if (!positions || !itemSize || positions.length < 2) {\n this.boundingSphere.radius = 0;\n this.boundingSphere.center.set(0, 0, 0);\n return;\n }\n utils.computeSphere(positions, this.boundingSphere);\n if (isNaN(this.boundingSphere.radius)) {\n console.error('THREE.BufferGeometry.computeBoundingSphere(): ' + 'Computed radius is NaN. The ' + '\"position\" attribute is likely to have NaN values.');\n }\n }\n computeBoundingBox() {\n if (this.boundingBox === null) {\n this.boundingBox = new THREE.Box3();\n }\n var bbox = this.boundingBox;\n var positions = this.attributes.position.array;\n var itemSize = this.attributes.position.itemSize;\n if (!positions || !itemSize || positions.length < 2) {\n bbox.makeEmpty();\n return;\n }\n utils.computeBox(positions, bbox);\n }\n}\n\n/***/ }),\n\n/***/ \"./node_modules/three-bmfont-text/lib/utils.js\":\n/*!*****************************************************!*\\\n !*** ./node_modules/three-bmfont-text/lib/utils.js ***!\n \\*****************************************************/\n/***/ ((module) => {\n\nvar itemSize = 2;\nvar box = {\n min: [0, 0],\n max: [0, 0]\n};\nfunction bounds(positions) {\n var count = positions.length / itemSize;\n box.min[0] = positions[0];\n box.min[1] = positions[1];\n box.max[0] = positions[0];\n box.max[1] = positions[1];\n for (var i = 0; i < count; i++) {\n var x = positions[i * itemSize + 0];\n var y = positions[i * itemSize + 1];\n box.min[0] = Math.min(x, box.min[0]);\n box.min[1] = Math.min(y, box.min[1]);\n box.max[0] = Math.max(x, box.max[0]);\n box.max[1] = Math.max(y, box.max[1]);\n }\n}\nmodule.exports.computeBox = function (positions, output) {\n bounds(positions);\n output.min.set(box.min[0], box.min[1], 0);\n output.max.set(box.max[0], box.max[1], 0);\n};\nmodule.exports.computeSphere = function (positions, output) {\n bounds(positions);\n var minX = box.min[0];\n var minY = box.min[1];\n var maxX = box.max[0];\n var maxY = box.max[1];\n var width = maxX - minX;\n var height = maxY - minY;\n var length = Math.sqrt(width * width + height * height);\n output.center.set(minX + width / 2, minY + height / 2, 0);\n output.radius = length / 2;\n};\n\n/***/ }),\n\n/***/ \"./node_modules/three-bmfont-text/lib/vertices.js\":\n/*!********************************************************!*\\\n !*** ./node_modules/three-bmfont-text/lib/vertices.js ***!\n \\********************************************************/\n/***/ ((module) => {\n\nmodule.exports.pages = function pages(glyphs) {\n var pages = new Float32Array(glyphs.length * 4 * 1);\n var i = 0;\n glyphs.forEach(function (glyph) {\n var id = glyph.data.page || 0;\n pages[i++] = id;\n pages[i++] = id;\n pages[i++] = id;\n pages[i++] = id;\n });\n return pages;\n};\nmodule.exports.uvs = function uvs(glyphs, texWidth, texHeight, flipY) {\n var uvs = new Float32Array(glyphs.length * 4 * 2);\n var i = 0;\n glyphs.forEach(function (glyph) {\n var bitmap = glyph.data;\n var bw = bitmap.x + bitmap.width;\n var bh = bitmap.y + bitmap.height;\n\n // top left position\n var u0 = bitmap.x / texWidth;\n var v1 = bitmap.y / texHeight;\n var u1 = bw / texWidth;\n var v0 = bh / texHeight;\n if (flipY) {\n v1 = (texHeight - bitmap.y) / texHeight;\n v0 = (texHeight - bh) / texHeight;\n }\n\n // BL\n uvs[i++] = u0;\n uvs[i++] = v1;\n // TL\n uvs[i++] = u0;\n uvs[i++] = v0;\n // TR\n uvs[i++] = u1;\n uvs[i++] = v0;\n // BR\n uvs[i++] = u1;\n uvs[i++] = v1;\n });\n return uvs;\n};\nmodule.exports.positions = function positions(glyphs) {\n var positions = new Float32Array(glyphs.length * 4 * 2);\n var i = 0;\n glyphs.forEach(function (glyph) {\n var bitmap = glyph.data;\n\n // bottom left position\n var x = glyph.position[0] + bitmap.xoffset;\n var y = glyph.position[1] + bitmap.yoffset;\n\n // quad size\n var w = bitmap.width;\n var h = bitmap.height;\n\n // BL\n positions[i++] = x;\n positions[i++] = y;\n // TL\n positions[i++] = x;\n positions[i++] = y + h;\n // TR\n positions[i++] = x + w;\n positions[i++] = y + h;\n // BR\n positions[i++] = x + w;\n positions[i++] = y;\n });\n return positions;\n};\n\n/***/ }),\n\n/***/ \"./node_modules/webvr-polyfill/build/webvr-polyfill.js\":\n/*!*************************************************************!*\\\n !*** ./node_modules/webvr-polyfill/build/webvr-polyfill.js ***!\n \\*************************************************************/\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\n/**\n * @license\n * webvr-polyfill\n * Copyright (c) 2015-2017 Google\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * @license\n * cardboard-vr-display\n * Copyright (c) 2015-2017 Google\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * @license\n * webvr-polyfill-dpdb \n * Copyright (c) 2017 Google\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * @license\n * wglu-preserve-state\n * Copyright (c) 2016, Brandon Jones.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n/**\n * @license\n * nosleep.js\n * Copyright (c) 2017, Rich Tibbett\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n(function (global, factory) {\n true ? module.exports = factory() : 0;\n})(this, function () {\n 'use strict';\n\n var commonjsGlobal = typeof window !== 'undefined' ? window : typeof __webpack_require__.g !== 'undefined' ? __webpack_require__.g : typeof self !== 'undefined' ? self : {};\n function unwrapExports(x) {\n return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;\n }\n function createCommonjsModule(fn, module) {\n return module = {\n exports: {}\n }, fn(module, module.exports), module.exports;\n }\n var isMobile = function isMobile() {\n return /Android/i.test(navigator.userAgent) || /iPhone|iPad|iPod/i.test(navigator.userAgent);\n };\n var copyArray = function copyArray(source, dest) {\n for (var i = 0, n = source.length; i < n; i++) {\n dest[i] = source[i];\n }\n };\n var extend = function extend(dest, src) {\n for (var key in src) {\n if (src.hasOwnProperty(key)) {\n dest[key] = src[key];\n }\n }\n return dest;\n };\n var cardboardVrDisplay = createCommonjsModule(function (module, exports) {\n /**\n * @license\n * cardboard-vr-display\n * Copyright (c) 2015-2017 Google\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n /**\n * @license\n * gl-preserve-state\n * Copyright (c) 2016, Brandon Jones.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n /**\n * @license\n * webvr-polyfill-dpdb\n * Copyright (c) 2015-2017 Google\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n /**\n * @license\n * nosleep.js\n * Copyright (c) 2017, Rich Tibbett\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n (function (global, factory) {\n module.exports = factory();\n })(commonjsGlobal, function () {\n var classCallCheck = function (instance, Constructor) {\n if (!(instance instanceof Constructor)) {\n throw new TypeError(\"Cannot call a class as a function\");\n }\n };\n var createClass = function () {\n function defineProperties(target, props) {\n for (var i = 0; i < props.length; i++) {\n var descriptor = props[i];\n descriptor.enumerable = descriptor.enumerable || false;\n descriptor.configurable = true;\n if (\"value\" in descriptor) descriptor.writable = true;\n Object.defineProperty(target, descriptor.key, descriptor);\n }\n }\n return function (Constructor, protoProps, staticProps) {\n if (protoProps) defineProperties(Constructor.prototype, protoProps);\n if (staticProps) defineProperties(Constructor, staticProps);\n return Constructor;\n };\n }();\n var slicedToArray = function () {\n function sliceIterator(arr, i) {\n var _arr = [];\n var _n = true;\n var _d = false;\n var _e = undefined;\n try {\n for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {\n _arr.push(_s.value);\n if (i && _arr.length === i) break;\n }\n } catch (err) {\n _d = true;\n _e = err;\n } finally {\n try {\n if (!_n && _i[\"return\"]) _i[\"return\"]();\n } finally {\n if (_d) throw _e;\n }\n }\n return _arr;\n }\n return function (arr, i) {\n if (Array.isArray(arr)) {\n return arr;\n } else if (Symbol.iterator in Object(arr)) {\n return sliceIterator(arr, i);\n } else {\n throw new TypeError(\"Invalid attempt to destructure non-iterable instance\");\n }\n };\n }();\n var MIN_TIMESTEP = 0.001;\n var MAX_TIMESTEP = 1;\n var dataUri = function dataUri(mimeType, svg) {\n return 'data:' + mimeType + ',' + encodeURIComponent(svg);\n };\n var lerp = function lerp(a, b, t) {\n return a + (b - a) * t;\n };\n var isIOS = function () {\n var isIOS = /iPad|iPhone|iPod/.test(navigator.platform);\n return function () {\n return isIOS;\n };\n }();\n var isWebViewAndroid = function () {\n var isWebViewAndroid = navigator.userAgent.indexOf('Version') !== -1 && navigator.userAgent.indexOf('Android') !== -1 && navigator.userAgent.indexOf('Chrome') !== -1;\n return function () {\n return isWebViewAndroid;\n };\n }();\n var isSafari = function () {\n var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\n return function () {\n return isSafari;\n };\n }();\n var isFirefoxAndroid = function () {\n var isFirefoxAndroid = navigator.userAgent.indexOf('Firefox') !== -1 && navigator.userAgent.indexOf('Android') !== -1;\n return function () {\n return isFirefoxAndroid;\n };\n }();\n var getChromeVersion = function () {\n var match = navigator.userAgent.match(/.*Chrome\\/([0-9]+)/);\n var value = match ? parseInt(match[1], 10) : null;\n return function () {\n return value;\n };\n }();\n var isSafariWithoutDeviceMotion = function () {\n var value = false;\n value = isIOS() && isSafari() && navigator.userAgent.indexOf('13_4') !== -1;\n return function () {\n return value;\n };\n }();\n var isChromeWithoutDeviceMotion = function () {\n var value = false;\n if (getChromeVersion() === 65) {\n var match = navigator.userAgent.match(/.*Chrome\\/([0-9\\.]*)/);\n if (match) {\n var _match$1$split = match[1].split('.'),\n _match$1$split2 = slicedToArray(_match$1$split, 4),\n major = _match$1$split2[0],\n minor = _match$1$split2[1],\n branch = _match$1$split2[2],\n build = _match$1$split2[3];\n value = parseInt(branch, 10) === 3325 && parseInt(build, 10) < 148;\n }\n }\n return function () {\n return value;\n };\n }();\n var isR7 = function () {\n var isR7 = navigator.userAgent.indexOf('R7 Build') !== -1;\n return function () {\n return isR7;\n };\n }();\n var isLandscapeMode = function isLandscapeMode() {\n var rtn = window.orientation == 90 || window.orientation == -90;\n return isR7() ? !rtn : rtn;\n };\n var isTimestampDeltaValid = function isTimestampDeltaValid(timestampDeltaS) {\n if (isNaN(timestampDeltaS)) {\n return false;\n }\n if (timestampDeltaS <= MIN_TIMESTEP) {\n return false;\n }\n if (timestampDeltaS > MAX_TIMESTEP) {\n return false;\n }\n return true;\n };\n var getScreenWidth = function getScreenWidth() {\n return Math.max(window.screen.width, window.screen.height) * window.devicePixelRatio;\n };\n var getScreenHeight = function getScreenHeight() {\n return Math.min(window.screen.width, window.screen.height) * window.devicePixelRatio;\n };\n var requestFullscreen = function requestFullscreen(element) {\n if (isWebViewAndroid()) {\n return false;\n }\n if (element.requestFullscreen) {\n element.requestFullscreen();\n } else if (element.webkitRequestFullscreen) {\n element.webkitRequestFullscreen();\n } else if (element.mozRequestFullScreen) {\n element.mozRequestFullScreen();\n } else if (element.msRequestFullscreen) {\n element.msRequestFullscreen();\n } else {\n return false;\n }\n return true;\n };\n var exitFullscreen = function exitFullscreen() {\n if (document.exitFullscreen) {\n document.exitFullscreen();\n } else if (document.webkitExitFullscreen) {\n document.webkitExitFullscreen();\n } else if (document.mozCancelFullScreen) {\n document.mozCancelFullScreen();\n } else if (document.msExitFullscreen) {\n document.msExitFullscreen();\n } else {\n return false;\n }\n return true;\n };\n var getFullscreenElement = function getFullscreenElement() {\n return document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement;\n };\n var linkProgram = function linkProgram(gl, vertexSource, fragmentSource, attribLocationMap) {\n var vertexShader = gl.createShader(gl.VERTEX_SHADER);\n gl.shaderSource(vertexShader, vertexSource);\n gl.compileShader(vertexShader);\n var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);\n gl.shaderSource(fragmentShader, fragmentSource);\n gl.compileShader(fragmentShader);\n var program = gl.createProgram();\n gl.attachShader(program, vertexShader);\n gl.attachShader(program, fragmentShader);\n for (var attribName in attribLocationMap) {\n gl.bindAttribLocation(program, attribLocationMap[attribName], attribName);\n }\n gl.linkProgram(program);\n gl.deleteShader(vertexShader);\n gl.deleteShader(fragmentShader);\n return program;\n };\n var getProgramUniforms = function getProgramUniforms(gl, program) {\n var uniforms = {};\n var uniformCount = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);\n var uniformName = '';\n for (var i = 0; i < uniformCount; i++) {\n var uniformInfo = gl.getActiveUniform(program, i);\n uniformName = uniformInfo.name.replace('[0]', '');\n uniforms[uniformName] = gl.getUniformLocation(program, uniformName);\n }\n return uniforms;\n };\n var orthoMatrix = function orthoMatrix(out, left, right, bottom, top, near, far) {\n var lr = 1 / (left - right),\n bt = 1 / (bottom - top),\n nf = 1 / (near - far);\n out[0] = -2 * lr;\n out[1] = 0;\n out[2] = 0;\n out[3] = 0;\n out[4] = 0;\n out[5] = -2 * bt;\n out[6] = 0;\n out[7] = 0;\n out[8] = 0;\n out[9] = 0;\n out[10] = 2 * nf;\n out[11] = 0;\n out[12] = (left + right) * lr;\n out[13] = (top + bottom) * bt;\n out[14] = (far + near) * nf;\n out[15] = 1;\n return out;\n };\n var isMobile = function isMobile() {\n var check = false;\n (function (a) {\n if (/(android|bb\\d+|meego).+mobile|avantgo|bada\\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\\-(n|u)|c55\\/|capi|ccwa|cdm\\-|cell|chtm|cldc|cmd\\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\\-s|devi|dica|dmob|do(c|p)o|ds(12|\\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\\-|_)|g1 u|g560|gene|gf\\-5|g\\-mo|go(\\.w|od)|gr(ad|un)|haie|hcit|hd\\-(m|p|t)|hei\\-|hi(pt|ta)|hp( i|ip)|hs\\-c|ht(c(\\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\\-(20|go|ma)|i230|iac( |\\-|\\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\\/)|klon|kpt |kwc\\-|kyo(c|k)|le(no|xi)|lg( g|\\/(k|l|u)|50|54|\\-[a-w])|libw|lynx|m1\\-w|m3ga|m50\\/|ma(te|ui|xo)|mc(01|21|ca)|m\\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\\-2|po(ck|rt|se)|prox|psio|pt\\-g|qa\\-a|qc(07|12|21|32|60|\\-[2-7]|i\\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\\-|oo|p\\-)|sdk\\/|se(c(\\-|0|1)|47|mc|nd|ri)|sgh\\-|shar|sie(\\-|m)|sk\\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\\-|v\\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\\-|tdg\\-|tel(i|m)|tim\\-|t\\-mo|to(pl|sh)|ts(70|m\\-|m3|m5)|tx\\-9|up(\\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\\-|your|zeto|zte\\-/i.test(a.substr(0, 4))) check = true;\n })(navigator.userAgent || navigator.vendor || window.opera);\n return check;\n };\n var extend = function extend(dest, src) {\n for (var key in src) {\n if (src.hasOwnProperty(key)) {\n dest[key] = src[key];\n }\n }\n return dest;\n };\n var safariCssSizeWorkaround = function safariCssSizeWorkaround(canvas) {\n if (isIOS()) {\n var width = canvas.style.width;\n var height = canvas.style.height;\n canvas.style.width = parseInt(width) + 1 + 'px';\n canvas.style.height = parseInt(height) + 'px';\n setTimeout(function () {\n canvas.style.width = width;\n canvas.style.height = height;\n }, 100);\n }\n window.canvas = canvas;\n };\n var frameDataFromPose = function () {\n var piOver180 = Math.PI / 180.0;\n var rad45 = Math.PI * 0.25;\n function mat4_perspectiveFromFieldOfView(out, fov, near, far) {\n var upTan = Math.tan(fov ? fov.upDegrees * piOver180 : rad45),\n downTan = Math.tan(fov ? fov.downDegrees * piOver180 : rad45),\n leftTan = Math.tan(fov ? fov.leftDegrees * piOver180 : rad45),\n rightTan = Math.tan(fov ? fov.rightDegrees * piOver180 : rad45),\n xScale = 2.0 / (leftTan + rightTan),\n yScale = 2.0 / (upTan + downTan);\n out[0] = xScale;\n out[1] = 0.0;\n out[2] = 0.0;\n out[3] = 0.0;\n out[4] = 0.0;\n out[5] = yScale;\n out[6] = 0.0;\n out[7] = 0.0;\n out[8] = -((leftTan - rightTan) * xScale * 0.5);\n out[9] = (upTan - downTan) * yScale * 0.5;\n out[10] = far / (near - far);\n out[11] = -1.0;\n out[12] = 0.0;\n out[13] = 0.0;\n out[14] = far * near / (near - far);\n out[15] = 0.0;\n return out;\n }\n function mat4_fromRotationTranslation(out, q, v) {\n var x = q[0],\n y = q[1],\n z = q[2],\n w = q[3],\n x2 = x + x,\n y2 = y + y,\n z2 = z + z,\n xx = x * x2,\n xy = x * y2,\n xz = x * z2,\n yy = y * y2,\n yz = y * z2,\n zz = z * z2,\n wx = w * x2,\n wy = w * y2,\n wz = w * z2;\n out[0] = 1 - (yy + zz);\n out[1] = xy + wz;\n out[2] = xz - wy;\n out[3] = 0;\n out[4] = xy - wz;\n out[5] = 1 - (xx + zz);\n out[6] = yz + wx;\n out[7] = 0;\n out[8] = xz + wy;\n out[9] = yz - wx;\n out[10] = 1 - (xx + yy);\n out[11] = 0;\n out[12] = v[0];\n out[13] = v[1];\n out[14] = v[2];\n out[15] = 1;\n return out;\n }\n function mat4_translate(out, a, v) {\n var x = v[0],\n y = v[1],\n z = v[2],\n a00,\n a01,\n a02,\n a03,\n a10,\n a11,\n a12,\n a13,\n a20,\n a21,\n a22,\n a23;\n if (a === out) {\n out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];\n out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];\n out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];\n out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];\n } else {\n a00 = a[0];\n a01 = a[1];\n a02 = a[2];\n a03 = a[3];\n a10 = a[4];\n a11 = a[5];\n a12 = a[6];\n a13 = a[7];\n a20 = a[8];\n a21 = a[9];\n a22 = a[10];\n a23 = a[11];\n out[0] = a00;\n out[1] = a01;\n out[2] = a02;\n out[3] = a03;\n out[4] = a10;\n out[5] = a11;\n out[6] = a12;\n out[7] = a13;\n out[8] = a20;\n out[9] = a21;\n out[10] = a22;\n out[11] = a23;\n out[12] = a00 * x + a10 * y + a20 * z + a[12];\n out[13] = a01 * x + a11 * y + a21 * z + a[13];\n out[14] = a02 * x + a12 * y + a22 * z + a[14];\n out[15] = a03 * x + a13 * y + a23 * z + a[15];\n }\n return out;\n }\n function mat4_invert(out, a) {\n var a00 = a[0],\n a01 = a[1],\n a02 = a[2],\n a03 = a[3],\n a10 = a[4],\n a11 = a[5],\n a12 = a[6],\n a13 = a[7],\n a20 = a[8],\n a21 = a[9],\n a22 = a[10],\n a23 = a[11],\n a30 = a[12],\n a31 = a[13],\n a32 = a[14],\n a33 = a[15],\n b00 = a00 * a11 - a01 * a10,\n b01 = a00 * a12 - a02 * a10,\n b02 = a00 * a13 - a03 * a10,\n b03 = a01 * a12 - a02 * a11,\n b04 = a01 * a13 - a03 * a11,\n b05 = a02 * a13 - a03 * a12,\n b06 = a20 * a31 - a21 * a30,\n b07 = a20 * a32 - a22 * a30,\n b08 = a20 * a33 - a23 * a30,\n b09 = a21 * a32 - a22 * a31,\n b10 = a21 * a33 - a23 * a31,\n b11 = a22 * a33 - a23 * a32,\n det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;\n if (!det) {\n return null;\n }\n det = 1.0 / det;\n out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;\n out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;\n out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;\n out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;\n out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;\n out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;\n out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;\n out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;\n out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;\n out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;\n out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;\n out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;\n out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;\n out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;\n out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;\n out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;\n return out;\n }\n var defaultOrientation = new Float32Array([0, 0, 0, 1]);\n var defaultPosition = new Float32Array([0, 0, 0]);\n function updateEyeMatrices(projection, view, pose, fov, offset, vrDisplay) {\n mat4_perspectiveFromFieldOfView(projection, fov || null, vrDisplay.depthNear, vrDisplay.depthFar);\n var orientation = pose.orientation || defaultOrientation;\n var position = pose.position || defaultPosition;\n mat4_fromRotationTranslation(view, orientation, position);\n if (offset) mat4_translate(view, view, offset);\n mat4_invert(view, view);\n }\n return function (frameData, pose, vrDisplay) {\n if (!frameData || !pose) return false;\n frameData.pose = pose;\n frameData.timestamp = pose.timestamp;\n updateEyeMatrices(frameData.leftProjectionMatrix, frameData.leftViewMatrix, pose, vrDisplay._getFieldOfView(\"left\"), vrDisplay._getEyeOffset(\"left\"), vrDisplay);\n updateEyeMatrices(frameData.rightProjectionMatrix, frameData.rightViewMatrix, pose, vrDisplay._getFieldOfView(\"right\"), vrDisplay._getEyeOffset(\"right\"), vrDisplay);\n return true;\n };\n }();\n var isInsideCrossOriginIFrame = function isInsideCrossOriginIFrame() {\n var isFramed = window.self !== window.top;\n var refOrigin = getOriginFromUrl(document.referrer);\n var thisOrigin = getOriginFromUrl(window.location.href);\n return isFramed && refOrigin !== thisOrigin;\n };\n var getOriginFromUrl = function getOriginFromUrl(url) {\n var domainIdx;\n var protoSepIdx = url.indexOf(\"://\");\n if (protoSepIdx !== -1) {\n domainIdx = protoSepIdx + 3;\n } else {\n domainIdx = 0;\n }\n var domainEndIdx = url.indexOf('/', domainIdx);\n if (domainEndIdx === -1) {\n domainEndIdx = url.length;\n }\n return url.substring(0, domainEndIdx);\n };\n var getQuaternionAngle = function getQuaternionAngle(quat) {\n if (quat.w > 1) {\n console.warn('getQuaternionAngle: w > 1');\n return 0;\n }\n var angle = 2 * Math.acos(quat.w);\n return angle;\n };\n var warnOnce = function () {\n var observedWarnings = {};\n return function (key, message) {\n if (observedWarnings[key] === undefined) {\n console.warn('webvr-polyfill: ' + message);\n observedWarnings[key] = true;\n }\n };\n }();\n var deprecateWarning = function deprecateWarning(deprecated, suggested) {\n var alternative = suggested ? 'Please use ' + suggested + ' instead.' : '';\n warnOnce(deprecated, deprecated + ' has been deprecated. ' + 'This may not work on native WebVR displays. ' + alternative);\n };\n function WGLUPreserveGLState(gl, bindings, callback) {\n if (!bindings) {\n callback(gl);\n return;\n }\n var boundValues = [];\n var activeTexture = null;\n for (var i = 0; i < bindings.length; ++i) {\n var binding = bindings[i];\n switch (binding) {\n case gl.TEXTURE_BINDING_2D:\n case gl.TEXTURE_BINDING_CUBE_MAP:\n var textureUnit = bindings[++i];\n if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31) {\n console.error(\"TEXTURE_BINDING_2D or TEXTURE_BINDING_CUBE_MAP must be followed by a valid texture unit\");\n boundValues.push(null, null);\n break;\n }\n if (!activeTexture) {\n activeTexture = gl.getParameter(gl.ACTIVE_TEXTURE);\n }\n gl.activeTexture(textureUnit);\n boundValues.push(gl.getParameter(binding), null);\n break;\n case gl.ACTIVE_TEXTURE:\n activeTexture = gl.getParameter(gl.ACTIVE_TEXTURE);\n boundValues.push(null);\n break;\n default:\n boundValues.push(gl.getParameter(binding));\n break;\n }\n }\n callback(gl);\n for (var i = 0; i < bindings.length; ++i) {\n var binding = bindings[i];\n var boundValue = boundValues[i];\n switch (binding) {\n case gl.ACTIVE_TEXTURE:\n break;\n case gl.ARRAY_BUFFER_BINDING:\n gl.bindBuffer(gl.ARRAY_BUFFER, boundValue);\n break;\n case gl.COLOR_CLEAR_VALUE:\n gl.clearColor(boundValue[0], boundValue[1], boundValue[2], boundValue[3]);\n break;\n case gl.COLOR_WRITEMASK:\n gl.colorMask(boundValue[0], boundValue[1], boundValue[2], boundValue[3]);\n break;\n case gl.CURRENT_PROGRAM:\n gl.useProgram(boundValue);\n break;\n case gl.ELEMENT_ARRAY_BUFFER_BINDING:\n gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, boundValue);\n break;\n case gl.FRAMEBUFFER_BINDING:\n gl.bindFramebuffer(gl.FRAMEBUFFER, boundValue);\n break;\n case gl.RENDERBUFFER_BINDING:\n gl.bindRenderbuffer(gl.RENDERBUFFER, boundValue);\n break;\n case gl.TEXTURE_BINDING_2D:\n var textureUnit = bindings[++i];\n if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31) break;\n gl.activeTexture(textureUnit);\n gl.bindTexture(gl.TEXTURE_2D, boundValue);\n break;\n case gl.TEXTURE_BINDING_CUBE_MAP:\n var textureUnit = bindings[++i];\n if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31) break;\n gl.activeTexture(textureUnit);\n gl.bindTexture(gl.TEXTURE_CUBE_MAP, boundValue);\n break;\n case gl.VIEWPORT:\n gl.viewport(boundValue[0], boundValue[1], boundValue[2], boundValue[3]);\n break;\n case gl.BLEND:\n case gl.CULL_FACE:\n case gl.DEPTH_TEST:\n case gl.SCISSOR_TEST:\n case gl.STENCIL_TEST:\n if (boundValue) {\n gl.enable(binding);\n } else {\n gl.disable(binding);\n }\n break;\n default:\n console.log(\"No GL restore behavior for 0x\" + binding.toString(16));\n break;\n }\n if (activeTexture) {\n gl.activeTexture(activeTexture);\n }\n }\n }\n var glPreserveState = WGLUPreserveGLState;\n var distortionVS = ['attribute vec2 position;', 'attribute vec3 texCoord;', 'varying vec2 vTexCoord;', 'uniform vec4 viewportOffsetScale[2];', 'void main() {', ' vec4 viewport = viewportOffsetScale[int(texCoord.z)];', ' vTexCoord = (texCoord.xy * viewport.zw) + viewport.xy;', ' gl_Position = vec4( position, 1.0, 1.0 );', '}'].join('\\n');\n var distortionFS = ['precision mediump float;', 'uniform sampler2D diffuse;', 'varying vec2 vTexCoord;', 'void main() {', ' gl_FragColor = texture2D(diffuse, vTexCoord);', '}'].join('\\n');\n function CardboardDistorter(gl, cardboardUI, bufferScale, dirtySubmitFrameBindings) {\n this.gl = gl;\n this.cardboardUI = cardboardUI;\n this.bufferScale = bufferScale;\n this.dirtySubmitFrameBindings = dirtySubmitFrameBindings;\n this.ctxAttribs = gl.getContextAttributes();\n this.instanceExt = gl.getExtension('ANGLE_instanced_arrays');\n this.meshWidth = 20;\n this.meshHeight = 20;\n this.bufferWidth = gl.drawingBufferWidth;\n this.bufferHeight = gl.drawingBufferHeight;\n this.realBindFramebuffer = gl.bindFramebuffer;\n this.realEnable = gl.enable;\n this.realDisable = gl.disable;\n this.realColorMask = gl.colorMask;\n this.realClearColor = gl.clearColor;\n this.realViewport = gl.viewport;\n if (!isIOS()) {\n this.realCanvasWidth = Object.getOwnPropertyDescriptor(gl.canvas.__proto__, 'width');\n this.realCanvasHeight = Object.getOwnPropertyDescriptor(gl.canvas.__proto__, 'height');\n }\n this.isPatched = false;\n this.lastBoundFramebuffer = null;\n this.cullFace = false;\n this.depthTest = false;\n this.blend = false;\n this.scissorTest = false;\n this.stencilTest = false;\n this.viewport = [0, 0, 0, 0];\n this.colorMask = [true, true, true, true];\n this.clearColor = [0, 0, 0, 0];\n this.attribs = {\n position: 0,\n texCoord: 1\n };\n this.program = linkProgram(gl, distortionVS, distortionFS, this.attribs);\n this.uniforms = getProgramUniforms(gl, this.program);\n this.viewportOffsetScale = new Float32Array(8);\n this.setTextureBounds();\n this.vertexBuffer = gl.createBuffer();\n this.indexBuffer = gl.createBuffer();\n this.indexCount = 0;\n this.renderTarget = gl.createTexture();\n this.framebuffer = gl.createFramebuffer();\n this.depthStencilBuffer = null;\n this.depthBuffer = null;\n this.stencilBuffer = null;\n if (this.ctxAttribs.depth && this.ctxAttribs.stencil) {\n this.depthStencilBuffer = gl.createRenderbuffer();\n } else if (this.ctxAttribs.depth) {\n this.depthBuffer = gl.createRenderbuffer();\n } else if (this.ctxAttribs.stencil) {\n this.stencilBuffer = gl.createRenderbuffer();\n }\n this.patch();\n this.onResize();\n }\n CardboardDistorter.prototype.destroy = function () {\n var gl = this.gl;\n this.unpatch();\n gl.deleteProgram(this.program);\n gl.deleteBuffer(this.vertexBuffer);\n gl.deleteBuffer(this.indexBuffer);\n gl.deleteTexture(this.renderTarget);\n gl.deleteFramebuffer(this.framebuffer);\n if (this.depthStencilBuffer) {\n gl.deleteRenderbuffer(this.depthStencilBuffer);\n }\n if (this.depthBuffer) {\n gl.deleteRenderbuffer(this.depthBuffer);\n }\n if (this.stencilBuffer) {\n gl.deleteRenderbuffer(this.stencilBuffer);\n }\n if (this.cardboardUI) {\n this.cardboardUI.destroy();\n }\n };\n CardboardDistorter.prototype.onResize = function () {\n var gl = this.gl;\n var self = this;\n var glState = [gl.RENDERBUFFER_BINDING, gl.TEXTURE_BINDING_2D, gl.TEXTURE0];\n glPreserveState(gl, glState, function (gl) {\n self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, null);\n if (self.scissorTest) {\n self.realDisable.call(gl, gl.SCISSOR_TEST);\n }\n self.realColorMask.call(gl, true, true, true, true);\n self.realViewport.call(gl, 0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);\n self.realClearColor.call(gl, 0, 0, 0, 1);\n gl.clear(gl.COLOR_BUFFER_BIT);\n self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.framebuffer);\n gl.bindTexture(gl.TEXTURE_2D, self.renderTarget);\n gl.texImage2D(gl.TEXTURE_2D, 0, self.ctxAttribs.alpha ? gl.RGBA : gl.RGB, self.bufferWidth, self.bufferHeight, 0, self.ctxAttribs.alpha ? gl.RGBA : gl.RGB, gl.UNSIGNED_BYTE, null);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, self.renderTarget, 0);\n if (self.ctxAttribs.depth && self.ctxAttribs.stencil) {\n gl.bindRenderbuffer(gl.RENDERBUFFER, self.depthStencilBuffer);\n gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, self.bufferWidth, self.bufferHeight);\n gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, self.depthStencilBuffer);\n } else if (self.ctxAttribs.depth) {\n gl.bindRenderbuffer(gl.RENDERBUFFER, self.depthBuffer);\n gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, self.bufferWidth, self.bufferHeight);\n gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, self.depthBuffer);\n } else if (self.ctxAttribs.stencil) {\n gl.bindRenderbuffer(gl.RENDERBUFFER, self.stencilBuffer);\n gl.renderbufferStorage(gl.RENDERBUFFER, gl.STENCIL_INDEX8, self.bufferWidth, self.bufferHeight);\n gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, self.stencilBuffer);\n }\n if (!gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE) {\n console.error('Framebuffer incomplete!');\n }\n self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.lastBoundFramebuffer);\n if (self.scissorTest) {\n self.realEnable.call(gl, gl.SCISSOR_TEST);\n }\n self.realColorMask.apply(gl, self.colorMask);\n self.realViewport.apply(gl, self.viewport);\n self.realClearColor.apply(gl, self.clearColor);\n });\n if (this.cardboardUI) {\n this.cardboardUI.onResize();\n }\n };\n CardboardDistorter.prototype.patch = function () {\n if (this.isPatched) {\n return;\n }\n var self = this;\n var canvas = this.gl.canvas;\n var gl = this.gl;\n if (!isIOS()) {\n canvas.width = getScreenWidth() * this.bufferScale;\n canvas.height = getScreenHeight() * this.bufferScale;\n Object.defineProperty(canvas, 'width', {\n configurable: true,\n enumerable: true,\n get: function get() {\n return self.bufferWidth;\n },\n set: function set(value) {\n self.bufferWidth = value;\n self.realCanvasWidth.set.call(canvas, value);\n self.onResize();\n }\n });\n Object.defineProperty(canvas, 'height', {\n configurable: true,\n enumerable: true,\n get: function get() {\n return self.bufferHeight;\n },\n set: function set(value) {\n self.bufferHeight = value;\n self.realCanvasHeight.set.call(canvas, value);\n self.onResize();\n }\n });\n }\n this.lastBoundFramebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);\n if (this.lastBoundFramebuffer == null) {\n this.lastBoundFramebuffer = this.framebuffer;\n this.gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);\n }\n this.gl.bindFramebuffer = function (target, framebuffer) {\n self.lastBoundFramebuffer = framebuffer ? framebuffer : self.framebuffer;\n self.realBindFramebuffer.call(gl, target, self.lastBoundFramebuffer);\n };\n this.cullFace = gl.getParameter(gl.CULL_FACE);\n this.depthTest = gl.getParameter(gl.DEPTH_TEST);\n this.blend = gl.getParameter(gl.BLEND);\n this.scissorTest = gl.getParameter(gl.SCISSOR_TEST);\n this.stencilTest = gl.getParameter(gl.STENCIL_TEST);\n gl.enable = function (pname) {\n switch (pname) {\n case gl.CULL_FACE:\n self.cullFace = true;\n break;\n case gl.DEPTH_TEST:\n self.depthTest = true;\n break;\n case gl.BLEND:\n self.blend = true;\n break;\n case gl.SCISSOR_TEST:\n self.scissorTest = true;\n break;\n case gl.STENCIL_TEST:\n self.stencilTest = true;\n break;\n }\n self.realEnable.call(gl, pname);\n };\n gl.disable = function (pname) {\n switch (pname) {\n case gl.CULL_FACE:\n self.cullFace = false;\n break;\n case gl.DEPTH_TEST:\n self.depthTest = false;\n break;\n case gl.BLEND:\n self.blend = false;\n break;\n case gl.SCISSOR_TEST:\n self.scissorTest = false;\n break;\n case gl.STENCIL_TEST:\n self.stencilTest = false;\n break;\n }\n self.realDisable.call(gl, pname);\n };\n this.colorMask = gl.getParameter(gl.COLOR_WRITEMASK);\n gl.colorMask = function (r, g, b, a) {\n self.colorMask[0] = r;\n self.colorMask[1] = g;\n self.colorMask[2] = b;\n self.colorMask[3] = a;\n self.realColorMask.call(gl, r, g, b, a);\n };\n this.clearColor = gl.getParameter(gl.COLOR_CLEAR_VALUE);\n gl.clearColor = function (r, g, b, a) {\n self.clearColor[0] = r;\n self.clearColor[1] = g;\n self.clearColor[2] = b;\n self.clearColor[3] = a;\n self.realClearColor.call(gl, r, g, b, a);\n };\n this.viewport = gl.getParameter(gl.VIEWPORT);\n gl.viewport = function (x, y, w, h) {\n self.viewport[0] = x;\n self.viewport[1] = y;\n self.viewport[2] = w;\n self.viewport[3] = h;\n self.realViewport.call(gl, x, y, w, h);\n };\n this.isPatched = true;\n safariCssSizeWorkaround(canvas);\n };\n CardboardDistorter.prototype.unpatch = function () {\n if (!this.isPatched) {\n return;\n }\n var gl = this.gl;\n var canvas = this.gl.canvas;\n if (!isIOS()) {\n Object.defineProperty(canvas, 'width', this.realCanvasWidth);\n Object.defineProperty(canvas, 'height', this.realCanvasHeight);\n }\n canvas.width = this.bufferWidth;\n canvas.height = this.bufferHeight;\n gl.bindFramebuffer = this.realBindFramebuffer;\n gl.enable = this.realEnable;\n gl.disable = this.realDisable;\n gl.colorMask = this.realColorMask;\n gl.clearColor = this.realClearColor;\n gl.viewport = this.realViewport;\n if (this.lastBoundFramebuffer == this.framebuffer) {\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n }\n this.isPatched = false;\n setTimeout(function () {\n safariCssSizeWorkaround(canvas);\n }, 1);\n };\n CardboardDistorter.prototype.setTextureBounds = function (leftBounds, rightBounds) {\n if (!leftBounds) {\n leftBounds = [0, 0, 0.5, 1];\n }\n if (!rightBounds) {\n rightBounds = [0.5, 0, 0.5, 1];\n }\n this.viewportOffsetScale[0] = leftBounds[0];\n this.viewportOffsetScale[1] = leftBounds[1];\n this.viewportOffsetScale[2] = leftBounds[2];\n this.viewportOffsetScale[3] = leftBounds[3];\n this.viewportOffsetScale[4] = rightBounds[0];\n this.viewportOffsetScale[5] = rightBounds[1];\n this.viewportOffsetScale[6] = rightBounds[2];\n this.viewportOffsetScale[7] = rightBounds[3];\n };\n CardboardDistorter.prototype.submitFrame = function () {\n var gl = this.gl;\n var self = this;\n var glState = [];\n if (!this.dirtySubmitFrameBindings) {\n glState.push(gl.CURRENT_PROGRAM, gl.ARRAY_BUFFER_BINDING, gl.ELEMENT_ARRAY_BUFFER_BINDING, gl.TEXTURE_BINDING_2D, gl.TEXTURE0);\n }\n glPreserveState(gl, glState, function (gl) {\n self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, null);\n var positionDivisor = 0;\n var texCoordDivisor = 0;\n if (self.instanceExt) {\n positionDivisor = gl.getVertexAttrib(self.attribs.position, self.instanceExt.VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);\n texCoordDivisor = gl.getVertexAttrib(self.attribs.texCoord, self.instanceExt.VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);\n }\n if (self.cullFace) {\n self.realDisable.call(gl, gl.CULL_FACE);\n }\n if (self.depthTest) {\n self.realDisable.call(gl, gl.DEPTH_TEST);\n }\n if (self.blend) {\n self.realDisable.call(gl, gl.BLEND);\n }\n if (self.scissorTest) {\n self.realDisable.call(gl, gl.SCISSOR_TEST);\n }\n if (self.stencilTest) {\n self.realDisable.call(gl, gl.STENCIL_TEST);\n }\n self.realColorMask.call(gl, true, true, true, true);\n self.realViewport.call(gl, 0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);\n if (self.ctxAttribs.alpha || isIOS()) {\n self.realClearColor.call(gl, 0, 0, 0, 1);\n gl.clear(gl.COLOR_BUFFER_BIT);\n }\n gl.useProgram(self.program);\n gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.indexBuffer);\n gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer);\n gl.enableVertexAttribArray(self.attribs.position);\n gl.enableVertexAttribArray(self.attribs.texCoord);\n gl.vertexAttribPointer(self.attribs.position, 2, gl.FLOAT, false, 20, 0);\n gl.vertexAttribPointer(self.attribs.texCoord, 3, gl.FLOAT, false, 20, 8);\n if (self.instanceExt) {\n if (positionDivisor != 0) {\n self.instanceExt.vertexAttribDivisorANGLE(self.attribs.position, 0);\n }\n if (texCoordDivisor != 0) {\n self.instanceExt.vertexAttribDivisorANGLE(self.attribs.texCoord, 0);\n }\n }\n gl.activeTexture(gl.TEXTURE0);\n gl.uniform1i(self.uniforms.diffuse, 0);\n gl.bindTexture(gl.TEXTURE_2D, self.renderTarget);\n gl.uniform4fv(self.uniforms.viewportOffsetScale, self.viewportOffsetScale);\n gl.drawElements(gl.TRIANGLES, self.indexCount, gl.UNSIGNED_SHORT, 0);\n if (self.cardboardUI) {\n self.cardboardUI.renderNoState();\n }\n self.realBindFramebuffer.call(self.gl, gl.FRAMEBUFFER, self.framebuffer);\n if (!self.ctxAttribs.preserveDrawingBuffer) {\n self.realClearColor.call(gl, 0, 0, 0, 0);\n gl.clear(gl.COLOR_BUFFER_BIT);\n }\n if (!self.dirtySubmitFrameBindings) {\n self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.lastBoundFramebuffer);\n }\n if (self.cullFace) {\n self.realEnable.call(gl, gl.CULL_FACE);\n }\n if (self.depthTest) {\n self.realEnable.call(gl, gl.DEPTH_TEST);\n }\n if (self.blend) {\n self.realEnable.call(gl, gl.BLEND);\n }\n if (self.scissorTest) {\n self.realEnable.call(gl, gl.SCISSOR_TEST);\n }\n if (self.stencilTest) {\n self.realEnable.call(gl, gl.STENCIL_TEST);\n }\n self.realColorMask.apply(gl, self.colorMask);\n self.realViewport.apply(gl, self.viewport);\n if (self.ctxAttribs.alpha || !self.ctxAttribs.preserveDrawingBuffer) {\n self.realClearColor.apply(gl, self.clearColor);\n }\n if (self.instanceExt) {\n if (positionDivisor != 0) {\n self.instanceExt.vertexAttribDivisorANGLE(self.attribs.position, positionDivisor);\n }\n if (texCoordDivisor != 0) {\n self.instanceExt.vertexAttribDivisorANGLE(self.attribs.texCoord, texCoordDivisor);\n }\n }\n });\n if (isIOS()) {\n var canvas = gl.canvas;\n if (canvas.width != self.bufferWidth || canvas.height != self.bufferHeight) {\n self.bufferWidth = canvas.width;\n self.bufferHeight = canvas.height;\n self.onResize();\n }\n }\n };\n CardboardDistorter.prototype.updateDeviceInfo = function (deviceInfo) {\n var gl = this.gl;\n var self = this;\n var glState = [gl.ARRAY_BUFFER_BINDING, gl.ELEMENT_ARRAY_BUFFER_BINDING];\n glPreserveState(gl, glState, function (gl) {\n var vertices = self.computeMeshVertices_(self.meshWidth, self.meshHeight, deviceInfo);\n gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer);\n gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);\n if (!self.indexCount) {\n var indices = self.computeMeshIndices_(self.meshWidth, self.meshHeight);\n gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.indexBuffer);\n gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);\n self.indexCount = indices.length;\n }\n });\n };\n CardboardDistorter.prototype.computeMeshVertices_ = function (width, height, deviceInfo) {\n var vertices = new Float32Array(2 * width * height * 5);\n var lensFrustum = deviceInfo.getLeftEyeVisibleTanAngles();\n var noLensFrustum = deviceInfo.getLeftEyeNoLensTanAngles();\n var viewport = deviceInfo.getLeftEyeVisibleScreenRect(noLensFrustum);\n var vidx = 0;\n for (var e = 0; e < 2; e++) {\n for (var j = 0; j < height; j++) {\n for (var i = 0; i < width; i++, vidx++) {\n var u = i / (width - 1);\n var v = j / (height - 1);\n var s = u;\n var t = v;\n var x = lerp(lensFrustum[0], lensFrustum[2], u);\n var y = lerp(lensFrustum[3], lensFrustum[1], v);\n var d = Math.sqrt(x * x + y * y);\n var r = deviceInfo.distortion.distortInverse(d);\n var p = x * r / d;\n var q = y * r / d;\n u = (p - noLensFrustum[0]) / (noLensFrustum[2] - noLensFrustum[0]);\n v = (q - noLensFrustum[3]) / (noLensFrustum[1] - noLensFrustum[3]);\n u = (viewport.x + u * viewport.width - 0.5) * 2.0;\n v = (viewport.y + v * viewport.height - 0.5) * 2.0;\n vertices[vidx * 5 + 0] = u;\n vertices[vidx * 5 + 1] = v;\n vertices[vidx * 5 + 2] = s;\n vertices[vidx * 5 + 3] = t;\n vertices[vidx * 5 + 4] = e;\n }\n }\n var w = lensFrustum[2] - lensFrustum[0];\n lensFrustum[0] = -(w + lensFrustum[0]);\n lensFrustum[2] = w - lensFrustum[2];\n w = noLensFrustum[2] - noLensFrustum[0];\n noLensFrustum[0] = -(w + noLensFrustum[0]);\n noLensFrustum[2] = w - noLensFrustum[2];\n viewport.x = 1 - (viewport.x + viewport.width);\n }\n return vertices;\n };\n CardboardDistorter.prototype.computeMeshIndices_ = function (width, height) {\n var indices = new Uint16Array(2 * (width - 1) * (height - 1) * 6);\n var halfwidth = width / 2;\n var halfheight = height / 2;\n var vidx = 0;\n var iidx = 0;\n for (var e = 0; e < 2; e++) {\n for (var j = 0; j < height; j++) {\n for (var i = 0; i < width; i++, vidx++) {\n if (i == 0 || j == 0) continue;\n if (i <= halfwidth == j <= halfheight) {\n indices[iidx++] = vidx;\n indices[iidx++] = vidx - width - 1;\n indices[iidx++] = vidx - width;\n indices[iidx++] = vidx - width - 1;\n indices[iidx++] = vidx;\n indices[iidx++] = vidx - 1;\n } else {\n indices[iidx++] = vidx - 1;\n indices[iidx++] = vidx - width;\n indices[iidx++] = vidx;\n indices[iidx++] = vidx - width;\n indices[iidx++] = vidx - 1;\n indices[iidx++] = vidx - width - 1;\n }\n }\n }\n }\n return indices;\n };\n CardboardDistorter.prototype.getOwnPropertyDescriptor_ = function (proto, attrName) {\n var descriptor = Object.getOwnPropertyDescriptor(proto, attrName);\n if (descriptor.get === undefined || descriptor.set === undefined) {\n descriptor.configurable = true;\n descriptor.enumerable = true;\n descriptor.get = function () {\n return this.getAttribute(attrName);\n };\n descriptor.set = function (val) {\n this.setAttribute(attrName, val);\n };\n }\n return descriptor;\n };\n var uiVS = ['attribute vec2 position;', 'uniform mat4 projectionMat;', 'void main() {', ' gl_Position = projectionMat * vec4( position, -1.0, 1.0 );', '}'].join('\\n');\n var uiFS = ['precision mediump float;', 'uniform vec4 color;', 'void main() {', ' gl_FragColor = color;', '}'].join('\\n');\n var DEG2RAD = Math.PI / 180.0;\n var kAnglePerGearSection = 60;\n var kOuterRimEndAngle = 12;\n var kInnerRimBeginAngle = 20;\n var kOuterRadius = 1;\n var kMiddleRadius = 0.75;\n var kInnerRadius = 0.3125;\n var kCenterLineThicknessDp = 4;\n var kButtonWidthDp = 28;\n var kTouchSlopFactor = 1.5;\n function CardboardUI(gl) {\n this.gl = gl;\n this.attribs = {\n position: 0\n };\n this.program = linkProgram(gl, uiVS, uiFS, this.attribs);\n this.uniforms = getProgramUniforms(gl, this.program);\n this.vertexBuffer = gl.createBuffer();\n this.gearOffset = 0;\n this.gearVertexCount = 0;\n this.arrowOffset = 0;\n this.arrowVertexCount = 0;\n this.projMat = new Float32Array(16);\n this.listener = null;\n this.onResize();\n }\n CardboardUI.prototype.destroy = function () {\n var gl = this.gl;\n if (this.listener) {\n gl.canvas.removeEventListener('click', this.listener, false);\n }\n gl.deleteProgram(this.program);\n gl.deleteBuffer(this.vertexBuffer);\n };\n CardboardUI.prototype.listen = function (optionsCallback, backCallback) {\n var canvas = this.gl.canvas;\n this.listener = function (event) {\n var midline = canvas.clientWidth / 2;\n var buttonSize = kButtonWidthDp * kTouchSlopFactor;\n if (event.clientX > midline - buttonSize && event.clientX < midline + buttonSize && event.clientY > canvas.clientHeight - buttonSize) {\n optionsCallback(event);\n } else if (event.clientX < buttonSize && event.clientY < buttonSize) {\n backCallback(event);\n }\n };\n canvas.addEventListener('click', this.listener, false);\n };\n CardboardUI.prototype.onResize = function () {\n var gl = this.gl;\n var self = this;\n var glState = [gl.ARRAY_BUFFER_BINDING];\n glPreserveState(gl, glState, function (gl) {\n var vertices = [];\n var midline = gl.drawingBufferWidth / 2;\n var physicalPixels = Math.max(screen.width, screen.height) * window.devicePixelRatio;\n var scalingRatio = gl.drawingBufferWidth / physicalPixels;\n var dps = scalingRatio * window.devicePixelRatio;\n var lineWidth = kCenterLineThicknessDp * dps / 2;\n var buttonSize = kButtonWidthDp * kTouchSlopFactor * dps;\n var buttonScale = kButtonWidthDp * dps / 2;\n var buttonBorder = (kButtonWidthDp * kTouchSlopFactor - kButtonWidthDp) * dps;\n vertices.push(midline - lineWidth, buttonSize);\n vertices.push(midline - lineWidth, gl.drawingBufferHeight);\n vertices.push(midline + lineWidth, buttonSize);\n vertices.push(midline + lineWidth, gl.drawingBufferHeight);\n self.gearOffset = vertices.length / 2;\n function addGearSegment(theta, r) {\n var angle = (90 - theta) * DEG2RAD;\n var x = Math.cos(angle);\n var y = Math.sin(angle);\n vertices.push(kInnerRadius * x * buttonScale + midline, kInnerRadius * y * buttonScale + buttonScale);\n vertices.push(r * x * buttonScale + midline, r * y * buttonScale + buttonScale);\n }\n for (var i = 0; i <= 6; i++) {\n var segmentTheta = i * kAnglePerGearSection;\n addGearSegment(segmentTheta, kOuterRadius);\n addGearSegment(segmentTheta + kOuterRimEndAngle, kOuterRadius);\n addGearSegment(segmentTheta + kInnerRimBeginAngle, kMiddleRadius);\n addGearSegment(segmentTheta + (kAnglePerGearSection - kInnerRimBeginAngle), kMiddleRadius);\n addGearSegment(segmentTheta + (kAnglePerGearSection - kOuterRimEndAngle), kOuterRadius);\n }\n self.gearVertexCount = vertices.length / 2 - self.gearOffset;\n self.arrowOffset = vertices.length / 2;\n function addArrowVertex(x, y) {\n vertices.push(buttonBorder + x, gl.drawingBufferHeight - buttonBorder - y);\n }\n var angledLineWidth = lineWidth / Math.sin(45 * DEG2RAD);\n addArrowVertex(0, buttonScale);\n addArrowVertex(buttonScale, 0);\n addArrowVertex(buttonScale + angledLineWidth, angledLineWidth);\n addArrowVertex(angledLineWidth, buttonScale + angledLineWidth);\n addArrowVertex(angledLineWidth, buttonScale - angledLineWidth);\n addArrowVertex(0, buttonScale);\n addArrowVertex(buttonScale, buttonScale * 2);\n addArrowVertex(buttonScale + angledLineWidth, buttonScale * 2 - angledLineWidth);\n addArrowVertex(angledLineWidth, buttonScale - angledLineWidth);\n addArrowVertex(0, buttonScale);\n addArrowVertex(angledLineWidth, buttonScale - lineWidth);\n addArrowVertex(kButtonWidthDp * dps, buttonScale - lineWidth);\n addArrowVertex(angledLineWidth, buttonScale + lineWidth);\n addArrowVertex(kButtonWidthDp * dps, buttonScale + lineWidth);\n self.arrowVertexCount = vertices.length / 2 - self.arrowOffset;\n gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer);\n gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);\n });\n };\n CardboardUI.prototype.render = function () {\n var gl = this.gl;\n var self = this;\n var glState = [gl.CULL_FACE, gl.DEPTH_TEST, gl.BLEND, gl.SCISSOR_TEST, gl.STENCIL_TEST, gl.COLOR_WRITEMASK, gl.VIEWPORT, gl.CURRENT_PROGRAM, gl.ARRAY_BUFFER_BINDING];\n glPreserveState(gl, glState, function (gl) {\n gl.disable(gl.CULL_FACE);\n gl.disable(gl.DEPTH_TEST);\n gl.disable(gl.BLEND);\n gl.disable(gl.SCISSOR_TEST);\n gl.disable(gl.STENCIL_TEST);\n gl.colorMask(true, true, true, true);\n gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);\n self.renderNoState();\n });\n };\n CardboardUI.prototype.renderNoState = function () {\n var gl = this.gl;\n gl.useProgram(this.program);\n gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);\n gl.enableVertexAttribArray(this.attribs.position);\n gl.vertexAttribPointer(this.attribs.position, 2, gl.FLOAT, false, 8, 0);\n gl.uniform4f(this.uniforms.color, 1.0, 1.0, 1.0, 1.0);\n orthoMatrix(this.projMat, 0, gl.drawingBufferWidth, 0, gl.drawingBufferHeight, 0.1, 1024.0);\n gl.uniformMatrix4fv(this.uniforms.projectionMat, false, this.projMat);\n gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);\n gl.drawArrays(gl.TRIANGLE_STRIP, this.gearOffset, this.gearVertexCount);\n gl.drawArrays(gl.TRIANGLE_STRIP, this.arrowOffset, this.arrowVertexCount);\n };\n function Distortion(coefficients) {\n this.coefficients = coefficients;\n }\n Distortion.prototype.distortInverse = function (radius) {\n var r0 = 0;\n var r1 = 1;\n var dr0 = radius - this.distort(r0);\n while (Math.abs(r1 - r0) > 0.0001) {\n var dr1 = radius - this.distort(r1);\n var r2 = r1 - dr1 * ((r1 - r0) / (dr1 - dr0));\n r0 = r1;\n r1 = r2;\n dr0 = dr1;\n }\n return r1;\n };\n Distortion.prototype.distort = function (radius) {\n var r2 = radius * radius;\n var ret = 0;\n for (var i = 0; i < this.coefficients.length; i++) {\n ret = r2 * (ret + this.coefficients[i]);\n }\n return (ret + 1) * radius;\n };\n var degToRad = Math.PI / 180;\n var radToDeg = 180 / Math.PI;\n var Vector3 = function Vector3(x, y, z) {\n this.x = x || 0;\n this.y = y || 0;\n this.z = z || 0;\n };\n Vector3.prototype = {\n constructor: Vector3,\n set: function set(x, y, z) {\n this.x = x;\n this.y = y;\n this.z = z;\n return this;\n },\n copy: function copy(v) {\n this.x = v.x;\n this.y = v.y;\n this.z = v.z;\n return this;\n },\n length: function length() {\n return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);\n },\n normalize: function normalize() {\n var scalar = this.length();\n if (scalar !== 0) {\n var invScalar = 1 / scalar;\n this.multiplyScalar(invScalar);\n } else {\n this.x = 0;\n this.y = 0;\n this.z = 0;\n }\n return this;\n },\n multiplyScalar: function multiplyScalar(scalar) {\n this.x *= scalar;\n this.y *= scalar;\n this.z *= scalar;\n },\n applyQuaternion: function applyQuaternion(q) {\n var x = this.x;\n var y = this.y;\n var z = this.z;\n var qx = q.x;\n var qy = q.y;\n var qz = q.z;\n var qw = q.w;\n var ix = qw * x + qy * z - qz * y;\n var iy = qw * y + qz * x - qx * z;\n var iz = qw * z + qx * y - qy * x;\n var iw = -qx * x - qy * y - qz * z;\n this.x = ix * qw + iw * -qx + iy * -qz - iz * -qy;\n this.y = iy * qw + iw * -qy + iz * -qx - ix * -qz;\n this.z = iz * qw + iw * -qz + ix * -qy - iy * -qx;\n return this;\n },\n dot: function dot(v) {\n return this.x * v.x + this.y * v.y + this.z * v.z;\n },\n crossVectors: function crossVectors(a, b) {\n var ax = a.x,\n ay = a.y,\n az = a.z;\n var bx = b.x,\n by = b.y,\n bz = b.z;\n this.x = ay * bz - az * by;\n this.y = az * bx - ax * bz;\n this.z = ax * by - ay * bx;\n return this;\n }\n };\n var Quaternion = function Quaternion(x, y, z, w) {\n this.x = x || 0;\n this.y = y || 0;\n this.z = z || 0;\n this.w = w !== undefined ? w : 1;\n };\n Quaternion.prototype = {\n constructor: Quaternion,\n set: function set(x, y, z, w) {\n this.x = x;\n this.y = y;\n this.z = z;\n this.w = w;\n return this;\n },\n copy: function copy(quaternion) {\n this.x = quaternion.x;\n this.y = quaternion.y;\n this.z = quaternion.z;\n this.w = quaternion.w;\n return this;\n },\n setFromEulerXYZ: function setFromEulerXYZ(x, y, z) {\n var c1 = Math.cos(x / 2);\n var c2 = Math.cos(y / 2);\n var c3 = Math.cos(z / 2);\n var s1 = Math.sin(x / 2);\n var s2 = Math.sin(y / 2);\n var s3 = Math.sin(z / 2);\n this.x = s1 * c2 * c3 + c1 * s2 * s3;\n this.y = c1 * s2 * c3 - s1 * c2 * s3;\n this.z = c1 * c2 * s3 + s1 * s2 * c3;\n this.w = c1 * c2 * c3 - s1 * s2 * s3;\n return this;\n },\n setFromEulerYXZ: function setFromEulerYXZ(x, y, z) {\n var c1 = Math.cos(x / 2);\n var c2 = Math.cos(y / 2);\n var c3 = Math.cos(z / 2);\n var s1 = Math.sin(x / 2);\n var s2 = Math.sin(y / 2);\n var s3 = Math.sin(z / 2);\n this.x = s1 * c2 * c3 + c1 * s2 * s3;\n this.y = c1 * s2 * c3 - s1 * c2 * s3;\n this.z = c1 * c2 * s3 - s1 * s2 * c3;\n this.w = c1 * c2 * c3 + s1 * s2 * s3;\n return this;\n },\n setFromAxisAngle: function setFromAxisAngle(axis, angle) {\n var halfAngle = angle / 2,\n s = Math.sin(halfAngle);\n this.x = axis.x * s;\n this.y = axis.y * s;\n this.z = axis.z * s;\n this.w = Math.cos(halfAngle);\n return this;\n },\n multiply: function multiply(q) {\n return this.multiplyQuaternions(this, q);\n },\n multiplyQuaternions: function multiplyQuaternions(a, b) {\n var qax = a.x,\n qay = a.y,\n qaz = a.z,\n qaw = a.w;\n var qbx = b.x,\n qby = b.y,\n qbz = b.z,\n qbw = b.w;\n this.x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;\n this.y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;\n this.z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;\n this.w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;\n return this;\n },\n inverse: function inverse() {\n this.x *= -1;\n this.y *= -1;\n this.z *= -1;\n this.normalize();\n return this;\n },\n normalize: function normalize() {\n var l = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w);\n if (l === 0) {\n this.x = 0;\n this.y = 0;\n this.z = 0;\n this.w = 1;\n } else {\n l = 1 / l;\n this.x = this.x * l;\n this.y = this.y * l;\n this.z = this.z * l;\n this.w = this.w * l;\n }\n return this;\n },\n slerp: function slerp(qb, t) {\n if (t === 0) return this;\n if (t === 1) return this.copy(qb);\n var x = this.x,\n y = this.y,\n z = this.z,\n w = this.w;\n var cosHalfTheta = w * qb.w + x * qb.x + y * qb.y + z * qb.z;\n if (cosHalfTheta < 0) {\n this.w = -qb.w;\n this.x = -qb.x;\n this.y = -qb.y;\n this.z = -qb.z;\n cosHalfTheta = -cosHalfTheta;\n } else {\n this.copy(qb);\n }\n if (cosHalfTheta >= 1.0) {\n this.w = w;\n this.x = x;\n this.y = y;\n this.z = z;\n return this;\n }\n var halfTheta = Math.acos(cosHalfTheta);\n var sinHalfTheta = Math.sqrt(1.0 - cosHalfTheta * cosHalfTheta);\n if (Math.abs(sinHalfTheta) < 0.001) {\n this.w = 0.5 * (w + this.w);\n this.x = 0.5 * (x + this.x);\n this.y = 0.5 * (y + this.y);\n this.z = 0.5 * (z + this.z);\n return this;\n }\n var ratioA = Math.sin((1 - t) * halfTheta) / sinHalfTheta,\n ratioB = Math.sin(t * halfTheta) / sinHalfTheta;\n this.w = w * ratioA + this.w * ratioB;\n this.x = x * ratioA + this.x * ratioB;\n this.y = y * ratioA + this.y * ratioB;\n this.z = z * ratioA + this.z * ratioB;\n return this;\n },\n setFromUnitVectors: function () {\n var v1, r;\n var EPS = 0.000001;\n return function (vFrom, vTo) {\n if (v1 === undefined) v1 = new Vector3();\n r = vFrom.dot(vTo) + 1;\n if (r < EPS) {\n r = 0;\n if (Math.abs(vFrom.x) > Math.abs(vFrom.z)) {\n v1.set(-vFrom.y, vFrom.x, 0);\n } else {\n v1.set(0, -vFrom.z, vFrom.y);\n }\n } else {\n v1.crossVectors(vFrom, vTo);\n }\n this.x = v1.x;\n this.y = v1.y;\n this.z = v1.z;\n this.w = r;\n this.normalize();\n return this;\n };\n }()\n };\n function Device(params) {\n this.width = params.width || getScreenWidth();\n this.height = params.height || getScreenHeight();\n this.widthMeters = params.widthMeters;\n this.heightMeters = params.heightMeters;\n this.bevelMeters = params.bevelMeters;\n }\n var DEFAULT_ANDROID = new Device({\n widthMeters: 0.110,\n heightMeters: 0.062,\n bevelMeters: 0.004\n });\n var DEFAULT_IOS = new Device({\n widthMeters: 0.1038,\n heightMeters: 0.0584,\n bevelMeters: 0.004\n });\n var Viewers = {\n CardboardV1: new CardboardViewer({\n id: 'CardboardV1',\n label: 'Cardboard I/O 2014',\n fov: 40,\n interLensDistance: 0.060,\n baselineLensDistance: 0.035,\n screenLensDistance: 0.042,\n distortionCoefficients: [0.441, 0.156],\n inverseCoefficients: [-0.4410035, 0.42756155, -0.4804439, 0.5460139, -0.58821183, 0.5733938, -0.48303202, 0.33299083, -0.17573841, 0.0651772, -0.01488963, 0.001559834]\n }),\n CardboardV2: new CardboardViewer({\n id: 'CardboardV2',\n label: 'Cardboard I/O 2015',\n fov: 60,\n interLensDistance: 0.064,\n baselineLensDistance: 0.035,\n screenLensDistance: 0.039,\n distortionCoefficients: [0.34, 0.55],\n inverseCoefficients: [-0.33836704, -0.18162185, 0.862655, -1.2462051, 1.0560602, -0.58208317, 0.21609078, -0.05444823, 0.009177956, -9.904169E-4, 6.183535E-5, -1.6981803E-6]\n })\n };\n function DeviceInfo(deviceParams, additionalViewers) {\n this.viewer = Viewers.CardboardV2;\n this.updateDeviceParams(deviceParams);\n this.distortion = new Distortion(this.viewer.distortionCoefficients);\n for (var i = 0; i < additionalViewers.length; i++) {\n var viewer = additionalViewers[i];\n Viewers[viewer.id] = new CardboardViewer(viewer);\n }\n }\n DeviceInfo.prototype.updateDeviceParams = function (deviceParams) {\n this.device = this.determineDevice_(deviceParams) || this.device;\n };\n DeviceInfo.prototype.getDevice = function () {\n return this.device;\n };\n DeviceInfo.prototype.setViewer = function (viewer) {\n this.viewer = viewer;\n this.distortion = new Distortion(this.viewer.distortionCoefficients);\n };\n DeviceInfo.prototype.determineDevice_ = function (deviceParams) {\n if (!deviceParams) {\n if (isIOS()) {\n console.warn('Using fallback iOS device measurements.');\n return DEFAULT_IOS;\n } else {\n console.warn('Using fallback Android device measurements.');\n return DEFAULT_ANDROID;\n }\n }\n var METERS_PER_INCH = 0.0254;\n var metersPerPixelX = METERS_PER_INCH / deviceParams.xdpi;\n var metersPerPixelY = METERS_PER_INCH / deviceParams.ydpi;\n var width = getScreenWidth();\n var height = getScreenHeight();\n return new Device({\n widthMeters: metersPerPixelX * width,\n heightMeters: metersPerPixelY * height,\n bevelMeters: deviceParams.bevelMm * 0.001\n });\n };\n DeviceInfo.prototype.getDistortedFieldOfViewLeftEye = function () {\n var viewer = this.viewer;\n var device = this.device;\n var distortion = this.distortion;\n var eyeToScreenDistance = viewer.screenLensDistance;\n var outerDist = (device.widthMeters - viewer.interLensDistance) / 2;\n var innerDist = viewer.interLensDistance / 2;\n var bottomDist = viewer.baselineLensDistance - device.bevelMeters;\n var topDist = device.heightMeters - bottomDist;\n var outerAngle = radToDeg * Math.atan(distortion.distort(outerDist / eyeToScreenDistance));\n var innerAngle = radToDeg * Math.atan(distortion.distort(innerDist / eyeToScreenDistance));\n var bottomAngle = radToDeg * Math.atan(distortion.distort(bottomDist / eyeToScreenDistance));\n var topAngle = radToDeg * Math.atan(distortion.distort(topDist / eyeToScreenDistance));\n return {\n leftDegrees: Math.min(outerAngle, viewer.fov),\n rightDegrees: Math.min(innerAngle, viewer.fov),\n downDegrees: Math.min(bottomAngle, viewer.fov),\n upDegrees: Math.min(topAngle, viewer.fov)\n };\n };\n DeviceInfo.prototype.getLeftEyeVisibleTanAngles = function () {\n var viewer = this.viewer;\n var device = this.device;\n var distortion = this.distortion;\n var fovLeft = Math.tan(-degToRad * viewer.fov);\n var fovTop = Math.tan(degToRad * viewer.fov);\n var fovRight = Math.tan(degToRad * viewer.fov);\n var fovBottom = Math.tan(-degToRad * viewer.fov);\n var halfWidth = device.widthMeters / 4;\n var halfHeight = device.heightMeters / 2;\n var verticalLensOffset = viewer.baselineLensDistance - device.bevelMeters - halfHeight;\n var centerX = viewer.interLensDistance / 2 - halfWidth;\n var centerY = -verticalLensOffset;\n var centerZ = viewer.screenLensDistance;\n var screenLeft = distortion.distort((centerX - halfWidth) / centerZ);\n var screenTop = distortion.distort((centerY + halfHeight) / centerZ);\n var screenRight = distortion.distort((centerX + halfWidth) / centerZ);\n var screenBottom = distortion.distort((centerY - halfHeight) / centerZ);\n var result = new Float32Array(4);\n result[0] = Math.max(fovLeft, screenLeft);\n result[1] = Math.min(fovTop, screenTop);\n result[2] = Math.min(fovRight, screenRight);\n result[3] = Math.max(fovBottom, screenBottom);\n return result;\n };\n DeviceInfo.prototype.getLeftEyeNoLensTanAngles = function () {\n var viewer = this.viewer;\n var device = this.device;\n var distortion = this.distortion;\n var result = new Float32Array(4);\n var fovLeft = distortion.distortInverse(Math.tan(-degToRad * viewer.fov));\n var fovTop = distortion.distortInverse(Math.tan(degToRad * viewer.fov));\n var fovRight = distortion.distortInverse(Math.tan(degToRad * viewer.fov));\n var fovBottom = distortion.distortInverse(Math.tan(-degToRad * viewer.fov));\n var halfWidth = device.widthMeters / 4;\n var halfHeight = device.heightMeters / 2;\n var verticalLensOffset = viewer.baselineLensDistance - device.bevelMeters - halfHeight;\n var centerX = viewer.interLensDistance / 2 - halfWidth;\n var centerY = -verticalLensOffset;\n var centerZ = viewer.screenLensDistance;\n var screenLeft = (centerX - halfWidth) / centerZ;\n var screenTop = (centerY + halfHeight) / centerZ;\n var screenRight = (centerX + halfWidth) / centerZ;\n var screenBottom = (centerY - halfHeight) / centerZ;\n result[0] = Math.max(fovLeft, screenLeft);\n result[1] = Math.min(fovTop, screenTop);\n result[2] = Math.min(fovRight, screenRight);\n result[3] = Math.max(fovBottom, screenBottom);\n return result;\n };\n DeviceInfo.prototype.getLeftEyeVisibleScreenRect = function (undistortedFrustum) {\n var viewer = this.viewer;\n var device = this.device;\n var dist = viewer.screenLensDistance;\n var eyeX = (device.widthMeters - viewer.interLensDistance) / 2;\n var eyeY = viewer.baselineLensDistance - device.bevelMeters;\n var left = (undistortedFrustum[0] * dist + eyeX) / device.widthMeters;\n var top = (undistortedFrustum[1] * dist + eyeY) / device.heightMeters;\n var right = (undistortedFrustum[2] * dist + eyeX) / device.widthMeters;\n var bottom = (undistortedFrustum[3] * dist + eyeY) / device.heightMeters;\n return {\n x: left,\n y: bottom,\n width: right - left,\n height: top - bottom\n };\n };\n DeviceInfo.prototype.getFieldOfViewLeftEye = function (opt_isUndistorted) {\n return opt_isUndistorted ? this.getUndistortedFieldOfViewLeftEye() : this.getDistortedFieldOfViewLeftEye();\n };\n DeviceInfo.prototype.getFieldOfViewRightEye = function (opt_isUndistorted) {\n var fov = this.getFieldOfViewLeftEye(opt_isUndistorted);\n return {\n leftDegrees: fov.rightDegrees,\n rightDegrees: fov.leftDegrees,\n upDegrees: fov.upDegrees,\n downDegrees: fov.downDegrees\n };\n };\n DeviceInfo.prototype.getUndistortedFieldOfViewLeftEye = function () {\n var p = this.getUndistortedParams_();\n return {\n leftDegrees: radToDeg * Math.atan(p.outerDist),\n rightDegrees: radToDeg * Math.atan(p.innerDist),\n downDegrees: radToDeg * Math.atan(p.bottomDist),\n upDegrees: radToDeg * Math.atan(p.topDist)\n };\n };\n DeviceInfo.prototype.getUndistortedViewportLeftEye = function () {\n var p = this.getUndistortedParams_();\n var viewer = this.viewer;\n var device = this.device;\n var eyeToScreenDistance = viewer.screenLensDistance;\n var screenWidth = device.widthMeters / eyeToScreenDistance;\n var screenHeight = device.heightMeters / eyeToScreenDistance;\n var xPxPerTanAngle = device.width / screenWidth;\n var yPxPerTanAngle = device.height / screenHeight;\n var x = Math.round((p.eyePosX - p.outerDist) * xPxPerTanAngle);\n var y = Math.round((p.eyePosY - p.bottomDist) * yPxPerTanAngle);\n return {\n x: x,\n y: y,\n width: Math.round((p.eyePosX + p.innerDist) * xPxPerTanAngle) - x,\n height: Math.round((p.eyePosY + p.topDist) * yPxPerTanAngle) - y\n };\n };\n DeviceInfo.prototype.getUndistortedParams_ = function () {\n var viewer = this.viewer;\n var device = this.device;\n var distortion = this.distortion;\n var eyeToScreenDistance = viewer.screenLensDistance;\n var halfLensDistance = viewer.interLensDistance / 2 / eyeToScreenDistance;\n var screenWidth = device.widthMeters / eyeToScreenDistance;\n var screenHeight = device.heightMeters / eyeToScreenDistance;\n var eyePosX = screenWidth / 2 - halfLensDistance;\n var eyePosY = (viewer.baselineLensDistance - device.bevelMeters) / eyeToScreenDistance;\n var maxFov = viewer.fov;\n var viewerMax = distortion.distortInverse(Math.tan(degToRad * maxFov));\n var outerDist = Math.min(eyePosX, viewerMax);\n var innerDist = Math.min(halfLensDistance, viewerMax);\n var bottomDist = Math.min(eyePosY, viewerMax);\n var topDist = Math.min(screenHeight - eyePosY, viewerMax);\n return {\n outerDist: outerDist,\n innerDist: innerDist,\n topDist: topDist,\n bottomDist: bottomDist,\n eyePosX: eyePosX,\n eyePosY: eyePosY\n };\n };\n function CardboardViewer(params) {\n this.id = params.id;\n this.label = params.label;\n this.fov = params.fov;\n this.interLensDistance = params.interLensDistance;\n this.baselineLensDistance = params.baselineLensDistance;\n this.screenLensDistance = params.screenLensDistance;\n this.distortionCoefficients = params.distortionCoefficients;\n this.inverseCoefficients = params.inverseCoefficients;\n }\n DeviceInfo.Viewers = Viewers;\n var format = 1;\n var last_updated = \"2019-11-09T17:36:14Z\";\n var devices = [{\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"asus/*/Nexus 7/*\"\n }, {\n \"ua\": \"Nexus 7\"\n }],\n \"dpi\": [320.8, 323],\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"asus/*/ASUS_X00PD/*\"\n }, {\n \"ua\": \"ASUS_X00PD\"\n }],\n \"dpi\": 245,\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"asus/*/ASUS_X008D/*\"\n }, {\n \"ua\": \"ASUS_X008D\"\n }],\n \"dpi\": 282,\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"asus/*/ASUS_Z00AD/*\"\n }, {\n \"ua\": \"ASUS_Z00AD\"\n }],\n \"dpi\": [403, 404.6],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"Google/*/Pixel 2 XL/*\"\n }, {\n \"ua\": \"Pixel 2 XL\"\n }],\n \"dpi\": 537.9,\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"Google/*/Pixel 3 XL/*\"\n }, {\n \"ua\": \"Pixel 3 XL\"\n }],\n \"dpi\": [558.5, 553.8],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"Google/*/Pixel XL/*\"\n }, {\n \"ua\": \"Pixel XL\"\n }],\n \"dpi\": [537.9, 533],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"Google/*/Pixel 3/*\"\n }, {\n \"ua\": \"Pixel 3\"\n }],\n \"dpi\": 442.4,\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"Google/*/Pixel 2/*\"\n }, {\n \"ua\": \"Pixel 2\"\n }],\n \"dpi\": 441,\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"Google/*/Pixel/*\"\n }, {\n \"ua\": \"Pixel\"\n }],\n \"dpi\": [432.6, 436.7],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"HTC/*/HTC6435LVW/*\"\n }, {\n \"ua\": \"HTC6435LVW\"\n }],\n \"dpi\": [449.7, 443.3],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"HTC/*/HTC One XL/*\"\n }, {\n \"ua\": \"HTC One XL\"\n }],\n \"dpi\": [315.3, 314.6],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"htc/*/Nexus 9/*\"\n }, {\n \"ua\": \"Nexus 9\"\n }],\n \"dpi\": 289,\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"HTC/*/HTC One M9/*\"\n }, {\n \"ua\": \"HTC One M9\"\n }],\n \"dpi\": [442.5, 443.3],\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"HTC/*/HTC One_M8/*\"\n }, {\n \"ua\": \"HTC One_M8\"\n }],\n \"dpi\": [449.7, 447.4],\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"HTC/*/HTC One/*\"\n }, {\n \"ua\": \"HTC One\"\n }],\n \"dpi\": 472.8,\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"Huawei/*/Nexus 6P/*\"\n }, {\n \"ua\": \"Nexus 6P\"\n }],\n \"dpi\": [515.1, 518],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"Huawei/*/BLN-L24/*\"\n }, {\n \"ua\": \"HONORBLN-L24\"\n }],\n \"dpi\": 480,\n \"bw\": 4,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"Huawei/*/BKL-L09/*\"\n }, {\n \"ua\": \"BKL-L09\"\n }],\n \"dpi\": 403,\n \"bw\": 3.47,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"LENOVO/*/Lenovo PB2-690Y/*\"\n }, {\n \"ua\": \"Lenovo PB2-690Y\"\n }],\n \"dpi\": [457.2, 454.713],\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"LGE/*/Nexus 5X/*\"\n }, {\n \"ua\": \"Nexus 5X\"\n }],\n \"dpi\": [422, 419.9],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"LGE/*/LGMS345/*\"\n }, {\n \"ua\": \"LGMS345\"\n }],\n \"dpi\": [221.7, 219.1],\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"LGE/*/LG-D800/*\"\n }, {\n \"ua\": \"LG-D800\"\n }],\n \"dpi\": [422, 424.1],\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"LGE/*/LG-D850/*\"\n }, {\n \"ua\": \"LG-D850\"\n }],\n \"dpi\": [537.9, 541.9],\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"LGE/*/VS985 4G/*\"\n }, {\n \"ua\": \"VS985 4G\"\n }],\n \"dpi\": [537.9, 535.6],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"LGE/*/Nexus 5/*\"\n }, {\n \"ua\": \"Nexus 5 B\"\n }],\n \"dpi\": [442.4, 444.8],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"LGE/*/Nexus 4/*\"\n }, {\n \"ua\": \"Nexus 4\"\n }],\n \"dpi\": [319.8, 318.4],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"LGE/*/LG-P769/*\"\n }, {\n \"ua\": \"LG-P769\"\n }],\n \"dpi\": [240.6, 247.5],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"LGE/*/LGMS323/*\"\n }, {\n \"ua\": \"LGMS323\"\n }],\n \"dpi\": [206.6, 204.6],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"LGE/*/LGLS996/*\"\n }, {\n \"ua\": \"LGLS996\"\n }],\n \"dpi\": [403.4, 401.5],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"Micromax/*/4560MMX/*\"\n }, {\n \"ua\": \"4560MMX\"\n }],\n \"dpi\": [240, 219.4],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"Micromax/*/A250/*\"\n }, {\n \"ua\": \"Micromax A250\"\n }],\n \"dpi\": [480, 446.4],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"Micromax/*/Micromax AQ4501/*\"\n }, {\n \"ua\": \"Micromax AQ4501\"\n }],\n \"dpi\": 240,\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"motorola/*/G5/*\"\n }, {\n \"ua\": \"Moto G (5) Plus\"\n }],\n \"dpi\": [403.4, 403],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"motorola/*/DROID RAZR/*\"\n }, {\n \"ua\": \"DROID RAZR\"\n }],\n \"dpi\": [368.1, 256.7],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"motorola/*/XT830C/*\"\n }, {\n \"ua\": \"XT830C\"\n }],\n \"dpi\": [254, 255.9],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"motorola/*/XT1021/*\"\n }, {\n \"ua\": \"XT1021\"\n }],\n \"dpi\": [254, 256.7],\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"motorola/*/XT1023/*\"\n }, {\n \"ua\": \"XT1023\"\n }],\n \"dpi\": [254, 256.7],\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"motorola/*/XT1028/*\"\n }, {\n \"ua\": \"XT1028\"\n }],\n \"dpi\": [326.6, 327.6],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"motorola/*/XT1034/*\"\n }, {\n \"ua\": \"XT1034\"\n }],\n \"dpi\": [326.6, 328.4],\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"motorola/*/XT1053/*\"\n }, {\n \"ua\": \"XT1053\"\n }],\n \"dpi\": [315.3, 316.1],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"motorola/*/XT1562/*\"\n }, {\n \"ua\": \"XT1562\"\n }],\n \"dpi\": [403.4, 402.7],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"motorola/*/Nexus 6/*\"\n }, {\n \"ua\": \"Nexus 6 B\"\n }],\n \"dpi\": [494.3, 489.7],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"motorola/*/XT1063/*\"\n }, {\n \"ua\": \"XT1063\"\n }],\n \"dpi\": [295, 296.6],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"motorola/*/XT1064/*\"\n }, {\n \"ua\": \"XT1064\"\n }],\n \"dpi\": [295, 295.6],\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"motorola/*/XT1092/*\"\n }, {\n \"ua\": \"XT1092\"\n }],\n \"dpi\": [422, 424.1],\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"motorola/*/XT1095/*\"\n }, {\n \"ua\": \"XT1095\"\n }],\n \"dpi\": [422, 423.4],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"motorola/*/G4/*\"\n }, {\n \"ua\": \"Moto G (4)\"\n }],\n \"dpi\": 401,\n \"bw\": 4,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"OnePlus/*/A0001/*\"\n }, {\n \"ua\": \"A0001\"\n }],\n \"dpi\": [403.4, 401],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"OnePlus/*/ONE E1001/*\"\n }, {\n \"ua\": \"ONE E1001\"\n }],\n \"dpi\": [442.4, 441.4],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"OnePlus/*/ONE E1003/*\"\n }, {\n \"ua\": \"ONE E1003\"\n }],\n \"dpi\": [442.4, 441.4],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"OnePlus/*/ONE E1005/*\"\n }, {\n \"ua\": \"ONE E1005\"\n }],\n \"dpi\": [442.4, 441.4],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"OnePlus/*/ONE A2001/*\"\n }, {\n \"ua\": \"ONE A2001\"\n }],\n \"dpi\": [391.9, 405.4],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"OnePlus/*/ONE A2003/*\"\n }, {\n \"ua\": \"ONE A2003\"\n }],\n \"dpi\": [391.9, 405.4],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"OnePlus/*/ONE A2005/*\"\n }, {\n \"ua\": \"ONE A2005\"\n }],\n \"dpi\": [391.9, 405.4],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"OnePlus/*/ONEPLUS A3000/*\"\n }, {\n \"ua\": \"ONEPLUS A3000\"\n }],\n \"dpi\": 401,\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"OnePlus/*/ONEPLUS A3003/*\"\n }, {\n \"ua\": \"ONEPLUS A3003\"\n }],\n \"dpi\": 401,\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"OnePlus/*/ONEPLUS A3010/*\"\n }, {\n \"ua\": \"ONEPLUS A3010\"\n }],\n \"dpi\": 401,\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"OnePlus/*/ONEPLUS A5000/*\"\n }, {\n \"ua\": \"ONEPLUS A5000 \"\n }],\n \"dpi\": [403.411, 399.737],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"OnePlus/*/ONE A5010/*\"\n }, {\n \"ua\": \"ONEPLUS A5010\"\n }],\n \"dpi\": [403, 400],\n \"bw\": 2,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"OnePlus/*/ONEPLUS A6000/*\"\n }, {\n \"ua\": \"ONEPLUS A6000\"\n }],\n \"dpi\": 401,\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"OnePlus/*/ONEPLUS A6003/*\"\n }, {\n \"ua\": \"ONEPLUS A6003\"\n }],\n \"dpi\": 401,\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"OnePlus/*/ONEPLUS A6010/*\"\n }, {\n \"ua\": \"ONEPLUS A6010\"\n }],\n \"dpi\": 401,\n \"bw\": 2,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"OnePlus/*/ONEPLUS A6013/*\"\n }, {\n \"ua\": \"ONEPLUS A6013\"\n }],\n \"dpi\": 401,\n \"bw\": 2,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"OPPO/*/X909/*\"\n }, {\n \"ua\": \"X909\"\n }],\n \"dpi\": [442.4, 444.1],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/GT-I9082/*\"\n }, {\n \"ua\": \"GT-I9082\"\n }],\n \"dpi\": [184.7, 185.4],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-G360P/*\"\n }, {\n \"ua\": \"SM-G360P\"\n }],\n \"dpi\": [196.7, 205.4],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/Nexus S/*\"\n }, {\n \"ua\": \"Nexus S\"\n }],\n \"dpi\": [234.5, 229.8],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/GT-I9300/*\"\n }, {\n \"ua\": \"GT-I9300\"\n }],\n \"dpi\": [304.8, 303.9],\n \"bw\": 5,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-T230NU/*\"\n }, {\n \"ua\": \"SM-T230NU\"\n }],\n \"dpi\": 216,\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SGH-T399/*\"\n }, {\n \"ua\": \"SGH-T399\"\n }],\n \"dpi\": [217.7, 231.4],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SGH-M919/*\"\n }, {\n \"ua\": \"SGH-M919\"\n }],\n \"dpi\": [440.8, 437.7],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-N9005/*\"\n }, {\n \"ua\": \"SM-N9005\"\n }],\n \"dpi\": [386.4, 387],\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SAMSUNG-SM-N900A/*\"\n }, {\n \"ua\": \"SAMSUNG-SM-N900A\"\n }],\n \"dpi\": [386.4, 387.7],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/GT-I9500/*\"\n }, {\n \"ua\": \"GT-I9500\"\n }],\n \"dpi\": [442.5, 443.3],\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/GT-I9505/*\"\n }, {\n \"ua\": \"GT-I9505\"\n }],\n \"dpi\": 439.4,\n \"bw\": 4,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-G900F/*\"\n }, {\n \"ua\": \"SM-G900F\"\n }],\n \"dpi\": [415.6, 431.6],\n \"bw\": 5,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-G900M/*\"\n }, {\n \"ua\": \"SM-G900M\"\n }],\n \"dpi\": [415.6, 431.6],\n \"bw\": 5,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-G800F/*\"\n }, {\n \"ua\": \"SM-G800F\"\n }],\n \"dpi\": 326.8,\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-G906S/*\"\n }, {\n \"ua\": \"SM-G906S\"\n }],\n \"dpi\": [562.7, 572.4],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/GT-I9300/*\"\n }, {\n \"ua\": \"GT-I9300\"\n }],\n \"dpi\": [306.7, 304.8],\n \"bw\": 5,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-T535/*\"\n }, {\n \"ua\": \"SM-T535\"\n }],\n \"dpi\": [142.6, 136.4],\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-N920C/*\"\n }, {\n \"ua\": \"SM-N920C\"\n }],\n \"dpi\": [515.1, 518.4],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-N920P/*\"\n }, {\n \"ua\": \"SM-N920P\"\n }],\n \"dpi\": [386.3655, 390.144],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-N920W8/*\"\n }, {\n \"ua\": \"SM-N920W8\"\n }],\n \"dpi\": [515.1, 518.4],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/GT-I9300I/*\"\n }, {\n \"ua\": \"GT-I9300I\"\n }],\n \"dpi\": [304.8, 305.8],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/GT-I9195/*\"\n }, {\n \"ua\": \"GT-I9195\"\n }],\n \"dpi\": [249.4, 256.7],\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SPH-L520/*\"\n }, {\n \"ua\": \"SPH-L520\"\n }],\n \"dpi\": [249.4, 255.9],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SAMSUNG-SGH-I717/*\"\n }, {\n \"ua\": \"SAMSUNG-SGH-I717\"\n }],\n \"dpi\": 285.8,\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SPH-D710/*\"\n }, {\n \"ua\": \"SPH-D710\"\n }],\n \"dpi\": [217.7, 204.2],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/GT-N7100/*\"\n }, {\n \"ua\": \"GT-N7100\"\n }],\n \"dpi\": 265.1,\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SCH-I605/*\"\n }, {\n \"ua\": \"SCH-I605\"\n }],\n \"dpi\": 265.1,\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/Galaxy Nexus/*\"\n }, {\n \"ua\": \"Galaxy Nexus\"\n }],\n \"dpi\": [315.3, 314.2],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-N910H/*\"\n }, {\n \"ua\": \"SM-N910H\"\n }],\n \"dpi\": [515.1, 518],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-N910C/*\"\n }, {\n \"ua\": \"SM-N910C\"\n }],\n \"dpi\": [515.2, 520.2],\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-G130M/*\"\n }, {\n \"ua\": \"SM-G130M\"\n }],\n \"dpi\": [165.9, 164.8],\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-G928I/*\"\n }, {\n \"ua\": \"SM-G928I\"\n }],\n \"dpi\": [515.1, 518.4],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-G920F/*\"\n }, {\n \"ua\": \"SM-G920F\"\n }],\n \"dpi\": 580.6,\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-G920P/*\"\n }, {\n \"ua\": \"SM-G920P\"\n }],\n \"dpi\": [522.5, 577],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-G925F/*\"\n }, {\n \"ua\": \"SM-G925F\"\n }],\n \"dpi\": 580.6,\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-G925V/*\"\n }, {\n \"ua\": \"SM-G925V\"\n }],\n \"dpi\": [522.5, 576.6],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-G930F/*\"\n }, {\n \"ua\": \"SM-G930F\"\n }],\n \"dpi\": 576.6,\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-G935F/*\"\n }, {\n \"ua\": \"SM-G935F\"\n }],\n \"dpi\": 533,\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-G950F/*\"\n }, {\n \"ua\": \"SM-G950F\"\n }],\n \"dpi\": [562.707, 565.293],\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-G955U/*\"\n }, {\n \"ua\": \"SM-G955U\"\n }],\n \"dpi\": [522.514, 525.762],\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-G955F/*\"\n }, {\n \"ua\": \"SM-G955F\"\n }],\n \"dpi\": [522.514, 525.762],\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-G960F/*\"\n }, {\n \"ua\": \"SM-G960F\"\n }],\n \"dpi\": [569.575, 571.5],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-G9600/*\"\n }, {\n \"ua\": \"SM-G9600\"\n }],\n \"dpi\": [569.575, 571.5],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-G960T/*\"\n }, {\n \"ua\": \"SM-G960T\"\n }],\n \"dpi\": [569.575, 571.5],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-G960N/*\"\n }, {\n \"ua\": \"SM-G960N\"\n }],\n \"dpi\": [569.575, 571.5],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-G960U/*\"\n }, {\n \"ua\": \"SM-G960U\"\n }],\n \"dpi\": [569.575, 571.5],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-G9608/*\"\n }, {\n \"ua\": \"SM-G9608\"\n }],\n \"dpi\": [569.575, 571.5],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-G960FD/*\"\n }, {\n \"ua\": \"SM-G960FD\"\n }],\n \"dpi\": [569.575, 571.5],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-G960W/*\"\n }, {\n \"ua\": \"SM-G960W\"\n }],\n \"dpi\": [569.575, 571.5],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-G965F/*\"\n }, {\n \"ua\": \"SM-G965F\"\n }],\n \"dpi\": 529,\n \"bw\": 2,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"Sony/*/C6903/*\"\n }, {\n \"ua\": \"C6903\"\n }],\n \"dpi\": [442.5, 443.3],\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"Sony/*/D6653/*\"\n }, {\n \"ua\": \"D6653\"\n }],\n \"dpi\": [428.6, 427.6],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"Sony/*/E6653/*\"\n }, {\n \"ua\": \"E6653\"\n }],\n \"dpi\": [428.6, 425.7],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"Sony/*/E6853/*\"\n }, {\n \"ua\": \"E6853\"\n }],\n \"dpi\": [403.4, 401.9],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"Sony/*/SGP321/*\"\n }, {\n \"ua\": \"SGP321\"\n }],\n \"dpi\": [224.7, 224.1],\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"TCT/*/ALCATEL ONE TOUCH Fierce/*\"\n }, {\n \"ua\": \"ALCATEL ONE TOUCH Fierce\"\n }],\n \"dpi\": [240, 247.5],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"THL/*/thl 5000/*\"\n }, {\n \"ua\": \"thl 5000\"\n }],\n \"dpi\": [480, 443.3],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"Fly/*/IQ4412/*\"\n }, {\n \"ua\": \"IQ4412\"\n }],\n \"dpi\": 307.9,\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"ZTE/*/ZTE Blade L2/*\"\n }, {\n \"ua\": \"ZTE Blade L2\"\n }],\n \"dpi\": 240,\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"BENEVE/*/VR518/*\"\n }, {\n \"ua\": \"VR518\"\n }],\n \"dpi\": 480,\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"ios\",\n \"rules\": [{\n \"res\": [640, 960]\n }],\n \"dpi\": [325.1, 328.4],\n \"bw\": 4,\n \"ac\": 1000\n }, {\n \"type\": \"ios\",\n \"rules\": [{\n \"res\": [640, 1136]\n }],\n \"dpi\": [317.1, 320.2],\n \"bw\": 3,\n \"ac\": 1000\n }, {\n \"type\": \"ios\",\n \"rules\": [{\n \"res\": [750, 1334]\n }],\n \"dpi\": 326.4,\n \"bw\": 4,\n \"ac\": 1000\n }, {\n \"type\": \"ios\",\n \"rules\": [{\n \"res\": [1242, 2208]\n }],\n \"dpi\": [453.6, 458.4],\n \"bw\": 4,\n \"ac\": 1000\n }, {\n \"type\": \"ios\",\n \"rules\": [{\n \"res\": [1125, 2001]\n }],\n \"dpi\": [410.9, 415.4],\n \"bw\": 4,\n \"ac\": 1000\n }, {\n \"type\": \"ios\",\n \"rules\": [{\n \"res\": [1125, 2436]\n }],\n \"dpi\": 458,\n \"bw\": 4,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"Huawei/*/EML-L29/*\"\n }, {\n \"ua\": \"EML-L29\"\n }],\n \"dpi\": 428,\n \"bw\": 3.45,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"Nokia/*/Nokia 7.1/*\"\n }, {\n \"ua\": \"Nokia 7.1\"\n }],\n \"dpi\": [432, 431.9],\n \"bw\": 3,\n \"ac\": 500\n }, {\n \"type\": \"ios\",\n \"rules\": [{\n \"res\": [1242, 2688]\n }],\n \"dpi\": 458,\n \"bw\": 4,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-G570M/*\"\n }, {\n \"ua\": \"SM-G570M\"\n }],\n \"dpi\": 320,\n \"bw\": 3.684,\n \"ac\": 1000\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-G970F/*\"\n }, {\n \"ua\": \"SM-G970F\"\n }],\n \"dpi\": 438,\n \"bw\": 2.281,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-G973F/*\"\n }, {\n \"ua\": \"SM-G973F\"\n }],\n \"dpi\": 550,\n \"bw\": 2.002,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-G975F/*\"\n }, {\n \"ua\": \"SM-G975F\"\n }],\n \"dpi\": 522,\n \"bw\": 2.054,\n \"ac\": 500\n }, {\n \"type\": \"android\",\n \"rules\": [{\n \"mdmh\": \"samsung/*/SM-G977F/*\"\n }, {\n \"ua\": \"SM-G977F\"\n }],\n \"dpi\": 505,\n \"bw\": 2.334,\n \"ac\": 500\n }, {\n \"type\": \"ios\",\n \"rules\": [{\n \"res\": [828, 1792]\n }],\n \"dpi\": 326,\n \"bw\": 5,\n \"ac\": 500\n }];\n var DPDB_CACHE = {\n format: format,\n last_updated: last_updated,\n devices: devices\n };\n function Dpdb(url, onDeviceParamsUpdated) {\n this.dpdb = DPDB_CACHE;\n this.recalculateDeviceParams_();\n if (url) {\n this.onDeviceParamsUpdated = onDeviceParamsUpdated;\n var xhr = new XMLHttpRequest();\n var obj = this;\n xhr.open('GET', url, true);\n xhr.addEventListener('load', function () {\n obj.loading = false;\n if (xhr.status >= 200 && xhr.status <= 299) {\n obj.dpdb = JSON.parse(xhr.response);\n obj.recalculateDeviceParams_();\n } else {\n console.error('Error loading online DPDB!');\n }\n });\n xhr.send();\n }\n }\n Dpdb.prototype.getDeviceParams = function () {\n return this.deviceParams;\n };\n Dpdb.prototype.recalculateDeviceParams_ = function () {\n var newDeviceParams = this.calcDeviceParams_();\n if (newDeviceParams) {\n this.deviceParams = newDeviceParams;\n if (this.onDeviceParamsUpdated) {\n this.onDeviceParamsUpdated(this.deviceParams);\n }\n } else {\n console.error('Failed to recalculate device parameters.');\n }\n };\n Dpdb.prototype.calcDeviceParams_ = function () {\n var db = this.dpdb;\n if (!db) {\n console.error('DPDB not available.');\n return null;\n }\n if (db.format != 1) {\n console.error('DPDB has unexpected format version.');\n return null;\n }\n if (!db.devices || !db.devices.length) {\n console.error('DPDB does not have a devices section.');\n return null;\n }\n var userAgent = navigator.userAgent || navigator.vendor || window.opera;\n var width = getScreenWidth();\n var height = getScreenHeight();\n if (!db.devices) {\n console.error('DPDB has no devices section.');\n return null;\n }\n for (var i = 0; i < db.devices.length; i++) {\n var device = db.devices[i];\n if (!device.rules) {\n console.warn('Device[' + i + '] has no rules section.');\n continue;\n }\n if (device.type != 'ios' && device.type != 'android') {\n console.warn('Device[' + i + '] has invalid type.');\n continue;\n }\n if (isIOS() != (device.type == 'ios')) continue;\n var matched = false;\n for (var j = 0; j < device.rules.length; j++) {\n var rule = device.rules[j];\n if (this.ruleMatches_(rule, userAgent, width, height)) {\n matched = true;\n break;\n }\n }\n if (!matched) continue;\n var xdpi = device.dpi[0] || device.dpi;\n var ydpi = device.dpi[1] || device.dpi;\n return new DeviceParams({\n xdpi: xdpi,\n ydpi: ydpi,\n bevelMm: device.bw\n });\n }\n console.warn('No DPDB device match.');\n return null;\n };\n Dpdb.prototype.ruleMatches_ = function (rule, ua, screenWidth, screenHeight) {\n if (!rule.ua && !rule.res) return false;\n if (rule.ua && rule.ua.substring(0, 2) === 'SM') rule.ua = rule.ua.substring(0, 7);\n if (rule.ua && ua.indexOf(rule.ua) < 0) return false;\n if (rule.res) {\n if (!rule.res[0] || !rule.res[1]) return false;\n var resX = rule.res[0];\n var resY = rule.res[1];\n if (Math.min(screenWidth, screenHeight) != Math.min(resX, resY) || Math.max(screenWidth, screenHeight) != Math.max(resX, resY)) {\n return false;\n }\n }\n return true;\n };\n function DeviceParams(params) {\n this.xdpi = params.xdpi;\n this.ydpi = params.ydpi;\n this.bevelMm = params.bevelMm;\n }\n function SensorSample(sample, timestampS) {\n this.set(sample, timestampS);\n }\n SensorSample.prototype.set = function (sample, timestampS) {\n this.sample = sample;\n this.timestampS = timestampS;\n };\n SensorSample.prototype.copy = function (sensorSample) {\n this.set(sensorSample.sample, sensorSample.timestampS);\n };\n function ComplementaryFilter(kFilter, isDebug) {\n this.kFilter = kFilter;\n this.isDebug = isDebug;\n this.currentAccelMeasurement = new SensorSample();\n this.currentGyroMeasurement = new SensorSample();\n this.previousGyroMeasurement = new SensorSample();\n if (isIOS()) {\n this.filterQ = new Quaternion(-1, 0, 0, 1);\n } else {\n this.filterQ = new Quaternion(1, 0, 0, 1);\n }\n this.previousFilterQ = new Quaternion();\n this.previousFilterQ.copy(this.filterQ);\n this.accelQ = new Quaternion();\n this.isOrientationInitialized = false;\n this.estimatedGravity = new Vector3();\n this.measuredGravity = new Vector3();\n this.gyroIntegralQ = new Quaternion();\n }\n ComplementaryFilter.prototype.addAccelMeasurement = function (vector, timestampS) {\n this.currentAccelMeasurement.set(vector, timestampS);\n };\n ComplementaryFilter.prototype.addGyroMeasurement = function (vector, timestampS) {\n this.currentGyroMeasurement.set(vector, timestampS);\n var deltaT = timestampS - this.previousGyroMeasurement.timestampS;\n if (isTimestampDeltaValid(deltaT)) {\n this.run_();\n }\n this.previousGyroMeasurement.copy(this.currentGyroMeasurement);\n };\n ComplementaryFilter.prototype.run_ = function () {\n if (!this.isOrientationInitialized) {\n this.accelQ = this.accelToQuaternion_(this.currentAccelMeasurement.sample);\n this.previousFilterQ.copy(this.accelQ);\n this.isOrientationInitialized = true;\n return;\n }\n var deltaT = this.currentGyroMeasurement.timestampS - this.previousGyroMeasurement.timestampS;\n var gyroDeltaQ = this.gyroToQuaternionDelta_(this.currentGyroMeasurement.sample, deltaT);\n this.gyroIntegralQ.multiply(gyroDeltaQ);\n this.filterQ.copy(this.previousFilterQ);\n this.filterQ.multiply(gyroDeltaQ);\n var invFilterQ = new Quaternion();\n invFilterQ.copy(this.filterQ);\n invFilterQ.inverse();\n this.estimatedGravity.set(0, 0, -1);\n this.estimatedGravity.applyQuaternion(invFilterQ);\n this.estimatedGravity.normalize();\n this.measuredGravity.copy(this.currentAccelMeasurement.sample);\n this.measuredGravity.normalize();\n var deltaQ = new Quaternion();\n deltaQ.setFromUnitVectors(this.estimatedGravity, this.measuredGravity);\n deltaQ.inverse();\n if (this.isDebug) {\n console.log('Delta: %d deg, G_est: (%s, %s, %s), G_meas: (%s, %s, %s)', radToDeg * getQuaternionAngle(deltaQ), this.estimatedGravity.x.toFixed(1), this.estimatedGravity.y.toFixed(1), this.estimatedGravity.z.toFixed(1), this.measuredGravity.x.toFixed(1), this.measuredGravity.y.toFixed(1), this.measuredGravity.z.toFixed(1));\n }\n var targetQ = new Quaternion();\n targetQ.copy(this.filterQ);\n targetQ.multiply(deltaQ);\n this.filterQ.slerp(targetQ, 1 - this.kFilter);\n this.previousFilterQ.copy(this.filterQ);\n };\n ComplementaryFilter.prototype.getOrientation = function () {\n return this.filterQ;\n };\n ComplementaryFilter.prototype.accelToQuaternion_ = function (accel) {\n var normAccel = new Vector3();\n normAccel.copy(accel);\n normAccel.normalize();\n var quat = new Quaternion();\n quat.setFromUnitVectors(new Vector3(0, 0, -1), normAccel);\n quat.inverse();\n return quat;\n };\n ComplementaryFilter.prototype.gyroToQuaternionDelta_ = function (gyro, dt) {\n var quat = new Quaternion();\n var axis = new Vector3();\n axis.copy(gyro);\n axis.normalize();\n quat.setFromAxisAngle(axis, gyro.length() * dt);\n return quat;\n };\n function PosePredictor(predictionTimeS, isDebug) {\n this.predictionTimeS = predictionTimeS;\n this.isDebug = isDebug;\n this.previousQ = new Quaternion();\n this.previousTimestampS = null;\n this.deltaQ = new Quaternion();\n this.outQ = new Quaternion();\n }\n PosePredictor.prototype.getPrediction = function (currentQ, gyro, timestampS) {\n if (!this.previousTimestampS) {\n this.previousQ.copy(currentQ);\n this.previousTimestampS = timestampS;\n return currentQ;\n }\n var axis = new Vector3();\n axis.copy(gyro);\n axis.normalize();\n var angularSpeed = gyro.length();\n if (angularSpeed < degToRad * 20) {\n if (this.isDebug) {\n console.log('Moving slowly, at %s deg/s: no prediction', (radToDeg * angularSpeed).toFixed(1));\n }\n this.outQ.copy(currentQ);\n this.previousQ.copy(currentQ);\n return this.outQ;\n }\n var predictAngle = angularSpeed * this.predictionTimeS;\n this.deltaQ.setFromAxisAngle(axis, predictAngle);\n this.outQ.copy(this.previousQ);\n this.outQ.multiply(this.deltaQ);\n this.previousQ.copy(currentQ);\n this.previousTimestampS = timestampS;\n return this.outQ;\n };\n function FusionPoseSensor(kFilter, predictionTime, yawOnly, isDebug) {\n this.yawOnly = yawOnly;\n this.accelerometer = new Vector3();\n this.gyroscope = new Vector3();\n this.filter = new ComplementaryFilter(kFilter, isDebug);\n this.posePredictor = new PosePredictor(predictionTime, isDebug);\n this.isFirefoxAndroid = isFirefoxAndroid();\n this.isIOS = isIOS();\n var chromeVersion = getChromeVersion();\n this.isDeviceMotionInRadians = !this.isIOS && chromeVersion && chromeVersion < 66;\n this.isWithoutDeviceMotion = isChromeWithoutDeviceMotion() || isSafariWithoutDeviceMotion();\n this.filterToWorldQ = new Quaternion();\n if (isIOS()) {\n this.filterToWorldQ.setFromAxisAngle(new Vector3(1, 0, 0), Math.PI / 2);\n } else {\n this.filterToWorldQ.setFromAxisAngle(new Vector3(1, 0, 0), -Math.PI / 2);\n }\n this.inverseWorldToScreenQ = new Quaternion();\n this.worldToScreenQ = new Quaternion();\n this.originalPoseAdjustQ = new Quaternion();\n this.originalPoseAdjustQ.setFromAxisAngle(new Vector3(0, 0, 1), -window.orientation * Math.PI / 180);\n this.setScreenTransform_();\n if (isLandscapeMode()) {\n this.filterToWorldQ.multiply(this.inverseWorldToScreenQ);\n }\n this.resetQ = new Quaternion();\n this.orientationOut_ = new Float32Array(4);\n this.start();\n }\n FusionPoseSensor.prototype.getPosition = function () {\n return null;\n };\n FusionPoseSensor.prototype.getOrientation = function () {\n var orientation = void 0;\n if (this.isWithoutDeviceMotion && this._deviceOrientationQ) {\n this.deviceOrientationFixQ = this.deviceOrientationFixQ || function () {\n var z = new Quaternion().setFromAxisAngle(new Vector3(0, 0, -1), 0);\n var y = new Quaternion();\n if (window.orientation === -90) {\n y.setFromAxisAngle(new Vector3(0, 1, 0), Math.PI / -2);\n } else {\n y.setFromAxisAngle(new Vector3(0, 1, 0), Math.PI / 2);\n }\n return z.multiply(y);\n }();\n this.deviceOrientationFilterToWorldQ = this.deviceOrientationFilterToWorldQ || function () {\n var q = new Quaternion();\n q.setFromAxisAngle(new Vector3(1, 0, 0), -Math.PI / 2);\n return q;\n }();\n orientation = this._deviceOrientationQ;\n var out = new Quaternion();\n out.copy(orientation);\n out.multiply(this.deviceOrientationFilterToWorldQ);\n out.multiply(this.resetQ);\n out.multiply(this.worldToScreenQ);\n out.multiplyQuaternions(this.deviceOrientationFixQ, out);\n if (this.yawOnly) {\n out.x = 0;\n out.z = 0;\n out.normalize();\n }\n this.orientationOut_[0] = out.x;\n this.orientationOut_[1] = out.y;\n this.orientationOut_[2] = out.z;\n this.orientationOut_[3] = out.w;\n return this.orientationOut_;\n } else {\n var filterOrientation = this.filter.getOrientation();\n orientation = this.posePredictor.getPrediction(filterOrientation, this.gyroscope, this.previousTimestampS);\n }\n var out = new Quaternion();\n out.copy(this.filterToWorldQ);\n out.multiply(this.resetQ);\n out.multiply(orientation);\n out.multiply(this.worldToScreenQ);\n if (this.yawOnly) {\n out.x = 0;\n out.z = 0;\n out.normalize();\n }\n this.orientationOut_[0] = out.x;\n this.orientationOut_[1] = out.y;\n this.orientationOut_[2] = out.z;\n this.orientationOut_[3] = out.w;\n return this.orientationOut_;\n };\n FusionPoseSensor.prototype.resetPose = function () {\n this.resetQ.copy(this.filter.getOrientation());\n this.resetQ.x = 0;\n this.resetQ.y = 0;\n this.resetQ.z *= -1;\n this.resetQ.normalize();\n if (isLandscapeMode()) {\n this.resetQ.multiply(this.inverseWorldToScreenQ);\n }\n this.resetQ.multiply(this.originalPoseAdjustQ);\n };\n FusionPoseSensor.prototype.onDeviceOrientation_ = function (e) {\n this._deviceOrientationQ = this._deviceOrientationQ || new Quaternion();\n var alpha = e.alpha,\n beta = e.beta,\n gamma = e.gamma;\n alpha = (alpha || 0) * Math.PI / 180;\n beta = (beta || 0) * Math.PI / 180;\n gamma = (gamma || 0) * Math.PI / 180;\n this._deviceOrientationQ.setFromEulerYXZ(beta, alpha, -gamma);\n };\n FusionPoseSensor.prototype.onDeviceMotion_ = function (deviceMotion) {\n this.updateDeviceMotion_(deviceMotion);\n };\n FusionPoseSensor.prototype.updateDeviceMotion_ = function (deviceMotion) {\n var accGravity = deviceMotion.accelerationIncludingGravity;\n var rotRate = deviceMotion.rotationRate;\n var timestampS = deviceMotion.timeStamp / 1000;\n var deltaS = timestampS - this.previousTimestampS;\n if (deltaS < 0) {\n warnOnce('fusion-pose-sensor:invalid:non-monotonic', 'Invalid timestamps detected: non-monotonic timestamp from devicemotion');\n this.previousTimestampS = timestampS;\n return;\n } else if (deltaS <= MIN_TIMESTEP || deltaS > MAX_TIMESTEP) {\n warnOnce('fusion-pose-sensor:invalid:outside-threshold', 'Invalid timestamps detected: Timestamp from devicemotion outside expected range.');\n this.previousTimestampS = timestampS;\n return;\n }\n this.accelerometer.set(-accGravity.x, -accGravity.y, -accGravity.z);\n if (rotRate) {\n if (isR7()) {\n this.gyroscope.set(-rotRate.beta, rotRate.alpha, rotRate.gamma);\n } else {\n this.gyroscope.set(rotRate.alpha, rotRate.beta, rotRate.gamma);\n }\n if (!this.isDeviceMotionInRadians) {\n this.gyroscope.multiplyScalar(Math.PI / 180);\n }\n this.filter.addGyroMeasurement(this.gyroscope, timestampS);\n }\n this.filter.addAccelMeasurement(this.accelerometer, timestampS);\n this.previousTimestampS = timestampS;\n };\n FusionPoseSensor.prototype.onOrientationChange_ = function (screenOrientation) {\n this.setScreenTransform_();\n };\n FusionPoseSensor.prototype.onMessage_ = function (event) {\n var message = event.data;\n if (!message || !message.type) {\n return;\n }\n var type = message.type.toLowerCase();\n if (type !== 'devicemotion') {\n return;\n }\n this.updateDeviceMotion_(message.deviceMotionEvent);\n };\n FusionPoseSensor.prototype.setScreenTransform_ = function () {\n this.worldToScreenQ.set(0, 0, 0, 1);\n switch (window.orientation) {\n case 0:\n break;\n case 90:\n this.worldToScreenQ.setFromAxisAngle(new Vector3(0, 0, 1), -Math.PI / 2);\n break;\n case -90:\n this.worldToScreenQ.setFromAxisAngle(new Vector3(0, 0, 1), Math.PI / 2);\n break;\n case 180:\n break;\n }\n this.inverseWorldToScreenQ.copy(this.worldToScreenQ);\n this.inverseWorldToScreenQ.inverse();\n };\n FusionPoseSensor.prototype.start = function () {\n this.onDeviceMotionCallback_ = this.onDeviceMotion_.bind(this);\n this.onOrientationChangeCallback_ = this.onOrientationChange_.bind(this);\n this.onMessageCallback_ = this.onMessage_.bind(this);\n this.onDeviceOrientationCallback_ = this.onDeviceOrientation_.bind(this);\n if (isIOS() && isInsideCrossOriginIFrame()) {\n window.addEventListener('message', this.onMessageCallback_);\n }\n window.addEventListener('orientationchange', this.onOrientationChangeCallback_);\n if (this.isWithoutDeviceMotion) {\n window.addEventListener('deviceorientation', this.onDeviceOrientationCallback_);\n } else {\n window.addEventListener('devicemotion', this.onDeviceMotionCallback_);\n }\n };\n FusionPoseSensor.prototype.stop = function () {\n window.removeEventListener('devicemotion', this.onDeviceMotionCallback_);\n window.removeEventListener('deviceorientation', this.onDeviceOrientationCallback_);\n window.removeEventListener('orientationchange', this.onOrientationChangeCallback_);\n window.removeEventListener('message', this.onMessageCallback_);\n };\n var SENSOR_FREQUENCY = 60;\n var X_AXIS = new Vector3(1, 0, 0);\n var Z_AXIS = new Vector3(0, 0, 1);\n var SENSOR_TO_VR = new Quaternion();\n SENSOR_TO_VR.setFromAxisAngle(X_AXIS, -Math.PI / 2);\n SENSOR_TO_VR.multiply(new Quaternion().setFromAxisAngle(Z_AXIS, Math.PI / 2));\n var PoseSensor = function () {\n function PoseSensor(config) {\n classCallCheck(this, PoseSensor);\n this.config = config;\n this.sensor = null;\n this.fusionSensor = null;\n this._out = new Float32Array(4);\n this.api = null;\n this.errors = [];\n this._sensorQ = new Quaternion();\n this._outQ = new Quaternion();\n this._onSensorRead = this._onSensorRead.bind(this);\n this._onSensorError = this._onSensorError.bind(this);\n this.init();\n }\n createClass(PoseSensor, [{\n key: 'init',\n value: function init() {\n var sensor = null;\n try {\n sensor = new RelativeOrientationSensor({\n frequency: SENSOR_FREQUENCY,\n referenceFrame: 'screen'\n });\n sensor.addEventListener('error', this._onSensorError);\n } catch (error) {\n this.errors.push(error);\n if (error.name === 'SecurityError') {\n console.error('Cannot construct sensors due to the Feature Policy');\n console.warn('Attempting to fall back using \"devicemotion\"; however this will ' + 'fail in the future without correct permissions.');\n this.useDeviceMotion();\n } else if (error.name === 'ReferenceError') {\n this.useDeviceMotion();\n } else {\n console.error(error);\n }\n }\n if (sensor) {\n this.api = 'sensor';\n this.sensor = sensor;\n this.sensor.addEventListener('reading', this._onSensorRead);\n this.sensor.start();\n }\n }\n }, {\n key: 'useDeviceMotion',\n value: function useDeviceMotion() {\n this.api = 'devicemotion';\n this.fusionSensor = new FusionPoseSensor(this.config.K_FILTER, this.config.PREDICTION_TIME_S, this.config.YAW_ONLY, this.config.DEBUG);\n if (this.sensor) {\n this.sensor.removeEventListener('reading', this._onSensorRead);\n this.sensor.removeEventListener('error', this._onSensorError);\n this.sensor = null;\n }\n }\n }, {\n key: 'getOrientation',\n value: function getOrientation() {\n if (this.fusionSensor) {\n return this.fusionSensor.getOrientation();\n }\n if (!this.sensor || !this.sensor.quaternion) {\n this._out[0] = this._out[1] = this._out[2] = 0;\n this._out[3] = 1;\n return this._out;\n }\n var q = this.sensor.quaternion;\n this._sensorQ.set(q[0], q[1], q[2], q[3]);\n var out = this._outQ;\n out.copy(SENSOR_TO_VR);\n out.multiply(this._sensorQ);\n if (this.config.YAW_ONLY) {\n out.x = out.z = 0;\n out.normalize();\n }\n this._out[0] = out.x;\n this._out[1] = out.y;\n this._out[2] = out.z;\n this._out[3] = out.w;\n return this._out;\n }\n }, {\n key: '_onSensorError',\n value: function _onSensorError(event) {\n this.errors.push(event.error);\n if (event.error.name === 'NotAllowedError') {\n console.error('Permission to access sensor was denied');\n } else if (event.error.name === 'NotReadableError') {\n console.error('Sensor could not be read');\n } else {\n console.error(event.error);\n }\n this.useDeviceMotion();\n }\n }, {\n key: '_onSensorRead',\n value: function _onSensorRead() {}\n }]);\n return PoseSensor;\n }();\n var rotateInstructionsAsset = \"\";\n function RotateInstructions() {\n this.loadIcon_();\n var overlay = document.createElement('div');\n var s = overlay.style;\n s.position = 'fixed';\n s.top = 0;\n s.right = 0;\n s.bottom = 0;\n s.left = 0;\n s.backgroundColor = 'gray';\n s.fontFamily = 'sans-serif';\n s.zIndex = 1000000;\n var img = document.createElement('img');\n img.src = this.icon;\n var s = img.style;\n s.marginLeft = '25%';\n s.marginTop = '25%';\n s.width = '50%';\n overlay.appendChild(img);\n var text = document.createElement('div');\n var s = text.style;\n s.textAlign = 'center';\n s.fontSize = '16px';\n s.lineHeight = '24px';\n s.margin = '24px 25%';\n s.width = '50%';\n text.innerHTML = 'Place your phone into your Cardboard viewer.';\n overlay.appendChild(text);\n var snackbar = document.createElement('div');\n var s = snackbar.style;\n s.backgroundColor = '#CFD8DC';\n s.position = 'fixed';\n s.bottom = 0;\n s.width = '100%';\n s.height = '48px';\n s.padding = '14px 24px';\n s.boxSizing = 'border-box';\n s.color = '#656A6B';\n overlay.appendChild(snackbar);\n var snackbarText = document.createElement('div');\n snackbarText.style.float = 'left';\n snackbarText.innerHTML = 'No Cardboard viewer?';\n var snackbarButton = document.createElement('a');\n snackbarButton.href = 'https://www.google.com/get/cardboard/get-cardboard/';\n snackbarButton.innerHTML = 'get one';\n snackbarButton.target = '_blank';\n var s = snackbarButton.style;\n s.float = 'right';\n s.fontWeight = 600;\n s.textTransform = 'uppercase';\n s.borderLeft = '1px solid gray';\n s.paddingLeft = '24px';\n s.textDecoration = 'none';\n s.color = '#656A6B';\n snackbar.appendChild(snackbarText);\n snackbar.appendChild(snackbarButton);\n this.overlay = overlay;\n this.text = text;\n this.hide();\n }\n RotateInstructions.prototype.show = function (parent) {\n if (!parent && !this.overlay.parentElement) {\n document.body.appendChild(this.overlay);\n } else if (parent) {\n if (this.overlay.parentElement && this.overlay.parentElement != parent) this.overlay.parentElement.removeChild(this.overlay);\n parent.appendChild(this.overlay);\n }\n this.overlay.style.display = 'block';\n var img = this.overlay.querySelector('img');\n var s = img.style;\n if (isLandscapeMode()) {\n s.width = '20%';\n s.marginLeft = '40%';\n s.marginTop = '3%';\n } else {\n s.width = '50%';\n s.marginLeft = '25%';\n s.marginTop = '25%';\n }\n };\n RotateInstructions.prototype.hide = function () {\n this.overlay.style.display = 'none';\n };\n RotateInstructions.prototype.showTemporarily = function (ms, parent) {\n this.show(parent);\n this.timer = setTimeout(this.hide.bind(this), ms);\n };\n RotateInstructions.prototype.disableShowTemporarily = function () {\n clearTimeout(this.timer);\n };\n RotateInstructions.prototype.update = function () {\n this.disableShowTemporarily();\n if (!isLandscapeMode() && isMobile()) {\n this.show();\n } else {\n this.hide();\n }\n };\n RotateInstructions.prototype.loadIcon_ = function () {\n this.icon = dataUri('image/svg+xml', rotateInstructionsAsset);\n };\n var DEFAULT_VIEWER = 'CardboardV1';\n var VIEWER_KEY = 'WEBVR_CARDBOARD_VIEWER';\n var CLASS_NAME = 'webvr-polyfill-viewer-selector';\n function ViewerSelector(defaultViewer) {\n try {\n this.selectedKey = localStorage.getItem(VIEWER_KEY);\n } catch (error) {\n console.error('Failed to load viewer profile: %s', error);\n }\n if (!this.selectedKey) {\n this.selectedKey = defaultViewer || DEFAULT_VIEWER;\n }\n this.dialog = this.createDialog_(DeviceInfo.Viewers);\n this.root = null;\n this.onChangeCallbacks_ = [];\n }\n ViewerSelector.prototype.show = function (root) {\n this.root = root;\n root.appendChild(this.dialog);\n var selected = this.dialog.querySelector('#' + this.selectedKey);\n selected.checked = true;\n this.dialog.style.display = 'block';\n };\n ViewerSelector.prototype.hide = function () {\n if (this.root && this.root.contains(this.dialog)) {\n this.root.removeChild(this.dialog);\n }\n this.dialog.style.display = 'none';\n };\n ViewerSelector.prototype.getCurrentViewer = function () {\n return DeviceInfo.Viewers[this.selectedKey];\n };\n ViewerSelector.prototype.getSelectedKey_ = function () {\n var input = this.dialog.querySelector('input[name=field]:checked');\n if (input) {\n return input.id;\n }\n return null;\n };\n ViewerSelector.prototype.onChange = function (cb) {\n this.onChangeCallbacks_.push(cb);\n };\n ViewerSelector.prototype.fireOnChange_ = function (viewer) {\n for (var i = 0; i < this.onChangeCallbacks_.length; i++) {\n this.onChangeCallbacks_[i](viewer);\n }\n };\n ViewerSelector.prototype.onSave_ = function () {\n this.selectedKey = this.getSelectedKey_();\n if (!this.selectedKey || !DeviceInfo.Viewers[this.selectedKey]) {\n console.error('ViewerSelector.onSave_: this should never happen!');\n return;\n }\n this.fireOnChange_(DeviceInfo.Viewers[this.selectedKey]);\n try {\n localStorage.setItem(VIEWER_KEY, this.selectedKey);\n } catch (error) {\n console.error('Failed to save viewer profile: %s', error);\n }\n this.hide();\n };\n ViewerSelector.prototype.createDialog_ = function (options) {\n var container = document.createElement('div');\n container.classList.add(CLASS_NAME);\n container.style.display = 'none';\n var overlay = document.createElement('div');\n var s = overlay.style;\n s.position = 'fixed';\n s.left = 0;\n s.top = 0;\n s.width = '100%';\n s.height = '100%';\n s.background = 'rgba(0, 0, 0, 0.3)';\n overlay.addEventListener('click', this.hide.bind(this));\n var width = 280;\n var dialog = document.createElement('div');\n var s = dialog.style;\n s.boxSizing = 'border-box';\n s.position = 'fixed';\n s.top = '24px';\n s.left = '50%';\n s.marginLeft = -width / 2 + 'px';\n s.width = width + 'px';\n s.padding = '24px';\n s.overflow = 'hidden';\n s.background = '#fafafa';\n s.fontFamily = \"'Roboto', sans-serif\";\n s.boxShadow = '0px 5px 20px #666';\n dialog.appendChild(this.createH1_('Select your viewer'));\n for (var id in options) {\n dialog.appendChild(this.createChoice_(id, options[id].label));\n }\n dialog.appendChild(this.createButton_('Save', this.onSave_.bind(this)));\n container.appendChild(overlay);\n container.appendChild(dialog);\n return container;\n };\n ViewerSelector.prototype.createH1_ = function (name) {\n var h1 = document.createElement('h1');\n var s = h1.style;\n s.color = 'black';\n s.fontSize = '20px';\n s.fontWeight = 'bold';\n s.marginTop = 0;\n s.marginBottom = '24px';\n h1.innerHTML = name;\n return h1;\n };\n ViewerSelector.prototype.createChoice_ = function (id, name) {\n var div = document.createElement('div');\n div.style.marginTop = '8px';\n div.style.color = 'black';\n var input = document.createElement('input');\n input.style.fontSize = '30px';\n input.setAttribute('id', id);\n input.setAttribute('type', 'radio');\n input.setAttribute('value', id);\n input.setAttribute('name', 'field');\n var label = document.createElement('label');\n label.style.marginLeft = '4px';\n label.setAttribute('for', id);\n label.innerHTML = name;\n div.appendChild(input);\n div.appendChild(label);\n return div;\n };\n ViewerSelector.prototype.createButton_ = function (label, onclick) {\n var button = document.createElement('button');\n button.innerHTML = label;\n var s = button.style;\n s.float = 'right';\n s.textTransform = 'uppercase';\n s.color = '#1094f7';\n s.fontSize = '14px';\n s.letterSpacing = 0;\n s.border = 0;\n s.background = 'none';\n s.marginTop = '16px';\n button.addEventListener('click', onclick);\n return button;\n };\n var commonjsGlobal$$1 = typeof window !== 'undefined' ? window : typeof commonjsGlobal !== 'undefined' ? commonjsGlobal : typeof self !== 'undefined' ? self : {};\n function unwrapExports$$1(x) {\n return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;\n }\n function createCommonjsModule$$1(fn, module) {\n return module = {\n exports: {}\n }, fn(module, module.exports), module.exports;\n }\n var NoSleep = createCommonjsModule$$1(function (module, exports) {\n (function webpackUniversalModuleDefinition(root, factory) {\n module.exports = factory();\n })(commonjsGlobal$$1, function () {\n return function (modules) {\n var installedModules = {};\n function __nested_webpack_require_167216__(moduleId) {\n if (installedModules[moduleId]) {\n return installedModules[moduleId].exports;\n }\n var module = installedModules[moduleId] = {\n i: moduleId,\n l: false,\n exports: {}\n };\n modules[moduleId].call(module.exports, module, module.exports, __nested_webpack_require_167216__);\n module.l = true;\n return module.exports;\n }\n __nested_webpack_require_167216__.m = modules;\n __nested_webpack_require_167216__.c = installedModules;\n __nested_webpack_require_167216__.d = function (exports, name, getter) {\n if (!__nested_webpack_require_167216__.o(exports, name)) {\n Object.defineProperty(exports, name, {\n configurable: false,\n enumerable: true,\n get: getter\n });\n }\n };\n __nested_webpack_require_167216__.n = function (module) {\n var getter = module && module.__esModule ? function getDefault() {\n return module['default'];\n } : function getModuleExports() {\n return module;\n };\n __nested_webpack_require_167216__.d(getter, 'a', getter);\n return getter;\n };\n __nested_webpack_require_167216__.o = function (object, property) {\n return Object.prototype.hasOwnProperty.call(object, property);\n };\n __nested_webpack_require_167216__.p = \"\";\n return __nested_webpack_require_167216__(__nested_webpack_require_167216__.s = 0);\n }([function (module, exports, __nested_webpack_require_168841__) {\n var _createClass = function () {\n function defineProperties(target, props) {\n for (var i = 0; i < props.length; i++) {\n var descriptor = props[i];\n descriptor.enumerable = descriptor.enumerable || false;\n descriptor.configurable = true;\n if (\"value\" in descriptor) descriptor.writable = true;\n Object.defineProperty(target, descriptor.key, descriptor);\n }\n }\n return function (Constructor, protoProps, staticProps) {\n if (protoProps) defineProperties(Constructor.prototype, protoProps);\n if (staticProps) defineProperties(Constructor, staticProps);\n return Constructor;\n };\n }();\n function _classCallCheck(instance, Constructor) {\n if (!(instance instanceof Constructor)) {\n throw new TypeError(\"Cannot call a class as a function\");\n }\n }\n var mediaFile = __nested_webpack_require_168841__(1);\n var oldIOS = typeof navigator !== 'undefined' && parseFloat(('' + (/CPU.*OS ([0-9_]{3,4})[0-9_]{0,1}|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent) || [0, ''])[1]).replace('undefined', '3_2').replace('_', '.').replace('_', '')) < 10 && !window.MSStream;\n var NoSleep = function () {\n function NoSleep() {\n _classCallCheck(this, NoSleep);\n if (oldIOS) {\n this.noSleepTimer = null;\n } else {\n this.noSleepVideo = document.createElement('video');\n this.noSleepVideo.setAttribute('playsinline', '');\n this.noSleepVideo.setAttribute('src', mediaFile);\n this.noSleepVideo.addEventListener('timeupdate', function (e) {\n if (this.noSleepVideo.currentTime > 0.5) {\n this.noSleepVideo.currentTime = Math.random();\n }\n }.bind(this));\n }\n }\n _createClass(NoSleep, [{\n key: 'enable',\n value: function enable() {\n if (oldIOS) {\n this.disable();\n this.noSleepTimer = window.setInterval(function () {\n window.location.href = '/';\n window.setTimeout(window.stop, 0);\n }, 15000);\n } else {\n this.noSleepVideo.play();\n }\n }\n }, {\n key: 'disable',\n value: function disable() {\n if (oldIOS) {\n if (this.noSleepTimer) {\n window.clearInterval(this.noSleepTimer);\n this.noSleepTimer = null;\n }\n } else {\n this.noSleepVideo.pause();\n }\n }\n }]);\n return NoSleep;\n }();\n module.exports = NoSleep;\n }, function (module, exports, __webpack_require__) {\n module.exports = 'data:video/mp4;base64,AAAAIGZ0eXBtcDQyAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAACKBtZGF0AAAC8wYF///v3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE0MiByMjQ3OSBkZDc5YTYxIC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZWZ0IDIwMDMtMjAxNCAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9wdGlvbnM6IGNhYmFjPTEgcmVmPTEgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MToweDExMSBtZT1oZXggc3VibWU9MiBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0wIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MCA4eDhkY3Q9MCBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0wIHRocmVhZHM9NiBsb29rYWhlYWRfdGhyZWFkcz0xIHNsaWNlZF90aHJlYWRzPTAgbnI9MCBkZWNpbWF0ZT0xIGludGVybGFjZWQ9MCBibHVyYXlfY29tcGF0PTAgY29uc3RyYWluZWRfaW50cmE9MCBiZnJhbWVzPTMgYl9weXJhbWlkPTIgYl9hZGFwdD0xIGJfYmlhcz0wIGRpcmVjdD0xIHdlaWdodGI9MSBvcGVuX2dvcD0wIHdlaWdodHA9MSBrZXlpbnQ9MzAwIGtleWludF9taW49MzAgc2NlbmVjdXQ9NDAgaW50cmFfcmVmcmVzaD0wIHJjX2xvb2thaGVhZD0xMCByYz1jcmYgbWJ0cmVlPTEgY3JmPTIwLjAgcWNvbXA9MC42MCBxcG1pbj0wIHFwbWF4PTY5IHFwc3RlcD00IHZidl9tYXhyYXRlPTIwMDAwIHZidl9idWZzaXplPTI1MDAwIGNyZl9tYXg9MC4wIG5hbF9ocmQ9bm9uZSBmaWxsZXI9MCBpcF9yYXRpbz0xLjQwIGFxPTE6MS4wMACAAAAAOWWIhAA3//p+C7v8tDDSTjf97w55i3SbRPO4ZY+hkjD5hbkAkL3zpJ6h/LR1CAABzgB1kqqzUorlhQAAAAxBmiQYhn/+qZYADLgAAAAJQZ5CQhX/AAj5IQADQGgcIQADQGgcAAAACQGeYUQn/wALKCEAA0BoHAAAAAkBnmNEJ/8ACykhAANAaBwhAANAaBwAAAANQZpoNExDP/6plgAMuSEAA0BoHAAAAAtBnoZFESwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBnqVEJ/8ACykhAANAaBwAAAAJAZ6nRCf/AAsoIQADQGgcIQADQGgcAAAADUGarDRMQz/+qZYADLghAANAaBwAAAALQZ7KRRUsK/8ACPkhAANAaBwAAAAJAZ7pRCf/AAsoIQADQGgcIQADQGgcAAAACQGe60Qn/wALKCEAA0BoHAAAAA1BmvA0TEM//qmWAAy5IQADQGgcIQADQGgcAAAAC0GfDkUVLCv/AAj5IQADQGgcAAAACQGfLUQn/wALKSEAA0BoHCEAA0BoHAAAAAkBny9EJ/8ACyghAANAaBwAAAANQZs0NExDP/6plgAMuCEAA0BoHAAAAAtBn1JFFSwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBn3FEJ/8ACyghAANAaBwAAAAJAZ9zRCf/AAsoIQADQGgcIQADQGgcAAAADUGbeDRMQz/+qZYADLkhAANAaBwAAAALQZ+WRRUsK/8ACPghAANAaBwhAANAaBwAAAAJAZ+1RCf/AAspIQADQGgcAAAACQGft0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bm7w0TEM//qmWAAy4IQADQGgcAAAAC0Gf2kUVLCv/AAj5IQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHAAAAAkBn/tEJ/8ACykhAANAaBwAAAANQZvgNExDP/6plgAMuSEAA0BoHCEAA0BoHAAAAAtBnh5FFSwr/wAI+CEAA0BoHAAAAAkBnj1EJ/8ACyghAANAaBwhAANAaBwAAAAJAZ4/RCf/AAspIQADQGgcAAAADUGaJDRMQz/+qZYADLghAANAaBwAAAALQZ5CRRUsK/8ACPkhAANAaBwhAANAaBwAAAAJAZ5hRCf/AAsoIQADQGgcAAAACQGeY0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bmmg0TEM//qmWAAy5IQADQGgcAAAAC0GehkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGepUQn/wALKSEAA0BoHAAAAAkBnqdEJ/8ACyghAANAaBwAAAANQZqsNExDP/6plgAMuCEAA0BoHCEAA0BoHAAAAAtBnspFFSwr/wAI+SEAA0BoHAAAAAkBnulEJ/8ACyghAANAaBwhAANAaBwAAAAJAZ7rRCf/AAsoIQADQGgcAAAADUGa8DRMQz/+qZYADLkhAANAaBwhAANAaBwAAAALQZ8ORRUsK/8ACPkhAANAaBwAAAAJAZ8tRCf/AAspIQADQGgcIQADQGgcAAAACQGfL0Qn/wALKCEAA0BoHAAAAA1BmzQ0TEM//qmWAAy4IQADQGgcAAAAC0GfUkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGfcUQn/wALKCEAA0BoHAAAAAkBn3NEJ/8ACyghAANAaBwhAANAaBwAAAANQZt4NExC//6plgAMuSEAA0BoHAAAAAtBn5ZFFSwr/wAI+CEAA0BoHCEAA0BoHAAAAAkBn7VEJ/8ACykhAANAaBwAAAAJAZ+3RCf/AAspIQADQGgcAAAADUGbuzRMQn/+nhAAYsAhAANAaBwhAANAaBwAAAAJQZ/aQhP/AAspIQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHAAACiFtb292AAAAbG12aGQAAAAA1YCCX9WAgl8AAAPoAAAH/AABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAGGlvZHMAAAAAEICAgAcAT////v7/AAAF+XRyYWsAAABcdGtoZAAAAAPVgIJf1YCCXwAAAAEAAAAAAAAH0AAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAygAAAMoAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAB9AAABdwAAEAAAAABXFtZGlhAAAAIG1kaGQAAAAA1YCCX9WAgl8AAV+QAAK/IFXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSGFuZGxlcgAAAAUcbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAAE3HN0YmwAAACYc3RzZAAAAAAAAAABAAAAiGF2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAygDKAEgAAABIAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAAyYXZjQwFNQCj/4QAbZ01AKOyho3ySTUBAQFAAAAMAEAAr8gDxgxlgAQAEaO+G8gAAABhzdHRzAAAAAAAAAAEAAAA8AAALuAAAABRzdHNzAAAAAAAAAAEAAAABAAAB8GN0dHMAAAAAAAAAPAAAAAEAABdwAAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAAC7gAAAAAQAAF3AAAAABAAAAAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAEEc3RzegAAAAAAAAAAAAAAPAAAAzQAAAAQAAAADQAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAANAAAADQAAAQBzdGNvAAAAAAAAADwAAAAwAAADZAAAA3QAAAONAAADoAAAA7kAAAPQAAAD6wAAA/4AAAQXAAAELgAABEMAAARcAAAEbwAABIwAAAShAAAEugAABM0AAATkAAAE/wAABRIAAAUrAAAFQgAABV0AAAVwAAAFiQAABaAAAAW1AAAFzgAABeEAAAX+AAAGEwAABiwAAAY/AAAGVgAABnEAAAaEAAAGnQAABrQAAAbPAAAG4gAABvUAAAcSAAAHJwAAB0AAAAdTAAAHcAAAB4UAAAeeAAAHsQAAB8gAAAfjAAAH9gAACA8AAAgmAAAIQQAACFQAAAhnAAAIhAAACJcAAAMsdHJhawAAAFx0a2hkAAAAA9WAgl/VgIJfAAAAAgAAAAAAAAf8AAAAAAAAAAAAAAABAQAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAACsm1kaWEAAAAgbWRoZAAAAADVgIJf1YCCXwAArEQAAWAAVcQAAAAAACdoZGxyAAAAAAAAAABzb3VuAAAAAAAAAAAAAAAAU3RlcmVvAAAAAmNtaW5mAAAAEHNtaGQAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAidzdGJsAAAAZ3N0c2QAAAAAAAAAAQAAAFdtcDRhAAAAAAAAAAEAAAAAAAAAAAACABAAAAAArEQAAAAAADNlc2RzAAAAAAOAgIAiAAIABICAgBRAFQAAAAADDUAAAAAABYCAgAISEAaAgIABAgAAABhzdHRzAAAAAAAAAAEAAABYAAAEAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAAUc3RzegAAAAAAAAAGAAAAWAAAAXBzdGNvAAAAAAAAAFgAAAOBAAADhwAAA5oAAAOtAAADswAAA8oAAAPfAAAD5QAAA/gAAAQLAAAEEQAABCgAAAQ9AAAEUAAABFYAAARpAAAEgAAABIYAAASbAAAErgAABLQAAATHAAAE3gAABPMAAAT5AAAFDAAABR8AAAUlAAAFPAAABVEAAAVXAAAFagAABX0AAAWDAAAFmgAABa8AAAXCAAAFyAAABdsAAAXyAAAF+AAABg0AAAYgAAAGJgAABjkAAAZQAAAGZQAABmsAAAZ+AAAGkQAABpcAAAauAAAGwwAABskAAAbcAAAG7wAABwYAAAcMAAAHIQAABzQAAAc6AAAHTQAAB2QAAAdqAAAHfwAAB5IAAAeYAAAHqwAAB8IAAAfXAAAH3QAAB/AAAAgDAAAICQAACCAAAAg1AAAIOwAACE4AAAhhAAAIeAAACH4AAAiRAAAIpAAACKoAAAiwAAAItgAACLwAAAjCAAAAFnVkdGEAAAAObmFtZVN0ZXJlbwAAAHB1ZHRhAAAAaG1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAAO2lsc3QAAAAzqXRvbwAAACtkYXRhAAAAAQAAAABIYW5kQnJha2UgMC4xMC4yIDIwMTUwNjExMDA=';\n }]);\n });\n });\n var NoSleep$1 = unwrapExports$$1(NoSleep);\n var nextDisplayId = 1000;\n var defaultLeftBounds = [0, 0, 0.5, 1];\n var defaultRightBounds = [0.5, 0, 0.5, 1];\n var raf = window.requestAnimationFrame;\n var caf = window.cancelAnimationFrame;\n function VRFrameData() {\n this.leftProjectionMatrix = new Float32Array(16);\n this.leftViewMatrix = new Float32Array(16);\n this.rightProjectionMatrix = new Float32Array(16);\n this.rightViewMatrix = new Float32Array(16);\n this.pose = null;\n }\n function VRDisplayCapabilities(config) {\n Object.defineProperties(this, {\n hasPosition: {\n writable: false,\n enumerable: true,\n value: config.hasPosition\n },\n hasExternalDisplay: {\n writable: false,\n enumerable: true,\n value: config.hasExternalDisplay\n },\n canPresent: {\n writable: false,\n enumerable: true,\n value: config.canPresent\n },\n maxLayers: {\n writable: false,\n enumerable: true,\n value: config.maxLayers\n },\n hasOrientation: {\n enumerable: true,\n get: function get() {\n deprecateWarning('VRDisplayCapabilities.prototype.hasOrientation', 'VRDisplay.prototype.getFrameData');\n return config.hasOrientation;\n }\n }\n });\n }\n function VRDisplay(config) {\n config = config || {};\n var USE_WAKELOCK = 'wakelock' in config ? config.wakelock : true;\n this.isPolyfilled = true;\n this.displayId = nextDisplayId++;\n this.displayName = '';\n this.depthNear = 0.01;\n this.depthFar = 10000.0;\n this.isPresenting = false;\n Object.defineProperty(this, 'isConnected', {\n get: function get() {\n deprecateWarning('VRDisplay.prototype.isConnected', 'VRDisplayCapabilities.prototype.hasExternalDisplay');\n return false;\n }\n });\n this.capabilities = new VRDisplayCapabilities({\n hasPosition: false,\n hasOrientation: false,\n hasExternalDisplay: false,\n canPresent: false,\n maxLayers: 1\n });\n this.stageParameters = null;\n this.waitingForPresent_ = false;\n this.layer_ = null;\n this.originalParent_ = null;\n this.fullscreenElement_ = null;\n this.fullscreenWrapper_ = null;\n this.fullscreenElementCachedStyle_ = null;\n this.fullscreenEventTarget_ = null;\n this.fullscreenChangeHandler_ = null;\n this.fullscreenErrorHandler_ = null;\n if (USE_WAKELOCK && isMobile()) {\n this.wakelock_ = new NoSleep$1();\n }\n }\n VRDisplay.prototype.getFrameData = function (frameData) {\n return frameDataFromPose(frameData, this._getPose(), this);\n };\n VRDisplay.prototype.getPose = function () {\n deprecateWarning('VRDisplay.prototype.getPose', 'VRDisplay.prototype.getFrameData');\n return this._getPose();\n };\n VRDisplay.prototype.resetPose = function () {\n deprecateWarning('VRDisplay.prototype.resetPose');\n return this._resetPose();\n };\n VRDisplay.prototype.getImmediatePose = function () {\n deprecateWarning('VRDisplay.prototype.getImmediatePose', 'VRDisplay.prototype.getFrameData');\n return this._getPose();\n };\n VRDisplay.prototype.requestAnimationFrame = function (callback) {\n return raf(callback);\n };\n VRDisplay.prototype.cancelAnimationFrame = function (id) {\n return caf(id);\n };\n VRDisplay.prototype.wrapForFullscreen = function (element) {\n if (isIOS()) {\n return element;\n }\n if (!this.fullscreenWrapper_) {\n this.fullscreenWrapper_ = document.createElement('div');\n var cssProperties = ['height: ' + Math.min(screen.height, screen.width) + 'px !important', 'top: 0 !important', 'left: 0 !important', 'right: 0 !important', 'border: 0', 'margin: 0', 'padding: 0', 'z-index: 999999 !important', 'position: fixed'];\n this.fullscreenWrapper_.setAttribute('style', cssProperties.join('; ') + ';');\n this.fullscreenWrapper_.classList.add('webvr-polyfill-fullscreen-wrapper');\n }\n if (this.fullscreenElement_ == element) {\n return this.fullscreenWrapper_;\n }\n if (this.fullscreenElement_) {\n if (this.originalParent_) {\n this.originalParent_.appendChild(this.fullscreenElement_);\n } else {\n this.fullscreenElement_.parentElement.removeChild(this.fullscreenElement_);\n }\n }\n this.fullscreenElement_ = element;\n this.originalParent_ = element.parentElement;\n if (!this.originalParent_) {\n document.body.appendChild(element);\n }\n if (!this.fullscreenWrapper_.parentElement) {\n var parent = this.fullscreenElement_.parentElement;\n parent.insertBefore(this.fullscreenWrapper_, this.fullscreenElement_);\n parent.removeChild(this.fullscreenElement_);\n }\n this.fullscreenWrapper_.insertBefore(this.fullscreenElement_, this.fullscreenWrapper_.firstChild);\n this.fullscreenElementCachedStyle_ = this.fullscreenElement_.getAttribute('style');\n var self = this;\n function applyFullscreenElementStyle() {\n if (!self.fullscreenElement_) {\n return;\n }\n var cssProperties = ['position: absolute', 'top: 0', 'left: 0', 'width: ' + Math.max(screen.width, screen.height) + 'px', 'height: ' + Math.min(screen.height, screen.width) + 'px', 'border: 0', 'margin: 0', 'padding: 0'];\n self.fullscreenElement_.setAttribute('style', cssProperties.join('; ') + ';');\n }\n applyFullscreenElementStyle();\n return this.fullscreenWrapper_;\n };\n VRDisplay.prototype.removeFullscreenWrapper = function () {\n if (!this.fullscreenElement_) {\n return;\n }\n var element = this.fullscreenElement_;\n if (this.fullscreenElementCachedStyle_) {\n element.setAttribute('style', this.fullscreenElementCachedStyle_);\n } else {\n element.removeAttribute('style');\n }\n this.fullscreenElement_ = null;\n this.fullscreenElementCachedStyle_ = null;\n var parent = this.fullscreenWrapper_.parentElement;\n this.fullscreenWrapper_.removeChild(element);\n if (this.originalParent_ === parent) {\n parent.insertBefore(element, this.fullscreenWrapper_);\n } else if (this.originalParent_) {\n this.originalParent_.appendChild(element);\n }\n parent.removeChild(this.fullscreenWrapper_);\n return element;\n };\n VRDisplay.prototype.requestPresent = function (layers) {\n var wasPresenting = this.isPresenting;\n var self = this;\n if (!(layers instanceof Array)) {\n deprecateWarning('VRDisplay.prototype.requestPresent with non-array argument', 'an array of VRLayers as the first argument');\n layers = [layers];\n }\n return new Promise(function (resolve, reject) {\n if (!self.capabilities.canPresent) {\n reject(new Error('VRDisplay is not capable of presenting.'));\n return;\n }\n if (layers.length == 0 || layers.length > self.capabilities.maxLayers) {\n reject(new Error('Invalid number of layers.'));\n return;\n }\n var incomingLayer = layers[0];\n if (!incomingLayer.source) {\n resolve();\n return;\n }\n var leftBounds = incomingLayer.leftBounds || defaultLeftBounds;\n var rightBounds = incomingLayer.rightBounds || defaultRightBounds;\n if (wasPresenting) {\n var layer = self.layer_;\n if (layer.source !== incomingLayer.source) {\n layer.source = incomingLayer.source;\n }\n for (var i = 0; i < 4; i++) {\n layer.leftBounds[i] = leftBounds[i];\n layer.rightBounds[i] = rightBounds[i];\n }\n self.wrapForFullscreen(self.layer_.source);\n self.updatePresent_();\n resolve();\n return;\n }\n self.layer_ = {\n predistorted: incomingLayer.predistorted,\n source: incomingLayer.source,\n leftBounds: leftBounds.slice(0),\n rightBounds: rightBounds.slice(0)\n };\n self.waitingForPresent_ = false;\n if (self.layer_ && self.layer_.source) {\n var fullscreenElement = self.wrapForFullscreen(self.layer_.source);\n var onFullscreenChange = function onFullscreenChange() {\n var actualFullscreenElement = getFullscreenElement();\n self.isPresenting = fullscreenElement === actualFullscreenElement;\n if (self.isPresenting) {\n if (screen.orientation && screen.orientation.lock) {\n screen.orientation.lock('landscape-primary').catch(function (error) {\n console.error('screen.orientation.lock() failed due to', error.message);\n });\n }\n self.waitingForPresent_ = false;\n self.beginPresent_();\n resolve();\n } else {\n if (screen.orientation && screen.orientation.unlock) {\n screen.orientation.unlock();\n }\n self.removeFullscreenWrapper();\n self.disableWakeLock();\n self.endPresent_();\n self.removeFullscreenListeners_();\n }\n self.fireVRDisplayPresentChange_();\n };\n var onFullscreenError = function onFullscreenError() {\n if (!self.waitingForPresent_) {\n return;\n }\n self.removeFullscreenWrapper();\n self.removeFullscreenListeners_();\n self.disableWakeLock();\n self.waitingForPresent_ = false;\n self.isPresenting = false;\n reject(new Error('Unable to present.'));\n };\n self.addFullscreenListeners_(fullscreenElement, onFullscreenChange, onFullscreenError);\n if (requestFullscreen(fullscreenElement)) {\n self.enableWakeLock();\n self.waitingForPresent_ = true;\n } else if (isIOS() || isWebViewAndroid()) {\n self.enableWakeLock();\n self.isPresenting = true;\n self.beginPresent_();\n self.fireVRDisplayPresentChange_();\n resolve();\n }\n }\n if (!self.waitingForPresent_ && !isIOS()) {\n exitFullscreen();\n reject(new Error('Unable to present.'));\n }\n });\n };\n VRDisplay.prototype.exitPresent = function () {\n var wasPresenting = this.isPresenting;\n var self = this;\n this.isPresenting = false;\n this.layer_ = null;\n this.disableWakeLock();\n return new Promise(function (resolve, reject) {\n if (wasPresenting) {\n if (!exitFullscreen() && isIOS()) {\n self.endPresent_();\n self.fireVRDisplayPresentChange_();\n }\n if (isWebViewAndroid()) {\n self.removeFullscreenWrapper();\n self.removeFullscreenListeners_();\n self.endPresent_();\n self.fireVRDisplayPresentChange_();\n }\n resolve();\n } else {\n reject(new Error('Was not presenting to VRDisplay.'));\n }\n });\n };\n VRDisplay.prototype.getLayers = function () {\n if (this.layer_) {\n return [this.layer_];\n }\n return [];\n };\n VRDisplay.prototype.fireVRDisplayPresentChange_ = function () {\n var event = new CustomEvent('vrdisplaypresentchange', {\n detail: {\n display: this\n }\n });\n window.dispatchEvent(event);\n };\n VRDisplay.prototype.fireVRDisplayConnect_ = function () {\n var event = new CustomEvent('vrdisplayconnect', {\n detail: {\n display: this\n }\n });\n window.dispatchEvent(event);\n };\n VRDisplay.prototype.addFullscreenListeners_ = function (element, changeHandler, errorHandler) {\n this.removeFullscreenListeners_();\n this.fullscreenEventTarget_ = element;\n this.fullscreenChangeHandler_ = changeHandler;\n this.fullscreenErrorHandler_ = errorHandler;\n if (changeHandler) {\n if (document.fullscreenEnabled) {\n element.addEventListener('fullscreenchange', changeHandler, false);\n } else if (document.webkitFullscreenEnabled) {\n element.addEventListener('webkitfullscreenchange', changeHandler, false);\n } else if (document.mozFullScreenEnabled) {\n document.addEventListener('mozfullscreenchange', changeHandler, false);\n } else if (document.msFullscreenEnabled) {\n element.addEventListener('msfullscreenchange', changeHandler, false);\n }\n }\n if (errorHandler) {\n if (document.fullscreenEnabled) {\n element.addEventListener('fullscreenerror', errorHandler, false);\n } else if (document.webkitFullscreenEnabled) {\n element.addEventListener('webkitfullscreenerror', errorHandler, false);\n } else if (document.mozFullScreenEnabled) {\n document.addEventListener('mozfullscreenerror', errorHandler, false);\n } else if (document.msFullscreenEnabled) {\n element.addEventListener('msfullscreenerror', errorHandler, false);\n }\n }\n };\n VRDisplay.prototype.removeFullscreenListeners_ = function () {\n if (!this.fullscreenEventTarget_) return;\n var element = this.fullscreenEventTarget_;\n if (this.fullscreenChangeHandler_) {\n var changeHandler = this.fullscreenChangeHandler_;\n element.removeEventListener('fullscreenchange', changeHandler, false);\n element.removeEventListener('webkitfullscreenchange', changeHandler, false);\n document.removeEventListener('mozfullscreenchange', changeHandler, false);\n element.removeEventListener('msfullscreenchange', changeHandler, false);\n }\n if (this.fullscreenErrorHandler_) {\n var errorHandler = this.fullscreenErrorHandler_;\n element.removeEventListener('fullscreenerror', errorHandler, false);\n element.removeEventListener('webkitfullscreenerror', errorHandler, false);\n document.removeEventListener('mozfullscreenerror', errorHandler, false);\n element.removeEventListener('msfullscreenerror', errorHandler, false);\n }\n this.fullscreenEventTarget_ = null;\n this.fullscreenChangeHandler_ = null;\n this.fullscreenErrorHandler_ = null;\n };\n VRDisplay.prototype.enableWakeLock = function () {\n if (this.wakelock_) {\n this.wakelock_.enable();\n }\n };\n VRDisplay.prototype.disableWakeLock = function () {\n if (this.wakelock_) {\n this.wakelock_.disable();\n }\n };\n VRDisplay.prototype.beginPresent_ = function () {};\n VRDisplay.prototype.endPresent_ = function () {};\n VRDisplay.prototype.submitFrame = function (pose) {};\n VRDisplay.prototype.getEyeParameters = function (whichEye) {\n return null;\n };\n var config = {\n ADDITIONAL_VIEWERS: [],\n DEFAULT_VIEWER: '',\n MOBILE_WAKE_LOCK: true,\n DEBUG: false,\n DPDB_URL: 'https://dpdb.webvr.rocks/dpdb.json',\n K_FILTER: 0.98,\n PREDICTION_TIME_S: 0.040,\n CARDBOARD_UI_DISABLED: false,\n ROTATE_INSTRUCTIONS_DISABLED: false,\n YAW_ONLY: false,\n BUFFER_SCALE: 0.5,\n DIRTY_SUBMIT_FRAME_BINDINGS: false\n };\n var Eye = {\n LEFT: 'left',\n RIGHT: 'right'\n };\n function CardboardVRDisplay(config$$1) {\n var defaults = extend({}, config);\n config$$1 = extend(defaults, config$$1 || {});\n VRDisplay.call(this, {\n wakelock: config$$1.MOBILE_WAKE_LOCK\n });\n this.config = config$$1;\n this.displayName = 'Cardboard VRDisplay';\n this.capabilities = new VRDisplayCapabilities({\n hasPosition: false,\n hasOrientation: true,\n hasExternalDisplay: false,\n canPresent: true,\n maxLayers: 1\n });\n this.stageParameters = null;\n this.bufferScale_ = this.config.BUFFER_SCALE;\n this.poseSensor_ = new PoseSensor(this.config);\n this.distorter_ = null;\n this.cardboardUI_ = null;\n this.dpdb_ = new Dpdb(this.config.DPDB_URL, this.onDeviceParamsUpdated_.bind(this));\n this.deviceInfo_ = new DeviceInfo(this.dpdb_.getDeviceParams(), config$$1.ADDITIONAL_VIEWERS);\n this.viewerSelector_ = new ViewerSelector(config$$1.DEFAULT_VIEWER);\n this.viewerSelector_.onChange(this.onViewerChanged_.bind(this));\n this.deviceInfo_.setViewer(this.viewerSelector_.getCurrentViewer());\n if (!this.config.ROTATE_INSTRUCTIONS_DISABLED) {\n this.rotateInstructions_ = new RotateInstructions();\n }\n if (isIOS()) {\n window.addEventListener('resize', this.onResize_.bind(this));\n }\n }\n CardboardVRDisplay.prototype = Object.create(VRDisplay.prototype);\n CardboardVRDisplay.prototype._getPose = function () {\n return {\n position: null,\n orientation: this.poseSensor_.getOrientation(),\n linearVelocity: null,\n linearAcceleration: null,\n angularVelocity: null,\n angularAcceleration: null\n };\n };\n CardboardVRDisplay.prototype._resetPose = function () {\n if (this.poseSensor_.resetPose) {\n this.poseSensor_.resetPose();\n }\n };\n CardboardVRDisplay.prototype._getFieldOfView = function (whichEye) {\n var fieldOfView;\n if (whichEye == Eye.LEFT) {\n fieldOfView = this.deviceInfo_.getFieldOfViewLeftEye();\n } else if (whichEye == Eye.RIGHT) {\n fieldOfView = this.deviceInfo_.getFieldOfViewRightEye();\n } else {\n console.error('Invalid eye provided: %s', whichEye);\n return null;\n }\n return fieldOfView;\n };\n CardboardVRDisplay.prototype._getEyeOffset = function (whichEye) {\n var offset;\n if (whichEye == Eye.LEFT) {\n offset = [-this.deviceInfo_.viewer.interLensDistance * 0.5, 0.0, 0.0];\n } else if (whichEye == Eye.RIGHT) {\n offset = [this.deviceInfo_.viewer.interLensDistance * 0.5, 0.0, 0.0];\n } else {\n console.error('Invalid eye provided: %s', whichEye);\n return null;\n }\n return offset;\n };\n CardboardVRDisplay.prototype.getEyeParameters = function (whichEye) {\n var offset = this._getEyeOffset(whichEye);\n var fieldOfView = this._getFieldOfView(whichEye);\n var eyeParams = {\n offset: offset,\n renderWidth: this.deviceInfo_.device.width * 0.5 * this.bufferScale_,\n renderHeight: this.deviceInfo_.device.height * this.bufferScale_\n };\n Object.defineProperty(eyeParams, 'fieldOfView', {\n enumerable: true,\n get: function get() {\n deprecateWarning('VRFieldOfView', 'VRFrameData\\'s projection matrices');\n return fieldOfView;\n }\n });\n return eyeParams;\n };\n CardboardVRDisplay.prototype.onDeviceParamsUpdated_ = function (newParams) {\n if (this.config.DEBUG) {\n console.log('DPDB reported that device params were updated.');\n }\n this.deviceInfo_.updateDeviceParams(newParams);\n if (this.distorter_) {\n this.distorter_.updateDeviceInfo(this.deviceInfo_);\n }\n };\n CardboardVRDisplay.prototype.updateBounds_ = function () {\n if (this.layer_ && this.distorter_ && (this.layer_.leftBounds || this.layer_.rightBounds)) {\n this.distorter_.setTextureBounds(this.layer_.leftBounds, this.layer_.rightBounds);\n }\n };\n CardboardVRDisplay.prototype.beginPresent_ = function () {\n var gl = this.layer_.source.getContext('webgl');\n if (!gl) gl = this.layer_.source.getContext('experimental-webgl');\n if (!gl) gl = this.layer_.source.getContext('webgl2');\n if (!gl) return;\n if (this.layer_.predistorted) {\n if (!this.config.CARDBOARD_UI_DISABLED) {\n gl.canvas.width = getScreenWidth() * this.bufferScale_;\n gl.canvas.height = getScreenHeight() * this.bufferScale_;\n this.cardboardUI_ = new CardboardUI(gl);\n }\n } else {\n if (!this.config.CARDBOARD_UI_DISABLED) {\n this.cardboardUI_ = new CardboardUI(gl);\n }\n this.distorter_ = new CardboardDistorter(gl, this.cardboardUI_, this.config.BUFFER_SCALE, this.config.DIRTY_SUBMIT_FRAME_BINDINGS);\n this.distorter_.updateDeviceInfo(this.deviceInfo_);\n }\n if (this.cardboardUI_) {\n this.cardboardUI_.listen(function (e) {\n this.viewerSelector_.show(this.layer_.source.parentElement);\n e.stopPropagation();\n e.preventDefault();\n }.bind(this), function (e) {\n this.exitPresent();\n e.stopPropagation();\n e.preventDefault();\n }.bind(this));\n }\n if (this.rotateInstructions_) {\n if (isLandscapeMode() && isMobile()) {\n this.rotateInstructions_.showTemporarily(3000, this.layer_.source.parentElement);\n } else {\n this.rotateInstructions_.update();\n }\n }\n this.orientationHandler = this.onOrientationChange_.bind(this);\n window.addEventListener('orientationchange', this.orientationHandler);\n this.vrdisplaypresentchangeHandler = this.updateBounds_.bind(this);\n window.addEventListener('vrdisplaypresentchange', this.vrdisplaypresentchangeHandler);\n this.fireVRDisplayDeviceParamsChange_();\n };\n CardboardVRDisplay.prototype.endPresent_ = function () {\n if (this.distorter_) {\n this.distorter_.destroy();\n this.distorter_ = null;\n }\n if (this.cardboardUI_) {\n this.cardboardUI_.destroy();\n this.cardboardUI_ = null;\n }\n if (this.rotateInstructions_) {\n this.rotateInstructions_.hide();\n }\n this.viewerSelector_.hide();\n window.removeEventListener('orientationchange', this.orientationHandler);\n window.removeEventListener('vrdisplaypresentchange', this.vrdisplaypresentchangeHandler);\n };\n CardboardVRDisplay.prototype.updatePresent_ = function () {\n this.endPresent_();\n this.beginPresent_();\n };\n CardboardVRDisplay.prototype.submitFrame = function (pose) {\n if (this.distorter_) {\n this.updateBounds_();\n this.distorter_.submitFrame();\n } else if (this.cardboardUI_ && this.layer_) {\n var gl = this.layer_.source.getContext('webgl');\n if (!gl) gl = this.layer_.source.getContext('experimental-webgl');\n if (!gl) gl = this.layer_.source.getContext('webgl2');\n var canvas = gl.canvas;\n if (canvas.width != this.lastWidth || canvas.height != this.lastHeight) {\n this.cardboardUI_.onResize();\n }\n this.lastWidth = canvas.width;\n this.lastHeight = canvas.height;\n this.cardboardUI_.render();\n }\n };\n CardboardVRDisplay.prototype.onOrientationChange_ = function (e) {\n this.viewerSelector_.hide();\n if (this.rotateInstructions_) {\n this.rotateInstructions_.update();\n }\n this.onResize_();\n };\n CardboardVRDisplay.prototype.onResize_ = function (e) {\n if (this.layer_) {\n var gl = this.layer_.source.getContext('webgl');\n if (!gl) gl = this.layer_.source.getContext('experimental-webgl');\n if (!gl) gl = this.layer_.source.getContext('webgl2');\n var cssProperties = ['position: absolute', 'top: 0', 'left: 0', 'width: 100vw', 'height: 100vh', 'border: 0', 'margin: 0', 'padding: 0px', 'box-sizing: content-box'];\n gl.canvas.setAttribute('style', cssProperties.join('; ') + ';');\n safariCssSizeWorkaround(gl.canvas);\n }\n };\n CardboardVRDisplay.prototype.onViewerChanged_ = function (viewer) {\n this.deviceInfo_.setViewer(viewer);\n if (this.distorter_) {\n this.distorter_.updateDeviceInfo(this.deviceInfo_);\n }\n this.fireVRDisplayDeviceParamsChange_();\n };\n CardboardVRDisplay.prototype.fireVRDisplayDeviceParamsChange_ = function () {\n var event = new CustomEvent('vrdisplaydeviceparamschange', {\n detail: {\n vrdisplay: this,\n deviceInfo: this.deviceInfo_\n }\n });\n window.dispatchEvent(event);\n };\n CardboardVRDisplay.VRFrameData = VRFrameData;\n CardboardVRDisplay.VRDisplay = VRDisplay;\n return CardboardVRDisplay;\n });\n });\n var CardboardVRDisplay = unwrapExports(cardboardVrDisplay);\n var version = \"0.10.12\";\n var DefaultConfig = {\n ADDITIONAL_VIEWERS: [],\n DEFAULT_VIEWER: '',\n PROVIDE_MOBILE_VRDISPLAY: true,\n MOBILE_WAKE_LOCK: true,\n DEBUG: false,\n DPDB_URL: 'https://dpdb.webvr.rocks/dpdb.json',\n K_FILTER: 0.98,\n PREDICTION_TIME_S: 0.040,\n CARDBOARD_UI_DISABLED: false,\n ROTATE_INSTRUCTIONS_DISABLED: false,\n YAW_ONLY: false,\n BUFFER_SCALE: 0.5,\n DIRTY_SUBMIT_FRAME_BINDINGS: false\n };\n function WebVRPolyfill(config) {\n this.config = extend(extend({}, DefaultConfig), config);\n this.polyfillDisplays = [];\n this.enabled = false;\n this.hasNative = 'getVRDisplays' in navigator;\n this.native = {};\n this.native.getVRDisplays = navigator.getVRDisplays;\n this.native.VRFrameData = window.VRFrameData;\n this.native.VRDisplay = window.VRDisplay;\n if (!this.hasNative || this.config.PROVIDE_MOBILE_VRDISPLAY && isMobile()) {\n this.enable();\n this.getVRDisplays().then(function (displays) {\n if (displays && displays[0] && displays[0].fireVRDisplayConnect_) {\n displays[0].fireVRDisplayConnect_();\n }\n });\n }\n }\n WebVRPolyfill.prototype.getPolyfillDisplays = function () {\n if (this._polyfillDisplaysPopulated) {\n return this.polyfillDisplays;\n }\n if (isMobile()) {\n var vrDisplay = new CardboardVRDisplay({\n ADDITIONAL_VIEWERS: this.config.ADDITIONAL_VIEWERS,\n DEFAULT_VIEWER: this.config.DEFAULT_VIEWER,\n MOBILE_WAKE_LOCK: this.config.MOBILE_WAKE_LOCK,\n DEBUG: this.config.DEBUG,\n DPDB_URL: this.config.DPDB_URL,\n CARDBOARD_UI_DISABLED: this.config.CARDBOARD_UI_DISABLED,\n K_FILTER: this.config.K_FILTER,\n PREDICTION_TIME_S: this.config.PREDICTION_TIME_S,\n ROTATE_INSTRUCTIONS_DISABLED: this.config.ROTATE_INSTRUCTIONS_DISABLED,\n YAW_ONLY: this.config.YAW_ONLY,\n BUFFER_SCALE: this.config.BUFFER_SCALE,\n DIRTY_SUBMIT_FRAME_BINDINGS: this.config.DIRTY_SUBMIT_FRAME_BINDINGS\n });\n this.polyfillDisplays.push(vrDisplay);\n }\n this._polyfillDisplaysPopulated = true;\n return this.polyfillDisplays;\n };\n WebVRPolyfill.prototype.enable = function () {\n this.enabled = true;\n if (this.hasNative && this.native.VRFrameData) {\n var NativeVRFrameData = this.native.VRFrameData;\n var nativeFrameData = new this.native.VRFrameData();\n var nativeGetFrameData = this.native.VRDisplay.prototype.getFrameData;\n window.VRDisplay.prototype.getFrameData = function (frameData) {\n if (frameData instanceof NativeVRFrameData) {\n nativeGetFrameData.call(this, frameData);\n return;\n }\n nativeGetFrameData.call(this, nativeFrameData);\n frameData.pose = nativeFrameData.pose;\n copyArray(nativeFrameData.leftProjectionMatrix, frameData.leftProjectionMatrix);\n copyArray(nativeFrameData.rightProjectionMatrix, frameData.rightProjectionMatrix);\n copyArray(nativeFrameData.leftViewMatrix, frameData.leftViewMatrix);\n copyArray(nativeFrameData.rightViewMatrix, frameData.rightViewMatrix);\n };\n }\n navigator.getVRDisplays = this.getVRDisplays.bind(this);\n window.VRDisplay = CardboardVRDisplay.VRDisplay;\n window.VRFrameData = CardboardVRDisplay.VRFrameData;\n };\n WebVRPolyfill.prototype.getVRDisplays = function () {\n var _this = this;\n var config = this.config;\n if (!this.hasNative) {\n return Promise.resolve(this.getPolyfillDisplays());\n }\n return this.native.getVRDisplays.call(navigator).then(function (nativeDisplays) {\n return nativeDisplays.length > 0 ? nativeDisplays : _this.getPolyfillDisplays();\n });\n };\n WebVRPolyfill.version = version;\n WebVRPolyfill.VRFrameData = CardboardVRDisplay.VRFrameData;\n WebVRPolyfill.VRDisplay = CardboardVRDisplay.VRDisplay;\n var webvrPolyfill = Object.freeze({\n default: WebVRPolyfill\n });\n var require$$0 = webvrPolyfill && WebVRPolyfill || webvrPolyfill;\n if (typeof commonjsGlobal !== 'undefined' && commonjsGlobal.window) {\n if (!commonjsGlobal.document) {\n commonjsGlobal.document = commonjsGlobal.window.document;\n }\n if (!commonjsGlobal.navigator) {\n commonjsGlobal.navigator = commonjsGlobal.window.navigator;\n }\n }\n var src = require$$0;\n return src;\n});\n\n/***/ }),\n\n/***/ \"./node_modules/word-wrapper/index.js\":\n/*!********************************************!*\\\n !*** ./node_modules/word-wrapper/index.js ***!\n \\********************************************/\n/***/ ((module) => {\n\nvar newline = /\\n/;\nvar newlineChar = '\\n';\nvar whitespace = /\\s/;\nmodule.exports = function (text, opt) {\n var lines = module.exports.lines(text, opt);\n return lines.map(function (line) {\n return text.substring(line.start, line.end);\n }).join('\\n');\n};\nmodule.exports.lines = function wordwrap(text, opt) {\n opt = opt || {};\n\n //zero width results in nothing visible\n if (opt.width === 0 && opt.mode !== 'nowrap') return [];\n text = text || '';\n var width = typeof opt.width === 'number' ? opt.width : Number.MAX_VALUE;\n var start = Math.max(0, opt.start || 0);\n var end = typeof opt.end === 'number' ? opt.end : text.length;\n var mode = opt.mode;\n var measure = opt.measure || monospace;\n if (mode === 'pre') return pre(measure, text, start, end, width);else return greedy(measure, text, start, end, width, mode);\n};\nfunction idxOf(text, chr, start, end) {\n var idx = text.indexOf(chr, start);\n if (idx === -1 || idx > end) return end;\n return idx;\n}\nfunction isWhitespace(chr) {\n return whitespace.test(chr);\n}\nfunction pre(measure, text, start, end, width) {\n var lines = [];\n var lineStart = start;\n for (var i = start; i < end && i < text.length; i++) {\n var chr = text.charAt(i);\n var isNewline = newline.test(chr);\n\n //If we've reached a newline, then step down a line\n //Or if we've reached the EOF\n if (isNewline || i === end - 1) {\n var lineEnd = isNewline ? i : i + 1;\n var measured = measure(text, lineStart, lineEnd, width);\n lines.push(measured);\n lineStart = i + 1;\n }\n }\n return lines;\n}\nfunction greedy(measure, text, start, end, width, mode) {\n //A greedy word wrapper based on LibGDX algorithm\n //https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/BitmapFontCache.java\n var lines = [];\n var testWidth = width;\n //if 'nowrap' is specified, we only wrap on newline chars\n if (mode === 'nowrap') testWidth = Number.MAX_VALUE;\n while (start < end && start < text.length) {\n //get next newline position\n var newLine = idxOf(text, newlineChar, start, end);\n\n //eat whitespace at start of line\n while (start < newLine) {\n if (!isWhitespace(text.charAt(start))) break;\n start++;\n }\n\n //determine visible # of glyphs for the available width\n var measured = measure(text, start, newLine, testWidth);\n var lineEnd = start + (measured.end - measured.start);\n var nextStart = lineEnd + newlineChar.length;\n\n //if we had to cut the line before the next newline...\n if (lineEnd < newLine) {\n //find char to break on\n while (lineEnd > start) {\n if (isWhitespace(text.charAt(lineEnd))) break;\n lineEnd--;\n }\n if (lineEnd === start) {\n if (nextStart > start + newlineChar.length) nextStart--;\n lineEnd = nextStart; // If no characters to break, show all.\n } else {\n nextStart = lineEnd;\n //eat whitespace at end of line\n while (lineEnd > start) {\n if (!isWhitespace(text.charAt(lineEnd - newlineChar.length))) break;\n lineEnd--;\n }\n }\n }\n if (lineEnd >= start) {\n var result = measure(text, start, lineEnd, testWidth);\n lines.push(result);\n }\n start = nextStart;\n }\n return lines;\n}\n\n//determines the visible number of glyphs within a given width\nfunction monospace(text, start, end, width) {\n var glyphs = Math.min(width, end - start);\n return {\n start: start,\n end: start + glyphs\n };\n}\n\n/***/ }),\n\n/***/ \"./node_modules/xhr/index.js\":\n/*!***********************************!*\\\n !*** ./node_modules/xhr/index.js ***!\n \\***********************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\n\"use strict\";\n\n\nvar window = __webpack_require__(/*! global/window */ \"./node_modules/global/window.js\");\nvar isFunction = __webpack_require__(/*! is-function */ \"./node_modules/is-function/index.js\");\nvar parseHeaders = __webpack_require__(/*! parse-headers */ \"./node_modules/parse-headers/parse-headers.js\");\nvar xtend = __webpack_require__(/*! xtend */ \"./node_modules/xtend/immutable.js\");\nmodule.exports = createXHR;\n// Allow use of default import syntax in TypeScript\nmodule.exports[\"default\"] = createXHR;\ncreateXHR.XMLHttpRequest = window.XMLHttpRequest || noop;\ncreateXHR.XDomainRequest = \"withCredentials\" in new createXHR.XMLHttpRequest() ? createXHR.XMLHttpRequest : window.XDomainRequest;\nforEachArray([\"get\", \"put\", \"post\", \"patch\", \"head\", \"delete\"], function (method) {\n createXHR[method === \"delete\" ? \"del\" : method] = function (uri, options, callback) {\n options = initParams(uri, options, callback);\n options.method = method.toUpperCase();\n return _createXHR(options);\n };\n});\nfunction forEachArray(array, iterator) {\n for (var i = 0; i < array.length; i++) {\n iterator(array[i]);\n }\n}\nfunction isEmpty(obj) {\n for (var i in obj) {\n if (obj.hasOwnProperty(i)) return false;\n }\n return true;\n}\nfunction initParams(uri, options, callback) {\n var params = uri;\n if (isFunction(options)) {\n callback = options;\n if (typeof uri === \"string\") {\n params = {\n uri: uri\n };\n }\n } else {\n params = xtend(options, {\n uri: uri\n });\n }\n params.callback = callback;\n return params;\n}\nfunction createXHR(uri, options, callback) {\n options = initParams(uri, options, callback);\n return _createXHR(options);\n}\nfunction _createXHR(options) {\n if (typeof options.callback === \"undefined\") {\n throw new Error(\"callback argument missing\");\n }\n var called = false;\n var callback = function cbOnce(err, response, body) {\n if (!called) {\n called = true;\n options.callback(err, response, body);\n }\n };\n function readystatechange() {\n if (xhr.readyState === 4) {\n setTimeout(loadFunc, 0);\n }\n }\n function getBody() {\n // Chrome with requestType=blob throws errors arround when even testing access to responseText\n var body = undefined;\n if (xhr.response) {\n body = xhr.response;\n } else {\n body = xhr.responseText || getXml(xhr);\n }\n if (isJson) {\n try {\n body = JSON.parse(body);\n } catch (e) {}\n }\n return body;\n }\n function errorFunc(evt) {\n clearTimeout(timeoutTimer);\n if (!(evt instanceof Error)) {\n evt = new Error(\"\" + (evt || \"Unknown XMLHttpRequest Error\"));\n }\n evt.statusCode = 0;\n return callback(evt, failureResponse);\n }\n\n // will load the data & process the response in a special response object\n function loadFunc() {\n if (aborted) return;\n var status;\n clearTimeout(timeoutTimer);\n if (options.useXDR && xhr.status === undefined) {\n //IE8 CORS GET successful response doesn't have a status field, but body is fine\n status = 200;\n } else {\n status = xhr.status === 1223 ? 204 : xhr.status;\n }\n var response = failureResponse;\n var err = null;\n if (status !== 0) {\n response = {\n body: getBody(),\n statusCode: status,\n method: method,\n headers: {},\n url: uri,\n rawRequest: xhr\n };\n if (xhr.getAllResponseHeaders) {\n //remember xhr can in fact be XDR for CORS in IE\n response.headers = parseHeaders(xhr.getAllResponseHeaders());\n }\n } else {\n err = new Error(\"Internal XMLHttpRequest Error\");\n }\n return callback(err, response, response.body);\n }\n var xhr = options.xhr || null;\n if (!xhr) {\n if (options.cors || options.useXDR) {\n xhr = new createXHR.XDomainRequest();\n } else {\n xhr = new createXHR.XMLHttpRequest();\n }\n }\n var key;\n var aborted;\n var uri = xhr.url = options.uri || options.url;\n var method = xhr.method = options.method || \"GET\";\n var body = options.body || options.data;\n var headers = xhr.headers = options.headers || {};\n var sync = !!options.sync;\n var isJson = false;\n var timeoutTimer;\n var failureResponse = {\n body: undefined,\n headers: {},\n statusCode: 0,\n method: method,\n url: uri,\n rawRequest: xhr\n };\n if (\"json\" in options && options.json !== false) {\n isJson = true;\n headers[\"accept\"] || headers[\"Accept\"] || (headers[\"Accept\"] = \"application/json\"); //Don't override existing accept header declared by user\n if (method !== \"GET\" && method !== \"HEAD\") {\n headers[\"content-type\"] || headers[\"Content-Type\"] || (headers[\"Content-Type\"] = \"application/json\"); //Don't override existing accept header declared by user\n body = JSON.stringify(options.json === true ? body : options.json);\n }\n }\n xhr.onreadystatechange = readystatechange;\n xhr.onload = loadFunc;\n xhr.onerror = errorFunc;\n // IE9 must have onprogress be set to a unique function.\n xhr.onprogress = function () {\n // IE must die\n };\n xhr.onabort = function () {\n aborted = true;\n };\n xhr.ontimeout = errorFunc;\n xhr.open(method, uri, !sync, options.username, options.password);\n //has to be after open\n if (!sync) {\n xhr.withCredentials = !!options.withCredentials;\n }\n // Cannot set timeout with sync request\n // not setting timeout on the xhr object, because of old webkits etc. not handling that correctly\n // both npm's request and jquery 1.x use this kind of timeout, so this is being consistent\n if (!sync && options.timeout > 0) {\n timeoutTimer = setTimeout(function () {\n if (aborted) return;\n aborted = true; //IE9 may still call readystatechange\n xhr.abort(\"timeout\");\n var e = new Error(\"XMLHttpRequest timeout\");\n e.code = \"ETIMEDOUT\";\n errorFunc(e);\n }, options.timeout);\n }\n if (xhr.setRequestHeader) {\n for (key in headers) {\n if (headers.hasOwnProperty(key)) {\n xhr.setRequestHeader(key, headers[key]);\n }\n }\n } else if (options.headers && !isEmpty(options.headers)) {\n throw new Error(\"Headers cannot be set on an XDomainRequest object\");\n }\n if (\"responseType\" in options) {\n xhr.responseType = options.responseType;\n }\n if (\"beforeSend\" in options && typeof options.beforeSend === \"function\") {\n options.beforeSend(xhr);\n }\n\n // Microsoft Edge browser sends \"undefined\" when send is called with undefined value.\n // XMLHttpRequest spec says to pass null as body to indicate no body\n // See https://github.com/naugtur/xhr/issues/100.\n xhr.send(body || null);\n return xhr;\n}\nfunction getXml(xhr) {\n // xhr.responseXML will throw Exception \"InvalidStateError\" or \"DOMException\"\n // See https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseXML.\n try {\n if (xhr.responseType === \"document\") {\n return xhr.responseXML;\n }\n var firefoxBugTakenEffect = xhr.responseXML && xhr.responseXML.documentElement.nodeName === \"parsererror\";\n if (xhr.responseType === \"\" && !firefoxBugTakenEffect) {\n return xhr.responseXML;\n }\n } catch (e) {}\n return null;\n}\nfunction noop() {}\n\n/***/ }),\n\n/***/ \"./node_modules/xml-parse-from-string/index.js\":\n/*!*****************************************************!*\\\n !*** ./node_modules/xml-parse-from-string/index.js ***!\n \\*****************************************************/\n/***/ ((module) => {\n\nmodule.exports = function xmlparser() {\n //common browsers\n if (typeof self.DOMParser !== 'undefined') {\n return function (str) {\n var parser = new self.DOMParser();\n return parser.parseFromString(str, 'application/xml');\n };\n }\n\n //IE8 fallback\n if (typeof self.ActiveXObject !== 'undefined' && new self.ActiveXObject('Microsoft.XMLDOM')) {\n return function (str) {\n var xmlDoc = new self.ActiveXObject(\"Microsoft.XMLDOM\");\n xmlDoc.async = \"false\";\n xmlDoc.loadXML(str);\n return xmlDoc;\n };\n }\n\n //last resort fallback\n return function (str) {\n var div = document.createElement('div');\n div.innerHTML = str;\n return div;\n };\n}();\n\n/***/ }),\n\n/***/ \"./node_modules/xtend/immutable.js\":\n/*!*****************************************!*\\\n !*** ./node_modules/xtend/immutable.js ***!\n \\*****************************************/\n/***/ ((module) => {\n\nmodule.exports = extend;\nvar hasOwnProperty = Object.prototype.hasOwnProperty;\nfunction extend() {\n var target = {};\n for (var i = 0; i < arguments.length; i++) {\n var source = arguments[i];\n for (var key in source) {\n if (hasOwnProperty.call(source, key)) {\n target[key] = source[key];\n }\n }\n }\n return target;\n}\n\n/***/ }),\n\n/***/ \"./src/components/anchored.js\":\n/*!************************************!*\\\n !*** ./src/components/anchored.js ***!\n \\************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\n/* global THREE, XRRigidTransform, localStorage */\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar utils = __webpack_require__(/*! ../utils/ */ \"./src/utils/index.js\");\nvar warn = utils.debug('components:anchored:warn');\n\n/**\n * Anchored component.\n * Feature only available in browsers that implement the WebXR anchors module.\n * Once anchored the entity remains to a fixed position in real-world space.\n * If the anchor is persistent, the anchor positioned remains across sessions or until the browser data is cleared.\n */\nmodule.exports.Component = registerComponent('anchored', {\n schema: {\n persistent: {\n default: false\n }\n },\n init: function () {\n var sceneEl = this.el.sceneEl;\n var webxrData = sceneEl.getAttribute('webxr');\n var optionalFeaturesArray = webxrData.optionalFeatures;\n if (optionalFeaturesArray.indexOf('anchors') === -1) {\n optionalFeaturesArray.push('anchors');\n this.el.sceneEl.setAttribute('webxr', webxrData);\n }\n this.auxQuaternion = new THREE.Quaternion();\n this.onEnterVR = this.onEnterVR.bind(this);\n this.el.sceneEl.addEventListener('enter-vr', this.onEnterVR);\n },\n onEnterVR: function () {\n this.anchor = undefined;\n this.requestPersistentAnchorPending = this.data.persistent;\n this.requestAnchorPending = !this.data.persistent;\n },\n tick: function () {\n var sceneEl = this.el.sceneEl;\n var xrManager = sceneEl.renderer.xr;\n var frame;\n var refSpace;\n var pose;\n var object3D = this.el.object3D;\n if (!sceneEl.is('ar-mode') && !sceneEl.is('vr-mode')) {\n return;\n }\n if (!this.anchor && this.requestPersistentAnchorPending) {\n this.restorePersistentAnchor();\n }\n if (!this.anchor && this.requestAnchorPending) {\n this.createAnchor();\n }\n if (!this.anchor) {\n return;\n }\n frame = sceneEl.frame;\n refSpace = xrManager.getReferenceSpace();\n pose = frame.getPose(this.anchor.anchorSpace, refSpace);\n object3D.matrix.elements = pose.transform.matrix;\n object3D.matrix.decompose(object3D.position, object3D.rotation, object3D.scale);\n },\n createAnchor: async function createAnchor(position, quaternion) {\n var sceneEl = this.el.sceneEl;\n var xrManager = sceneEl.renderer.xr;\n var frame;\n var referenceSpace;\n var anchorPose;\n var anchor;\n var object3D = this.el.object3D;\n position = position || object3D.position;\n quaternion = quaternion || this.auxQuaternion.setFromEuler(object3D.rotation);\n if (!anchorsSupported(sceneEl)) {\n warn('This browser doesn\\'t support the WebXR anchors module');\n return;\n }\n if (this.anchor) {\n this.deleteAnchor();\n }\n frame = sceneEl.frame;\n referenceSpace = xrManager.getReferenceSpace();\n anchorPose = new XRRigidTransform({\n x: position.x,\n y: position.y,\n z: position.z\n }, {\n x: quaternion.x,\n y: quaternion.y,\n z: quaternion.z,\n w: quaternion.w\n });\n this.requestAnchorPending = false;\n anchor = await frame.createAnchor(anchorPose, referenceSpace);\n if (this.data.persistent) {\n if (this.el.id) {\n this.persistentHandle = await anchor.requestPersistentHandle();\n localStorage.setItem(this.el.id, this.persistentHandle);\n } else {\n warn('The anchor won\\'t be persisted because the entity has no assigned id.');\n }\n }\n sceneEl.object3D.attach(this.el.object3D);\n this.anchor = anchor;\n },\n restorePersistentAnchor: async function restorePersistentAnchor() {\n var xrManager = this.el.sceneEl.renderer.xr;\n var session = xrManager.getSession();\n var persistentAnchors = session.persistentAnchors;\n var storedPersistentHandle;\n this.requestPersistentAnchorPending = false;\n if (!this.el.id) {\n warn('The entity associated to the persistent anchor cannot be retrieved because it doesn\\'t have an assigned id.');\n this.requestAnchorPending = true;\n return;\n }\n if (persistentAnchors) {\n storedPersistentHandle = localStorage.getItem(this.el.id);\n for (var i = 0; i < persistentAnchors.length; ++i) {\n if (storedPersistentHandle !== persistentAnchors[i]) {\n continue;\n }\n this.anchor = await session.restorePersistentAnchor(persistentAnchors[i]);\n if (this.anchor) {\n this.persistentHandle = persistentAnchors[i];\n }\n break;\n }\n if (!this.anchor) {\n this.requestAnchorPending = true;\n }\n } else {\n this.requestPersistentAnchorPending = true;\n }\n },\n deleteAnchor: function () {\n var xrManager;\n var session;\n var anchor = this.anchor;\n if (!anchor) {\n return;\n }\n xrManager = this.el.sceneEl.renderer.xr;\n session = xrManager.getSession();\n anchor.delete();\n this.el.sceneEl.object3D.add(this.el.object3D);\n if (this.persistentHandle) {\n session.deletePersistentAnchor(this.persistentHandle);\n }\n this.anchor = undefined;\n }\n});\nfunction anchorsSupported(sceneEl) {\n var xrManager = sceneEl.renderer.xr;\n var session = xrManager.getSession();\n return session && session.restorePersistentAnchor;\n}\n\n/***/ }),\n\n/***/ \"./src/components/animation.js\":\n/*!*************************************!*\\\n !*** ./src/components/animation.js ***!\n \\*************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar anime = (__webpack_require__(/*! super-animejs */ \"./node_modules/super-animejs/lib/anime.es.js\")[\"default\"]);\nvar components = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").components);\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar THREE = __webpack_require__(/*! ../lib/three */ \"./src/lib/three.js\");\nvar utils = __webpack_require__(/*! ../utils */ \"./src/utils/index.js\");\nvar colorHelperFrom = new THREE.Color();\nvar colorHelperTo = new THREE.Color();\nvar getComponentProperty = utils.entity.getComponentProperty;\nvar setComponentProperty = utils.entity.setComponentProperty;\nvar splitCache = {};\nvar TYPE_COLOR = 'color';\nvar PROP_POSITION = 'position';\nvar PROP_ROTATION = 'rotation';\nvar PROP_SCALE = 'scale';\nvar STRING_COMPONENTS = 'components';\nvar STRING_OBJECT3D = 'object3D';\n\n/**\n * Animation component for A-Frame using anime.js.\n *\n * The component manually controls the tick by setting `autoplay: false` on anime.js and\n * manually * calling `animation.tick()` in the tick handler. To pause or resume, we toggle a\n * boolean * flag * `isAnimationPlaying`.\n *\n * anime.js animation config for tweenining Javascript objects and values works as:\n *\n * config = {\n * targets: {foo: 0.0, bar: '#000'},\n * foo: 1.0,\n * bar: '#FFF'\n * }\n *\n * The above will tween each property in `targets`. The `to` values are set in the root of\n * the config.\n *\n * @member {object} animation - anime.js instance.\n * @member {boolean} animationIsPlaying - Control if animation is playing.\n */\nmodule.exports.Component = registerComponent('animation', {\n schema: {\n autoplay: {\n default: true\n },\n delay: {\n default: 0\n },\n dir: {\n default: ''\n },\n dur: {\n default: 1000\n },\n easing: {\n default: 'easeInQuad'\n },\n elasticity: {\n default: 400\n },\n enabled: {\n default: true\n },\n from: {\n default: ''\n },\n loop: {\n default: 0,\n parse: function (value) {\n // Boolean or integer.\n if (value === true || value === 'true') {\n return true;\n }\n if (value === false || value === 'false') {\n return false;\n }\n return parseInt(value, 10);\n }\n },\n property: {\n default: ''\n },\n startEvents: {\n type: 'array'\n },\n pauseEvents: {\n type: 'array'\n },\n resumeEvents: {\n type: 'array'\n },\n round: {\n default: false\n },\n to: {\n default: ''\n },\n type: {\n default: ''\n },\n isRawProperty: {\n default: false\n }\n },\n multiple: true,\n init: function () {\n var self = this;\n this.eventDetail = {\n name: this.attrName\n };\n this.time = 0;\n this.animation = null;\n this.animationIsPlaying = false;\n this.onStartEvent = this.onStartEvent.bind(this);\n this.beginAnimation = this.beginAnimation.bind(this);\n this.pauseAnimation = this.pauseAnimation.bind(this);\n this.resumeAnimation = this.resumeAnimation.bind(this);\n this.fromColor = {};\n this.toColor = {};\n this.targets = {};\n this.targetsArray = [];\n this.updateConfigForDefault = this.updateConfigForDefault.bind(this);\n this.updateConfigForRawColor = this.updateConfigForRawColor.bind(this);\n this.config = {\n complete: function () {\n self.animationIsPlaying = false;\n self.el.emit('animationcomplete', self.eventDetail, false);\n if (self.id) {\n self.el.emit('animationcomplete__' + self.id, self.eventDetail, false);\n }\n }\n };\n },\n update: function (oldData) {\n var config = this.config;\n var data = this.data;\n this.animationIsPlaying = false;\n if (!this.data.enabled) {\n return;\n }\n if (!data.property) {\n return;\n }\n\n // Base config.\n config.autoplay = false;\n config.direction = data.dir;\n config.duration = data.dur;\n config.easing = data.easing;\n config.elasticity = data.elasticity;\n config.loop = data.loop;\n config.round = data.round;\n\n // Start new animation.\n this.createAndStartAnimation();\n },\n tick: function (t, dt) {\n if (!this.animationIsPlaying) {\n return;\n }\n this.time += dt;\n this.animation.tick(this.time);\n },\n remove: function () {\n this.pauseAnimation();\n this.removeEventListeners();\n },\n pause: function () {\n this.paused = true;\n this.pausedWasPlaying = this.animationIsPlaying;\n this.pauseAnimation();\n this.removeEventListeners();\n },\n /**\n * `play` handler only for resuming scene.\n */\n play: function () {\n if (!this.paused) {\n return;\n }\n this.paused = false;\n this.addEventListeners();\n if (this.pausedWasPlaying) {\n this.resumeAnimation();\n this.pausedWasPlaying = false;\n }\n },\n /**\n * Start animation from scratch.\n */\n createAndStartAnimation: function () {\n var data = this.data;\n this.updateConfig();\n this.animationIsPlaying = false;\n this.animation = anime(this.config);\n this.animation.began = true;\n this.removeEventListeners();\n this.addEventListeners();\n\n // Wait for start events for animation.\n if (!data.autoplay || data.startEvents && data.startEvents.length) {\n return;\n }\n\n // Delay animation.\n if (data.delay) {\n setTimeout(this.beginAnimation, data.delay);\n return;\n }\n\n // Play animation.\n this.beginAnimation();\n },\n /**\n * This is before animation start (including from startEvents).\n * Set to initial state (config.from, time = 0, seekTime = 0).\n */\n beginAnimation: function () {\n this.updateConfig();\n this.animation.began = true;\n this.time = 0;\n this.animationIsPlaying = true;\n this.stopRelatedAnimations();\n this.el.emit('animationbegin', this.eventDetail, false);\n },\n pauseAnimation: function () {\n this.animationIsPlaying = false;\n },\n resumeAnimation: function () {\n this.animationIsPlaying = true;\n },\n /**\n * startEvents callback.\n */\n onStartEvent: function () {\n if (!this.data.enabled) {\n return;\n }\n this.updateConfig();\n if (this.animation) {\n this.animation.pause();\n }\n this.animation = anime(this.config);\n\n // Include the delay before each start event.\n if (this.data.delay) {\n setTimeout(this.beginAnimation, this.data.delay);\n return;\n }\n this.beginAnimation();\n },\n /**\n * rawProperty: true and type: color;\n */\n updateConfigForRawColor: function () {\n var config = this.config;\n var data = this.data;\n var el = this.el;\n var from;\n var key;\n var to;\n if (this.waitComponentInitRawProperty(this.updateConfigForRawColor)) {\n return;\n }\n from = data.from === '' ? getRawProperty(el, data.property) : data.from;\n to = data.to;\n\n // Use r/g/b vector for color type.\n this.setColorConfig(from, to);\n from = this.fromColor;\n to = this.toColor;\n this.targetsArray.length = 0;\n this.targetsArray.push(from);\n config.targets = this.targetsArray;\n for (key in to) {\n config[key] = to[key];\n }\n config.update = function () {\n var lastValue = {};\n return function (anim) {\n var value;\n value = anim.animatables[0].target;\n // For animation timeline.\n if (value.r === lastValue.r && value.g === lastValue.g && value.b === lastValue.b) {\n return;\n }\n setRawProperty(el, data.property, value, data.type);\n };\n }();\n },\n /**\n * Stuff property into generic `property` key.\n */\n updateConfigForDefault: function () {\n var config = this.config;\n var data = this.data;\n var el = this.el;\n var from;\n var isBoolean;\n var isNumber;\n var to;\n if (this.waitComponentInitRawProperty(this.updateConfigForDefault)) {\n return;\n }\n if (data.from === '') {\n // Infer from.\n from = isRawProperty(data) ? getRawProperty(el, data.property) : getComponentProperty(el, data.property);\n } else {\n // Explicit from.\n from = data.from;\n }\n to = data.to;\n isNumber = !isNaN(from || to);\n if (isNumber) {\n from = parseFloat(from);\n to = parseFloat(to);\n } else {\n from = from ? from.toString() : from;\n to = to ? to.toString() : to;\n }\n\n // Convert booleans to integer to allow boolean flipping.\n isBoolean = data.to === 'true' || data.to === 'false' || data.to === true || data.to === false;\n if (isBoolean) {\n from = data.from === 'true' || data.from === true ? 1 : 0;\n to = data.to === 'true' || data.to === true ? 1 : 0;\n }\n this.targets.aframeProperty = from;\n config.targets = this.targets;\n config.aframeProperty = to;\n config.update = function () {\n var lastValue;\n return function (anim) {\n var value;\n value = anim.animatables[0].target.aframeProperty;\n\n // Need to do a last value check for animation timeline since all the tweening\n // begins simultaneously even if the value has not changed. Also better for perf\n // anyway.\n if (value === lastValue) {\n return;\n }\n lastValue = value;\n if (isBoolean) {\n value = value >= 1;\n }\n if (isRawProperty(data)) {\n setRawProperty(el, data.property, value, data.type);\n } else {\n setComponentProperty(el, data.property, value);\n }\n };\n }();\n },\n /**\n * Extend x/y/z/w onto the config.\n * Update vector by modifying object3D.\n */\n updateConfigForVector: function () {\n var config = this.config;\n var data = this.data;\n var el = this.el;\n var key;\n var from;\n var to;\n\n // Parse coordinates.\n from = data.from !== '' ? utils.coordinates.parse(data.from) // If data.from defined, use that.\n : getComponentProperty(el, data.property); // If data.from not defined, get on the fly.\n to = utils.coordinates.parse(data.to);\n if (data.property === PROP_ROTATION) {\n toRadians(from);\n toRadians(to);\n }\n\n // Set to and from.\n this.targetsArray.length = 0;\n this.targetsArray.push(from);\n config.targets = this.targetsArray;\n for (key in to) {\n config[key] = to[key];\n }\n\n // If animating object3D transformation, run more optimized updater.\n if (data.property === PROP_POSITION || data.property === PROP_ROTATION || data.property === PROP_SCALE) {\n config.update = function () {\n var lastValue = {};\n return function (anim) {\n var value = anim.animatables[0].target;\n\n // For animation timeline.\n if (value.x === lastValue.x && value.y === lastValue.y && value.z === lastValue.z) {\n return;\n }\n lastValue.x = value.x;\n lastValue.y = value.y;\n lastValue.z = value.z;\n el.object3D[data.property].set(value.x, value.y, value.z);\n };\n }();\n return;\n }\n\n // Animating some vector.\n config.update = function () {\n var lastValue = {};\n return function (anim) {\n var value = anim.animatables[0].target;\n\n // Animate rotation through radians.\n // For animation timeline.\n if (value.x === lastValue.x && value.y === lastValue.y && value.z === lastValue.z) {\n return;\n }\n lastValue.x = value.x;\n lastValue.y = value.y;\n lastValue.z = value.z;\n setComponentProperty(el, data.property, value);\n };\n }();\n },\n /**\n * Update the config before each run.\n */\n updateConfig: function () {\n var propType;\n\n // Route config type.\n propType = getPropertyType(this.el, this.data.property);\n if (isRawProperty(this.data) && this.data.type === TYPE_COLOR) {\n this.updateConfigForRawColor();\n } else if (propType === 'vec2' || propType === 'vec3' || propType === 'vec4') {\n this.updateConfigForVector();\n } else {\n this.updateConfigForDefault();\n }\n },\n /**\n * Wait for component to initialize.\n */\n waitComponentInitRawProperty: function (cb) {\n var componentName;\n var data = this.data;\n var el = this.el;\n var self = this;\n if (data.from !== '') {\n return false;\n }\n if (!data.property.startsWith(STRING_COMPONENTS)) {\n return false;\n }\n componentName = splitDot(data.property)[1];\n if (el.components[componentName]) {\n return false;\n }\n el.addEventListener('componentinitialized', function wait(evt) {\n if (evt.detail.name !== componentName) {\n return;\n }\n cb();\n // Since the config was created async, create the animation now since we missed it\n // earlier.\n self.animation = anime(self.config);\n el.removeEventListener('componentinitialized', wait);\n });\n return true;\n },\n /**\n * Make sure two animations on the same property don't fight each other.\n * e.g., animation__mouseenter=\"property: material.opacity\"\n * animation__mouseleave=\"property: material.opacity\"\n */\n stopRelatedAnimations: function () {\n var component;\n var componentName;\n for (componentName in this.el.components) {\n component = this.el.components[componentName];\n if (componentName === this.attrName) {\n continue;\n }\n if (component.name !== 'animation') {\n continue;\n }\n if (!component.animationIsPlaying) {\n continue;\n }\n if (component.data.property !== this.data.property) {\n continue;\n }\n component.animationIsPlaying = false;\n }\n },\n addEventListeners: function () {\n var data = this.data;\n var el = this.el;\n addEventListeners(el, data.startEvents, this.onStartEvent);\n addEventListeners(el, data.pauseEvents, this.pauseAnimation);\n addEventListeners(el, data.resumeEvents, this.resumeAnimation);\n },\n removeEventListeners: function () {\n var data = this.data;\n var el = this.el;\n removeEventListeners(el, data.startEvents, this.onStartEvent);\n removeEventListeners(el, data.pauseEvents, this.pauseAnimation);\n removeEventListeners(el, data.resumeEvents, this.resumeAnimation);\n },\n setColorConfig: function (from, to) {\n colorHelperFrom.set(from);\n colorHelperTo.set(to);\n from = this.fromColor;\n to = this.toColor;\n from.r = colorHelperFrom.r;\n from.g = colorHelperFrom.g;\n from.b = colorHelperFrom.b;\n to.r = colorHelperTo.r;\n to.g = colorHelperTo.g;\n to.b = colorHelperTo.b;\n }\n});\n\n/**\n * Given property name, check schema to see what type we are animating.\n * We just care whether the property is a vector.\n */\nfunction getPropertyType(el, property) {\n var component;\n var componentName;\n var split;\n var propertyName;\n split = property.split('.');\n componentName = split[0];\n propertyName = split[1];\n component = el.components[componentName] || components[componentName];\n\n // Primitives.\n if (!component) {\n return null;\n }\n\n // Dynamic schema. We only care about vectors anyways.\n if (propertyName && !component.schema[propertyName]) {\n return null;\n }\n\n // Multi-prop.\n if (propertyName) {\n return component.schema[propertyName].type;\n }\n\n // Single-prop.\n return component.schema.type;\n}\n\n/**\n * Convert object to radians.\n */\nfunction toRadians(obj) {\n obj.x = THREE.MathUtils.degToRad(obj.x);\n obj.y = THREE.MathUtils.degToRad(obj.y);\n obj.z = THREE.MathUtils.degToRad(obj.z);\n}\nfunction addEventListeners(el, eventNames, handler) {\n var i;\n for (i = 0; i < eventNames.length; i++) {\n el.addEventListener(eventNames[i], handler);\n }\n}\nfunction removeEventListeners(el, eventNames, handler) {\n var i;\n for (i = 0; i < eventNames.length; i++) {\n el.removeEventListener(eventNames[i], handler);\n }\n}\nfunction getRawProperty(el, path) {\n var i;\n var split;\n var value;\n split = splitDot(path);\n value = el;\n for (i = 0; i < split.length; i++) {\n value = value[split[i]];\n }\n if (value === undefined) {\n console.log(el);\n throw new Error('[animation] property (' + path + ') could not be found');\n }\n return value;\n}\nfunction setRawProperty(el, path, value, type) {\n var i;\n var split;\n var propertyName;\n var targetValue;\n if (path.startsWith('object3D.rotation')) {\n value = THREE.MathUtils.degToRad(value);\n }\n\n // Walk.\n split = splitDot(path);\n targetValue = el;\n for (i = 0; i < split.length - 1; i++) {\n targetValue = targetValue[split[i]];\n }\n propertyName = split[split.length - 1];\n\n // Raw color.\n if (type === TYPE_COLOR) {\n if ('r' in targetValue[propertyName]) {\n targetValue[propertyName].r = value.r;\n targetValue[propertyName].g = value.g;\n targetValue[propertyName].b = value.b;\n } else {\n targetValue[propertyName].x = value.r;\n targetValue[propertyName].y = value.g;\n targetValue[propertyName].z = value.b;\n }\n return;\n }\n targetValue[propertyName] = value;\n}\nfunction splitDot(path) {\n if (path in splitCache) {\n return splitCache[path];\n }\n splitCache[path] = path.split('.');\n return splitCache[path];\n}\nfunction isRawProperty(data) {\n return data.isRawProperty || data.property.startsWith(STRING_COMPONENTS) || data.property.startsWith(STRING_OBJECT3D);\n}\n\n/***/ }),\n\n/***/ \"./src/components/camera.js\":\n/*!**********************************!*\\\n !*** ./src/components/camera.js ***!\n \\**********************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar THREE = __webpack_require__(/*! ../lib/three */ \"./src/lib/three.js\");\n\n/**\n * Camera component.\n * Pairs along with camera system to handle tracking the active camera.\n */\nmodule.exports.Component = registerComponent('camera', {\n schema: {\n active: {\n default: true\n },\n far: {\n default: 10000\n },\n fov: {\n default: 80,\n min: 0\n },\n near: {\n default: 0.005,\n min: 0\n },\n spectator: {\n default: false\n },\n zoom: {\n default: 1,\n min: 0\n }\n },\n /**\n * Initialize three.js camera and add it to the entity.\n * Add reference from scene to this entity as the camera.\n */\n init: function () {\n var camera;\n var el = this.el;\n\n // Create camera.\n camera = this.camera = new THREE.PerspectiveCamera();\n el.setObject3D('camera', camera);\n },\n /**\n * Update three.js camera.\n */\n update: function (oldData) {\n var data = this.data;\n var camera = this.camera;\n\n // Update properties.\n camera.aspect = data.aspect || window.innerWidth / window.innerHeight;\n camera.far = data.far;\n camera.fov = data.fov;\n camera.near = data.near;\n camera.zoom = data.zoom;\n camera.updateProjectionMatrix();\n this.updateActiveCamera(oldData);\n this.updateSpectatorCamera(oldData);\n },\n updateActiveCamera: function (oldData) {\n var data = this.data;\n var el = this.el;\n var system = this.system;\n // Active property did not change.\n if (oldData && oldData.active === data.active || data.spectator) {\n return;\n }\n\n // If `active` property changes, or first update, handle active camera with system.\n if (data.active && system.activeCameraEl !== el) {\n // Camera enabled. Set camera to this camera.\n system.setActiveCamera(el);\n } else if (!data.active && system.activeCameraEl === el) {\n // Camera disabled. Set camera to another camera.\n system.disableActiveCamera();\n }\n },\n updateSpectatorCamera: function (oldData) {\n var data = this.data;\n var el = this.el;\n var system = this.system;\n // spectator property did not change.\n if (oldData && oldData.spectator === data.spectator) {\n return;\n }\n\n // If `spectator` property changes, or first update, handle spectator camera with system.\n if (data.spectator && system.spectatorCameraEl !== el) {\n // Camera enabled. Set camera to this camera.\n system.setSpectatorCamera(el);\n } else if (!data.spectator && system.spectatorCameraEl === el) {\n // Camera disabled. Set camera to another camera.\n system.disableSpectatorCamera();\n }\n },\n /**\n * Remove camera on remove (callback).\n */\n remove: function () {\n this.el.removeObject3D('camera');\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/cursor.js\":\n/*!**********************************!*\\\n !*** ./src/components/cursor.js ***!\n \\**********************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\n/* global THREE, MouseEvent, TouchEvent */\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar utils = __webpack_require__(/*! ../utils/ */ \"./src/utils/index.js\");\nvar EVENTS = {\n CLICK: 'click',\n FUSING: 'fusing',\n MOUSEENTER: 'mouseenter',\n MOUSEDOWN: 'mousedown',\n MOUSELEAVE: 'mouseleave',\n MOUSEUP: 'mouseup'\n};\nvar STATES = {\n FUSING: 'cursor-fusing',\n HOVERING: 'cursor-hovering',\n HOVERED: 'cursor-hovered'\n};\nvar CANVAS_EVENTS = {\n DOWN: ['mousedown', 'touchstart'],\n UP: ['mouseup', 'touchend']\n};\nvar WEBXR_EVENTS = {\n DOWN: ['selectstart'],\n UP: ['selectend']\n};\nvar CANVAS_HOVER_CLASS = 'a-mouse-cursor-hover';\n\n/**\n * Cursor component. Applies the raycaster component specifically for starting the raycaster\n * from the camera and pointing from camera's facing direction, and then only returning the\n * closest intersection. Cursor can be fine-tuned by setting raycaster properties.\n *\n * @member {object} fuseTimeout - Timeout to trigger fuse-click.\n * @member {Element} cursorDownEl - Entity that was last mousedowned during current click.\n * @member {object} intersection - Attributes of the current intersection event, including\n * 3D- and 2D-space coordinates. See: http://threejs.org/docs/api/core/Raycaster.html\n * @member {Element} intersectedEl - Currently-intersected entity. Used to keep track to\n * emit events when unintersecting.\n */\nmodule.exports.Component = registerComponent('cursor', {\n dependencies: ['raycaster'],\n schema: {\n downEvents: {\n default: []\n },\n fuse: {\n default: utils.device.isMobile()\n },\n fuseTimeout: {\n default: 1500,\n min: 0\n },\n mouseCursorStylesEnabled: {\n default: true\n },\n upEvents: {\n default: []\n },\n rayOrigin: {\n default: 'entity',\n oneOf: ['mouse', 'entity', 'xrselect']\n }\n },\n after: ['tracked-controls'],\n multiple: true,\n init: function () {\n var self = this;\n this.fuseTimeout = undefined;\n this.cursorDownEl = null;\n this.intersectedEl = null;\n this.canvasBounds = document.body.getBoundingClientRect();\n this.isCursorDown = false;\n this.activeXRInput = null;\n\n // Debounce.\n this.updateCanvasBounds = utils.debounce(function updateCanvasBounds() {\n self.canvasBounds = self.el.sceneEl.canvas.getBoundingClientRect();\n }, 500);\n this.eventDetail = {};\n this.intersectedEventDetail = {\n cursorEl: this.el\n };\n\n // Bind methods.\n this.onCursorDown = this.onCursorDown.bind(this);\n this.onCursorUp = this.onCursorUp.bind(this);\n this.onIntersection = this.onIntersection.bind(this);\n this.onIntersectionCleared = this.onIntersectionCleared.bind(this);\n this.onMouseMove = this.onMouseMove.bind(this);\n this.onEnterVR = this.onEnterVR.bind(this);\n },\n update: function (oldData) {\n if (this.data.rayOrigin === oldData.rayOrigin) {\n return;\n }\n this.updateMouseEventListeners();\n },\n tick: function () {\n // Update on frame to allow someone to select and mousemove\n var frame = this.el.sceneEl.frame;\n var inputSource = this.activeXRInput;\n if (this.data.rayOrigin === 'xrselect' && frame && inputSource) {\n this.onMouseMove({\n frame: frame,\n inputSource: inputSource,\n type: 'fakeselectevent'\n });\n }\n },\n play: function () {\n this.addEventListeners();\n },\n pause: function () {\n this.removeEventListeners();\n },\n remove: function () {\n var el = this.el;\n el.removeState(STATES.HOVERING);\n el.removeState(STATES.FUSING);\n clearTimeout(this.fuseTimeout);\n if (this.intersectedEl) {\n this.intersectedEl.removeState(STATES.HOVERED);\n }\n this.removeEventListeners();\n },\n addEventListeners: function () {\n var canvas;\n var data = this.data;\n var el = this.el;\n var self = this;\n function addCanvasListeners() {\n canvas = el.sceneEl.canvas;\n if (data.downEvents.length || data.upEvents.length) {\n return;\n }\n CANVAS_EVENTS.DOWN.forEach(function (downEvent) {\n canvas.addEventListener(downEvent, self.onCursorDown, {\n passive: false\n });\n });\n CANVAS_EVENTS.UP.forEach(function (upEvent) {\n canvas.addEventListener(upEvent, self.onCursorUp, {\n passive: false\n });\n });\n }\n canvas = el.sceneEl.canvas;\n if (canvas) {\n addCanvasListeners();\n } else {\n el.sceneEl.addEventListener('render-target-loaded', addCanvasListeners);\n }\n data.downEvents.forEach(function (downEvent) {\n el.addEventListener(downEvent, self.onCursorDown);\n });\n data.upEvents.forEach(function (upEvent) {\n el.addEventListener(upEvent, self.onCursorUp);\n });\n el.addEventListener('raycaster-intersection', this.onIntersection);\n el.addEventListener('raycaster-closest-entity-changed', this.onIntersection);\n el.addEventListener('raycaster-intersection-cleared', this.onIntersectionCleared);\n el.sceneEl.addEventListener('rendererresize', this.updateCanvasBounds);\n el.sceneEl.addEventListener('enter-vr', this.onEnterVR);\n window.addEventListener('resize', this.updateCanvasBounds);\n window.addEventListener('scroll', this.updateCanvasBounds);\n this.updateMouseEventListeners();\n },\n removeEventListeners: function () {\n var canvas;\n var data = this.data;\n var el = this.el;\n var self = this;\n canvas = el.sceneEl.canvas;\n if (canvas && !data.downEvents.length && !data.upEvents.length) {\n CANVAS_EVENTS.DOWN.forEach(function (downEvent) {\n canvas.removeEventListener(downEvent, self.onCursorDown);\n });\n CANVAS_EVENTS.UP.forEach(function (upEvent) {\n canvas.removeEventListener(upEvent, self.onCursorUp);\n });\n }\n data.downEvents.forEach(function (downEvent) {\n el.removeEventListener(downEvent, self.onCursorDown);\n });\n data.upEvents.forEach(function (upEvent) {\n el.removeEventListener(upEvent, self.onCursorUp);\n });\n el.removeEventListener('raycaster-intersection', this.onIntersection);\n el.removeEventListener('raycaster-intersection-cleared', this.onIntersectionCleared);\n canvas.removeEventListener('mousemove', this.onMouseMove);\n canvas.removeEventListener('touchstart', this.onMouseMove);\n canvas.removeEventListener('touchmove', this.onMouseMove);\n el.sceneEl.removeEventListener('rendererresize', this.updateCanvasBounds);\n el.sceneEl.removeEventListener('enter-vr', this.onEnterVR);\n window.removeEventListener('resize', this.updateCanvasBounds);\n window.removeEventListener('scroll', this.updateCanvasBounds);\n },\n updateMouseEventListeners: function () {\n var canvas;\n var el = this.el;\n canvas = el.sceneEl.canvas;\n canvas.removeEventListener('mousemove', this.onMouseMove);\n canvas.removeEventListener('touchmove', this.onMouseMove);\n el.setAttribute('raycaster', 'useWorldCoordinates', false);\n if (this.data.rayOrigin !== 'mouse') {\n return;\n }\n canvas.addEventListener('mousemove', this.onMouseMove);\n canvas.addEventListener('touchmove', this.onMouseMove, {\n passive: false\n });\n el.setAttribute('raycaster', 'useWorldCoordinates', true);\n this.updateCanvasBounds();\n },\n onMouseMove: function () {\n var direction = new THREE.Vector3();\n var mouse = new THREE.Vector2();\n var origin = new THREE.Vector3();\n var rayCasterConfig = {\n origin: origin,\n direction: direction\n };\n return function (evt) {\n var bounds = this.canvasBounds;\n var camera = this.el.sceneEl.camera;\n var left;\n var point;\n var top;\n var frame;\n var inputSource;\n var referenceSpace;\n var pose;\n var transform;\n camera.parent.updateMatrixWorld();\n\n // Calculate mouse position based on the canvas element\n if (evt.type === 'touchmove' || evt.type === 'touchstart') {\n // Track the first touch for simplicity.\n point = evt.touches.item(0);\n } else {\n point = evt;\n }\n left = point.clientX - bounds.left;\n top = point.clientY - bounds.top;\n mouse.x = left / bounds.width * 2 - 1;\n mouse.y = -(top / bounds.height) * 2 + 1;\n if (this.data.rayOrigin === 'xrselect' && (evt.type === 'selectstart' || evt.type === 'fakeselectevent')) {\n frame = evt.frame;\n inputSource = evt.inputSource;\n referenceSpace = this.el.renderer.xr.getReferenceSpace();\n pose = frame.getPose(inputSource.targetRaySpace, referenceSpace);\n transform = pose.transform;\n direction.set(0, 0, -1);\n direction.applyQuaternion(transform.orientation);\n origin.copy(transform.position);\n } else if (evt.type === 'fakeselectout') {\n direction.set(0, 1, 0);\n origin.set(0, 9999, 0);\n } else if (camera && camera.isPerspectiveCamera) {\n origin.setFromMatrixPosition(camera.matrixWorld);\n direction.set(mouse.x, mouse.y, 0.5).unproject(camera).sub(origin).normalize();\n } else if (camera && camera.isOrthographicCamera) {\n origin.set(mouse.x, mouse.y, (camera.near + camera.far) / (camera.near - camera.far)).unproject(camera); // set origin in plane of camera\n direction.set(0, 0, -1).transformDirection(camera.matrixWorld);\n } else {\n console.error('AFRAME.Raycaster: Unsupported camera type: ' + camera.type);\n }\n this.el.setAttribute('raycaster', rayCasterConfig);\n if (evt.type === 'touchmove') {\n evt.preventDefault();\n }\n };\n }(),\n /**\n * Trigger mousedown and keep track of the mousedowned entity.\n */\n onCursorDown: function (evt) {\n this.isCursorDown = true;\n // Raycast again for touch.\n if (this.data.rayOrigin === 'mouse' && evt.type === 'touchstart') {\n this.onMouseMove(evt);\n this.el.components.raycaster.checkIntersections();\n evt.preventDefault();\n }\n if (this.data.rayOrigin === 'xrselect' && evt.type === 'selectstart') {\n this.activeXRInput = evt.inputSource;\n this.onMouseMove(evt);\n this.el.components.raycaster.checkIntersections();\n\n // if something was tapped on don't do ar-hit-test things\n if (this.el.components.raycaster.intersectedEls.length && this.el.sceneEl.components['ar-hit-test'] !== undefined && this.el.sceneEl.getAttribute('ar-hit-test').enabled) {\n // Cancel the ar-hit-test behaviours and disable the ar-hit-test\n this.el.sceneEl.setAttribute('ar-hit-test', 'enabled', false);\n this.reenableARHitTest = true;\n }\n }\n this.twoWayEmit(EVENTS.MOUSEDOWN, evt);\n this.cursorDownEl = this.intersectedEl;\n },\n /**\n * Trigger mouseup if:\n * - Not fusing (mobile has no mouse).\n * - Currently intersecting an entity.\n * - Currently-intersected entity is the same as the one when mousedown was triggered,\n * in case user mousedowned one entity, dragged to another, and mouseupped.\n */\n onCursorUp: function (evt) {\n if (!this.isCursorDown) {\n return;\n }\n this.isCursorDown = false;\n var data = this.data;\n this.twoWayEmit(EVENTS.MOUSEUP, evt);\n if (this.reenableARHitTest === true) {\n this.el.sceneEl.setAttribute('ar-hit-test', 'enabled', true);\n this.reenableARHitTest = undefined;\n }\n\n // If intersected entity has changed since the cursorDown, still emit mouseUp on the\n // previously cursorUp entity.\n if (this.cursorDownEl && this.cursorDownEl !== this.intersectedEl) {\n this.intersectedEventDetail.intersection = null;\n this.cursorDownEl.emit(EVENTS.MOUSEUP, this.intersectedEventDetail);\n }\n if ((!data.fuse || data.rayOrigin === 'mouse' || data.rayOrigin === 'xrselect') && this.intersectedEl && this.cursorDownEl === this.intersectedEl) {\n this.twoWayEmit(EVENTS.CLICK, evt);\n }\n\n // if the current xr input stops selecting then make the ray caster point somewhere else\n if (data.rayOrigin === 'xrselect' && this.activeXRInput === evt.inputSource) {\n this.onMouseMove({\n type: 'fakeselectout'\n });\n }\n this.activeXRInput = null;\n this.cursorDownEl = null;\n if (evt.type === 'touchend') {\n evt.preventDefault();\n }\n },\n /**\n * Handle intersection.\n */\n onIntersection: function (evt) {\n var currentIntersection;\n var cursorEl = this.el;\n var index;\n var intersectedEl;\n var intersection;\n\n // Select closest object, excluding the cursor.\n index = evt.detail.els[0] === cursorEl ? 1 : 0;\n intersection = evt.detail.intersections[index];\n intersectedEl = evt.detail.els[index];\n\n // If cursor is the only intersected object, ignore the event.\n if (!intersectedEl) {\n return;\n }\n\n // Already intersecting this entity.\n if (this.intersectedEl === intersectedEl) {\n return;\n }\n\n // Ignore events further away than active intersection.\n if (this.intersectedEl) {\n currentIntersection = this.el.components.raycaster.getIntersection(this.intersectedEl);\n if (currentIntersection && currentIntersection.distance <= intersection.distance) {\n return;\n }\n }\n\n // Unset current intersection.\n this.clearCurrentIntersection(true);\n this.setIntersection(intersectedEl, intersection);\n },\n /**\n * Handle intersection cleared.\n */\n onIntersectionCleared: function (evt) {\n var clearedEls = evt.detail.clearedEls;\n // Check if the current intersection has ended\n if (clearedEls.indexOf(this.intersectedEl) === -1) {\n return;\n }\n this.clearCurrentIntersection();\n },\n onEnterVR: function () {\n this.clearCurrentIntersection(true);\n var xrSession = this.el.sceneEl.xrSession;\n var self = this;\n if (!xrSession) {\n return;\n }\n if (this.data.rayOrigin === 'mouse') {\n return;\n }\n WEBXR_EVENTS.DOWN.forEach(function (downEvent) {\n xrSession.addEventListener(downEvent, self.onCursorDown);\n });\n WEBXR_EVENTS.UP.forEach(function (upEvent) {\n xrSession.addEventListener(upEvent, self.onCursorUp);\n });\n },\n setIntersection: function (intersectedEl, intersection) {\n var cursorEl = this.el;\n var data = this.data;\n var self = this;\n\n // Already intersecting.\n if (this.intersectedEl === intersectedEl) {\n return;\n }\n\n // Set new intersection.\n this.intersectedEl = intersectedEl;\n\n // Hovering.\n cursorEl.addState(STATES.HOVERING);\n intersectedEl.addState(STATES.HOVERED);\n this.twoWayEmit(EVENTS.MOUSEENTER);\n if (this.data.mouseCursorStylesEnabled && this.data.rayOrigin === 'mouse') {\n this.el.sceneEl.canvas.classList.add(CANVAS_HOVER_CLASS);\n }\n\n // Begin fuse if necessary.\n if (data.fuseTimeout === 0 || !data.fuse || data.rayOrigin === 'xrselect' || data.rayOrigin === 'mouse') {\n return;\n }\n cursorEl.addState(STATES.FUSING);\n this.twoWayEmit(EVENTS.FUSING);\n this.fuseTimeout = setTimeout(function fuse() {\n cursorEl.removeState(STATES.FUSING);\n self.twoWayEmit(EVENTS.CLICK);\n }, data.fuseTimeout);\n },\n clearCurrentIntersection: function (ignoreRemaining) {\n var index;\n var intersection;\n var intersections;\n var cursorEl = this.el;\n\n // Nothing to be cleared.\n if (!this.intersectedEl) {\n return;\n }\n\n // No longer hovering (or fusing).\n this.intersectedEl.removeState(STATES.HOVERED);\n cursorEl.removeState(STATES.HOVERING);\n cursorEl.removeState(STATES.FUSING);\n this.twoWayEmit(EVENTS.MOUSELEAVE);\n if (this.data.mouseCursorStylesEnabled && this.data.rayOrigin === 'mouse') {\n this.el.sceneEl.canvas.classList.remove(CANVAS_HOVER_CLASS);\n }\n\n // Unset intersected entity (after emitting the event).\n this.intersectedEl = null;\n\n // Clear fuseTimeout.\n clearTimeout(this.fuseTimeout);\n\n // Set intersection to another raycast element if any.\n if (ignoreRemaining === true) {\n return;\n }\n intersections = this.el.components.raycaster.intersections;\n if (intersections.length === 0) {\n return;\n }\n // Exclude the cursor.\n index = intersections[0].object.el === cursorEl ? 1 : 0;\n intersection = intersections[index];\n if (!intersection) {\n return;\n }\n this.setIntersection(intersection.object.el, intersection);\n },\n /**\n * Helper to emit on both the cursor and the intersected entity (if exists).\n */\n twoWayEmit: function (evtName, originalEvent) {\n var el = this.el;\n var intersectedEl = this.intersectedEl;\n var intersection;\n function addOriginalEvent(detail, evt) {\n if (originalEvent instanceof MouseEvent) {\n detail.mouseEvent = originalEvent;\n } else if (typeof TouchEvent !== 'undefined' && originalEvent instanceof TouchEvent) {\n detail.touchEvent = originalEvent;\n }\n }\n intersection = this.el.components.raycaster.getIntersection(intersectedEl);\n this.eventDetail.intersectedEl = intersectedEl;\n this.eventDetail.intersection = intersection;\n addOriginalEvent(this.eventDetail, originalEvent);\n el.emit(evtName, this.eventDetail);\n if (!intersectedEl) {\n return;\n }\n this.intersectedEventDetail.intersection = intersection;\n addOriginalEvent(this.intersectedEventDetail, originalEvent);\n intersectedEl.emit(evtName, this.intersectedEventDetail);\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/generic-tracked-controller-controls.js\":\n/*!***************************************************************!*\\\n !*** ./src/components/generic-tracked-controller-controls.js ***!\n \\***************************************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar trackedControlsUtils = __webpack_require__(/*! ../utils/tracked-controls */ \"./src/utils/tracked-controls.js\");\nvar checkControllerPresentAndSetup = trackedControlsUtils.checkControllerPresentAndSetup;\nvar emitIfAxesChanged = trackedControlsUtils.emitIfAxesChanged;\nvar onButtonEvent = trackedControlsUtils.onButtonEvent;\nvar GAMEPAD_ID_PREFIX = 'generic';\n\n/**\n * Button indices:\n * 0 - trigger\n * 1 - squeeze\n * 2 - touchpad\n * 3 - thumbstick\n *\n * Axis:\n * 0 - touchpad\n * 1 - thumbstick\n *\n */\nvar INPUT_MAPPING = {\n axes: {\n touchpad: [0, 1],\n thumbstick: [2, 3]\n },\n buttons: ['trigger', 'squeeze', 'touchpad', 'thumbstick']\n};\n\n/**\n * Oculus Go controls.\n * Interface with Oculus Go controller and map Gamepad events to\n * controller buttons: trackpad, trigger\n * Load a controller model and highlight the pressed buttons.\n */\nmodule.exports.Component = registerComponent('generic-tracked-controller-controls', {\n schema: {\n hand: {\n default: ''\n },\n // This informs the degenerate arm model.\n defaultModel: {\n default: true\n },\n defaultModelColor: {\n default: 'gray'\n },\n orientationOffset: {\n type: 'vec3'\n },\n disabled: {\n default: false\n }\n },\n after: ['tracked-controls'],\n /**\n * Button IDs:\n * 0 - trackpad\n * 1 - trigger\n */\n mapping: INPUT_MAPPING,\n bindMethods: function () {\n this.onControllersUpdate = this.onControllersUpdate.bind(this);\n this.checkIfControllerPresent = this.checkIfControllerPresent.bind(this);\n this.removeControllersUpdateListener = this.removeControllersUpdateListener.bind(this);\n this.onAxisMoved = this.onAxisMoved.bind(this);\n },\n init: function () {\n var self = this;\n this.onButtonChanged = this.onButtonChanged.bind(this);\n this.onButtonDown = function (evt) {\n onButtonEvent(evt.detail.id, 'down', self);\n };\n this.onButtonUp = function (evt) {\n onButtonEvent(evt.detail.id, 'up', self);\n };\n this.onButtonTouchStart = function (evt) {\n onButtonEvent(evt.detail.id, 'touchstart', self);\n };\n this.onButtonTouchEnd = function (evt) {\n onButtonEvent(evt.detail.id, 'touchend', self);\n };\n this.controllerPresent = false;\n this.wasControllerConnected = false;\n this.lastControllerCheck = 0;\n this.bindMethods();\n\n // generic-tracked-controller-controls has the lowest precedence.\n // Disable this component if there are more specialized controls components.\n this.el.addEventListener('controllerconnected', function (evt) {\n if (evt.detail.name === self.name) {\n return;\n }\n self.wasControllerConnected = true;\n self.removeEventListeners();\n self.removeControllersUpdateListener();\n });\n },\n addEventListeners: function () {\n var el = this.el;\n el.addEventListener('buttonchanged', this.onButtonChanged);\n el.addEventListener('buttondown', this.onButtonDown);\n el.addEventListener('buttonup', this.onButtonUp);\n el.addEventListener('touchstart', this.onButtonTouchStart);\n el.addEventListener('touchend', this.onButtonTouchEnd);\n el.addEventListener('axismove', this.onAxisMoved);\n this.controllerEventsActive = true;\n },\n removeEventListeners: function () {\n var el = this.el;\n el.removeEventListener('buttonchanged', this.onButtonChanged);\n el.removeEventListener('buttondown', this.onButtonDown);\n el.removeEventListener('buttonup', this.onButtonUp);\n el.removeEventListener('touchstart', this.onButtonTouchStart);\n el.removeEventListener('touchend', this.onButtonTouchEnd);\n el.removeEventListener('axismove', this.onAxisMoved);\n this.controllerEventsActive = false;\n },\n checkIfControllerPresent: function () {\n var data = this.data;\n var hand = data.hand ? data.hand : undefined;\n checkControllerPresentAndSetup(this, GAMEPAD_ID_PREFIX, {\n hand: hand,\n iterateControllerProfiles: true\n });\n },\n play: function () {\n if (this.wasControllerConnected) {\n return;\n }\n this.checkIfControllerPresent();\n this.addControllersUpdateListener();\n },\n pause: function () {\n this.removeEventListeners();\n this.removeControllersUpdateListener();\n },\n injectTrackedControls: function () {\n var el = this.el;\n var data = this.data;\n\n // Do nothing if tracked-controls already set.\n // Generic controls have the lowest precedence.\n if (this.el.components['tracked-controls']) {\n this.removeEventListeners();\n return;\n }\n el.setAttribute('tracked-controls', {\n hand: data.hand,\n idPrefix: GAMEPAD_ID_PREFIX,\n orientationOffset: data.orientationOffset,\n iterateControllerProfiles: true\n });\n if (!this.data.defaultModel) {\n return;\n }\n this.initDefaultModel();\n },\n addControllersUpdateListener: function () {\n this.el.sceneEl.addEventListener('controllersupdated', this.onControllersUpdate, false);\n },\n removeControllersUpdateListener: function () {\n this.el.sceneEl.removeEventListener('controllersupdated', this.onControllersUpdate, false);\n },\n onControllersUpdate: function () {\n if (!this.wasControllerConnected) {\n return;\n }\n this.checkIfControllerPresent();\n },\n onButtonChanged: function (evt) {\n var button = this.mapping.buttons[evt.detail.id];\n if (!button) return;\n // Pass along changed event with button state, using button mapping for convenience.\n this.el.emit(button + 'changed', evt.detail.state);\n },\n onAxisMoved: function (evt) {\n emitIfAxesChanged(this, this.mapping.axes, evt);\n },\n initDefaultModel: function () {\n var modelEl = this.modelEl = document.createElement('a-entity');\n modelEl.setAttribute('geometry', {\n primitive: 'sphere',\n radius: 0.03\n });\n modelEl.setAttribute('material', {\n color: this.data.color\n });\n this.el.appendChild(modelEl);\n this.el.emit('controllermodelready', {\n name: 'generic-tracked-controller-controls',\n model: this.modelEl,\n rayOrigin: {\n origin: {\n x: 0,\n y: 0,\n z: -0.01\n },\n direction: {\n x: 0,\n y: 0,\n z: -1\n }\n }\n });\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/geometry.js\":\n/*!************************************!*\\\n !*** ./src/components/geometry.js ***!\n \\************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar geometries = (__webpack_require__(/*! ../core/geometry */ \"./src/core/geometry.js\").geometries);\nvar geometryNames = (__webpack_require__(/*! ../core/geometry */ \"./src/core/geometry.js\").geometryNames);\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar THREE = __webpack_require__(/*! ../lib/three */ \"./src/lib/three.js\");\nvar dummyGeometry = new THREE.BufferGeometry();\n\n/**\n * Geometry component. Combined with material component to make a mesh in 3D object.\n * Extended with registered geometries.\n */\nmodule.exports.Component = registerComponent('geometry', {\n schema: {\n buffer: {\n default: true\n },\n primitive: {\n default: 'box',\n oneOf: geometryNames,\n schemaChange: true\n },\n skipCache: {\n default: false\n }\n },\n init: function () {\n this.geometry = null;\n },\n /**\n * Talk to geometry system to get or create geometry.\n */\n update: function (previousData) {\n var data = this.data;\n var el = this.el;\n var mesh;\n var system = this.system;\n\n // Dispose old geometry if we created one.\n if (this.geometry) {\n system.unuseGeometry(previousData);\n this.geometry = null;\n }\n\n // Create new geometry.\n this.geometry = system.getOrCreateGeometry(data);\n\n // Set on mesh. If mesh does not exist, create it.\n mesh = el.getObject3D('mesh');\n if (mesh) {\n mesh.geometry = this.geometry;\n } else {\n mesh = new THREE.Mesh();\n mesh.geometry = this.geometry;\n // Default material if not defined on the entity.\n if (!this.el.getAttribute('material')) {\n mesh.material = new THREE.MeshStandardMaterial({\n color: Math.random() * 0xFFFFFF,\n metalness: 0,\n roughness: 0.5\n });\n }\n el.setObject3D('mesh', mesh);\n }\n },\n /**\n * Tell geometry system that entity is no longer using the geometry.\n * Unset the geometry on the mesh\n */\n remove: function () {\n this.system.unuseGeometry(this.data);\n this.el.getObject3D('mesh').geometry = dummyGeometry;\n this.geometry = null;\n },\n /**\n * Update geometry component schema based on geometry type.\n */\n updateSchema: function (data) {\n var currentGeometryType = this.oldData && this.oldData.primitive;\n var newGeometryType = data.primitive;\n var schema = geometries[newGeometryType] && geometries[newGeometryType].schema;\n\n // Geometry has no schema.\n if (!schema) {\n throw new Error('Unknown geometry schema `' + newGeometryType + '`');\n }\n // Nothing has changed.\n if (currentGeometryType && currentGeometryType === newGeometryType) {\n return;\n }\n this.extendSchema(schema);\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/gltf-model.js\":\n/*!**************************************!*\\\n !*** ./src/components/gltf-model.js ***!\n \\**************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar THREE = __webpack_require__(/*! ../lib/three */ \"./src/lib/three.js\");\nvar utils = __webpack_require__(/*! ../utils/ */ \"./src/utils/index.js\");\nvar warn = utils.debug('components:gltf-model:warn');\n\n/**\n * glTF model loader.\n */\nmodule.exports.Component = registerComponent('gltf-model', {\n schema: {\n type: 'model'\n },\n init: function () {\n var self = this;\n var dracoLoader = this.system.getDRACOLoader();\n var meshoptDecoder = this.system.getMeshoptDecoder();\n var ktxLoader = this.system.getKTX2Loader();\n this.model = null;\n this.loader = new THREE.GLTFLoader();\n if (dracoLoader) {\n this.loader.setDRACOLoader(dracoLoader);\n }\n if (meshoptDecoder) {\n this.ready = meshoptDecoder.then(function (meshoptDecoder) {\n self.loader.setMeshoptDecoder(meshoptDecoder);\n });\n } else {\n this.ready = Promise.resolve();\n }\n if (ktxLoader) {\n this.loader.setKTX2Loader(ktxLoader);\n }\n },\n update: function () {\n var self = this;\n var el = this.el;\n var src = this.data;\n if (!src) {\n return;\n }\n this.remove();\n this.ready.then(function () {\n self.loader.load(src, function gltfLoaded(gltfModel) {\n self.model = gltfModel.scene || gltfModel.scenes[0];\n self.model.animations = gltfModel.animations;\n el.setObject3D('mesh', self.model);\n el.emit('model-loaded', {\n format: 'gltf',\n model: self.model\n });\n }, undefined /* onProgress */, function gltfFailed(error) {\n var message = error && error.message ? error.message : 'Failed to load glTF model';\n warn(message);\n el.emit('model-error', {\n format: 'gltf',\n src: src\n });\n });\n });\n },\n remove: function () {\n if (!this.model) {\n return;\n }\n this.el.removeObject3D('mesh');\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/grabbable.js\":\n/*!*************************************!*\\\n !*** ./src/components/grabbable.js ***!\n \\*************************************/\n/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {\n\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nregisterComponent('grabbable', {\n init: function () {\n this.el.setAttribute('obb-collider', 'centerModel: true');\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/hand-controls.js\":\n/*!*****************************************!*\\\n !*** ./src/components/hand-controls.js ***!\n \\*****************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\n/* global THREE */\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar AFRAME_CDN_ROOT = (__webpack_require__(/*! ../constants */ \"./src/constants/index.js\").AFRAME_CDN_ROOT);\n// Found at https://github.com/aframevr/assets.\nvar MODEL_URLS = {\n toonLeft: AFRAME_CDN_ROOT + 'controllers/hands/leftHand.glb',\n toonRight: AFRAME_CDN_ROOT + 'controllers/hands/rightHand.glb',\n lowPolyLeft: AFRAME_CDN_ROOT + 'controllers/hands/leftHandLow.glb',\n lowPolyRight: AFRAME_CDN_ROOT + 'controllers/hands/rightHandLow.glb',\n highPolyLeft: AFRAME_CDN_ROOT + 'controllers/hands/leftHandHigh.glb',\n highPolyRight: AFRAME_CDN_ROOT + 'controllers/hands/rightHandHigh.glb'\n};\n\n// Poses.\nvar ANIMATIONS = {\n open: 'Open',\n // point: grip active, trackpad surface active, trigger inactive.\n point: 'Point',\n // pointThumb: grip active, trigger inactive, trackpad surface inactive.\n pointThumb: 'Point + Thumb',\n // fist: grip active, trigger active, trackpad surface active.\n fist: 'Fist',\n // hold: trigger active, grip inactive.\n hold: 'Hold',\n // thumbUp: grip active, trigger active, trackpad surface inactive.\n thumbUp: 'Thumb Up'\n};\n\n// Map animation to public events for the API.\nvar EVENTS = {};\nEVENTS[ANIMATIONS.fist] = 'grip';\nEVENTS[ANIMATIONS.thumbUp] = 'pistol';\nEVENTS[ANIMATIONS.point] = 'pointing';\n\n/**\n * Hand controls component that abstracts 6DoF controls:\n * oculus-touch-controls, vive-controls, windows-motion-controls.\n *\n * Originally meant to be a sample implementation of applications-specific controls that\n * abstracts multiple types of controllers.\n *\n * Auto-detect appropriate controller.\n * Handle common events coming from the detected vendor-specific controls.\n * Translate button events to semantic hand-related event names:\n * (gripclose, gripopen, thumbup, thumbdown, pointup, pointdown)\n * Load hand model with gestures that are applied based on the button pressed.\n *\n * @property {string} Hand mapping (`left`, `right`).\n */\nmodule.exports.Component = registerComponent('hand-controls', {\n schema: {\n color: {\n default: 'white',\n type: 'color'\n },\n hand: {\n default: 'left'\n },\n handModelStyle: {\n default: 'lowPoly',\n oneOf: ['lowPoly', 'highPoly', 'toon']\n }\n },\n after: ['tracked-controls'],\n init: function () {\n var self = this;\n var el = this.el;\n // Active buttons populated by events provided by the attached controls.\n this.pressedButtons = {};\n this.touchedButtons = {};\n this.loader = new THREE.GLTFLoader();\n this.loader.setCrossOrigin('anonymous');\n this.onGripDown = function () {\n self.handleButton('grip', 'down');\n };\n this.onGripUp = function () {\n self.handleButton('grip', 'up');\n };\n this.onTrackpadDown = function () {\n self.handleButton('trackpad', 'down');\n };\n this.onTrackpadUp = function () {\n self.handleButton('trackpad', 'up');\n };\n this.onTrackpadTouchStart = function () {\n self.handleButton('trackpad', 'touchstart');\n };\n this.onTrackpadTouchEnd = function () {\n self.handleButton('trackpad', 'touchend');\n };\n this.onTriggerDown = function () {\n self.handleButton('trigger', 'down');\n };\n this.onTriggerUp = function () {\n self.handleButton('trigger', 'up');\n };\n this.onTriggerTouchStart = function () {\n self.handleButton('trigger', 'touchstart');\n };\n this.onTriggerTouchEnd = function () {\n self.handleButton('trigger', 'touchend');\n };\n this.onGripTouchStart = function () {\n self.handleButton('grip', 'touchstart');\n };\n this.onGripTouchEnd = function () {\n self.handleButton('grip', 'touchend');\n };\n this.onThumbstickDown = function () {\n self.handleButton('thumbstick', 'down');\n };\n this.onThumbstickUp = function () {\n self.handleButton('thumbstick', 'up');\n };\n this.onAorXTouchStart = function () {\n self.handleButton('AorX', 'touchstart');\n };\n this.onAorXTouchEnd = function () {\n self.handleButton('AorX', 'touchend');\n };\n this.onBorYTouchStart = function () {\n self.handleButton('BorY', 'touchstart');\n };\n this.onBorYTouchEnd = function () {\n self.handleButton('BorY', 'touchend');\n };\n this.onSurfaceTouchStart = function () {\n self.handleButton('surface', 'touchstart');\n };\n this.onSurfaceTouchEnd = function () {\n self.handleButton('surface', 'touchend');\n };\n this.onControllerConnected = this.onControllerConnected.bind(this);\n this.onControllerDisconnected = this.onControllerDisconnected.bind(this);\n el.addEventListener('controllerconnected', this.onControllerConnected);\n el.addEventListener('controllerdisconnected', this.onControllerDisconnected);\n\n // Hidden by default.\n el.object3D.visible = false;\n },\n play: function () {\n this.addEventListeners();\n },\n pause: function () {\n this.removeEventListeners();\n },\n tick: function (time, delta) {\n var mesh = this.el.getObject3D('mesh');\n if (!mesh || !mesh.mixer) {\n return;\n }\n mesh.mixer.update(delta / 1000);\n },\n onControllerConnected: function () {\n this.el.object3D.visible = true;\n },\n onControllerDisconnected: function () {\n this.el.object3D.visible = false;\n },\n addEventListeners: function () {\n var el = this.el;\n el.addEventListener('gripdown', this.onGripDown);\n el.addEventListener('gripup', this.onGripUp);\n el.addEventListener('trackpaddown', this.onTrackpadDown);\n el.addEventListener('trackpadup', this.onTrackpadUp);\n el.addEventListener('trackpadtouchstart', this.onTrackpadTouchStart);\n el.addEventListener('trackpadtouchend', this.onTrackpadTouchEnd);\n el.addEventListener('triggerdown', this.onTriggerDown);\n el.addEventListener('triggerup', this.onTriggerUp);\n el.addEventListener('triggertouchstart', this.onTriggerTouchStart);\n el.addEventListener('triggertouchend', this.onTriggerTouchEnd);\n el.addEventListener('griptouchstart', this.onGripTouchStart);\n el.addEventListener('griptouchend', this.onGripTouchEnd);\n el.addEventListener('thumbstickdown', this.onThumbstickDown);\n el.addEventListener('thumbstickup', this.onThumbstickUp);\n el.addEventListener('abuttontouchstart', this.onAorXTouchStart);\n el.addEventListener('abuttontouchend', this.onAorXTouchEnd);\n el.addEventListener('bbuttontouchstart', this.onBorYTouchStart);\n el.addEventListener('bbuttontouchend', this.onBorYTouchEnd);\n el.addEventListener('xbuttontouchstart', this.onAorXTouchStart);\n el.addEventListener('xbuttontouchend', this.onAorXTouchEnd);\n el.addEventListener('ybuttontouchstart', this.onBorYTouchStart);\n el.addEventListener('ybuttontouchend', this.onBorYTouchEnd);\n el.addEventListener('surfacetouchstart', this.onSurfaceTouchStart);\n el.addEventListener('surfacetouchend', this.onSurfaceTouchEnd);\n },\n removeEventListeners: function () {\n var el = this.el;\n el.removeEventListener('gripdown', this.onGripDown);\n el.removeEventListener('gripup', this.onGripUp);\n el.removeEventListener('trackpaddown', this.onTrackpadDown);\n el.removeEventListener('trackpadup', this.onTrackpadUp);\n el.removeEventListener('trackpadtouchstart', this.onTrackpadTouchStart);\n el.removeEventListener('trackpadtouchend', this.onTrackpadTouchEnd);\n el.removeEventListener('triggerdown', this.onTriggerDown);\n el.removeEventListener('triggerup', this.onTriggerUp);\n el.removeEventListener('triggertouchstart', this.onTriggerTouchStart);\n el.removeEventListener('triggertouchend', this.onTriggerTouchEnd);\n el.removeEventListener('griptouchstart', this.onGripTouchStart);\n el.removeEventListener('griptouchend', this.onGripTouchEnd);\n el.removeEventListener('thumbstickdown', this.onThumbstickDown);\n el.removeEventListener('thumbstickup', this.onThumbstickUp);\n el.removeEventListener('abuttontouchstart', this.onAorXTouchStart);\n el.removeEventListener('abuttontouchend', this.onAorXTouchEnd);\n el.removeEventListener('bbuttontouchstart', this.onBorYTouchStart);\n el.removeEventListener('bbuttontouchend', this.onBorYTouchEnd);\n el.removeEventListener('xbuttontouchstart', this.onAorXTouchStart);\n el.removeEventListener('xbuttontouchend', this.onAorXTouchEnd);\n el.removeEventListener('ybuttontouchstart', this.onBorYTouchStart);\n el.removeEventListener('ybuttontouchend', this.onBorYTouchEnd);\n el.removeEventListener('surfacetouchstart', this.onSurfaceTouchStart);\n el.removeEventListener('surfacetouchend', this.onSurfaceTouchEnd);\n },\n /**\n * Update handler. More like the `init` handler since the only property is the hand, and\n * that won't be changing much.\n */\n update: function (previousHand) {\n var controlConfiguration;\n var el = this.el;\n var hand = this.data.hand;\n var handModelStyle = this.data.handModelStyle;\n var handColor = this.data.color;\n var self = this;\n\n // Get common configuration to abstract different vendor controls.\n controlConfiguration = {\n hand: hand,\n model: false\n };\n\n // Set model.\n if (hand !== previousHand) {\n var handmodelUrl = MODEL_URLS[handModelStyle + hand.charAt(0).toUpperCase() + hand.slice(1)];\n this.loader.load(handmodelUrl, function (gltf) {\n var mesh = gltf.scene.children[0];\n var handModelOrientationZ = hand === 'left' ? Math.PI / 2 : -Math.PI / 2;\n // The WebXR standard defines the grip space such that a cylinder held in a closed hand points\n // along the Z axis. The models currently have such a cylinder point along the X-Axis.\n var handModelOrientationX = el.sceneEl.hasWebXR ? -Math.PI / 2 : 0;\n mesh.mixer = new THREE.AnimationMixer(mesh);\n self.clips = gltf.animations;\n el.setObject3D('mesh', mesh);\n mesh.traverse(function (object) {\n if (!object.isMesh) {\n return;\n }\n object.material.color = new THREE.Color(handColor);\n });\n mesh.position.set(0, 0, 0);\n mesh.rotation.set(handModelOrientationX, 0, handModelOrientationZ);\n el.setAttribute('magicleap-controls', controlConfiguration);\n el.setAttribute('vive-controls', controlConfiguration);\n el.setAttribute('oculus-touch-controls', controlConfiguration);\n el.setAttribute('pico-controls', controlConfiguration);\n el.setAttribute('windows-motion-controls', controlConfiguration);\n el.setAttribute('hp-mixed-reality-controls', controlConfiguration);\n });\n }\n },\n remove: function () {\n this.el.removeObject3D('mesh');\n },\n /**\n * Play model animation, based on which button was pressed and which kind of event.\n *\n * 1. Process buttons.\n * 2. Determine gesture (this.determineGesture()).\n * 3. Animation gesture (this.animationGesture()).\n * 4. Emit gesture events (this.emitGestureEvents()).\n *\n * @param {string} button - Name of the button.\n * @param {string} evt - Type of event for the button (i.e., down/up/touchstart/touchend).\n */\n handleButton: function (button, evt) {\n var lastGesture;\n var isPressed = evt === 'down';\n var isTouched = evt === 'touchstart';\n\n // Update objects.\n if (evt.indexOf('touch') === 0) {\n // Update touch object.\n if (isTouched === this.touchedButtons[button]) {\n return;\n }\n this.touchedButtons[button] = isTouched;\n } else {\n // Update button object.\n if (isPressed === this.pressedButtons[button]) {\n return;\n }\n this.pressedButtons[button] = isPressed;\n }\n\n // Determine the gesture.\n lastGesture = this.gesture;\n this.gesture = this.determineGesture();\n\n // Same gesture.\n if (this.gesture === lastGesture) {\n return;\n }\n // Animate gesture.\n this.animateGesture(this.gesture, lastGesture);\n\n // Emit events.\n this.emitGestureEvents(this.gesture, lastGesture);\n },\n /**\n * Determine which pose hand should be in considering active and touched buttons.\n */\n determineGesture: function () {\n var gesture;\n var isGripActive = this.pressedButtons.grip;\n var isSurfaceActive = this.pressedButtons.surface || this.touchedButtons.surface;\n var isTrackpadActive = this.pressedButtons.trackpad || this.touchedButtons.trackpad;\n var isTriggerActive = this.pressedButtons.trigger || this.touchedButtons.trigger;\n var isABXYActive = this.touchedButtons.AorX || this.touchedButtons.BorY;\n var isVive = isViveController(this.el.components['tracked-controls']);\n\n // Works well with Oculus Touch and Windows Motion Controls, but Vive needs tweaks.\n if (isVive) {\n if (isGripActive || isTriggerActive) {\n gesture = ANIMATIONS.fist;\n } else if (isTrackpadActive) {\n gesture = ANIMATIONS.point;\n }\n } else {\n if (isGripActive) {\n if (isSurfaceActive || isABXYActive || isTrackpadActive) {\n gesture = isTriggerActive ? ANIMATIONS.fist : ANIMATIONS.point;\n } else {\n gesture = isTriggerActive ? ANIMATIONS.thumbUp : ANIMATIONS.pointThumb;\n }\n } else if (isTriggerActive) {\n gesture = ANIMATIONS.hold;\n }\n }\n return gesture;\n },\n /**\n * Play corresponding clip to a gesture\n */\n getClip: function (gesture) {\n var clip;\n var i;\n for (i = 0; i < this.clips.length; i++) {\n clip = this.clips[i];\n if (clip.name !== gesture) {\n continue;\n }\n return clip;\n }\n },\n /**\n * Play gesture animation.\n *\n * @param {string} gesture - Which pose to animate to. If absent, then animate to open.\n * @param {string} lastGesture - Previous gesture, to reverse back to open if needed.\n */\n animateGesture: function (gesture, lastGesture) {\n if (gesture) {\n this.playAnimation(gesture || ANIMATIONS.open, lastGesture, false);\n return;\n }\n\n // If no gesture, then reverse the current gesture back to open pose.\n this.playAnimation(lastGesture, lastGesture, true);\n },\n /**\n * Emit `hand-controls`-specific events.\n */\n emitGestureEvents: function (gesture, lastGesture) {\n var el = this.el;\n var eventName;\n if (lastGesture === gesture) {\n return;\n }\n\n // Emit event for lastGesture not inactive.\n eventName = getGestureEventName(lastGesture, false);\n if (eventName) {\n el.emit(eventName);\n }\n\n // Emit event for current gesture now active.\n eventName = getGestureEventName(gesture, true);\n if (eventName) {\n el.emit(eventName);\n }\n },\n /**\n * Play hand animation based on button state.\n *\n * @param {string} gesture - Name of the animation as specified by the model.\n * @param {string} lastGesture - Previous pose.\n * @param {boolean} reverse - Whether animation should play in reverse.\n */\n playAnimation: function (gesture, lastGesture, reverse) {\n var clip;\n var fromAction;\n var mesh = this.el.getObject3D('mesh');\n var toAction;\n if (!mesh) {\n return;\n }\n\n // Grab clip action.\n clip = this.getClip(gesture);\n toAction = mesh.mixer.clipAction(clip);\n\n // Reverse from gesture to no gesture.\n if (reverse) {\n toAction.paused = false;\n toAction.timeScale = -1;\n return;\n }\n toAction.clampWhenFinished = true;\n toAction.loop = THREE.LoopOnce;\n toAction.repetitions = 0;\n toAction.timeScale = 1;\n toAction.time = 0;\n toAction.weight = 1;\n\n // No gesture to gesture.\n if (!lastGesture) {\n // Play animation.\n mesh.mixer.stopAllAction();\n toAction.play();\n return;\n }\n\n // Animate or crossfade from gesture to gesture.\n clip = this.getClip(lastGesture);\n toAction.reset();\n toAction.play();\n fromAction = mesh.mixer.clipAction(clip);\n fromAction.crossFadeTo(toAction, 0.15, true);\n }\n});\n\n/**\n * Suffix gestures based on toggle state (e.g., open/close, up/down, start/end).\n *\n * @param {string} gesture\n * @param {boolean} active\n */\nfunction getGestureEventName(gesture, active) {\n var eventName;\n if (!gesture) {\n return;\n }\n eventName = EVENTS[gesture];\n if (eventName === 'grip') {\n return eventName + (active ? 'close' : 'open');\n }\n if (eventName === 'point') {\n return eventName + (active ? 'up' : 'down');\n }\n if (eventName === 'pointing' || eventName === 'pistol') {\n return eventName + (active ? 'start' : 'end');\n }\n}\nfunction isViveController(trackedControls) {\n var controller = trackedControls && trackedControls.controller;\n var isVive = controller && (controller.id && controller.id.indexOf('OpenVR ') === 0 || controller.profiles && controller.profiles[0] && controller.profiles[0] === 'htc-vive');\n return isVive;\n}\n\n/***/ }),\n\n/***/ \"./src/components/hand-tracking-controls.js\":\n/*!**************************************************!*\\\n !*** ./src/components/hand-tracking-controls.js ***!\n \\**************************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\n/* global THREE, XRHand */\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar AEntity = (__webpack_require__(/*! ../core/a-entity */ \"./src/core/a-entity.js\").AEntity);\nvar trackedControlsUtils = __webpack_require__(/*! ../utils/tracked-controls */ \"./src/utils/tracked-controls.js\");\nvar checkControllerPresentAndSetup = trackedControlsUtils.checkControllerPresentAndSetup;\nvar AFRAME_CDN_ROOT = (__webpack_require__(/*! ../constants */ \"./src/constants/index.js\").AFRAME_CDN_ROOT);\nvar LEFT_HAND_MODEL_URL = AFRAME_CDN_ROOT + 'controllers/oculus-hands/v4/left.glb';\nvar RIGHT_HAND_MODEL_URL = AFRAME_CDN_ROOT + 'controllers/oculus-hands/v4/right.glb';\nvar JOINTS = ['wrist', 'thumb-metacarpal', 'thumb-phalanx-proximal', 'thumb-phalanx-distal', 'thumb-tip', 'index-finger-metacarpal', 'index-finger-phalanx-proximal', 'index-finger-phalanx-intermediate', 'index-finger-phalanx-distal', 'index-finger-tip', 'middle-finger-metacarpal', 'middle-finger-phalanx-proximal', 'middle-finger-phalanx-intermediate', 'middle-finger-phalanx-distal', 'middle-finger-tip', 'ring-finger-metacarpal', 'ring-finger-phalanx-proximal', 'ring-finger-phalanx-intermediate', 'ring-finger-phalanx-distal', 'ring-finger-tip', 'pinky-finger-metacarpal', 'pinky-finger-phalanx-proximal', 'pinky-finger-phalanx-intermediate', 'pinky-finger-phalanx-distal', 'pinky-finger-tip'];\nvar WRIST_INDEX = 0;\nvar THUMB_TIP_INDEX = 4;\nvar INDEX_TIP_INDEX = 9;\nvar PINCH_START_DISTANCE = 0.015;\nvar PINCH_END_PERCENTAGE = 0.1;\n\n/**\n * Controls for hand tracking\n */\nmodule.exports.Component = registerComponent('hand-tracking-controls', {\n schema: {\n hand: {\n default: 'right',\n oneOf: ['left', 'right']\n },\n modelStyle: {\n default: 'mesh',\n oneOf: ['dots', 'mesh']\n },\n modelColor: {\n default: 'white'\n },\n modelOpacity: {\n default: 1.0\n }\n },\n after: ['tracked-controls'],\n bindMethods: function () {\n this.onControllersUpdate = this.onControllersUpdate.bind(this);\n this.checkIfControllerPresent = this.checkIfControllerPresent.bind(this);\n this.removeControllersUpdateListener = this.removeControllersUpdateListener.bind(this);\n },\n addEventListeners: function () {\n this.el.addEventListener('model-loaded', this.onModelLoaded);\n for (var i = 0; i < this.jointEls.length; ++i) {\n this.jointEls[i].object3D.visible = true;\n }\n },\n removeEventListeners: function () {\n this.el.removeEventListener('model-loaded', this.onModelLoaded);\n for (var i = 0; i < this.jointEls.length; ++i) {\n this.jointEls[i].object3D.visible = false;\n }\n },\n init: function () {\n var sceneEl = this.el.sceneEl;\n var webxrData = sceneEl.getAttribute('webxr');\n var optionalFeaturesArray = webxrData.optionalFeatures;\n if (optionalFeaturesArray.indexOf('hand-tracking') === -1) {\n optionalFeaturesArray.push('hand-tracking');\n sceneEl.setAttribute('webxr', webxrData);\n }\n this.wristObject3D = new THREE.Object3D();\n this.el.sceneEl.object3D.add(this.wristObject3D);\n this.onModelLoaded = this.onModelLoaded.bind(this);\n this.onChildAttached = this.onChildAttached.bind(this);\n this.jointEls = [];\n this.controllerPresent = false;\n this.isPinched = false;\n this.pinchEventDetail = {\n position: new THREE.Vector3(),\n wristRotation: new THREE.Quaternion()\n };\n this.indexTipPosition = new THREE.Vector3();\n this.hasPoses = false;\n this.jointPoses = new Float32Array(16 * JOINTS.length);\n this.jointRadii = new Float32Array(JOINTS.length);\n this.bindMethods();\n this.updateReferenceSpace = this.updateReferenceSpace.bind(this);\n this.el.sceneEl.addEventListener('enter-vr', this.updateReferenceSpace);\n this.el.sceneEl.addEventListener('exit-vr', this.updateReferenceSpace);\n this.el.addEventListener('child-attached', this.onChildAttached);\n this.el.object3D.visible = false;\n this.wristObject3D.visible = false;\n },\n onChildAttached: function (evt) {\n this.addChildEntity(evt.detail.el);\n },\n update: function () {\n this.updateModelMaterial();\n },\n updateModelMaterial: function () {\n var jointEls = this.jointEls;\n var skinnedMesh = this.skinnedMesh;\n var transparent = !(this.data.modelOpacity === 1.0);\n if (skinnedMesh) {\n this.skinnedMesh.material.color.set(this.data.modelColor);\n this.skinnedMesh.material.transparent = transparent;\n this.skinnedMesh.material.opacity = this.data.modelOpacity;\n }\n for (var i = 0; i < jointEls.length; i++) {\n jointEls[i].setAttribute('material', {\n color: this.data.modelColor,\n transparent: transparent,\n opacity: this.data.modelOpacity\n });\n }\n },\n updateReferenceSpace: function () {\n var self = this;\n var xrSession = this.el.sceneEl.xrSession;\n this.referenceSpace = undefined;\n if (!xrSession) {\n return;\n }\n var referenceSpaceType = self.el.sceneEl.systems.webxr.sessionReferenceSpaceType;\n xrSession.requestReferenceSpace(referenceSpaceType).then(function (referenceSpace) {\n self.referenceSpace = referenceSpace;\n }).catch(function (error) {\n self.el.sceneEl.systems.webxr.warnIfFeatureNotRequested(referenceSpaceType, 'tracked-controls-webxr uses reference space ' + referenceSpaceType);\n throw error;\n });\n },\n checkIfControllerPresent: function () {\n var data = this.data;\n var hand = data.hand ? data.hand : undefined;\n checkControllerPresentAndSetup(this, '', {\n hand: hand,\n iterateControllerProfiles: true,\n handTracking: true\n });\n },\n play: function () {\n this.checkIfControllerPresent();\n this.addControllersUpdateListener();\n },\n tick: function () {\n var sceneEl = this.el.sceneEl;\n var controller = this.el.components['tracked-controls'] && this.el.components['tracked-controls'].controller;\n var frame = sceneEl.frame;\n var trackedControlsWebXR = this.el.components['tracked-controls-webxr'];\n var referenceSpace = this.referenceSpace;\n if (!controller || !frame || !referenceSpace || !trackedControlsWebXR) {\n return;\n }\n this.hasPoses = false;\n if (controller.hand) {\n this.el.object3D.position.set(0, 0, 0);\n this.el.object3D.rotation.set(0, 0, 0);\n this.hasPoses = frame.fillPoses(controller.hand.values(), referenceSpace, this.jointPoses) && frame.fillJointRadii(controller.hand.values(), this.jointRadii);\n this.updateHandModel();\n this.detectGesture();\n this.updateWristObject();\n }\n },\n updateWristObject: function () {\n var jointPose = new THREE.Matrix4();\n return function () {\n var wristObject3D = this.wristObject3D;\n if (!wristObject3D || !this.hasPoses) {\n return;\n }\n jointPose.fromArray(this.jointPoses, WRIST_INDEX * 16);\n wristObject3D.position.setFromMatrixPosition(jointPose);\n wristObject3D.quaternion.setFromRotationMatrix(jointPose);\n };\n }(),\n updateHandModel: function () {\n if (this.data.modelStyle === 'dots') {\n this.updateHandDotsModel();\n }\n if (this.data.modelStyle === 'mesh') {\n this.updateHandMeshModel();\n }\n },\n getBone: function (name) {\n var bones = this.bones;\n for (var i = 0; i < bones.length; i++) {\n if (bones[i].name === name) {\n return bones[i];\n }\n }\n return null;\n },\n updateHandMeshModel: function () {\n var jointPose = new THREE.Matrix4();\n return function () {\n var i = 0;\n var jointPoses = this.jointPoses;\n var controller = this.el.components['tracked-controls'] && this.el.components['tracked-controls'].controller;\n if (!controller || !this.mesh) {\n return;\n }\n this.mesh.visible = false;\n if (!this.hasPoses) {\n return;\n }\n for (var inputjoint of controller.hand.values()) {\n var bone = this.getBone(inputjoint.jointName);\n if (bone != null) {\n this.mesh.visible = true;\n jointPose.fromArray(jointPoses, i * 16);\n bone.position.setFromMatrixPosition(jointPose);\n bone.quaternion.setFromRotationMatrix(jointPose);\n }\n i++;\n }\n };\n }(),\n updateHandDotsModel: function () {\n var jointPoses = this.jointPoses;\n var jointRadii = this.jointRadii;\n var controller = this.el.components['tracked-controls'] && this.el.components['tracked-controls'].controller;\n var jointEl;\n var object3D;\n for (var i = 0; i < controller.hand.size; i++) {\n jointEl = this.jointEls[i];\n object3D = jointEl.object3D;\n jointEl.object3D.visible = this.hasPoses;\n if (!this.hasPoses) {\n continue;\n }\n object3D.matrix.fromArray(jointPoses, i * 16);\n object3D.matrix.decompose(object3D.position, object3D.rotation, object3D.scale);\n jointEl.setAttribute('scale', {\n x: jointRadii[i],\n y: jointRadii[i],\n z: jointRadii[i]\n });\n }\n },\n detectGesture: function () {\n this.detectPinch();\n },\n detectPinch: function () {\n var thumbTipPosition = new THREE.Vector3();\n var jointPose = new THREE.Matrix4();\n return function () {\n var indexTipPosition = this.indexTipPosition;\n var pinchEventDetail = this.pinchEventDetail;\n if (!this.hasPoses) {\n return;\n }\n thumbTipPosition.setFromMatrixPosition(jointPose.fromArray(this.jointPoses, THUMB_TIP_INDEX * 16));\n indexTipPosition.setFromMatrixPosition(jointPose.fromArray(this.jointPoses, INDEX_TIP_INDEX * 16));\n pinchEventDetail.wristRotation.setFromRotationMatrix(jointPose.fromArray(this.jointPoses, WRIST_INDEX * 16));\n var distance = indexTipPosition.distanceTo(thumbTipPosition);\n if (distance < PINCH_START_DISTANCE && this.isPinched === false) {\n this.isPinched = true;\n this.pinchDistance = distance;\n pinchEventDetail.position.copy(indexTipPosition).add(thumbTipPosition).multiplyScalar(0.5);\n this.el.emit('pinchstarted', pinchEventDetail);\n }\n if (distance > this.pinchDistance + this.pinchDistance * PINCH_END_PERCENTAGE && this.isPinched === true) {\n this.isPinched = false;\n pinchEventDetail.position.copy(indexTipPosition).add(thumbTipPosition).multiplyScalar(0.5);\n this.el.emit('pinchended', pinchEventDetail);\n }\n if (this.isPinched) {\n pinchEventDetail.position.copy(indexTipPosition).add(thumbTipPosition).multiplyScalar(0.5);\n this.el.emit('pinchmoved', pinchEventDetail);\n }\n };\n }(),\n pause: function () {\n this.removeEventListeners();\n this.removeControllersUpdateListener();\n },\n injectTrackedControls: function () {\n var el = this.el;\n var data = this.data;\n el.setAttribute('tracked-controls', {\n id: '',\n hand: data.hand,\n iterateControllerProfiles: true,\n handTrackingEnabled: true\n });\n if (this.mesh) {\n if (this.mesh !== el.getObject3D('mesh')) {\n el.setObject3D('mesh', this.mesh);\n }\n return;\n }\n this.initDefaultModel();\n },\n addControllersUpdateListener: function () {\n this.el.sceneEl.addEventListener('controllersupdated', this.onControllersUpdate, false);\n },\n removeControllersUpdateListener: function () {\n this.el.sceneEl.removeEventListener('controllersupdated', this.onControllersUpdate, false);\n },\n onControllersUpdate: function () {\n var el = this.el;\n var controller;\n this.checkIfControllerPresent();\n controller = el.components['tracked-controls'] && el.components['tracked-controls'].controller;\n if (!this.mesh) {\n return;\n }\n if (controller && controller.hand && controller.hand instanceof XRHand) {\n el.setObject3D('mesh', this.mesh);\n }\n },\n initDefaultModel: function () {\n var data = this.data;\n if (data.modelStyle === 'dots') {\n this.initDotsModel();\n }\n if (data.modelStyle === 'mesh') {\n this.initMeshHandModel();\n }\n this.el.object3D.visible = true;\n this.wristObject3D.visible = true;\n },\n initDotsModel: function () {\n // Add models just once.\n if (this.jointEls.length !== 0) {\n return;\n }\n for (var i = 0; i < JOINTS.length; ++i) {\n var jointEl = this.jointEl = document.createElement('a-entity');\n jointEl.setAttribute('geometry', {\n primitive: 'sphere',\n radius: 1.0\n });\n jointEl.object3D.visible = false;\n this.el.appendChild(jointEl);\n this.jointEls.push(jointEl);\n }\n this.updateModelMaterial();\n },\n initMeshHandModel: function () {\n var modelURL = this.data.hand === 'left' ? LEFT_HAND_MODEL_URL : RIGHT_HAND_MODEL_URL;\n this.el.setAttribute('gltf-model', modelURL);\n },\n onModelLoaded: function () {\n var mesh = this.mesh = this.el.getObject3D('mesh').children[0];\n var skinnedMesh = this.skinnedMesh = mesh.getObjectByProperty('type', 'SkinnedMesh');\n if (!this.skinnedMesh) {\n return;\n }\n this.bones = skinnedMesh.skeleton.bones;\n this.el.removeObject3D('mesh');\n mesh.position.set(0, 0, 0);\n mesh.rotation.set(0, 0, 0);\n skinnedMesh.frustumCulled = false;\n skinnedMesh.material = new THREE.MeshStandardMaterial();\n this.updateModelMaterial();\n this.setupChildrenEntities();\n this.el.setObject3D('mesh', mesh);\n },\n setupChildrenEntities: function () {\n var childrenEls = this.el.children;\n for (var i = 0; i < childrenEls.length; ++i) {\n if (!(childrenEls[i] instanceof AEntity)) {\n continue;\n }\n this.addChildEntity(childrenEls[i]);\n }\n },\n addChildEntity: function (childEl) {\n if (!(childEl instanceof AEntity)) {\n return;\n }\n this.wristObject3D.add(childEl.object3D);\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/hand-tracking-grab-controls.js\":\n/*!*******************************************************!*\\\n !*** ./src/components/hand-tracking-grab-controls.js ***!\n \\*******************************************************/\n/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {\n\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar THREE = __webpack_require__(/*! ../lib/three */ \"./src/lib/three.js\");\nregisterComponent('hand-tracking-grab-controls', {\n schema: {\n hand: {\n default: 'right',\n oneOf: ['left', 'right']\n },\n color: {\n type: 'color',\n default: 'white'\n },\n hoverColor: {\n type: 'color',\n default: '#538df1'\n },\n hoverEnabled: {\n default: false\n }\n },\n init: function () {\n var el = this.el;\n var data = this.data;\n var trackedObject3DVariable;\n if (data.hand === 'right') {\n trackedObject3DVariable = 'components.hand-tracking-controls.bones.3';\n } else {\n trackedObject3DVariable = 'components.hand-tracking-controls.bones.21';\n }\n el.setAttribute('hand-tracking-controls', {\n hand: data.hand\n });\n el.setAttribute('obb-collider', {\n trackedObject3D: trackedObject3DVariable,\n size: 0.04\n });\n this.auxMatrix = new THREE.Matrix4();\n this.auxQuaternion = new THREE.Quaternion();\n this.auxQuaternion2 = new THREE.Quaternion();\n this.auxVector = new THREE.Vector3();\n this.auxVector2 = new THREE.Vector3();\n this.grabbingObjectPosition = new THREE.Vector3();\n this.grabbedObjectPosition = new THREE.Vector3();\n this.grabbedObjectPositionDelta = new THREE.Vector3();\n this.grabDeltaPosition = new THREE.Vector3();\n this.grabInitialRotation = new THREE.Quaternion();\n this.onCollisionStarted = this.onCollisionStarted.bind(this);\n this.el.addEventListener('obbcollisionstarted', this.onCollisionStarted);\n this.onCollisionEnded = this.onCollisionEnded.bind(this);\n this.el.addEventListener('obbcollisionended', this.onCollisionEnded);\n this.onPinchStarted = this.onPinchStarted.bind(this);\n this.el.addEventListener('pinchstarted', this.onPinchStarted);\n this.onPinchEnded = this.onPinchEnded.bind(this);\n this.el.addEventListener('pinchended', this.onPinchEnded);\n this.onPinchMoved = this.onPinchMoved.bind(this);\n this.el.addEventListener('pinchmoved', this.onPinchMoved);\n },\n transferEntityOwnership: function () {\n var grabbingElComponent;\n var grabbingEls = this.el.sceneEl.querySelectorAll('[hand-tracking-grab-controls]');\n for (var i = 0; i < grabbingEls.length; ++i) {\n grabbingElComponent = grabbingEls[i].components['hand-tracking-grab-controls'];\n if (grabbingElComponent === this) {\n continue;\n }\n if (this.grabbedEl && this.grabbedEl === grabbingElComponent.grabbedEl) {\n grabbingElComponent.releaseGrabbedEntity();\n }\n }\n return false;\n },\n onCollisionStarted: function (evt) {\n var withEl = evt.detail.withEl;\n if (this.collidedEl) {\n return;\n }\n if (!withEl.getAttribute('grabbable')) {\n return;\n }\n this.collidedEl = withEl;\n this.grabbingObject3D = evt.detail.trackedObject3D;\n if (this.data.hoverEnabled) {\n this.el.setAttribute('hand-tracking-controls', 'modelColor', this.data.hoverColor);\n }\n },\n onCollisionEnded: function () {\n this.collidedEl = undefined;\n if (this.grabbedEl) {\n return;\n }\n this.grabbingObject3D = undefined;\n if (this.data.hoverEnabled) {\n this.el.setAttribute('hand-tracking-controls', 'modelColor', this.data.color);\n }\n },\n onPinchStarted: function (evt) {\n if (!this.collidedEl) {\n return;\n }\n this.pinchPosition = evt.detail.position;\n this.wristRotation = evt.detail.wristRotation;\n this.grabbedEl = this.collidedEl;\n this.transferEntityOwnership();\n this.grab();\n },\n onPinchEnded: function () {\n this.releaseGrabbedEntity();\n },\n onPinchMoved: function (evt) {\n this.wristRotation = evt.detail.wristRotation;\n },\n releaseGrabbedEntity: function () {\n var grabbedEl = this.grabbedEl;\n if (!grabbedEl) {\n return;\n }\n grabbedEl.object3D.updateMatrixWorld = this.originalUpdateMatrixWorld;\n grabbedEl.object3D.matrixAutoUpdate = true;\n grabbedEl.object3D.matrixWorldAutoUpdate = true;\n grabbedEl.object3D.matrixWorld.decompose(this.auxVector, this.auxQuaternion, this.auxVector2);\n grabbedEl.object3D.position.copy(this.auxVector);\n grabbedEl.object3D.quaternion.copy(this.auxQuaternion);\n this.el.emit('grabended', {\n grabbedEl: grabbedEl\n });\n this.grabbedEl = undefined;\n },\n grab: function () {\n var grabbedEl = this.grabbedEl;\n var grabbedObjectWorldPosition;\n grabbedObjectWorldPosition = grabbedEl.object3D.getWorldPosition(this.grabbedObjectPosition);\n this.grabDeltaPosition.copy(grabbedObjectWorldPosition).sub(this.pinchPosition);\n this.grabInitialRotation.copy(this.auxQuaternion.copy(this.wristRotation).invert());\n this.originalUpdateMatrixWorld = grabbedEl.object3D.updateMatrixWorld;\n grabbedEl.object3D.updateMatrixWorld = function () {/* no op */};\n grabbedEl.object3D.updateMatrixWorldChildren = function (force) {\n var children = this.children;\n for (var i = 0, l = children.length; i < l; i++) {\n var child = children[i];\n if (child.matrixWorldAutoUpdate === true || force === true) {\n child.updateMatrixWorld(true);\n }\n }\n };\n grabbedEl.object3D.matrixAutoUpdate = false;\n grabbedEl.object3D.matrixWorldAutoUpdate = false;\n this.el.emit('grabstarted', {\n grabbedEl: grabbedEl\n });\n },\n tock: function () {\n var auxMatrix = this.auxMatrix;\n var auxQuaternion = this.auxQuaternion;\n var auxQuaternion2 = this.auxQuaternion2;\n var grabbedObject3D;\n var grabbedEl = this.grabbedEl;\n if (!grabbedEl) {\n return;\n }\n\n // We have to compose 4 transformations.\n // Both grabbing and grabbed entities position and rotation.\n\n // 1. Move grabbed entity to the pinch position (middle point between index and thumb)\n // 2. Apply the rotation delta (subtract initial rotation) of the grabbing entity position (wrist).\n // 3. Translate grabbed entity to the original position: distance between grabbed and grabbing entities at collision time.\n // 4. Apply grabbed entity rotation.\n // 5. Preserve original scale.\n\n // Store grabbed entity local rotation.\n grabbedObject3D = grabbedEl.object3D;\n grabbedObject3D.getWorldQuaternion(auxQuaternion2);\n\n // Reset grabbed entity matrix.\n grabbedObject3D.matrixWorld.identity();\n\n // 1.\n auxMatrix.identity();\n auxMatrix.makeTranslation(this.pinchPosition);\n grabbedObject3D.matrixWorld.multiply(auxMatrix);\n\n // 2.\n auxMatrix.identity();\n auxMatrix.makeRotationFromQuaternion(auxQuaternion.copy(this.wristRotation).multiply(this.grabInitialRotation));\n grabbedObject3D.matrixWorld.multiply(auxMatrix);\n\n // 3.\n auxMatrix.identity();\n auxMatrix.makeTranslation(this.grabDeltaPosition);\n grabbedObject3D.matrixWorld.multiply(auxMatrix);\n\n // 4.\n auxMatrix.identity();\n auxMatrix.makeRotationFromQuaternion(auxQuaternion2);\n grabbedObject3D.matrixWorld.multiply(auxMatrix);\n\n // 5.\n auxMatrix.makeScale(grabbedEl.object3D.scale.x, grabbedEl.object3D.scale.y, grabbedEl.object3D.scale.z);\n grabbedObject3D.matrixWorld.multiply(auxMatrix);\n grabbedObject3D.updateMatrixWorldChildren();\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/hide-on-enter-ar.js\":\n/*!********************************************!*\\\n !*** ./src/components/hide-on-enter-ar.js ***!\n \\********************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar register = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nmodule.exports.Component = register('hide-on-enter-ar', {\n init: function () {\n var self = this;\n this.el.sceneEl.addEventListener('enter-vr', function () {\n if (self.el.sceneEl.is('ar-mode')) {\n self.el.object3D.visible = false;\n }\n });\n this.el.sceneEl.addEventListener('exit-vr', function () {\n self.el.object3D.visible = true;\n });\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/hide-on-enter-vr.js\":\n/*!********************************************!*\\\n !*** ./src/components/hide-on-enter-vr.js ***!\n \\********************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar register = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nmodule.exports.Component = register('hide-on-enter-vr', {\n init: function () {\n var self = this;\n this.el.sceneEl.addEventListener('enter-vr', function () {\n if (self.el.sceneEl.is('vr-mode')) {\n self.el.object3D.visible = false;\n }\n });\n this.el.sceneEl.addEventListener('exit-vr', function () {\n self.el.object3D.visible = true;\n });\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/hp-mixed-reality-controls.js\":\n/*!*****************************************************!*\\\n !*** ./src/components/hp-mixed-reality-controls.js ***!\n \\*****************************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar THREE = __webpack_require__(/*! ../lib/three */ \"./src/lib/three.js\");\nvar trackedControlsUtils = __webpack_require__(/*! ../utils/tracked-controls */ \"./src/utils/tracked-controls.js\");\nvar checkControllerPresentAndSetup = trackedControlsUtils.checkControllerPresentAndSetup;\nvar emitIfAxesChanged = trackedControlsUtils.emitIfAxesChanged;\nvar onButtonEvent = trackedControlsUtils.onButtonEvent;\n\n// See Profiles Registry:\n// https://github.com/immersive-web/webxr-input-profiles/tree/master/packages/registry\n// TODO: Add a more robust system for deriving gamepad name.\nvar GAMEPAD_ID = 'hp-mixed-reality';\nvar AFRAME_CDN_ROOT = (__webpack_require__(/*! ../constants */ \"./src/constants/index.js\").AFRAME_CDN_ROOT);\nvar HP_MIXED_REALITY_MODEL_GLB_BASE_URL = AFRAME_CDN_ROOT + 'controllers/hp/mixed-reality/';\nvar HP_MIXED_REALITY_POSITION_OFFSET = {\n x: 0,\n y: 0,\n z: 0.06\n};\nvar HP_MIXED_REALITY_ROTATION_OFFSET = {\n _x: Math.PI / 4,\n _y: 0,\n _z: 0,\n _order: 'XYZ'\n};\n\n/**\n * Button IDs:\n * 0 - trigger\n * 1 - grip\n * 3 - X / A\n * 4 - Y / B\n *\n * Axis:\n * 2 - joystick x axis\n * 3 - joystick y axis\n */\nvar INPUT_MAPPING_WEBXR = {\n left: {\n axes: {\n touchpad: [2, 3]\n },\n buttons: ['trigger', 'grip', 'none', 'thumbstick', 'xbutton', 'ybutton']\n },\n right: {\n axes: {\n touchpad: [2, 3]\n },\n buttons: ['trigger', 'grip', 'none', 'thumbstick', 'abutton', 'bbutton']\n }\n};\n\n/**\n * HP Mixed Reality Controls\n */\nmodule.exports.Component = registerComponent('hp-mixed-reality-controls', {\n schema: {\n hand: {\n default: 'none'\n },\n model: {\n default: true\n },\n orientationOffset: {\n type: 'vec3'\n }\n },\n mapping: INPUT_MAPPING_WEBXR,\n init: function () {\n var self = this;\n this.controllerPresent = false;\n this.lastControllerCheck = 0;\n this.onButtonChanged = this.onButtonChanged.bind(this);\n this.onButtonDown = function (evt) {\n onButtonEvent(evt.detail.id, 'down', self, self.data.hand);\n };\n this.onButtonUp = function (evt) {\n onButtonEvent(evt.detail.id, 'up', self, self.data.hand);\n };\n this.onButtonTouchEnd = function (evt) {\n onButtonEvent(evt.detail.id, 'touchend', self, self.data.hand);\n };\n this.onButtonTouchStart = function (evt) {\n onButtonEvent(evt.detail.id, 'touchstart', self, self.data.hand);\n };\n this.previousButtonValues = {};\n this.bindMethods();\n },\n update: function () {\n var data = this.data;\n this.controllerIndex = data.hand === 'right' ? 0 : data.hand === 'left' ? 1 : 2;\n },\n play: function () {\n this.checkIfControllerPresent();\n this.addControllersUpdateListener();\n },\n pause: function () {\n this.removeEventListeners();\n this.removeControllersUpdateListener();\n },\n bindMethods: function () {\n this.onModelLoaded = this.onModelLoaded.bind(this);\n this.onControllersUpdate = this.onControllersUpdate.bind(this);\n this.checkIfControllerPresent = this.checkIfControllerPresent.bind(this);\n this.removeControllersUpdateListener = this.removeControllersUpdateListener.bind(this);\n this.onAxisMoved = this.onAxisMoved.bind(this);\n },\n addEventListeners: function () {\n var el = this.el;\n el.addEventListener('buttonchanged', this.onButtonChanged);\n el.addEventListener('buttondown', this.onButtonDown);\n el.addEventListener('buttonup', this.onButtonUp);\n el.addEventListener('touchstart', this.onButtonTouchStart);\n el.addEventListener('touchend', this.onButtonTouchEnd);\n el.addEventListener('axismove', this.onAxisMoved);\n el.addEventListener('model-loaded', this.onModelLoaded);\n this.controllerEventsActive = true;\n },\n removeEventListeners: function () {\n var el = this.el;\n el.removeEventListener('buttonchanged', this.onButtonChanged);\n el.removeEventListener('buttondown', this.onButtonDown);\n el.removeEventListener('buttonup', this.onButtonUp);\n el.removeEventListener('touchstart', this.onButtonTouchStart);\n el.removeEventListener('touchend', this.onButtonTouchEnd);\n el.removeEventListener('axismove', this.onAxisMoved);\n el.removeEventListener('model-loaded', this.onModelLoaded);\n this.controllerEventsActive = false;\n },\n checkIfControllerPresent: function () {\n var data = this.data;\n checkControllerPresentAndSetup(this, GAMEPAD_ID, {\n index: this.controllerIndex,\n hand: data.hand\n });\n },\n injectTrackedControls: function () {\n var el = this.el;\n var data = this.data;\n el.setAttribute('tracked-controls', {\n // TODO: verify expected behavior between reserved prefixes.\n idPrefix: GAMEPAD_ID,\n hand: data.hand,\n controller: this.controllerIndex,\n orientationOffset: data.orientationOffset\n });\n\n // Load model.\n if (!this.data.model) {\n return;\n }\n this.el.setAttribute('gltf-model', HP_MIXED_REALITY_MODEL_GLB_BASE_URL + this.data.hand + '.glb');\n },\n addControllersUpdateListener: function () {\n this.el.sceneEl.addEventListener('controllersupdated', this.onControllersUpdate, false);\n },\n removeControllersUpdateListener: function () {\n this.el.sceneEl.removeEventListener('controllersupdated', this.onControllersUpdate, false);\n },\n onControllersUpdate: function () {\n // Note that due to gamepadconnected event propagation issues, we don't rely on events.\n this.checkIfControllerPresent();\n },\n onButtonChanged: function (evt) {\n var button = this.mapping[this.data.hand].buttons[evt.detail.id];\n var analogValue;\n if (!button) {\n return;\n }\n if (button === 'trigger') {\n analogValue = evt.detail.state.value;\n console.log('analog value of trigger press: ' + analogValue);\n }\n\n // Pass along changed event with button state, using button mapping for convenience.\n this.el.emit(button + 'changed', evt.detail.state);\n },\n onModelLoaded: function (evt) {\n var controllerObject3D = evt.detail.model;\n if (!this.data.model) {\n return;\n }\n controllerObject3D.position.copy(HP_MIXED_REALITY_POSITION_OFFSET);\n controllerObject3D.rotation.copy(HP_MIXED_REALITY_ROTATION_OFFSET);\n this.el.emit('controllermodelready', {\n name: 'hp-mixed-reality-controls',\n model: this.data.model,\n rayOrigin: new THREE.Vector3(0, 0, 0)\n });\n },\n onAxisMoved: function (evt) {\n emitIfAxesChanged(this, this.mapping.axes, evt);\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/index.js\":\n/*!*********************************!*\\\n !*** ./src/components/index.js ***!\n \\*********************************/\n/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {\n\n__webpack_require__(/*! ./animation */ \"./src/components/animation.js\");\n__webpack_require__(/*! ./anchored */ \"./src/components/anchored.js\");\n__webpack_require__(/*! ./camera */ \"./src/components/camera.js\");\n__webpack_require__(/*! ./cursor */ \"./src/components/cursor.js\");\n__webpack_require__(/*! ./geometry */ \"./src/components/geometry.js\");\n__webpack_require__(/*! ./generic-tracked-controller-controls */ \"./src/components/generic-tracked-controller-controls.js\");\n__webpack_require__(/*! ./gltf-model */ \"./src/components/gltf-model.js\");\n__webpack_require__(/*! ./grabbable */ \"./src/components/grabbable.js\");\n__webpack_require__(/*! ./hand-tracking-controls */ \"./src/components/hand-tracking-controls.js\");\n__webpack_require__(/*! ./hand-tracking-grab-controls */ \"./src/components/hand-tracking-grab-controls.js\");\n__webpack_require__(/*! ./hand-controls */ \"./src/components/hand-controls.js\");\n__webpack_require__(/*! ./hide-on-enter-ar */ \"./src/components/hide-on-enter-ar.js\");\n__webpack_require__(/*! ./hide-on-enter-vr */ \"./src/components/hide-on-enter-vr.js\");\n__webpack_require__(/*! ./hp-mixed-reality-controls */ \"./src/components/hp-mixed-reality-controls.js\");\n__webpack_require__(/*! ./layer */ \"./src/components/layer.js\");\n__webpack_require__(/*! ./laser-controls */ \"./src/components/laser-controls.js\");\n__webpack_require__(/*! ./light */ \"./src/components/light.js\");\n__webpack_require__(/*! ./line */ \"./src/components/line.js\");\n__webpack_require__(/*! ./link */ \"./src/components/link.js\");\n__webpack_require__(/*! ./look-controls */ \"./src/components/look-controls.js\");\n__webpack_require__(/*! ./magicleap-controls */ \"./src/components/magicleap-controls.js\");\n__webpack_require__(/*! ./material */ \"./src/components/material.js\");\n__webpack_require__(/*! ./obb-collider */ \"./src/components/obb-collider.js\");\n__webpack_require__(/*! ./obj-model */ \"./src/components/obj-model.js\");\n__webpack_require__(/*! ./oculus-go-controls */ \"./src/components/oculus-go-controls.js\");\n__webpack_require__(/*! ./oculus-touch-controls */ \"./src/components/oculus-touch-controls.js\");\n__webpack_require__(/*! ./pico-controls */ \"./src/components/pico-controls.js\");\n__webpack_require__(/*! ./position */ \"./src/components/position.js\");\n__webpack_require__(/*! ./raycaster */ \"./src/components/raycaster.js\");\n__webpack_require__(/*! ./rotation */ \"./src/components/rotation.js\");\n__webpack_require__(/*! ./scale */ \"./src/components/scale.js\");\n__webpack_require__(/*! ./shadow */ \"./src/components/shadow.js\");\n__webpack_require__(/*! ./sound */ \"./src/components/sound.js\");\n__webpack_require__(/*! ./text */ \"./src/components/text.js\");\n__webpack_require__(/*! ./tracked-controls */ \"./src/components/tracked-controls.js\");\n__webpack_require__(/*! ./tracked-controls-webvr */ \"./src/components/tracked-controls-webvr.js\");\n__webpack_require__(/*! ./tracked-controls-webxr */ \"./src/components/tracked-controls-webxr.js\");\n__webpack_require__(/*! ./visible */ \"./src/components/visible.js\");\n__webpack_require__(/*! ./valve-index-controls */ \"./src/components/valve-index-controls.js\");\n__webpack_require__(/*! ./vive-controls */ \"./src/components/vive-controls.js\");\n__webpack_require__(/*! ./vive-focus-controls */ \"./src/components/vive-focus-controls.js\");\n__webpack_require__(/*! ./wasd-controls */ \"./src/components/wasd-controls.js\");\n__webpack_require__(/*! ./windows-motion-controls */ \"./src/components/windows-motion-controls.js\");\n__webpack_require__(/*! ./scene/ar-hit-test */ \"./src/components/scene/ar-hit-test.js\");\n__webpack_require__(/*! ./scene/background */ \"./src/components/scene/background.js\");\n__webpack_require__(/*! ./scene/debug */ \"./src/components/scene/debug.js\");\n__webpack_require__(/*! ./scene/device-orientation-permission-ui */ \"./src/components/scene/device-orientation-permission-ui.js\");\n__webpack_require__(/*! ./scene/embedded */ \"./src/components/scene/embedded.js\");\n__webpack_require__(/*! ./scene/inspector */ \"./src/components/scene/inspector.js\");\n__webpack_require__(/*! ./scene/fog */ \"./src/components/scene/fog.js\");\n__webpack_require__(/*! ./scene/keyboard-shortcuts */ \"./src/components/scene/keyboard-shortcuts.js\");\n__webpack_require__(/*! ./scene/pool */ \"./src/components/scene/pool.js\");\n__webpack_require__(/*! ./scene/real-world-meshing */ \"./src/components/scene/real-world-meshing.js\");\n__webpack_require__(/*! ./scene/reflection */ \"./src/components/scene/reflection.js\");\n__webpack_require__(/*! ./scene/screenshot */ \"./src/components/scene/screenshot.js\");\n__webpack_require__(/*! ./scene/stats */ \"./src/components/scene/stats.js\");\n__webpack_require__(/*! ./scene/xr-mode-ui */ \"./src/components/scene/xr-mode-ui.js\");\n\n/***/ }),\n\n/***/ \"./src/components/laser-controls.js\":\n/*!******************************************!*\\\n !*** ./src/components/laser-controls.js ***!\n \\******************************************/\n/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {\n\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar utils = __webpack_require__(/*! ../utils/ */ \"./src/utils/index.js\");\nregisterComponent('laser-controls', {\n schema: {\n hand: {\n default: 'right'\n },\n model: {\n default: true\n },\n defaultModelColor: {\n type: 'color',\n default: 'grey'\n }\n },\n init: function () {\n var config = this.config;\n var data = this.data;\n var el = this.el;\n var self = this;\n var controlsConfiguration = {\n hand: data.hand,\n model: data.model\n };\n\n // Set all controller models.\n el.setAttribute('hp-mixed-reality-controls', controlsConfiguration);\n el.setAttribute('magicleap-controls', controlsConfiguration);\n el.setAttribute('oculus-go-controls', controlsConfiguration);\n el.setAttribute('oculus-touch-controls', controlsConfiguration);\n el.setAttribute('pico-controls', controlsConfiguration);\n el.setAttribute('valve-index-controls', controlsConfiguration);\n el.setAttribute('vive-controls', controlsConfiguration);\n el.setAttribute('vive-focus-controls', controlsConfiguration);\n el.setAttribute('windows-motion-controls', controlsConfiguration);\n el.setAttribute('generic-tracked-controller-controls', {\n hand: controlsConfiguration.hand\n });\n\n // Wait for controller to connect, or have a valid pointing pose, before creating ray\n el.addEventListener('controllerconnected', createRay);\n el.addEventListener('controllerdisconnected', hideRay);\n el.addEventListener('controllermodelready', function (evt) {\n createRay(evt);\n self.modelReady = true;\n });\n function createRay(evt) {\n var controllerConfig = config[evt.detail.name];\n if (!controllerConfig) {\n return;\n }\n\n // Show the line unless a particular config opts to hide it, until a controllermodelready\n // event comes through.\n var raycasterConfig = utils.extend({\n showLine: true\n }, controllerConfig.raycaster || {});\n\n // The controllermodelready event contains a rayOrigin that takes into account\n // offsets specific to the loaded model.\n if (evt.detail.rayOrigin) {\n raycasterConfig.origin = evt.detail.rayOrigin.origin;\n raycasterConfig.direction = evt.detail.rayOrigin.direction;\n raycasterConfig.showLine = true;\n }\n\n // Only apply a default raycaster if it does not yet exist. This prevents it overwriting\n // config applied from a controllermodelready event.\n if (evt.detail.rayOrigin || !self.modelReady) {\n el.setAttribute('raycaster', raycasterConfig);\n } else {\n el.setAttribute('raycaster', 'showLine', true);\n }\n el.setAttribute('cursor', utils.extend({\n fuse: false\n }, controllerConfig.cursor));\n }\n function hideRay(evt) {\n var controllerConfig = config[evt.detail.name];\n if (!controllerConfig) {\n return;\n }\n el.setAttribute('raycaster', 'showLine', false);\n }\n },\n config: {\n 'generic-tracked-controller-controls': {\n cursor: {\n downEvents: ['triggerdown'],\n upEvents: ['triggerup']\n }\n },\n 'hp-mixed-reality-controls': {\n cursor: {\n downEvents: ['triggerdown'],\n upEvents: ['triggerup']\n },\n raycaster: {\n origin: {\n x: 0,\n y: 0,\n z: 0\n }\n }\n },\n 'magicleap-controls': {\n cursor: {\n downEvents: ['trackpaddown', 'triggerdown'],\n upEvents: ['trackpadup', 'triggerup']\n }\n },\n 'oculus-go-controls': {\n cursor: {\n downEvents: ['triggerdown'],\n upEvents: ['triggerup']\n },\n raycaster: {\n origin: {\n x: 0,\n y: 0.0005,\n z: 0\n }\n }\n },\n 'oculus-touch-controls': {\n cursor: {\n downEvents: ['triggerdown'],\n upEvents: ['triggerup']\n },\n raycaster: {\n origin: {\n x: 0,\n y: 0,\n z: 0\n }\n }\n },\n 'pico-controls': {\n cursor: {\n downEvents: ['triggerdown'],\n upEvents: ['triggerup']\n }\n },\n 'valve-index-controls': {\n cursor: {\n downEvents: ['triggerdown'],\n upEvents: ['triggerup']\n }\n },\n 'vive-controls': {\n cursor: {\n downEvents: ['triggerdown'],\n upEvents: ['triggerup']\n }\n },\n 'vive-focus-controls': {\n cursor: {\n downEvents: ['trackpaddown', 'triggerdown'],\n upEvents: ['trackpadup', 'triggerup']\n }\n },\n 'windows-motion-controls': {\n cursor: {\n downEvents: ['triggerdown'],\n upEvents: ['triggerup']\n },\n raycaster: {\n showLine: false\n }\n }\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/layer.js\":\n/*!*********************************!*\\\n !*** ./src/components/layer.js ***!\n \\*********************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\n/* global THREE, XRRigidTransform, XRWebGLBinding */\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar utils = __webpack_require__(/*! ../utils/ */ \"./src/utils/index.js\");\nvar warn = utils.debug('components:layer:warn');\nmodule.exports.Component = registerComponent('layer', {\n schema: {\n type: {\n default: 'quad',\n oneOf: ['quad', 'monocubemap', 'stereocubemap']\n },\n src: {\n type: 'map'\n },\n rotateCubemap: {\n default: false\n },\n width: {\n default: 0\n },\n height: {\n default: 0\n }\n },\n init: function () {\n var gl = this.el.sceneEl.renderer.getContext();\n this.quaternion = new THREE.Quaternion();\n this.position = new THREE.Vector3();\n this.bindMethods();\n this.needsRedraw = false;\n this.frameBuffer = gl.createFramebuffer();\n var webxrData = this.el.sceneEl.getAttribute('webxr');\n var requiredFeaturesArray = webxrData.requiredFeatures;\n if (requiredFeaturesArray.indexOf('layers') === -1) {\n requiredFeaturesArray.push('layers');\n this.el.sceneEl.setAttribute('webxr', webxrData);\n }\n this.el.sceneEl.addEventListener('enter-vr', this.onEnterVR);\n this.el.sceneEl.addEventListener('exit-vr', this.onExitVR);\n },\n bindMethods: function () {\n this.onRequestedReferenceSpace = this.onRequestedReferenceSpace.bind(this);\n this.onEnterVR = this.onEnterVR.bind(this);\n this.onExitVR = this.onExitVR.bind(this);\n },\n update: function (oldData) {\n if (this.data.src !== oldData.src) {\n this.updateSrc();\n }\n },\n updateSrc: function () {\n var type = this.data.type;\n this.texture = undefined;\n if (type === 'quad') {\n this.loadQuadImage();\n return;\n }\n if (type === 'monocubemap' || type === 'stereocubemap') {\n this.loadCubeMapImages();\n return;\n }\n },\n loadCubeMapImages: function () {\n var glayer;\n var xrGLFactory = this.xrGLFactory;\n var frame = this.el.sceneEl.frame;\n var src = this.data.src;\n var type = this.data.type;\n this.visibilityChanged = false;\n if (!this.layer) {\n return;\n }\n if (type !== 'monocubemap' && type !== 'stereocubemap') {\n return;\n }\n if (!src.complete) {\n this.pendingCubeMapUpdate = true;\n } else {\n this.pendingCubeMapUpdate = false;\n }\n if (!this.loadingScreen) {\n this.loadingScreen = true;\n } else {\n this.loadingScreen = false;\n }\n if (type === 'monocubemap') {\n glayer = xrGLFactory.getSubImage(this.layer, frame);\n this.loadCubeMapImage(glayer.colorTexture, src, 0);\n } else {\n glayer = xrGLFactory.getSubImage(this.layer, frame, 'left');\n this.loadCubeMapImage(glayer.colorTexture, src, 0);\n glayer = xrGLFactory.getSubImage(this.layer, frame, 'right');\n this.loadCubeMapImage(glayer.colorTexture, src, 6);\n }\n },\n loadQuadImage: function () {\n var src = this.data.src;\n var self = this;\n this.el.sceneEl.systems.material.loadTexture(src, {\n src: src\n }, function textureLoaded(texture) {\n self.el.sceneEl.renderer.initTexture(texture);\n self.texture = texture;\n if (src.tagName === 'VIDEO') {\n setTimeout(function () {\n self.textureIsVideo = true;\n }, 1000);\n }\n if (self.layer) {\n self.layer.height = self.data.height / 2 || self.texture.image.height / 1000;\n self.layer.width = self.data.width / 2 || self.texture.image.width / 1000;\n self.needsRedraw = true;\n }\n self.updateQuadPanel();\n });\n },\n preGenerateCubeMapTextures: function (src, callback) {\n if (this.data.type === 'monocubemap') {\n this.generateCubeMapTextures(src, 0, callback);\n } else {\n this.generateCubeMapTextures(src, 0, callback);\n this.generateCubeMapTextures(src, 6, callback);\n }\n },\n generateCubeMapTextures: function (src, faceOffset, callback) {\n var data = this.data;\n var cubeFaceSize = this.cubeFaceSize;\n var textureSourceCubeFaceSize = Math.min(src.width, src.height);\n var cubefaceTextures = [];\n var imgTmp0;\n var imgTmp2;\n for (var i = 0; i < 6; i++) {\n var tempCanvas = document.createElement('CANVAS');\n tempCanvas.width = tempCanvas.height = cubeFaceSize;\n var tempCanvasContext = tempCanvas.getContext('2d');\n if (data.rotateCubemap) {\n if (i === 2 || i === 3) {\n tempCanvasContext.save();\n tempCanvasContext.translate(cubeFaceSize, cubeFaceSize);\n tempCanvasContext.rotate(Math.PI);\n }\n }\n\n // Note that this call to drawImage will not only copy the bytes to the\n // canvas but also could resized the image if our cube face size is\n // smaller than the source image due to GL max texture size.\n tempCanvasContext.drawImage(src, (i + faceOffset) * textureSourceCubeFaceSize,\n // top left x coord in source\n 0,\n // top left y coord in source\n textureSourceCubeFaceSize,\n // x pixel count from source\n textureSourceCubeFaceSize,\n // y pixel count from source\n 0,\n // dest x offset in the canvas\n 0,\n // dest y offset in the canvas\n cubeFaceSize,\n // x pixel count in dest\n cubeFaceSize // y pixel count in dest\n );\n\n tempCanvasContext.restore();\n if (callback) {\n callback();\n }\n cubefaceTextures.push(tempCanvas);\n }\n if (data.rotateCubemap) {\n imgTmp0 = cubefaceTextures[0];\n imgTmp2 = cubefaceTextures[1];\n cubefaceTextures[0] = imgTmp2;\n cubefaceTextures[1] = imgTmp0;\n imgTmp0 = cubefaceTextures[4];\n imgTmp2 = cubefaceTextures[5];\n cubefaceTextures[4] = imgTmp2;\n cubefaceTextures[5] = imgTmp0;\n }\n if (callback) {\n callback();\n }\n return cubefaceTextures;\n },\n loadCubeMapImage: function (layerColorTexture, src, faceOffset) {\n var gl = this.el.sceneEl.renderer.getContext();\n var cubefaceTextures;\n\n // don't flip the pixels as we load them into the texture buffer.\n // TEXTURE_CUBE_MAP expects the Y to be flipped for the faces and it already\n // is flipped in our texture image.\n gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);\n gl.bindTexture(gl.TEXTURE_CUBE_MAP, layerColorTexture);\n if (!src.complete || this.loadingScreen) {\n cubefaceTextures = this.loadingScreenImages;\n } else {\n cubefaceTextures = this.generateCubeMapTextures(src, faceOffset);\n }\n var errorCode = 0;\n cubefaceTextures.forEach(function (canvas, i) {\n gl.texSubImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, canvas);\n errorCode = gl.getError();\n });\n if (errorCode !== 0) {\n console.log('renderingError, WebGL Error Code: ' + errorCode);\n }\n gl.bindTexture(gl.TEXTURE_CUBE_MAP, null);\n },\n tick: function () {\n if (!this.el.sceneEl.xrSession) {\n return;\n }\n if (!this.layer && (this.el.sceneEl.is('vr-mode') || this.el.sceneEl.is('ar-mode'))) {\n this.initLayer();\n }\n this.updateTransform();\n if (this.data.src.complete && (this.pendingCubeMapUpdate || this.loadingScreen || this.visibilityChanged)) {\n this.loadCubeMapImages();\n }\n if (!this.needsRedraw && !this.layer.needsRedraw && !this.textureIsVideo) {\n return;\n }\n if (this.data.type === 'quad') {\n this.draw();\n }\n this.needsRedraw = false;\n },\n initLayer: function () {\n var self = this;\n var type = this.data.type;\n this.el.sceneEl.xrSession.onvisibilitychange = function (evt) {\n self.visibilityChanged = evt.session.visibilityState !== 'hidden';\n };\n if (type === 'quad') {\n this.initQuadLayer();\n return;\n }\n if (type === 'monocubemap' || type === 'stereocubemap') {\n this.initCubeMapLayer();\n return;\n }\n },\n initQuadLayer: function () {\n var sceneEl = this.el.sceneEl;\n var gl = sceneEl.renderer.getContext();\n var xrGLFactory = this.xrGLFactory = new XRWebGLBinding(sceneEl.xrSession, gl);\n if (!this.texture) {\n return;\n }\n this.layer = xrGLFactory.createQuadLayer({\n space: this.referenceSpace,\n viewPixelHeight: 2048,\n viewPixelWidth: 2048,\n height: this.data.height / 2 || this.texture.image.height / 1000,\n width: this.data.width / 2 || this.texture.image.width / 1000\n });\n this.initLoadingScreenImages();\n sceneEl.renderer.xr.addLayer(this.layer);\n },\n initCubeMapLayer: function () {\n var src = this.data.src;\n var sceneEl = this.el.sceneEl;\n var gl = sceneEl.renderer.getContext();\n var glSizeLimit = gl.getParameter(gl.MAX_CUBE_MAP_TEXTURE_SIZE);\n var cubeFaceSize = this.cubeFaceSize = Math.min(glSizeLimit, Math.min(src.width, src.height));\n var xrGLFactory = this.xrGLFactory = new XRWebGLBinding(sceneEl.xrSession, gl);\n this.layer = xrGLFactory.createCubeLayer({\n space: this.referenceSpace,\n viewPixelWidth: cubeFaceSize,\n viewPixelHeight: cubeFaceSize,\n layout: this.data.type === 'monocubemap' ? 'mono' : 'stereo',\n isStatic: false\n });\n this.initLoadingScreenImages();\n this.loadCubeMapImages();\n sceneEl.renderer.xr.addLayer(this.layer);\n },\n initLoadingScreenImages: function () {\n var cubeFaceSize = this.cubeFaceSize;\n var loadingScreenImages = this.loadingScreenImages = [];\n for (var i = 0; i < 6; i++) {\n var tempCanvas = document.createElement('CANVAS');\n tempCanvas.width = tempCanvas.height = cubeFaceSize;\n var tempCanvasContext = tempCanvas.getContext('2d');\n tempCanvas.width = tempCanvas.height = cubeFaceSize;\n tempCanvasContext.fillStyle = 'black';\n tempCanvasContext.fillRect(0, 0, cubeFaceSize, cubeFaceSize);\n if (i !== 2 && i !== 3) {\n tempCanvasContext.translate(cubeFaceSize, 0);\n tempCanvasContext.scale(-1, 1);\n tempCanvasContext.fillStyle = 'white';\n tempCanvasContext.font = '30px Arial';\n tempCanvasContext.fillText('Loading', cubeFaceSize / 2, cubeFaceSize / 2);\n }\n loadingScreenImages.push(tempCanvas);\n }\n },\n destroyLayer: function () {\n if (!this.layer) {\n return;\n }\n this.el.sceneEl.renderer.xr.removeLayer(this.layer);\n this.layer.destroy();\n this.layer = undefined;\n },\n toggleCompositorLayer: function () {\n this.enableCompositorLayer(!this.layerEnabled);\n },\n enableCompositorLayer: function (enable) {\n this.layerEnabled = enable;\n this.quadPanelEl.object3D.visible = !this.layerEnabled;\n },\n updateQuadPanel: function () {\n var quadPanelEl = this.quadPanelEl;\n if (!this.quadPanelEl) {\n quadPanelEl = this.quadPanelEl = document.createElement('a-entity');\n this.el.appendChild(quadPanelEl);\n }\n quadPanelEl.setAttribute('material', {\n shader: 'flat',\n src: this.data.src,\n transparent: true\n });\n quadPanelEl.setAttribute('geometry', {\n primitive: 'plane',\n height: this.data.height || this.texture.image.height / 1000,\n width: this.data.width || this.texture.image.height / 1000\n });\n },\n draw: function () {\n var sceneEl = this.el.sceneEl;\n var gl = this.el.sceneEl.renderer.getContext();\n var glayer = this.xrGLFactory.getSubImage(this.layer, sceneEl.frame);\n var texture = sceneEl.renderer.properties.get(this.texture).__webglTexture;\n var previousFrameBuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);\n gl.viewport(glayer.viewport.x, glayer.viewport.y, glayer.viewport.width, glayer.viewport.height);\n gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer);\n gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, glayer.colorTexture, 0);\n blitTexture(gl, texture, glayer, this.data.src);\n gl.bindFramebuffer(gl.FRAMEBUFFER, previousFrameBuffer);\n },\n updateTransform: function () {\n var el = this.el;\n var position = this.position;\n var quaternion = this.quaternion;\n el.object3D.updateMatrixWorld();\n position.setFromMatrixPosition(el.object3D.matrixWorld);\n quaternion.setFromRotationMatrix(el.object3D.matrixWorld);\n if (!this.layerEnabled) {\n position.set(0, 0, 100000000);\n }\n this.layer.transform = new XRRigidTransform(position, quaternion);\n },\n onEnterVR: function () {\n var sceneEl = this.el.sceneEl;\n var xrSession = sceneEl.xrSession;\n if (!sceneEl.hasWebXR || !XRWebGLBinding || !xrSession) {\n warn('The layer component requires WebXR and the layers API enabled');\n return;\n }\n xrSession.requestReferenceSpace('local-floor').then(this.onRequestedReferenceSpace);\n this.layerEnabled = true;\n if (this.quadPanelEl) {\n this.quadPanelEl.object3D.visible = false;\n }\n if (this.data.src.play) {\n this.data.src.play();\n }\n },\n onExitVR: function () {\n if (this.quadPanelEl) {\n this.quadPanelEl.object3D.visible = true;\n }\n this.destroyLayer();\n },\n onRequestedReferenceSpace: function (referenceSpace) {\n this.referenceSpace = referenceSpace;\n }\n});\nfunction blitTexture(gl, texture, subImage, textureEl) {\n var xrReadFramebuffer = gl.createFramebuffer();\n var x1offset = subImage.viewport.x;\n var y1offset = subImage.viewport.y;\n var x2offset = subImage.viewport.x + subImage.viewport.width;\n var y2offset = subImage.viewport.y + subImage.viewport.height;\n\n // Update video texture.\n if (textureEl.tagName === 'VIDEO') {\n gl.bindTexture(gl.TEXTURE_2D, texture);\n gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, textureEl.width, textureEl.height, gl.RGB, gl.UNSIGNED_BYTE, textureEl);\n }\n\n // Bind texture to read framebuffer.\n gl.bindFramebuffer(gl.READ_FRAMEBUFFER, xrReadFramebuffer);\n gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);\n\n // Blit into layer buffer.\n gl.readBuffer(gl.COLOR_ATTACHMENT0);\n gl.blitFramebuffer(0, 0, textureEl.width, textureEl.height, x1offset, y1offset, x2offset, y2offset, gl.COLOR_BUFFER_BIT, gl.NEAREST);\n gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);\n gl.deleteFramebuffer(xrReadFramebuffer);\n}\n\n/***/ }),\n\n/***/ \"./src/components/light.js\":\n/*!*********************************!*\\\n !*** ./src/components/light.js ***!\n \\*********************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar utils = __webpack_require__(/*! ../utils */ \"./src/utils/index.js\");\nvar diff = utils.diff;\nvar debug = __webpack_require__(/*! ../utils/debug */ \"./src/utils/debug.js\");\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar THREE = __webpack_require__(/*! ../lib/three */ \"./src/lib/three.js\");\nvar mathUtils = __webpack_require__(/*! ../utils/math */ \"./src/utils/math.js\");\nvar degToRad = THREE.MathUtils.degToRad;\nvar warn = debug('components:light:warn');\nvar CubeLoader = new THREE.CubeTextureLoader();\nvar probeCache = {};\n\n/**\n * Light component.\n */\nmodule.exports.Component = registerComponent('light', {\n schema: {\n angle: {\n default: 60,\n if: {\n type: ['spot']\n }\n },\n color: {\n type: 'color',\n if: {\n type: ['ambient', 'directional', 'hemisphere', 'point', 'spot']\n }\n },\n envMap: {\n default: '',\n if: {\n type: ['probe']\n }\n },\n groundColor: {\n type: 'color',\n if: {\n type: ['hemisphere']\n }\n },\n decay: {\n default: 1,\n if: {\n type: ['point', 'spot']\n }\n },\n distance: {\n default: 0.0,\n min: 0,\n if: {\n type: ['point', 'spot']\n }\n },\n intensity: {\n default: 1.0,\n min: 0,\n if: {\n type: ['ambient', 'directional', 'hemisphere', 'point', 'spot', 'probe']\n }\n },\n penumbra: {\n default: 0,\n min: 0,\n max: 1,\n if: {\n type: ['spot']\n }\n },\n type: {\n default: 'directional',\n oneOf: ['ambient', 'directional', 'hemisphere', 'point', 'spot', 'probe'],\n schemaChange: true\n },\n target: {\n type: 'selector',\n if: {\n type: ['spot', 'directional']\n }\n },\n // Shadows.\n castShadow: {\n default: false,\n if: {\n type: ['point', 'spot', 'directional']\n }\n },\n shadowBias: {\n default: 0,\n if: {\n castShadow: true\n }\n },\n shadowCameraFar: {\n default: 500,\n if: {\n castShadow: true\n }\n },\n shadowCameraFov: {\n default: 90,\n if: {\n castShadow: true\n }\n },\n shadowCameraNear: {\n default: 0.5,\n if: {\n castShadow: true\n }\n },\n shadowCameraTop: {\n default: 5,\n if: {\n castShadow: true\n }\n },\n shadowCameraRight: {\n default: 5,\n if: {\n castShadow: true\n }\n },\n shadowCameraBottom: {\n default: -5,\n if: {\n castShadow: true\n }\n },\n shadowCameraLeft: {\n default: -5,\n if: {\n castShadow: true\n }\n },\n shadowCameraVisible: {\n default: false,\n if: {\n castShadow: true\n }\n },\n shadowCameraAutomatic: {\n default: '',\n if: {\n type: ['directional']\n }\n },\n shadowMapHeight: {\n default: 512,\n if: {\n castShadow: true\n }\n },\n shadowMapWidth: {\n default: 512,\n if: {\n castShadow: true\n }\n },\n shadowRadius: {\n default: 1,\n if: {\n castShadow: true\n }\n }\n },\n /**\n * Notifies scene a light has been added to remove default lighting.\n */\n init: function () {\n var el = this.el;\n this.light = null;\n this.defaultTarget = null;\n this.system.registerLight(el);\n },\n /**\n * (Re)create or update light.\n */\n update: function (oldData) {\n var data = this.data;\n var diffData = diff(data, oldData);\n var light = this.light;\n var self = this;\n\n // Existing light.\n if (light && !('type' in diffData)) {\n var shadowsLoaded = false;\n // Light type has not changed. Update light.\n Object.keys(diffData).forEach(function (key) {\n var value = data[key];\n switch (key) {\n case 'color':\n {\n light.color.set(value);\n break;\n }\n case 'groundColor':\n {\n light.groundColor.set(value);\n break;\n }\n case 'angle':\n {\n light.angle = degToRad(value);\n break;\n }\n case 'target':\n {\n // Reset target if selector is null.\n if (value === null) {\n if (data.type === 'spot' || data.type === 'directional') {\n light.target = self.defaultTarget;\n }\n } else {\n // Target specified, set target to entity's `object3D` when it is loaded.\n if (value.hasLoaded) {\n self.onSetTarget(value, light);\n } else {\n value.addEventListener('loaded', self.onSetTarget.bind(self, value, light));\n }\n }\n break;\n }\n case 'envMap':\n self.updateProbeMap(data, light);\n break;\n case 'castShadow':\n case 'shadowBias':\n case 'shadowCameraFar':\n case 'shadowCameraFov':\n case 'shadowCameraNear':\n case 'shadowCameraTop':\n case 'shadowCameraRight':\n case 'shadowCameraBottom':\n case 'shadowCameraLeft':\n case 'shadowCameraVisible':\n case 'shadowMapHeight':\n case 'shadowMapWidth':\n case 'shadowRadius':\n if (!shadowsLoaded) {\n self.updateShadow();\n shadowsLoaded = true;\n }\n break;\n case 'shadowCameraAutomatic':\n if (data.shadowCameraAutomatic) {\n self.shadowCameraAutomaticEls = Array.from(document.querySelectorAll(data.shadowCameraAutomatic));\n } else {\n self.shadowCameraAutomaticEls = [];\n }\n break;\n default:\n {\n light[key] = value;\n }\n }\n });\n return;\n }\n\n // No light yet or light type has changed. Create and add light.\n this.setLight(this.data);\n this.updateShadow();\n },\n tick: function () {\n var bbox = new THREE.Box3();\n var normal = new THREE.Vector3();\n var cameraWorldPosition = new THREE.Vector3();\n var tempMat = new THREE.Matrix4();\n var sphere = new THREE.Sphere();\n var tempVector = new THREE.Vector3();\n return function () {\n if (!(this.data.type === 'directional' && this.light.shadow && this.light.shadow.camera instanceof THREE.OrthographicCamera && this.shadowCameraAutomaticEls.length)) return;\n var camera = this.light.shadow.camera;\n camera.getWorldDirection(normal);\n camera.getWorldPosition(cameraWorldPosition);\n tempMat.copy(camera.matrixWorld);\n tempMat.invert();\n camera.near = 1;\n camera.left = 100000;\n camera.right = -100000;\n camera.top = -100000;\n camera.bottom = 100000;\n this.shadowCameraAutomaticEls.forEach(function (el) {\n bbox.setFromObject(el.object3D);\n bbox.getBoundingSphere(sphere);\n var distanceToPlane = mathUtils.distanceOfPointFromPlane(cameraWorldPosition, normal, sphere.center);\n var pointOnCameraPlane = mathUtils.nearestPointInPlane(cameraWorldPosition, normal, sphere.center, tempVector);\n var pointInXYPlane = pointOnCameraPlane.applyMatrix4(tempMat);\n camera.near = Math.min(-distanceToPlane - sphere.radius - 1, camera.near);\n camera.left = Math.min(-sphere.radius + pointInXYPlane.x, camera.left);\n camera.right = Math.max(sphere.radius + pointInXYPlane.x, camera.right);\n camera.top = Math.max(sphere.radius + pointInXYPlane.y, camera.top);\n camera.bottom = Math.min(-sphere.radius + pointInXYPlane.y, camera.bottom);\n });\n camera.updateProjectionMatrix();\n };\n }(),\n setLight: function (data) {\n var el = this.el;\n var newLight = this.getLight(data);\n if (newLight) {\n if (this.light) {\n el.removeObject3D('light');\n }\n this.light = newLight;\n this.light.el = el;\n el.setObject3D('light', this.light);\n\n // HACK solution for issue #1624\n if (data.type === 'spot' || data.type === 'directional' || data.type === 'hemisphere') {\n el.getObject3D('light').translateY(-1);\n }\n\n // set and position default lighttarget as a child to enable spotlight orientation\n if (data.type === 'spot') {\n el.setObject3D('light-target', this.defaultTarget);\n el.getObject3D('light-target').position.set(0, 0, -1);\n }\n if (data.shadowCameraAutomatic) {\n this.shadowCameraAutomaticEls = Array.from(document.querySelectorAll(data.shadowCameraAutomatic));\n } else {\n this.shadowCameraAutomaticEls = [];\n }\n }\n },\n /**\n * Updates shadow-related properties on the current light.\n */\n updateShadow: function () {\n var el = this.el;\n var data = this.data;\n var light = this.light;\n light.castShadow = data.castShadow;\n\n // Shadow camera helper.\n var cameraHelper = el.getObject3D('cameraHelper');\n if (data.shadowCameraVisible && !cameraHelper) {\n el.setObject3D('cameraHelper', new THREE.CameraHelper(light.shadow.camera));\n } else if (!data.shadowCameraVisible && cameraHelper) {\n el.removeObject3D('cameraHelper');\n }\n if (!data.castShadow) {\n return light;\n }\n\n // Shadow appearance.\n light.shadow.bias = data.shadowBias;\n light.shadow.radius = data.shadowRadius;\n light.shadow.mapSize.height = data.shadowMapHeight;\n light.shadow.mapSize.width = data.shadowMapWidth;\n\n // Shadow camera.\n light.shadow.camera.near = data.shadowCameraNear;\n light.shadow.camera.far = data.shadowCameraFar;\n if (light.shadow.camera instanceof THREE.OrthographicCamera) {\n light.shadow.camera.top = data.shadowCameraTop;\n light.shadow.camera.right = data.shadowCameraRight;\n light.shadow.camera.bottom = data.shadowCameraBottom;\n light.shadow.camera.left = data.shadowCameraLeft;\n } else {\n light.shadow.camera.fov = data.shadowCameraFov;\n }\n light.shadow.camera.updateProjectionMatrix();\n if (cameraHelper) {\n cameraHelper.update();\n }\n },\n /**\n * Creates a new three.js light object given data object defining the light.\n *\n * @param {object} data\n */\n getLight: function (data) {\n var angle = data.angle;\n var color = new THREE.Color(data.color);\n color = color.getHex();\n var decay = data.decay;\n var distance = data.distance;\n var groundColor = new THREE.Color(data.groundColor);\n groundColor = groundColor.getHex();\n var intensity = data.intensity;\n var type = data.type;\n var target = data.target;\n var light = null;\n switch (type.toLowerCase()) {\n case 'ambient':\n {\n return new THREE.AmbientLight(color, intensity);\n }\n case 'directional':\n {\n light = new THREE.DirectionalLight(color, intensity);\n this.defaultTarget = light.target;\n if (target) {\n if (target.hasLoaded) {\n this.onSetTarget(target, light);\n } else {\n target.addEventListener('loaded', this.onSetTarget.bind(this, target, light));\n }\n }\n return light;\n }\n case 'hemisphere':\n {\n return new THREE.HemisphereLight(color, groundColor, intensity);\n }\n case 'point':\n {\n return new THREE.PointLight(color, intensity, distance, decay);\n }\n case 'spot':\n {\n light = new THREE.SpotLight(color, intensity, distance, degToRad(angle), data.penumbra, decay);\n this.defaultTarget = light.target;\n if (target) {\n if (target.hasLoaded) {\n this.onSetTarget(target, light);\n } else {\n target.addEventListener('loaded', this.onSetTarget.bind(this, target, light));\n }\n }\n return light;\n }\n case 'probe':\n {\n light = new THREE.LightProbe();\n this.updateProbeMap(data, light);\n return light;\n }\n default:\n {\n warn('%s is not a valid light type. ' + 'Choose from ambient, directional, hemisphere, point, spot.', type);\n }\n }\n },\n /**\n * Generate the spherical harmonics for the LightProbe from a cube map\n */\n updateProbeMap: function (data, light) {\n if (!data.envMap) {\n // reset parameters if no map\n light.copy(new THREE.LightProbe());\n }\n if (probeCache[data.envMap] instanceof window.Promise) {\n probeCache[data.envMap].then(function (tempLightProbe) {\n light.copy(tempLightProbe);\n });\n }\n if (probeCache[data.envMap] instanceof THREE.LightProbe) {\n light.copy(probeCache[data.envMap]);\n }\n probeCache[data.envMap] = new window.Promise(function (resolve) {\n utils.srcLoader.validateCubemapSrc(data.envMap, function loadEnvMap(urls) {\n CubeLoader.load(urls, function (cube) {\n var tempLightProbe = THREE.LightProbeGenerator.fromCubeTexture(cube);\n probeCache[data.envMap] = tempLightProbe;\n light.copy(tempLightProbe);\n });\n });\n });\n },\n onSetTarget: function (targetEl, light) {\n light.target = targetEl.object3D;\n },\n /**\n * Remove light on remove (callback).\n */\n remove: function () {\n var el = this.el;\n el.removeObject3D('light');\n if (el.getObject3D('cameraHelper')) {\n el.removeObject3D('cameraHelper');\n }\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/line.js\":\n/*!********************************!*\\\n !*** ./src/components/line.js ***!\n \\********************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\n/* global THREE */\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nmodule.exports.Component = registerComponent('line', {\n schema: {\n start: {\n type: 'vec3',\n default: {\n x: 0,\n y: 0,\n z: 0\n }\n },\n end: {\n type: 'vec3',\n default: {\n x: 0,\n y: 0,\n z: 0\n }\n },\n color: {\n type: 'color',\n default: '#74BEC1'\n },\n opacity: {\n type: 'number',\n default: 1\n },\n visible: {\n default: true\n }\n },\n multiple: true,\n init: function () {\n var data = this.data;\n var geometry;\n var material;\n material = this.material = new THREE.LineBasicMaterial({\n color: data.color,\n opacity: data.opacity,\n transparent: data.opacity < 1,\n visible: data.visible\n });\n geometry = this.geometry = new THREE.BufferGeometry();\n geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(2 * 3), 3));\n this.line = new THREE.Line(geometry, material);\n this.el.setObject3D(this.attrName, this.line);\n },\n update: function (oldData) {\n var data = this.data;\n var geometry = this.geometry;\n var geoNeedsUpdate = false;\n var material = this.material;\n var positionArray = geometry.attributes.position.array;\n\n // Update geometry.\n if (!isEqualVec3(data.start, oldData.start)) {\n positionArray[0] = data.start.x;\n positionArray[1] = data.start.y;\n positionArray[2] = data.start.z;\n geoNeedsUpdate = true;\n }\n if (!isEqualVec3(data.end, oldData.end)) {\n positionArray[3] = data.end.x;\n positionArray[4] = data.end.y;\n positionArray[5] = data.end.z;\n geoNeedsUpdate = true;\n }\n if (geoNeedsUpdate) {\n geometry.attributes.position.needsUpdate = true;\n geometry.computeBoundingSphere();\n }\n material.color.setStyle(data.color);\n material.opacity = data.opacity;\n material.transparent = data.opacity < 1;\n material.visible = data.visible;\n },\n remove: function () {\n this.el.removeObject3D(this.attrName, this.line);\n }\n});\nfunction isEqualVec3(a, b) {\n if (!a || !b) {\n return false;\n }\n return a.x === b.x && a.y === b.y && a.z === b.z;\n}\n\n/***/ }),\n\n/***/ \"./src/components/link.js\":\n/*!********************************!*\\\n !*** ./src/components/link.js ***!\n \\********************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar registerShader = (__webpack_require__(/*! ../core/shader */ \"./src/core/shader.js\").registerShader);\nvar THREE = __webpack_require__(/*! ../lib/three */ \"./src/lib/three.js\");\n\n/**\n * Link component. Connect experiences and traverse between them in VR\n *\n * @member {object} hiddenEls - Store the hidden elements during peek mode.\n */\nmodule.exports.Component = registerComponent('link', {\n schema: {\n backgroundColor: {\n default: 'red',\n type: 'color'\n },\n borderColor: {\n default: 'white',\n type: 'color'\n },\n highlighted: {\n default: false\n },\n highlightedColor: {\n default: '#24CAFF',\n type: 'color'\n },\n href: {\n default: ''\n },\n image: {\n type: 'asset'\n },\n on: {\n default: 'click'\n },\n peekMode: {\n default: false\n },\n title: {\n default: ''\n },\n titleColor: {\n default: 'white',\n type: 'color'\n },\n visualAspectEnabled: {\n default: false\n }\n },\n init: function () {\n this.navigate = this.navigate.bind(this);\n this.previousQuaternion = undefined;\n this.quaternionClone = new THREE.Quaternion();\n // Store hidden elements during peek mode so we can show them again later.\n this.hiddenEls = [];\n },\n update: function (oldData) {\n var data = this.data;\n var el = this.el;\n var backgroundColor;\n var strokeColor;\n if (!data.visualAspectEnabled) {\n return;\n }\n this.initVisualAspect();\n backgroundColor = data.highlighted ? data.highlightedColor : data.backgroundColor;\n strokeColor = data.highlighted ? data.highlightedColor : data.borderColor;\n el.setAttribute('material', 'backgroundColor', backgroundColor);\n el.setAttribute('material', 'strokeColor', strokeColor);\n if (data.on !== oldData.on) {\n this.updateEventListener();\n }\n if (oldData.peekMode !== undefined && data.peekMode !== oldData.peekMode) {\n this.updatePeekMode();\n }\n if (!data.image || oldData.image === data.image) {\n return;\n }\n el.setAttribute('material', 'pano', typeof data.image === 'string' ? data.image : data.image.src);\n },\n /*\n * Toggle all elements and full 360 preview of the linked page.\n */\n updatePeekMode: function () {\n var el = this.el;\n var sphereEl = this.sphereEl;\n if (this.data.peekMode) {\n this.hideAll();\n el.getObject3D('mesh').visible = false;\n sphereEl.setAttribute('visible', true);\n } else {\n this.showAll();\n el.getObject3D('mesh').visible = true;\n sphereEl.setAttribute('visible', false);\n }\n },\n play: function () {\n this.updateEventListener();\n },\n pause: function () {\n this.removeEventListener();\n },\n updateEventListener: function () {\n var el = this.el;\n if (!el.isPlaying) {\n return;\n }\n this.removeEventListener();\n el.addEventListener(this.data.on, this.navigate);\n },\n removeEventListener: function () {\n var on = this.data.on;\n if (!on) {\n return;\n }\n this.el.removeEventListener(on, this.navigate);\n },\n initVisualAspect: function () {\n var el = this.el;\n var semiSphereEl;\n var sphereEl;\n var textEl;\n if (!this.data.visualAspectEnabled || this.visualAspectInitialized) {\n return;\n }\n textEl = this.textEl = this.textEl || document.createElement('a-entity');\n sphereEl = this.sphereEl = this.sphereEl || document.createElement('a-entity');\n semiSphereEl = this.semiSphereEl = this.semiSphereEl || document.createElement('a-entity');\n\n // Set portal.\n el.setAttribute('geometry', {\n primitive: 'circle',\n radius: 1.0,\n segments: 64\n });\n el.setAttribute('material', {\n shader: 'portal',\n pano: this.data.image,\n side: 'double'\n });\n\n // Set text that displays the link title and URL.\n textEl.setAttribute('text', {\n color: this.data.titleColor,\n align: 'center',\n font: 'kelsonsans',\n value: this.data.title || this.data.href,\n width: 4\n });\n textEl.setAttribute('position', '0 1.5 0');\n el.appendChild(textEl);\n\n // Set sphere rendered when camera is close to portal to allow user to peek inside.\n semiSphereEl.setAttribute('geometry', {\n primitive: 'sphere',\n radius: 1.0,\n phiStart: 0,\n segmentsWidth: 64,\n segmentsHeight: 64,\n phiLength: 180,\n thetaStart: 0,\n thetaLength: 360\n });\n semiSphereEl.setAttribute('material', {\n shader: 'portal',\n borderEnabled: 0.0,\n pano: this.data.image,\n side: 'back'\n });\n semiSphereEl.setAttribute('rotation', '0 180 0');\n semiSphereEl.setAttribute('position', '0 0 0');\n semiSphereEl.setAttribute('visible', false);\n el.appendChild(semiSphereEl);\n\n // Set sphere rendered when camera is close to portal to allow user to peek inside.\n sphereEl.setAttribute('geometry', {\n primitive: 'sphere',\n radius: 10,\n segmentsWidth: 64,\n segmentsHeight: 64\n });\n sphereEl.setAttribute('material', {\n shader: 'portal',\n borderEnabled: 0.0,\n pano: this.data.image,\n side: 'back'\n });\n sphereEl.setAttribute('visible', false);\n el.appendChild(sphereEl);\n this.visualAspectInitialized = true;\n },\n navigate: function () {\n window.location = this.data.href;\n },\n /**\n * 1. Swap plane that represents portal with sphere with a hole when the camera is close\n * so user can peek inside portal. Sphere is rendered on opposite side of portal\n * from where user enters.\n * 2. Place the url/title above or inside portal depending on distance to camera.\n * 3. Face portal to camera when far away from user.\n */\n tick: function () {\n var cameraWorldPosition = new THREE.Vector3();\n var elWorldPosition = new THREE.Vector3();\n var quaternion = new THREE.Quaternion();\n var scale = new THREE.Vector3();\n return function () {\n var el = this.el;\n var object3D = el.object3D;\n var camera = el.sceneEl.camera;\n var cameraPortalOrientation;\n var distance;\n var textEl = this.textEl;\n if (!this.data.visualAspectEnabled) {\n return;\n }\n\n // Update matrices\n object3D.updateMatrixWorld();\n camera.parent.updateMatrixWorld();\n camera.updateMatrixWorld();\n object3D.matrix.decompose(elWorldPosition, quaternion, scale);\n elWorldPosition.setFromMatrixPosition(object3D.matrixWorld);\n cameraWorldPosition.setFromMatrixPosition(camera.matrixWorld);\n distance = elWorldPosition.distanceTo(cameraWorldPosition);\n if (distance > 20) {\n // Store original orientation to be restored when the portal stops facing the camera.\n if (!this.previousQuaternion) {\n this.quaternionClone.copy(quaternion);\n this.previousQuaternion = this.quaternionClone;\n }\n // If the portal is far away from the user, face portal to camera.\n object3D.lookAt(cameraWorldPosition);\n } else {\n // When portal is close to the user/camera.\n cameraPortalOrientation = this.calculateCameraPortalOrientation();\n // If user gets very close to portal, replace with holed sphere they can peek in.\n if (distance < 0.5) {\n // Configure text size and sphere orientation depending side user approaches portal.\n if (this.semiSphereEl.getAttribute('visible') === true) {\n return;\n }\n textEl.setAttribute('text', 'width', 1.5);\n if (cameraPortalOrientation <= 0.0) {\n textEl.setAttribute('position', '0 0 0.75');\n textEl.setAttribute('rotation', '0 180 0');\n this.semiSphereEl.setAttribute('rotation', '0 0 0');\n } else {\n textEl.setAttribute('position', '0 0 -0.75');\n textEl.setAttribute('rotation', '0 0 0');\n this.semiSphereEl.setAttribute('rotation', '0 180 0');\n }\n el.getObject3D('mesh').visible = false;\n this.semiSphereEl.setAttribute('visible', true);\n this.peekCameraPortalOrientation = cameraPortalOrientation;\n } else {\n // Calculate which side the camera is approaching the camera (back / front).\n // Adjust text orientation based on camera position.\n if (cameraPortalOrientation <= 0.0) {\n textEl.setAttribute('rotation', '0 180 0');\n } else {\n textEl.setAttribute('rotation', '0 0 0');\n }\n textEl.setAttribute('text', 'width', 5);\n textEl.setAttribute('position', '0 1.5 0');\n el.getObject3D('mesh').visible = true;\n this.semiSphereEl.setAttribute('visible', false);\n this.peekCameraPortalOrientation = undefined;\n }\n if (this.previousQuaternion) {\n object3D.quaternion.copy(this.previousQuaternion);\n this.previousQuaternion = undefined;\n }\n }\n };\n }(),\n hideAll: function () {\n var el = this.el;\n var hiddenEls = this.hiddenEls;\n var self = this;\n if (hiddenEls.length > 0) {\n return;\n }\n el.sceneEl.object3D.traverse(function (object) {\n if (object && object.el && object.el.hasAttribute('link-controls')) {\n return;\n }\n if (!object.el || object === el.sceneEl.object3D || object.el === el || object.el === self.sphereEl || object.el === el.sceneEl.cameraEl || object.el.getAttribute('visible') === false || object.el === self.textEl || object.el === self.semiSphereEl) {\n return;\n }\n object.el.setAttribute('visible', false);\n hiddenEls.push(object.el);\n });\n },\n showAll: function () {\n this.hiddenEls.forEach(function (el) {\n el.setAttribute('visible', true);\n });\n this.hiddenEls = [];\n },\n /**\n * Calculate whether the camera faces the front or back face of the portal.\n * @returns {number} > 0 if camera faces front of portal, < 0 if it faces back of portal.\n */\n calculateCameraPortalOrientation: function () {\n var mat4 = new THREE.Matrix4();\n var cameraPosition = new THREE.Vector3();\n var portalNormal = new THREE.Vector3(0, 0, 1);\n var portalPosition = new THREE.Vector3(0, 0, 0);\n return function () {\n var el = this.el;\n var camera = el.sceneEl.camera;\n\n // Reset tmp variables.\n cameraPosition.set(0, 0, 0);\n portalNormal.set(0, 0, 1);\n portalPosition.set(0, 0, 0);\n\n // Apply portal orientation to the normal.\n el.object3D.matrixWorld.extractRotation(mat4);\n portalNormal.applyMatrix4(mat4);\n\n // Calculate portal world position.\n el.object3D.updateMatrixWorld();\n el.object3D.localToWorld(portalPosition);\n\n // Calculate camera world position.\n camera.parent.parent.updateMatrixWorld();\n camera.parent.updateMatrixWorld();\n camera.updateMatrixWorld();\n camera.localToWorld(cameraPosition);\n\n // Calculate vector from portal to camera.\n // (portal) -------> (camera)\n cameraPosition.sub(portalPosition).normalize();\n portalNormal.normalize();\n\n // Side where camera approaches portal is given by sign of dot product of portal normal\n // and portal to camera vectors.\n return Math.sign(portalNormal.dot(cameraPosition));\n };\n }(),\n remove: function () {\n this.removeEventListener();\n }\n});\n\n/* eslint-disable */\nregisterShader('portal', {\n schema: {\n borderEnabled: {\n default: 1.0,\n type: 'int',\n is: 'uniform'\n },\n backgroundColor: {\n default: 'red',\n type: 'color',\n is: 'uniform'\n },\n pano: {\n type: 'map',\n is: 'uniform'\n },\n strokeColor: {\n default: 'white',\n type: 'color',\n is: 'uniform'\n }\n },\n vertexShader: ['vec3 portalPosition;', 'varying vec3 vWorldPosition;', 'varying float vDistanceToCenter;', 'varying float vDistance;', 'void main() {', 'vDistanceToCenter = clamp(length(position - vec3(0.0, 0.0, 0.0)), 0.0, 1.0);', 'portalPosition = (modelMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;', 'vDistance = length(portalPosition - cameraPosition);', 'vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;', 'gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);', '}'].join('\\n'),\n fragmentShader: ['#define RECIPROCAL_PI2 0.15915494', 'uniform sampler2D pano;', 'uniform vec3 strokeColor;', 'uniform vec3 backgroundColor;', 'uniform float borderEnabled;', 'varying float vDistanceToCenter;', 'varying float vDistance;', 'varying vec3 vWorldPosition;', 'void main() {', 'vec3 direction = normalize(vWorldPosition - cameraPosition);', 'vec2 sampleUV;', 'float borderThickness = clamp(exp(-vDistance / 50.0), 0.6, 0.95);', 'sampleUV.y = clamp(direction.y * 0.5 + 0.5, 0.0, 1.0);', 'sampleUV.x = atan(direction.z, -direction.x) * -RECIPROCAL_PI2 + 0.5;', 'if (vDistanceToCenter > borderThickness && borderEnabled == 1.0) {', 'gl_FragColor = vec4(strokeColor, 1.0);', '} else {', 'gl_FragColor = mix(texture2D(pano, sampleUV), vec4(backgroundColor, 1.0), clamp(pow((vDistance / 15.0), 2.0), 0.0, 1.0));', '}', '}'].join('\\n')\n});\n/* eslint-enable */\n\n/***/ }),\n\n/***/ \"./src/components/look-controls.js\":\n/*!*****************************************!*\\\n !*** ./src/components/look-controls.js ***!\n \\*****************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\n/* global DeviceOrientationEvent */\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar THREE = __webpack_require__(/*! ../lib/three */ \"./src/lib/three.js\");\nvar utils = __webpack_require__(/*! ../utils/ */ \"./src/utils/index.js\");\n\n// To avoid recalculation at every mouse movement tick\nvar PI_2 = Math.PI / 2;\n\n/**\n * look-controls. Update entity pose, factoring mouse, touch, and WebVR API data.\n */\nmodule.exports.Component = registerComponent('look-controls', {\n dependencies: ['position', 'rotation'],\n schema: {\n enabled: {\n default: true\n },\n magicWindowTrackingEnabled: {\n default: true\n },\n pointerLockEnabled: {\n default: false\n },\n reverseMouseDrag: {\n default: false\n },\n reverseTouchDrag: {\n default: false\n },\n touchEnabled: {\n default: true\n },\n mouseEnabled: {\n default: true\n }\n },\n init: function () {\n this.deltaYaw = 0;\n this.previousHMDPosition = new THREE.Vector3();\n this.hmdQuaternion = new THREE.Quaternion();\n this.magicWindowAbsoluteEuler = new THREE.Euler();\n this.magicWindowDeltaEuler = new THREE.Euler();\n this.position = new THREE.Vector3();\n this.magicWindowObject = new THREE.Object3D();\n this.rotation = {};\n this.deltaRotation = {};\n this.savedPose = null;\n this.pointerLocked = false;\n this.setupMouseControls();\n this.bindMethods();\n this.previousMouseEvent = {};\n this.setupMagicWindowControls();\n\n // To save / restore camera pose\n this.savedPose = {\n position: new THREE.Vector3(),\n rotation: new THREE.Euler()\n };\n\n // Call enter VR handler if the scene has entered VR before the event listeners attached.\n if (this.el.sceneEl.is('vr-mode') || this.el.sceneEl.is('ar-mode')) {\n this.onEnterVR();\n }\n },\n setupMagicWindowControls: function () {\n var magicWindowControls;\n var data = this.data;\n\n // Only on mobile devices and only enabled if DeviceOrientation permission has been granted.\n if (utils.device.isMobile() || utils.device.isMobileDeviceRequestingDesktopSite()) {\n magicWindowControls = this.magicWindowControls = new THREE.DeviceOrientationControls(this.magicWindowObject);\n if (typeof DeviceOrientationEvent !== 'undefined' && DeviceOrientationEvent.requestPermission) {\n magicWindowControls.enabled = false;\n if (this.el.sceneEl.components['device-orientation-permission-ui'].permissionGranted) {\n magicWindowControls.enabled = data.magicWindowTrackingEnabled;\n } else {\n this.el.sceneEl.addEventListener('deviceorientationpermissiongranted', function () {\n magicWindowControls.enabled = data.magicWindowTrackingEnabled;\n });\n }\n }\n }\n },\n update: function (oldData) {\n var data = this.data;\n\n // Disable grab cursor classes if no longer enabled.\n if (data.enabled !== oldData.enabled) {\n this.updateGrabCursor(data.enabled);\n }\n\n // Reset magic window eulers if tracking is disabled.\n if (oldData && !data.magicWindowTrackingEnabled && oldData.magicWindowTrackingEnabled) {\n this.magicWindowAbsoluteEuler.set(0, 0, 0);\n this.magicWindowDeltaEuler.set(0, 0, 0);\n }\n\n // Pass on magic window tracking setting to magicWindowControls.\n if (this.magicWindowControls) {\n this.magicWindowControls.enabled = data.magicWindowTrackingEnabled;\n }\n if (oldData && !data.pointerLockEnabled !== oldData.pointerLockEnabled) {\n this.removeEventListeners();\n this.addEventListeners();\n if (this.pointerLocked) {\n this.exitPointerLock();\n }\n }\n },\n tick: function (t) {\n var data = this.data;\n if (!data.enabled) {\n return;\n }\n this.updateOrientation();\n },\n play: function () {\n this.addEventListeners();\n },\n pause: function () {\n this.removeEventListeners();\n if (this.pointerLocked) {\n this.exitPointerLock();\n }\n },\n remove: function () {\n this.removeEventListeners();\n if (this.pointerLocked) {\n this.exitPointerLock();\n }\n },\n bindMethods: function () {\n this.onMouseDown = this.onMouseDown.bind(this);\n this.onMouseMove = this.onMouseMove.bind(this);\n this.onMouseUp = this.onMouseUp.bind(this);\n this.onTouchStart = this.onTouchStart.bind(this);\n this.onTouchMove = this.onTouchMove.bind(this);\n this.onTouchEnd = this.onTouchEnd.bind(this);\n this.onEnterVR = this.onEnterVR.bind(this);\n this.onExitVR = this.onExitVR.bind(this);\n this.onPointerLockChange = this.onPointerLockChange.bind(this);\n this.onPointerLockError = this.onPointerLockError.bind(this);\n },\n /**\n * Set up states and Object3Ds needed to store rotation data.\n */\n setupMouseControls: function () {\n this.mouseDown = false;\n this.pitchObject = new THREE.Object3D();\n this.yawObject = new THREE.Object3D();\n this.yawObject.position.y = 10;\n this.yawObject.add(this.pitchObject);\n },\n /**\n * Add mouse and touch event listeners to canvas.\n */\n addEventListeners: function () {\n var sceneEl = this.el.sceneEl;\n var canvasEl = sceneEl.canvas;\n\n // Wait for canvas to load.\n if (!canvasEl) {\n sceneEl.addEventListener('render-target-loaded', this.addEventListeners.bind(this));\n return;\n }\n\n // Mouse events.\n canvasEl.addEventListener('mousedown', this.onMouseDown, false);\n window.addEventListener('mousemove', this.onMouseMove, false);\n window.addEventListener('mouseup', this.onMouseUp, false);\n\n // Touch events.\n canvasEl.addEventListener('touchstart', this.onTouchStart, {\n passive: true\n });\n window.addEventListener('touchmove', this.onTouchMove, {\n passive: true\n });\n window.addEventListener('touchend', this.onTouchEnd, {\n passive: true\n });\n\n // sceneEl events.\n sceneEl.addEventListener('enter-vr', this.onEnterVR);\n sceneEl.addEventListener('exit-vr', this.onExitVR);\n\n // Pointer Lock events.\n if (this.data.pointerLockEnabled) {\n document.addEventListener('pointerlockchange', this.onPointerLockChange, false);\n document.addEventListener('mozpointerlockchange', this.onPointerLockChange, false);\n document.addEventListener('pointerlockerror', this.onPointerLockError, false);\n }\n },\n /**\n * Remove mouse and touch event listeners from canvas.\n */\n removeEventListeners: function () {\n var sceneEl = this.el.sceneEl;\n var canvasEl = sceneEl && sceneEl.canvas;\n if (!canvasEl) {\n return;\n }\n\n // Mouse events.\n canvasEl.removeEventListener('mousedown', this.onMouseDown);\n window.removeEventListener('mousemove', this.onMouseMove);\n window.removeEventListener('mouseup', this.onMouseUp);\n\n // Touch events.\n canvasEl.removeEventListener('touchstart', this.onTouchStart);\n window.removeEventListener('touchmove', this.onTouchMove);\n window.removeEventListener('touchend', this.onTouchEnd);\n\n // sceneEl events.\n sceneEl.removeEventListener('enter-vr', this.onEnterVR);\n sceneEl.removeEventListener('exit-vr', this.onExitVR);\n\n // Pointer Lock events.\n document.removeEventListener('pointerlockchange', this.onPointerLockChange, false);\n document.removeEventListener('mozpointerlockchange', this.onPointerLockChange, false);\n document.removeEventListener('pointerlockerror', this.onPointerLockError, false);\n },\n /**\n * Update orientation for mobile, mouse drag, and headset.\n * Mouse-drag only enabled if HMD is not active.\n */\n updateOrientation: function () {\n var object3D = this.el.object3D;\n var pitchObject = this.pitchObject;\n var yawObject = this.yawObject;\n var sceneEl = this.el.sceneEl;\n\n // In VR or AR mode, THREE is in charge of updating the camera pose.\n if ((sceneEl.is('vr-mode') || sceneEl.is('ar-mode')) && sceneEl.checkHeadsetConnected()) {\n // With WebXR THREE applies headset pose to the object3D internally.\n return;\n }\n this.updateMagicWindowOrientation();\n\n // On mobile, do camera rotation with touch events and sensors.\n object3D.rotation.x = this.magicWindowDeltaEuler.x + pitchObject.rotation.x;\n object3D.rotation.y = this.magicWindowDeltaEuler.y + yawObject.rotation.y;\n object3D.rotation.z = this.magicWindowDeltaEuler.z;\n },\n updateMagicWindowOrientation: function () {\n var magicWindowAbsoluteEuler = this.magicWindowAbsoluteEuler;\n var magicWindowDeltaEuler = this.magicWindowDeltaEuler;\n // Calculate magic window HMD quaternion.\n if (this.magicWindowControls && this.magicWindowControls.enabled) {\n this.magicWindowControls.update();\n magicWindowAbsoluteEuler.setFromQuaternion(this.magicWindowObject.quaternion, 'YXZ');\n if (!this.previousMagicWindowYaw && magicWindowAbsoluteEuler.y !== 0) {\n this.previousMagicWindowYaw = magicWindowAbsoluteEuler.y;\n }\n if (this.previousMagicWindowYaw) {\n magicWindowDeltaEuler.x = magicWindowAbsoluteEuler.x;\n magicWindowDeltaEuler.y += magicWindowAbsoluteEuler.y - this.previousMagicWindowYaw;\n magicWindowDeltaEuler.z = magicWindowAbsoluteEuler.z;\n this.previousMagicWindowYaw = magicWindowAbsoluteEuler.y;\n }\n }\n },\n /**\n * Translate mouse drag into rotation.\n *\n * Dragging up and down rotates the camera around the X-axis (yaw).\n * Dragging left and right rotates the camera around the Y-axis (pitch).\n */\n onMouseMove: function (evt) {\n var direction;\n var movementX;\n var movementY;\n var pitchObject = this.pitchObject;\n var previousMouseEvent = this.previousMouseEvent;\n var yawObject = this.yawObject;\n\n // Not dragging or not enabled.\n if (!this.data.enabled || !this.mouseDown && !this.pointerLocked) {\n return;\n }\n\n // Calculate delta.\n if (this.pointerLocked) {\n movementX = evt.movementX || evt.mozMovementX || 0;\n movementY = evt.movementY || evt.mozMovementY || 0;\n } else {\n movementX = evt.screenX - previousMouseEvent.screenX;\n movementY = evt.screenY - previousMouseEvent.screenY;\n }\n this.previousMouseEvent.screenX = evt.screenX;\n this.previousMouseEvent.screenY = evt.screenY;\n\n // Calculate rotation.\n direction = this.data.reverseMouseDrag ? 1 : -1;\n yawObject.rotation.y += movementX * 0.002 * direction;\n pitchObject.rotation.x += movementY * 0.002 * direction;\n pitchObject.rotation.x = Math.max(-PI_2, Math.min(PI_2, pitchObject.rotation.x));\n },\n /**\n * Register mouse down to detect mouse drag.\n */\n onMouseDown: function (evt) {\n var sceneEl = this.el.sceneEl;\n if (!this.data.enabled || !this.data.mouseEnabled || (sceneEl.is('vr-mode') || sceneEl.is('ar-mode')) && sceneEl.checkHeadsetConnected()) {\n return;\n }\n // Handle only primary button.\n if (evt.button !== 0) {\n return;\n }\n var canvasEl = sceneEl && sceneEl.canvas;\n this.mouseDown = true;\n this.previousMouseEvent.screenX = evt.screenX;\n this.previousMouseEvent.screenY = evt.screenY;\n this.showGrabbingCursor();\n if (this.data.pointerLockEnabled && !this.pointerLocked) {\n if (canvasEl.requestPointerLock) {\n canvasEl.requestPointerLock();\n } else if (canvasEl.mozRequestPointerLock) {\n canvasEl.mozRequestPointerLock();\n }\n }\n },\n /**\n * Shows grabbing cursor on scene\n */\n showGrabbingCursor: function () {\n this.el.sceneEl.canvas.style.cursor = 'grabbing';\n },\n /**\n * Hides grabbing cursor on scene\n */\n hideGrabbingCursor: function () {\n this.el.sceneEl.canvas.style.cursor = '';\n },\n /**\n * Register mouse up to detect release of mouse drag.\n */\n onMouseUp: function () {\n this.mouseDown = false;\n this.hideGrabbingCursor();\n },\n /**\n * Register touch down to detect touch drag.\n */\n onTouchStart: function (evt) {\n if (evt.touches.length !== 1 || !this.data.touchEnabled || this.el.sceneEl.is('vr-mode') || this.el.sceneEl.is('ar-mode')) {\n return;\n }\n this.touchStart = {\n x: evt.touches[0].pageX,\n y: evt.touches[0].pageY\n };\n this.touchStarted = true;\n },\n /**\n * Translate touch move to Y-axis rotation.\n */\n onTouchMove: function (evt) {\n var direction;\n var canvas = this.el.sceneEl.canvas;\n var deltaY;\n var yawObject = this.yawObject;\n if (!this.touchStarted || !this.data.touchEnabled) {\n return;\n }\n deltaY = 2 * Math.PI * (evt.touches[0].pageX - this.touchStart.x) / canvas.clientWidth;\n direction = this.data.reverseTouchDrag ? 1 : -1;\n // Limit touch orientation to to yaw (y axis).\n yawObject.rotation.y -= deltaY * 0.5 * direction;\n this.touchStart = {\n x: evt.touches[0].pageX,\n y: evt.touches[0].pageY\n };\n },\n /**\n * Register touch end to detect release of touch drag.\n */\n onTouchEnd: function () {\n this.touchStarted = false;\n },\n /**\n * Save pose.\n */\n onEnterVR: function () {\n var sceneEl = this.el.sceneEl;\n if (!sceneEl.checkHeadsetConnected()) {\n return;\n }\n this.saveCameraPose();\n this.el.object3D.position.set(0, 0, 0);\n this.el.object3D.rotation.set(0, 0, 0);\n if (sceneEl.hasWebXR) {\n this.el.object3D.matrixAutoUpdate = false;\n this.el.object3D.updateMatrix();\n }\n },\n /**\n * Restore the pose.\n */\n onExitVR: function () {\n if (!this.el.sceneEl.checkHeadsetConnected()) {\n return;\n }\n this.restoreCameraPose();\n this.previousHMDPosition.set(0, 0, 0);\n this.el.object3D.matrixAutoUpdate = true;\n },\n /**\n * Update Pointer Lock state.\n */\n onPointerLockChange: function () {\n this.pointerLocked = !!(document.pointerLockElement || document.mozPointerLockElement);\n },\n /**\n * Recover from Pointer Lock error.\n */\n onPointerLockError: function () {\n this.pointerLocked = false;\n },\n // Exits pointer-locked mode.\n exitPointerLock: function () {\n document.exitPointerLock();\n this.pointerLocked = false;\n },\n /**\n * Toggle the feature of showing/hiding the grab cursor.\n */\n updateGrabCursor: function (enabled) {\n var sceneEl = this.el.sceneEl;\n function enableGrabCursor() {\n sceneEl.canvas.classList.add('a-grab-cursor');\n }\n function disableGrabCursor() {\n sceneEl.canvas.classList.remove('a-grab-cursor');\n }\n if (!sceneEl.canvas) {\n if (enabled) {\n sceneEl.addEventListener('render-target-loaded', enableGrabCursor);\n } else {\n sceneEl.addEventListener('render-target-loaded', disableGrabCursor);\n }\n return;\n }\n if (enabled) {\n enableGrabCursor();\n return;\n }\n disableGrabCursor();\n },\n /**\n * Save camera pose before entering VR to restore later if exiting.\n */\n saveCameraPose: function () {\n var el = this.el;\n this.savedPose.position.copy(el.object3D.position);\n this.savedPose.rotation.copy(el.object3D.rotation);\n this.hasSavedPose = true;\n },\n /**\n * Reset camera pose to before entering VR.\n */\n restoreCameraPose: function () {\n var el = this.el;\n var savedPose = this.savedPose;\n if (!this.hasSavedPose) {\n return;\n }\n\n // Reset camera orientation.\n el.object3D.position.copy(savedPose.position);\n el.object3D.rotation.copy(savedPose.rotation);\n this.hasSavedPose = false;\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/magicleap-controls.js\":\n/*!**********************************************!*\\\n !*** ./src/components/magicleap-controls.js ***!\n \\**********************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar trackedControlsUtils = __webpack_require__(/*! ../utils/tracked-controls */ \"./src/utils/tracked-controls.js\");\nvar checkControllerPresentAndSetup = trackedControlsUtils.checkControllerPresentAndSetup;\nvar emitIfAxesChanged = trackedControlsUtils.emitIfAxesChanged;\nvar onButtonEvent = trackedControlsUtils.onButtonEvent;\n\n// See Profiles Registry:\n// https://github.com/immersive-web/webxr-input-profiles/tree/master/packages/registry\n// TODO: Add a more robust system for deriving gamepad name.\nvar GAMEPAD_ID_PREFIX = 'magicleap';\nvar GAMEPAD_ID_SUFFIX = '-one';\nvar GAMEPAD_ID_COMPOSITE = GAMEPAD_ID_PREFIX + GAMEPAD_ID_SUFFIX;\nvar AFRAME_CDN_ROOT = (__webpack_require__(/*! ../constants */ \"./src/constants/index.js\").AFRAME_CDN_ROOT);\nvar MAGICLEAP_CONTROLLER_MODEL_GLB_URL = AFRAME_CDN_ROOT + 'controllers/magicleap/magicleap-one-controller.glb';\n\n/**\n * Button IDs:\n * 0 - trigger\n * 1 - grip\n * 2 - touchpad\n * 3 - menu (never dispatched on this layer)\n *\n * Axis:\n * 0 - touchpad x axis\n * 1 - touchpad y axis\n */\nvar INPUT_MAPPING_WEBXR = {\n axes: {\n touchpad: [0, 1]\n },\n buttons: ['trigger', 'grip', 'touchpad', 'menu']\n};\n\n/**\n * Magic Leap Controls\n * Interface with Magic Leap control and map Gamepad events to controller\n * buttons: trigger, grip, touchpad, and menu.\n * Load a controller model.\n */\nmodule.exports.Component = registerComponent('magicleap-controls', {\n schema: {\n hand: {\n default: 'none'\n },\n model: {\n default: true\n },\n orientationOffset: {\n type: 'vec3'\n }\n },\n mapping: INPUT_MAPPING_WEBXR,\n init: function () {\n var self = this;\n this.controllerPresent = false;\n this.lastControllerCheck = 0;\n this.onButtonChanged = this.onButtonChanged.bind(this);\n this.onButtonDown = function (evt) {\n onButtonEvent(evt.detail.id, 'down', self);\n };\n this.onButtonUp = function (evt) {\n onButtonEvent(evt.detail.id, 'up', self);\n };\n this.onButtonTouchEnd = function (evt) {\n onButtonEvent(evt.detail.id, 'touchend', self);\n };\n this.onButtonTouchStart = function (evt) {\n onButtonEvent(evt.detail.id, 'touchstart', self);\n };\n this.previousButtonValues = {};\n this.bindMethods();\n },\n update: function () {\n var data = this.data;\n this.controllerIndex = data.hand === 'right' ? 0 : data.hand === 'left' ? 1 : 2;\n },\n play: function () {\n this.checkIfControllerPresent();\n this.addControllersUpdateListener();\n },\n pause: function () {\n this.removeEventListeners();\n this.removeControllersUpdateListener();\n },\n bindMethods: function () {\n this.onModelLoaded = this.onModelLoaded.bind(this);\n this.onControllersUpdate = this.onControllersUpdate.bind(this);\n this.checkIfControllerPresent = this.checkIfControllerPresent.bind(this);\n this.removeControllersUpdateListener = this.removeControllersUpdateListener.bind(this);\n this.onAxisMoved = this.onAxisMoved.bind(this);\n },\n addEventListeners: function () {\n var el = this.el;\n el.addEventListener('buttonchanged', this.onButtonChanged);\n el.addEventListener('buttondown', this.onButtonDown);\n el.addEventListener('buttonup', this.onButtonUp);\n el.addEventListener('touchstart', this.onButtonTouchStart);\n el.addEventListener('touchend', this.onButtonTouchEnd);\n el.addEventListener('axismove', this.onAxisMoved);\n el.addEventListener('model-loaded', this.onModelLoaded);\n this.controllerEventsActive = true;\n },\n removeEventListeners: function () {\n var el = this.el;\n el.removeEventListener('buttonchanged', this.onButtonChanged);\n el.removeEventListener('buttondown', this.onButtonDown);\n el.removeEventListener('buttonup', this.onButtonUp);\n el.removeEventListener('touchstart', this.onButtonTouchStart);\n el.removeEventListener('touchend', this.onButtonTouchEnd);\n el.removeEventListener('axismove', this.onAxisMoved);\n el.removeEventListener('model-loaded', this.onModelLoaded);\n this.controllerEventsActive = false;\n },\n checkIfControllerPresent: function () {\n var data = this.data;\n checkControllerPresentAndSetup(this, GAMEPAD_ID_COMPOSITE, {\n index: this.controllerIndex,\n hand: data.hand\n });\n },\n injectTrackedControls: function () {\n var el = this.el;\n var data = this.data;\n el.setAttribute('tracked-controls', {\n // TODO: verify expected behavior between reserved prefixes.\n idPrefix: GAMEPAD_ID_COMPOSITE,\n hand: data.hand,\n controller: this.controllerIndex,\n orientationOffset: data.orientationOffset\n });\n\n // Load model.\n if (!this.data.model) {\n return;\n }\n this.el.setAttribute('gltf-model', MAGICLEAP_CONTROLLER_MODEL_GLB_URL);\n },\n addControllersUpdateListener: function () {\n this.el.sceneEl.addEventListener('controllersupdated', this.onControllersUpdate, false);\n },\n removeControllersUpdateListener: function () {\n this.el.sceneEl.removeEventListener('controllersupdated', this.onControllersUpdate, false);\n },\n onControllersUpdate: function () {\n // Note that due to gamepadconnected event propagation issues, we don't rely on events.\n this.checkIfControllerPresent();\n },\n /**\n * Rotate the trigger button based on how hard the trigger is pressed.\n */\n onButtonChanged: function (evt) {\n var button = this.mapping.buttons[evt.detail.id];\n var analogValue;\n if (!button) {\n return;\n }\n if (button === 'trigger') {\n analogValue = evt.detail.state.value;\n console.log('analog value of trigger press: ' + analogValue);\n }\n\n // Pass along changed event with button state, using button mapping for convenience.\n this.el.emit(button + 'changed', evt.detail.state);\n },\n onModelLoaded: function (evt) {\n var controllerObject3D = evt.detail.model;\n // our glb scale is too large.\n controllerObject3D.scale.set(0.01, 0.01, 0.01);\n },\n onAxisMoved: function (evt) {\n emitIfAxesChanged(this, this.mapping.axes, evt);\n },\n updateModel: function (buttonName, evtName) {},\n setButtonColor: function (buttonName, color) {}\n});\n\n/***/ }),\n\n/***/ \"./src/components/material.js\":\n/*!************************************!*\\\n !*** ./src/components/material.js ***!\n \\************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\n/* global Promise */\nvar utils = __webpack_require__(/*! ../utils/ */ \"./src/utils/index.js\");\nvar component = __webpack_require__(/*! ../core/component */ \"./src/core/component.js\");\nvar THREE = __webpack_require__(/*! ../lib/three */ \"./src/lib/three.js\");\nvar shader = __webpack_require__(/*! ../core/shader */ \"./src/core/shader.js\");\nvar error = utils.debug('components:material:error');\nvar registerComponent = component.registerComponent;\nvar shaders = shader.shaders;\nvar shaderNames = shader.shaderNames;\n\n/**\n * Material component.\n *\n * @member {object} shader - Determines how material is shaded. Defaults to `standard`,\n * three.js's implementation of PBR. Another standard shading model is `flat` which\n * uses MeshBasicMaterial.\n */\nmodule.exports.Component = registerComponent('material', {\n schema: {\n alphaTest: {\n default: 0.0,\n min: 0.0,\n max: 1.0\n },\n depthTest: {\n default: true\n },\n depthWrite: {\n default: true\n },\n flatShading: {\n default: false\n },\n npot: {\n default: false\n },\n offset: {\n type: 'vec2',\n default: {\n x: 0,\n y: 0\n }\n },\n opacity: {\n default: 1.0,\n min: 0.0,\n max: 1.0\n },\n repeat: {\n type: 'vec2',\n default: {\n x: 1,\n y: 1\n }\n },\n shader: {\n default: 'standard',\n oneOf: shaderNames,\n schemaChange: true\n },\n side: {\n default: 'front',\n oneOf: ['front', 'back', 'double']\n },\n transparent: {\n default: false\n },\n vertexColorsEnabled: {\n default: false\n },\n visible: {\n default: true\n },\n blending: {\n default: 'normal',\n oneOf: ['none', 'normal', 'additive', 'subtractive', 'multiply']\n },\n dithering: {\n default: true\n },\n anisotropy: {\n default: 0,\n min: 0\n }\n },\n init: function () {\n this.material = null;\n },\n /**\n * Update or create material.\n *\n * @param {object|null} oldData\n */\n update: function (oldData) {\n var data = this.data;\n if (!this.shader || data.shader !== oldData.shader) {\n this.updateShader(data.shader);\n }\n this.shader.update(this.data);\n this.updateMaterial(oldData);\n },\n updateSchema: function (data) {\n var currentShader;\n var newShader;\n var schema;\n var shader;\n newShader = data && data.shader;\n currentShader = this.oldData && this.oldData.shader;\n shader = newShader || currentShader;\n schema = shaders[shader] && shaders[shader].schema;\n if (!schema) {\n error('Unknown shader schema ' + shader);\n }\n if (currentShader && newShader === currentShader) {\n return;\n }\n this.extendSchema(schema);\n this.updateBehavior();\n },\n updateBehavior: function () {\n var key;\n var sceneEl = this.el.sceneEl;\n var schema = this.schema;\n var self = this;\n var tickProperties;\n function tickTime(time, delta) {\n var key;\n for (key in tickProperties) {\n tickProperties[key] = time;\n }\n self.shader.update(tickProperties);\n }\n this.tick = undefined;\n tickProperties = {};\n for (key in schema) {\n if (schema[key].type === 'time') {\n this.tick = tickTime;\n tickProperties[key] = true;\n }\n }\n if (!sceneEl) {\n return;\n }\n if (this.tick) {\n sceneEl.addBehavior(this);\n } else {\n sceneEl.removeBehavior(this);\n }\n },\n updateShader: function (shaderName) {\n var data = this.data;\n var Shader = shaders[shaderName] && shaders[shaderName].Shader;\n var shaderInstance;\n if (!Shader) {\n throw new Error('Unknown shader ' + shaderName);\n }\n\n // Get material from A-Frame shader.\n shaderInstance = this.shader = new Shader();\n shaderInstance.el = this.el;\n shaderInstance.init(data);\n this.setMaterial(shaderInstance.material);\n this.updateSchema(data);\n },\n /**\n * Set and update base material properties.\n * Set `needsUpdate` when needed.\n */\n updateMaterial: function (oldData) {\n var data = this.data;\n var material = this.material;\n var oldDataHasKeys;\n\n // Base material properties.\n material.alphaTest = data.alphaTest;\n material.depthTest = data.depthTest !== false;\n material.depthWrite = data.depthWrite !== false;\n material.opacity = data.opacity;\n material.flatShading = data.flatShading;\n material.side = parseSide(data.side);\n material.transparent = data.transparent !== false || data.opacity < 1.0;\n material.vertexColors = data.vertexColorsEnabled;\n material.visible = data.visible;\n material.blending = parseBlending(data.blending);\n material.dithering = data.dithering;\n\n // Check if material needs update.\n for (oldDataHasKeys in oldData) {\n break;\n }\n if (oldDataHasKeys && (oldData.alphaTest !== data.alphaTest || oldData.side !== data.side || oldData.vertexColorsEnabled !== data.vertexColorsEnabled)) {\n material.needsUpdate = true;\n }\n },\n /**\n * Remove material on remove (callback).\n * Dispose of it from memory and unsubscribe from scene updates.\n */\n remove: function () {\n var defaultMaterial = new THREE.MeshBasicMaterial();\n var material = this.material;\n var object3D = this.el.getObject3D('mesh');\n if (object3D) {\n object3D.material = defaultMaterial;\n }\n disposeMaterial(material, this.system);\n },\n /**\n * (Re)create new material. Has side-effects of setting `this.material` and updating\n * material registration in scene.\n *\n * @param {object} data - Material component data.\n * @param {object} type - Material type to create.\n * @returns {object} Material.\n */\n setMaterial: function (material) {\n var el = this.el;\n var mesh;\n var system = this.system;\n if (this.material) {\n disposeMaterial(this.material, system);\n }\n this.material = material;\n system.registerMaterial(material);\n\n // Set on mesh. If mesh does not exist, wait for it.\n mesh = el.getObject3D('mesh');\n if (mesh) {\n mesh.material = material;\n } else {\n el.addEventListener('object3dset', function waitForMesh(evt) {\n if (evt.detail.type !== 'mesh' || evt.target !== el) {\n return;\n }\n el.getObject3D('mesh').material = material;\n el.removeEventListener('object3dset', waitForMesh);\n });\n }\n }\n});\n\n/**\n * Return a three.js constant determining which material face sides to render\n * based on the side parameter (passed as a component property).\n *\n * @param {string} [side=front] - `front`, `back`, or `double`.\n * @returns {number} THREE.FrontSide, THREE.BackSide, or THREE.DoubleSide.\n */\nfunction parseSide(side) {\n switch (side) {\n case 'back':\n {\n return THREE.BackSide;\n }\n case 'double':\n {\n return THREE.DoubleSide;\n }\n default:\n {\n // Including case `front`.\n return THREE.FrontSide;\n }\n }\n}\n\n/**\n * Return a three.js constant determining blending\n *\n * @param {string} [blending=normal]\n * - `none`, additive`, `subtractive`,`multiply` or `normal`.\n * @returns {number}\n */\nfunction parseBlending(blending) {\n switch (blending) {\n case 'none':\n {\n return THREE.NoBlending;\n }\n case 'additive':\n {\n return THREE.AdditiveBlending;\n }\n case 'subtractive':\n {\n return THREE.SubtractiveBlending;\n }\n case 'multiply':\n {\n return THREE.MultiplyBlending;\n }\n default:\n {\n return THREE.NormalBlending;\n }\n }\n}\n\n/**\n * Dispose of material from memory and unsubscribe material from scene updates like fog.\n */\nfunction disposeMaterial(material, system) {\n material.dispose();\n system.unregisterMaterial(material);\n\n // Dispose textures on this material\n Object.keys(material).filter(function (propName) {\n return material[propName] && material[propName].isTexture;\n }).forEach(function (mapName) {\n material[mapName].dispose();\n });\n}\n\n/***/ }),\n\n/***/ \"./src/components/obb-collider.js\":\n/*!****************************************!*\\\n !*** ./src/components/obb-collider.js ***!\n \\****************************************/\n/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {\n\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar THREE = __webpack_require__(/*! ../lib/three */ \"./src/lib/three.js\");\nregisterComponent('obb-collider', {\n schema: {\n size: {\n default: 0\n },\n trackedObject3D: {\n default: ''\n },\n minimumColliderDimension: {\n default: 0.02\n },\n centerModel: {\n default: false\n }\n },\n init: function () {\n this.previousScale = new THREE.Vector3().copy(this.el.object3D.scale);\n this.auxEuler = new THREE.Euler();\n this.boundingBox = new THREE.Box3();\n this.boundingBoxSize = new THREE.Vector3();\n this.updateCollider = this.updateCollider.bind(this);\n this.onModelLoaded = this.onModelLoaded.bind(this);\n this.updateBoundingBox = this.updateBoundingBox.bind(this);\n this.el.addEventListener('model-loaded', this.onModelLoaded);\n this.updateCollider();\n this.system.addCollider(this.el);\n },\n remove: function () {\n this.system.removeCollider(this.el);\n },\n update: function () {\n if (this.data.trackedObject3D) {\n this.trackedObject3DPath = this.data.trackedObject3D.split('.');\n }\n },\n onModelLoaded: function () {\n if (this.data.centerModel) {\n this.centerModel();\n }\n this.updateCollider();\n },\n centerModel: function () {\n var el = this.el;\n var model = el.components['gltf-model'] && el.components['gltf-model'].model;\n var box;\n var center;\n if (!model) {\n return;\n }\n this.el.removeObject3D('mesh');\n box = new THREE.Box3().setFromObject(model);\n center = box.getCenter(new THREE.Vector3());\n model.position.x += model.position.x - center.x;\n model.position.y += model.position.y - center.y;\n model.position.z += model.position.z - center.z;\n this.el.setObject3D('mesh', model);\n },\n updateCollider: function () {\n var el = this.el;\n var boundingBoxSize = this.boundingBoxSize;\n var aabb = this.aabb = this.aabb || new THREE.OBB();\n this.obb = this.obb || new THREE.OBB();\n\n // Defer if entity has not yet loaded.\n if (!el.hasLoaded) {\n el.addEventListener('loaded', this.updateCollider);\n return;\n }\n this.updateBoundingBox();\n aabb.halfSize.copy(boundingBoxSize).multiplyScalar(0.5);\n if (this.el.sceneEl.systems['obb-collider'].data.showColliders) {\n this.showCollider();\n }\n },\n showCollider: function () {\n this.updateColliderMesh();\n this.renderColliderMesh.visible = true;\n },\n updateColliderMesh: function () {\n var renderColliderMesh = this.renderColliderMesh;\n var boundingBoxSize = this.boundingBoxSize;\n if (!renderColliderMesh) {\n this.initColliderMesh();\n return;\n }\n\n // Destroy current geometry.\n renderColliderMesh.geometry.dispose();\n renderColliderMesh.geometry = new THREE.BoxGeometry(boundingBoxSize.x, boundingBoxSize.y, boundingBoxSize.z);\n },\n hideCollider: function () {\n if (!this.renderColliderMesh) {\n return;\n }\n this.renderColliderMesh.visible = false;\n },\n initColliderMesh: function () {\n var boundingBoxSize;\n var renderColliderGeometry;\n var renderColliderMesh;\n boundingBoxSize = this.boundingBoxSize;\n renderColliderGeometry = this.renderColliderGeometry = new THREE.BoxGeometry(boundingBoxSize.x, boundingBoxSize.y, boundingBoxSize.z);\n renderColliderMesh = this.renderColliderMesh = new THREE.Mesh(renderColliderGeometry, new THREE.MeshLambertMaterial({\n color: 0x00ff00,\n side: THREE.DoubleSide\n }));\n renderColliderMesh.matrixAutoUpdate = false;\n renderColliderMesh.matrixWorldAutoUpdate = false;\n // THREE scene forces matrix world update even if matrixWorldAutoUpdate set to false.\n renderColliderMesh.updateMatrixWorld = function () {/* no op */};\n this.el.sceneEl.object3D.add(renderColliderMesh);\n },\n updateBoundingBox: function () {\n var auxPosition = new THREE.Vector3();\n var auxScale = new THREE.Vector3();\n var auxQuaternion = new THREE.Quaternion();\n var identityQuaternion = new THREE.Quaternion();\n var auxMatrix = new THREE.Matrix4();\n return function () {\n var auxEuler = this.auxEuler;\n var boundingBox = this.boundingBox;\n var size = this.data.size;\n var trackedObject3D = this.trackedObject3D || this.el.object3D;\n var boundingBoxSize = this.boundingBoxSize;\n var minimumColliderDimension = this.data.minimumColliderDimension;\n\n // user defined size takes precedence.\n if (size) {\n this.boundingBoxSize.x = size;\n this.boundingBoxSize.y = size;\n this.boundingBoxSize.z = size;\n return;\n }\n\n // Bounding box is created axis-aligned AABB.\n // If there's any rotation the box will have the wrong size.\n // It undoes the local entity rotation and then restores so box has the expected size.\n // We also undo the parent world rotation.\n auxEuler.copy(trackedObject3D.rotation);\n trackedObject3D.rotation.set(0, 0, 0);\n trackedObject3D.parent.matrixWorld.decompose(auxPosition, auxQuaternion, auxScale);\n auxMatrix.compose(auxPosition, identityQuaternion, auxScale);\n trackedObject3D.parent.matrixWorld.copy(auxMatrix);\n\n // Calculate bounding box size.\n boundingBox.setFromObject(trackedObject3D, true);\n boundingBox.getSize(boundingBoxSize);\n\n // Enforce minimum dimensions.\n boundingBoxSize.x = boundingBoxSize.x < minimumColliderDimension ? minimumColliderDimension : boundingBoxSize.x;\n boundingBoxSize.y = boundingBoxSize.y < minimumColliderDimension ? minimumColliderDimension : boundingBoxSize.y;\n boundingBoxSize.z = boundingBoxSize.z < minimumColliderDimension ? minimumColliderDimension : boundingBoxSize.z;\n\n // Restore rotations.\n trackedObject3D.parent.matrixWorld.compose(auxPosition, auxQuaternion, auxScale);\n this.el.object3D.rotation.copy(auxEuler);\n };\n }(),\n checkTrackedObject: function () {\n var trackedObject3DPath = this.trackedObject3DPath;\n var trackedObject3D;\n if (trackedObject3DPath && trackedObject3DPath.length && !this.trackedObject3D) {\n trackedObject3D = this.el;\n for (var i = 0; i < trackedObject3DPath.length; i++) {\n trackedObject3D = trackedObject3D[trackedObject3DPath[i]];\n if (!trackedObject3D) {\n break;\n }\n }\n if (trackedObject3D) {\n this.trackedObject3D = trackedObject3D;\n this.updateCollider();\n }\n }\n return this.trackedObject3D;\n },\n tick: function () {\n var auxPosition = new THREE.Vector3();\n var auxScale = new THREE.Vector3();\n var auxQuaternion = new THREE.Quaternion();\n var auxMatrix = new THREE.Matrix4();\n return function () {\n var obb = this.obb;\n var renderColliderMesh = this.renderColliderMesh;\n var trackedObject3D = this.checkTrackedObject() || this.el.object3D;\n if (!trackedObject3D) {\n return;\n }\n trackedObject3D.updateMatrix();\n trackedObject3D.updateMatrixWorld(true);\n trackedObject3D.matrixWorld.decompose(auxPosition, auxQuaternion, auxScale);\n\n // Recalculate collider if scale has changed.\n if (Math.abs(auxScale.x - this.previousScale.x) > 0.0001 || Math.abs(auxScale.y - this.previousScale.y) > 0.0001 || Math.abs(auxScale.z - this.previousScale.z) > 0.0001) {\n this.updateCollider();\n }\n this.previousScale.copy(auxScale);\n\n // reset scale, keep position and rotation\n auxScale.set(1, 1, 1);\n auxMatrix.compose(auxPosition, auxQuaternion, auxScale);\n // Update OBB visual representation.\n if (renderColliderMesh) {\n renderColliderMesh.matrixWorld.copy(auxMatrix);\n }\n\n // Reset OBB with AABB and apply entity matrix. applyMatrix4 changes OBB internal state.\n obb.copy(this.aabb);\n obb.applyMatrix4(auxMatrix);\n };\n }()\n});\n\n/***/ }),\n\n/***/ \"./src/components/obj-model.js\":\n/*!*************************************!*\\\n !*** ./src/components/obj-model.js ***!\n \\*************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar debug = __webpack_require__(/*! ../utils/debug */ \"./src/utils/debug.js\");\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar THREE = __webpack_require__(/*! ../lib/three */ \"./src/lib/three.js\");\nvar warn = debug('components:obj-model:warn');\nmodule.exports.Component = registerComponent('obj-model', {\n schema: {\n mtl: {\n type: 'model'\n },\n obj: {\n type: 'model'\n }\n },\n init: function () {\n var self = this;\n this.model = null;\n this.objLoader = new THREE.OBJLoader();\n this.mtlLoader = new THREE.MTLLoader(this.objLoader.manager);\n // Allow cross-origin images to be loaded.\n this.mtlLoader.crossOrigin = '';\n this.el.addEventListener('componentinitialized', function (evt) {\n if (!self.model) {\n return;\n }\n if (evt.detail.name !== 'material') {\n return;\n }\n self.applyMaterial();\n });\n },\n update: function () {\n var data = this.data;\n if (!data.obj) {\n return;\n }\n this.resetMesh();\n this.loadObj(data.obj, data.mtl);\n },\n remove: function () {\n this.resetMesh();\n },\n resetMesh: function () {\n if (!this.model) {\n return;\n }\n this.el.removeObject3D('mesh');\n },\n loadObj: function (objUrl, mtlUrl) {\n var self = this;\n var el = this.el;\n var mtlLoader = this.mtlLoader;\n var objLoader = this.objLoader;\n var rendererSystem = this.el.sceneEl.systems.renderer;\n var BASE_PATH = mtlUrl.substr(0, mtlUrl.lastIndexOf('/') + 1);\n if (mtlUrl) {\n // .OBJ with an .MTL.\n if (el.hasAttribute('material')) {\n warn('Material component properties are ignored when a .MTL is provided');\n }\n mtlLoader.setResourcePath(BASE_PATH);\n mtlLoader.load(mtlUrl, function (materials) {\n materials.preload();\n objLoader.setMaterials(materials);\n objLoader.load(objUrl, function (objModel) {\n self.model = objModel;\n self.model.traverse(function (object) {\n if (object.isMesh) {\n var material = object.material;\n if (material.map) rendererSystem.applyColorCorrection(material.map);\n if (material.emissiveMap) rendererSystem.applyColorCorrection(material.emissiveMap);\n }\n });\n el.setObject3D('mesh', objModel);\n el.emit('model-loaded', {\n format: 'obj',\n model: objModel\n });\n });\n });\n return;\n }\n\n // .OBJ only.\n objLoader.load(objUrl, function loadObjOnly(objModel) {\n self.model = objModel;\n self.applyMaterial();\n el.setObject3D('mesh', objModel);\n el.emit('model-loaded', {\n format: 'obj',\n model: objModel\n });\n });\n },\n /**\n * Apply material from material component recursively.\n */\n applyMaterial: function () {\n var material = this.el.components.material;\n if (!material) {\n return;\n }\n this.model.traverse(function (child) {\n if (child instanceof THREE.Mesh) {\n child.material = material.material;\n }\n });\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/oculus-go-controls.js\":\n/*!**********************************************!*\\\n !*** ./src/components/oculus-go-controls.js ***!\n \\**********************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar trackedControlsUtils = __webpack_require__(/*! ../utils/tracked-controls */ \"./src/utils/tracked-controls.js\");\nvar checkControllerPresentAndSetup = trackedControlsUtils.checkControllerPresentAndSetup;\nvar emitIfAxesChanged = trackedControlsUtils.emitIfAxesChanged;\nvar onButtonEvent = trackedControlsUtils.onButtonEvent;\nvar isWebXRAvailable = (__webpack_require__(/*! ../utils/ */ \"./src/utils/index.js\").device.isWebXRAvailable);\nvar GAMEPAD_ID_WEBXR = 'oculus-go';\nvar GAMEPAD_ID_WEBVR = 'Oculus Go';\nvar AFRAME_CDN_ROOT = (__webpack_require__(/*! ../constants */ \"./src/constants/index.js\").AFRAME_CDN_ROOT);\nvar OCULUS_GO_CONTROLLER_MODEL_URL = AFRAME_CDN_ROOT + 'controllers/oculus/go/oculus-go-controller.gltf';\n\n// Prefix for Gen1 and Gen2 Oculus Touch Controllers.\nvar GAMEPAD_ID_PREFIX = isWebXRAvailable ? GAMEPAD_ID_WEBXR : GAMEPAD_ID_WEBVR;\n\n/**\n * Button indices:\n * 0 - trackpad\n * 1 - trigger\n *\n * Axis:\n * 0 - trackpad x\n * 1 - trackpad y\n */\nvar INPUT_MAPPING_WEBVR = {\n axes: {\n trackpad: [0, 1]\n },\n buttons: ['trackpad', 'trigger']\n};\n\n/**\n * Button indices:\n * 0 - trigger\n * 1 - none\n * 2 - touchpad\n *\n * Axis:\n * 0 - touchpad x\n * 1 - touchpad y\n * Reference: https://github.com/immersive-web/webxr-input-profiles/blob/master/packages/registry/profiles/oculus/oculus-go.json\n */\nvar INPUT_MAPPING_WEBXR = {\n axes: {\n touchpad: [0, 1]\n },\n buttons: ['trigger', 'none', 'touchpad']\n};\nvar INPUT_MAPPING = isWebXRAvailable ? INPUT_MAPPING_WEBXR : INPUT_MAPPING_WEBVR;\n\n/**\n * Oculus Go controls.\n * Interface with Oculus Go controller and map Gamepad events to\n * controller buttons: trackpad, trigger\n * Load a controller model and highlight the pressed buttons.\n */\nmodule.exports.Component = registerComponent('oculus-go-controls', {\n schema: {\n hand: {\n default: ''\n },\n // This informs the degenerate arm model.\n buttonColor: {\n type: 'color',\n default: '#FFFFFF'\n },\n buttonTouchedColor: {\n type: 'color',\n default: '#BBBBBB'\n },\n buttonHighlightColor: {\n type: 'color',\n default: '#7A7A7A'\n },\n model: {\n default: true\n },\n orientationOffset: {\n type: 'vec3'\n },\n armModel: {\n default: true\n }\n },\n mapping: INPUT_MAPPING,\n bindMethods: function () {\n this.onModelLoaded = this.onModelLoaded.bind(this);\n this.onControllersUpdate = this.onControllersUpdate.bind(this);\n this.checkIfControllerPresent = this.checkIfControllerPresent.bind(this);\n this.removeControllersUpdateListener = this.removeControllersUpdateListener.bind(this);\n this.onAxisMoved = this.onAxisMoved.bind(this);\n },\n init: function () {\n var self = this;\n this.onButtonChanged = this.onButtonChanged.bind(this);\n this.onButtonDown = function (evt) {\n onButtonEvent(evt.detail.id, 'down', self);\n };\n this.onButtonUp = function (evt) {\n onButtonEvent(evt.detail.id, 'up', self);\n };\n this.onButtonTouchStart = function (evt) {\n onButtonEvent(evt.detail.id, 'touchstart', self);\n };\n this.onButtonTouchEnd = function (evt) {\n onButtonEvent(evt.detail.id, 'touchend', self);\n };\n this.controllerPresent = false;\n this.lastControllerCheck = 0;\n this.bindMethods();\n },\n addEventListeners: function () {\n var el = this.el;\n el.addEventListener('buttonchanged', this.onButtonChanged);\n el.addEventListener('buttondown', this.onButtonDown);\n el.addEventListener('buttonup', this.onButtonUp);\n el.addEventListener('touchstart', this.onButtonTouchStart);\n el.addEventListener('touchend', this.onButtonTouchEnd);\n el.addEventListener('model-loaded', this.onModelLoaded);\n el.addEventListener('axismove', this.onAxisMoved);\n this.controllerEventsActive = true;\n },\n removeEventListeners: function () {\n var el = this.el;\n el.removeEventListener('buttonchanged', this.onButtonChanged);\n el.removeEventListener('buttondown', this.onButtonDown);\n el.removeEventListener('buttonup', this.onButtonUp);\n el.removeEventListener('touchstart', this.onButtonTouchStart);\n el.removeEventListener('touchend', this.onButtonTouchEnd);\n el.removeEventListener('model-loaded', this.onModelLoaded);\n el.removeEventListener('axismove', this.onAxisMoved);\n this.controllerEventsActive = false;\n },\n checkIfControllerPresent: function () {\n checkControllerPresentAndSetup(this, GAMEPAD_ID_PREFIX, this.data.hand ? {\n hand: this.data.hand\n } : {});\n },\n play: function () {\n this.checkIfControllerPresent();\n this.addControllersUpdateListener();\n },\n pause: function () {\n this.removeEventListeners();\n this.removeControllersUpdateListener();\n },\n injectTrackedControls: function () {\n var el = this.el;\n var data = this.data;\n el.setAttribute('tracked-controls', {\n armModel: data.armModel,\n hand: data.hand,\n idPrefix: GAMEPAD_ID_PREFIX,\n orientationOffset: data.orientationOffset\n });\n if (!this.data.model) {\n return;\n }\n this.el.setAttribute('gltf-model', OCULUS_GO_CONTROLLER_MODEL_URL);\n },\n addControllersUpdateListener: function () {\n this.el.sceneEl.addEventListener('controllersupdated', this.onControllersUpdate, false);\n },\n removeControllersUpdateListener: function () {\n this.el.sceneEl.removeEventListener('controllersupdated', this.onControllersUpdate, false);\n },\n onControllersUpdate: function () {\n this.checkIfControllerPresent();\n },\n // No need for onButtonChanged, since Oculus Go controller has no analog buttons.\n\n onModelLoaded: function (evt) {\n var controllerObject3D = evt.detail.model;\n var buttonMeshes;\n if (evt.target !== this.el || !this.data.model) {\n return;\n }\n buttonMeshes = this.buttonMeshes = {};\n buttonMeshes.trigger = controllerObject3D.getObjectByName('oculus_go_button_trigger');\n buttonMeshes.trackpad = controllerObject3D.getObjectByName('oculus_go_touchpad');\n buttonMeshes.touchpad = controllerObject3D.getObjectByName('oculus_go_touchpad');\n },\n onButtonChanged: function (evt) {\n var button = this.mapping.buttons[evt.detail.id];\n if (!button) return;\n // Pass along changed event with button state, using button mapping for convenience.\n this.el.emit(button + 'changed', evt.detail.state);\n },\n onAxisMoved: function (evt) {\n emitIfAxesChanged(this, this.mapping.axes, evt);\n },\n updateModel: function (buttonName, evtName) {\n if (!this.data.model) {\n return;\n }\n this.updateButtonModel(buttonName, evtName);\n },\n updateButtonModel: function (buttonName, state) {\n var buttonMeshes = this.buttonMeshes;\n if (!buttonMeshes || !buttonMeshes[buttonName]) {\n return;\n }\n var color;\n var button;\n switch (state) {\n case 'down':\n color = this.data.buttonHighlightColor;\n break;\n case 'touchstart':\n color = this.data.buttonTouchedColor;\n break;\n default:\n color = this.data.buttonColor;\n }\n button = buttonMeshes[buttonName];\n button.material.color.set(color);\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/oculus-touch-controls.js\":\n/*!*************************************************!*\\\n !*** ./src/components/oculus-touch-controls.js ***!\n \\*************************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar THREE = __webpack_require__(/*! ../lib/three */ \"./src/lib/three.js\");\nvar trackedControlsUtils = __webpack_require__(/*! ../utils/tracked-controls */ \"./src/utils/tracked-controls.js\");\nvar checkControllerPresentAndSetup = trackedControlsUtils.checkControllerPresentAndSetup;\nvar emitIfAxesChanged = trackedControlsUtils.emitIfAxesChanged;\nvar onButtonEvent = trackedControlsUtils.onButtonEvent;\nvar isWebXRAvailable = (__webpack_require__(/*! ../utils/ */ \"./src/utils/index.js\").device.isWebXRAvailable);\nvar GAMEPAD_ID_WEBXR = 'oculus-touch';\nvar GAMEPAD_ID_WEBVR = 'Oculus Touch';\n\n// Prefix for Gen1 and Gen2 Oculus Touch Controllers.\nvar GAMEPAD_ID_PREFIX = isWebXRAvailable ? GAMEPAD_ID_WEBXR : GAMEPAD_ID_WEBVR;\n\n// First generation model URL.\nvar AFRAME_CDN_ROOT = (__webpack_require__(/*! ../constants */ \"./src/constants/index.js\").AFRAME_CDN_ROOT);\nvar TOUCH_CONTROLLER_MODEL_BASE_URL = AFRAME_CDN_ROOT + 'controllers/oculus/oculus-touch-controller-';\nvar META_CONTROLLER_MODEL_BASE_URL = AFRAME_CDN_ROOT + 'controllers/meta/';\nvar OCULUS_TOUCH_WEBVR = {\n left: {\n modelUrl: TOUCH_CONTROLLER_MODEL_BASE_URL + 'left.gltf',\n rayOrigin: {\n origin: {\n x: 0.008,\n y: -0.01,\n z: 0\n },\n direction: {\n x: 0,\n y: -0.8,\n z: -1\n }\n },\n modelPivotOffset: new THREE.Vector3(-0.005, 0.003, -0.055),\n modelPivotRotation: new THREE.Euler(0, 0, 0)\n },\n right: {\n modelUrl: TOUCH_CONTROLLER_MODEL_BASE_URL + 'right.gltf',\n rayOrigin: {\n origin: {\n x: -0.008,\n y: -0.01,\n z: 0\n },\n direction: {\n x: 0,\n y: -0.8,\n z: -1\n }\n },\n modelPivotOffset: new THREE.Vector3(0.005, 0.003, -0.055),\n modelPivotRotation: new THREE.Euler(0, 0, 0)\n }\n};\nvar OCULUS_TOUCH_WEBXR = {\n left: {\n modelUrl: TOUCH_CONTROLLER_MODEL_BASE_URL + 'left.gltf',\n rayOrigin: {\n origin: {\n x: 0.002,\n y: -0.005,\n z: -0.03\n },\n direction: {\n x: 0,\n y: -0.8,\n z: -1\n }\n },\n modelPivotOffset: new THREE.Vector3(-0.005, 0.036, -0.037),\n modelPivotRotation: new THREE.Euler(Math.PI / 4.5, 0, 0)\n },\n right: {\n modelUrl: TOUCH_CONTROLLER_MODEL_BASE_URL + 'right.gltf',\n rayOrigin: {\n origin: {\n x: -0.002,\n y: -0.005,\n z: -0.03\n },\n direction: {\n x: 0,\n y: -0.8,\n z: -1\n }\n },\n modelPivotOffset: new THREE.Vector3(0.005, 0.036, -0.037),\n modelPivotRotation: new THREE.Euler(Math.PI / 4.5, 0, 0)\n }\n};\nvar OCULUS_TOUCH_CONFIG = isWebXRAvailable ? OCULUS_TOUCH_WEBXR : OCULUS_TOUCH_WEBVR;\nvar CONTROLLER_DEFAULT = 'oculus-touch';\nvar CONTROLLER_PROPERTIES = {\n 'oculus-touch': OCULUS_TOUCH_CONFIG,\n 'oculus-touch-v2': {\n left: {\n modelUrl: TOUCH_CONTROLLER_MODEL_BASE_URL + 'gen2-left.gltf',\n rayOrigin: {\n origin: {\n x: -0.006,\n y: -0.03,\n z: -0.04\n },\n direction: {\n x: 0,\n y: -0.9,\n z: -1\n }\n },\n modelPivotOffset: new THREE.Vector3(0, -0.007, -0.021),\n modelPivotRotation: new THREE.Euler(-Math.PI / 4, 0, 0)\n },\n right: {\n modelUrl: TOUCH_CONTROLLER_MODEL_BASE_URL + 'gen2-right.gltf',\n rayOrigin: {\n origin: {\n x: 0.006,\n y: -0.03,\n z: -0.04\n },\n direction: {\n x: 0,\n y: -0.9,\n z: -1\n }\n },\n modelPivotOffset: new THREE.Vector3(0, -0.007, -0.021),\n modelPivotRotation: new THREE.Euler(-Math.PI / 4, 0, 0)\n }\n },\n 'oculus-touch-v3': {\n left: {\n modelUrl: TOUCH_CONTROLLER_MODEL_BASE_URL + 'v3-left.glb',\n rayOrigin: {\n origin: {\n x: 0.0065,\n y: -0.0186,\n z: -0.05\n },\n direction: {\n x: 0.12394785839500175,\n y: -0.5944043672340157,\n z: -0.7945567170519814\n }\n },\n modelPivotOffset: new THREE.Vector3(0, 0, 0),\n modelPivotRotation: new THREE.Euler(0, 0, 0)\n },\n right: {\n modelUrl: TOUCH_CONTROLLER_MODEL_BASE_URL + 'v3-right.glb',\n rayOrigin: {\n origin: {\n x: -0.0065,\n y: -0.0186,\n z: -0.05\n },\n direction: {\n x: -0.12394785839500175,\n y: -0.5944043672340157,\n z: -0.7945567170519814\n }\n },\n modelPivotOffset: new THREE.Vector3(0, 0, 0),\n modelPivotRotation: new THREE.Euler(0, 0, 0)\n }\n },\n 'meta-quest-touch-pro': {\n left: {\n modelUrl: META_CONTROLLER_MODEL_BASE_URL + 'quest-touch-pro-left.glb',\n rayOrigin: {\n origin: {\n x: 0.0065,\n y: -0.0186,\n z: -0.05\n },\n direction: {\n x: 0.12394785839500175,\n y: -0.5944043672340157,\n z: -0.7945567170519814\n }\n },\n modelPivotOffset: new THREE.Vector3(0, 0, 0),\n modelPivotRotation: new THREE.Euler(0, 0, 0)\n },\n right: {\n modelUrl: META_CONTROLLER_MODEL_BASE_URL + 'quest-touch-pro-right.glb',\n rayOrigin: {\n origin: {\n x: -0.0065,\n y: -0.0186,\n z: -0.05\n },\n direction: {\n x: -0.12394785839500175,\n y: -0.5944043672340157,\n z: -0.7945567170519814\n }\n },\n modelPivotOffset: new THREE.Vector3(0, 0, 0),\n modelPivotRotation: new THREE.Euler(0, 0, 0)\n }\n },\n 'meta-quest-touch-plus': {\n left: {\n modelUrl: META_CONTROLLER_MODEL_BASE_URL + 'quest-touch-plus-left.glb',\n rayOrigin: {\n origin: {\n x: 0.0065,\n y: -0.0186,\n z: -0.05\n },\n direction: {\n x: 0.12394785839500175,\n y: -0.5944043672340157,\n z: -0.7945567170519814\n }\n },\n modelPivotOffset: new THREE.Vector3(0, 0, 0),\n modelPivotRotation: new THREE.Euler(0, 0, 0)\n },\n right: {\n modelUrl: META_CONTROLLER_MODEL_BASE_URL + 'quest-touch-plus-right.glb',\n rayOrigin: {\n origin: {\n x: -0.0065,\n y: -0.0186,\n z: -0.05\n },\n direction: {\n x: -0.12394785839500175,\n y: -0.5944043672340157,\n z: -0.7945567170519814\n }\n },\n modelPivotOffset: new THREE.Vector3(0, 0, 0),\n modelPivotRotation: new THREE.Euler(0, 0, 0)\n }\n }\n};\n\n/**\n * Button indices:\n * 0 - thumbstick (which has separate axismove / thumbstickmoved events)\n * 1 - trigger (with analog value, which goes up to 1)\n * 2 - grip (with analog value, which goes up to 1)\n * 3 - X (left) or A (right)\n * 4 - Y (left) or B (right)\n * 5 - surface (touch only)\n */\nvar INPUT_MAPPING_WEBVR = {\n left: {\n axes: {\n thumbstick: [0, 1]\n },\n buttons: ['thumbstick', 'trigger', 'grip', 'xbutton', 'ybutton', 'surface']\n },\n right: {\n axes: {\n thumbstick: [0, 1]\n },\n buttons: ['thumbstick', 'trigger', 'grip', 'abutton', 'bbutton', 'surface']\n }\n};\n\n/**\n * Button indices:\n * 0 - trigger\n * 1 - grip\n * 2 - none\n * 3 - thumbstick\n * 4 - X or A button\n * 5 - Y or B button\n * 6 - surface\n *\n * Axis:\n * 0 - none\n * 1 - none\n * 2 - thumbstick\n * 3 - thumbstick\n * Reference: https://github.com/immersive-web/webxr-input-profiles/blob/master/packages/registry/profiles/oculus/oculus-touch.json\n */\nvar INPUT_MAPPING_WEBXR = {\n left: {\n axes: {\n thumbstick: [2, 3]\n },\n buttons: ['trigger', 'grip', 'none', 'thumbstick', 'xbutton', 'ybutton', 'surface']\n },\n right: {\n axes: {\n thumbstick: [2, 3]\n },\n buttons: ['trigger', 'grip', 'none', 'thumbstick', 'abutton', 'bbutton', 'surface']\n }\n};\nvar INPUT_MAPPING = isWebXRAvailable ? INPUT_MAPPING_WEBXR : INPUT_MAPPING_WEBVR;\n\n/**\n * Oculus Touch controls.\n * Interface with Oculus Touch controllers and map Gamepad events to\n * controller buttons: thumbstick, trigger, grip, xbutton, ybutton, surface\n * Load a controller model and highlight the pressed buttons.\n */\nmodule.exports.Component = registerComponent('oculus-touch-controls', {\n schema: {\n hand: {\n default: 'left'\n },\n buttonColor: {\n type: 'color',\n default: '#999'\n },\n // Off-white.\n buttonTouchColor: {\n type: 'color',\n default: '#8AB'\n },\n buttonHighlightColor: {\n type: 'color',\n default: '#2DF'\n },\n // Light blue.\n model: {\n default: true\n },\n controllerType: {\n default: 'auto',\n oneOf: ['auto', 'oculus-touch', 'oculus-touch-v2', 'oculus-touch-v3']\n },\n orientationOffset: {\n type: 'vec3',\n default: {\n x: 43,\n y: 0,\n z: 0\n }\n }\n },\n after: ['tracked-controls'],\n mapping: INPUT_MAPPING,\n bindMethods: function () {\n this.onButtonChanged = this.onButtonChanged.bind(this);\n this.onThumbstickMoved = this.onThumbstickMoved.bind(this);\n this.onModelLoaded = this.onModelLoaded.bind(this);\n this.onControllersUpdate = this.onControllersUpdate.bind(this);\n this.checkIfControllerPresent = this.checkIfControllerPresent.bind(this);\n this.onAxisMoved = this.onAxisMoved.bind(this);\n },\n init: function () {\n var self = this;\n this.onButtonDown = function (evt) {\n onButtonEvent(evt.detail.id, 'down', self, self.data.hand);\n };\n this.onButtonUp = function (evt) {\n onButtonEvent(evt.detail.id, 'up', self, self.data.hand);\n };\n this.onButtonTouchStart = function (evt) {\n onButtonEvent(evt.detail.id, 'touchstart', self, self.data.hand);\n };\n this.onButtonTouchEnd = function (evt) {\n onButtonEvent(evt.detail.id, 'touchend', self, self.data.hand);\n };\n this.controllerPresent = false;\n this.lastControllerCheck = 0;\n this.previousButtonValues = {};\n this.bindMethods();\n this.triggerEuler = new THREE.Euler();\n },\n addEventListeners: function () {\n var el = this.el;\n el.addEventListener('buttonchanged', this.onButtonChanged);\n el.addEventListener('buttondown', this.onButtonDown);\n el.addEventListener('buttonup', this.onButtonUp);\n el.addEventListener('touchstart', this.onButtonTouchStart);\n el.addEventListener('touchend', this.onButtonTouchEnd);\n el.addEventListener('axismove', this.onAxisMoved);\n el.addEventListener('model-loaded', this.onModelLoaded);\n el.addEventListener('thumbstickmoved', this.onThumbstickMoved);\n this.controllerEventsActive = true;\n },\n removeEventListeners: function () {\n var el = this.el;\n el.removeEventListener('buttonchanged', this.onButtonChanged);\n el.removeEventListener('buttondown', this.onButtonDown);\n el.removeEventListener('buttonup', this.onButtonUp);\n el.removeEventListener('touchstart', this.onButtonTouchStart);\n el.removeEventListener('touchend', this.onButtonTouchEnd);\n el.removeEventListener('axismove', this.onAxisMoved);\n el.removeEventListener('model-loaded', this.onModelLoaded);\n el.removeEventListener('thumbstickmoved', this.onThumbstickMoved);\n this.controllerEventsActive = false;\n },\n checkIfControllerPresent: function () {\n checkControllerPresentAndSetup(this, GAMEPAD_ID_PREFIX, {\n hand: this.data.hand,\n iterateControllerProfiles: true\n });\n },\n play: function () {\n this.checkIfControllerPresent();\n this.addControllersUpdateListener();\n },\n pause: function () {\n this.removeEventListeners();\n this.removeControllersUpdateListener();\n },\n loadModel: function (controller) {\n var data = this.data;\n var controllerId;\n if (!data.model) {\n return;\n }\n // If model has been already loaded\n if (this.controllerObject3D) {\n this.el.setObject3D('mesh', this.controllerObject3D);\n return;\n }\n\n // Set the controller display model based on the data passed in.\n this.displayModel = CONTROLLER_PROPERTIES[data.controllerType] || CONTROLLER_PROPERTIES[CONTROLLER_DEFAULT];\n // If the developer is asking for auto-detection, use the retrieved displayName to identify the specific unit.\n // This only works for WebVR currently.\n if (data.controllerType === 'auto') {\n var trackedControlsSystem = this.el.sceneEl.systems['tracked-controls-webvr'];\n // WebVR\n if (trackedControlsSystem && trackedControlsSystem.vrDisplay) {\n var displayName = trackedControlsSystem.vrDisplay.displayName;\n if (/^Oculus Quest$/.test(displayName)) {\n this.displayModel = CONTROLLER_PROPERTIES['oculus-touch-v2'];\n }\n } else {\n // WebXR\n controllerId = CONTROLLER_DEFAULT;\n var controllersPropertiesIds = Object.keys(CONTROLLER_PROPERTIES);\n for (var i = 0; i < controller.profiles.length; i++) {\n if (controllersPropertiesIds.indexOf(controller.profiles[i]) !== -1) {\n controllerId = controller.profiles[i];\n break;\n }\n }\n this.displayModel = CONTROLLER_PROPERTIES[controllerId];\n }\n }\n var modelUrl = this.displayModel[data.hand].modelUrl;\n this.isTouchV3orPROorPlus = this.displayModel === CONTROLLER_PROPERTIES['oculus-touch-v3'] || this.displayModel === CONTROLLER_PROPERTIES['meta-quest-touch-pro'] || this.displayModel === CONTROLLER_PROPERTIES['meta-quest-touch-plus'];\n this.el.setAttribute('gltf-model', modelUrl);\n },\n injectTrackedControls: function (controller) {\n var data = this.data;\n var webXRId = GAMEPAD_ID_WEBXR;\n var webVRId = data.hand === 'right' ? 'Oculus Touch (Right)' : 'Oculus Touch (Left)';\n var id = isWebXRAvailable ? webXRId : webVRId;\n this.el.setAttribute('tracked-controls', {\n id: id,\n hand: data.hand,\n orientationOffset: data.orientationOffset,\n handTrackingEnabled: false,\n iterateControllerProfiles: true,\n space: 'gripSpace'\n });\n this.loadModel(controller);\n },\n addControllersUpdateListener: function () {\n this.el.sceneEl.addEventListener('controllersupdated', this.onControllersUpdate, false);\n },\n removeControllersUpdateListener: function () {\n this.el.sceneEl.removeEventListener('controllersupdated', this.onControllersUpdate, false);\n },\n onControllersUpdate: function () {\n // Note that due to gamepadconnected event propagation issues, we don't rely on events.\n this.checkIfControllerPresent();\n },\n onButtonChanged: function (evt) {\n var button = this.mapping[this.data.hand].buttons[evt.detail.id];\n if (!button) {\n return;\n }\n // move the button meshes\n if (this.isTouchV3orPROorPlus) {\n this.onButtonChangedV3orPROorPlus(evt);\n } else {\n var buttonMeshes = this.buttonMeshes;\n var analogValue;\n if (button === 'trigger' || button === 'grip') {\n analogValue = evt.detail.state.value;\n }\n if (buttonMeshes) {\n if (button === 'trigger' && buttonMeshes.trigger) {\n buttonMeshes.trigger.rotation.x = this.originalXRotationTrigger - analogValue * (Math.PI / 26);\n }\n if (button === 'grip' && buttonMeshes.grip) {\n analogValue *= this.data.hand === 'left' ? -1 : 1;\n buttonMeshes.grip.position.x = this.originalXPositionGrip + analogValue * 0.004;\n }\n }\n }\n // Pass along changed event with button state, using the button mapping for convenience.\n this.el.emit(button + 'changed', evt.detail.state);\n },\n onButtonChangedV3orPROorPlus: function (evt) {\n var button = this.mapping[this.data.hand].buttons[evt.detail.id];\n var buttonObjects = this.buttonObjects;\n var analogValue;\n if (!buttonObjects || !buttonObjects[button]) {\n return;\n }\n analogValue = evt.detail.state.value;\n buttonObjects[button].quaternion.slerpQuaternions(this.buttonRanges[button].min.quaternion, this.buttonRanges[button].max.quaternion, analogValue);\n buttonObjects[button].position.lerpVectors(this.buttonRanges[button].min.position, this.buttonRanges[button].max.position, analogValue);\n },\n onModelLoaded: function (evt) {\n if (evt.target !== this.el || !this.data.model) {\n return;\n }\n if (this.isTouchV3orPROorPlus) {\n this.onTouchV3orPROorPlusModelLoaded(evt);\n } else {\n // All oculus headset controller models prior to the Quest 2 (i.e., Oculus Touch V3)\n // used a consistent format that is handled here\n var controllerObject3D = this.controllerObject3D = evt.detail.model;\n var buttonMeshes;\n buttonMeshes = this.buttonMeshes = {};\n buttonMeshes.grip = controllerObject3D.getObjectByName('buttonHand');\n this.originalXPositionGrip = buttonMeshes.grip && buttonMeshes.grip.position.x;\n buttonMeshes.trigger = controllerObject3D.getObjectByName('buttonTrigger');\n this.originalXRotationTrigger = buttonMeshes.trigger && buttonMeshes.trigger.rotation.x;\n buttonMeshes.thumbstick = controllerObject3D.getObjectByName('stick');\n buttonMeshes.xbutton = controllerObject3D.getObjectByName('buttonX');\n buttonMeshes.abutton = controllerObject3D.getObjectByName('buttonA');\n buttonMeshes.ybutton = controllerObject3D.getObjectByName('buttonY');\n buttonMeshes.bbutton = controllerObject3D.getObjectByName('buttonB');\n }\n for (var button in this.buttonMeshes) {\n if (this.buttonMeshes[button]) {\n cloneMeshMaterial(this.buttonMeshes[button]);\n }\n }\n this.applyOffset(evt.detail.model);\n this.el.emit('controllermodelready', {\n name: 'oculus-touch-controls',\n model: this.data.model,\n rayOrigin: this.displayModel[this.data.hand].rayOrigin\n });\n },\n applyOffset: function (model) {\n model.position.copy(this.displayModel[this.data.hand].modelPivotOffset);\n model.rotation.copy(this.displayModel[this.data.hand].modelPivotRotation);\n },\n onTouchV3orPROorPlusModelLoaded: function (evt) {\n var controllerObject3D = this.controllerObject3D = evt.detail.model;\n var buttonObjects = this.buttonObjects = {};\n var buttonMeshes = this.buttonMeshes = {};\n var buttonRanges = this.buttonRanges = {};\n buttonMeshes.grip = controllerObject3D.getObjectByName('squeeze');\n buttonObjects.grip = controllerObject3D.getObjectByName('xr_standard_squeeze_pressed_value');\n buttonRanges.grip = {\n min: controllerObject3D.getObjectByName('xr_standard_squeeze_pressed_min'),\n max: controllerObject3D.getObjectByName('xr_standard_squeeze_pressed_max')\n };\n buttonObjects.grip.minX = buttonObjects.grip.position.x;\n buttonMeshes.thumbstick = controllerObject3D.getObjectByName('thumbstick');\n buttonObjects.thumbstick = controllerObject3D.getObjectByName('xr_standard_thumbstick_pressed_value');\n buttonRanges.thumbstick = {\n min: controllerObject3D.getObjectByName('xr_standard_thumbstick_pressed_min'),\n max: controllerObject3D.getObjectByName('xr_standard_thumbstick_pressed_max')\n };\n buttonObjects.thumbstickXAxis = controllerObject3D.getObjectByName('xr_standard_thumbstick_xaxis_pressed_value');\n buttonRanges.thumbstickXAxis = {\n min: controllerObject3D.getObjectByName('xr_standard_thumbstick_xaxis_pressed_min'),\n max: controllerObject3D.getObjectByName('xr_standard_thumbstick_xaxis_pressed_max')\n };\n buttonObjects.thumbstickYAxis = controllerObject3D.getObjectByName('xr_standard_thumbstick_yaxis_pressed_value');\n buttonRanges.thumbstickYAxis = {\n min: controllerObject3D.getObjectByName('xr_standard_thumbstick_yaxis_pressed_min'),\n max: controllerObject3D.getObjectByName('xr_standard_thumbstick_yaxis_pressed_max')\n };\n buttonMeshes.trigger = controllerObject3D.getObjectByName('trigger');\n buttonObjects.trigger = controllerObject3D.getObjectByName('xr_standard_trigger_pressed_value');\n buttonRanges.trigger = {\n min: controllerObject3D.getObjectByName('xr_standard_trigger_pressed_min'),\n max: controllerObject3D.getObjectByName('xr_standard_trigger_pressed_max')\n };\n buttonRanges.trigger.diff = {\n x: Math.abs(buttonRanges.trigger.max.rotation.x) - Math.abs(buttonRanges.trigger.min.rotation.x),\n y: Math.abs(buttonRanges.trigger.max.rotation.y) - Math.abs(buttonRanges.trigger.min.rotation.y),\n z: Math.abs(buttonRanges.trigger.max.rotation.z) - Math.abs(buttonRanges.trigger.min.rotation.z)\n };\n var button1 = this.data.hand === 'left' ? 'x' : 'a';\n var button2 = this.data.hand === 'left' ? 'y' : 'b';\n var button1id = button1 + 'button';\n var button2id = button2 + 'button';\n buttonMeshes[button1id] = controllerObject3D.getObjectByName(button1 + '_button');\n buttonObjects[button1id] = controllerObject3D.getObjectByName(button1 + '_button_pressed_value');\n buttonRanges[button1id] = {\n min: controllerObject3D.getObjectByName(button1 + '_button_pressed_min'),\n max: controllerObject3D.getObjectByName(button1 + '_button_pressed_max')\n };\n buttonMeshes[button2id] = controllerObject3D.getObjectByName(button2 + '_button');\n buttonObjects[button2id] = controllerObject3D.getObjectByName(button2 + '_button_pressed_value');\n buttonRanges[button2id] = {\n min: controllerObject3D.getObjectByName(button2 + '_button_pressed_min'),\n max: controllerObject3D.getObjectByName(button2 + '_button_pressed_max')\n };\n },\n onAxisMoved: function (evt) {\n emitIfAxesChanged(this, this.mapping[this.data.hand].axes, evt);\n },\n onThumbstickMoved: function (evt) {\n if (!this.buttonMeshes || !this.buttonMeshes.thumbstick) {\n return;\n }\n if (this.isTouchV3orPROorPlus) {\n this.updateThumbstickTouchV3orPROorPlus(evt);\n return;\n }\n for (var axis in evt.detail) {\n this.buttonObjects.thumbstick.rotation[this.axisMap[axis]] = this.buttonRanges.thumbstick.originalRotation[this.axisMap[axis]] - Math.PI / 8 * evt.detail[axis] * (axis === 'y' || this.data.hand === 'right' ? -1 : 1);\n }\n },\n axisMap: {\n y: 'x',\n x: 'z'\n },\n updateThumbstickTouchV3orPROorPlus: function (evt) {\n var normalizedXAxis = (evt.detail.x + 1.0) / 2.0;\n this.buttonObjects.thumbstickXAxis.quaternion.slerpQuaternions(this.buttonRanges.thumbstickXAxis.min.quaternion, this.buttonRanges.thumbstickXAxis.max.quaternion, normalizedXAxis);\n var normalizedYAxis = (evt.detail.y + 1.0) / 2.0;\n this.buttonObjects.thumbstickYAxis.quaternion.slerpQuaternions(this.buttonRanges.thumbstickYAxis.min.quaternion, this.buttonRanges.thumbstickYAxis.max.quaternion, normalizedYAxis);\n },\n updateModel: function (buttonName, evtName) {\n if (!this.data.model) {\n return;\n }\n this.updateButtonModel(buttonName, evtName);\n },\n updateButtonModel: function (buttonName, state) {\n // update the button mesh colors\n var buttonMeshes = this.buttonMeshes;\n var button;\n var color;\n if (!buttonMeshes) {\n return;\n }\n if (buttonMeshes[buttonName]) {\n color = state === 'up' || state === 'touchend' ? buttonMeshes[buttonName].originalColor || this.data.buttonColor : state === 'touchstart' ? this.data.buttonTouchColor : this.data.buttonHighlightColor;\n button = buttonMeshes[buttonName];\n button.material.color.set(color);\n }\n }\n});\n\n/**\n * Some of the controller models share the same material for different parts (buttons, triggers...).\n * In order to change their color independently we have to create separate materials.\n */\nfunction cloneMeshMaterial(object3d) {\n object3d.traverse(function (node) {\n var newMaterial;\n if (node.type !== 'Mesh') return;\n newMaterial = node.material.clone();\n object3d.originalColor = node.material.color;\n node.material.dispose();\n node.material = newMaterial;\n });\n}\n\n/***/ }),\n\n/***/ \"./src/components/pico-controls.js\":\n/*!*****************************************!*\\\n !*** ./src/components/pico-controls.js ***!\n \\*****************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar THREE = __webpack_require__(/*! ../lib/three */ \"./src/lib/three.js\");\nvar trackedControlsUtils = __webpack_require__(/*! ../utils/tracked-controls */ \"./src/utils/tracked-controls.js\");\nvar checkControllerPresentAndSetup = trackedControlsUtils.checkControllerPresentAndSetup;\nvar emitIfAxesChanged = trackedControlsUtils.emitIfAxesChanged;\nvar onButtonEvent = trackedControlsUtils.onButtonEvent;\n\n// See Profiles Registry:\n// https://github.com/immersive-web/webxr-input-profiles/tree/master/packages/registry\n// TODO: Add a more robust system for deriving gamepad name.\nvar GAMEPAD_ID = 'pico-4';\nvar AFRAME_CDN_ROOT = (__webpack_require__(/*! ../constants */ \"./src/constants/index.js\").AFRAME_CDN_ROOT);\nvar PICO_MODEL_GLB_BASE_URL = AFRAME_CDN_ROOT + 'controllers/pico/pico4/';\n\n/**\n * Button IDs:\n * 0 - trigger\n * 1 - grip\n * 3 - X / A\n * 4 - Y / B\n *\n * Axis:\n * 2 - joystick x axis\n * 3 - joystick y axis\n */\nvar INPUT_MAPPING_WEBXR = {\n left: {\n axes: {\n touchpad: [2, 3]\n },\n buttons: ['trigger', 'squeeze', 'none', 'thumbstick', 'xbutton', 'ybutton']\n },\n right: {\n axes: {\n touchpad: [2, 3]\n },\n buttons: ['trigger', 'squeeze', 'none', 'thumbstick', 'abutton', 'bbutton']\n }\n};\n\n/**\n * Pico Controls\n */\nmodule.exports.Component = registerComponent('pico-controls', {\n schema: {\n hand: {\n default: 'none'\n },\n model: {\n default: true\n },\n orientationOffset: {\n type: 'vec3'\n }\n },\n mapping: INPUT_MAPPING_WEBXR,\n init: function () {\n var self = this;\n this.onButtonChanged = this.onButtonChanged.bind(this);\n this.onButtonDown = function (evt) {\n onButtonEvent(evt.detail.id, 'down', self, self.data.hand);\n };\n this.onButtonUp = function (evt) {\n onButtonEvent(evt.detail.id, 'up', self, self.data.hand);\n };\n this.onButtonTouchEnd = function (evt) {\n onButtonEvent(evt.detail.id, 'touchend', self, self.data.hand);\n };\n this.onButtonTouchStart = function (evt) {\n onButtonEvent(evt.detail.id, 'touchstart', self, self.data.hand);\n };\n this.bindMethods();\n },\n update: function () {\n var data = this.data;\n this.controllerIndex = data.hand === 'right' ? 0 : data.hand === 'left' ? 1 : 2;\n },\n play: function () {\n this.checkIfControllerPresent();\n this.addControllersUpdateListener();\n },\n pause: function () {\n this.removeEventListeners();\n this.removeControllersUpdateListener();\n },\n bindMethods: function () {\n this.onModelLoaded = this.onModelLoaded.bind(this);\n this.onControllersUpdate = this.onControllersUpdate.bind(this);\n this.checkIfControllerPresent = this.checkIfControllerPresent.bind(this);\n this.removeControllersUpdateListener = this.removeControllersUpdateListener.bind(this);\n this.onAxisMoved = this.onAxisMoved.bind(this);\n },\n addEventListeners: function () {\n var el = this.el;\n el.addEventListener('buttonchanged', this.onButtonChanged);\n el.addEventListener('buttondown', this.onButtonDown);\n el.addEventListener('buttonup', this.onButtonUp);\n el.addEventListener('touchstart', this.onButtonTouchStart);\n el.addEventListener('touchend', this.onButtonTouchEnd);\n el.addEventListener('axismove', this.onAxisMoved);\n el.addEventListener('model-loaded', this.onModelLoaded);\n this.controllerEventsActive = true;\n },\n removeEventListeners: function () {\n var el = this.el;\n el.removeEventListener('buttonchanged', this.onButtonChanged);\n el.removeEventListener('buttondown', this.onButtonDown);\n el.removeEventListener('buttonup', this.onButtonUp);\n el.removeEventListener('touchstart', this.onButtonTouchStart);\n el.removeEventListener('touchend', this.onButtonTouchEnd);\n el.removeEventListener('axismove', this.onAxisMoved);\n el.removeEventListener('model-loaded', this.onModelLoaded);\n this.controllerEventsActive = false;\n },\n checkIfControllerPresent: function () {\n var data = this.data;\n checkControllerPresentAndSetup(this, GAMEPAD_ID, {\n index: this.controllerIndex,\n hand: data.hand\n });\n },\n injectTrackedControls: function () {\n var el = this.el;\n var data = this.data;\n el.setAttribute('tracked-controls', {\n // TODO: verify expected behavior between reserved prefixes.\n idPrefix: GAMEPAD_ID,\n hand: data.hand,\n controller: this.controllerIndex,\n orientationOffset: data.orientationOffset\n });\n // Load model.\n if (!this.data.model) {\n return;\n }\n this.el.setAttribute('gltf-model', PICO_MODEL_GLB_BASE_URL + this.data.hand + '.glb');\n },\n addControllersUpdateListener: function () {\n this.el.sceneEl.addEventListener('controllersupdated', this.onControllersUpdate, false);\n },\n removeControllersUpdateListener: function () {\n this.el.sceneEl.removeEventListener('controllersupdated', this.onControllersUpdate, false);\n },\n onControllersUpdate: function () {\n // Note that due to gamepadconnected event propagation issues, we don't rely on events.\n this.checkIfControllerPresent();\n },\n onButtonChanged: function (evt) {\n var button = this.mapping[this.data.hand].buttons[evt.detail.id];\n var analogValue;\n if (!button) {\n return;\n }\n if (button === 'trigger') {\n analogValue = evt.detail.state.value;\n console.log('analog value of trigger press: ' + analogValue);\n }\n\n // Pass along changed event with button state, using button mapping for convenience.\n this.el.emit(button + 'changed', evt.detail.state);\n },\n onModelLoaded: function (evt) {\n if (evt.target !== this.el || !this.data.model) {\n return;\n }\n this.el.emit('controllermodelready', {\n name: 'pico-controls',\n model: this.data.model,\n rayOrigin: new THREE.Vector3(0, 0, 0)\n });\n },\n onAxisMoved: function (evt) {\n emitIfAxesChanged(this, this.mapping.axes, evt);\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/position.js\":\n/*!************************************!*\\\n !*** ./src/components/position.js ***!\n \\************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nmodule.exports.Component = registerComponent('position', {\n schema: {\n type: 'vec3'\n },\n update: function () {\n var object3D = this.el.object3D;\n var data = this.data;\n object3D.position.set(data.x, data.y, data.z);\n },\n remove: function () {\n // Pretty much for mixins.\n this.el.object3D.position.set(0, 0, 0);\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/raycaster.js\":\n/*!*************************************!*\\\n !*** ./src/components/raycaster.js ***!\n \\*************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\n/* global MutationObserver */\n\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar THREE = __webpack_require__(/*! ../lib/three */ \"./src/lib/three.js\");\nvar utils = __webpack_require__(/*! ../utils/ */ \"./src/utils/index.js\");\nvar warn = utils.debug('components:raycaster:warn');\n\n// Defines selectors that should be 'safe' for the MutationObserver used to\n// refresh the whitelist. Matches classnames, IDs, and presence of attributes.\n// Selectors for the value of an attribute, like [position=0 2 0], cannot be\n// reliably detected and are therefore disallowed.\nvar OBSERVER_SELECTOR_RE = /^[\\w\\s-.,[\\]#]*$/;\n\n// Configuration for the MutationObserver used to refresh the whitelist.\n// Listens for addition/removal of elements and attributes within the scene.\nvar OBSERVER_CONFIG = {\n childList: true,\n attributes: true,\n subtree: true\n};\nvar EVENTS = {\n INTERSECT: 'raycaster-intersected',\n INTERSECTION: 'raycaster-intersection',\n INTERSECT_CLEAR: 'raycaster-intersected-cleared',\n INTERSECTION_CLEAR: 'raycaster-intersection-cleared',\n INTERSECTION_CLOSEST_ENTITY_CHANGED: 'raycaster-closest-entity-changed'\n};\n\n/**\n * Raycaster component.\n *\n * Pass options to three.js Raycaster including which objects to test.\n * Poll for intersections.\n * Emit event on origin entity and on target entity on intersect.\n *\n * @member {array} intersectedEls - List of currently intersected entities.\n * @member {array} objects - Cached list of meshes to intersect.\n * @member {number} prevCheckTime - Previous time intersection was checked. To help interval.\n * @member {object} raycaster - three.js Raycaster.\n */\nmodule.exports.Component = registerComponent('raycaster', {\n schema: {\n autoRefresh: {\n default: true\n },\n direction: {\n type: 'vec3',\n default: {\n x: 0,\n y: 0,\n z: -1\n }\n },\n enabled: {\n default: true\n },\n far: {\n default: 1000\n },\n interval: {\n default: 0\n },\n near: {\n default: 0\n },\n objects: {\n default: ''\n },\n origin: {\n type: 'vec3'\n },\n showLine: {\n default: false\n },\n lineColor: {\n default: 'white'\n },\n lineOpacity: {\n default: 1\n },\n useWorldCoordinates: {\n default: false\n }\n },\n multiple: true,\n init: function () {\n this.clearedIntersectedEls = [];\n this.unitLineEndVec3 = new THREE.Vector3();\n this.intersectedEls = [];\n this.intersections = [];\n this.newIntersectedEls = [];\n this.newIntersections = [];\n this.objects = [];\n this.prevCheckTime = undefined;\n this.prevIntersectedEls = [];\n this.rawIntersections = [];\n this.raycaster = new THREE.Raycaster();\n this.updateOriginDirection();\n this.setDirty = this.setDirty.bind(this);\n this.updateLine = this.updateLine.bind(this);\n this.observer = new MutationObserver(this.setDirty);\n this.dirty = true;\n this.lineEndVec3 = new THREE.Vector3();\n this.otherLineEndVec3 = new THREE.Vector3();\n this.lineData = {\n end: this.lineEndVec3\n };\n this.getIntersection = this.getIntersection.bind(this);\n this.intersectedDetail = {\n el: this.el,\n getIntersection: this.getIntersection\n };\n this.intersectedClearedDetail = {\n el: this.el\n };\n this.intersectionClearedDetail = {\n clearedEls: this.clearedIntersectedEls\n };\n this.intersectionDetail = {};\n },\n /**\n * Create or update raycaster object.\n */\n update: function (oldData) {\n var data = this.data;\n var el = this.el;\n var raycaster = this.raycaster;\n\n // Set raycaster properties.\n raycaster.far = data.far;\n raycaster.near = data.near;\n\n // Draw line.\n if (data.showLine && (data.far !== oldData.far || data.origin !== oldData.origin || data.direction !== oldData.direction || !oldData.showLine)) {\n // Calculate unit vector for line direction. Can be multiplied via scalar and added\n // to origin to adjust line length.\n this.unitLineEndVec3.copy(data.direction).normalize();\n this.drawLine();\n }\n if (!data.showLine && oldData.showLine) {\n el.removeAttribute('line');\n }\n if (data.objects !== oldData.objects && !OBSERVER_SELECTOR_RE.test(data.objects)) {\n warn('[raycaster] Selector \"' + data.objects + '\" may not update automatically with DOM changes.');\n }\n if (!data.objects) {\n warn('[raycaster] For performance, please define raycaster.objects when using ' + 'raycaster or cursor components to whitelist which entities to intersect with. ' + 'e.g., raycaster=\"objects: [data-raycastable]\".');\n }\n if (data.autoRefresh !== oldData.autoRefresh && el.isPlaying) {\n data.autoRefresh ? this.addEventListeners() : this.removeEventListeners();\n }\n if (oldData.enabled && !data.enabled) {\n this.clearAllIntersections();\n }\n this.setDirty();\n },\n play: function () {\n this.addEventListeners();\n },\n pause: function () {\n this.removeEventListeners();\n },\n remove: function () {\n if (this.data.showLine) {\n this.el.removeAttribute('line');\n }\n this.clearAllIntersections();\n },\n addEventListeners: function () {\n if (!this.data.autoRefresh) {\n return;\n }\n this.observer.observe(this.el.sceneEl, OBSERVER_CONFIG);\n this.el.sceneEl.addEventListener('object3dset', this.setDirty);\n this.el.sceneEl.addEventListener('object3dremove', this.setDirty);\n },\n removeEventListeners: function () {\n this.observer.disconnect();\n this.el.sceneEl.removeEventListener('object3dset', this.setDirty);\n this.el.sceneEl.removeEventListener('object3dremove', this.setDirty);\n },\n /**\n * Mark the object list as dirty, to be refreshed before next raycast.\n */\n setDirty: function () {\n this.dirty = true;\n },\n /**\n * Update list of objects to test for intersection.\n */\n refreshObjects: function () {\n var data = this.data;\n var els;\n\n // If objects not defined, intersect with everything.\n els = data.objects ? this.el.sceneEl.querySelectorAll(data.objects) : this.el.sceneEl.querySelectorAll('*');\n this.objects = this.flattenObject3DMaps(els);\n this.dirty = false;\n },\n /**\n * Check for intersections and cleared intersections on an interval.\n */\n tock: function (time) {\n var data = this.data;\n var prevCheckTime = this.prevCheckTime;\n if (!data.enabled) {\n return;\n }\n\n // Only check for intersection if interval time has passed.\n if (prevCheckTime && time - prevCheckTime < data.interval) {\n return;\n }\n\n // Update check time.\n this.prevCheckTime = time;\n this.checkIntersections();\n },\n /**\n * Raycast for intersections and emit events for current and cleared intersections.\n */\n checkIntersections: function () {\n var clearedIntersectedEls = this.clearedIntersectedEls;\n var el = this.el;\n var data = this.data;\n var i;\n var intersectedEls = this.intersectedEls;\n var intersection;\n var intersections = this.intersections;\n var newIntersectedEls = this.newIntersectedEls;\n var newIntersections = this.newIntersections;\n var prevIntersectedEls = this.prevIntersectedEls;\n var rawIntersections = this.rawIntersections;\n\n // Refresh the object whitelist if needed.\n if (this.dirty) {\n this.refreshObjects();\n }\n\n // Store old previously intersected entities.\n copyArray(this.prevIntersectedEls, this.intersectedEls);\n\n // Raycast.\n this.updateOriginDirection();\n rawIntersections.length = 0;\n this.raycaster.intersectObjects(this.objects, true, rawIntersections);\n\n // Only keep intersections against objects that have a reference to an entity.\n intersections.length = 0;\n intersectedEls.length = 0;\n for (i = 0; i < rawIntersections.length; i++) {\n intersection = rawIntersections[i];\n // Don't intersect with own line.\n if (data.showLine && intersection.object === el.getObject3D('line')) {\n continue;\n }\n if (intersection.object.el) {\n intersections.push(intersection);\n intersectedEls.push(intersection.object.el);\n }\n }\n\n // Get newly intersected entities.\n newIntersections.length = 0;\n newIntersectedEls.length = 0;\n for (i = 0; i < intersections.length; i++) {\n if (prevIntersectedEls.indexOf(intersections[i].object.el) === -1) {\n newIntersections.push(intersections[i]);\n newIntersectedEls.push(intersections[i].object.el);\n }\n }\n\n // Emit intersection cleared on both entities per formerly intersected entity.\n clearedIntersectedEls.length = 0;\n for (i = 0; i < prevIntersectedEls.length; i++) {\n if (intersectedEls.indexOf(prevIntersectedEls[i]) !== -1) {\n continue;\n }\n prevIntersectedEls[i].emit(EVENTS.INTERSECT_CLEAR, this.intersectedClearedDetail);\n clearedIntersectedEls.push(prevIntersectedEls[i]);\n }\n if (clearedIntersectedEls.length) {\n el.emit(EVENTS.INTERSECTION_CLEAR, this.intersectionClearedDetail);\n }\n\n // Emit intersected on intersected entity per intersected entity.\n for (i = 0; i < newIntersectedEls.length; i++) {\n newIntersectedEls[i].emit(EVENTS.INTERSECT, this.intersectedDetail);\n }\n\n // Emit all intersections at once on raycasting entity.\n if (newIntersections.length) {\n this.intersectionDetail.els = newIntersectedEls;\n this.intersectionDetail.intersections = newIntersections;\n el.emit(EVENTS.INTERSECTION, this.intersectionDetail);\n }\n\n // Emit event when the closest intersected entity has changed.\n if (prevIntersectedEls.length === 0 && intersections.length > 0 || prevIntersectedEls.length > 0 && intersections.length === 0 || prevIntersectedEls.length && intersections.length && prevIntersectedEls[0] !== intersections[0].object.el) {\n this.intersectionDetail.els = this.intersectedEls;\n this.intersectionDetail.intersections = intersections;\n el.emit(EVENTS.INTERSECTION_CLOSEST_ENTITY_CHANGED, this.intersectionDetail);\n }\n\n // Update line length.\n if (data.showLine) {\n setTimeout(this.updateLine);\n }\n },\n updateLine: function () {\n var el = this.el;\n var intersections = this.intersections;\n var lineLength;\n if (intersections.length) {\n if (intersections[0].object.el === el && intersections[1]) {\n lineLength = intersections[1].distance;\n } else {\n lineLength = intersections[0].distance;\n }\n }\n this.drawLine(lineLength);\n },\n /**\n * Return the most recent intersection details for a given entity, if any.\n * @param {AEntity} el\n * @return {Object}\n */\n getIntersection: function (el) {\n var i;\n var intersection;\n for (i = 0; i < this.intersections.length; i++) {\n intersection = this.intersections[i];\n if (intersection.object.el === el) {\n return intersection;\n }\n }\n return null;\n },\n /**\n * Update origin and direction of raycaster using entity transforms and supplied origin or\n * direction offsets.\n */\n updateOriginDirection: function () {\n var direction = new THREE.Vector3();\n var originVec3 = new THREE.Vector3();\n\n // Closure to make quaternion/vector3 objects private.\n return function updateOriginDirection() {\n var el = this.el;\n var data = this.data;\n if (data.useWorldCoordinates) {\n this.raycaster.set(data.origin, data.direction);\n return;\n }\n el.object3D.updateMatrixWorld();\n originVec3.setFromMatrixPosition(el.object3D.matrixWorld);\n\n // If non-zero origin, translate the origin into world space.\n if (data.origin.x !== 0 || data.origin.y !== 0 || data.origin.z !== 0) {\n originVec3 = el.object3D.localToWorld(originVec3.copy(data.origin));\n }\n\n // three.js raycaster direction is relative to 0, 0, 0 NOT the origin / offset we\n // provide. Apply the offset to the direction, then rotation from the object,\n // and normalize.\n direction.copy(data.direction).transformDirection(el.object3D.matrixWorld).normalize();\n\n // Apply offset and direction, in world coordinates.\n this.raycaster.set(originVec3, direction);\n };\n }(),\n /**\n * Create or update line to give raycaster visual representation.\n * Customize the line through through line component.\n * We draw the line in the raycaster component to customize the line to the\n * raycaster's origin, direction, and far.\n *\n * Unlike the raycaster, we create the line as a child of the object. The line will\n * be affected by the transforms of the objects, so we don't have to calculate transforms\n * like we do with the raycaster.\n *\n * @param {number} length - Length of line. Pass in to shorten the line to the intersection\n * point. If not provided, length will default to the max length, `raycaster.far`.\n */\n drawLine: function (length) {\n var data = this.data;\n var el = this.el;\n var endVec3;\n\n // Switch each time vector so line update triggered and to avoid unnecessary vector clone.\n endVec3 = this.lineData.end === this.lineEndVec3 ? this.otherLineEndVec3 : this.lineEndVec3;\n\n // Treat Infinity as 1000m for the line.\n if (length === undefined) {\n length = data.far === Infinity ? 1000 : data.far;\n }\n\n // Update the length of the line if given. `unitLineEndVec3` is the direction\n // given by data.direction, then we apply a scalar to give it a length and the\n // origin point to offset it.\n this.lineData.start = data.origin;\n this.lineData.end = endVec3.copy(this.unitLineEndVec3).multiplyScalar(length).add(data.origin);\n this.lineData.color = data.lineColor;\n this.lineData.opacity = data.lineOpacity;\n el.setAttribute('line', this.lineData);\n },\n /**\n * Return A-Frame attachments of each element's object3D group (e.g., mesh).\n * Children are flattened by one level, removing the THREE.Group wrapper,\n * so that non-recursive raycasting remains useful.\n *\n * Only push children defined as component attachments (e.g., setObject3D),\n * NOT actual children in the scene graph hierarchy.\n *\n * @param {Array} els\n * @return {Array}\n */\n flattenObject3DMaps: function (els) {\n var key;\n var i;\n var objects = this.objects;\n var scene = this.el.sceneEl.object3D;\n function isAttachedToScene(object) {\n if (object.parent) {\n return isAttachedToScene(object.parent);\n } else {\n return object === scene;\n }\n }\n\n // Push meshes and other attachments onto list of objects to intersect.\n objects.length = 0;\n for (i = 0; i < els.length; i++) {\n var el = els[i];\n if (el.isEntity && el.object3D && isAttachedToScene(el.object3D)) {\n for (key in el.object3DMap) {\n objects.push(el.getObject3D(key));\n }\n }\n }\n return objects;\n },\n clearAllIntersections: function () {\n var i;\n for (i = 0; i < this.intersectedEls.length; i++) {\n this.intersectedEls[i].emit(EVENTS.INTERSECT_CLEAR, this.intersectedClearedDetail);\n }\n copyArray(this.clearedIntersectedEls, this.intersectedEls);\n this.intersectedEls.length = 0;\n this.intersections.length = 0;\n this.el.emit(EVENTS.INTERSECTION_CLEAR, this.intersectionClearedDetail);\n }\n});\n\n/**\n * Copy contents of one array to another without allocating new array.\n */\nfunction copyArray(a, b) {\n var i;\n a.length = b.length;\n for (i = 0; i < b.length; i++) {\n a[i] = b[i];\n }\n}\n\n/***/ }),\n\n/***/ \"./src/components/rotation.js\":\n/*!************************************!*\\\n !*** ./src/components/rotation.js ***!\n \\************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar degToRad = (__webpack_require__(/*! ../lib/three */ \"./src/lib/three.js\").MathUtils.degToRad);\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nmodule.exports.Component = registerComponent('rotation', {\n schema: {\n type: 'vec3'\n },\n /**\n * Updates object3D rotation.\n */\n update: function () {\n var data = this.data;\n var object3D = this.el.object3D;\n object3D.rotation.set(degToRad(data.x), degToRad(data.y), degToRad(data.z), 'YXZ');\n },\n remove: function () {\n // Pretty much for mixins.\n this.el.object3D.rotation.set(0, 0, 0);\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/scale.js\":\n/*!*********************************!*\\\n !*** ./src/components/scale.js ***!\n \\*********************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nmodule.exports.Component = registerComponent('scale', {\n schema: {\n type: 'vec3',\n default: {\n x: 1,\n y: 1,\n z: 1\n }\n },\n update: function () {\n var data = this.data;\n var object3D = this.el.object3D;\n object3D.scale.set(data.x, data.y, data.z);\n },\n remove: function () {\n // Pretty much for mixins.\n this.el.object3D.scale.set(1, 1, 1);\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/scene/ar-hit-test.js\":\n/*!*********************************************!*\\\n !*** ./src/components/scene/ar-hit-test.js ***!\n \\*********************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\n/* global ImageData, Map, Set */\nvar arrowURL = 'data:image/webp;base64,UklGRkQHAABXRUJQVlA4WAoAAAAQAAAA/wEA/wEAQUxQSL0DAAARDzD/ERGCjrY9sYYFfgo6aa1kJ7K0w9Lo3AadLSVeFxevQwj5kuM8RfR/Atw/C0+ozB/oUBrloFZs6ElSW88j1KA4yExNWQaqRZquIDF0JYmlq0hAuUDTFu66tng3teW7pa3cQf1V1edvur54M/Slm6Wv3Gx9zw0MXlQLntcsBN6wkHjTQuYtC4W3LTw8mGRVG57TbAROtxHfZNhInGkjc5aNwtk2Hg6Mvki14k+NkZzCwQgCxalcAv3kddRTPI1DcUrXId1FLf1uHpzaQz4tquhZVLlKesbVpqKeTj0n0F5PpXDlFN9UqmhalL/ImuZFo6KmToWLoKlddMprqlS8cKovBvHo2kTiFV2LN4msaxKZl3QNiair8xYRdDWivIvXVXmbcMqJ51UebZuFXxZt6xd4laxtciqRtA3Cv0nU1t+kEUFbI8JvCa+tvkm3FDlO/W+OR99+kWEp/YYo+tYfTVnf/K8cE/F///3vv//993eeL+a+uvjawLcX3xjYvJotBFY3kVjTRGFtE+BU2AiMbiQyhpHMWEYeBozAH5qNBYRDB5KBCaTDBKKBAZTDBoKBDjwHAN5ABeCJBsAZcAAC0YHHxAYSMYBiYgGZWEA2MYFCbCCZGAAIANFEB+AnYgMQTDQAYSJ2AN5EBZAm4gDgTDgAeSIu4DGygTIRN1CMLOCZiACykQlg4jsAycgA8AO+BxCNdJyDkcbwRirDGXGnx8w+FDPrkM3MQ9JQZMYhiiwV/RDMtIM3U1/DmXHUo+IR2kSR2ToWkQ1NIn2qf2J8LCqJKiDUiSADHY3whirhdHgZ94HKaR97PhE+twEUJUFoAcgyTct8hfSxSkShASDKdMJ/ritKHwgyQ0sD4D/miCxU5SbhOOUDTnZpccCjYP/i0bZ/8bAgtVGEoGapWIQXyzKVKLwgNJFk2rtMIgoNRJlOZF7SNSSyUEeQmbxBFKEmtYjEe8S8zOZ1AkJVCmS88FJOtF40Ksg4oUaFiygk3C8qlTVNyl8UTevCUdAE2t14PfVqU1FPp57TopKeQZWromddTQp6QOfTOEQt/ZDuipZ11w/wOiqO8dRORcc6BQEkDQMClaHcn5wV9yLbxsNZNgpn2sicYSNxuo34Js1G4FQbnuNsOPa28PCWhcKbFjJvWEi8ZiHwqgXPcxbc5db33Cx95WboSzddX7yp+vyN0+eul7ZyN7Xlu64t3jVt4c5pc4JLV5EYupJE0xUknC4nOjVlmaYpyLit53HCQ0+ScnqceNcS5dzUkd0/CwMAVlA4IGADAAAQXwCdASoAAgACP8ne6Wy/tjCpqJ/IA/A5CWlu4XYBG/Pz8AfwD8APz//f3v8E1fuHZnxKYACtfuHZnxKYACrYTb5mOslhxu843ecbvON3nG7zjd3a0VCn7G1MABVxwH/Xd25gAK1+4dmfEpe2+PHhQaj75++riG6FuYACtfuHZnxKYACRrK3q9xO8Ss3uWKnMhs/rDF1hi6wxdYYusMXWGI5QRcCFDZog5OgqNlse1NDuz/UoFa/cOzPiUwAEsAOK4/nu5eZHK2tlXxJfNYlMABWv3Dsz4bvNJ5YA/LtxJ38SmAArX7h2Z8Sk5vdZUYv7mZPiUwAFa/cOzPh21s5OgZxf1mfEpemRyFr/rM+JS9noA/LtxJ38SmAAlUJIotzAASn6TjdhK+D3Dsz4dyvB7h2Z8O2tnJ0DOL+sz4lL2nKLT4lL/+iSLOocxq639w7M34MNZdm55uJ8v8ra2cpVZnxKTq2F3PN/cNksAfl24k7+JTAASqrD37h2Z7b1W+VtbOUqsz4lJ1bC7nm/uGyWAPy7cSd/EpgAJVVh79w7M9t6rfK2tnKVWZ8Sk6thdzzf3DZLAH5duJO/iUwAEqqw9+4dme29VvlbWzlKrM+JSdWwu55v7hslgD8u3EnfxKYACVVYe/cOzPbeq3ytrZylVme0kYJ8557FLerqFrzIbPrrf3DZLAH5duJO/iUvaVMS9BoaF4p7pSDFTP1XMyfElelrM0DOL+sz4eBJ13nV1OppBGPuKb4YzXQgq9uH19uS/0+JS9t9fr6ZUlQBelDG6GMgq97otb5QMPJwtKyBTbFp8Sl7b6/X0ykkawEOsgdiE6Fi0vb/Eve6xkwsmug0Z4nGNHQO8839bpTsjpz7SWIJxKagvd1QWMa6FYT1KEw3j4XDT6vJ9Xk+nyfT5Pq8n1eEmk5dinMM/9Fcfz4Z3Dsz3KD2dw7LxBRxKrqUUGQPH/7zxr1KIfNpLEJ0MZB2ITM/0Z2EFoh12NlXnEcpYcbvON3nG7zjd5xu84vfcNIAAP7+y8ceyzbVxkakPYY4lcr72fqOnDwipv+yxC71wAADBrjKnAAAAAAAAAAAAAAw7oNGHttqWONcoFN/2WIDc2pa6WVFtFYROlsaMaTXdcOjXHz93+YxAglKa4AAAAA=';\nvar register = (__webpack_require__(/*! ../../core/component */ \"./src/core/component.js\").registerComponent);\nvar THREE = __webpack_require__(/*! ../../lib/three */ \"./src/lib/three.js\");\nvar CAM_LAYER = 21;\nvar applyPose = function () {\n var tempQuaternion = new THREE.Quaternion();\n var tempVec3 = new THREE.Vector3();\n function applyPose(pose, object3D, offset) {\n object3D.position.copy(pose.transform.position);\n object3D.quaternion.copy(pose.transform.orientation);\n tempVec3.copy(offset);\n tempQuaternion.copy(pose.transform.orientation);\n tempVec3.applyQuaternion(tempQuaternion);\n object3D.position.sub(tempVec3);\n }\n return applyPose;\n}();\napplyPose.tempFakePose = {\n transform: {\n orientation: new THREE.Quaternion(),\n position: new THREE.Vector3()\n }\n};\n\n/**\n * Class to handle hit-test from a single source\n *\n * For a normal space provide it as a space option\n * new HitTest(renderer, {\n * space: viewerSpace\n * });\n *\n * this is also useful for the targetRaySpace of an XRInputSource\n *\n * It can also describe a transient input source like so:\n *\n * var profileToSupport = 'generic-touchscreen';\n * var transientHitTest = new HitTest(renderer, {\n * profile: profileToSupport\n * });\n *\n * Where the profile matches an item in a type of controller, profiles matching 'generic-touchscreen'\n * will always be a transient input and as of 08/2021 all transient inputs are 'generic-touchscreen'\n *\n * @param {WebGLRenderer} renderer THREE.JS Renderer\n * @param {} hitTestSourceDetails The source information either as the information for a transient hit-test or a regular hit-test\n */\nfunction HitTest(renderer, hitTestSourceDetails) {\n this.renderer = renderer;\n this.xrHitTestSource = null;\n renderer.xr.addEventListener('sessionend', function () {\n this.xrHitTestSource = null;\n }.bind(this));\n renderer.xr.addEventListener('sessionstart', function () {\n this.sessionStart(hitTestSourceDetails);\n }.bind(this));\n if (this.renderer.xr.isPresenting) {\n this.sessionStart(hitTestSourceDetails);\n }\n}\nHitTest.prototype.previousFrameAnchors = new Set();\nHitTest.prototype.anchorToObject3D = new Map();\nfunction warnAboutHitTest(e) {\n console.warn(e.message);\n console.warn('Cannot requestHitTestSource Are you missing: webxr=\"optionalFeatures: hit-test;\" from ?');\n}\nHitTest.prototype.sessionStart = function sessionStart(hitTestSourceDetails) {\n this.session = this.renderer.xr.getSession();\n if (!('requestHitTestSource' in this.session)) {\n warnAboutHitTest({\n message: 'No requestHitTestSource on the session.'\n });\n return;\n }\n if (hitTestSourceDetails.space) {\n this.session.requestHitTestSource(hitTestSourceDetails).then(function (xrHitTestSource) {\n this.xrHitTestSource = xrHitTestSource;\n }.bind(this)).catch(warnAboutHitTest);\n } else if (hitTestSourceDetails.profile) {\n this.session.requestHitTestSourceForTransientInput(hitTestSourceDetails).then(function (xrHitTestSource) {\n this.xrHitTestSource = xrHitTestSource;\n this.transient = true;\n }.bind(this)).catch(warnAboutHitTest);\n }\n};\n\n/**\n * Turns the last hit test into an anchor, the provided Object3D will have it's\n * position update to track the anchor.\n *\n * @param {Object3D} object3D object to track\n * @param {Vector3} offset offset of the object from the origin that gets subtracted\n * @returns\n */\nHitTest.prototype.anchorFromLastHitTestResult = function (object3D, offset) {\n var hitTest = this.lastHitTest;\n if (!hitTest) {\n return;\n }\n var object3DOptions = {\n object3D: object3D,\n offset: offset\n };\n Array.from(this.anchorToObject3D.entries()).forEach(function (entry) {\n var entryObject = entry[1].object3D;\n var anchor = entry[0];\n if (entryObject === object3D) {\n this.anchorToObject3D.delete(anchor);\n anchor.delete();\n }\n }.bind(this));\n if (hitTest.createAnchor) {\n hitTest.createAnchor().then(function (anchor) {\n this.anchorToObject3D.set(anchor, object3DOptions);\n }.bind(this)).catch(function (e) {\n console.warn(e.message);\n console.warn('Cannot create anchor, are you missing: webxr=\"optionalFeatures: anchors;\" from ?');\n });\n }\n};\nHitTest.prototype.doHit = function doHit(frame) {\n if (!this.renderer.xr.isPresenting) {\n return;\n }\n var refSpace = this.renderer.xr.getReferenceSpace();\n var xrViewerPose = frame.getViewerPose(refSpace);\n var hitTestResults;\n var results;\n if (this.xrHitTestSource && xrViewerPose) {\n if (this.transient) {\n hitTestResults = frame.getHitTestResultsForTransientInput(this.xrHitTestSource);\n if (hitTestResults.length > 0) {\n results = hitTestResults[0].results;\n if (results.length > 0) {\n this.lastHitTest = results[0];\n return results[0].getPose(refSpace);\n } else {\n return false;\n }\n } else {\n return false;\n }\n } else {\n hitTestResults = frame.getHitTestResults(this.xrHitTestSource);\n if (hitTestResults.length > 0) {\n this.lastHitTest = hitTestResults[0];\n return hitTestResults[0].getPose(refSpace);\n } else {\n return false;\n }\n }\n }\n};\n\n// static function\nHitTest.updateAnchorPoses = function (frame, refSpace) {\n // If tracked anchors isn't defined because it's not supported then just use the empty set\n var trackedAnchors = frame.trackedAnchors || HitTest.prototype.previousFrameAnchors;\n HitTest.prototype.previousFrameAnchors.forEach(function (anchor) {\n // Handle anchor tracking loss - `anchor` was present\n // in the present frame but is no longer tracked.\n if (!trackedAnchors.has(anchor)) {\n HitTest.prototype.anchorToObject3D.delete(anchor);\n }\n });\n trackedAnchors.forEach(function (anchor) {\n var anchorPose;\n var object3DOptions;\n var offset;\n var object3D;\n try {\n // Query most recent pose of the anchor relative to some reference space:\n anchorPose = frame.getPose(anchor.anchorSpace, refSpace);\n } catch (e) {\n // This will fail if the anchor has been deleted that frame\n }\n if (anchorPose) {\n object3DOptions = HitTest.prototype.anchorToObject3D.get(anchor);\n if (!object3DOptions) {\n return;\n }\n offset = object3DOptions.offset;\n object3D = object3DOptions.object3D;\n applyPose(anchorPose, object3D, offset);\n }\n });\n};\nvar hitTestCache;\nmodule.exports.Component = register('ar-hit-test', {\n schema: {\n target: {\n type: 'selector'\n },\n enabled: {\n default: true\n },\n src: {\n default: arrowURL,\n type: 'map'\n },\n type: {\n default: 'footprint',\n oneOf: ['footprint', 'map']\n },\n footprintDepth: {\n default: 0.1\n },\n mapSize: {\n type: 'vec2',\n default: {\n x: 0.5,\n y: 0.5\n }\n }\n },\n sceneOnly: true,\n init: function () {\n this.hitTest = null;\n this.imageDataArray = new Uint8ClampedArray(512 * 512 * 4);\n this.imageData = new ImageData(this.imageDataArray, 512, 512);\n this.textureCache = new Map();\n this.orthoCam = new THREE.OrthographicCamera();\n this.orthoCam.layers.set(CAM_LAYER);\n this.textureTarget = new THREE.WebGLRenderTarget(512, 512, {});\n this.basicMaterial = new THREE.MeshBasicMaterial({\n color: 0x000000,\n side: THREE.DoubleSide\n });\n this.canvas = document.createElement('canvas');\n this.context = this.canvas.getContext('2d');\n this.context.imageSmoothingEnabled = false;\n this.canvas.width = 512;\n this.canvas.height = 512;\n this.canvasTexture = new THREE.CanvasTexture(this.canvas, {\n alpha: true\n });\n this.canvasTexture.flipY = false;\n\n // Update WebXR to support hit-test and anchors\n var webxrData = this.el.getAttribute('webxr');\n var optionalFeaturesArray = webxrData.optionalFeatures;\n if (!optionalFeaturesArray.includes('hit-test') || !optionalFeaturesArray.includes('anchors')) {\n optionalFeaturesArray.push('hit-test');\n optionalFeaturesArray.push('anchors');\n this.el.setAttribute('webxr', webxrData);\n }\n this.el.sceneEl.renderer.xr.addEventListener('sessionend', function () {\n this.hitTest = null;\n }.bind(this));\n this.el.sceneEl.renderer.xr.addEventListener('sessionstart', function () {\n // Don't request Hit Test unless AR (breaks WebXR Emulator)\n if (!this.el.is('ar-mode')) {\n return;\n }\n var renderer = this.el.sceneEl.renderer;\n var session = this.session = renderer.xr.getSession();\n this.hasPosedOnce = false;\n this.bboxMesh.visible = false;\n if (!hitTestCache) {\n hitTestCache = new Map();\n }\n\n // Default to selecting through the face\n session.requestReferenceSpace('viewer').then(function (viewerSpace) {\n this.hitTest = new HitTest(renderer, {\n space: viewerSpace\n });\n hitTestCache.set(viewerSpace, this.hitTest);\n this.el.emit('ar-hit-test-start');\n }.bind(this));\n\n // These are transient inputs so need to be handled separately\n var profileToSupport = 'generic-touchscreen';\n var transientHitTest = new HitTest(renderer, {\n profile: profileToSupport\n });\n session.addEventListener('selectstart', function (e) {\n if (this.data.enabled !== true) {\n return;\n }\n var inputSource = e.inputSource;\n this.bboxMesh.visible = true;\n if (this.hasPosedOnce === true) {\n this.el.emit('ar-hit-test-select-start', {\n inputSource: inputSource,\n position: this.bboxMesh.position,\n orientation: this.bboxMesh.quaternion\n });\n if (inputSource.profiles[0] === profileToSupport) {\n this.hitTest = transientHitTest;\n } else {\n this.hitTest = hitTestCache.get(inputSource) || new HitTest(renderer, {\n space: inputSource.targetRaySpace\n });\n hitTestCache.set(inputSource, this.hitTest);\n }\n }\n }.bind(this));\n session.addEventListener('selectend', function (e) {\n if (!this.hitTest || this.data.enabled !== true) {\n this.hitTest = null;\n return;\n }\n var inputSource = e.inputSource;\n var object;\n if (this.hasPosedOnce === true) {\n this.bboxMesh.visible = false;\n\n // if we have a target with a 3D object then automatically generate an anchor for it.\n if (this.data.target) {\n object = this.data.target.object3D;\n if (object) {\n applyPose.tempFakePose.transform.position.copy(this.bboxMesh.position);\n applyPose.tempFakePose.transform.orientation.copy(this.bboxMesh.quaternion);\n applyPose(applyPose.tempFakePose, object, this.bboxOffset);\n object.visible = true;\n\n // create an anchor attached to the object\n this.hitTest.anchorFromLastHitTestResult(object, this.bboxOffset);\n }\n }\n this.el.emit('ar-hit-test-select', {\n inputSource: inputSource,\n position: this.bboxMesh.position,\n orientation: this.bboxMesh.quaternion\n });\n }\n this.hitTest = null;\n }.bind(this));\n }.bind(this));\n this.bboxOffset = new THREE.Vector3();\n this.update = this.update.bind(this);\n this.makeBBox();\n },\n update: function () {\n // If it is disabled it's cleaned up\n if (this.data.enabled === false) {\n this.hitTest = null;\n this.bboxMesh.visible = false;\n }\n if (this.data.target) {\n if (this.data.target.object3D) {\n this.data.target.addEventListener('model-loaded', this.update);\n this.data.target.object3D.layers.enable(CAM_LAYER);\n this.data.target.object3D.traverse(function (child) {\n child.layers.enable(CAM_LAYER);\n });\n } else {\n this.data.target.addEventListener('loaded', this.update, {\n once: true\n });\n }\n }\n this.bboxNeedsUpdate = true;\n },\n makeBBox: function () {\n var geometry = new THREE.PlaneGeometry(1, 1);\n var material = new THREE.MeshBasicMaterial({\n transparent: true,\n color: 0xffffff\n });\n geometry.rotateX(-Math.PI / 2);\n geometry.rotateY(-Math.PI / 2);\n this.bbox = new THREE.Box3();\n this.bboxMesh = new THREE.Mesh(geometry, material);\n this.el.setObject3D('ar-hit-test', this.bboxMesh);\n this.bboxMesh.visible = false;\n },\n updateFootprint: function () {\n var tempImageData;\n var renderer = this.el.sceneEl.renderer;\n var oldRenderTarget, oldBackground;\n var isXREnabled = renderer.xr.enabled;\n this.bboxMesh.material.map = this.canvasTexture;\n this.bboxMesh.material.needsUpdate = true;\n this.orthoCam.rotation.set(-Math.PI / 2, 0, -Math.PI / 2);\n this.orthoCam.position.copy(this.bboxMesh.position);\n this.orthoCam.position.y -= this.bboxMesh.scale.y / 2;\n this.orthoCam.near = 0.1;\n this.orthoCam.far = this.orthoCam.near + this.data.footprintDepth * this.bboxMesh.scale.y;\n this.orthoCam.position.y += this.orthoCam.far;\n this.orthoCam.right = this.bboxMesh.scale.z / 2;\n this.orthoCam.left = -this.bboxMesh.scale.z / 2;\n this.orthoCam.top = this.bboxMesh.scale.x / 2;\n this.orthoCam.bottom = -this.bboxMesh.scale.x / 2;\n this.orthoCam.updateProjectionMatrix();\n oldRenderTarget = renderer.getRenderTarget();\n renderer.setRenderTarget(this.textureTarget);\n renderer.xr.enabled = false;\n oldBackground = this.el.object3D.background;\n this.el.object3D.overrideMaterial = this.basicMaterial;\n this.el.object3D.background = null;\n renderer.render(this.el.object3D, this.orthoCam);\n this.el.object3D.background = oldBackground;\n this.el.object3D.overrideMaterial = null;\n renderer.xr.enabled = isXREnabled;\n renderer.setRenderTarget(oldRenderTarget);\n renderer.readRenderTargetPixels(this.textureTarget, 0, 0, 512, 512, this.imageDataArray);\n this.context.putImageData(this.imageData, 0, 0);\n this.context.shadowColor = 'white';\n this.context.shadowBlur = 10;\n this.context.drawImage(this.canvas, 0, 0);\n tempImageData = this.context.getImageData(0, 0, 512, 512);\n for (var i = 0; i < 512 * 512; i++) {\n // if it's a little bit transparent but not opaque make it middle transparent\n if (tempImageData.data[i * 4 + 3] !== 0 && tempImageData.data[i * 4 + 3] !== 255) {\n tempImageData.data[i * 4 + 3] = 128;\n }\n }\n this.context.putImageData(tempImageData, 0, 0);\n this.canvasTexture.needsUpdate = true;\n },\n tick: function () {\n var pose;\n var frame = this.el.sceneEl.frame;\n var renderer = this.el.sceneEl.renderer;\n if (frame) {\n // if we are in XR then update the positions of the objects attached to anchors\n HitTest.updateAnchorPoses(frame, renderer.xr.getReferenceSpace());\n }\n if (this.bboxNeedsUpdate) {\n this.bboxNeedsUpdate = false;\n if (!this.data.target || this.data.type === 'map') {\n var texture;\n if (this.textureCache.has(this.data.src)) {\n texture = this.textureCache.get(this.data.src);\n } else {\n texture = new THREE.TextureLoader().load(this.data.src);\n this.textureCache.set(this.data.src, texture);\n }\n this.bboxMesh.material.map = texture;\n this.bboxMesh.material.needsUpdate = true;\n }\n if (this.data.target && this.data.target.object3D) {\n this.bbox.setFromObject(this.data.target.object3D);\n this.bbox.getCenter(this.bboxMesh.position);\n this.bbox.getSize(this.bboxMesh.scale);\n if (this.data.type === 'footprint') {\n // Add a little buffer for the footprint border\n this.bboxMesh.scale.x *= 1.04;\n this.bboxMesh.scale.z *= 1.04;\n this.updateFootprint();\n }\n this.bboxMesh.position.y -= this.bboxMesh.scale.y / 2;\n this.bboxOffset.copy(this.bboxMesh.position);\n this.bboxOffset.sub(this.data.target.object3D.position);\n } else {\n this.bboxMesh.scale.set(this.data.mapSize.x, 1, this.data.mapSize.y);\n }\n }\n if (this.hitTest) {\n pose = this.hitTest.doHit(frame);\n if (pose) {\n if (this.hasPosedOnce !== true) {\n this.hasPosedOnce = true;\n this.el.emit('ar-hit-test-achieved');\n }\n this.bboxMesh.visible = true;\n this.bboxMesh.position.copy(pose.transform.position);\n this.bboxMesh.quaternion.copy(pose.transform.orientation);\n }\n }\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/scene/background.js\":\n/*!********************************************!*\\\n !*** ./src/components/scene/background.js ***!\n \\********************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\n/* global THREE */\nvar register = (__webpack_require__(/*! ../../core/component */ \"./src/core/component.js\").registerComponent);\nmodule.exports.Component = register('background', {\n schema: {\n color: {\n type: 'color',\n default: 'black'\n },\n transparent: {\n default: false\n }\n },\n sceneOnly: true,\n update: function () {\n var data = this.data;\n var object3D = this.el.object3D;\n if (data.transparent) {\n object3D.background = null;\n } else {\n object3D.background = new THREE.Color(data.color);\n }\n },\n remove: function () {\n var object3D = this.el.object3D;\n object3D.background = null;\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/scene/debug.js\":\n/*!***************************************!*\\\n !*** ./src/components/scene/debug.js ***!\n \\***************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar register = (__webpack_require__(/*! ../../core/component */ \"./src/core/component.js\").registerComponent);\nmodule.exports.Component = register('debug', {\n schema: {\n default: true\n },\n sceneOnly: true\n});\n\n/***/ }),\n\n/***/ \"./src/components/scene/device-orientation-permission-ui.js\":\n/*!******************************************************************!*\\\n !*** ./src/components/scene/device-orientation-permission-ui.js ***!\n \\******************************************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\n/* global DeviceOrientationEvent, location */\nvar registerComponent = (__webpack_require__(/*! ../../core/component */ \"./src/core/component.js\").registerComponent);\nvar constants = __webpack_require__(/*! ../../constants/ */ \"./src/constants/index.js\");\nvar MODAL_CLASS = 'a-modal';\nvar DIALOG_CLASS = 'a-dialog';\nvar DIALOG_TEXT_CLASS = 'a-dialog-text';\nvar DIALOG_TEXT_CONTAINER_CLASS = 'a-dialog-text-container';\nvar DIALOG_BUTTONS_CONTAINER_CLASS = 'a-dialog-buttons-container';\nvar DIALOG_BUTTON_CLASS = 'a-dialog-button';\nvar DIALOG_ALLOW_BUTTON_CLASS = 'a-dialog-allow-button';\nvar DIALOG_DENY_BUTTON_CLASS = 'a-dialog-deny-button';\nvar DIALOG_OK_BUTTON_CLASS = 'a-dialog-ok-button';\n\n/**\n * UI for enabling device motion permission\n */\nmodule.exports.Component = registerComponent('device-orientation-permission-ui', {\n schema: {\n enabled: {\n default: true\n },\n deviceMotionMessage: {\n default: 'This immersive website requires access to your device motion sensors.'\n },\n httpsMessage: {\n default: 'Access this site over HTTPS to enter VR mode and grant access to the device sensors.'\n },\n denyButtonText: {\n default: 'Deny'\n },\n allowButtonText: {\n default: 'Allow'\n },\n cancelButtonText: {\n default: 'Cancel'\n }\n },\n sceneOnly: true,\n init: function () {\n var self = this;\n if (!this.data.enabled) {\n return;\n }\n if (!window.isSecureContext) {\n this.showHTTPAlert();\n }\n\n // Browser doesn't support or doesn't require permission to DeviceOrientationEvent API.\n if (typeof DeviceOrientationEvent === 'undefined' || !DeviceOrientationEvent.requestPermission) {\n this.permissionGranted = true;\n return;\n }\n this.onDeviceMotionDialogAllowClicked = this.onDeviceMotionDialogAllowClicked.bind(this);\n this.onDeviceMotionDialogDenyClicked = this.onDeviceMotionDialogDenyClicked.bind(this);\n // Show dialog only if permission has not yet been granted.\n DeviceOrientationEvent.requestPermission().then(function () {\n self.el.emit('deviceorientationpermissiongranted');\n self.permissionGranted = true;\n }).catch(function () {\n self.devicePermissionDialogEl = createPermissionDialog(self.data.denyButtonText, self.data.allowButtonText, self.data.deviceMotionMessage, self.onDeviceMotionDialogAllowClicked, self.onDeviceMotionDialogDenyClicked);\n self.el.appendChild(self.devicePermissionDialogEl);\n });\n },\n remove: function () {\n // This removes the modal screen\n if (this.devicePermissionDialogEl) {\n this.el.removeChild(this.devicePermissionDialogEl);\n }\n },\n onDeviceMotionDialogDenyClicked: function () {\n this.remove();\n },\n showHTTPAlert: function () {\n var self = this;\n var httpAlertEl = createAlertDialog(self.data.cancelButtonText, self.data.httpsMessage, function () {\n self.el.removeChild(httpAlertEl);\n });\n this.el.appendChild(httpAlertEl);\n },\n /**\n * Enable device motion permission when clicked.\n */\n onDeviceMotionDialogAllowClicked: function () {\n var self = this;\n this.el.emit('deviceorientationpermissionrequested');\n DeviceOrientationEvent.requestPermission().then(function (response) {\n if (response === 'granted') {\n self.el.emit('deviceorientationpermissiongranted');\n self.permissionGranted = true;\n } else {\n self.el.emit('deviceorientationpermissionrejected');\n }\n self.remove();\n }).catch(console.error);\n }\n});\n\n/**\n * Create a modal dialog that request users permission to access the Device Motion API.\n *\n * @param {function} onAllowClicked - click event handler\n * @param {function} onDenyClicked - click event handler\n *\n * @returns {Element} Wrapper
.\n */\nfunction createPermissionDialog(denyText, allowText, dialogText, onAllowClicked, onDenyClicked) {\n var buttonsContainer;\n var denyButton;\n var acceptButton;\n buttonsContainer = document.createElement('div');\n buttonsContainer.classList.add(DIALOG_BUTTONS_CONTAINER_CLASS);\n\n // Buttons\n denyButton = document.createElement('button');\n denyButton.classList.add(DIALOG_BUTTON_CLASS, DIALOG_DENY_BUTTON_CLASS);\n denyButton.setAttribute(constants.AFRAME_INJECTED, '');\n denyButton.innerHTML = denyText;\n buttonsContainer.appendChild(denyButton);\n acceptButton = document.createElement('button');\n acceptButton.classList.add(DIALOG_BUTTON_CLASS, DIALOG_ALLOW_BUTTON_CLASS);\n acceptButton.setAttribute(constants.AFRAME_INJECTED, '');\n acceptButton.innerHTML = allowText;\n buttonsContainer.appendChild(acceptButton);\n\n // Ask for sensor events to be used\n acceptButton.addEventListener('click', function (evt) {\n evt.stopPropagation();\n onAllowClicked();\n });\n denyButton.addEventListener('click', function (evt) {\n evt.stopPropagation();\n onDenyClicked();\n });\n return createDialog(dialogText, buttonsContainer);\n}\nfunction createAlertDialog(closeText, dialogText, onOkClicked) {\n var buttonsContainer;\n var okButton;\n buttonsContainer = document.createElement('div');\n buttonsContainer.classList.add(DIALOG_BUTTONS_CONTAINER_CLASS);\n\n // Buttons\n okButton = document.createElement('button');\n okButton.classList.add(DIALOG_BUTTON_CLASS, DIALOG_OK_BUTTON_CLASS);\n okButton.setAttribute(constants.AFRAME_INJECTED, '');\n okButton.innerHTML = closeText;\n buttonsContainer.appendChild(okButton);\n\n // Ask for sensor events to be used\n okButton.addEventListener('click', function (evt) {\n evt.stopPropagation();\n onOkClicked();\n });\n return createDialog(dialogText, buttonsContainer);\n}\nfunction createDialog(text, buttonsContainerEl) {\n var modalContainer;\n var dialog;\n var dialogTextContainer;\n var dialogText;\n modalContainer = document.createElement('div');\n modalContainer.classList.add(MODAL_CLASS);\n modalContainer.setAttribute(constants.AFRAME_INJECTED, '');\n dialog = document.createElement('div');\n dialog.className = DIALOG_CLASS;\n dialog.setAttribute(constants.AFRAME_INJECTED, '');\n modalContainer.appendChild(dialog);\n dialogTextContainer = document.createElement('div');\n dialogTextContainer.classList.add(DIALOG_TEXT_CONTAINER_CLASS);\n dialog.appendChild(dialogTextContainer);\n dialogText = document.createElement('div');\n dialogText.classList.add(DIALOG_TEXT_CLASS);\n dialogText.innerHTML = text;\n dialogTextContainer.appendChild(dialogText);\n dialog.appendChild(buttonsContainerEl);\n return modalContainer;\n}\n\n/***/ }),\n\n/***/ \"./src/components/scene/embedded.js\":\n/*!******************************************!*\\\n !*** ./src/components/scene/embedded.js ***!\n \\******************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar registerComponent = (__webpack_require__(/*! ../../core/component */ \"./src/core/component.js\").registerComponent);\n\n/**\n * Component to embed an a-frame scene within the layout of a 2D page.\n */\nmodule.exports.Component = registerComponent('embedded', {\n dependencies: ['xr-mode-ui'],\n schema: {\n default: true\n },\n sceneOnly: true,\n update: function () {\n var sceneEl = this.el;\n var enterVREl = sceneEl.querySelector('.a-enter-vr');\n if (this.data === true) {\n if (enterVREl) {\n enterVREl.classList.add('embedded');\n }\n sceneEl.removeFullScreenStyles();\n } else {\n if (enterVREl) {\n enterVREl.classList.remove('embedded');\n }\n sceneEl.addFullScreenStyles();\n }\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/scene/fog.js\":\n/*!*************************************!*\\\n !*** ./src/components/scene/fog.js ***!\n \\*************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar register = (__webpack_require__(/*! ../../core/component */ \"./src/core/component.js\").registerComponent);\nvar THREE = __webpack_require__(/*! ../../lib/three */ \"./src/lib/three.js\");\nvar debug = __webpack_require__(/*! ../../utils/debug */ \"./src/utils/debug.js\");\nvar warn = debug('components:fog:warn');\n\n/**\n * Fog component.\n * Applies only to the scene entity.\n */\nmodule.exports.Component = register('fog', {\n schema: {\n color: {\n type: 'color',\n default: '#000'\n },\n density: {\n default: 0.00025\n },\n far: {\n default: 1000,\n min: 0\n },\n near: {\n default: 1,\n min: 0\n },\n type: {\n default: 'linear',\n oneOf: ['linear', 'exponential']\n }\n },\n sceneOnly: true,\n update: function () {\n var data = this.data;\n var el = this.el;\n var fog = this.el.object3D.fog;\n\n // (Re)create fog if fog doesn't exist or fog type changed.\n if (!fog || data.type !== fog.name) {\n el.object3D.fog = getFog(data);\n return;\n }\n\n // Fog data changed. Update fog.\n Object.keys(this.schema).forEach(function (key) {\n var value = data[key];\n if (key === 'color') {\n value = new THREE.Color(value);\n }\n fog[key] = value;\n });\n },\n /**\n * Remove fog on remove (callback).\n */\n remove: function () {\n var el = this.el;\n var fog = this.el.object3D.fog;\n if (!fog) {\n return;\n }\n el.object3D.fog = null;\n }\n});\n\n/**\n * Creates a fog object. Sets fog.name to be able to detect fog type changes.\n *\n * @param {object} data - Fog data.\n * @returns {object} fog\n */\nfunction getFog(data) {\n var fog;\n if (data.type === 'exponential') {\n fog = new THREE.FogExp2(data.color, data.density);\n } else {\n fog = new THREE.Fog(data.color, data.near, data.far);\n }\n fog.name = data.type;\n return fog;\n}\n\n/***/ }),\n\n/***/ \"./src/components/scene/inspector.js\":\n/*!*******************************************!*\\\n !*** ./src/components/scene/inspector.js ***!\n \\*******************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\n/* global AFRAME, INSPECTOR_VERSION */\nvar AFRAME_INJECTED = (__webpack_require__(/*! ../../constants */ \"./src/constants/index.js\").AFRAME_INJECTED);\nvar pkg = __webpack_require__(/*! ../../../package */ \"./package.json\");\nvar registerComponent = (__webpack_require__(/*! ../../core/component */ \"./src/core/component.js\").registerComponent);\nvar utils = __webpack_require__(/*! ../../utils/ */ \"./src/utils/index.js\");\n\n/**\n * 0.4.2 to 0.4.x\n * Will need to update this when A-Frame goes to 1.x.x.\n */\nfunction getFuzzyPatchVersion(version) {\n var split = version.split('.');\n split[2] = 'x';\n return split.join('.');\n}\nvar INSPECTOR_DEV_URL = 'https://aframe.io/aframe-inspector/dist/aframe-inspector.js';\nvar INSPECTOR_RELEASE_URL = 'https://unpkg.com/aframe-inspector@' + getFuzzyPatchVersion(pkg.version) + '/dist/aframe-inspector.min.js';\nvar INSPECTOR_URL = false ? 0 : INSPECTOR_RELEASE_URL;\nvar LOADING_MESSAGE = 'Loading Inspector';\nvar LOADING_ERROR_MESSAGE = 'Error loading Inspector';\nmodule.exports.Component = registerComponent('inspector', {\n schema: {\n url: {\n default: INSPECTOR_URL\n }\n },\n sceneOnly: true,\n init: function () {\n this.firstPlay = true;\n this.onKeydown = this.onKeydown.bind(this);\n this.onMessage = this.onMessage.bind(this);\n this.initOverlay();\n window.addEventListener('keydown', this.onKeydown);\n window.addEventListener('message', this.onMessage);\n },\n play: function () {\n var urlParam;\n if (!this.firstPlay) {\n return;\n }\n urlParam = utils.getUrlParameter('inspector');\n if (urlParam !== 'false' && !!urlParam) {\n this.openInspector();\n this.firstPlay = false;\n }\n },\n initOverlay: function () {\n var dotsHTML = '...';\n this.loadingMessageEl = document.createElement('div');\n this.loadingMessageEl.classList.add('a-inspector-loader');\n this.loadingMessageEl.innerHTML = LOADING_MESSAGE + dotsHTML;\n },\n remove: function () {\n this.removeEventListeners();\n },\n /**\n * + + i keyboard shortcut.\n */\n onKeydown: function (evt) {\n var shortcutPressed = evt.keyCode === 73 && (evt.ctrlKey && evt.altKey || evt.getModifierState('AltGraph'));\n if (!shortcutPressed) {\n return;\n }\n this.openInspector();\n },\n showLoader: function () {\n document.body.appendChild(this.loadingMessageEl);\n },\n hideLoader: function () {\n document.body.removeChild(this.loadingMessageEl);\n },\n /**\n * postMessage. aframe.io uses this to create a button on examples to open Inspector.\n */\n onMessage: function (evt) {\n if (evt.data === 'INJECT_AFRAME_INSPECTOR') {\n this.openInspector();\n }\n },\n openInspector: function (focusEl) {\n var self = this;\n var script;\n\n // Already injected. Open.\n if (AFRAME.INSPECTOR || AFRAME.inspectorInjected) {\n AFRAME.INSPECTOR.open(focusEl);\n return;\n }\n this.showLoader();\n\n // Inject.\n script = document.createElement('script');\n script.src = this.data.url;\n script.setAttribute('data-name', 'aframe-inspector');\n script.setAttribute(AFRAME_INJECTED, '');\n script.onload = function () {\n AFRAME.INSPECTOR.open(focusEl);\n self.hideLoader();\n self.removeEventListeners();\n };\n script.onerror = function () {\n self.loadingMessageEl.innerHTML = LOADING_ERROR_MESSAGE;\n };\n document.head.appendChild(script);\n AFRAME.inspectorInjected = true;\n },\n removeEventListeners: function () {\n window.removeEventListener('keydown', this.onKeydown);\n window.removeEventListener('message', this.onMessage);\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/scene/keyboard-shortcuts.js\":\n/*!****************************************************!*\\\n !*** ./src/components/scene/keyboard-shortcuts.js ***!\n \\****************************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar registerComponent = (__webpack_require__(/*! ../../core/component */ \"./src/core/component.js\").registerComponent);\nvar shouldCaptureKeyEvent = (__webpack_require__(/*! ../../utils/ */ \"./src/utils/index.js\").shouldCaptureKeyEvent);\nmodule.exports.Component = registerComponent('keyboard-shortcuts', {\n schema: {\n enterVR: {\n default: true\n },\n exitVR: {\n default: true\n }\n },\n sceneOnly: true,\n init: function () {\n this.onKeyup = this.onKeyup.bind(this);\n },\n update: function (oldData) {\n var data = this.data;\n this.enterVREnabled = data.enterVR;\n },\n play: function () {\n window.addEventListener('keyup', this.onKeyup, false);\n },\n pause: function () {\n window.removeEventListener('keyup', this.onKeyup);\n },\n onKeyup: function (evt) {\n var scene = this.el;\n if (!shouldCaptureKeyEvent(evt)) {\n return;\n }\n if (this.enterVREnabled && evt.keyCode === 70) {\n // f.\n scene.enterVR();\n }\n if (this.enterVREnabled && evt.keyCode === 27) {\n // escape.\n scene.exitVR();\n }\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/scene/pool.js\":\n/*!**************************************!*\\\n !*** ./src/components/scene/pool.js ***!\n \\**************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar debug = __webpack_require__(/*! ../../utils/debug */ \"./src/utils/debug.js\");\nvar registerComponent = (__webpack_require__(/*! ../../core/component */ \"./src/core/component.js\").registerComponent);\nvar warn = debug('components:pool:warn');\n\n/**\n * Pool component to reuse entities.\n * Avoids creating and destroying the same kind of entities.\n * Helps reduce GC pauses. For example in a game to reuse enemies entities.\n *\n * @member {array} availableEls - Available entities in the pool.\n * @member {array} usedEls - Entities of the pool in use.\n */\nmodule.exports.Component = registerComponent('pool', {\n schema: {\n container: {\n default: ''\n },\n mixin: {\n default: ''\n },\n size: {\n default: 0\n },\n dynamic: {\n default: false\n }\n },\n sceneOnly: true,\n multiple: true,\n initPool: function () {\n var i;\n this.availableEls = [];\n this.usedEls = [];\n if (!this.data.mixin) {\n warn('No mixin provided for pool component.');\n }\n if (this.data.container) {\n this.container = document.querySelector(this.data.container);\n if (!this.container) {\n warn('Container ' + this.data.container + ' not found.');\n }\n }\n this.container = this.container || this.el;\n for (i = 0; i < this.data.size; ++i) {\n this.createEntity();\n }\n },\n update: function (oldData) {\n var data = this.data;\n if (oldData.mixin !== data.mixin || oldData.size !== data.size) {\n this.initPool();\n }\n },\n /**\n * Add a new entity to the list of available entities.\n */\n createEntity: function () {\n var el;\n el = document.createElement('a-entity');\n el.play = this.wrapPlay(el.play);\n el.setAttribute('mixin', this.data.mixin);\n el.object3D.visible = false;\n el.pause();\n this.container.appendChild(el);\n this.availableEls.push(el);\n var usedEls = this.usedEls;\n el.addEventListener('loaded', function () {\n if (usedEls.indexOf(el) !== -1) {\n return;\n }\n el.object3DParent = el.object3D.parent;\n el.object3D.parent.remove(el.object3D);\n });\n },\n /**\n * Play wrapper for pooled entities. When pausing and playing a scene, don't want to play\n * entities that are not in use.\n */\n wrapPlay: function (playMethod) {\n var usedEls = this.usedEls;\n return function () {\n if (usedEls.indexOf(this) === -1) {\n return;\n }\n playMethod.call(this);\n };\n },\n /**\n * Used to request one of the available entities of the pool.\n */\n requestEntity: function () {\n var el;\n if (this.availableEls.length === 0) {\n if (this.data.dynamic === false) {\n warn('Requested entity from empty pool: ' + this.attrName);\n return;\n } else {\n warn('Requested entity from empty pool. This pool is dynamic and will resize ' + 'automatically. You might want to increase its initial size: ' + this.attrName);\n }\n this.createEntity();\n }\n el = this.availableEls.shift();\n this.usedEls.push(el);\n if (el.object3DParent) {\n el.object3DParent.add(el.object3D);\n this.updateRaycasters();\n }\n el.object3D.visible = true;\n return el;\n },\n /**\n * Used to return a used entity to the pool.\n */\n returnEntity: function (el) {\n var index = this.usedEls.indexOf(el);\n if (index === -1) {\n warn('The returned entity was not previously pooled from ' + this.attrName);\n return;\n }\n this.usedEls.splice(index, 1);\n this.availableEls.push(el);\n el.object3DParent = el.object3D.parent;\n el.object3D.parent.remove(el.object3D);\n this.updateRaycasters();\n el.object3D.visible = false;\n el.pause();\n return el;\n },\n updateRaycasters: function () {\n var raycasterEls = document.querySelectorAll('[raycaster]');\n raycasterEls.forEach(function (el) {\n el.components['raycaster'].setDirty();\n });\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/scene/real-world-meshing.js\":\n/*!****************************************************!*\\\n !*** ./src/components/scene/real-world-meshing.js ***!\n \\****************************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\n/* global XRPlane, XRMesh */\nvar register = (__webpack_require__(/*! ../../core/component */ \"./src/core/component.js\").registerComponent);\nvar THREE = __webpack_require__(/*! ../../lib/three */ \"./src/lib/three.js\");\n\n/**\n * Real World Meshing.\n *\n * Create entities with meshes corresponding to 3D surfaces detected in user's environment.\n * It requires a browser with support for the WebXR Mesh and Plane detection modules.\n *\n */\nmodule.exports.Component = register('real-world-meshing', {\n schema: {\n filterLabels: {\n type: 'array'\n },\n meshesEnabled: {\n default: true\n },\n meshMixin: {\n default: true\n },\n planesEnabled: {\n default: true\n },\n planeMixin: {\n default: ''\n }\n },\n sceneOnly: true,\n init: function () {\n var webxrData = this.el.getAttribute('webxr');\n var requiredFeaturesArray = webxrData.requiredFeatures;\n if (requiredFeaturesArray.indexOf('mesh-detection') === -1) {\n requiredFeaturesArray.push('mesh-detection');\n this.el.setAttribute('webxr', webxrData);\n }\n if (requiredFeaturesArray.indexOf('plane-detection') === -1) {\n requiredFeaturesArray.push('plane-detection');\n this.el.setAttribute('webxr', webxrData);\n }\n this.meshEntities = [];\n this.initWorldMeshEntity = this.initWorldMeshEntity.bind(this);\n },\n tick: function () {\n if (!this.el.is('ar-mode')) {\n return;\n }\n this.detectMeshes();\n this.updateMeshes();\n },\n detectMeshes: function () {\n var data = this.data;\n var detectedMeshes;\n var detectedPlanes;\n var sceneEl = this.el;\n var xrManager = sceneEl.renderer.xr;\n var frame;\n var meshEntities = this.meshEntities;\n var present = false;\n var newMeshes = [];\n var filterLabels = this.data.filterLabels;\n frame = sceneEl.frame;\n detectedMeshes = frame.detectedMeshes;\n detectedPlanes = frame.detectedPlanes;\n for (var i = 0; i < meshEntities.length; i++) {\n meshEntities[i].present = false;\n }\n if (data.meshesEnabled) {\n for (var mesh of detectedMeshes.values()) {\n // Ignore meshes that don't match the filterLabels.\n if (filterLabels.length && filterLabels.indexOf(mesh.semanticLabel) === -1) {\n continue;\n }\n for (i = 0; i < meshEntities.length; i++) {\n if (mesh === meshEntities[i].mesh) {\n present = true;\n meshEntities[i].present = true;\n if (meshEntities[i].lastChangedTime < mesh.lastChangedTime) {\n this.updateMeshGeometry(meshEntities[i].el, mesh);\n }\n meshEntities[i].lastChangedTime = mesh.lastChangedTime;\n break;\n }\n }\n if (!present) {\n newMeshes.push(mesh);\n }\n present = false;\n }\n }\n if (data.planesEnabled) {\n for (mesh of detectedPlanes.values()) {\n // Ignore meshes that don't match the filterLabels.\n if (filterLabels.length && filterLabels.indexOf(mesh.semanticLabel) === -1) {\n continue;\n }\n for (i = 0; i < meshEntities.length; i++) {\n if (mesh === meshEntities[i].mesh) {\n present = true;\n meshEntities[i].present = true;\n if (meshEntities[i].lastChangedTime < mesh.lastChangedTime) {\n this.updateMeshGeometry(meshEntities[i].el, mesh);\n }\n meshEntities[i].lastChangedTime = mesh.lastChangedTime;\n break;\n }\n }\n if (!present) {\n newMeshes.push(mesh);\n }\n present = false;\n }\n }\n this.deleteMeshes();\n this.createNewMeshes(newMeshes);\n },\n updateMeshes: function () {\n var auxMatrix = new THREE.Matrix4();\n return function () {\n var meshPose;\n var sceneEl = this.el;\n var meshEl;\n var frame = sceneEl.frame;\n var meshEntities = this.meshEntities;\n var referenceSpace = sceneEl.renderer.xr.getReferenceSpace();\n var meshSpace;\n for (var i = 0; i < meshEntities.length; i++) {\n meshSpace = meshEntities[i].mesh.meshSpace || meshEntities[i].mesh.planeSpace;\n meshPose = frame.getPose(meshSpace, referenceSpace);\n meshEl = meshEntities[i].el;\n if (!meshEl.hasLoaded) {\n continue;\n }\n auxMatrix.fromArray(meshPose.transform.matrix);\n auxMatrix.decompose(meshEl.object3D.position, meshEl.object3D.quaternion, meshEl.object3D.scale);\n }\n };\n }(),\n deleteMeshes: function () {\n var meshEntities = this.meshEntities;\n var newMeshEntities = [];\n for (var i = 0; i < meshEntities.length; i++) {\n if (!meshEntities[i].present) {\n this.el.removeChild(meshEntities[i]);\n } else {\n newMeshEntities.push(meshEntities[i]);\n }\n }\n this.meshEntities = newMeshEntities;\n },\n createNewMeshes: function (newMeshes) {\n var meshEl;\n for (var i = 0; i < newMeshes.length; i++) {\n meshEl = document.createElement('a-entity');\n this.meshEntities.push({\n mesh: newMeshes[i],\n el: meshEl\n });\n meshEl.addEventListener('loaded', this.initWorldMeshEntity);\n this.el.appendChild(meshEl);\n }\n },\n initMeshGeometry: function (mesh) {\n var geometry;\n var shape;\n var polygon;\n if (mesh instanceof XRPlane) {\n shape = new THREE.Shape();\n polygon = mesh.polygon;\n for (var i = 0; i < polygon.length; ++i) {\n if (i === 0) {\n shape.moveTo(polygon[i].x, polygon[i].z);\n } else {\n shape.lineTo(polygon[i].x, polygon[i].z);\n }\n }\n geometry = new THREE.ShapeGeometry(shape);\n geometry.rotateX(Math.PI / 2);\n return geometry;\n }\n geometry = new THREE.BufferGeometry();\n geometry.setAttribute('position', new THREE.BufferAttribute(mesh.vertices, 3));\n geometry.setIndex(new THREE.BufferAttribute(mesh.indices, 1));\n return geometry;\n },\n initWorldMeshEntity: function (evt) {\n var el = evt.target;\n var geometry;\n var mesh;\n var meshEntity;\n var meshEntities = this.meshEntities;\n for (var i = 0; i < meshEntities.length; i++) {\n if (meshEntities[i].el === el) {\n meshEntity = meshEntities[i];\n break;\n }\n }\n geometry = this.initMeshGeometry(meshEntity.mesh);\n mesh = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({\n color: Math.random() * 0xFFFFFF,\n side: THREE.DoubleSide\n }));\n el.setObject3D('mesh', mesh);\n if (meshEntity.mesh instanceof XRPlane && this.data.planeMixin) {\n el.setAttribute('mixin', this.data.planeMixin);\n } else {\n if (this.data.meshMixin) {\n el.setAttribute('mixin', this.data.meshMixin);\n }\n }\n el.setAttribute('data-world-mesh', meshEntity.mesh.semanticLabel);\n },\n updateMeshGeometry: function (entityEl, mesh) {\n var entityMesh = entityEl.getObject3D('mesh');\n entityMesh.geometry.dispose();\n entityMesh.geometry = this.initMeshGeometry(mesh);\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/scene/reflection.js\":\n/*!********************************************!*\\\n !*** ./src/components/scene/reflection.js ***!\n \\********************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\n/* global THREE, XRWebGLBinding */\nvar register = (__webpack_require__(/*! ../../core/component */ \"./src/core/component.js\").registerComponent);\n\n// source: view-source:https://storage.googleapis.com/chromium-webxr-test/r886480/proposals/lighting-estimation.html\nfunction updateLights(estimate, probeLight, directionalLight, directionalLightPosition) {\n var intensityScalar = Math.max(estimate.primaryLightIntensity.x, Math.max(estimate.primaryLightIntensity.y, estimate.primaryLightIntensity.z));\n probeLight.sh.fromArray(estimate.sphericalHarmonicsCoefficients);\n probeLight.intensity = 1;\n if (directionalLight) {\n directionalLight.color.setRGB(estimate.primaryLightIntensity.x / intensityScalar, estimate.primaryLightIntensity.y / intensityScalar, estimate.primaryLightIntensity.z / intensityScalar);\n directionalLight.intensity = intensityScalar;\n directionalLightPosition.copy(estimate.primaryLightDirection);\n }\n}\nmodule.exports.Component = register('reflection', {\n schema: {\n directionalLight: {\n type: 'selector'\n }\n },\n sceneOnly: true,\n init: function () {\n var self = this;\n this.cubeRenderTarget = new THREE.WebGLCubeRenderTarget(16);\n this.cubeCamera = new THREE.CubeCamera(0.1, 1000, this.cubeRenderTarget);\n this.lightingEstimationTexture = new THREE.WebGLCubeRenderTarget(16).texture;\n this.needsVREnvironmentUpdate = true;\n\n // Update WebXR to support light-estimation\n var webxrData = this.el.getAttribute('webxr');\n var optionalFeaturesArray = webxrData.optionalFeatures;\n if (!optionalFeaturesArray.includes('light-estimation')) {\n optionalFeaturesArray.push('light-estimation');\n this.el.setAttribute('webxr', webxrData);\n }\n this.el.addEventListener('enter-vr', function () {\n if (!self.el.is('ar-mode')) {\n return;\n }\n var renderer = self.el.renderer;\n var session = renderer.xr.getSession();\n if (session.requestLightProbe) {\n self.startLightProbe();\n }\n });\n this.el.addEventListener('exit-vr', function () {\n if (self.xrLightProbe) {\n self.stopLightProbe();\n }\n });\n this.el.object3D.environment = this.cubeRenderTarget.texture;\n },\n stopLightProbe: function () {\n this.xrLightProbe = null;\n if (this.probeLight) {\n this.probeLight.components.light.light.intensity = 0;\n }\n this.needsVREnvironmentUpdate = true;\n this.el.object3D.environment = this.cubeRenderTarget.texture;\n },\n startLightProbe: function () {\n this.needsLightProbeUpdate = true;\n },\n setupLightProbe: function () {\n var renderer = this.el.renderer;\n var xrSession = renderer.xr.getSession();\n var self = this;\n var gl = renderer.getContext();\n if (!this.probeLight) {\n var probeLight = document.createElement('a-light');\n probeLight.setAttribute('type', 'probe');\n probeLight.setAttribute('intensity', 0);\n this.el.appendChild(probeLight);\n this.probeLight = probeLight;\n }\n\n // Ensure that we have any extensions needed to use the preferred cube map format.\n switch (xrSession.preferredReflectionFormat) {\n case 'srgba8':\n gl.getExtension('EXT_sRGB');\n break;\n case 'rgba16f':\n gl.getExtension('OES_texture_half_float');\n break;\n }\n this.glBinding = new XRWebGLBinding(xrSession, gl);\n gl.getExtension('EXT_sRGB');\n gl.getExtension('OES_texture_half_float');\n xrSession.requestLightProbe().then(function (lightProbe) {\n self.xrLightProbe = lightProbe;\n lightProbe.addEventListener('reflectionchange', self.updateXRCubeMap.bind(self));\n }).catch(function (err) {\n console.warn('Lighting estimation not supported: ' + err.message);\n console.warn('Are you missing: webxr=\"optionalFeatures: light-estimation;\" from ?');\n });\n },\n updateXRCubeMap: function () {\n // Update Cube Map, cubeMap maybe some unavailable on some hardware\n var renderer = this.el.renderer;\n var cubeMap = this.glBinding.getReflectionCubeMap(this.xrLightProbe);\n if (cubeMap) {\n var rendererProps = renderer.properties.get(this.lightingEstimationTexture);\n rendererProps.__webglTexture = cubeMap;\n this.lightingEstimationTexture.needsPMREMUpdate = true;\n this.el.object3D.environment = this.lightingEstimationTexture;\n }\n },\n tick: function () {\n var scene = this.el.object3D;\n var renderer = this.el.renderer;\n var frame = this.el.frame;\n if (frame && this.xrLightProbe) {\n // light estimate may not yet be available, it takes a few frames to start working\n var estimate = frame.getLightEstimate(this.xrLightProbe);\n if (estimate) {\n updateLights(estimate, this.probeLight.components.light.light, this.data.directionalLight && this.data.directionalLight.components.light.light, this.data.directionalLight && this.data.directionalLight.object3D.position);\n }\n }\n if (this.needsVREnvironmentUpdate) {\n scene.environment = null;\n this.needsVREnvironmentUpdate = false;\n this.cubeCamera.position.set(0, 1.6, 0);\n this.cubeCamera.update(renderer, scene);\n scene.environment = this.cubeRenderTarget.texture;\n }\n if (this.needsLightProbeUpdate && frame) {\n // wait until the XR Session has started before trying to make\n // the light probe\n this.setupLightProbe();\n this.needsLightProbeUpdate = false;\n }\n },\n remove: function () {\n this.el.object3D.environment = null;\n if (this.probeLight) {\n this.el.removeChild(this.probeLight);\n }\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/scene/screenshot.js\":\n/*!********************************************!*\\\n !*** ./src/components/scene/screenshot.js ***!\n \\********************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\n/* global ImageData, URL */\nvar registerComponent = (__webpack_require__(/*! ../../core/component */ \"./src/core/component.js\").registerComponent);\nvar THREE = __webpack_require__(/*! ../../lib/three */ \"./src/lib/three.js\");\nvar VERTEX_SHADER = ['attribute vec3 position;', 'attribute vec2 uv;', 'uniform mat4 projectionMatrix;', 'uniform mat4 modelViewMatrix;', 'varying vec2 vUv;', 'void main() {', ' vUv = vec2( 1.- uv.x, uv.y );', ' gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );', '}'].join('\\n');\nvar FRAGMENT_SHADER = ['precision mediump float;', 'uniform samplerCube map;', 'varying vec2 vUv;', '#define M_PI 3.141592653589793238462643383279', 'void main() {', ' vec2 uv = vUv;', ' float longitude = uv.x * 2. * M_PI - M_PI + M_PI / 2.;', ' float latitude = uv.y * M_PI;', ' vec3 dir = vec3(', ' - sin( longitude ) * sin( latitude ),', ' cos( latitude ),', ' - cos( longitude ) * sin( latitude )', ' );', ' normalize( dir );', ' gl_FragColor = vec4( textureCube( map, dir ).rgb, 1.0 );', '}'].join('\\n');\n\n/**\n * Component to take screenshots of the scene using a keyboard shortcut (alt+s).\n * It can be configured to either take 360° captures (`equirectangular`)\n * or regular screenshots (`projection`)\n *\n * This is based on https://github.com/spite/THREE.CubemapToEquirectangular\n * To capture an equirectangular projection of the scene a THREE.CubeCamera is used\n * The cube map produced by the CubeCamera is projected on a quad and then rendered to\n * WebGLRenderTarget with an orthographic camera.\n */\nmodule.exports.Component = registerComponent('screenshot', {\n schema: {\n width: {\n default: 4096\n },\n height: {\n default: 2048\n },\n camera: {\n type: 'selector'\n }\n },\n sceneOnly: true,\n setup: function () {\n var el = this.el;\n if (this.canvas) {\n return;\n }\n var gl = el.renderer.getContext();\n if (!gl) {\n return;\n }\n this.cubeMapSize = gl.getParameter(gl.MAX_CUBE_MAP_TEXTURE_SIZE);\n this.material = new THREE.RawShaderMaterial({\n uniforms: {\n map: {\n type: 't',\n value: null\n }\n },\n vertexShader: VERTEX_SHADER,\n fragmentShader: FRAGMENT_SHADER,\n side: THREE.DoubleSide\n });\n this.quad = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), this.material);\n this.quad.visible = false;\n this.camera = new THREE.OrthographicCamera(-1 / 2, 1 / 2, 1 / 2, -1 / 2, -10000, 10000);\n this.canvas = document.createElement('canvas');\n this.ctx = this.canvas.getContext('2d');\n el.object3D.add(this.quad);\n this.onKeyDown = this.onKeyDown.bind(this);\n },\n getRenderTarget: function (width, height) {\n return new THREE.WebGLRenderTarget(width, height, {\n colorSpace: this.el.sceneEl.renderer.outputColorSpace,\n minFilter: THREE.LinearFilter,\n magFilter: THREE.LinearFilter,\n wrapS: THREE.ClampToEdgeWrapping,\n wrapT: THREE.ClampToEdgeWrapping,\n format: THREE.RGBAFormat,\n type: THREE.UnsignedByteType\n });\n },\n resize: function (width, height) {\n // Resize quad.\n this.quad.scale.set(width, height, 1);\n\n // Resize camera.\n this.camera.left = -1 * width / 2;\n this.camera.right = width / 2;\n this.camera.top = height / 2;\n this.camera.bottom = -1 * height / 2;\n this.camera.updateProjectionMatrix();\n\n // Resize canvas.\n this.canvas.width = width;\n this.canvas.height = height;\n },\n play: function () {\n window.addEventListener('keydown', this.onKeyDown);\n },\n /**\n * + + s = Regular screenshot.\n * + + + s = Equirectangular screenshot.\n */\n onKeyDown: function (evt) {\n var shortcutPressed = evt.keyCode === 83 && evt.ctrlKey && evt.altKey;\n if (!this.data || !shortcutPressed) {\n return;\n }\n var projection = evt.shiftKey ? 'equirectangular' : 'perspective';\n this.capture(projection);\n },\n /**\n * Capture a screenshot of the scene.\n *\n * @param {string} projection - Screenshot projection (equirectangular or perspective).\n */\n setCapture: function (projection) {\n var el = this.el;\n var size;\n var camera;\n var cubeCamera;\n var cubeRenderTarget;\n // Configure camera.\n if (projection === 'perspective') {\n // Quad is only used in equirectangular mode. Hide it in this case.\n this.quad.visible = false;\n // Use scene camera.\n camera = this.data.camera && this.data.camera.components.camera.camera || el.camera;\n size = {\n width: this.data.width,\n height: this.data.height\n };\n } else {\n // Use ortho camera.\n camera = this.camera;\n cubeRenderTarget = new THREE.WebGLCubeRenderTarget(Math.min(this.cubeMapSize, 2048), {\n format: THREE.RGBFormat,\n generateMipmaps: true,\n minFilter: THREE.LinearMipmapLinearFilter,\n colorSpace: THREE.SRGBColorSpace\n });\n // Create cube camera and copy position from scene camera.\n cubeCamera = new THREE.CubeCamera(el.camera.near, el.camera.far, cubeRenderTarget);\n // Copy camera position into cube camera;\n el.camera.getWorldPosition(cubeCamera.position);\n el.camera.getWorldQuaternion(cubeCamera.quaternion);\n // Render scene with cube camera.\n cubeCamera.update(el.renderer, el.object3D);\n this.quad.material.uniforms.map.value = cubeCamera.renderTarget.texture;\n size = {\n width: this.data.width,\n height: this.data.height\n };\n // Use quad to project image taken by the cube camera.\n this.quad.visible = true;\n }\n return {\n camera: camera,\n size: size,\n projection: projection\n };\n },\n /**\n * Maintained for backwards compatibility.\n */\n capture: function (projection) {\n var isVREnabled = this.el.renderer.xr.enabled;\n var renderer = this.el.renderer;\n var params;\n this.setup();\n // Disable VR.\n renderer.xr.enabled = false;\n params = this.setCapture(projection);\n this.renderCapture(params.camera, params.size, params.projection);\n // Trigger file download.\n this.saveCapture();\n // Restore VR.\n renderer.xr.enabled = isVREnabled;\n },\n /**\n * Return canvas instead of triggering download (e.g., for uploading blob to server).\n */\n getCanvas: function (projection) {\n var isVREnabled = this.el.renderer.xr.enabled;\n var renderer = this.el.renderer;\n this.setup();\n // Disable VR.\n var params = this.setCapture(projection);\n renderer.xr.enabled = false;\n this.renderCapture(params.camera, params.size, params.projection);\n // Restore VR.\n renderer.xr.enabled = isVREnabled;\n return this.canvas;\n },\n renderCapture: function (camera, size, projection) {\n var autoClear = this.el.renderer.autoClear;\n var el = this.el;\n var imageData;\n var output;\n var pixels;\n var renderer = el.renderer;\n // Create rendering target and buffer to store the read pixels.\n output = this.getRenderTarget(size.width, size.height);\n pixels = new Uint8Array(4 * size.width * size.height);\n // Resize quad, camera, and canvas.\n this.resize(size.width, size.height);\n // Render scene to render target.\n renderer.autoClear = true;\n renderer.clear();\n renderer.setRenderTarget(output);\n renderer.render(el.object3D, camera);\n renderer.autoClear = autoClear;\n // Read image pixels back.\n renderer.readRenderTargetPixels(output, 0, 0, size.width, size.height, pixels);\n renderer.setRenderTarget(null);\n if (projection === 'perspective') {\n pixels = this.flipPixelsVertically(pixels, size.width, size.height);\n }\n imageData = new ImageData(new Uint8ClampedArray(pixels), size.width, size.height);\n // Hide quad after projecting the image.\n this.quad.visible = false;\n // Copy pixels into canvas.\n this.ctx.putImageData(imageData, 0, 0);\n },\n flipPixelsVertically: function (pixels, width, height) {\n var flippedPixels = pixels.slice(0);\n for (var x = 0; x < width; ++x) {\n for (var y = 0; y < height; ++y) {\n flippedPixels[x * 4 + y * width * 4] = pixels[x * 4 + (height - y) * width * 4];\n flippedPixels[x * 4 + 1 + y * width * 4] = pixels[x * 4 + 1 + (height - y) * width * 4];\n flippedPixels[x * 4 + 2 + y * width * 4] = pixels[x * 4 + 2 + (height - y) * width * 4];\n flippedPixels[x * 4 + 3 + y * width * 4] = pixels[x * 4 + 3 + (height - y) * width * 4];\n }\n }\n return flippedPixels;\n },\n /**\n * Download capture to file.\n */\n saveCapture: function () {\n this.canvas.toBlob(function (blob) {\n var fileName = 'screenshot-' + document.title.toLowerCase() + '-' + Date.now() + '.png';\n var linkEl = document.createElement('a');\n var url = URL.createObjectURL(blob);\n linkEl.href = url;\n linkEl.setAttribute('download', fileName);\n linkEl.innerHTML = 'downloading...';\n linkEl.style.display = 'none';\n document.body.appendChild(linkEl);\n setTimeout(function () {\n linkEl.click();\n document.body.removeChild(linkEl);\n }, 1);\n }, 'image/png');\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/scene/stats.js\":\n/*!***************************************!*\\\n !*** ./src/components/scene/stats.js ***!\n \\***************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar registerComponent = (__webpack_require__(/*! ../../core/component */ \"./src/core/component.js\").registerComponent);\nvar RStats = __webpack_require__(/*! ../../../vendor/rStats */ \"./vendor/rStats.js\");\nvar utils = __webpack_require__(/*! ../../utils */ \"./src/utils/index.js\");\n__webpack_require__(/*! ../../../vendor/rStats.extras */ \"./vendor/rStats.extras.js\");\n__webpack_require__(/*! ../../lib/rStatsAframe */ \"./src/lib/rStatsAframe.js\");\nvar AFrameStats = window.aframeStats;\nvar HIDDEN_CLASS = 'a-hidden';\nvar ThreeStats = window.threeStats;\n\n/**\n * Stats appended to document.body by RStats.\n */\nmodule.exports.Component = registerComponent('stats', {\n schema: {\n default: true\n },\n sceneOnly: true,\n init: function () {\n var scene = this.el;\n if (utils.getUrlParameter('stats') === 'false') {\n return;\n }\n this.stats = createStats(scene);\n this.statsEl = document.querySelector('.rs-base');\n this.hideBound = this.hide.bind(this);\n this.showBound = this.show.bind(this);\n scene.addEventListener('enter-vr', this.hideBound);\n scene.addEventListener('exit-vr', this.showBound);\n },\n update: function () {\n if (!this.stats) {\n return;\n }\n return !this.data ? this.hide() : this.show();\n },\n remove: function () {\n this.el.removeEventListener('enter-vr', this.hideBound);\n this.el.removeEventListener('exit-vr', this.showBound);\n if (!this.statsEl) {\n return;\n } // Scene detached.\n this.statsEl.parentNode.removeChild(this.statsEl);\n },\n tick: function () {\n var stats = this.stats;\n if (!stats) {\n return;\n }\n stats('rAF').tick();\n stats('FPS').frame();\n stats().update();\n },\n hide: function () {\n this.statsEl.classList.add(HIDDEN_CLASS);\n },\n show: function () {\n this.statsEl.classList.remove(HIDDEN_CLASS);\n }\n});\nfunction createStats(scene) {\n var threeStats = new ThreeStats(scene.renderer);\n var aframeStats = new AFrameStats(scene);\n var plugins = scene.isMobile ? [] : [threeStats, aframeStats];\n return new RStats({\n css: [],\n // Our stylesheet is injected from `src/index.js`.\n values: {\n fps: {\n caption: 'fps',\n below: 30\n }\n },\n groups: [{\n caption: 'Framerate',\n values: ['fps', 'raf']\n }],\n plugins: plugins\n });\n}\n\n/***/ }),\n\n/***/ \"./src/components/scene/xr-mode-ui.js\":\n/*!********************************************!*\\\n !*** ./src/components/scene/xr-mode-ui.js ***!\n \\********************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar registerComponent = (__webpack_require__(/*! ../../core/component */ \"./src/core/component.js\").registerComponent);\nvar constants = __webpack_require__(/*! ../../constants/ */ \"./src/constants/index.js\");\nvar utils = __webpack_require__(/*! ../../utils/ */ \"./src/utils/index.js\");\nvar ENTER_VR_CLASS = 'a-enter-vr';\nvar ENTER_AR_CLASS = 'a-enter-ar';\nvar ENTER_VR_BTN_CLASS = 'a-enter-vr-button';\nvar ENTER_AR_BTN_CLASS = 'a-enter-ar-button';\nvar HIDDEN_CLASS = 'a-hidden';\nvar ORIENTATION_MODAL_CLASS = 'a-orientation-modal';\n\n/**\n * UI for entering VR mode.\n */\nmodule.exports.Component = registerComponent('xr-mode-ui', {\n dependencies: ['canvas'],\n schema: {\n enabled: {\n default: true\n },\n cardboardModeEnabled: {\n default: false\n },\n enterVRButton: {\n default: ''\n },\n enterVREnabled: {\n default: true\n },\n enterARButton: {\n default: ''\n },\n enterAREnabled: {\n default: true\n },\n XRMode: {\n default: 'vr',\n oneOf: ['vr', 'ar', 'xr']\n }\n },\n sceneOnly: true,\n init: function () {\n var self = this;\n var sceneEl = this.el;\n if (utils.getUrlParameter('ui') === 'false') {\n return;\n }\n this.insideLoader = false;\n this.enterVREl = null;\n this.enterAREl = null;\n this.orientationModalEl = null;\n this.bindMethods();\n\n // Hide/show VR UI when entering/exiting VR mode.\n sceneEl.addEventListener('enter-vr', this.updateEnterInterfaces);\n sceneEl.addEventListener('exit-vr', this.updateEnterInterfaces);\n sceneEl.addEventListener('update-vr-devices', this.updateEnterInterfaces);\n window.addEventListener('message', function (event) {\n if (event.data.type === 'loaderReady') {\n self.insideLoader = true;\n self.remove();\n }\n });\n\n // Modal that tells the user to change orientation if in portrait.\n window.addEventListener('orientationchange', this.toggleOrientationModalIfNeeded);\n },\n bindMethods: function () {\n this.onEnterVRButtonClick = this.onEnterVRButtonClick.bind(this);\n this.onEnterARButtonClick = this.onEnterARButtonClick.bind(this);\n this.onModalClick = this.onModalClick.bind(this);\n this.toggleOrientationModalIfNeeded = this.toggleOrientationModalIfNeeded.bind(this);\n this.updateEnterInterfaces = this.updateEnterInterfaces.bind(this);\n },\n /**\n * Exit VR when modal clicked.\n */\n onModalClick: function () {\n this.el.exitVR();\n },\n /**\n * Enter VR when clicked.\n */\n onEnterVRButtonClick: function () {\n this.el.enterVR();\n },\n /**\n * Enter AR when clicked.\n */\n onEnterARButtonClick: function () {\n this.el.enterAR();\n },\n update: function () {\n var data = this.data;\n var sceneEl = this.el;\n if (!data.enabled || this.insideLoader || utils.getUrlParameter('ui') === 'false') {\n return this.remove();\n }\n if (this.enterVREl || this.enterAREl || this.orientationModalEl) {\n return;\n }\n\n // Add UI if enabled and not already present.\n if (!this.enterVREl && data.enterVREnabled && (data.XRMode === 'xr' || data.XRMode === 'vr')) {\n if (data.enterVRButton) {\n // Custom button.\n this.enterVREl = document.querySelector(data.enterVRButton);\n this.enterVREl.addEventListener('click', this.onEnterVRButtonClick);\n } else {\n this.enterVREl = createEnterVRButton(this.onEnterVRButtonClick);\n sceneEl.appendChild(this.enterVREl);\n }\n }\n if (!this.enterAREl && data.enterAREnabled && (data.XRMode === 'xr' || data.XRMode === 'ar')) {\n if (data.enterARButton) {\n // Custom button.\n this.enterAREl = document.querySelector(data.enterARButton);\n this.enterAREl.addEventListener('click', this.onEnterARButtonClick);\n } else {\n this.enterAREl = createEnterARButton(this.onEnterARButtonClick, data.XRMode === 'xr');\n sceneEl.appendChild(this.enterAREl);\n }\n }\n this.orientationModalEl = createOrientationModal(this.onModalClick);\n sceneEl.appendChild(this.orientationModalEl);\n this.updateEnterInterfaces();\n },\n remove: function () {\n [this.enterVREl, this.enterAREl, this.orientationModalEl].forEach(function (uiElement) {\n if (uiElement && uiElement.parentNode) {\n uiElement.parentNode.removeChild(uiElement);\n }\n });\n this.enterVREl = undefined;\n this.enterAREl = undefined;\n this.orientationModalEl = undefined;\n },\n updateEnterInterfaces: function () {\n this.toggleEnterVRButtonIfNeeded();\n this.toggleEnterARButtonIfNeeded();\n this.toggleOrientationModalIfNeeded();\n },\n toggleEnterVRButtonIfNeeded: function () {\n var sceneEl = this.el;\n if (!this.enterVREl) {\n return;\n }\n if (sceneEl.is('vr-mode') || (sceneEl.isMobile || utils.device.isMobileDeviceRequestingDesktopSite()) && !this.data.cardboardModeEnabled && !utils.device.checkVRSupport()) {\n this.enterVREl.classList.add(HIDDEN_CLASS);\n } else {\n if (!utils.device.checkVRSupport()) {\n this.enterVREl.classList.add('fullscreen');\n }\n this.enterVREl.classList.remove(HIDDEN_CLASS);\n sceneEl.enterVR(false, true);\n }\n },\n toggleEnterARButtonIfNeeded: function () {\n var sceneEl = this.el;\n if (!this.enterAREl) {\n return;\n }\n // Hide the button while in a session, or if AR is not supported.\n if (sceneEl.is('vr-mode') || !utils.device.checkARSupport()) {\n this.enterAREl.classList.add(HIDDEN_CLASS);\n } else {\n this.enterAREl.classList.remove(HIDDEN_CLASS);\n sceneEl.enterVR(true, true);\n }\n },\n toggleOrientationModalIfNeeded: function () {\n var sceneEl = this.el;\n var orientationModalEl = this.orientationModalEl;\n if (!orientationModalEl || !sceneEl.isMobile) {\n return;\n }\n if (!utils.device.isLandscape() && sceneEl.is('vr-mode')) {\n // Show if in VR mode on portrait.\n orientationModalEl.classList.remove(HIDDEN_CLASS);\n } else {\n orientationModalEl.classList.add(HIDDEN_CLASS);\n }\n }\n});\n\n/**\n * Create a button that when clicked will enter into stereo-rendering mode for VR.\n *\n * Structure:
\n *\n * @param {function} onClick - click event handler\n * @returns {Element} Wrapper
.\n */\nfunction createEnterVRButton(onClick) {\n var vrButton;\n var wrapper;\n\n // Create elements.\n wrapper = document.createElement('div');\n wrapper.classList.add(ENTER_VR_CLASS);\n wrapper.setAttribute(constants.AFRAME_INJECTED, '');\n vrButton = document.createElement('button');\n vrButton.className = ENTER_VR_BTN_CLASS;\n vrButton.setAttribute('title', 'Enter VR mode with a headset or fullscreen without');\n vrButton.setAttribute(constants.AFRAME_INJECTED, '');\n if (utils.device.isMobile()) {\n applyStickyHoverFix(vrButton);\n }\n // Insert elements.\n wrapper.appendChild(vrButton);\n vrButton.addEventListener('click', function (evt) {\n onClick();\n evt.stopPropagation();\n });\n return wrapper;\n}\n\n/**\n * Create a button that when clicked will enter into AR mode\n *\n * Structure:
\n *\n * @param {function} onClick - click event handler\n * @returns {Element} Wrapper
.\n */\nfunction createEnterARButton(onClick, xrMode) {\n var arButton;\n var wrapper;\n\n // Create elements.\n wrapper = document.createElement('div');\n wrapper.classList.add(ENTER_AR_CLASS);\n if (xrMode) {\n wrapper.classList.add('xr');\n }\n wrapper.setAttribute(constants.AFRAME_INJECTED, '');\n arButton = document.createElement('button');\n arButton.className = ENTER_AR_BTN_CLASS;\n arButton.setAttribute('title', 'Enter AR mode with a headset or handheld device.');\n arButton.setAttribute(constants.AFRAME_INJECTED, '');\n if (utils.device.isMobile()) {\n applyStickyHoverFix(arButton);\n }\n // Insert elements.\n wrapper.appendChild(arButton);\n arButton.addEventListener('click', function (evt) {\n onClick();\n evt.stopPropagation();\n });\n return wrapper;\n}\n\n/**\n * Creates a modal dialog to request the user to switch to landscape orientation.\n *\n * @param {function} onClick - click event handler\n * @returns {Element} Wrapper
.\n */\nfunction createOrientationModal(onClick) {\n var modal = document.createElement('div');\n modal.className = ORIENTATION_MODAL_CLASS;\n modal.classList.add(HIDDEN_CLASS);\n modal.setAttribute(constants.AFRAME_INJECTED, '');\n var exit = document.createElement('button');\n exit.setAttribute(constants.AFRAME_INJECTED, '');\n exit.innerHTML = 'Exit VR';\n\n // Exit VR on close.\n exit.addEventListener('click', onClick);\n modal.appendChild(exit);\n return modal;\n}\n\n/**\n * CSS hover state is sticky in iOS (as in 12/18/2019)\n * They are not removed on mouseleave and this function applies a class\n * to resets the style.\n *\n * @param {function} buttonEl - Button element\n */\nfunction applyStickyHoverFix(buttonEl) {\n buttonEl.addEventListener('touchstart', function () {\n buttonEl.classList.remove('resethover');\n }, {\n passive: true\n });\n buttonEl.addEventListener('touchend', function () {\n buttonEl.classList.add('resethover');\n }, {\n passive: true\n });\n}\n\n/***/ }),\n\n/***/ \"./src/components/shadow.js\":\n/*!**********************************!*\\\n !*** ./src/components/shadow.js ***!\n \\**********************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar component = __webpack_require__(/*! ../core/component */ \"./src/core/component.js\");\nvar THREE = __webpack_require__(/*! ../lib/three */ \"./src/lib/three.js\");\nvar registerComponent = component.registerComponent;\n\n/**\n * Shadow component.\n *\n * When applied to an entity, that entity's geometry and any descendants will cast or receive\n * shadows as specified by the `cast` and `receive` properties.\n */\nmodule.exports.Component = registerComponent('shadow', {\n schema: {\n cast: {\n default: true\n },\n receive: {\n default: true\n }\n },\n init: function () {\n this.onMeshChanged = this.update.bind(this);\n this.el.addEventListener('object3dset', this.onMeshChanged);\n this.system.setShadowMapEnabled(true);\n },\n update: function () {\n var data = this.data;\n this.updateDescendants(data.cast, data.receive);\n },\n remove: function () {\n var el = this.el;\n el.removeEventListener('object3dset', this.onMeshChanged);\n this.updateDescendants(false, false);\n },\n updateDescendants: function (cast, receive) {\n var sceneEl = this.el.sceneEl;\n this.el.object3D.traverse(function (node) {\n if (!(node instanceof THREE.Mesh)) {\n return;\n }\n node.castShadow = cast;\n node.receiveShadow = receive;\n\n // If scene has already rendered, materials must be updated.\n if (sceneEl.hasLoaded && node.material) {\n var materials = Array.isArray(node.material) ? node.material : [node.material];\n for (var i = 0; i < materials.length; i++) {\n materials[i].needsUpdate = true;\n }\n }\n });\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/sound.js\":\n/*!*********************************!*\\\n !*** ./src/components/sound.js ***!\n \\*********************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar debug = __webpack_require__(/*! ../utils/debug */ \"./src/utils/debug.js\");\nvar THREE = __webpack_require__(/*! ../lib/three */ \"./src/lib/three.js\");\nvar warn = debug('components:sound:warn');\n\n/**\n * Sound component.\n */\nmodule.exports.Component = registerComponent('sound', {\n schema: {\n autoplay: {\n default: false\n },\n distanceModel: {\n default: 'inverse',\n oneOf: ['linear', 'inverse', 'exponential']\n },\n loop: {\n default: false\n },\n loopStart: {\n default: 0\n },\n loopEnd: {\n default: 0\n },\n maxDistance: {\n default: 10000\n },\n on: {\n default: ''\n },\n poolSize: {\n default: 1\n },\n positional: {\n default: true\n },\n refDistance: {\n default: 1\n },\n rolloffFactor: {\n default: 1\n },\n src: {\n type: 'audio'\n },\n volume: {\n default: 1\n }\n },\n multiple: true,\n init: function () {\n var self = this;\n this.listener = null;\n this.audioLoader = new THREE.AudioLoader();\n this.pool = new THREE.Group();\n this.loaded = false;\n this.mustPlay = false;\n\n // Don't pass evt because playSound takes a function as parameter.\n this.playSoundBound = function () {\n self.playSound();\n };\n },\n update: function (oldData) {\n var data = this.data;\n var i;\n var sound;\n var srcChanged = data.src !== oldData.src;\n\n // Create new sound if not yet created or changing `src`.\n if (srcChanged) {\n if (!data.src) {\n return;\n }\n this.setupSound();\n }\n for (i = 0; i < this.pool.children.length; i++) {\n sound = this.pool.children[i];\n if (data.positional) {\n sound.setDistanceModel(data.distanceModel);\n sound.setMaxDistance(data.maxDistance);\n sound.setRefDistance(data.refDistance);\n sound.setRolloffFactor(data.rolloffFactor);\n }\n sound.setLoop(data.loop);\n sound.setLoopStart(data.loopStart);\n\n // With a loop start specified without a specified loop end, the end of the loop should be the end of the file\n if (data.loopStart !== 0 && data.loopEnd === 0) {\n sound.setLoopEnd(sound.buffer.duration);\n } else {\n sound.setLoopEnd(data.loopEnd);\n }\n sound.setVolume(data.volume);\n sound.isPaused = false;\n }\n if (data.on !== oldData.on) {\n this.updateEventListener(oldData.on);\n }\n\n // All sound values set. Load in `src`.\n if (srcChanged) {\n var self = this;\n this.loaded = false;\n this.audioLoader.load(data.src, function (buffer) {\n for (i = 0; i < self.pool.children.length; i++) {\n sound = self.pool.children[i];\n sound.setBuffer(buffer);\n }\n self.loaded = true;\n\n // Remove this key from cache, otherwise we can't play it again\n THREE.Cache.remove(data.src);\n if (self.data.autoplay || self.mustPlay) {\n self.playSound(self.processSound);\n }\n self.el.emit('sound-loaded', self.evtDetail, false);\n });\n }\n },\n pause: function () {\n this.stopSound();\n this.removeEventListener();\n },\n play: function () {\n if (this.data.autoplay) {\n this.playSound();\n }\n this.updateEventListener();\n },\n remove: function () {\n var i;\n var sound;\n this.removeEventListener();\n if (this.el.getObject3D(this.attrName)) {\n this.el.removeObject3D(this.attrName);\n }\n try {\n for (i = 0; i < this.pool.children.length; i++) {\n sound = this.pool.children[i];\n sound.disconnect();\n }\n } catch (e) {\n // disconnect() will throw if it was never connected initially.\n warn('Audio source not properly disconnected');\n }\n },\n /**\n * Update listener attached to the user defined on event.\n */\n updateEventListener: function (oldEvt) {\n var el = this.el;\n if (oldEvt) {\n el.removeEventListener(oldEvt, this.playSoundBound);\n }\n el.addEventListener(this.data.on, this.playSoundBound);\n },\n removeEventListener: function () {\n this.el.removeEventListener(this.data.on, this.playSoundBound);\n },\n /**\n * Removes current sound object, creates new sound object, adds to entity.\n *\n * @returns {object} sound\n */\n setupSound: function () {\n var el = this.el;\n var i;\n var sceneEl = el.sceneEl;\n var self = this;\n var sound;\n if (this.pool.children.length > 0) {\n this.stopSound();\n el.removeObject3D('sound');\n }\n\n // Only want one AudioListener. Cache it on the scene.\n var listener = this.listener = sceneEl.audioListener || new THREE.AudioListener();\n sceneEl.audioListener = listener;\n if (sceneEl.camera) {\n sceneEl.camera.add(listener);\n }\n\n // Wait for camera if necessary.\n sceneEl.addEventListener('camera-set-active', function (evt) {\n evt.detail.cameraEl.getObject3D('camera').add(listener);\n });\n\n // Create [poolSize] audio instances and attach them to pool\n this.pool = new THREE.Group();\n for (i = 0; i < this.data.poolSize; i++) {\n sound = this.data.positional ? new THREE.PositionalAudio(listener) : new THREE.Audio(listener);\n this.pool.add(sound);\n }\n el.setObject3D(this.attrName, this.pool);\n for (i = 0; i < this.pool.children.length; i++) {\n sound = this.pool.children[i];\n sound.onEnded = function () {\n this.isPlaying = false;\n self.el.emit('sound-ended', self.evtDetail, false);\n };\n }\n },\n /**\n * Pause all the sounds in the pool.\n */\n pauseSound: function () {\n var i;\n var sound;\n this.isPlaying = false;\n for (i = 0; i < this.pool.children.length; i++) {\n sound = this.pool.children[i];\n if (!sound.source || !sound.source.buffer || !sound.isPlaying || sound.isPaused) {\n continue;\n }\n sound.isPaused = true;\n sound.pause();\n }\n },\n /**\n * Look for an unused sound in the pool and play it if found.\n */\n playSound: function (processSound) {\n var found;\n var i;\n var sound;\n if (!this.loaded) {\n warn('Sound not loaded yet. It will be played once it finished loading');\n this.mustPlay = true;\n this.processSound = processSound;\n return;\n }\n found = false;\n this.isPlaying = true;\n for (i = 0; i < this.pool.children.length; i++) {\n sound = this.pool.children[i];\n if (!sound.isPlaying && sound.buffer && !found) {\n if (processSound) {\n processSound(sound);\n }\n sound.play();\n sound.isPaused = false;\n found = true;\n continue;\n }\n }\n if (!found) {\n warn('All the sounds are playing. If you need to play more sounds simultaneously ' + 'consider increasing the size of pool with the `poolSize` attribute.', this.el);\n return;\n }\n this.mustPlay = false;\n this.processSound = undefined;\n },\n /**\n * Stop all the sounds in the pool.\n */\n stopSound: function () {\n var i;\n var sound;\n this.isPlaying = false;\n for (i = 0; i < this.pool.children.length; i++) {\n sound = this.pool.children[i];\n if (!sound.source || !sound.source.buffer) {\n return;\n }\n sound.stop();\n }\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/text.js\":\n/*!********************************!*\\\n !*** ./src/components/text.js ***!\n \\********************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar createTextGeometry = __webpack_require__(/*! three-bmfont-text */ \"./node_modules/three-bmfont-text/index.js\");\nvar loadBMFont = __webpack_require__(/*! load-bmfont */ \"./node_modules/load-bmfont/browser.js\");\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar coreShader = __webpack_require__(/*! ../core/shader */ \"./src/core/shader.js\");\nvar THREE = __webpack_require__(/*! ../lib/three */ \"./src/lib/three.js\");\nvar utils = __webpack_require__(/*! ../utils/ */ \"./src/utils/index.js\");\nvar error = utils.debug('components:text:error');\nvar shaders = coreShader.shaders;\nvar warn = utils.debug('components:text:warn');\n\n// 1 to match other A-Frame default widths.\nvar DEFAULT_WIDTH = 1;\n\n// @bryik set anisotropy to 16. Improves look of large amounts of text when viewed from angle.\nvar MAX_ANISOTROPY = 16;\nvar AFRAME_CDN_ROOT = (__webpack_require__(/*! ../constants */ \"./src/constants/index.js\").AFRAME_CDN_ROOT);\nvar FONT_BASE_URL = AFRAME_CDN_ROOT + 'fonts/';\nvar FONTS = {\n aileronsemibold: FONT_BASE_URL + 'Aileron-Semibold.fnt',\n dejavu: FONT_BASE_URL + 'DejaVu-sdf.fnt',\n exo2bold: FONT_BASE_URL + 'Exo2Bold.fnt',\n exo2semibold: FONT_BASE_URL + 'Exo2SemiBold.fnt',\n kelsonsans: FONT_BASE_URL + 'KelsonSans.fnt',\n monoid: FONT_BASE_URL + 'Monoid.fnt',\n mozillavr: FONT_BASE_URL + 'mozillavr.fnt',\n roboto: FONT_BASE_URL + 'Roboto-msdf.json',\n sourcecodepro: FONT_BASE_URL + 'SourceCodePro.fnt'\n};\nvar MSDF_FONTS = ['roboto'];\nvar DEFAULT_FONT = 'roboto';\nmodule.exports.FONTS = FONTS;\nvar cache = new PromiseCache();\nvar fontWidthFactors = {};\nvar textures = {};\n\n// Regular expression for detecting a URLs with a protocol prefix.\nvar protocolRe = /^\\w+:/;\n\n/**\n * SDF-based text component.\n * Based on https://github.com/Jam3/three-bmfont-text.\n *\n * All the stock fonts are for the `sdf` registered shader, an improved version of jam3's\n * original `sdf` shader.\n */\nmodule.exports.Component = registerComponent('text', {\n multiple: true,\n schema: {\n align: {\n type: 'string',\n default: 'left',\n oneOf: ['left', 'right', 'center']\n },\n alphaTest: {\n default: 0.5\n },\n // `anchor` defaults to center to match geometries.\n anchor: {\n default: 'center',\n oneOf: ['left', 'right', 'center', 'align']\n },\n baseline: {\n default: 'center',\n oneOf: ['top', 'center', 'bottom']\n },\n color: {\n type: 'color',\n default: '#FFF'\n },\n font: {\n type: 'string',\n default: DEFAULT_FONT\n },\n // `fontImage` defaults to the font name as a .png (e.g., mozillavr.fnt -> mozillavr.png).\n fontImage: {\n type: 'string'\n },\n // `height` has no default, will be populated at layout.\n height: {\n type: 'number'\n },\n letterSpacing: {\n type: 'number',\n default: 0\n },\n // `lineHeight` defaults to font's `lineHeight` value.\n lineHeight: {\n type: 'number'\n },\n // `negate` must be true for fonts generated with older versions of msdfgen (white background).\n negate: {\n type: 'boolean',\n default: true\n },\n opacity: {\n type: 'number',\n default: 1.0\n },\n shader: {\n default: 'sdf',\n oneOf: shaders\n },\n side: {\n default: 'front',\n oneOf: ['front', 'back', 'double']\n },\n tabSize: {\n default: 4\n },\n transparent: {\n default: true\n },\n value: {\n type: 'string'\n },\n whiteSpace: {\n default: 'normal',\n oneOf: ['normal', 'pre', 'nowrap']\n },\n // `width` defaults to geometry width if present, else `DEFAULT_WIDTH`.\n width: {\n type: 'number'\n },\n // `wrapCount` units are about one default font character. Wrap roughly at this number.\n wrapCount: {\n type: 'number',\n default: 40\n },\n // `wrapPixels` will wrap using bmfont pixel units (e.g., dejavu's is 32 pixels).\n wrapPixels: {\n type: 'number'\n },\n // `xOffset` to add padding.\n xOffset: {\n type: 'number',\n default: 0\n },\n // `yOffset` to adjust generated fonts from tools that may have incorrect metrics.\n yOffset: {\n type: 'number',\n default: 0\n },\n // `zOffset` will provide a small z offset to avoid z-fighting.\n zOffset: {\n type: 'number',\n default: 0.001\n }\n },\n init: function () {\n this.shaderData = {};\n this.geometry = createTextGeometry();\n this.createOrUpdateMaterial();\n this.explicitGeoDimensionsChecked = false;\n },\n update: function (oldData) {\n var data = this.data;\n var font = this.currentFont;\n if (textures[data.font]) {\n this.texture = textures[data.font];\n } else {\n // Create texture per font.\n this.texture = textures[data.font] = new THREE.Texture();\n this.texture.anisotropy = MAX_ANISOTROPY;\n }\n\n // Update material.\n this.createOrUpdateMaterial();\n\n // New font. `updateFont` will later change data and layout.\n if (oldData.font !== data.font) {\n this.updateFont();\n return;\n }\n\n // Update geometry and layout.\n if (font) {\n this.updateGeometry(this.geometry, font);\n this.updateLayout();\n }\n },\n /**\n * Clean up geometry, material, texture, mesh, objects.\n */\n remove: function () {\n this.geometry.dispose();\n this.geometry = null;\n this.el.removeObject3D(this.attrName);\n this.material.dispose();\n this.material = null;\n this.texture.dispose();\n this.texture = null;\n if (this.shaderObject) {\n delete this.shaderObject;\n }\n },\n /**\n * Update the shader of the material.\n */\n createOrUpdateMaterial: function () {\n var data = this.data;\n var hasChangedShader;\n var material = this.material;\n var NewShader;\n var shaderData = this.shaderData;\n var shaderName;\n\n // Infer shader if using a stock font (or from `-msdf` filename convention).\n shaderName = data.shader;\n if (MSDF_FONTS.indexOf(data.font) !== -1 || data.font.indexOf('-msdf.') >= 0) {\n shaderName = 'msdf';\n } else if (data.font in FONTS && MSDF_FONTS.indexOf(data.font) === -1) {\n shaderName = 'sdf';\n }\n hasChangedShader = (this.shaderObject && this.shaderObject.name) !== shaderName;\n shaderData.alphaTest = data.alphaTest;\n shaderData.color = data.color;\n shaderData.map = this.texture;\n shaderData.opacity = data.opacity;\n shaderData.side = parseSide(data.side);\n shaderData.transparent = data.transparent;\n shaderData.negate = data.negate;\n\n // Shader has not changed, do an update.\n if (!hasChangedShader) {\n // Update shader material.\n this.shaderObject.update(shaderData);\n // Apparently, was not set on `init` nor `update`.\n material.transparent = shaderData.transparent;\n material.side = shaderData.side;\n return;\n }\n\n // Shader has changed. Create a shader material.\n NewShader = createShader(this.el, shaderName, shaderData);\n this.material = NewShader.material;\n this.shaderObject = NewShader.shader;\n\n // Set new shader material.\n this.material.side = shaderData.side;\n if (this.mesh) {\n this.mesh.material = this.material;\n }\n },\n /**\n * Load font for geometry, load font image for material, and apply.\n */\n updateFont: function () {\n var data = this.data;\n var el = this.el;\n var fontSrc;\n var geometry = this.geometry;\n var self = this;\n if (!data.font) {\n warn('No font specified. Using the default font.');\n }\n\n // Make invisible during font swap.\n if (this.mesh) {\n this.mesh.visible = false;\n }\n\n // Look up font URL to use, and perform cached load.\n fontSrc = this.lookupFont(data.font || DEFAULT_FONT) || data.font;\n cache.get(fontSrc, function doLoadFont() {\n return loadFont(fontSrc, data.yOffset);\n }).then(function setFont(font) {\n var fontImgSrc;\n if (font.pages.length !== 1) {\n throw new Error('Currently only single-page bitmap fonts are supported.');\n }\n if (!fontWidthFactors[fontSrc]) {\n font.widthFactor = fontWidthFactors[font] = computeFontWidthFactor(font);\n }\n self.currentFont = font;\n // Look up font image URL to use, and perform cached load.\n fontImgSrc = self.getFontImageSrc();\n cache.get(fontImgSrc, function () {\n return loadTexture(fontImgSrc);\n }).then(function (image) {\n // Make mesh visible and apply font image as texture.\n var texture = self.texture;\n // The component may have been removed at this point and texture will\n // be null. This happens mainly while executing the tests,\n // in this case we just return.\n if (!texture) return;\n texture.image = image;\n texture.needsUpdate = true;\n textures[data.font] = texture;\n self.texture = texture;\n self.initMesh();\n self.currentFont = font;\n // Update geometry given font metrics.\n self.updateGeometry(geometry, font);\n self.updateLayout();\n self.mesh.visible = true;\n el.emit('textfontset', {\n font: data.font,\n fontObj: font\n });\n }).catch(function (err) {\n error(err.message);\n error(err.stack);\n });\n }).catch(function (err) {\n error(err.message);\n error(err.stack);\n });\n },\n initMesh: function () {\n if (this.mesh) {\n return;\n }\n this.mesh = new THREE.Mesh(this.geometry, this.material);\n this.el.setObject3D(this.attrName, this.mesh);\n },\n getFontImageSrc: function () {\n if (this.data.fontImage) {\n return this.data.fontImage;\n }\n var fontSrc = this.lookupFont(this.data.font || DEFAULT_FONT) || this.data.font;\n var imageSrc = this.currentFont.pages[0];\n // If the image URL contains a non-HTTP(S) protocol, assume it's an absolute\n // path on disk and try to infer the path from the font source instead.\n if (imageSrc.match(protocolRe) && imageSrc.indexOf('http') !== 0) {\n return fontSrc.replace(/(\\.fnt)|(\\.json)/, '.png');\n }\n return THREE.LoaderUtils.extractUrlBase(fontSrc) + imageSrc;\n },\n /**\n * Update layout with anchor, alignment, baseline, and considering any meshes.\n */\n updateLayout: function () {\n var anchor;\n var baseline;\n var el = this.el;\n var data = this.data;\n var geometry = this.geometry;\n var geometryComponent;\n var height;\n var layout;\n var mesh = this.mesh;\n var textRenderWidth;\n var textScale;\n var width;\n var x;\n var y;\n if (!mesh || !geometry.layout) {\n return;\n }\n\n // Determine width to use (defined width, geometry's width, or default width).\n geometryComponent = el.getAttribute('geometry');\n width = data.width || geometryComponent && geometryComponent.width || DEFAULT_WIDTH;\n\n // Determine wrap pixel count. Either specified or by experimental fudge factor.\n // Note that experimental factor will never be correct for variable width fonts.\n textRenderWidth = computeWidth(data.wrapPixels, data.wrapCount, this.currentFont.widthFactor);\n textScale = width / textRenderWidth;\n\n // Determine height to use.\n layout = geometry.layout;\n height = textScale * (layout.height + layout.descender);\n\n // Update geometry dimensions to match text layout if width and height are set to 0.\n // For example, scales a plane to fit text.\n if (geometryComponent && geometryComponent.primitive === 'plane') {\n if (!this.explicitGeoDimensionsChecked) {\n this.explicitGeoDimensionsChecked = true;\n this.hasExplicitGeoWidth = !!geometryComponent.width;\n this.hasExplicitGeoHeight = !!geometryComponent.height;\n }\n if (!this.hasExplicitGeoWidth) {\n el.setAttribute('geometry', 'width', width);\n }\n if (!this.hasExplicitGeoHeight) {\n el.setAttribute('geometry', 'height', height);\n }\n }\n\n // Calculate X position to anchor text left, center, or right.\n anchor = data.anchor === 'align' ? data.align : data.anchor;\n if (anchor === 'left') {\n x = 0;\n } else if (anchor === 'right') {\n x = -1 * layout.width;\n } else if (anchor === 'center') {\n x = -1 * layout.width / 2;\n } else {\n throw new TypeError('Invalid text.anchor property value', anchor);\n }\n\n // Calculate Y position to anchor text top, center, or bottom.\n baseline = data.baseline;\n if (baseline === 'bottom') {\n y = 0;\n } else if (baseline === 'top') {\n y = -1 * layout.height + layout.ascender;\n } else if (baseline === 'center') {\n y = -1 * layout.height / 2;\n } else {\n throw new TypeError('Invalid text.baseline property value', baseline);\n }\n\n // Position and scale mesh to apply layout.\n mesh.position.x = x * textScale + data.xOffset;\n mesh.position.y = y * textScale;\n // Place text slightly in front to avoid Z-fighting.\n mesh.position.z = data.zOffset;\n mesh.scale.set(textScale, -1 * textScale, textScale);\n },\n /**\n * Grab font from the constant.\n * Set as a method for test stubbing purposes.\n */\n lookupFont: function (key) {\n return FONTS[key];\n },\n /**\n * Update the text geometry using `three-bmfont-text.update`.\n */\n updateGeometry: function () {\n var geometryUpdateBase = {};\n var geometryUpdateData = {};\n var newLineRegex = /\\\\n/g;\n var tabRegex = /\\\\t/g;\n return function (geometry, font) {\n var data = this.data;\n geometryUpdateData.font = font;\n geometryUpdateData.lineHeight = data.lineHeight && isFinite(data.lineHeight) ? data.lineHeight : font.common.lineHeight;\n geometryUpdateData.text = data.value.toString().replace(newLineRegex, '\\n').replace(tabRegex, '\\t');\n geometryUpdateData.width = computeWidth(data.wrapPixels, data.wrapCount, font.widthFactor);\n geometry.update(utils.extend(geometryUpdateBase, data, geometryUpdateData));\n };\n }()\n});\n\n/**\n * Due to using negative scale, we return the opposite side specified.\n * https://github.com/mrdoob/three.js/pull/12787/\n */\nfunction parseSide(side) {\n switch (side) {\n case 'back':\n {\n return THREE.FrontSide;\n }\n case 'double':\n {\n return THREE.DoubleSide;\n }\n default:\n {\n return THREE.BackSide;\n }\n }\n}\n\n/**\n * @returns {Promise}\n */\nfunction loadFont(src, yOffset) {\n return new Promise(function (resolve, reject) {\n loadBMFont(src, function (err, font) {\n if (err) {\n error('Error loading font', src);\n reject(err);\n return;\n }\n\n // Fix negative Y offsets for Roboto MSDF font from tool. Experimentally determined.\n if (src.indexOf('/Roboto-msdf.json') >= 0) {\n yOffset = 30;\n }\n if (yOffset) {\n font.chars.map(function doOffset(ch) {\n ch.yoffset += yOffset;\n });\n }\n resolve(font);\n });\n });\n}\n\n/**\n * @returns {Promise}\n */\nfunction loadTexture(src) {\n return new Promise(function (resolve, reject) {\n new THREE.ImageLoader().load(src, function (image) {\n resolve(image);\n }, undefined, function () {\n error('Error loading font image', src);\n reject(null);\n });\n });\n}\nfunction createShader(el, shaderName, data) {\n var shader;\n var shaderObject;\n\n // Set up Shader.\n shaderObject = new shaders[shaderName].Shader();\n shaderObject.el = el;\n shaderObject.init(data);\n shaderObject.update(data);\n\n // Get material.\n shader = shaderObject.material;\n // Apparently, was not set on `init` nor `update`.\n shader.transparent = data.transparent;\n return {\n material: shader,\n shader: shaderObject\n };\n}\n\n/**\n * Determine wrap pixel count. Either specified or by experimental fudge factor.\n * Note that experimental factor will never be correct for variable width fonts.\n */\nfunction computeWidth(wrapPixels, wrapCount, widthFactor) {\n return wrapPixels || (0.5 + wrapCount) * widthFactor;\n}\n\n/**\n * Compute default font width factor to use.\n */\nfunction computeFontWidthFactor(font) {\n var sum = 0;\n var digitsum = 0;\n var digits = 0;\n font.chars.map(function (ch) {\n sum += ch.xadvance;\n if (ch.id >= 48 && ch.id <= 57) {\n digits++;\n digitsum += ch.xadvance;\n }\n });\n return digits ? digitsum / digits : sum / font.chars.length;\n}\n\n/**\n * Get or create a promise given a key and promise generator.\n * @todo Move to a utility and use in other parts of A-Frame.\n */\nfunction PromiseCache() {\n var cache = this.cache = {};\n this.get = function (key, promiseGenerator) {\n if (key in cache) {\n return cache[key];\n }\n cache[key] = promiseGenerator();\n return cache[key];\n };\n}\n\n/***/ }),\n\n/***/ \"./src/components/tracked-controls-webvr.js\":\n/*!**************************************************!*\\\n !*** ./src/components/tracked-controls-webvr.js ***!\n \\**************************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar controllerUtils = __webpack_require__(/*! ../utils/tracked-controls */ \"./src/utils/tracked-controls.js\");\nvar DEFAULT_CAMERA_HEIGHT = (__webpack_require__(/*! ../constants */ \"./src/constants/index.js\").DEFAULT_CAMERA_HEIGHT);\nvar THREE = __webpack_require__(/*! ../lib/three */ \"./src/lib/three.js\");\nvar DEFAULT_HANDEDNESS = (__webpack_require__(/*! ../constants */ \"./src/constants/index.js\").DEFAULT_HANDEDNESS);\n// Vector from eyes to elbow (divided by user height).\nvar EYES_TO_ELBOW = {\n x: 0.175,\n y: -0.3,\n z: -0.03\n};\n// Vector from eyes to elbow (divided by user height).\nvar FOREARM = {\n x: 0,\n y: 0,\n z: -0.175\n};\n\n// Due to unfortunate name collision, add empty touches array to avoid Daydream error.\nvar EMPTY_DAYDREAM_TOUCHES = {\n touches: []\n};\nvar EVENTS = {\n AXISMOVE: 'axismove',\n BUTTONCHANGED: 'buttonchanged',\n BUTTONDOWN: 'buttondown',\n BUTTONUP: 'buttonup',\n TOUCHSTART: 'touchstart',\n TOUCHEND: 'touchend'\n};\n\n/**\n * Tracked controls component.\n * Wrap the gamepad API for pose and button states.\n * Select the appropriate controller and apply pose to the entity.\n * Observe button states and emit appropriate events.\n *\n * @property {number} controller - Index of controller in array returned by Gamepad API.\n * Only used if hand property is not set.\n * @property {string} id - Selected controller among those returned by Gamepad API.\n * @property {number} hand - If multiple controllers found with id, choose the one with the\n * given value for hand. If set, we ignore 'controller' property\n */\nmodule.exports.Component = registerComponent('tracked-controls-webvr', {\n schema: {\n autoHide: {\n default: true\n },\n controller: {\n default: 0\n },\n id: {\n type: 'string',\n default: ''\n },\n hand: {\n type: 'string',\n default: ''\n },\n idPrefix: {\n type: 'string',\n default: ''\n },\n orientationOffset: {\n type: 'vec3'\n },\n // Arm model parameters when not 6DoF.\n armModel: {\n default: false\n },\n headElement: {\n type: 'selector'\n }\n },\n init: function () {\n // Copy variables back to tracked-controls for backwards compatibility.\n // Some 3rd components rely on them.\n this.axis = this.el.components['tracked-controls'].axis = [0, 0, 0];\n this.buttonStates = this.el.components['tracked-controls'].buttonStates = {};\n this.changedAxes = [];\n this.targetControllerNumber = this.data.controller;\n this.axisMoveEventDetail = {\n axis: this.axis,\n changed: this.changedAxes\n };\n this.deltaControllerPosition = new THREE.Vector3();\n this.controllerQuaternion = new THREE.Quaternion();\n this.controllerEuler = new THREE.Euler();\n this.updateGamepad();\n this.buttonEventDetails = {};\n },\n tick: function (time, delta) {\n var mesh = this.el.getObject3D('mesh');\n // Update mesh animations.\n if (mesh && mesh.update) {\n mesh.update(delta / 1000);\n }\n this.updateGamepad();\n this.updatePose();\n this.updateButtons();\n },\n /**\n * Return default user height to use for non-6DOF arm model.\n */\n defaultUserHeight: function () {\n return DEFAULT_CAMERA_HEIGHT;\n },\n /**\n * Return head element to use for non-6DOF arm model.\n */\n getHeadElement: function () {\n return this.data.headElement || this.el.sceneEl.camera.el;\n },\n /**\n * Handle update controller match criteria (such as `id`, `idPrefix`, `hand`, `controller`)\n */\n updateGamepad: function () {\n var data = this.data;\n var controller = controllerUtils.findMatchingControllerWebVR(this.system.controllers, data.id, data.idPrefix, data.hand, data.controller);\n this.controller = controller;\n // Legacy handle to the controller for old components.\n this.el.components['tracked-controls'].controller = controller;\n if (this.data.autoHide) {\n this.el.object3D.visible = !!this.controller;\n }\n },\n /**\n * Applies an artificial arm model to simulate elbow to wrist positioning\n * based on the orientation of the controller.\n *\n * @param {object} controllerPosition - Existing vector to update with controller position.\n */\n applyArmModel: function (controllerPosition) {\n // Use controllerPosition and deltaControllerPosition to avoid creating variables.\n var controller = this.controller;\n var controllerEuler = this.controllerEuler;\n var controllerQuaternion = this.controllerQuaternion;\n var deltaControllerPosition = this.deltaControllerPosition;\n var hand;\n var headEl;\n var headObject3D;\n var pose;\n var userHeight;\n headEl = this.getHeadElement();\n headObject3D = headEl.object3D;\n userHeight = this.defaultUserHeight();\n pose = controller.pose;\n hand = (controller ? controller.hand : undefined) || DEFAULT_HANDEDNESS;\n\n // Use camera position as head position.\n controllerPosition.copy(headObject3D.position);\n // Set offset for degenerate \"arm model\" to elbow.\n deltaControllerPosition.set(EYES_TO_ELBOW.x * (hand === 'left' ? -1 : hand === 'right' ? 1 : 0), EYES_TO_ELBOW.y,\n // Lower than our eyes.\n EYES_TO_ELBOW.z); // Slightly out in front.\n // Scale offset by user height.\n deltaControllerPosition.multiplyScalar(userHeight);\n // Apply camera Y rotation (not X or Z, so you can look down at your hand).\n deltaControllerPosition.applyAxisAngle(headObject3D.up, headObject3D.rotation.y);\n // Apply rotated offset to position.\n controllerPosition.add(deltaControllerPosition);\n\n // Set offset for degenerate \"arm model\" forearm. Forearm sticking out from elbow.\n deltaControllerPosition.set(FOREARM.x, FOREARM.y, FOREARM.z);\n // Scale offset by user height.\n deltaControllerPosition.multiplyScalar(userHeight);\n // Apply controller X/Y rotation (tilting up/down/left/right is usually moving the arm).\n if (pose.orientation) {\n controllerQuaternion.fromArray(pose.orientation);\n } else {\n controllerQuaternion.copy(headObject3D.quaternion);\n }\n controllerEuler.setFromQuaternion(controllerQuaternion);\n controllerEuler.set(controllerEuler.x, controllerEuler.y, 0);\n deltaControllerPosition.applyEuler(controllerEuler);\n // Apply rotated offset to position.\n controllerPosition.add(deltaControllerPosition);\n },\n /**\n * Read pose from controller (from Gamepad API), apply transforms, apply to entity.\n */\n updatePose: function () {\n var controller = this.controller;\n var data = this.data;\n var object3D = this.el.object3D;\n var pose;\n var vrDisplay = this.system.vrDisplay;\n var standingMatrix;\n if (!controller) {\n return;\n }\n\n // Compose pose from Gamepad.\n pose = controller.pose;\n if (pose.position) {\n object3D.position.fromArray(pose.position);\n } else {\n // Controller not 6DOF, apply arm model.\n if (data.armModel) {\n this.applyArmModel(object3D.position);\n }\n }\n if (pose.orientation) {\n object3D.quaternion.fromArray(pose.orientation);\n }\n\n // Apply transforms, if 6DOF and in VR.\n if (vrDisplay && pose.position) {\n standingMatrix = this.el.sceneEl.renderer.xr.getStandingMatrix();\n object3D.matrix.compose(object3D.position, object3D.quaternion, object3D.scale);\n object3D.matrix.multiplyMatrices(standingMatrix, object3D.matrix);\n object3D.matrix.decompose(object3D.position, object3D.quaternion, object3D.scale);\n }\n object3D.rotateX(this.data.orientationOffset.x * THREE.MathUtils.DEG2RAD);\n object3D.rotateY(this.data.orientationOffset.y * THREE.MathUtils.DEG2RAD);\n object3D.rotateZ(this.data.orientationOffset.z * THREE.MathUtils.DEG2RAD);\n },\n /**\n * Handle button changes including axes, presses, touches, values.\n */\n updateButtons: function () {\n var buttonState;\n var controller = this.controller;\n var id;\n if (!controller) {\n return;\n }\n\n // Check every button.\n for (id = 0; id < controller.buttons.length; ++id) {\n // Initialize button state.\n if (!this.buttonStates[id]) {\n this.buttonStates[id] = {\n pressed: false,\n touched: false,\n value: 0\n };\n }\n if (!this.buttonEventDetails[id]) {\n this.buttonEventDetails[id] = {\n id: id,\n state: this.buttonStates[id]\n };\n }\n buttonState = controller.buttons[id];\n this.handleButton(id, buttonState);\n }\n // Check axes.\n this.handleAxes();\n },\n /**\n * Handle presses and touches for a single button.\n *\n * @param {number} id - Index of button in Gamepad button array.\n * @param {number} buttonState - Value of button state from 0 to 1.\n * @returns {boolean} Whether button has changed in any way.\n */\n handleButton: function (id, buttonState) {\n var changed;\n changed = this.handlePress(id, buttonState) | this.handleTouch(id, buttonState) | this.handleValue(id, buttonState);\n if (!changed) {\n return false;\n }\n this.el.emit(EVENTS.BUTTONCHANGED, this.buttonEventDetails[id], false);\n return true;\n },\n /**\n * An axis is an array of values from -1 (up, left) to 1 (down, right).\n * Compare each component of the axis to the previous value to determine change.\n *\n * @returns {boolean} Whether axes changed.\n */\n handleAxes: function () {\n var changed = false;\n var controllerAxes = this.controller.axes;\n var i;\n var previousAxis = this.axis;\n var changedAxes = this.changedAxes;\n\n // Check if axis changed.\n this.changedAxes.splice(0, this.changedAxes.length);\n for (i = 0; i < controllerAxes.length; ++i) {\n changedAxes.push(previousAxis[i] !== controllerAxes[i]);\n if (changedAxes[i]) {\n changed = true;\n }\n }\n if (!changed) {\n return false;\n }\n this.axis.splice(0, this.axis.length);\n for (i = 0; i < controllerAxes.length; i++) {\n this.axis.push(controllerAxes[i]);\n }\n this.el.emit(EVENTS.AXISMOVE, this.axisMoveEventDetail, false);\n return true;\n },\n /**\n * Determine whether a button press has occurred and emit events as appropriate.\n *\n * @param {string} id - ID of the button to check.\n * @param {object} buttonState - State of the button to check.\n * @returns {boolean} Whether button press state changed.\n */\n handlePress: function (id, buttonState) {\n var evtName;\n var previousButtonState = this.buttonStates[id];\n\n // Not changed.\n if (buttonState.pressed === previousButtonState.pressed) {\n return false;\n }\n evtName = buttonState.pressed ? EVENTS.BUTTONDOWN : EVENTS.BUTTONUP;\n this.el.emit(evtName, this.buttonEventDetails[id], false);\n previousButtonState.pressed = buttonState.pressed;\n return true;\n },\n /**\n * Determine whether a button touch has occurred and emit events as appropriate.\n *\n * @param {string} id - ID of the button to check.\n * @param {object} buttonState - State of the button to check.\n * @returns {boolean} Whether button touch state changed.\n */\n handleTouch: function (id, buttonState) {\n var evtName;\n var previousButtonState = this.buttonStates[id];\n\n // Not changed.\n if (buttonState.touched === previousButtonState.touched) {\n return false;\n }\n evtName = buttonState.touched ? EVENTS.TOUCHSTART : EVENTS.TOUCHEND;\n this.el.emit(evtName, this.buttonEventDetails[id], false, EMPTY_DAYDREAM_TOUCHES);\n previousButtonState.touched = buttonState.touched;\n return true;\n },\n /**\n * Determine whether a button value has changed.\n *\n * @param {string} id - Id of the button to check.\n * @param {object} buttonState - State of the button to check.\n * @returns {boolean} Whether button value changed.\n */\n handleValue: function (id, buttonState) {\n var previousButtonState = this.buttonStates[id];\n\n // Not changed.\n if (buttonState.value === previousButtonState.value) {\n return false;\n }\n previousButtonState.value = buttonState.value;\n return true;\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/tracked-controls-webxr.js\":\n/*!**************************************************!*\\\n !*** ./src/components/tracked-controls-webxr.js ***!\n \\**************************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar controllerUtils = __webpack_require__(/*! ../utils/tracked-controls */ \"./src/utils/tracked-controls.js\");\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar EVENTS = {\n AXISMOVE: 'axismove',\n BUTTONCHANGED: 'buttonchanged',\n BUTTONDOWN: 'buttondown',\n BUTTONUP: 'buttonup',\n TOUCHSTART: 'touchstart',\n TOUCHEND: 'touchend'\n};\nmodule.exports.Component = registerComponent('tracked-controls-webxr', {\n schema: {\n id: {\n type: 'string',\n default: ''\n },\n hand: {\n type: 'string',\n default: ''\n },\n handTrackingEnabled: {\n default: false\n },\n index: {\n type: 'int',\n default: -1\n },\n iterateControllerProfiles: {\n default: false\n },\n space: {\n type: 'string',\n oneOf: ['targetRaySpace', 'gripSpace'],\n default: 'gripSpace'\n }\n },\n init: function () {\n this.updateController = this.updateController.bind(this);\n this.buttonEventDetails = {};\n this.buttonStates = this.el.components['tracked-controls'].buttonStates = {};\n this.axis = this.el.components['tracked-controls'].axis = [0, 0, 0];\n this.changedAxes = [];\n this.axisMoveEventDetail = {\n axis: this.axis,\n changed: this.changedAxes\n };\n },\n update: function () {\n this.updateController();\n },\n play: function () {\n var sceneEl = this.el.sceneEl;\n this.updateController();\n sceneEl.addEventListener('controllersupdated', this.updateController);\n },\n pause: function () {\n var sceneEl = this.el.sceneEl;\n sceneEl.removeEventListener('controllersupdated', this.updateController);\n },\n isControllerPresent: function (evt) {\n if (!this.controller || this.controller.gamepad) {\n return false;\n }\n if (evt.inputSource.handedness !== 'none' && evt.inputSource.handedness !== this.data.hand) {\n return false;\n }\n return true;\n },\n /**\n * Handle update controller match criteria (such as `id`, `idPrefix`, `hand`, `controller`)\n */\n updateController: function () {\n this.controller = controllerUtils.findMatchingControllerWebXR(this.system.controllers, this.data.id, this.data.hand, this.data.index, this.data.iterateControllerProfiles, this.data.handTrackingEnabled);\n // Legacy handle to the controller for old components.\n this.el.components['tracked-controls'].controller = this.controller;\n if (this.data.autoHide) {\n this.el.object3D.visible = !!this.controller;\n }\n },\n tick: function () {\n var sceneEl = this.el.sceneEl;\n var controller = this.controller;\n var frame = sceneEl.frame;\n if (!controller || !sceneEl.frame || !this.system.referenceSpace) {\n return;\n }\n if (!controller.hand) {\n this.pose = frame.getPose(controller[this.data.space], this.system.referenceSpace);\n this.updatePose();\n this.updateButtons();\n }\n },\n updatePose: function () {\n var object3D = this.el.object3D;\n var pose = this.pose;\n if (!pose) {\n return;\n }\n object3D.matrix.elements = pose.transform.matrix;\n object3D.matrix.decompose(object3D.position, object3D.rotation, object3D.scale);\n },\n /**\n * Handle button changes including axes, presses, touches, values.\n */\n updateButtons: function () {\n var buttonState;\n var id;\n var controller = this.controller;\n var gamepad;\n if (!controller || !controller.gamepad) {\n return;\n }\n gamepad = controller.gamepad;\n // Check every button.\n for (id = 0; id < gamepad.buttons.length; ++id) {\n // Initialize button state.\n if (!this.buttonStates[id]) {\n this.buttonStates[id] = {\n pressed: false,\n touched: false,\n value: 0\n };\n }\n if (!this.buttonEventDetails[id]) {\n this.buttonEventDetails[id] = {\n id: id,\n state: this.buttonStates[id]\n };\n }\n buttonState = gamepad.buttons[id];\n this.handleButton(id, buttonState);\n }\n // Check axes.\n this.handleAxes();\n },\n /**\n * Handle presses and touches for a single button.\n *\n * @param {number} id - Index of button in Gamepad button array.\n * @param {number} buttonState - Value of button state from 0 to 1.\n * @returns {boolean} Whether button has changed in any way.\n */\n handleButton: function (id, buttonState) {\n var changed;\n changed = this.handlePress(id, buttonState) | this.handleTouch(id, buttonState) | this.handleValue(id, buttonState);\n if (!changed) {\n return false;\n }\n this.el.emit(EVENTS.BUTTONCHANGED, this.buttonEventDetails[id], false);\n return true;\n },\n /**\n * An axis is an array of values from -1 (up, left) to 1 (down, right).\n * Compare each component of the axis to the previous value to determine change.\n *\n * @returns {boolean} Whether axes changed.\n */\n handleAxes: function () {\n var changed = false;\n var controllerAxes = this.controller.gamepad.axes;\n var i;\n var previousAxis = this.axis;\n var changedAxes = this.changedAxes;\n\n // Check if axis changed.\n this.changedAxes.splice(0, this.changedAxes.length);\n for (i = 0; i < controllerAxes.length; ++i) {\n changedAxes.push(previousAxis[i] !== controllerAxes[i]);\n if (changedAxes[i]) {\n changed = true;\n }\n }\n if (!changed) {\n return false;\n }\n this.axis.splice(0, this.axis.length);\n for (i = 0; i < controllerAxes.length; i++) {\n this.axis.push(controllerAxes[i]);\n }\n this.el.emit(EVENTS.AXISMOVE, this.axisMoveEventDetail, false);\n return true;\n },\n /**\n * Determine whether a button press has occurred and emit events as appropriate.\n *\n * @param {string} id - ID of the button to check.\n * @param {object} buttonState - State of the button to check.\n * @returns {boolean} Whether button press state changed.\n */\n handlePress: function (id, buttonState) {\n var evtName;\n var previousButtonState = this.buttonStates[id];\n\n // Not changed.\n if (buttonState.pressed === previousButtonState.pressed) {\n return false;\n }\n evtName = buttonState.pressed ? EVENTS.BUTTONDOWN : EVENTS.BUTTONUP;\n this.el.emit(evtName, this.buttonEventDetails[id], false);\n previousButtonState.pressed = buttonState.pressed;\n return true;\n },\n /**\n * Determine whether a button touch has occurred and emit events as appropriate.\n *\n * @param {string} id - ID of the button to check.\n * @param {object} buttonState - State of the button to check.\n * @returns {boolean} Whether button touch state changed.\n */\n handleTouch: function (id, buttonState) {\n var evtName;\n var previousButtonState = this.buttonStates[id];\n\n // Not changed.\n if (buttonState.touched === previousButtonState.touched) {\n return false;\n }\n evtName = buttonState.touched ? EVENTS.TOUCHSTART : EVENTS.TOUCHEND;\n this.el.emit(evtName, this.buttonEventDetails[id], false);\n previousButtonState.touched = buttonState.touched;\n return true;\n },\n /**\n * Determine whether a button value has changed.\n *\n * @param {string} id - Id of the button to check.\n * @param {object} buttonState - State of the button to check.\n * @returns {boolean} Whether button value changed.\n */\n handleValue: function (id, buttonState) {\n var previousButtonState = this.buttonStates[id];\n\n // Not changed.\n if (buttonState.value === previousButtonState.value) {\n return false;\n }\n previousButtonState.value = buttonState.value;\n return true;\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/tracked-controls.js\":\n/*!********************************************!*\\\n !*** ./src/components/tracked-controls.js ***!\n \\********************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\n\n/**\n * Tracked controls.\n * Abstract controls that decide if the WebVR or WebXR version is going to be applied.\n *\n * @property {number} controller - Index of controller in array returned by Gamepad API.\n * Only used if hand property is not set.\n * @property {string} id - Selected controller among those returned by Gamepad API.\n * @property {number} hand - If multiple controllers found with id, choose the one with the\n * given value for hand. If set, we ignore 'controller' property\n */\nmodule.exports.Component = registerComponent('tracked-controls', {\n schema: {\n autoHide: {\n default: true\n },\n controller: {\n default: -1\n },\n id: {\n type: 'string',\n default: ''\n },\n hand: {\n type: 'string',\n default: ''\n },\n idPrefix: {\n type: 'string',\n default: ''\n },\n handTrackingEnabled: {\n default: false\n },\n orientationOffset: {\n type: 'vec3'\n },\n // Arm model parameters when not 6DoF.\n armModel: {\n default: false\n },\n headElement: {\n type: 'selector'\n },\n iterateControllerProfiles: {\n default: false\n },\n space: {\n type: 'string',\n oneOf: ['targetRaySpace', 'gripSpace'],\n default: 'targetRaySpace'\n }\n },\n // Run after both tracked-controls-webvr and tracked-controls-webxr to allow other components\n // to be after either without having to list them both.\n after: ['tracked-controls-webvr', 'tracked-controls-webxr'],\n update: function () {\n var data = this.data;\n var el = this.el;\n if (el.sceneEl.hasWebXR) {\n el.setAttribute('tracked-controls-webxr', {\n id: data.id,\n hand: data.hand,\n index: data.controller,\n iterateControllerProfiles: data.iterateControllerProfiles,\n handTrackingEnabled: data.handTrackingEnabled,\n space: data.space\n });\n } else {\n el.setAttribute('tracked-controls-webvr', data);\n }\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/valve-index-controls.js\":\n/*!************************************************!*\\\n !*** ./src/components/valve-index-controls.js ***!\n \\************************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar THREE = __webpack_require__(/*! ../lib/three */ \"./src/lib/three.js\");\nvar trackedControlsUtils = __webpack_require__(/*! ../utils/tracked-controls */ \"./src/utils/tracked-controls.js\");\nvar checkControllerPresentAndSetup = trackedControlsUtils.checkControllerPresentAndSetup;\nvar emitIfAxesChanged = trackedControlsUtils.emitIfAxesChanged;\nvar onButtonEvent = trackedControlsUtils.onButtonEvent;\nvar AFRAME_CDN_ROOT = (__webpack_require__(/*! ../constants */ \"./src/constants/index.js\").AFRAME_CDN_ROOT);\nvar INDEX_CONTROLLER_MODEL_BASE_URL = AFRAME_CDN_ROOT + 'controllers/valve/index/valve-index-';\nvar INDEX_CONTROLLER_MODEL_URL = {\n left: INDEX_CONTROLLER_MODEL_BASE_URL + 'left.glb',\n right: INDEX_CONTROLLER_MODEL_BASE_URL + 'right.glb'\n};\nvar GAMEPAD_ID_PREFIX = 'valve';\nvar isWebXRAvailable = (__webpack_require__(/*! ../utils/ */ \"./src/utils/index.js\").device.isWebXRAvailable);\nvar INDEX_CONTROLLER_POSITION_OFFSET_WEBVR = {\n left: {\n x: -0.00023692678902063457,\n y: 0.04724540367838371,\n z: -0.061959880395271096\n },\n right: {\n x: 0.002471558599671131,\n y: 0.055765208987076195,\n z: -0.061068168708348844\n }\n};\nvar INDEX_CONTROLLER_POSITION_OFFSET_WEBXR = {\n left: {\n x: 0,\n y: -0.05,\n z: 0.06\n },\n right: {\n x: 0,\n y: -0.05,\n z: 0.06\n }\n};\nvar INDEX_CONTROLLER_ROTATION_OFFSET_WEBVR = {\n left: {\n _x: 0.692295102620542,\n _y: -0.0627618864318427,\n _z: -0.06265893149611756,\n _order: 'XYZ'\n },\n right: {\n _x: 0.6484021229942998,\n _y: -0.032563619881892894,\n _z: -0.1327973171917482,\n _order: 'XYZ'\n }\n};\nvar INDEX_CONTROLLER_ROTATION_OFFSET_WEBXR = {\n left: {\n _x: Math.PI / 3,\n _y: 0,\n _z: 0,\n _order: 'XYZ'\n },\n right: {\n _x: Math.PI / 3,\n _y: 0,\n _z: 0,\n _order: 'XYZ'\n }\n};\nvar INDEX_CONTROLLER_ROTATION_OFFSET = isWebXRAvailable ? INDEX_CONTROLLER_ROTATION_OFFSET_WEBXR : INDEX_CONTROLLER_ROTATION_OFFSET_WEBVR;\nvar INDEX_CONTROLLER_POSITION_OFFSET = isWebXRAvailable ? INDEX_CONTROLLER_POSITION_OFFSET_WEBXR : INDEX_CONTROLLER_POSITION_OFFSET_WEBVR;\n/**\n * Vive controls.\n * Interface with Vive controllers and map Gamepad events to controller buttons:\n * trackpad, trigger, grip, menu, system\n * Load a controller model and highlight the pressed buttons.\n */\nmodule.exports.Component = registerComponent('valve-index-controls', {\n schema: {\n hand: {\n default: 'left'\n },\n buttonColor: {\n type: 'color',\n default: '#FAFAFA'\n },\n // Off-white.\n buttonHighlightColor: {\n type: 'color',\n default: '#22D1EE'\n },\n // Light blue.\n model: {\n default: true\n },\n orientationOffset: {\n type: 'vec3'\n }\n },\n after: ['tracked-controls'],\n mapping: {\n axes: {\n trackpad: [0, 1],\n thumbstick: [2, 3]\n },\n buttons: ['trigger', 'grip', 'trackpad', 'thumbstick', 'abutton']\n },\n init: function () {\n var self = this;\n this.controllerPresent = false;\n this.lastControllerCheck = 0;\n this.onButtonChanged = this.onButtonChanged.bind(this);\n this.onButtonDown = function (evt) {\n onButtonEvent(evt.detail.id, 'down', self);\n };\n this.onButtonUp = function (evt) {\n onButtonEvent(evt.detail.id, 'up', self);\n };\n this.onButtonTouchEnd = function (evt) {\n onButtonEvent(evt.detail.id, 'touchend', self);\n };\n this.onButtonTouchStart = function (evt) {\n onButtonEvent(evt.detail.id, 'touchstart', self);\n };\n this.previousButtonValues = {};\n this.bindMethods();\n },\n play: function () {\n this.checkIfControllerPresent();\n this.addControllersUpdateListener();\n },\n pause: function () {\n this.removeEventListeners();\n this.removeControllersUpdateListener();\n },\n bindMethods: function () {\n this.onModelLoaded = this.onModelLoaded.bind(this);\n this.onControllersUpdate = this.onControllersUpdate.bind(this);\n this.checkIfControllerPresent = this.checkIfControllerPresent.bind(this);\n this.removeControllersUpdateListener = this.removeControllersUpdateListener.bind(this);\n this.onAxisMoved = this.onAxisMoved.bind(this);\n },\n addEventListeners: function () {\n var el = this.el;\n el.addEventListener('buttonchanged', this.onButtonChanged);\n el.addEventListener('buttondown', this.onButtonDown);\n el.addEventListener('buttonup', this.onButtonUp);\n el.addEventListener('touchend', this.onButtonTouchEnd);\n el.addEventListener('touchstart', this.onButtonTouchStart);\n el.addEventListener('model-loaded', this.onModelLoaded);\n el.addEventListener('axismove', this.onAxisMoved);\n this.controllerEventsActive = true;\n },\n removeEventListeners: function () {\n var el = this.el;\n el.removeEventListener('buttonchanged', this.onButtonChanged);\n el.removeEventListener('buttondown', this.onButtonDown);\n el.removeEventListener('buttonup', this.onButtonUp);\n el.removeEventListener('touchend', this.onButtonTouchEnd);\n el.removeEventListener('touchstart', this.onButtonTouchStart);\n el.removeEventListener('model-loaded', this.onModelLoaded);\n el.removeEventListener('axismove', this.onAxisMoved);\n this.controllerEventsActive = false;\n },\n /**\n * Once OpenVR returns correct hand data in supporting browsers, we can use hand property.\n * var isPresent = checkControllerPresentAndSetup(this.el.sceneEl, GAMEPAD_ID_PREFIX,\n { hand: data.hand });\n * Until then, use hardcoded index.\n */\n checkIfControllerPresent: function () {\n var data = this.data;\n var controllerIndex = data.hand === 'right' ? 0 : data.hand === 'left' ? 1 : 2;\n checkControllerPresentAndSetup(this, GAMEPAD_ID_PREFIX, {\n index: controllerIndex,\n iterateControllerProfiles: true,\n hand: data.hand\n });\n },\n injectTrackedControls: function () {\n var el = this.el;\n var data = this.data;\n\n // If we have an OpenVR Gamepad, use the fixed mapping.\n el.setAttribute('tracked-controls', {\n idPrefix: GAMEPAD_ID_PREFIX,\n // Hand IDs: 1 = right, 0 = left, 2 = anything else.\n controller: data.hand === 'right' ? 1 : data.hand === 'left' ? 0 : 2,\n hand: data.hand,\n orientationOffset: data.orientationOffset\n });\n this.loadModel();\n },\n loadModel: function () {\n var data = this.data;\n if (!data.model) {\n return;\n }\n this.el.setAttribute('gltf-model', '' + INDEX_CONTROLLER_MODEL_URL[data.hand] + '');\n },\n addControllersUpdateListener: function () {\n this.el.sceneEl.addEventListener('controllersupdated', this.onControllersUpdate, false);\n },\n removeControllersUpdateListener: function () {\n this.el.sceneEl.removeEventListener('controllersupdated', this.onControllersUpdate, false);\n },\n onControllersUpdate: function () {\n this.checkIfControllerPresent();\n },\n /**\n * Rotate the trigger button based on how hard the trigger is pressed.\n */\n onButtonChanged: function (evt) {\n var button = this.mapping.buttons[evt.detail.id];\n var buttonMeshes = this.buttonMeshes;\n var analogValue;\n if (!button) {\n return;\n }\n if (button === 'trigger') {\n analogValue = evt.detail.state.value;\n // Update trigger rotation depending on button value.\n if (buttonMeshes && buttonMeshes.trigger) {\n buttonMeshes.trigger.rotation.x = this.triggerOriginalRotationX - analogValue * (Math.PI / 40);\n }\n }\n\n // Pass along changed event with button state, using button mapping for convenience.\n this.el.emit(button + 'changed', evt.detail.state);\n },\n onModelLoaded: function (evt) {\n var buttonMeshes;\n var controllerObject3D = evt.detail.model;\n var self = this;\n if (evt.target !== this.el || !this.data.model) {\n return;\n }\n\n // Store button meshes object to be able to change their colors.\n buttonMeshes = this.buttonMeshes = {};\n buttonMeshes.grip = {\n left: controllerObject3D.getObjectByName('leftgrip'),\n right: controllerObject3D.getObjectByName('rightgrip')\n };\n buttonMeshes.menu = controllerObject3D.getObjectByName('menubutton');\n buttonMeshes.system = controllerObject3D.getObjectByName('systembutton');\n buttonMeshes.trackpad = controllerObject3D.getObjectByName('touchpad');\n buttonMeshes.trigger = controllerObject3D.getObjectByName('trigger');\n this.triggerOriginalRotationX = buttonMeshes.trigger.rotation.x;\n\n // Set default colors.\n Object.keys(buttonMeshes).forEach(function (buttonName) {\n self.setButtonColor(buttonName, self.data.buttonColor);\n });\n\n // Offset pivot point.\n controllerObject3D.position.copy(INDEX_CONTROLLER_POSITION_OFFSET[this.data.hand]);\n controllerObject3D.rotation.copy(INDEX_CONTROLLER_ROTATION_OFFSET[this.data.hand]);\n this.el.emit('controllermodelready', {\n name: 'valve-index-controls',\n model: this.data.model,\n rayOrigin: new THREE.Vector3(0, 0, 0)\n });\n },\n onAxisMoved: function (evt) {\n emitIfAxesChanged(this, this.mapping.axes, evt);\n },\n updateModel: function (buttonName, evtName) {\n var color;\n var isTouch;\n if (!this.data.model) {\n return;\n }\n isTouch = evtName.indexOf('touch') !== -1;\n // Don't change color for trackpad touch.\n if (isTouch) {\n return;\n }\n\n // Update colors.\n color = evtName === 'up' ? this.data.buttonColor : this.data.buttonHighlightColor;\n this.setButtonColor(buttonName, color);\n },\n setButtonColor: function (buttonName, color) {\n // TODO: The meshes aren't set up correctly now, skipping for the moment\n return;\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/visible.js\":\n/*!***********************************!*\\\n !*** ./src/components/visible.js ***!\n \\***********************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\n\n/**\n * Visibility component.\n */\nmodule.exports.Component = registerComponent('visible', {\n schema: {\n default: true\n },\n update: function () {\n this.el.object3D.visible = this.data;\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/vive-controls.js\":\n/*!*****************************************!*\\\n !*** ./src/components/vive-controls.js ***!\n \\*****************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar trackedControlsUtils = __webpack_require__(/*! ../utils/tracked-controls */ \"./src/utils/tracked-controls.js\");\nvar checkControllerPresentAndSetup = trackedControlsUtils.checkControllerPresentAndSetup;\nvar emitIfAxesChanged = trackedControlsUtils.emitIfAxesChanged;\nvar onButtonEvent = trackedControlsUtils.onButtonEvent;\nvar AFRAME_CDN_ROOT = (__webpack_require__(/*! ../constants */ \"./src/constants/index.js\").AFRAME_CDN_ROOT);\nvar VIVE_CONTROLLER_MODEL_OBJ_URL = AFRAME_CDN_ROOT + 'controllers/vive/vr_controller_vive.obj';\nvar VIVE_CONTROLLER_MODEL_OBJ_MTL = AFRAME_CDN_ROOT + 'controllers/vive/vr_controller_vive.mtl';\nvar isWebXRAvailable = (__webpack_require__(/*! ../utils/ */ \"./src/utils/index.js\").device.isWebXRAvailable);\nvar GAMEPAD_ID_WEBXR = 'htc-vive';\nvar GAMEPAD_ID_WEBVR = 'OpenVR ';\n\n// Prefix for HTC Vive Controllers.\nvar GAMEPAD_ID_PREFIX = isWebXRAvailable ? GAMEPAD_ID_WEBXR : GAMEPAD_ID_WEBVR;\n\n/**\n * Button IDs:\n * 0 - trackpad\n * 1 - trigger (intensity value from 0.5 to 1)\n * 2 - grip\n * 3 - menu (dispatch but better for menu options)\n * 4 - system (never dispatched on this layer)\n */\nvar INPUT_MAPPING_WEBVR = {\n axes: {\n trackpad: [0, 1]\n },\n buttons: ['trackpad', 'trigger', 'grip', 'menu', 'system']\n};\n\n/**\n * Button IDs:\n * 0 - trigger\n * 1 - squeeze\n * 2 - touchpad\n * 3 - none (dispatch but better for menu options)\n * 4 - menu (never dispatched on this layer)\n *\n * Axis:\n * 0 - touchpad x axis\n * 1 - touchpad y axis\n * Reference: https://github.com/immersive-web/webxr-input-profiles/blob/master/packages/registry/profiles/htc/htc-vive.json\n */\nvar INPUT_MAPPING_WEBXR = {\n axes: {\n touchpad: [0, 1]\n },\n buttons: ['trigger', 'grip', 'touchpad', 'none']\n};\nvar INPUT_MAPPING = isWebXRAvailable ? INPUT_MAPPING_WEBXR : INPUT_MAPPING_WEBVR;\n\n/**\n * Vive controls.\n * Interface with Vive controllers and map Gamepad events to controller buttons:\n * touchpad, trigger, grip, menu, system\n * Load a controller model and highlight the pressed buttons.\n */\nmodule.exports.Component = registerComponent('vive-controls', {\n schema: {\n hand: {\n default: 'left'\n },\n buttonColor: {\n type: 'color',\n default: '#FAFAFA'\n },\n // Off-white.\n buttonHighlightColor: {\n type: 'color',\n default: '#22D1EE'\n },\n // Light blue.\n model: {\n default: true\n },\n orientationOffset: {\n type: 'vec3'\n }\n },\n after: ['tracked-controls'],\n mapping: INPUT_MAPPING,\n init: function () {\n var self = this;\n this.controllerPresent = false;\n this.lastControllerCheck = 0;\n this.onButtonChanged = this.onButtonChanged.bind(this);\n this.onButtonDown = function (evt) {\n onButtonEvent(evt.detail.id, 'down', self);\n };\n this.onButtonUp = function (evt) {\n onButtonEvent(evt.detail.id, 'up', self);\n };\n this.onButtonTouchEnd = function (evt) {\n onButtonEvent(evt.detail.id, 'touchend', self);\n };\n this.onButtonTouchStart = function (evt) {\n onButtonEvent(evt.detail.id, 'touchstart', self);\n };\n this.previousButtonValues = {};\n this.bindMethods();\n },\n update: function () {\n var data = this.data;\n this.controllerIndex = data.hand === 'right' ? 0 : data.hand === 'left' ? 1 : 2;\n },\n play: function () {\n this.checkIfControllerPresent();\n this.addControllersUpdateListener();\n },\n pause: function () {\n this.removeEventListeners();\n this.removeControllersUpdateListener();\n },\n bindMethods: function () {\n this.onModelLoaded = this.onModelLoaded.bind(this);\n this.onControllersUpdate = this.onControllersUpdate.bind(this);\n this.checkIfControllerPresent = this.checkIfControllerPresent.bind(this);\n this.removeControllersUpdateListener = this.removeControllersUpdateListener.bind(this);\n this.onAxisMoved = this.onAxisMoved.bind(this);\n },\n addEventListeners: function () {\n var el = this.el;\n el.addEventListener('buttonchanged', this.onButtonChanged);\n el.addEventListener('buttondown', this.onButtonDown);\n el.addEventListener('buttonup', this.onButtonUp);\n el.addEventListener('touchend', this.onButtonTouchEnd);\n el.addEventListener('touchstart', this.onButtonTouchStart);\n el.addEventListener('model-loaded', this.onModelLoaded);\n el.addEventListener('axismove', this.onAxisMoved);\n this.controllerEventsActive = true;\n },\n removeEventListeners: function () {\n var el = this.el;\n el.removeEventListener('buttonchanged', this.onButtonChanged);\n el.removeEventListener('buttondown', this.onButtonDown);\n el.removeEventListener('buttonup', this.onButtonUp);\n el.removeEventListener('touchend', this.onButtonTouchEnd);\n el.removeEventListener('touchstart', this.onButtonTouchStart);\n el.removeEventListener('model-loaded', this.onModelLoaded);\n el.removeEventListener('axismove', this.onAxisMoved);\n this.controllerEventsActive = false;\n },\n /**\n * Once OpenVR returns correct hand data in supporting browsers, we can use hand property.\n * var isPresent = checkControllerPresentAndSetup(this.el.sceneEl, GAMEPAD_ID_PREFIX,\n { hand: data.hand });\n * Until then, use hardcoded index.\n */\n checkIfControllerPresent: function () {\n var data = this.data;\n checkControllerPresentAndSetup(this, GAMEPAD_ID_PREFIX, {\n index: this.controllerIndex,\n hand: data.hand\n });\n },\n injectTrackedControls: function () {\n var el = this.el;\n var data = this.data;\n\n // If we have an OpenVR Gamepad, use the fixed mapping.\n el.setAttribute('tracked-controls', {\n idPrefix: GAMEPAD_ID_PREFIX,\n hand: data.hand,\n controller: this.controllerIndex,\n orientationOffset: data.orientationOffset\n });\n\n // Load model.\n if (!this.data.model) {\n return;\n }\n this.el.setAttribute('obj-model', {\n obj: VIVE_CONTROLLER_MODEL_OBJ_URL,\n mtl: VIVE_CONTROLLER_MODEL_OBJ_MTL\n });\n },\n addControllersUpdateListener: function () {\n this.el.sceneEl.addEventListener('controllersupdated', this.onControllersUpdate, false);\n },\n removeControllersUpdateListener: function () {\n this.el.sceneEl.removeEventListener('controllersupdated', this.onControllersUpdate, false);\n },\n onControllersUpdate: function () {\n this.checkIfControllerPresent();\n },\n /**\n * Rotate the trigger button based on how hard the trigger is pressed.\n */\n onButtonChanged: function (evt) {\n var button = this.mapping.buttons[evt.detail.id];\n var buttonMeshes = this.buttonMeshes;\n var analogValue;\n if (!button) {\n return;\n }\n if (button === 'trigger') {\n analogValue = evt.detail.state.value;\n // Update trigger rotation depending on button value.\n if (buttonMeshes && buttonMeshes.trigger) {\n buttonMeshes.trigger.rotation.x = -analogValue * (Math.PI / 12);\n }\n }\n\n // Pass along changed event with button state, using button mapping for convenience.\n this.el.emit(button + 'changed', evt.detail.state);\n },\n onModelLoaded: function (evt) {\n var buttonMeshes;\n var controllerObject3D = evt.detail.model;\n var self = this;\n if (evt.target !== this.el || !this.data.model) {\n return;\n }\n\n // Store button meshes object to be able to change their colors.\n buttonMeshes = this.buttonMeshes = {};\n buttonMeshes.grip = {\n left: controllerObject3D.getObjectByName('leftgrip'),\n right: controllerObject3D.getObjectByName('rightgrip')\n };\n buttonMeshes.menu = controllerObject3D.getObjectByName('menubutton');\n buttonMeshes.system = controllerObject3D.getObjectByName('systembutton');\n buttonMeshes.trackpad = controllerObject3D.getObjectByName('touchpad');\n buttonMeshes.touchpad = controllerObject3D.getObjectByName('touchpad');\n buttonMeshes.trigger = controllerObject3D.getObjectByName('trigger');\n\n // Set default colors.\n Object.keys(buttonMeshes).forEach(function (buttonName) {\n self.setButtonColor(buttonName, self.data.buttonColor);\n });\n\n // Offset pivot point.\n controllerObject3D.position.set(0, -0.015, 0.04);\n },\n onAxisMoved: function (evt) {\n emitIfAxesChanged(this, this.mapping.axes, evt);\n },\n updateModel: function (buttonName, evtName) {\n var color;\n var isTouch;\n if (!this.data.model) {\n return;\n }\n isTouch = evtName.indexOf('touch') !== -1;\n // Don't change color for trackpad touch.\n if (isTouch) {\n return;\n }\n\n // Update colors.\n color = evtName === 'up' ? this.data.buttonColor : this.data.buttonHighlightColor;\n this.setButtonColor(buttonName, color);\n },\n setButtonColor: function (buttonName, color) {\n var buttonMeshes = this.buttonMeshes;\n if (!buttonMeshes) {\n return;\n }\n\n // Need to do both left and right sides for grip.\n if (buttonName === 'grip') {\n buttonMeshes.grip.left.material.color.set(color);\n buttonMeshes.grip.right.material.color.set(color);\n return;\n }\n buttonMeshes[buttonName].material.color.set(color);\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/vive-focus-controls.js\":\n/*!***********************************************!*\\\n !*** ./src/components/vive-focus-controls.js ***!\n \\***********************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar trackedControlsUtils = __webpack_require__(/*! ../utils/tracked-controls */ \"./src/utils/tracked-controls.js\");\nvar checkControllerPresentAndSetup = trackedControlsUtils.checkControllerPresentAndSetup;\nvar emitIfAxesChanged = trackedControlsUtils.emitIfAxesChanged;\nvar onButtonEvent = trackedControlsUtils.onButtonEvent;\nvar AFRAME_CDN_ROOT = (__webpack_require__(/*! ../constants */ \"./src/constants/index.js\").AFRAME_CDN_ROOT);\nvar VIVE_FOCUS_CONTROLLER_MODEL_URL = AFRAME_CDN_ROOT + 'controllers/vive/focus-controller/focus-controller.gltf';\nvar isWebXRAvailable = (__webpack_require__(/*! ../utils/ */ \"./src/utils/index.js\").device.isWebXRAvailable);\nvar GAMEPAD_ID_WEBXR = 'htc-vive-focus';\nvar GAMEPAD_ID_WEBVR = 'HTC Vive Focus ';\n\n// Prefix for HTC Vive Focus Controllers.\nvar GAMEPAD_ID_PREFIX = isWebXRAvailable ? GAMEPAD_ID_WEBXR : GAMEPAD_ID_WEBVR;\n\n/**\n * Button IDs:\n * 0 - trackpad\n * 1 - trigger\n */\nvar INPUT_MAPPING_WEBVR = {\n axes: {\n trackpad: [0, 1]\n },\n buttons: ['trackpad', 'trigger']\n};\n\n/**\n * Button IDs:\n * 0 - trigger\n * 2 - touchpad\n * 4 - menu\n */\nvar INPUT_MAPPING_WEBXR = {\n axes: {\n touchpad: [0, 1]\n },\n buttons: ['trigger', 'none', 'touchpad', 'none', 'menu']\n};\nvar INPUT_MAPPING = isWebXRAvailable ? INPUT_MAPPING_WEBXR : INPUT_MAPPING_WEBVR;\n\n/**\n * Vive Focus controls.\n * Interface with Vive Focus controller and map Gamepad events to\n * controller buttons: trackpad, trigger\n * Load a controller model and highlight the pressed buttons.\n */\nmodule.exports.Component = registerComponent('vive-focus-controls', {\n schema: {\n hand: {\n default: ''\n },\n // This informs the degenerate arm model.\n buttonTouchedColor: {\n type: 'color',\n default: '#BBBBBB'\n },\n buttonHighlightColor: {\n type: 'color',\n default: '#7A7A7A'\n },\n model: {\n default: true\n },\n orientationOffset: {\n type: 'vec3'\n },\n armModel: {\n default: true\n }\n },\n after: ['tracked-controls'],\n mapping: INPUT_MAPPING,\n bindMethods: function () {\n this.onModelLoaded = this.onModelLoaded.bind(this);\n this.onControllersUpdate = this.onControllersUpdate.bind(this);\n this.checkIfControllerPresent = this.checkIfControllerPresent.bind(this);\n this.removeControllersUpdateListener = this.removeControllersUpdateListener.bind(this);\n this.onAxisMoved = this.onAxisMoved.bind(this);\n },\n init: function () {\n var self = this;\n this.onButtonChanged = this.onButtonChanged.bind(this);\n this.onButtonDown = function (evt) {\n onButtonEvent(evt.detail.id, 'down', self);\n };\n this.onButtonUp = function (evt) {\n onButtonEvent(evt.detail.id, 'up', self);\n };\n this.onButtonTouchStart = function (evt) {\n onButtonEvent(evt.detail.id, 'touchstart', self);\n };\n this.onButtonTouchEnd = function (evt) {\n onButtonEvent(evt.detail.id, 'touchend', self);\n };\n this.controllerPresent = false;\n this.lastControllerCheck = 0;\n this.bindMethods();\n },\n addEventListeners: function () {\n var el = this.el;\n el.addEventListener('buttonchanged', this.onButtonChanged);\n el.addEventListener('buttondown', this.onButtonDown);\n el.addEventListener('buttonup', this.onButtonUp);\n el.addEventListener('touchstart', this.onButtonTouchStart);\n el.addEventListener('touchend', this.onButtonTouchEnd);\n el.addEventListener('model-loaded', this.onModelLoaded);\n el.addEventListener('axismove', this.onAxisMoved);\n this.controllerEventsActive = true;\n this.addControllersUpdateListener();\n },\n removeEventListeners: function () {\n var el = this.el;\n el.removeEventListener('buttonchanged', this.onButtonChanged);\n el.removeEventListener('buttondown', this.onButtonDown);\n el.removeEventListener('buttonup', this.onButtonUp);\n el.removeEventListener('touchstart', this.onButtonTouchStart);\n el.removeEventListener('touchend', this.onButtonTouchEnd);\n el.removeEventListener('model-loaded', this.onModelLoaded);\n el.removeEventListener('axismove', this.onAxisMoved);\n this.controllerEventsActive = false;\n this.removeControllersUpdateListener();\n },\n checkIfControllerPresent: function () {\n checkControllerPresentAndSetup(this, GAMEPAD_ID_PREFIX, this.data.hand ? {\n hand: this.data.hand\n } : {});\n },\n play: function () {\n this.checkIfControllerPresent();\n this.addControllersUpdateListener();\n },\n pause: function () {\n this.removeEventListeners();\n this.removeControllersUpdateListener();\n },\n injectTrackedControls: function () {\n var el = this.el;\n var data = this.data;\n el.setAttribute('tracked-controls', {\n armModel: data.armModel,\n idPrefix: GAMEPAD_ID_PREFIX,\n orientationOffset: data.orientationOffset\n });\n if (!this.data.model) {\n return;\n }\n this.el.setAttribute('gltf-model', VIVE_FOCUS_CONTROLLER_MODEL_URL);\n },\n addControllersUpdateListener: function () {\n this.el.sceneEl.addEventListener('controllersupdated', this.onControllersUpdate, false);\n },\n removeControllersUpdateListener: function () {\n this.el.sceneEl.removeEventListener('controllersupdated', this.onControllersUpdate, false);\n },\n onControllersUpdate: function () {\n this.checkIfControllerPresent();\n },\n onModelLoaded: function (evt) {\n var controllerObject3D = evt.detail.model;\n var buttonMeshes;\n if (evt.target !== this.el || !this.data.model) {\n return;\n }\n buttonMeshes = this.buttonMeshes = {};\n buttonMeshes.trigger = controllerObject3D.getObjectByName('BumperKey');\n buttonMeshes.triggerPressed = controllerObject3D.getObjectByName('BumperKey_Press');\n if (buttonMeshes.triggerPressed) {\n buttonMeshes.triggerPressed.visible = false;\n }\n buttonMeshes.trackpad = controllerObject3D.getObjectByName('TouchPad');\n buttonMeshes.trackpadPressed = controllerObject3D.getObjectByName('TouchPad_Press');\n if (buttonMeshes.trackpadPressed) {\n buttonMeshes.trackpadPressed.visible = false;\n }\n },\n // No analog buttons, only emits 0/1 values\n onButtonChanged: function (evt) {\n var button = this.mapping.buttons[evt.detail.id];\n if (!button) return;\n // Pass along changed event with button state, using button mapping for convenience.\n this.el.emit(button + 'changed', evt.detail.state);\n },\n onAxisMoved: function (evt) {\n emitIfAxesChanged(this, this.mapping.axes, evt);\n },\n updateModel: function (buttonName, evtName) {\n if (!this.data.model) {\n return;\n }\n this.updateButtonModel(buttonName, evtName);\n },\n updateButtonModel: function (buttonName, state) {\n var buttonMeshes = this.buttonMeshes;\n var pressedName = buttonName + 'Pressed';\n if (!buttonMeshes || !buttonMeshes[buttonName] || !buttonMeshes[pressedName]) {\n return;\n }\n var color;\n switch (state) {\n case 'down':\n color = this.data.buttonHighlightColor;\n break;\n case 'touchstart':\n color = this.data.buttonTouchedColor;\n break;\n }\n if (color) {\n buttonMeshes[pressedName].material.color.set(color);\n }\n buttonMeshes[pressedName].visible = !!color;\n buttonMeshes[buttonName].visible = !color;\n }\n});\n\n/***/ }),\n\n/***/ \"./src/components/wasd-controls.js\":\n/*!*****************************************!*\\\n !*** ./src/components/wasd-controls.js ***!\n \\*****************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nvar KEYCODE_TO_CODE = (__webpack_require__(/*! ../constants */ \"./src/constants/index.js\").keyboardevent.KEYCODE_TO_CODE);\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar THREE = __webpack_require__(/*! ../lib/three */ \"./src/lib/three.js\");\nvar utils = __webpack_require__(/*! ../utils/ */ \"./src/utils/index.js\");\nvar shouldCaptureKeyEvent = utils.shouldCaptureKeyEvent;\nvar CLAMP_VELOCITY = 0.00001;\nvar MAX_DELTA = 0.2;\nvar KEYS = ['KeyW', 'KeyA', 'KeyS', 'KeyD', 'ArrowUp', 'ArrowLeft', 'ArrowRight', 'ArrowDown'];\n\n/**\n * WASD component to control entities using WASD keys.\n */\nmodule.exports.Component = registerComponent('wasd-controls', {\n schema: {\n acceleration: {\n default: 65\n },\n adAxis: {\n default: 'x',\n oneOf: ['x', 'y', 'z']\n },\n adEnabled: {\n default: true\n },\n adInverted: {\n default: false\n },\n enabled: {\n default: true\n },\n fly: {\n default: false\n },\n wsAxis: {\n default: 'z',\n oneOf: ['x', 'y', 'z']\n },\n wsEnabled: {\n default: true\n },\n wsInverted: {\n default: false\n }\n },\n after: ['look-controls'],\n init: function () {\n // To keep track of the pressed keys.\n this.keys = {};\n this.easing = 1.1;\n this.velocity = new THREE.Vector3();\n\n // Bind methods and add event listeners.\n this.onBlur = this.onBlur.bind(this);\n this.onContextMenu = this.onContextMenu.bind(this);\n this.onFocus = this.onFocus.bind(this);\n this.onKeyDown = this.onKeyDown.bind(this);\n this.onKeyUp = this.onKeyUp.bind(this);\n this.onVisibilityChange = this.onVisibilityChange.bind(this);\n this.attachVisibilityEventListeners();\n },\n tick: function (time, delta) {\n var data = this.data;\n var el = this.el;\n var velocity = this.velocity;\n if (!velocity[data.adAxis] && !velocity[data.wsAxis] && isEmptyObject(this.keys)) {\n return;\n }\n\n // Update velocity.\n delta = delta / 1000;\n this.updateVelocity(delta);\n if (!velocity[data.adAxis] && !velocity[data.wsAxis]) {\n return;\n }\n\n // Get movement vector and translate position.\n el.object3D.position.add(this.getMovementVector(delta));\n },\n update: function (oldData) {\n // Reset velocity if axis have changed.\n if (oldData.adAxis !== this.data.adAxis) {\n this.velocity[oldData.adAxis] = 0;\n }\n if (oldData.wsAxis !== this.data.wsAxis) {\n this.velocity[oldData.wsAxis] = 0;\n }\n },\n remove: function () {\n this.removeKeyEventListeners();\n this.removeVisibilityEventListeners();\n },\n play: function () {\n this.attachKeyEventListeners();\n },\n pause: function () {\n this.keys = {};\n this.removeKeyEventListeners();\n },\n updateVelocity: function (delta) {\n var acceleration;\n var adAxis;\n var adSign;\n var data = this.data;\n var keys = this.keys;\n var velocity = this.velocity;\n var wsAxis;\n var wsSign;\n adAxis = data.adAxis;\n wsAxis = data.wsAxis;\n\n // If FPS too low, reset velocity.\n if (delta > MAX_DELTA) {\n velocity[adAxis] = 0;\n velocity[wsAxis] = 0;\n return;\n }\n\n // https://gamedev.stackexchange.com/questions/151383/frame-rate-independant-movement-with-acceleration\n var scaledEasing = Math.pow(1 / this.easing, delta * 60);\n // Velocity Easing.\n if (velocity[adAxis] !== 0) {\n velocity[adAxis] = velocity[adAxis] * scaledEasing;\n }\n if (velocity[wsAxis] !== 0) {\n velocity[wsAxis] = velocity[wsAxis] * scaledEasing;\n }\n\n // Clamp velocity easing.\n if (Math.abs(velocity[adAxis]) < CLAMP_VELOCITY) {\n velocity[adAxis] = 0;\n }\n if (Math.abs(velocity[wsAxis]) < CLAMP_VELOCITY) {\n velocity[wsAxis] = 0;\n }\n if (!data.enabled) {\n return;\n }\n\n // Update velocity using keys pressed.\n acceleration = data.acceleration;\n if (data.adEnabled) {\n adSign = data.adInverted ? -1 : 1;\n if (keys.KeyA || keys.ArrowLeft) {\n velocity[adAxis] -= adSign * acceleration * delta;\n }\n if (keys.KeyD || keys.ArrowRight) {\n velocity[adAxis] += adSign * acceleration * delta;\n }\n }\n if (data.wsEnabled) {\n wsSign = data.wsInverted ? -1 : 1;\n if (keys.KeyW || keys.ArrowUp) {\n velocity[wsAxis] -= wsSign * acceleration * delta;\n }\n if (keys.KeyS || keys.ArrowDown) {\n velocity[wsAxis] += wsSign * acceleration * delta;\n }\n }\n },\n getMovementVector: function () {\n var directionVector = new THREE.Vector3(0, 0, 0);\n var rotationEuler = new THREE.Euler(0, 0, 0, 'YXZ');\n return function (delta) {\n var rotation = this.el.getAttribute('rotation');\n var velocity = this.velocity;\n var xRotation;\n directionVector.copy(velocity);\n directionVector.multiplyScalar(delta);\n\n // Absolute.\n if (!rotation) {\n return directionVector;\n }\n xRotation = this.data.fly ? rotation.x : 0;\n\n // Transform direction relative to heading.\n rotationEuler.set(THREE.MathUtils.degToRad(xRotation), THREE.MathUtils.degToRad(rotation.y), 0);\n directionVector.applyEuler(rotationEuler);\n return directionVector;\n };\n }(),\n attachVisibilityEventListeners: function () {\n window.oncontextmenu = this.onContextMenu;\n window.addEventListener('blur', this.onBlur);\n window.addEventListener('focus', this.onFocus);\n document.addEventListener('visibilitychange', this.onVisibilityChange);\n },\n removeVisibilityEventListeners: function () {\n window.removeEventListener('blur', this.onBlur);\n window.removeEventListener('focus', this.onFocus);\n document.removeEventListener('visibilitychange', this.onVisibilityChange);\n },\n attachKeyEventListeners: function () {\n window.addEventListener('keydown', this.onKeyDown);\n window.addEventListener('keyup', this.onKeyUp);\n },\n removeKeyEventListeners: function () {\n window.removeEventListener('keydown', this.onKeyDown);\n window.removeEventListener('keyup', this.onKeyUp);\n },\n onContextMenu: function () {\n var keys = Object.keys(this.keys);\n for (var i = 0; i < keys.length; i++) {\n delete this.keys[keys[i]];\n }\n },\n onBlur: function () {\n this.pause();\n },\n onFocus: function () {\n this.play();\n },\n onVisibilityChange: function () {\n if (document.hidden) {\n this.onBlur();\n } else {\n this.onFocus();\n }\n },\n onKeyDown: function (event) {\n var code;\n if (!shouldCaptureKeyEvent(event)) {\n return;\n }\n code = event.code || KEYCODE_TO_CODE[event.keyCode];\n if (KEYS.indexOf(code) !== -1) {\n this.keys[code] = true;\n }\n },\n onKeyUp: function (event) {\n var code;\n code = event.code || KEYCODE_TO_CODE[event.keyCode];\n delete this.keys[code];\n }\n});\nfunction isEmptyObject(keys) {\n var key;\n for (key in keys) {\n return false;\n }\n return true;\n}\n\n/***/ }),\n\n/***/ \"./src/components/windows-motion-controls.js\":\n/*!***************************************************!*\\\n !*** ./src/components/windows-motion-controls.js ***!\n \\***************************************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\n/* global THREE */\nvar registerComponent = (__webpack_require__(/*! ../core/component */ \"./src/core/component.js\").registerComponent);\nvar trackedControlsUtils = __webpack_require__(/*! ../utils/tracked-controls */ \"./src/utils/tracked-controls.js\");\nvar checkControllerPresentAndSetup = trackedControlsUtils.checkControllerPresentAndSetup;\nvar emitIfAxesChanged = trackedControlsUtils.emitIfAxesChanged;\nvar onButtonEvent = trackedControlsUtils.onButtonEvent;\nvar utils = __webpack_require__(/*! ../utils/ */ \"./src/utils/index.js\");\nvar debug = utils.debug('components:windows-motion-controls:debug');\nvar warn = utils.debug('components:windows-motion-controls:warn');\nvar DEFAULT_HANDEDNESS = (__webpack_require__(/*! ../constants */ \"./src/constants/index.js\").DEFAULT_HANDEDNESS);\nvar AFRAME_CDN_ROOT = (__webpack_require__(/*! ../constants */ \"./src/constants/index.js\").AFRAME_CDN_ROOT);\nvar MODEL_BASE_URL = AFRAME_CDN_ROOT + 'controllers/microsoft/';\nvar MODEL_FILENAMES = {\n left: 'left.glb',\n right: 'right.glb',\n default: 'universal.glb'\n};\nvar isWebXRAvailable = (__webpack_require__(/*! ../utils/ */ \"./src/utils/index.js\").device.isWebXRAvailable);\nvar GAMEPAD_ID_WEBXR = 'windows-mixed-reality';\nvar GAMEPAD_ID_WEBVR = 'Spatial Controller (Spatial Interaction Source) ';\nvar GAMEPAD_ID_PATTERN = /([0-9a-zA-Z]+-[0-9a-zA-Z]+)$/;\nvar GAMEPAD_ID_PREFIX = isWebXRAvailable ? GAMEPAD_ID_WEBXR : GAMEPAD_ID_WEBVR;\nvar INPUT_MAPPING_WEBVR = {\n // A-Frame specific semantic axis names\n axes: {\n 'thumbstick': [0, 1],\n 'trackpad': [2, 3]\n },\n // A-Frame specific semantic button names\n buttons: ['thumbstick', 'trigger', 'grip', 'menu', 'trackpad'],\n // A mapping of the semantic name to node name in the glTF model file,\n // that should be transformed by axis value.\n // This array mirrors the browser Gamepad.axes array, such that\n // the mesh corresponding to axis 0 is in this array index 0.\n axisMeshNames: ['THUMBSTICK_X', 'THUMBSTICK_Y', 'TOUCHPAD_TOUCH_X', 'TOUCHPAD_TOUCH_Y'],\n // A mapping of the semantic name to button node name in the glTF model file,\n // that should be transformed by button value.\n buttonMeshNames: {\n 'trigger': 'SELECT',\n 'menu': 'MENU',\n 'grip': 'GRASP',\n 'thumbstick': 'THUMBSTICK_PRESS',\n 'trackpad': 'TOUCHPAD_PRESS'\n },\n pointingPoseMeshName: 'POINTING_POSE'\n};\nvar INPUT_MAPPING_WEBXR = {\n // A-Frame specific semantic axis names\n axes: {\n 'touchpad': [0, 1],\n 'thumbstick': [2, 3]\n },\n // A-Frame specific semantic button names\n buttons: ['trigger', 'squeeze', 'touchpad', 'thumbstick', 'menu'],\n // A mapping of the semantic name to node name in the glTF model file,\n // that should be transformed by axis value.\n // This array mirrors the browser Gamepad.axes array, such that\n // the mesh corresponding to axis 0 is in this array index 0.\n axisMeshNames: ['TOUCHPAD_TOUCH_X', 'TOUCHPAD_TOUCH_X', 'THUMBSTICK_X', 'THUMBSTICK_Y'],\n // A mapping of the semantic name to button node name in the glTF model file,\n // that should be transformed by button value.\n buttonMeshNames: {\n 'trigger': 'SELECT',\n 'menu': 'MENU',\n 'squeeze': 'GRASP',\n 'thumbstick': 'THUMBSTICK_PRESS',\n 'touchpad': 'TOUCHPAD_PRESS'\n },\n pointingPoseMeshName: 'POINTING_POSE'\n};\nvar INPUT_MAPPING = isWebXRAvailable ? INPUT_MAPPING_WEBXR : INPUT_MAPPING_WEBVR;\n\n/**\n * Windows Motion Controller controls.\n * Interface with Windows Motion Controller controllers and map Gamepad events to\n * controller buttons: trackpad, trigger, grip, menu, thumbstick\n * Load a controller model and transform the pressed buttons.\n */\nmodule.exports.Component = registerComponent('windows-motion-controls', {\n schema: {\n hand: {\n default: DEFAULT_HANDEDNESS\n },\n // It is possible to have multiple pairs of controllers attached (a pair has both left and right).\n // Set this to 1 to use a controller from the second pair, 2 from the third pair, etc.\n pair: {\n default: 0\n },\n // If true, loads the controller glTF asset.\n model: {\n default: true\n },\n // If true, will hide the model from the scene if no matching gamepad (based on ID & hand) is connected.\n hideDisconnected: {\n default: true\n }\n },\n after: ['tracked-controls'],\n mapping: INPUT_MAPPING,\n bindMethods: function () {\n this.onModelError = this.onModelError.bind(this);\n this.onModelLoaded = this.onModelLoaded.bind(this);\n this.onControllersUpdate = this.onControllersUpdate.bind(this);\n this.checkIfControllerPresent = this.checkIfControllerPresent.bind(this);\n this.onAxisMoved = this.onAxisMoved.bind(this);\n },\n init: function () {\n var self = this;\n var el = this.el;\n this.onButtonChanged = this.onButtonChanged.bind(this);\n this.onButtonDown = function (evt) {\n onButtonEvent(evt.detail.id, 'down', self);\n };\n this.onButtonUp = function (evt) {\n onButtonEvent(evt.detail.id, 'up', self);\n };\n this.onButtonTouchStart = function (evt) {\n onButtonEvent(evt.detail.id, 'touchstart', self);\n };\n this.onButtonTouchEnd = function (evt) {\n onButtonEvent(evt.detail.id, 'touchend', self);\n };\n this.onControllerConnected = function () {\n self.setModelVisibility(true);\n };\n this.onControllerDisconnected = function () {\n self.setModelVisibility(false);\n };\n this.controllerPresent = false;\n this.lastControllerCheck = 0;\n this.previousButtonValues = {};\n this.bindMethods();\n\n // Cache for submeshes that we have looked up by name.\n this.loadedMeshInfo = {\n buttonMeshes: null,\n axisMeshes: null\n };\n\n // Pointing poses\n this.rayOrigin = {\n origin: new THREE.Vector3(),\n direction: new THREE.Vector3(0, 0, -1),\n createdFromMesh: false\n };\n el.addEventListener('controllerconnected', this.onControllerConnected);\n el.addEventListener('controllerdisconnected', this.onControllerDisconnected);\n },\n addEventListeners: function () {\n var el = this.el;\n el.addEventListener('buttonchanged', this.onButtonChanged);\n el.addEventListener('buttondown', this.onButtonDown);\n el.addEventListener('buttonup', this.onButtonUp);\n el.addEventListener('touchstart', this.onButtonTouchStart);\n el.addEventListener('touchend', this.onButtonTouchEnd);\n el.addEventListener('axismove', this.onAxisMoved);\n el.addEventListener('model-error', this.onModelError);\n el.addEventListener('model-loaded', this.onModelLoaded);\n this.controllerEventsActive = true;\n },\n removeEventListeners: function () {\n var el = this.el;\n el.removeEventListener('buttonchanged', this.onButtonChanged);\n el.removeEventListener('buttondown', this.onButtonDown);\n el.removeEventListener('buttonup', this.onButtonUp);\n el.removeEventListener('touchstart', this.onButtonTouchStart);\n el.removeEventListener('touchend', this.onButtonTouchEnd);\n el.removeEventListener('axismove', this.onAxisMoved);\n el.removeEventListener('model-error', this.onModelError);\n el.removeEventListener('model-loaded', this.onModelLoaded);\n this.controllerEventsActive = false;\n },\n checkIfControllerPresent: function () {\n checkControllerPresentAndSetup(this, GAMEPAD_ID_PREFIX, {\n hand: this.data.hand,\n index: this.data.pair,\n iterateControllerProfiles: true\n });\n },\n play: function () {\n this.checkIfControllerPresent();\n this.addControllersUpdateListener();\n },\n pause: function () {\n this.removeEventListeners();\n this.removeControllersUpdateListener();\n },\n updateControllerModel: function () {\n // If we do not want to load a model, or, have already loaded the model, emit the controllermodelready event.\n if (!this.data.model || this.rayOrigin.createdFromMesh) {\n this.modelReady();\n return;\n }\n var sourceUrl = this.createControllerModelUrl();\n this.loadModel(sourceUrl);\n },\n /**\n * Helper function that constructs a URL from the controller ID suffix, for future proofed\n * art assets.\n */\n createControllerModelUrl: function (forceDefault) {\n // Determine the device specific folder based on the ID suffix\n var trackedControlsComponent = this.el.components['tracked-controls'];\n var controller = trackedControlsComponent ? trackedControlsComponent.controller : null;\n var device = 'default';\n var hand = this.data.hand;\n var filename;\n if (controller && !window.hasNativeWebXRImplementation) {\n // Read hand directly from the controller, rather than this.data, as in the case that the controller\n // is unhanded this.data will still have 'left' or 'right' (depending on what the user inserted in to the scene).\n // In this case, we want to load the universal model, so need to get the '' from the controller.\n hand = controller.hand;\n if (!forceDefault) {\n var match = controller.id.match(GAMEPAD_ID_PATTERN);\n device = match && match[0] || device;\n }\n }\n\n // Hand\n filename = MODEL_FILENAMES[hand] || MODEL_FILENAMES.default;\n\n // Final url\n return MODEL_BASE_URL + device + '/' + filename;\n },\n injectTrackedControls: function () {\n var data = this.data;\n this.el.setAttribute('tracked-controls', {\n idPrefix: GAMEPAD_ID_PREFIX,\n controller: data.pair,\n hand: data.hand,\n armModel: false\n });\n this.updateControllerModel();\n },\n addControllersUpdateListener: function () {\n this.el.sceneEl.addEventListener('controllersupdated', this.onControllersUpdate, false);\n },\n removeControllersUpdateListener: function () {\n this.el.sceneEl.removeEventListener('controllersupdated', this.onControllersUpdate, false);\n },\n onControllersUpdate: function () {\n this.checkIfControllerPresent();\n },\n onModelError: function (evt) {\n var defaultUrl = this.createControllerModelUrl(true);\n if (evt.detail.src !== defaultUrl) {\n warn('Failed to load controller model for device, attempting to load default.');\n this.loadModel(defaultUrl);\n } else {\n warn('Failed to load default controller model.');\n }\n },\n loadModel: function (url) {\n // The model is loaded by the gltf-model component when this attribute is initially set,\n // removed and re-loaded if the given url changes.\n this.el.setAttribute('gltf-model', 'url(' + url + ')');\n },\n onModelLoaded: function (evt) {\n var rootNode = this.controllerModel = evt.detail.model;\n var loadedMeshInfo = this.loadedMeshInfo;\n var i;\n var meshName;\n var mesh;\n var meshInfo;\n if (evt.target !== this.el) {\n return;\n }\n debug('Processing model');\n\n // Reset the caches\n loadedMeshInfo.buttonMeshes = {};\n loadedMeshInfo.axisMeshes = {};\n\n // Cache our meshes so we aren't traversing the hierarchy per frame\n if (rootNode) {\n // Button Meshes\n for (i = 0; i < this.mapping.buttons.length; i++) {\n meshName = this.mapping.buttonMeshNames[this.mapping.buttons[i]];\n if (!meshName) {\n debug('Skipping unknown button at index: ' + i + ' with mapped name: ' + this.mapping.buttons[i]);\n continue;\n }\n mesh = rootNode.getObjectByName(meshName);\n if (!mesh) {\n warn('Missing button mesh with name: ' + meshName);\n continue;\n }\n meshInfo = {\n index: i,\n value: getImmediateChildByName(mesh, 'VALUE'),\n pressed: getImmediateChildByName(mesh, 'PRESSED'),\n unpressed: getImmediateChildByName(mesh, 'UNPRESSED')\n };\n if (meshInfo.value && meshInfo.pressed && meshInfo.unpressed) {\n loadedMeshInfo.buttonMeshes[this.mapping.buttons[i]] = meshInfo;\n } else {\n // If we didn't find the mesh, it simply means this button won't have transforms applied as mapped button value changes.\n warn('Missing button submesh under mesh with name: ' + meshName + '(VALUE: ' + !!meshInfo.value + ', PRESSED: ' + !!meshInfo.pressed + ', UNPRESSED:' + !!meshInfo.unpressed + ')');\n }\n }\n\n // Axis Meshes\n for (i = 0; i < this.mapping.axisMeshNames.length; i++) {\n meshName = this.mapping.axisMeshNames[i];\n if (!meshName) {\n debug('Skipping unknown axis at index: ' + i);\n continue;\n }\n mesh = rootNode.getObjectByName(meshName);\n if (!mesh) {\n warn('Missing axis mesh with name: ' + meshName);\n continue;\n }\n meshInfo = {\n index: i,\n value: getImmediateChildByName(mesh, 'VALUE'),\n min: getImmediateChildByName(mesh, 'MIN'),\n max: getImmediateChildByName(mesh, 'MAX')\n };\n if (meshInfo.value && meshInfo.min && meshInfo.max) {\n loadedMeshInfo.axisMeshes[i] = meshInfo;\n } else {\n // If we didn't find the mesh, it simply means this axis won't have transforms applied as mapped axis values change.\n warn('Missing axis submesh under mesh with name: ' + meshName + '(VALUE: ' + !!meshInfo.value + ', MIN: ' + !!meshInfo.min + ', MAX:' + !!meshInfo.max + ')');\n }\n }\n this.calculateRayOriginFromMesh(rootNode);\n // Determine if the model has to be visible or not.\n this.setModelVisibility();\n }\n debug('Model load complete.');\n\n // Look through only immediate children. This will return null if no mesh exists with the given name.\n function getImmediateChildByName(object3d, value) {\n for (var i = 0, l = object3d.children.length; i < l; i++) {\n var obj = object3d.children[i];\n if (obj && obj['name'] === value) {\n return obj;\n }\n }\n return undefined;\n }\n },\n calculateRayOriginFromMesh: function () {\n var quaternion = new THREE.Quaternion();\n return function (rootNode) {\n var mesh;\n\n // Calculate the pointer pose (used for rays), by applying the world transform of th POINTER_POSE node\n // in the glTF (assumes that root node is at world origin)\n this.rayOrigin.origin.set(0, 0, 0);\n this.rayOrigin.direction.set(0, 0, -1);\n this.rayOrigin.createdFromMesh = true;\n\n // Try to read Pointing pose from the source model\n mesh = rootNode.getObjectByName(this.mapping.pointingPoseMeshName);\n if (mesh) {\n var parent = rootNode.parent;\n\n // We need to read pose transforms accumulated from the root of the glTF, not the scene.\n if (parent) {\n rootNode.parent = null;\n rootNode.updateMatrixWorld(true);\n rootNode.parent = parent;\n }\n mesh.getWorldPosition(this.rayOrigin.origin);\n mesh.getWorldQuaternion(quaternion);\n this.rayOrigin.direction.applyQuaternion(quaternion);\n\n // Recalculate the world matrices now that the rootNode is re-attached to the parent.\n if (parent) {\n rootNode.updateMatrixWorld(true);\n }\n } else {\n debug('Mesh does not contain pointing origin data, defaulting to none.');\n }\n\n // Emit event stating that our pointing ray is now accurate.\n this.modelReady();\n };\n }(),\n lerpAxisTransform: function () {\n var quaternion = new THREE.Quaternion();\n return function (axis, axisValue) {\n var axisMeshInfo = this.loadedMeshInfo.axisMeshes[axis];\n if (!axisMeshInfo) return;\n var min = axisMeshInfo.min;\n var max = axisMeshInfo.max;\n var target = axisMeshInfo.value;\n\n // Convert from gamepad value range (-1 to +1) to lerp range (0 to 1)\n var lerpValue = axisValue * 0.5 + 0.5;\n target.setRotationFromQuaternion(quaternion.copy(min.quaternion).slerp(max.quaternion, lerpValue));\n target.position.lerpVectors(min.position, max.position, lerpValue);\n };\n }(),\n lerpButtonTransform: function () {\n var quaternion = new THREE.Quaternion();\n return function (buttonName, buttonValue) {\n var buttonMeshInfo = this.loadedMeshInfo.buttonMeshes[buttonName];\n if (!buttonMeshInfo) return;\n var min = buttonMeshInfo.unpressed;\n var max = buttonMeshInfo.pressed;\n var target = buttonMeshInfo.value;\n target.setRotationFromQuaternion(quaternion.copy(min.quaternion).slerp(max.quaternion, buttonValue));\n target.position.lerpVectors(min.position, max.position, buttonValue);\n };\n }(),\n modelReady: function () {\n this.el.emit('controllermodelready', {\n name: 'windows-motion-controls',\n model: this.data.model,\n rayOrigin: this.rayOrigin\n });\n },\n onButtonChanged: function (evt) {\n var buttonName = this.mapping.buttons[evt.detail.id];\n if (buttonName) {\n // Update the button mesh transform\n if (this.loadedMeshInfo && this.loadedMeshInfo.buttonMeshes) {\n this.lerpButtonTransform(buttonName, evt.detail.state.value);\n }\n\n // Only emit events for buttons that we know how to map from index to name\n this.el.emit(buttonName + 'changed', evt.detail.state);\n }\n },\n onAxisMoved: function (evt) {\n var numAxes = this.mapping.axisMeshNames.length;\n\n // Only attempt to update meshes if we have valid data.\n if (this.loadedMeshInfo && this.loadedMeshInfo.axisMeshes) {\n for (var axis = 0; axis < numAxes; axis++) {\n // Update the button mesh transform\n this.lerpAxisTransform(axis, evt.detail.axis[axis] || 0.0);\n }\n }\n emitIfAxesChanged(this, this.mapping.axes, evt);\n },\n setModelVisibility: function (visible) {\n var model = this.el.getObject3D('mesh');\n if (!this.controllerPresent) {\n return;\n }\n visible = visible !== undefined ? visible : this.modelVisible;\n this.modelVisible = visible;\n if (!model) {\n return;\n }\n model.visible = visible;\n }\n});\n\n/***/ }),\n\n/***/ \"./src/constants/index.js\":\n/*!********************************!*\\\n !*** ./src/constants/index.js ***!\n \\********************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\nmodule.exports = {\n AFRAME_CDN_ROOT: window.AFRAME_CDN_ROOT || 'https://cdn.aframe.io/',\n AFRAME_INJECTED: 'aframe-injected',\n DEFAULT_CAMERA_HEIGHT: 1.6,\n DEFAULT_HANDEDNESS: 'right',\n keyboardevent: __webpack_require__(/*! ./keyboardevent */ \"./src/constants/keyboardevent.js\")\n};\n\n/***/ }),\n\n/***/ \"./src/constants/keyboardevent.js\":\n/*!****************************************!*\\\n !*** ./src/constants/keyboardevent.js ***!\n \\****************************************/\n/***/ ((module) => {\n\nmodule.exports = {\n // Tiny KeyboardEvent.code polyfill.\n KEYCODE_TO_CODE: {\n '38': 'ArrowUp',\n '37': 'ArrowLeft',\n '40': 'ArrowDown',\n '39': 'ArrowRight',\n '87': 'KeyW',\n '65': 'KeyA',\n '83': 'KeyS',\n '68': 'KeyD'\n }\n};\n\n/***/ }),\n\n/***/ \"./src/core/a-assets.js\":\n/*!******************************!*\\\n !*** ./src/core/a-assets.js ***!\n \\******************************/\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\n/* global customElements */\nvar ANode = (__webpack_require__(/*! ./a-node */ \"./src/core/a-node.js\").ANode);\nvar debug = __webpack_require__(/*! ../utils/debug */ \"./src/utils/debug.js\");\nvar THREE = __webpack_require__(/*! ../lib/three */ \"./src/lib/three.js\");\nvar fileLoader = new THREE.FileLoader();\nvar warn = debug('core:a-assets:warn');\n\n/**\n * Asset management system. Handles blocking on asset loading.\n */\nclass AAssets extends ANode {\n constructor() {\n super();\n this.isAssets = true;\n this.fileLoader = fileLoader;\n this.timeout = null;\n }\n doConnectedCallback() {\n var self = this;\n var i;\n var loaded = [];\n var mediaEl;\n var mediaEls;\n var imgEl;\n var imgEls;\n var timeout;\n var children;\n super.doConnectedCallback();\n if (!this.parentNode.isScene) {\n throw new Error(' must be a child of a .');\n }\n\n // Wait for s.\n imgEls = this.querySelectorAll('img');\n for (i = 0; i < imgEls.length; i++) {\n imgEl = fixUpMediaElement(imgEls[i]);\n loaded.push(new Promise(function (resolve, reject) {\n // Set in cache because we won't be needing to call three.js loader if we have.\n // a loaded media element.\n THREE.Cache.add(imgEls[i].getAttribute('src'), imgEl);\n if (imgEl.complete) {\n resolve();\n return;\n }\n imgEl.onload = resolve;\n imgEl.onerror = reject;\n }));\n }\n\n // Wait for